summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/qaction.cpp2144
-rw-r--r--src/widgets/qaction.h218
-rw-r--r--src/widgets/qbutton.cpp1008
-rw-r--r--src/widgets/qbutton.h234
-rw-r--r--src/widgets/qbuttongroup.cpp682
-rw-r--r--src/widgets/qbuttongroup.h121
-rw-r--r--src/widgets/qcheckbox.cpp364
-rw-r--r--src/widgets/qcheckbox.h96
-rw-r--r--src/widgets/qcombobox.cpp2334
-rw-r--r--src/widgets/qcombobox.h206
-rw-r--r--src/widgets/qdatetimeedit.cpp2842
-rw-r--r--src/widgets/qdatetimeedit.h293
-rw-r--r--src/widgets/qdial.cpp976
-rw-r--r--src/widgets/qdial.h153
-rw-r--r--src/widgets/qdialogbuttons.cpp456
-rw-r--r--src/widgets/qdialogbuttons_p.h118
-rw-r--r--src/widgets/qdockarea.cpp1320
-rw-r--r--src/widgets/qdockarea.h191
-rw-r--r--src/widgets/qdockwindow.cpp2123
-rw-r--r--src/widgets/qdockwindow.h237
-rw-r--r--src/widgets/qeffects.cpp675
-rw-r--r--src/widgets/qeffects_p.h81
-rw-r--r--src/widgets/qframe.cpp754
-rw-r--r--src/widgets/qframe.h171
-rw-r--r--src/widgets/qgrid.cpp137
-rw-r--r--src/widgets/qgrid.h77
-rw-r--r--src/widgets/qgridview.cpp369
-rw-r--r--src/widgets/qgridview.h139
-rw-r--r--src/widgets/qgroupbox.cpp989
-rw-r--r--src/widgets/qgroupbox.h165
-rw-r--r--src/widgets/qhbox.cpp145
-rw-r--r--src/widgets/qhbox.h76
-rw-r--r--src/widgets/qhbuttongroup.cpp94
-rw-r--r--src/widgets/qhbuttongroup.h68
-rw-r--r--src/widgets/qheader.cpp2049
-rw-r--r--src/widgets/qheader.h219
-rw-r--r--src/widgets/qhgroupbox.cpp93
-rw-r--r--src/widgets/qhgroupbox.h67
-rw-r--r--src/widgets/qlabel.cpp1190
-rw-r--r--src/widgets/qlabel.h174
-rw-r--r--src/widgets/qlcdnumber.cpp1170
-rw-r--r--src/widgets/qlcdnumber.h146
-rw-r--r--src/widgets/qlineedit.cpp2925
-rw-r--r--src/widgets/qlineedit.h232
-rw-r--r--src/widgets/qlistbox.cpp4693
-rw-r--r--src/widgets/qlistbox.h435
-rw-r--r--src/widgets/qlistview.cpp8174
-rw-r--r--src/widgets/qlistview.h605
-rw-r--r--src/widgets/qmainwindow.cpp2609
-rw-r--r--src/widgets/qmainwindow.h261
-rw-r--r--src/widgets/qmenubar.cpp1683
-rw-r--r--src/widgets/qmenubar.h205
-rw-r--r--src/widgets/qmenudata.cpp1603
-rw-r--r--src/widgets/qmenudata.h286
-rw-r--r--src/widgets/qmultilineedit.cpp541
-rw-r--r--src/widgets/qmultilineedit.h141
-rw-r--r--src/widgets/qpopupmenu.cpp2886
-rw-r--r--src/widgets/qpopupmenu.h201
-rw-r--r--src/widgets/qprogressbar.cpp408
-rw-r--r--src/widgets/qprogressbar.h149
-rw-r--r--src/widgets/qpushbutton.cpp760
-rw-r--r--src/widgets/qpushbutton.h149
-rw-r--r--src/widgets/qradiobutton.cpp358
-rw-r--r--src/widgets/qradiobutton.h91
-rw-r--r--src/widgets/qrangecontrol.cpp565
-rw-r--r--src/widgets/qrangecontrol.h194
-rw-r--r--src/widgets/qscrollbar.cpp1072
-rw-r--r--src/widgets/qscrollbar.h197
-rw-r--r--src/widgets/qscrollview.cpp2854
-rw-r--r--src/widgets/qscrollview.h269
-rw-r--r--src/widgets/qslider.cpp921
-rw-r--r--src/widgets/qslider.h199
-rw-r--r--src/widgets/qspinbox.cpp1116
-rw-r--r--src/widgets/qspinbox.h172
-rw-r--r--src/widgets/qspinwidget.cpp465
-rw-r--r--src/widgets/qsplashscreen.cpp271
-rw-r--r--src/widgets/qsplashscreen.h80
-rw-r--r--src/widgets/qsplitter.cpp1429
-rw-r--r--src/widgets/qsplitter.h169
-rw-r--r--src/widgets/qstatusbar.cpp526
-rw-r--r--src/widgets/qstatusbar.h96
-rw-r--r--src/widgets/qsyntaxhighlighter.cpp221
-rw-r--r--src/widgets/qsyntaxhighlighter.h81
-rw-r--r--src/widgets/qsyntaxhighlighter_p.h97
-rw-r--r--src/widgets/qt_widgets.pri139
-rw-r--r--src/widgets/qtabbar.cpp1368
-rw-r--r--src/widgets/qtabbar.h186
-rw-r--r--src/widgets/qtabwidget.cpp1097
-rw-r--r--src/widgets/qtabwidget.h162
-rw-r--r--src/widgets/qtextbrowser.cpp555
-rw-r--r--src/widgets/qtextbrowser.h107
-rw-r--r--src/widgets/qtextedit.cpp7467
-rw-r--r--src/widgets/qtextedit.h616
-rw-r--r--src/widgets/qtextview.cpp103
-rw-r--r--src/widgets/qtextview.h74
-rw-r--r--src/widgets/qtitlebar.cpp671
-rw-r--r--src/widgets/qtitlebar_p.h139
-rw-r--r--src/widgets/qtoolbar.cpp815
-rw-r--r--src/widgets/qtoolbar.h117
-rw-r--r--src/widgets/qtoolbox.cpp692
-rw-r--r--src/widgets/qtoolbox.h126
-rw-r--r--src/widgets/qtoolbutton.cpp1041
-rw-r--r--src/widgets/qtoolbutton.h192
-rw-r--r--src/widgets/qtooltip.cpp1270
-rw-r--r--src/widgets/qtooltip.h149
-rw-r--r--src/widgets/qvalidator.cpp672
-rw-r--r--src/widgets/qvalidator.h169
-rw-r--r--src/widgets/qvbox.cpp71
-rw-r--r--src/widgets/qvbox.h65
-rw-r--r--src/widgets/qvbuttongroup.cpp92
-rw-r--r--src/widgets/qvbuttongroup.h69
-rw-r--r--src/widgets/qvgroupbox.cpp91
-rw-r--r--src/widgets/qvgroupbox.h68
-rw-r--r--src/widgets/qwhatsthis.cpp1001
-rw-r--r--src/widgets/qwhatsthis.h81
-rw-r--r--src/widgets/qwidgetinterface_p.h145
-rw-r--r--src/widgets/qwidgetplugin.cpp729
-rw-r--r--src/widgets/qwidgetplugin.h120
-rw-r--r--src/widgets/qwidgetresizehandler.cpp516
-rw-r--r--src/widgets/qwidgetresizehandler_p.h137
-rw-r--r--src/widgets/qwidgetstack.cpp610
-rw-r--r--src/widgets/qwidgetstack.h112
122 files changed, 87387 insertions, 0 deletions
diff --git a/src/widgets/qaction.cpp b/src/widgets/qaction.cpp
new file mode 100644
index 0000000..1e68de0
--- /dev/null
+++ b/src/widgets/qaction.cpp
@@ -0,0 +1,2144 @@
+/****************************************************************************
+**
+** Implementation of QAction class
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qaction.h"
+
+#ifndef QT_NO_ACTION
+
+#include "qtoolbar.h"
+#include "qptrlist.h"
+#include "qpopupmenu.h"
+#include "qaccel.h"
+#include "qtoolbutton.h"
+#include "qcombobox.h"
+#include "qtooltip.h"
+#include "qwhatsthis.h"
+#include "qstatusbar.h"
+#include "qobjectlist.h"
+
+
+/*!
+ \class QAction qaction.h
+ \brief The QAction class provides an abstract user interface
+ action that can appear both in menus and tool bars.
+
+ \ingroup basic
+ \ingroup application
+ \mainclass
+
+ In GUI applications many commands can be invoked via a menu
+ option, a toolbar button and a keyboard accelerator. Since the
+ same action must be performed regardless of how the action was
+ invoked, and since the menu and toolbar should be kept in sync, it
+ is useful to represent a command as an \e action. An action can be
+ added to a menu and a toolbar and will automatically keep them in
+ sync. For example, if the user presses a Bold toolbar button the
+ Bold menu item will automatically be checked.
+
+ A QAction may contain an icon, a menu text, an accelerator, a
+ status text, a whats this text and a tool tip. Most of these can
+ be set in the constructor. They can also be set independently with
+ setIconSet(), setText(), setMenuText(), setToolTip(),
+ setStatusTip(), setWhatsThis() and setAccel().
+
+ An action may be a toggle action e.g. a Bold toolbar button, or a
+ command action, e.g. 'Open File' to invoke an open file dialog.
+ Toggle actions emit the toggled() signal when their state changes.
+ Both command and toggle actions emit the activated() signal when
+ they are invoked. Use setToggleAction() to set an action's toggled
+ status. To see if an action is a toggle action use
+ isToggleAction(). A toggle action may be "on", isOn() returns
+ TRUE, or "off", isOn() returns FALSE.
+
+ Actions are added to widgets (menus or toolbars) using addTo(),
+ and removed using removeFrom().
+
+ Once a QAction has been created it should be added to the relevant
+ menu and toolbar and then connected to the slot which will perform
+ the action. For example:
+
+ \quotefile action/application.cpp
+ \skipto QPixmap( fileopen
+ \printuntil connect
+
+ We create a "File Save" action with a menu text of "&Save" and
+ \e{Ctrl+S} as the keyboard accelerator. We connect the
+ fileSaveAction's activated() signal to our own save() slot. Note
+ that at this point there is no menu or toolbar action, we'll add
+ them next:
+
+ \skipto new QToolBar
+ \printline
+ \skipto fileSaveAction->addTo
+ \printline
+ \skipto new QPopupMenu
+ \printuntil insertItem
+ \skipto fileSaveAction->addTo
+ \printline
+
+ We create a toolbar and add our fileSaveAction to it. Similarly we
+ create a menu, add a top-level menu item, and add our
+ fileSaveAction.
+
+ We recommend that actions are created as children of the window
+ that they are used in. In most cases actions will be children of
+ the application's main window.
+
+ To prevent recursion, don't create an action as a child of a
+ widget that the action is later added to.
+*/
+
+class QActionPrivate
+{
+public:
+ QActionPrivate(QAction *act);
+ ~QActionPrivate();
+ QIconSet *iconset;
+ QString text;
+ QString menutext;
+ QString tooltip;
+ QString statustip;
+ QString whatsthis;
+#ifndef QT_NO_ACCEL
+ QKeySequence key;
+ QAccel* accel;
+ int accelid;
+#endif
+ uint enabled : 1;
+ uint visible : 1;
+ uint toggleaction : 1;
+ uint on : 1;
+ uint forceDisabled : 1;
+ uint forceInvisible : 1;
+#ifndef QT_NO_TOOLTIP
+ QToolTipGroup tipGroup;
+#endif
+ QActionGroupPrivate* d_group;
+ QAction *action;
+
+ struct MenuItem {
+ MenuItem():popup(0),id(0){}
+ QPopupMenu* popup;
+ int id;
+ };
+ // ComboItem is only necessary for actions that are
+ // in dropdown/exclusive actiongroups. The actiongroup
+ // will clean this up
+ struct ComboItem {
+ ComboItem():combo(0), id(0) {}
+ QComboBox *combo;
+ int id;
+ };
+ QPtrList<MenuItem> menuitems;
+ QPtrList<QToolButton> toolbuttons;
+ QPtrList<ComboItem> comboitems;
+
+ enum Update { Icons = 1, Visibility = 2, State = 4, EverythingElse = 8 };
+ void update( uint upd = EverythingElse );
+
+ QString menuText() const;
+ QString toolTip() const;
+ QString statusTip() const;
+};
+
+QActionPrivate::QActionPrivate(QAction *act)
+ : iconset( 0 ),
+#ifndef QT_NO_ACCEL
+ key( 0 ), accel( 0 ), accelid( 0 ),
+#endif
+ enabled( TRUE ), visible( TRUE ), toggleaction( FALSE ), on( FALSE ),
+ forceDisabled( FALSE ), forceInvisible( FALSE ),
+#ifndef QT_NO_TOOLTIP
+ tipGroup( 0 ),
+#endif
+ d_group( 0 ), action(act)
+{
+ menuitems.setAutoDelete( TRUE );
+ comboitems.setAutoDelete( TRUE );
+#ifndef QT_NO_TOOLTIP
+ tipGroup.setDelay( FALSE );
+#endif
+}
+
+QActionPrivate::~QActionPrivate()
+{
+ QPtrListIterator<QToolButton> ittb( toolbuttons );
+ QToolButton *tb;
+
+ while ( ( tb = ittb.current() ) ) {
+ ++ittb;
+ delete tb;
+ }
+
+ QPtrListIterator<QActionPrivate::MenuItem> itmi( menuitems);
+ QActionPrivate::MenuItem* mi;
+ while ( ( mi = itmi.current() ) ) {
+ ++itmi;
+ QPopupMenu* menu = mi->popup;
+ if ( menu->findItem( mi->id ) )
+ menu->removeItem( mi->id );
+ }
+
+ QPtrListIterator<QActionPrivate::ComboItem> itci(comboitems);
+ QActionPrivate::ComboItem* ci;
+ while ( ( ci = itci.current() ) ) {
+ ++itci;
+ QComboBox* combo = ci->combo;
+ combo->clear();
+ QActionGroup *group = ::qt_cast<QActionGroup*>(action->parent());
+ QObjectList *siblings = group ? group->queryList("QAction") : 0;
+ if (siblings) {
+ QObjectListIt it(*siblings);
+ while (it.current()) {
+ QAction *sib = ::qt_cast<QAction*>(it.current());
+ ++it;
+ sib->removeFrom(combo);
+ }
+ it = QObjectListIt(*siblings);
+ while (it.current()) {
+ QAction *sib = ::qt_cast<QAction*>(it.current());
+ ++it;
+ if (sib == action)
+ continue;
+ sib->addTo(combo);
+ }
+ }
+ delete siblings;
+ }
+
+#ifndef QT_NO_ACCEL
+ delete accel;
+#endif
+ delete iconset;
+}
+
+class QActionGroupPrivate
+{
+public:
+ uint exclusive: 1;
+ uint dropdown: 1;
+ QPtrList<QAction> actions;
+ QAction* selected;
+ QAction* separatorAction;
+
+ struct MenuItem {
+ MenuItem():popup(0),id(0){}
+ QPopupMenu* popup;
+ int id;
+ };
+
+ QPtrList<QComboBox> comboboxes;
+ QPtrList<QToolButton> menubuttons;
+ QPtrList<MenuItem> menuitems;
+ QPtrList<QPopupMenu> popupmenus;
+
+ void update( const QActionGroup * );
+};
+
+void QActionPrivate::update( uint upd )
+{
+ for ( QPtrListIterator<MenuItem> it( menuitems); it.current(); ++it ) {
+ MenuItem* mi = it.current();
+ QString t = menuText();
+#ifndef QT_NO_ACCEL
+ if ( key )
+ t += '\t' + QAccel::keyToString( key );
+#endif
+ if ( upd & State ) {
+ mi->popup->setItemEnabled( mi->id, enabled );
+ if ( toggleaction )
+ mi->popup->setItemChecked( mi->id, on );
+ }
+ if ( upd & Visibility )
+ mi->popup->setItemVisible( mi->id, visible );
+
+ if ( upd & Icons )
+ if ( iconset )
+ mi->popup->changeItem( mi->id, *iconset, t );
+ else
+ mi->popup->changeItem( mi->id, QIconSet(), t );
+ if ( upd & EverythingElse ) {
+ mi->popup->changeItem( mi->id, t );
+ if ( !whatsthis.isEmpty() )
+ mi->popup->setWhatsThis( mi->id, whatsthis );
+ if ( toggleaction ) {
+ mi->popup->setCheckable( TRUE );
+ mi->popup->setItemChecked( mi->id, on );
+ }
+ }
+ }
+ for ( QPtrListIterator<QToolButton> it2(toolbuttons); it2.current(); ++it2 ) {
+ QToolButton* btn = it2.current();
+ if ( upd & State ) {
+ btn->setEnabled( enabled );
+ if ( toggleaction )
+ btn->setOn( on );
+ }
+ if ( upd & Visibility )
+ visible ? btn->show() : btn->hide();
+ if ( upd & Icons ) {
+ if ( iconset )
+ btn->setIconSet( *iconset );
+ else
+ btn->setIconSet( QIconSet() );
+ }
+ if ( upd & EverythingElse ) {
+ btn->setToggleButton( toggleaction );
+ if ( !text.isEmpty() )
+ btn->setTextLabel( text, FALSE );
+#ifndef QT_NO_TOOLTIP
+ QToolTip::remove( btn );
+ QToolTip::add( btn, toolTip(), &tipGroup, statusTip() );
+#endif
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::remove( btn );
+ if ( !whatsthis.isEmpty() )
+ QWhatsThis::add( btn, whatsthis );
+#endif
+ }
+ }
+#ifndef QT_NO_ACCEL
+ if ( accel ) {
+ accel->setEnabled( enabled && visible );
+ if ( !whatsthis.isEmpty() )
+ accel->setWhatsThis( accelid, whatsthis );
+ }
+#endif
+ // Only used by actiongroup
+ for ( QPtrListIterator<ComboItem> it3( comboitems ); it3.current(); ++it3 ) {
+ ComboItem *ci = it3.current();
+ if ( !ci->combo )
+ return;
+ if ( iconset )
+ ci->combo->changeItem( iconset->pixmap(), text, ci->id );
+ else
+ ci->combo->changeItem( text, ci->id );
+ }
+}
+
+QString QActionPrivate::menuText() const
+{
+ if ( menutext.isNull() ) {
+ QString t(text);
+ t.replace('&', "&&");
+ return t;
+ }
+ return menutext;
+}
+
+QString QActionPrivate::toolTip() const
+{
+ if ( tooltip.isNull() ) {
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ return text + " (" + QAccel::keyToString( accel->key( accelid )) + ")";
+#endif
+ return text;
+ }
+ return tooltip;
+}
+
+QString QActionPrivate::statusTip() const
+{
+ if ( statustip.isNull() )
+ return toolTip();
+ return statustip;
+}
+
+/*
+ internal: guesses a descriptive text from a menu text
+ */
+static QString qt_stripMenuText( QString s )
+{
+ s.remove( QString::fromLatin1("...") );
+ s.remove( QChar('&' ) );
+ return s.stripWhiteSpace();
+}
+
+/*!
+ Constructs an action called \a name with parent \a parent.
+
+ If \a parent is a QActionGroup, the new action inserts itself into
+ \a parent.
+
+ For accelerators and status tips to work, \a parent must either be
+ a widget, or an action group whose parent is a widget.
+
+ \warning To prevent recursion, don't create an action as a child
+ of a widget that the action is later added to.
+*/
+QAction::QAction( QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ d = new QActionPrivate(this);
+ init();
+}
+
+/*! \obsolete
+ Constructs an action called \a name with parent \a parent.
+
+ If \a toggle is TRUE the action will be a toggle action, otherwise
+ it will be a command action.
+
+ If \a parent is a QActionGroup, the new action inserts itself into
+ \a parent.
+
+ For accelerators and status tips to work, \a parent must either be
+ a widget, or an action group whose parent is a widget.
+*/
+QAction::QAction( QObject* parent, const char* name, bool toggle )
+ : QObject( parent, name )
+{
+ d = new QActionPrivate(this);
+ d->toggleaction = toggle;
+ init();
+}
+
+
+#ifndef QT_NO_ACCEL
+
+/*!
+ This constructor creates an action with the following properties:
+ the icon or iconset \a icon, the menu text \a menuText and
+ keyboard accelerator \a accel. It is a child of \a parent and
+ called \a name.
+
+ If \a parent is a QActionGroup, the action automatically becomes
+ a member of it.
+
+ For accelerators and status tips to work, \a parent must either be
+ a widget, or an action group whose parent is a widget.
+
+ The action uses a stripped version of \a menuText (e.g. "\&Menu
+ Option..." becomes "Menu Option") as descriptive text for
+ toolbuttons. You can override this by setting a specific
+ description with setText(). The same text and \a accel will be
+ used for tool tips and status tips unless you provide text for
+ these using setToolTip() and setStatusTip().
+
+ Call setToggleAction(TRUE) to make the action a toggle action.
+
+ \warning To prevent recursion, don't create an action as a child
+ of a widget that the action is later added to.
+*/
+QAction::QAction( const QIconSet& icon, const QString& menuText, QKeySequence accel,
+ QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ d = new QActionPrivate(this);
+ if ( !icon.isNull() )
+ setIconSet( icon );
+ d->text = qt_stripMenuText( menuText );
+ d->menutext = menuText;
+ setAccel( accel );
+ init();
+}
+
+/*!
+ This constructor results in an icon-less action with the the menu
+ text \a menuText and keyboard accelerator \a accel. It is a child
+ of \a parent and called \a name.
+
+ If \a parent is a QActionGroup, the action automatically becomes
+ a member of it.
+
+ For accelerators and status tips to work, \a parent must either be
+ a widget, or an action group whose parent is a widget.
+
+ The action uses a stripped version of \a menuText (e.g. "\&Menu
+ Option..." becomes "Menu Option") as descriptive text for
+ toolbuttons. You can override this by setting a specific
+ description with setText(). The same text and \a accel will be
+ used for tool tips and status tips unless you provide text for
+ these using setToolTip() and setStatusTip().
+
+ Call setToggleAction(TRUE) to make the action a toggle action.
+
+ \warning To prevent recursion, don't create an action as a child
+ of a widget that the action is later added to.
+*/
+QAction::QAction( const QString& menuText, QKeySequence accel,
+ QObject* parent, const char* name )
+ : QObject( parent, name )
+{
+ d = new QActionPrivate(this);
+ d->text = qt_stripMenuText( menuText );
+ d->menutext = menuText;
+ setAccel( accel );
+ init();
+}
+
+/*! \obsolete
+ This constructor creates an action with the following properties:
+ the description \a text, the icon or iconset \a icon, the menu
+ text \a menuText and keyboard accelerator \a accel. It is a child
+ of \a parent and called \a name. If \a toggle is TRUE the action
+ will be a toggle action, otherwise it will be a command action.
+
+ If \a parent is a QActionGroup, the action automatically becomes
+ a member of it.
+
+ For accelerators and status tips to work, \a parent must either be
+ a widget, or an action group whose parent is a widget.
+
+ The \a text and \a accel will be used for tool tips and status
+ tips unless you provide specific text for these using setToolTip()
+ and setStatusTip().
+*/
+QAction::QAction( const QString& text, const QIconSet& icon, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle )
+ : QObject( parent, name )
+{
+ d = new QActionPrivate(this);
+ d->toggleaction = toggle;
+ if ( !icon.isNull() )
+ setIconSet( icon );
+
+ d->text = text;
+ d->menutext = menuText;
+ setAccel( accel );
+ init();
+}
+
+/*! \obsolete
+ This constructor results in an icon-less action with the
+ description \a text, the menu text \a menuText and the keyboard
+ accelerator \a accel. Its parent is \a parent and it is called \a
+ name. If \a toggle is TRUE the action will be a toggle action,
+ otherwise it will be a command action.
+
+ The action automatically becomes a member of \a parent if \a
+ parent is a QActionGroup.
+
+ For accelerators and status tips to work, \a parent must either be
+ a widget, or an action group whose parent is a widget.
+
+ The \a text and \a accel will be used for tool tips and status
+ tips unless you provide specific text for these using setToolTip()
+ and setStatusTip().
+*/
+QAction::QAction( const QString& text, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle )
+ : QObject( parent, name )
+{
+ d = new QActionPrivate(this);
+ d->toggleaction = toggle;
+ d->text = text;
+ d->menutext = menuText;
+ setAccel( accel );
+ init();
+}
+#endif
+
+/*!
+ \internal
+*/
+void QAction::init()
+{
+ if ( ::qt_cast<QActionGroup*>(parent()) )
+ ((QActionGroup*) parent())->add( this ); // insert into action group
+}
+
+/*!
+ Destroys the object and frees allocated resources.
+*/
+
+QAction::~QAction()
+{
+ delete d;
+}
+
+/*!
+ \property QAction::iconSet
+ \brief the action's icon
+
+ The icon is used as the tool button icon and in the menu to the
+ left of the menu text. There is no default icon.
+
+ If a null icon (QIconSet::isNull() is passed into this function,
+ the icon of the action is cleared.
+
+ (See the action/toggleaction/toggleaction.cpp example.)
+
+*/
+void QAction::setIconSet( const QIconSet& icon )
+{
+ register QIconSet *i = d->iconset;
+ if ( !icon.isNull() )
+ d->iconset = new QIconSet( icon );
+ else
+ d->iconset = 0;
+ delete i;
+ d->update( QActionPrivate::Icons );
+}
+
+QIconSet QAction::iconSet() const
+{
+ if ( d->iconset )
+ return *d->iconset;
+ return QIconSet();
+}
+
+/*!
+ \property QAction::text
+ \brief the action's descriptive text
+
+ If \l QMainWindow::usesTextLabel is TRUE, the text appears as a
+ label in the relevant tool button. It also serves as the default
+ text in menus and tool tips if these have not been specifically
+ defined. There is no default text.
+
+ \sa setMenuText() setToolTip() setStatusTip()
+*/
+void QAction::setText( const QString& text )
+{
+ d->text = text;
+ d->update();
+}
+
+QString QAction::text() const
+{
+ return d->text;
+}
+
+
+/*!
+ \property QAction::menuText
+ \brief the action's menu text
+
+ If the action is added to a menu the menu option will consist of
+ the icon (if there is one), the menu text and the accelerator (if
+ there is one). If the menu text is not explicitly set in the
+ constructor or by using setMenuText() the action's description
+ text will be used as the menu text. There is no default menu text.
+
+ \sa text
+*/
+void QAction::setMenuText( const QString& text )
+{
+ if ( d->menutext == text )
+ return;
+
+ d->menutext = text;
+ d->update();
+}
+
+QString QAction::menuText() const
+{
+ return d->menuText();
+}
+
+/*!
+ \property QAction::toolTip
+ \brief the action's tool tip
+
+ This text is used for the tool tip. If no status tip has been set
+ the tool tip will be used for the status tip.
+
+ If no tool tip is specified the action's text is used, and if that
+ hasn't been specified the description text is used as the tool tip
+ text.
+
+ There is no default tool tip text.
+
+ \sa setStatusTip() setAccel()
+*/
+void QAction::setToolTip( const QString& tip )
+{
+ if ( d->tooltip == tip )
+ return;
+
+ d->tooltip = tip;
+ d->update();
+}
+
+QString QAction::toolTip() const
+{
+ return d->toolTip();
+}
+
+/*!
+ \property QAction::statusTip
+ \brief the action's status tip
+
+ The statusTip is displayed on all status bars that this action's
+ toplevel parent widget provides.
+
+ If no status tip is defined, the action uses the tool tip text.
+
+ There is no default statusTip text.
+
+ \sa setStatusTip() setToolTip()
+*/
+//#### Please reimp for QActionGroup!
+//#### For consistency reasons even action groups should show
+//#### status tips (as they already do with tool tips)
+//#### Please change QActionGroup class doc appropriately after
+//#### reimplementation.
+void QAction::setStatusTip( const QString& tip )
+{
+ if ( d->statustip == tip )
+ return;
+
+ d->statustip = tip;
+ d->update();
+}
+
+QString QAction::statusTip() const
+{
+ return d->statusTip();
+}
+
+/*!
+ \property QAction::whatsThis
+ \brief the action's "What's This?" help text
+
+ The whats this text is used to provide a brief description of the
+ action. The text may contain rich text (HTML-like tags -- see
+ QStyleSheet for the list of supported tags). There is no default
+ "What's This" text.
+
+ \sa QWhatsThis
+*/
+void QAction::setWhatsThis( const QString& whatsThis )
+{
+ if ( d->whatsthis == whatsThis )
+ return;
+ d->whatsthis = whatsThis;
+ d->update();
+}
+
+QString QAction::whatsThis() const
+{
+ return d->whatsthis;
+}
+
+
+#ifndef QT_NO_ACCEL
+/*!
+ \property QAction::accel
+ \brief the action's accelerator key
+
+ The keycodes can be found in \l Qt::Key and \l Qt::Modifier. There
+ is no default accelerator key.
+*/
+//#### Please reimp for QActionGroup!
+//#### For consistency reasons even QActionGroups should respond to
+//#### their accelerators and e.g. open the relevant submenu.
+//#### Please change appropriate QActionGroup class doc after
+//#### reimplementation.
+void QAction::setAccel( const QKeySequence& key )
+{
+ if ( d->key == key )
+ return;
+
+ d->key = key;
+ delete d->accel;
+ d->accel = 0;
+
+ if ( !(int)key ) {
+ d->update();
+ return;
+ }
+
+ QObject* p = parent();
+ while ( p && !p->isWidgetType() ) {
+ p = p->parent();
+ }
+ if ( p ) {
+ d->accel = new QAccel( (QWidget*)p, this, "qt_action_accel" );
+ d->accelid = d->accel->insertItem( d->key );
+ d->accel->connectItem( d->accelid, this, SLOT( internalActivation() ) );
+ }
+#if defined(QT_CHECK_STATE)
+ else
+ qWarning( "QAction::setAccel() (%s) requires widget in parent chain", name() );
+#endif
+ d->update();
+}
+
+
+QKeySequence QAction::accel() const
+{
+ return d->key;
+}
+#endif
+
+
+/*!
+ \property QAction::toggleAction
+ \brief whether the action is a toggle action
+
+ A toggle action is one which has an on/off state. For example a
+ Bold toolbar button is either on or off. An action which is not a
+ toggle action is a command action; a command action is simply
+ executed, e.g. file save. This property's default is FALSE.
+
+ In some situations, the state of one toggle action should depend
+ on the state of others. For example, "Left Align", "Center" and
+ "Right Align" toggle actions are mutually exclusive. To achieve
+ exclusive toggling, add the relevant toggle actions to a
+ QActionGroup with the \l QActionGroup::exclusive property set to
+ TRUE.
+*/
+void QAction::setToggleAction( bool enable )
+{
+ if ( enable == (bool)d->toggleaction )
+ return;
+
+ if ( !enable )
+ d->on = FALSE;
+
+ d->toggleaction = enable;
+ d->update();
+}
+
+bool QAction::isToggleAction() const
+{
+ return d->toggleaction;
+}
+
+/*!
+ Activates the action and executes all connected slots.
+ This only works for actions that are not toggle action.
+
+ \sa toggle()
+*/
+void QAction::activate()
+{
+ if ( isToggleAction() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QAction::%s() (%s) Toggle actions "
+ "can not be activated", "activate", name() );
+#endif
+ return;
+ }
+ emit activated();
+}
+
+/*!
+ Toggles the state of a toggle action.
+
+ \sa on, activate(), toggled(), isToggleAction()
+*/
+void QAction::toggle()
+{
+ if ( !isToggleAction() ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QAction::%s() (%s) Only toggle actions "
+ "can be switched", "toggle", name() );
+#endif
+ return;
+ }
+ setOn( !isOn() );
+}
+
+/*!
+ \property QAction::on
+ \brief whether a toggle action is on
+
+ This property is always on (TRUE) for command actions and
+ \l{QActionGroup}s; setOn() has no effect on them. For action's
+ where isToggleAction() is TRUE, this property's default value is
+ off (FALSE).
+
+ \sa toggleAction
+*/
+void QAction::setOn( bool enable )
+{
+ if ( !isToggleAction() ) {
+#if defined(QT_CHECK_STATE)
+ if ( enable )
+ qWarning( "QAction::%s() (%s) Only toggle actions "
+ "can be switched", "setOn", name() );
+#endif
+ return;
+ }
+ if ( enable == (bool)d->on )
+ return;
+ d->on = enable;
+ d->update( QActionPrivate::State );
+ emit toggled( enable );
+}
+
+bool QAction::isOn() const
+{
+ return d->on;
+}
+
+/*!
+ \property QAction::enabled
+ \brief whether the action is enabled
+
+ Disabled actions can't be chosen by the user. They don't disappear
+ from the menu/tool bar but are displayed in a way which indicates
+ that they are unavailable, e.g. they might be displayed grayed
+ out.
+
+ What's this? help on disabled actions is still available provided
+ the \l QAction::whatsThis property is set.
+*/
+void QAction::setEnabled( bool enable )
+{
+ d->forceDisabled = !enable;
+
+ if ( (bool)d->enabled == enable )
+ return;
+
+ d->enabled = enable;
+ d->update( QActionPrivate::State );
+}
+
+bool QAction::isEnabled() const
+{
+ return d->enabled;
+}
+
+/*!
+ Disables the action if \a disable is TRUE; otherwise
+ enables the action.
+
+ See the \l enabled documentation for more information.
+*/
+void QAction::setDisabled( bool disable )
+{
+ setEnabled( !disable );
+}
+
+/*!
+ \property QAction::visible
+ \brief whether the action can be seen (e.g. in menus and toolbars)
+
+ If \e visible is TRUE the action can be seen (e.g. in menus and
+ toolbars) and chosen by the user; if \e visible is FALSE the
+ action cannot be seen or chosen by the user.
+
+ Actions which are not visible are \e not grayed out; they do not
+ appear at all.
+*/
+void QAction::setVisible( bool visible )
+{
+ d->forceInvisible = !visible;
+
+ if ( (bool)d->visible == visible )
+ return;
+ d->visible = visible;
+ d->update( QActionPrivate::Visibility );
+#if (QT_VERSION-0 >= 0x040000)
+#error "QAction::setVisible function wants to be virtual. Also add virtual change() function"
+#endif
+ if ( d->d_group ) //### this function wants to be virtual in 4.0
+ d->d_group->update( (QActionGroup*) this );
+}
+
+/*
+ Returns TRUE if the action is visible (e.g. in menus and
+ toolbars); otherwise returns FALSE.
+*/
+bool QAction::isVisible() const
+{
+ return d->visible;
+}
+
+/*! \internal
+*/
+void QAction::internalActivation()
+{
+ if ( isToggleAction() )
+ setOn( !isOn() );
+ emit activated();
+}
+
+/*! \internal
+*/
+void QAction::toolButtonToggled( bool on )
+{
+ if ( !isToggleAction() )
+ return;
+ setOn( on );
+}
+
+/*!
+ Adds this action to widget \a w.
+
+ Currently actions may be added to QToolBar and QPopupMenu widgets.
+
+ An action added to a tool bar is automatically displayed as a tool
+ button; an action added to a pop up menu appears as a menu option.
+
+ addTo() returns TRUE if the action was added successfully and
+ FALSE otherwise. (If \a w is not a QToolBar or QPopupMenu the
+ action will not be added and FALSE will be returned.)
+
+ \sa removeFrom()
+*/
+bool QAction::addTo( QWidget* w )
+{
+#ifndef QT_NO_TOOLBAR
+ if ( ::qt_cast<QToolBar*>(w) ) {
+ if ( !qstrcmp( name(), "qt_separator_action" ) ) {
+ ((QToolBar*)w)->addSeparator();
+ } else {
+ QCString bname = name() + QCString( "_action_button" );
+ QToolButton* btn = new QToolButton( (QToolBar*) w, bname );
+ addedTo( btn, w );
+ btn->setToggleButton( d->toggleaction );
+ d->toolbuttons.append( btn );
+ if ( d->iconset )
+ btn->setIconSet( *d->iconset );
+ d->update( QActionPrivate::State | QActionPrivate::Visibility | QActionPrivate::EverythingElse ) ;
+ connect( btn, SIGNAL( clicked() ), this, SIGNAL( activated() ) );
+ connect( btn, SIGNAL( toggled(bool) ), this, SLOT( toolButtonToggled(bool) ) );
+ connect( btn, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
+#ifndef QT_NO_TOOLTIP
+ connect( &(d->tipGroup), SIGNAL(showTip(const QString&)), this, SLOT(showStatusText(const QString&)) );
+ connect( &(d->tipGroup), SIGNAL(removeTip()), this, SLOT(clearStatusText()) );
+#endif
+ }
+ } else
+#endif
+ if ( ::qt_cast<QPopupMenu*>(w) ) {
+ QActionPrivate::MenuItem* mi = new QActionPrivate::MenuItem;
+ mi->popup = (QPopupMenu*) w;
+ QIconSet* diconset = d->iconset;
+ if ( !qstrcmp( name(), "qt_separator_action" ) )
+ mi->id = ((QPopupMenu*)w)->insertSeparator();
+ else if ( diconset )
+ mi->id = mi->popup->insertItem( *diconset, QString::fromLatin1("") );
+ else
+ mi->id = mi->popup->insertItem( QString::fromLatin1("") );
+ addedTo( mi->popup->indexOf( mi->id ), mi->popup );
+ mi->popup->connectItem( mi->id, this, SLOT(internalActivation()) );
+ d->menuitems.append( mi );
+ d->update( QActionPrivate::State | QActionPrivate::Visibility | QActionPrivate::EverythingElse ) ;
+ w->topLevelWidget()->className();
+ connect( mi->popup, SIGNAL(highlighted(int)), this, SLOT(menuStatusText(int)) );
+ connect( mi->popup, SIGNAL(aboutToHide()), this, SLOT(clearStatusText()) );
+ connect( mi->popup, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
+ // Makes only sense when called by QActionGroup::addTo
+ } else if ( ::qt_cast<QComboBox*>(w) ) {
+ QActionPrivate::ComboItem *ci = new QActionPrivate::ComboItem;
+ ci->combo = (QComboBox*)w;
+ connect( ci->combo, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
+ ci->id = ci->combo->count();
+ if ( qstrcmp( name(), "qt_separator_action" ) ) {
+ if ( d->iconset )
+ ci->combo->insertItem( d->iconset->pixmap(), text() );
+ else
+ ci->combo->insertItem( text() );
+ } else {
+ ci->id = -1;
+ }
+ d->comboitems.append( ci );
+
+ d->update( QActionPrivate::State | QActionPrivate::EverythingElse );
+ } else {
+ qWarning( "QAction::addTo(), unknown object" );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*!
+ This function is called from the addTo() function when it has
+ created a widget (\a actionWidget) for the action in the \a
+ container.
+*/
+
+void QAction::addedTo( QWidget *actionWidget, QWidget *container )
+{
+ Q_UNUSED( actionWidget );
+ Q_UNUSED( container );
+}
+
+/*!
+ \overload
+
+ This function is called from the addTo() function when it has
+ created a menu item at the index position \a index in the popup
+ menu \a menu.
+*/
+
+void QAction::addedTo( int index, QPopupMenu *menu )
+{
+ Q_UNUSED( index );
+ Q_UNUSED( menu );
+}
+
+/*!
+ Sets the status message to \a text
+*/
+void QAction::showStatusText( const QString& text )
+{
+#ifndef QT_NO_STATUSBAR
+ // find out whether we are clearing the status bar by the popup that actually set the text
+ static QPopupMenu *lastmenu = 0;
+ QObject *s = (QObject*)sender();
+ if ( s ) {
+ QPopupMenu *menu = (QPopupMenu*)s->qt_cast( "QPopupMenu" );
+ if ( menu && !!text )
+ lastmenu = menu;
+ else if ( menu && text.isEmpty() ) {
+ if ( lastmenu && menu != lastmenu )
+ return;
+ lastmenu = 0;
+ }
+ }
+
+ QObject* par = parent();
+ QObject* lpar = 0;
+ QStatusBar *bar = 0;
+ while ( par && !bar ) {
+ lpar = par;
+ bar = (QStatusBar*)par->child( 0, "QStatusBar", FALSE );
+ par = par->parent();
+ }
+ if ( !bar && lpar ) {
+ QObjectList *l = lpar->queryList( "QStatusBar" );
+ if ( !l )
+ return;
+ // #### hopefully the last one is the one of the mainwindow...
+ bar = (QStatusBar*)l->last();
+ delete l;
+ }
+ if ( bar ) {
+ if ( text.isEmpty() )
+ bar->clear();
+ else
+ bar->message( text );
+ }
+#endif
+}
+
+/*!
+ Sets the status message to the menu item's status text, or to the
+ tooltip, if there is no status text.
+*/
+void QAction::menuStatusText( int id )
+{
+ static int lastId = 0;
+ QString text;
+ QPtrListIterator<QActionPrivate::MenuItem> it( d->menuitems);
+ QActionPrivate::MenuItem* mi;
+ while ( ( mi = it.current() ) ) {
+ ++it;
+ if ( mi->id == id ) {
+ text = statusTip();
+ break;
+ }
+ }
+
+ if ( !text.isEmpty() )
+ showStatusText( text );
+ else if ( id != lastId )
+ clearStatusText();
+ lastId = id;
+}
+
+/*!
+ Clears the status text.
+*/
+void QAction::clearStatusText()
+{
+ if (!statusTip().isEmpty())
+ showStatusText( QString::null );
+}
+
+/*!
+ Removes the action from widget \a w.
+
+ Returns TRUE if the action was removed successfully; otherwise
+ returns FALSE.
+
+ \sa addTo()
+*/
+bool QAction::removeFrom( QWidget* w )
+{
+#ifndef QT_NO_TOOLBAR
+ if ( ::qt_cast<QToolBar*>(w) ) {
+ QPtrListIterator<QToolButton> it( d->toolbuttons);
+ QToolButton* btn;
+ while ( ( btn = it.current() ) ) {
+ ++it;
+ if ( btn->parentWidget() == w ) {
+ d->toolbuttons.removeRef( btn );
+ disconnect( btn, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
+ delete btn;
+ // no need to disconnect from statusbar
+ }
+ }
+ } else
+#endif
+ if ( ::qt_cast<QPopupMenu*>(w) ) {
+ QPtrListIterator<QActionPrivate::MenuItem> it( d->menuitems);
+ QActionPrivate::MenuItem* mi;
+ while ( ( mi = it.current() ) ) {
+ ++it;
+ if ( mi->popup == w ) {
+ disconnect( mi->popup, SIGNAL(highlighted(int)), this, SLOT(menuStatusText(int)) );
+ disconnect( mi->popup, SIGNAL(aboutToHide()), this, SLOT(clearStatusText()) );
+ disconnect( mi->popup, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
+ mi->popup->removeItem( mi->id );
+ d->menuitems.removeRef( mi );
+ }
+ }
+ } else if ( ::qt_cast<QComboBox*>(w) ) {
+ QPtrListIterator<QActionPrivate::ComboItem> it( d->comboitems );
+ QActionPrivate::ComboItem *ci;
+ while ( ( ci = it.current() ) ) {
+ ++it;
+ if ( ci->combo == w ) {
+ disconnect( ci->combo, SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
+ d->comboitems.removeRef( ci );
+ }
+ }
+ } else {
+ qWarning( "QAction::removeFrom(), unknown object" );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*!
+ \internal
+*/
+void QAction::objectDestroyed()
+{
+ const QObject* obj = sender();
+ QPtrListIterator<QActionPrivate::MenuItem> it( d->menuitems );
+ QActionPrivate::MenuItem* mi;
+ while ( ( mi = it.current() ) ) {
+ ++it;
+ if ( mi->popup == obj )
+ d->menuitems.removeRef( mi );
+ }
+ QActionPrivate::ComboItem *ci;
+ QPtrListIterator<QActionPrivate::ComboItem> it2( d->comboitems );
+ while ( ( ci = it2.current() ) ) {
+ ++it2;
+ if ( ci->combo == obj )
+ d->comboitems.removeRef( ci );
+ }
+ d->toolbuttons.removeRef( (QToolButton*) obj );
+}
+
+/*!
+ \fn void QAction::activated()
+
+ This signal is emitted when an action is activated by the user,
+ e.g. when the user clicks a menu option or a toolbar button or
+ presses an action's accelerator key combination.
+
+ Connect to this signal for command actions. Connect to the
+ toggled() signal for toggle actions.
+*/
+
+/*!
+ \fn void QAction::toggled(bool on)
+
+ This signal is emitted when a toggle action changes state; command
+ actions and \l{QActionGroup}s don't emit toggled().
+
+ The \a on argument denotes the new state: If \a on is TRUE the
+ toggle action is switched on, and if \a on is FALSE the toggle
+ action is switched off.
+
+ To trigger a user command depending on whether a toggle action has
+ been switched on or off connect it to a slot that takes a bool to
+ indicate the state, e.g.
+
+ \quotefile action/toggleaction/toggleaction.cpp
+ \skipto QMainWindow * window
+ \printline QMainWindow * window
+ \skipto labelonoffaction
+ \printline labelonoffaction
+ \skipto connect
+ \printuntil setUsesTextLabel
+
+ \sa activated() setToggleAction() setOn()
+*/
+
+void QActionGroupPrivate::update( const QActionGroup* that )
+{
+ for ( QPtrListIterator<QAction> it( actions ); it.current(); ++it ) {
+ if ( that->isEnabled() && !it.current()->d->forceDisabled ) {
+ it.current()->setEnabled( TRUE );
+ } else if ( !that->isEnabled() && it.current()->isEnabled() ) {
+ it.current()->setEnabled( FALSE );
+ it.current()->d->forceDisabled = FALSE;
+ }
+ if ( that->isVisible() && !it.current()->d->forceInvisible ) {
+ it.current()->setVisible( TRUE );
+ } else if ( !that->isVisible() && it.current()->isVisible() ) {
+ it.current()->setVisible( FALSE );
+ it.current()->d->forceInvisible = FALSE;
+ }
+ }
+ for ( QPtrListIterator<QComboBox> cb( comboboxes ); cb.current(); ++cb ) {
+ QComboBox *combobox = cb.current();
+ combobox->setEnabled( that->isEnabled() );
+ combobox->setShown( that->isVisible() );
+
+#ifndef QT_NO_TOOLTIP
+ QToolTip::remove( combobox );
+ if ( !!that->toolTip() )
+ QToolTip::add( combobox, that->toolTip() );
+#endif
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::remove( combobox );
+ if ( !!that->whatsThis() )
+ QWhatsThis::add( combobox, that->whatsThis() );
+#endif
+
+ }
+ for ( QPtrListIterator<QToolButton> mb( menubuttons ); mb.current(); ++mb ) {
+ QToolButton *button = mb.current();
+ button->setEnabled( that->isEnabled() );
+ button->setShown( that->isVisible() );
+
+ if ( !that->text().isNull() )
+ button->setTextLabel( that->text() );
+ if ( !that->iconSet().isNull() )
+ button->setIconSet( that->iconSet() );
+
+#ifndef QT_NO_TOOLTIP
+ QToolTip::remove( mb.current() );
+ if ( !!that->toolTip() )
+ QToolTip::add( button, that->toolTip() );
+#endif
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::remove( button );
+ if ( !!that->whatsThis() )
+ QWhatsThis::add( button, that->whatsThis() );
+#endif
+ }
+ for ( QPtrListIterator<QActionGroupPrivate::MenuItem> pu( menuitems ); pu.current(); ++pu ) {
+ QWidget* parent = pu.current()->popup->parentWidget();
+ if ( ::qt_cast<QPopupMenu*>(parent) ) {
+ QPopupMenu* ppopup = (QPopupMenu*)parent;
+ ppopup->setItemEnabled( pu.current()->id, that->isEnabled() );
+ ppopup->setItemVisible( pu.current()->id, that->isVisible() );
+ } else {
+ pu.current()->popup->setEnabled( that->isEnabled() );
+ }
+ }
+ for ( QPtrListIterator<QPopupMenu> pm( popupmenus ); pm.current(); ++pm ) {
+ QPopupMenu *popup = pm.current();
+ QPopupMenu *parent = ::qt_cast<QPopupMenu*>(popup->parentWidget());
+ if ( !parent )
+ continue;
+
+ int index;
+ parent->findPopup( popup, &index );
+ int id = parent->idAt( index );
+ if ( !that->iconSet().isNull() )
+ parent->changeItem( id, that->iconSet(), that->menuText() );
+ else
+ parent->changeItem( id, that->menuText() );
+ parent->setItemEnabled( id, that->isEnabled() );
+#ifndef QT_NO_ACCEL
+ parent->setAccel( that->accel(), id );
+#endif
+ }
+}
+
+/*!
+ \class QActionGroup qaction.h
+ \brief The QActionGroup class groups actions together.
+
+ \ingroup basic
+ \ingroup application
+
+ In some situations it is useful to group actions together. For
+ example, if you have a left justify action, a right justify action
+ and a center action, only one of these actions should be active at
+ any one time, and one simple way of achieving this is to group the
+ actions together in an action group.
+
+ An action group can also be added to a menu or a toolbar as a
+ single unit, with all the actions within the action group
+ appearing as separate menu options and toolbar buttons.
+
+ Here's an example from examples/textedit:
+ \quotefile textedit/textedit.cpp
+ \skipto QActionGroup
+ \printuntil connect
+
+ Here we create a new action group. Since the action group is exclusive
+ by default, only one of the actions in the group is ever active at any
+ one time. We then connect the group's selected() signal to our
+ textAlign() slot.
+
+ \printuntil actionAlignLeft->setToggleAction
+
+ We create a left align action, add it to the toolbar and the menu
+ and make it a toggle action. We create center and right align
+ actions in exactly the same way.
+
+ \omit
+ A QActionGroup emits an activated() signal when one of its actions
+ is activated.
+ \endomit
+ The actions in an action group emit their activated() (and for
+ toggle actions, toggled()) signals as usual.
+
+ The setExclusive() function is used to ensure that only one action
+ is active at any one time: it should be used with actions which
+ have their \c toggleAction set to TRUE.
+
+ Action group actions appear as individual menu options and toolbar
+ buttons. For exclusive action groups use setUsesDropDown() to
+ display the actions in a subwidget of any widget the action group
+ is added to. For example, the actions would appear in a combobox
+ in a toolbar or as a submenu in a menu.
+
+ Actions can be added to an action group using add(), but normally
+ they are added by creating the action with the action group as
+ parent. Actions can have separators dividing them using
+ addSeparator(). Action groups are added to widgets with addTo().
+*/
+
+/*!
+ Constructs an action group called \a name, with parent \a parent.
+
+ The action group is exclusive by default. Call setExclusive(FALSE) to make
+ the action group non-exclusive.
+*/
+QActionGroup::QActionGroup( QObject* parent, const char* name )
+ : QAction( parent, name )
+{
+ d = new QActionGroupPrivate;
+ d->exclusive = TRUE;
+ d->dropdown = FALSE;
+ d->selected = 0;
+ d->separatorAction = 0;
+ QAction::d->d_group = d;
+
+ connect( this, SIGNAL(selected(QAction*)), SLOT(internalToggle(QAction*)) );
+}
+
+/*!
+ Constructs an action group called \a name, with parent \a parent.
+
+ If \a exclusive is TRUE only one toggle action in the group will
+ ever be active.
+
+ \sa exclusive
+*/
+QActionGroup::QActionGroup( QObject* parent, const char* name, bool exclusive )
+ : QAction( parent, name )
+{
+ d = new QActionGroupPrivate;
+ d->exclusive = exclusive;
+ d->dropdown = FALSE;
+ d->selected = 0;
+ d->separatorAction = 0;
+ QAction::d->d_group = d;
+
+ connect( this, SIGNAL(selected(QAction*)), SLOT(internalToggle(QAction*)) );
+}
+
+/*!
+ Destroys the object and frees allocated resources.
+*/
+
+QActionGroup::~QActionGroup()
+{
+ QPtrListIterator<QActionGroupPrivate::MenuItem> mit( d->menuitems );
+ while ( mit.current() ) {
+ QActionGroupPrivate::MenuItem *mi = mit.current();
+ ++mit;
+ if ( mi->popup )
+ mi->popup->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
+ }
+
+ QPtrListIterator<QComboBox> cbit( d->comboboxes );
+ while ( cbit.current() ) {
+ QComboBox *cb = cbit.current();
+ ++cbit;
+ cb->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
+ }
+ QPtrListIterator<QToolButton> mbit( d->menubuttons );
+ while ( mbit.current() ) {
+ QToolButton *mb = mbit.current();
+ ++mbit;
+ mb->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
+ }
+ QPtrListIterator<QPopupMenu> pmit( d->popupmenus );
+ while ( pmit.current() ) {
+ QPopupMenu *pm = pmit.current();
+ ++pmit;
+ pm->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
+ }
+
+ delete d->separatorAction;
+ d->menubuttons.setAutoDelete( TRUE );
+ d->comboboxes.setAutoDelete( TRUE );
+ d->menuitems.setAutoDelete( TRUE );
+ d->popupmenus.setAutoDelete( TRUE );
+ delete d;
+}
+
+/*!
+ \property QActionGroup::exclusive
+ \brief whether the action group does exclusive toggling
+
+ If exclusive is TRUE only one toggle action in the action group
+ can ever be active at any one time. If the user chooses another
+ toggle action in the group the one they chose becomes active and
+ the one that was active becomes inactive.
+
+ \sa QAction::toggleAction
+*/
+void QActionGroup::setExclusive( bool enable )
+{
+ d->exclusive = enable;
+}
+
+bool QActionGroup::isExclusive() const
+{
+ return d->exclusive;
+}
+
+/*!
+ \property QActionGroup::usesDropDown
+ \brief whether the group's actions are displayed in a subwidget of
+ the widgets the action group is added to
+
+ Exclusive action groups added to a toolbar display their actions
+ in a combobox with the action's \l QAction::text and \l
+ QAction::iconSet properties shown. Non-exclusive groups are
+ represented by a tool button showing their \l QAction::iconSet and
+ -- depending on \l QMainWindow::usesTextLabel() -- text()
+ property.
+
+ In a popup menu the member actions are displayed in a submenu.
+
+ Changing usesDropDown only affects \e subsequent calls to addTo().
+
+ Note that setting this property for actions in a combobox causes
+ calls to their \link QAction::setVisible()\endlink,
+ \link QAction::setEnabled()\endlink, and
+ \link QAction::setDisabled()\endlink functions to have no effect.
+
+ This property's default is FALSE.
+
+*/
+void QActionGroup::setUsesDropDown( bool enable )
+{
+ d->dropdown = enable;
+}
+
+bool QActionGroup::usesDropDown() const
+{
+ return d->dropdown;
+}
+
+/*!
+ Adds action \a action to this group.
+
+ Normally an action is added to a group by creating it with the
+ group as parent, so this function is not usually used.
+
+ \sa addTo()
+*/
+void QActionGroup::add( QAction* action )
+{
+ if ( d->actions.containsRef( action ) )
+ return;
+
+ d->actions.append( action );
+
+ if ( action->whatsThis().isNull() )
+ action->setWhatsThis( whatsThis() );
+ if ( action->toolTip().isNull() )
+ action->setToolTip( toolTip() );
+
+ if (!action->d->forceDisabled)
+ action->d->enabled = isEnabled();
+ if (!action->d->forceInvisible)
+ action->d->visible = isVisible();
+
+ connect( action, SIGNAL( destroyed() ), this, SLOT( childDestroyed() ) );
+ connect( action, SIGNAL( activated() ), this, SIGNAL( activated() ) );
+ connect( action, SIGNAL( toggled(bool) ), this, SLOT( childToggled(bool) ) );
+
+ for ( QPtrListIterator<QComboBox> cb( d->comboboxes ); cb.current(); ++cb ) {
+ action->addTo( cb.current() );
+ }
+ for ( QPtrListIterator<QToolButton> mb( d->menubuttons ); mb.current(); ++mb ) {
+ QPopupMenu* popup = mb.current()->popup();
+ if ( !popup )
+ continue;
+ action->addTo( popup );
+ }
+ for ( QPtrListIterator<QActionGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
+ QPopupMenu* popup = mi.current()->popup;
+ if ( !popup )
+ continue;
+ action->addTo( popup );
+ }
+}
+
+/*!
+ Adds a separator to the group.
+*/
+void QActionGroup::addSeparator()
+{
+ if ( !d->separatorAction )
+ d->separatorAction = new QAction( 0, "qt_separator_action" );
+ d->actions.append( d->separatorAction );
+}
+
+
+/*! \fn void QActionGroup::insert( QAction* a )
+
+ \obsolete
+
+ Use add() instead, or better still create the action with the action
+ group as its parent.
+ */
+
+/*!
+ Adds this action group to the widget \a w.
+
+ If isExclusive() is FALSE or usesDropDown() is FALSE, the actions within
+ the group are added to the widget individually. For example, if the widget
+ is a menu, the actions will appear as individual menu options, and
+ if the widget is a toolbar, the actions will appear as toolbar buttons.
+
+ If both isExclusive() and usesDropDown() are TRUE, the actions
+ are presented either in a combobox (if \a w is a toolbar) or in a
+ submenu (if \a w is a menu).
+
+ All actions should be added to the action group \e before the
+ action group is added to the widget. If actions are added to the
+ action group \e after the action group has been added to the
+ widget these later actions will \e not appear.
+
+ \sa setExclusive() setUsesDropDown() removeFrom()
+*/
+bool QActionGroup::addTo( QWidget* w )
+{
+#ifndef QT_NO_TOOLBAR
+ if ( ::qt_cast<QToolBar*>(w) ) {
+ if ( d->dropdown ) {
+ if ( !d->exclusive ) {
+ QPtrListIterator<QAction> it( d->actions);
+ if ( !it.current() )
+ return TRUE;
+
+ QAction *defAction = it.current();
+
+ QToolButton* btn = new QToolButton( (QToolBar*) w, "qt_actiongroup_btn" );
+ addedTo( btn, w );
+ connect( btn, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
+ d->menubuttons.append( btn );
+
+ if ( !iconSet().isNull() )
+ btn->setIconSet( iconSet() );
+ else if ( !defAction->iconSet().isNull() )
+ btn->setIconSet( defAction->iconSet() );
+ if ( !!text() )
+ btn->setTextLabel( text() );
+ else if ( !!defAction->text() )
+ btn->setTextLabel( defAction->text() );
+#ifndef QT_NO_TOOLTIP
+ if ( !!toolTip() )
+ QToolTip::add( btn, toolTip() );
+ else if ( !!defAction->toolTip() )
+ QToolTip::add( btn, defAction->toolTip() );
+#endif
+#ifndef QT_NO_WHATSTHIS
+ if ( !!whatsThis() )
+ QWhatsThis::add( btn, whatsThis() );
+ else if ( !!defAction->whatsThis() )
+ QWhatsThis::add( btn, defAction->whatsThis() );
+#endif
+
+ connect( btn, SIGNAL( clicked() ), defAction, SIGNAL( activated() ) );
+ connect( btn, SIGNAL( toggled(bool) ), defAction, SLOT( toolButtonToggled(bool) ) );
+ connect( btn, SIGNAL( destroyed() ), defAction, SLOT( objectDestroyed() ) );
+
+ QPopupMenu *menu = new QPopupMenu( btn, "qt_actiongroup_menu" );
+ btn->setPopupDelay( 0 );
+ btn->setPopup( menu );
+
+ while( it.current() ) {
+ it.current()->addTo( menu );
+ ++it;
+ }
+ d->update( this );
+ return TRUE;
+ } else {
+ QComboBox *box = new QComboBox( FALSE, w, "qt_actiongroup_combo" );
+ addedTo( box, w );
+ connect( box, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
+ d->comboboxes.append( box );
+#ifndef QT_NO_TOOLTIP
+ if ( !!toolTip() )
+ QToolTip::add( box, toolTip() );
+#endif
+#ifndef QT_NO_WHATSTHIS
+ if ( !!whatsThis() )
+ QWhatsThis::add( box, whatsThis() );
+#endif
+
+ int onIndex = 0;
+ bool foundOn = FALSE;
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ QAction *action = it.current();
+ if ( !foundOn )
+ foundOn = action->isOn();
+ if ( qstrcmp( action->name(), "qt_separator_action" ) && !foundOn )
+ onIndex++;
+ action->addTo( box );
+ }
+ if ( foundOn )
+ box->setCurrentItem( onIndex );
+ connect( box, SIGNAL(activated(int)), this, SLOT( internalComboBoxActivated(int)) );
+ connect( box, SIGNAL(highlighted(int)), this, SLOT( internalComboBoxHighlighted(int)) );
+ d->update( this );
+ return TRUE;
+ }
+ }
+ } else
+#endif
+ if ( ::qt_cast<QPopupMenu*>(w) ) {
+ QPopupMenu *popup;
+ if ( d->dropdown ) {
+ QPopupMenu *menu = (QPopupMenu*)w;
+ popup = new QPopupMenu( w, "qt_actiongroup_menu" );
+ d->popupmenus.append( popup );
+ connect( popup, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
+
+ int id;
+ if ( !iconSet().isNull() ) {
+ if ( menuText().isEmpty() )
+ id = menu->insertItem( iconSet(), text(), popup );
+ else
+ id = menu->insertItem( iconSet(), menuText(), popup );
+ } else {
+ if ( menuText().isEmpty() )
+ id = menu->insertItem( text(), popup );
+ else
+ id = menu->insertItem( menuText(), popup );
+ }
+
+ addedTo( menu->indexOf( id ), menu );
+
+ QActionGroupPrivate::MenuItem *item = new QActionGroupPrivate::MenuItem;
+ item->id = id;
+ item->popup = popup;
+ d->menuitems.append( item );
+ } else {
+ popup = (QPopupMenu*)w;
+ }
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ // #### do an addedTo( index, popup, action), need to find out index
+ it.current()->addTo( popup );
+ }
+ return TRUE;
+ }
+
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ // #### do an addedTo( index, popup, action), need to find out index
+ it.current()->addTo( w );
+ }
+
+ return TRUE;
+}
+
+/*! \reimp
+*/
+bool QActionGroup::removeFrom( QWidget* w )
+{
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ it.current()->removeFrom( w );
+ }
+
+#ifndef QT_NO_TOOLBAR
+ if ( ::qt_cast<QToolBar*>(w) ) {
+ QPtrListIterator<QComboBox> cb( d->comboboxes );
+ while( cb.current() ) {
+ QComboBox *box = cb.current();
+ ++cb;
+ if ( box->parentWidget() == w )
+ delete box;
+ }
+ QPtrListIterator<QToolButton> mb( d->menubuttons );
+ while( mb.current() ) {
+ QToolButton *btn = mb.current();
+ ++mb;
+ if ( btn->parentWidget() == w )
+ delete btn;
+ }
+ } else
+#endif
+ if ( ::qt_cast<QPopupMenu*>(w) ) {
+ QPtrListIterator<QActionGroupPrivate::MenuItem> pu( d->menuitems );
+ while ( pu.current() ) {
+ QActionGroupPrivate::MenuItem *mi = pu.current();
+ ++pu;
+ if ( d->dropdown && mi->popup )
+ ( (QPopupMenu*)w )->removeItem( mi->id );
+ delete mi->popup;
+ }
+ }
+
+ return TRUE;
+}
+
+/*! \internal
+*/
+void QActionGroup::childToggled( bool b )
+{
+ if ( !isExclusive() )
+ return;
+ QAction* s = (QAction*) sender();
+ if ( b ) {
+ if ( s != d->selected ) {
+ d->selected = s;
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ if ( it.current()->isToggleAction() && it.current() != s )
+ it.current()->setOn( FALSE );
+ }
+ emit activated();
+ emit selected( s );
+ } else if ( !s->isToggleAction() ) {
+ emit activated();
+ }
+ } else {
+ if ( s == d->selected ) {
+ // at least one has to be selected
+ s->setOn( TRUE );
+ }
+ }
+}
+
+/*! \internal
+*/
+void QActionGroup::childDestroyed()
+{
+ d->actions.removeRef( (QAction*) sender() );
+ if ( d->selected == sender() )
+ d->selected = 0;
+}
+
+/*! \reimp
+*/
+void QActionGroup::setEnabled( bool enable )
+{
+ if ( enable == isEnabled() )
+ return;
+
+ QAction::setEnabled( enable );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setToggleAction( bool toggle )
+{
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it )
+ it.current()->setToggleAction( toggle );
+
+ QAction::setToggleAction( TRUE );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setOn( bool on )
+{
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ QAction *act = it.current();
+ if ( act->isToggleAction() )
+ act->setOn( on );
+ }
+
+ QAction::setOn( on );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setIconSet( const QIconSet& icon )
+{
+ QAction::setIconSet( icon );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setText( const QString& txt )
+{
+ if ( txt == text() )
+ return;
+
+ QAction::setText( txt );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setMenuText( const QString& text )
+{
+ if ( text == menuText() )
+ return;
+
+ QAction::setMenuText( text );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setToolTip( const QString& text )
+{
+ if ( text == toolTip() )
+ return;
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ if ( it.current()->toolTip().isNull() )
+ it.current()->setToolTip( text );
+ }
+ QAction::setToolTip( text );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::setWhatsThis( const QString& text )
+{
+ if ( text == whatsThis() )
+ return;
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ if ( it.current()->whatsThis().isNull() )
+ it.current()->setWhatsThis( text );
+ }
+ QAction::setWhatsThis( text );
+ d->update( this );
+}
+
+/*! \reimp
+*/
+void QActionGroup::childEvent( QChildEvent *e )
+{
+ if ( !e->removed() )
+ return;
+
+ QAction *action = ::qt_cast<QAction*>(e->child());
+ if ( !action )
+ return;
+
+ for ( QPtrListIterator<QComboBox> cb( d->comboboxes ); cb.current(); ++cb ) {
+ for ( int i = 0; i < cb.current()->count(); i++ ) {
+ if ( cb.current()->text( i ) == action->text() ) {
+ cb.current()->removeItem( i );
+ break;
+ }
+ }
+ }
+ for ( QPtrListIterator<QToolButton> mb( d->menubuttons ); mb.current(); ++mb ) {
+ QPopupMenu* popup = mb.current()->popup();
+ if ( !popup )
+ continue;
+ action->removeFrom( popup );
+ }
+ for ( QPtrListIterator<QActionGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
+ QPopupMenu* popup = mi.current()->popup;
+ if ( !popup )
+ continue;
+ action->removeFrom( popup );
+ }
+}
+
+/*!
+ \fn void QActionGroup::selected( QAction* )
+
+ This signal is emitted from exclusive groups when toggle actions
+ change state.
+
+ The argument is the action whose state changed to "on".
+
+ \sa setExclusive(), isOn() QAction::toggled()
+*/
+
+/*! \internal
+*/
+void QActionGroup::internalComboBoxActivated( int index )
+{
+ QAction *a = 0;
+ for ( int i = 0; i <= index && i < (int)d->actions.count(); ++i ) {
+ a = d->actions.at( i );
+ if ( a && !qstrcmp( a->name(), "qt_separator_action" ) )
+ index++;
+ }
+ a = d->actions.at( index );
+ if ( a ) {
+ if ( a != d->selected ) {
+ d->selected = a;
+ for ( QPtrListIterator<QAction> it( d->actions); it.current(); ++it ) {
+ if ( it.current()->isToggleAction() && it.current() != a )
+ it.current()->setOn( FALSE );
+ }
+ if ( a->isToggleAction() )
+ a->setOn( TRUE );
+
+ emit activated();
+ if ( a->isToggleAction() )
+ emit selected( d->selected );
+ emit ((QActionGroup*)a)->activated();
+ } else if ( !a->isToggleAction() ) {
+ emit activated();
+ emit ((QActionGroup*)a)->activated();
+ }
+ a->clearStatusText();
+ }
+}
+
+/*! \internal
+*/
+void QActionGroup::internalComboBoxHighlighted( int index )
+{
+ QAction *a = 0;
+ for ( int i = 0; i <= index && i < (int)d->actions.count(); ++i ) {
+ a = d->actions.at( i );
+ if ( a && !qstrcmp( a->name(), "qt_separator_action" ) )
+ index++;
+ }
+ a = d->actions.at( index );
+ if ( a )
+ a->showStatusText(a->statusTip());
+ else
+ clearStatusText();
+}
+
+/*! \internal
+*/
+void QActionGroup::internalToggle( QAction *a )
+{
+ int index = d->actions.find( a );
+ if ( index == -1 )
+ return;
+
+ int lastItem = index;
+ for ( int i = 0; i < lastItem; i++ ) {
+ QAction *action = d->actions.at( i );
+ if ( !qstrcmp( action->name(), "qt_separator_action" ) )
+ index--;
+ }
+
+ for ( QPtrListIterator<QComboBox> it( d->comboboxes); it.current(); ++it )
+ it.current()->setCurrentItem( index );
+}
+
+/*! \internal
+*/
+void QActionGroup::objectDestroyed()
+{
+ const QObject* obj = sender();
+ d->menubuttons.removeRef( (QToolButton*)obj );
+ for ( QPtrListIterator<QActionGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
+ if ( mi.current()->popup == obj ) {
+ d->menuitems.removeRef( mi.current() );
+ break;
+ }
+ }
+ d->popupmenus.removeRef( (QPopupMenu*)obj );
+ d->comboboxes.removeRef( (QComboBox*)obj );
+}
+
+/*!
+ \internal
+
+ This function is called from the addTo() function when it has
+ created a widget (\a actionWidget) for the child action \a a in
+ the \a container.
+*/
+
+void QActionGroup::addedTo( QWidget *actionWidget, QWidget *container, QAction *a )
+{
+ Q_UNUSED( actionWidget );
+ Q_UNUSED( container );
+ Q_UNUSED( a );
+}
+
+/*!
+ \overload
+ \internal
+
+ This function is called from the addTo() function when it has
+ created a menu item for the child action at the index position \a
+ index in the popup menu \a menu.
+*/
+
+void QActionGroup::addedTo( int index, QPopupMenu *menu, QAction *a )
+{
+ Q_UNUSED( index );
+ Q_UNUSED( menu );
+ Q_UNUSED( a );
+}
+
+/*!
+ \reimp
+ \overload
+
+ This function is called from the addTo() function when it has
+ created a widget (\a actionWidget) in the \a container.
+*/
+
+void QActionGroup::addedTo( QWidget *actionWidget, QWidget *container )
+{
+ Q_UNUSED( actionWidget );
+ Q_UNUSED( container );
+}
+
+/*!
+ \reimp
+ \overload
+
+ This function is called from the addTo() function when it has
+ created a menu item at the index position \a index in the popup
+ menu \a menu.
+*/
+
+void QActionGroup::addedTo( int index, QPopupMenu *menu )
+{
+ Q_UNUSED( index );
+ Q_UNUSED( menu );
+}
+
+#endif
diff --git a/src/widgets/qaction.h b/src/widgets/qaction.h
new file mode 100644
index 0000000..b6ec99c
--- /dev/null
+++ b/src/widgets/qaction.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Definition of QAction class
+**
+** Created : 000000
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QACTION_H
+#define QACTION_H
+
+#ifndef QT_H
+#include "qobject.h"
+#include "qiconset.h"
+#include "qstring.h"
+#include "qkeysequence.h"
+#endif // QT_H
+
+#ifndef QT_NO_ACTION
+
+class QActionPrivate;
+class QActionGroupPrivate;
+class QStatusBar;
+class QPopupMenu;
+class QToolTipGroup;
+
+class Q_EXPORT QAction : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY( bool toggleAction READ isToggleAction WRITE setToggleAction)
+ Q_PROPERTY( bool on READ isOn WRITE setOn )
+ Q_PROPERTY( bool enabled READ isEnabled WRITE setEnabled )
+ Q_PROPERTY( QIconSet iconSet READ iconSet WRITE setIconSet )
+ Q_PROPERTY( QString text READ text WRITE setText )
+ Q_PROPERTY( QString menuText READ menuText WRITE setMenuText )
+ Q_PROPERTY( QString toolTip READ toolTip WRITE setToolTip )
+ Q_PROPERTY( QString statusTip READ statusTip WRITE setStatusTip )
+ Q_PROPERTY( QString whatsThis READ whatsThis WRITE setWhatsThis )
+#ifndef QT_NO_ACCEL
+ Q_PROPERTY( QKeySequence accel READ accel WRITE setAccel )
+#endif
+ Q_PROPERTY( bool visible READ isVisible WRITE setVisible )
+
+public:
+ QAction( QObject* parent, const char* name = 0 );
+#ifndef QT_NO_ACCEL
+ QAction( const QString& menuText, QKeySequence accel,
+ QObject* parent, const char* name = 0 );
+ QAction( const QIconSet& icon, const QString& menuText, QKeySequence accel,
+ QObject* parent, const char* name = 0 );
+
+ QAction( const QString& text, const QIconSet& icon, const QString& menuText, QKeySequence accel,
+ QObject* parent, const char* name = 0, bool toggle = FALSE ); // obsolete
+ QAction( const QString& text, const QString& menuText, QKeySequence accel, QObject* parent,
+ const char* name = 0, bool toggle = FALSE ); // obsolete
+#endif
+ QAction( QObject* parent, const char* name , bool toggle ); // obsolete
+ ~QAction();
+
+ virtual void setIconSet( const QIconSet& );
+ QIconSet iconSet() const;
+ virtual void setText( const QString& );
+ QString text() const;
+ virtual void setMenuText( const QString& );
+ QString menuText() const;
+ virtual void setToolTip( const QString& );
+ QString toolTip() const;
+ virtual void setStatusTip( const QString& );
+ QString statusTip() const;
+ virtual void setWhatsThis( const QString& );
+ QString whatsThis() const;
+#ifndef QT_NO_ACCEL
+ virtual void setAccel( const QKeySequence& key );
+ QKeySequence accel() const;
+#endif
+ virtual void setToggleAction( bool );
+
+ bool isToggleAction() const;
+ bool isOn() const;
+ bool isEnabled() const;
+ bool isVisible() const;
+ virtual bool addTo( QWidget* );
+ virtual bool removeFrom( QWidget* );
+
+protected:
+ virtual void addedTo( QWidget *actionWidget, QWidget *container );
+ virtual void addedTo( int index, QPopupMenu *menu );
+
+public slots:
+ void activate();
+ void toggle();
+ virtual void setOn( bool );
+ virtual void setEnabled( bool );
+ void setDisabled( bool );
+ void setVisible( bool );
+
+signals:
+ void activated();
+ void toggled( bool );
+
+private slots:
+ void internalActivation();
+ void toolButtonToggled( bool );
+ void objectDestroyed();
+ void menuStatusText( int id );
+ void showStatusText( const QString& );
+ void clearStatusText();
+
+private:
+ void init();
+
+ friend class QActionGroup;
+ friend class QActionGroupPrivate;
+ QActionPrivate* d;
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ QAction( const QAction & );
+ QAction &operator=( const QAction & );
+#endif
+};
+
+class Q_EXPORT QActionGroup : public QAction
+{
+ Q_OBJECT
+ Q_PROPERTY( bool exclusive READ isExclusive WRITE setExclusive )
+ Q_PROPERTY( bool usesDropDown READ usesDropDown WRITE setUsesDropDown )
+
+public:
+ QActionGroup( QObject* parent, const char* name = 0 );
+ QActionGroup( QObject* parent, const char* name , bool exclusive ); // obsolete
+ ~QActionGroup();
+ void setExclusive( bool );
+ bool isExclusive() const;
+ void add( QAction* a);
+ void addSeparator();
+ bool addTo( QWidget* );
+ bool removeFrom( QWidget* );
+ void setEnabled( bool );
+ void setToggleAction( bool toggle );
+ void setOn( bool on );
+
+ void setUsesDropDown( bool enable );
+ bool usesDropDown() const;
+
+ void setIconSet( const QIconSet& );
+ void setText( const QString& );
+ void setMenuText( const QString& );
+ void setToolTip( const QString& );
+ void setWhatsThis( const QString& );
+
+protected:
+ void childEvent( QChildEvent* );
+ virtual void addedTo( QWidget *actionWidget, QWidget *container, QAction *a );
+ virtual void addedTo( int index, QPopupMenu *menu, QAction *a );
+ virtual void addedTo( QWidget *actionWidget, QWidget *container );
+ virtual void addedTo( int index, QPopupMenu *menu );
+
+signals:
+ void selected( QAction* );
+
+private slots:
+ void childToggled( bool );
+ void childDestroyed();
+ void internalComboBoxActivated( int );
+ void internalComboBoxHighlighted( int );
+ void internalToggle( QAction* );
+ void objectDestroyed();
+
+private:
+ QActionGroupPrivate* d;
+
+#ifndef QT_NO_COMPAT
+public:
+ void insert( QAction* a ) { add( a ); }
+#endif
+
+private:
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ QActionGroup( const QActionGroup & );
+ QActionGroup &operator=( const QActionGroup & );
+#endif
+};
+
+#endif
+
+#endif
diff --git a/src/widgets/qbutton.cpp b/src/widgets/qbutton.cpp
new file mode 100644
index 0000000..57178fb
--- /dev/null
+++ b/src/widgets/qbutton.cpp
@@ -0,0 +1,1008 @@
+/****************************************************************************
+**
+** Implementation of QButton widget class
+**
+** Created : 940206
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#undef QT_NO_COMPAT
+#include "qbutton.h"
+#ifndef QT_NO_BUTTON
+#include "qbuttongroup.h"
+#include "qbitmap.h"
+#include "qpainter.h"
+#include "qtimer.h"
+#include "qaccel.h"
+#include "qpixmapcache.h"
+#include "qapplication.h"
+#include "qpushbutton.h"
+#include "qradiobutton.h"
+#include "qguardedptr.h"
+#include "../kernel/qinternal_p.h"
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+#define AUTO_REPEAT_DELAY 300
+#define AUTO_REPEAT_PERIOD 100
+
+class QButtonData
+{
+public:
+ QButtonData() {
+#ifndef QT_NO_BUTTONGROUP
+ group = 0;
+#endif
+#ifndef QT_NO_ACCEL
+ a = 0;
+#endif
+ }
+#ifndef QT_NO_BUTTONGROUP
+ QButtonGroup *group;
+#endif
+ QTimer timer;
+#ifndef QT_NO_ACCEL
+ QAccel *a;
+#endif
+};
+
+
+void QButton::ensureData()
+{
+ if ( !d ) {
+ d = new QButtonData;
+ Q_CHECK_PTR( d );
+ connect(&d->timer, SIGNAL(timeout()), this, SLOT(autoRepeatTimeout()));
+ }
+}
+
+
+/*!
+ 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 *QButton::group() const
+{
+#ifndef QT_NO_BUTTONGROUP
+ return d ? d->group : 0;
+#else
+ return 0;
+#endif
+}
+
+
+void QButton::setGroup( QButtonGroup* g )
+{
+#ifndef QT_NO_BUTTONGROUP
+ ensureData();
+ d->group = g;
+#endif
+}
+
+
+QTimer *QButton::timer()
+{
+ ensureData();
+ return &d->timer;
+}
+
+
+/*!
+ \class QButton qbutton.h
+ \brief The QButton class is the abstract base class of button
+ widgets, providing functionality common to buttons.
+
+ \ingroup abstractwidgets
+
+ <b>If you want to create a button use QPushButton.</b>
+
+ The QButton class implements an \e abstract button, and lets
+ subclasses specify how to reply to user actions and how to draw
+ the button.
+
+ QButton provides both push and toggle buttons. The QRadioButton
+ and QCheckBox classes provide only toggle buttons; QPushButton and
+ QToolButton provide both toggle and push buttons.
+
+ Any button can have either a text or pixmap label. setText() sets
+ the button to be a text button and setPixmap() sets it to be a
+ pixmap button. The text/pixmap is manipulated as necessary to
+ create the "disabled" appearance when the button is disabled.
+
+ QButton provides most of the states used for buttons:
+ \list
+ \i isDown() indicates whether the button is \e pressed down.
+ \i isOn() indicates whether the button is \e on.
+ Only toggle buttons can be switched on and off (see below).
+ \i isEnabled() indicates whether the button can be pressed by the
+ user.
+ \i setAutoRepeat() sets whether the button will auto-repeat
+ if the user holds it down.
+ \i setToggleButton() sets whether the button is a toggle
+ button or not.
+ \endlist
+
+ The difference between isDown() and isOn() is as follows: When the
+ user clicks a toggle button to toggle it on, the button is first
+ \e pressed and then released into the \e on state. When the user
+ clicks it again (to toggle it off), the button moves first to the
+ \e pressed state, then to the \e off state (isOn() and isDown()
+ are both FALSE).
+
+ Default buttons (as used in many dialogs) are provided by
+ QPushButton::setDefault() and QPushButton::setAutoDefault().
+
+ QButton provides five signals:
+ \list 1
+ \i pressed() is emitted when the button is pressed. E.g. with the mouse
+ or when animateClick() is called.
+ \i released() is emitted when the button is released. E.g. when the mouse
+ is released or the cursor is moved outside the widget.
+ \i clicked() is emitted when the button is first pressed and then
+ released when the accelerator key is typed, or when
+ animateClick() is called.
+ \i toggled(bool) is emitted when the state of a toggle button changes.
+ \i stateChanged(int) is emitted when the state of a tristate
+ toggle button changes.
+ \endlist
+
+ If the button is a text button with an ampersand (\&) in its text,
+ QButton creates an automatic accelerator key. This code creates a
+ push button labelled "Ro<u>c</u>k \& Roll" (where the c is
+ underlined). The button gets an automatic accelerator key, Alt+C:
+
+ \code
+ QPushButton *p = new QPushButton( "Ro&ck && Roll", this );
+ \endcode
+
+ In this example, when the user presses Alt+C the button will call
+ animateClick().
+
+ You can also set a custom accelerator using the setAccel()
+ function. This is useful mostly for pixmap buttons because they
+ have no automatic accelerator.
+
+ \code
+ p->setPixmap( QPixmap("print.png") );
+ p->setAccel( ALT+Key_F7 );
+ \endcode
+
+ All of the buttons provided by Qt (\l QPushButton, \l QToolButton,
+ \l QCheckBox and \l QRadioButton) can display both text and
+ pixmaps.
+
+ To subclass QButton, you must reimplement at least drawButton()
+ (to draw the button's outline) and drawButtonLabel() (to draw 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).
+
+ To reduce flickering, QButton::paintEvent() sets up a pixmap that
+ the drawButton() function draws in. You should not reimplement
+ paintEvent() for a subclass of QButton unless you want to take
+ over all drawing.
+
+ \sa QButtonGroup
+*/
+
+
+/*!
+ \enum QButton::ToggleType
+
+ This enum type defines what a button can do in response to a
+ mouse/keyboard press:
+
+ \value SingleShot pressing the button causes an action, then the
+ button returns to the unpressed state.
+
+ \value Toggle pressing the button toggles it between an \c On and
+ an \c Off state.
+
+ \value Tristate pressing the button cycles between the three
+ states \c On, \c Off and \c NoChange
+*/
+
+/*!
+ \enum QButton::ToggleState
+
+ This enum defines the state of a toggle button.
+
+ \value Off the button is in the "off" state
+ \value NoChange the button is in the default/unchanged state
+ \value On the button is in the "on" state
+*/
+
+/*!
+ \property QButton::accel
+ \brief the accelerator associated with the button
+
+ This property is 0 if there is no accelerator set. If you set this
+ property to 0 then any current accelerator is removed.
+*/
+
+/*!
+ \property QButton::autoRepeat
+ \brief whether autoRepeat is enabled
+
+ If autoRepeat is enabled then the clicked() signal is emitted at
+ regular intervals if the button is down. This property has no
+ effect on toggle buttons. autoRepeat is off by default.
+*/
+
+/*! \property QButton::autoResize
+ \brief whether autoResize is enabled
+ \obsolete
+
+ If autoResize is enabled then the button will resize itself
+ whenever the contents are changed.
+*/
+
+/*!
+ \property QButton::down
+ \brief whether the button is pressed
+
+ 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.
+*/
+
+/*!
+ \property QButton::exclusiveToggle
+ \brief whether the button is an exclusive toggle
+
+ If this property is TRUE and the button is in a QButtonGroup, the
+ button can only be toggled off by another one being toggled on.
+ The default is FALSE.
+*/
+
+/*!
+ \property QButton::on
+ \brief whether the button is toggled
+
+ This property should only be set for toggle buttons.
+*/
+
+/*!
+ \fn void QButton::setOn( bool on )
+
+ Sets the state of this button to On if \a on is TRUE; otherwise to
+ Off.
+
+ \sa toggleState
+*/
+
+/*!
+ \property QButton::pixmap
+ \brief the pixmap shown on the button
+
+ If the pixmap is monochrome (i.e. it is a QBitmap or its \link
+ QPixmap::depth() depth\endlink is 1) and it does not have a mask,
+ this property will set the pixmap to be its own mask. The purpose
+ of this is to draw transparent bitmaps which are important for
+ toggle buttons, for example.
+
+ pixmap() returns 0 if no pixmap was set.
+*/
+
+/*!
+ \property QButton::text
+ \brief the text shown on the button
+
+ This property will return a QString::null if the button has no
+ text. If the text has an ampersand (\&) in it, then an
+ accelerator is automatically created for it using the character
+ that follows the '\&' as the accelerator key. Any previous
+ accelerator will be overwritten, or cleared if no accelerator is
+ defined by the text.
+
+ There is no default text.
+*/
+
+/*!
+ \property QButton::toggleButton
+ \brief whether the button is a toggle button
+
+ The default value is FALSE.
+*/
+
+/*!
+ \fn QButton::setToggleButton( bool b )
+
+ If \a b is TRUE, this button becomes a toggle button; if \a b is
+ FALSE, this button becomes a command button.
+
+ \sa toggleButton
+*/
+
+/*!
+ \property QButton::toggleState
+ \brief the state of the toggle button
+
+ If this property is changed then it does not cause the button
+ to be repainted.
+*/
+
+/*!
+ \property QButton::toggleType
+ \brief the type of toggle on the button
+
+ The default toggle type is \c SingleShot.
+
+ \sa QButton::ToggleType
+*/
+
+/*!
+ Constructs a standard button called \a name with parent \a parent,
+ using the widget flags \a f.
+
+ If \a parent is a QButtonGroup, this constructor calls
+ QButtonGroup::insert().
+*/
+
+QButton::QButton( QWidget *parent, const char *name, WFlags f )
+ : QWidget( parent, name, f )
+{
+ bpixmap = 0;
+ toggleTyp = SingleShot; // button is simple
+ buttonDown = FALSE; // button is up
+ stat = Off; // button is off
+ mlbDown = FALSE; // mouse left button up
+ autoresize = FALSE; // not auto resizing
+ animation = FALSE; // no pending animateClick
+ repeat = FALSE; // not in autorepeat mode
+ d = 0;
+#ifndef QT_NO_BUTTONGROUP
+ if ( ::qt_cast<QButtonGroup*>(parent) ) {
+ setGroup((QButtonGroup*)parent);
+ group()->insert( this ); // insert into button group
+ }
+#endif
+ setFocusPolicy( TabFocus );
+}
+
+/*!
+ Destroys the button.
+ */
+QButton::~QButton()
+{
+#ifndef QT_NO_BUTTONGROUP
+ if ( group() )
+ group()->remove( this );
+#endif
+ delete bpixmap;
+ delete d;
+}
+
+
+/*!
+ \fn void QButton::pressed()
+
+ This signal is emitted when the button is pressed down.
+
+ \sa released(), clicked()
+*/
+
+/*!
+ \fn void QButton::released()
+
+ This signal is emitted when the button is released.
+
+ \sa pressed(), clicked(), toggled()
+*/
+
+/*!
+ \fn void QButton::clicked()
+
+ This signal is emitted when the button is activated (i.e. first
+ pressed down and then released when the mouse cursor is inside the
+ button), when the accelerator key is typed or when animateClick()
+ is called. This signal is \e not emitted if you call setDown().
+
+ The QButtonGroup::clicked() signal does the same job, if you want
+ to connect several buttons to the same slot.
+
+ \warning Don't launch a model dialog in response to this signal
+ for a button that has \c autoRepeat turned on.
+
+ \sa pressed(), released(), toggled() autoRepeat down
+*/
+
+/*!
+ \fn void QButton::toggled( bool on )
+
+ This signal is emitted whenever a toggle button changes status. \a
+ on is TRUE if the button is on, or FALSE if the button is off.
+
+ This may be the result of a user action, toggle() slot activation,
+ or because setOn() was called.
+
+ \sa clicked()
+*/
+
+/*!
+ \fn void QButton::stateChanged( int state )
+
+ This signal is emitted whenever a toggle button changes state. \a
+ state is \c On if the button is on, \c NoChange if it is in the
+ \link QCheckBox::setTristate() "no change" state\endlink or \c Off
+ if the button is off.
+
+ This may be the result of a user action, toggle() slot activation,
+ setState(), or because setOn() was called.
+
+ \sa clicked() QButton::ToggleState
+*/
+
+void QButton::setText( const QString &text )
+{
+ if ( btext == text )
+ return;
+ btext = text;
+#ifndef QT_NO_ACCEL
+ setAccel( QAccel::shortcutKey( text ) );
+#endif
+
+ if ( bpixmap ) {
+ delete bpixmap;
+ bpixmap = 0;
+ }
+
+ if ( autoresize )
+ adjustSize();
+
+ update();
+ updateGeometry();
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::NameChanged );
+#endif
+}
+
+void QButton::setPixmap( const QPixmap &pixmap )
+{
+ if ( bpixmap && bpixmap->serialNumber() == pixmap.serialNumber() )
+ return;
+
+ bool newSize;
+ if ( bpixmap ) {
+ newSize = pixmap.width() != bpixmap->width() ||
+ pixmap.height() != bpixmap->height();
+ *bpixmap = pixmap;
+ } else {
+ newSize = TRUE;
+ bpixmap = new QPixmap( pixmap );
+ Q_CHECK_PTR( bpixmap );
+ }
+ if ( bpixmap->depth() == 1 && !bpixmap->mask() )
+ bpixmap->setMask( *((QBitmap *)bpixmap) );
+ if ( !btext.isNull() ) {
+ btext = QString::null;
+#ifndef QT_NO_ACCEL
+ setAccel( QKeySequence() );
+#endif
+ }
+ if ( autoresize && newSize )
+ adjustSize();
+ if ( autoMask() )
+ updateMask();
+ update();
+ if ( newSize )
+ updateGeometry();
+}
+
+
+#ifndef QT_NO_ACCEL
+QKeySequence QButton::accel() const
+{
+ if ( d && d->a )
+ return d->a->key( 0 );
+ return QKeySequence();
+}
+
+void QButton::setAccel( const QKeySequence& key )
+{
+ if ( d && d->a )
+ d->a->clear();
+ if ( key.isEmpty() )
+ return;
+ ensureData();
+ if ( !d->a ) {
+ d->a = new QAccel( this, "buttonAccel" );
+ connect( d->a, SIGNAL( activated(int) ), this, SLOT( animateClick() ) );
+ connect( d->a, SIGNAL( activatedAmbiguously(int) ), this, SLOT( setFocus() ) );
+ }
+ d->a->insertItem( key, 0 );
+}
+#endif
+
+#ifndef QT_NO_COMPAT
+
+void QButton::setAutoResize( bool enable )
+{
+ if ( (bool)autoresize != enable ) {
+ autoresize = enable;
+ if ( autoresize )
+ adjustSize(); // calls resize which repaints
+ }
+}
+
+#endif
+
+void QButton::setAutoRepeat( bool enable )
+{
+ repeat = (uint)enable;
+ if ( repeat && mlbDown )
+ timer()->start( AUTO_REPEAT_DELAY, TRUE );
+}
+
+/*!
+ Performs an animated click: the button is pressed and released a
+ short while later.
+
+ The pressed(), released(), clicked(), toggled(), and
+ stateChanged() signals are emitted as appropriate.
+
+ This function does nothing if the button is \link setEnabled()
+ disabled. \endlink
+
+ \sa setAccel()
+*/
+
+void QButton::animateClick()
+{
+ if ( !isEnabled() || animation )
+ return;
+ animation = TRUE;
+ buttonDown = TRUE;
+ repaint( FALSE );
+ emit pressed();
+ QTimer::singleShot( 100, this, SLOT(animateTimeout()) );
+}
+
+void QButton::emulateClick()
+{
+ if ( !isEnabled() || animation )
+ return;
+ animation = TRUE;
+ buttonDown = TRUE;
+ emit pressed();
+ animateTimeout();
+}
+
+void QButton::setDown( bool enable )
+{
+ if ( d )
+ timer()->stop();
+ mlbDown = FALSE; // the safe setting
+ if ( (bool)buttonDown != enable ) {
+ buttonDown = enable;
+ repaint( FALSE );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ }
+}
+
+/*!
+ Sets the toggle state of the button to \a s. \a s can be \c Off, \c
+ NoChange or \c On.
+*/
+
+void QButton::setState( ToggleState s )
+{
+ if ( !toggleTyp ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QButton::setState() / setOn: (%s) Only toggle buttons "
+ "may be switched", name( "unnamed" ) );
+#endif
+ return;
+ }
+
+ if ( (ToggleState)stat != s ) { // changed state
+ bool was = stat != Off;
+ stat = s;
+ if ( autoMask() )
+ updateMask();
+ repaint( FALSE );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ // ### toggled for tristate makes no sense. Don't emit the signal in 4.0
+ if ( was != (stat != Off) )
+ emit toggled( stat != Off );
+ emit stateChanged( s );
+ }
+}
+
+
+/*!
+ 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 it, though.
+*/
+bool QButton::hitButton( const QPoint &pos ) const
+{
+ return rect().contains( pos );
+}
+
+/*!
+ Draws the button. The default implementation does nothing.
+
+ This virtual function is reimplemented by subclasses to draw real
+ buttons. At some point, these reimplementations should call
+ drawButtonLabel().
+
+ \sa drawButtonLabel(), paintEvent()
+*/
+#if (QT_VERSION-0 >= 0x040000)
+#error "QButton. Make pure virtual"
+#endif
+void QButton::drawButton( QPainter * )
+{
+ return;
+}
+
+/*!
+ Draws the button text or pixmap.
+
+ This virtual function is reimplemented by subclasses to draw real
+ buttons. It is invoked by drawButton().
+
+ \sa drawButton(), paintEvent()
+*/
+
+void QButton::drawButtonLabel( QPainter * )
+{
+ return;
+}
+
+/*! \reimp */
+void QButton::keyPressEvent( QKeyEvent *e )
+{
+ switch ( e->key() ) {
+ case Key_Enter:
+ case Key_Return:
+ {
+#ifndef QT_NO_PUSHBUTTON
+ QPushButton *pb = (QPushButton*)qt_cast( "QPushButton" );
+ if ( pb && ( pb->autoDefault() || pb->isDefault() ) )
+ emit clicked();
+ else
+#endif
+ e->ignore();
+ }
+ break;
+ case Key_Space:
+ if ( !e->isAutoRepeat() ) {
+ setDown( TRUE );
+#ifndef QT_NO_PUSHBUTTON
+ if ( ::qt_cast<QPushButton*>(this) )
+ emit pressed();
+ else
+#endif
+ e->ignore();
+ }
+ break;
+ case Key_Up:
+ case Key_Left:
+#ifndef QT_NO_BUTTONGROUP
+ if ( group() ) {
+ group()->moveFocus( e->key() );
+ } else
+#endif
+ {
+ QFocusEvent::setReason(QFocusEvent::Backtab);
+ focusNextPrevChild( FALSE );
+ QFocusEvent::resetReason();
+ }
+ break;
+ case Key_Right:
+ case Key_Down:
+#ifndef QT_NO_BUTTONGROUP
+ if ( group() ) {
+ group()->moveFocus( e->key() );
+ } else
+#endif
+ {
+ QFocusEvent::setReason(QFocusEvent::Tab);
+ focusNextPrevChild( TRUE );
+ QFocusEvent::resetReason();
+ }
+ break;
+ case Key_Escape:
+ if ( buttonDown ) {
+ buttonDown = FALSE;
+ update();
+ break;
+ }
+ // fall through
+ default:
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QButton::keyReleaseEvent( QKeyEvent * e)
+{
+ switch ( e->key() ) {
+ case Key_Space:
+ if ( buttonDown && !e->isAutoRepeat() ) {
+ buttonDown = FALSE;
+ nextState();
+ emit released();
+ emit clicked();
+ }
+ break;
+ default:
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QButton::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton ) {
+ e->ignore();
+ return;
+ }
+ bool hit = hitButton( e->pos() );
+ if ( hit ) { // mouse press on button
+ mlbDown = TRUE; // left mouse button down
+ buttonDown = TRUE;
+ if ( autoMask() )
+ updateMask();
+
+ repaint( FALSE );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ QGuardedPtr<QTimer> t = timer();
+ emit pressed();
+ if ( t && repeat )
+ t->start( AUTO_REPEAT_DELAY, TRUE );
+ }
+}
+
+/*! \reimp */
+void QButton::mouseReleaseEvent( QMouseEvent *e)
+{
+ if ( e->button() != LeftButton ) {
+
+ // clean up apperance if left button has been pressed
+ if (mlbDown || buttonDown) {
+ mlbDown = FALSE;
+ buttonDown = FALSE;
+
+ if ( autoMask() )
+ updateMask();
+ repaint( FALSE );
+ }
+
+ e->ignore();
+ return;
+ }
+ if ( !mlbDown )
+ return;
+ if ( d )
+ timer()->stop();
+
+ const bool oldButtonDown = buttonDown;
+ mlbDown = FALSE; // left mouse button up
+ buttonDown = FALSE;
+ if ( hitButton( e->pos() ) ) { // mouse release on button
+ nextState();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ emit released();
+ emit clicked();
+ } else {
+ repaint( FALSE );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ if (oldButtonDown)
+ emit released();
+ }
+}
+
+/*! \reimp */
+void QButton::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !((e->state() & LeftButton) && mlbDown) ) {
+ e->ignore();
+ return; // left mouse button is up
+ }
+ if ( hitButton(e->pos()) ) { // mouse move in button
+ if ( !buttonDown ) {
+ buttonDown = TRUE;
+ repaint( FALSE );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ emit pressed();
+ }
+ } else { // mouse move outside button
+ if ( buttonDown ) {
+ buttonDown = FALSE;
+ repaint( FALSE );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ emit released();
+ }
+ }
+}
+
+
+/*!
+ Handles paint events for buttons. Small and typically complex
+ buttons are painted double-buffered to reduce flicker. The
+ actually drawing is done in the virtual functions drawButton() and
+ drawButtonLabel().
+
+ \sa drawButton(), drawButtonLabel()
+*/
+void QButton::paintEvent( QPaintEvent *)
+{
+ QSharedDoubleBuffer buffer( this );
+ drawButton( buffer.painter() );
+}
+
+/*! \reimp */
+void QButton::focusInEvent( QFocusEvent * e)
+{
+ QWidget::focusInEvent( e );
+}
+
+/*! \reimp */
+void QButton::focusOutEvent( QFocusEvent * e )
+{
+ buttonDown = FALSE;
+ QWidget::focusOutEvent( e );
+}
+
+/*!
+ Internal slot used for auto repeat.
+*/
+void QButton::autoRepeatTimeout()
+{
+ if ( mlbDown && isEnabled() && autoRepeat() ) {
+ QGuardedPtr<QTimer> t = timer();
+ if ( buttonDown ) {
+ emit released();
+ emit clicked();
+ emit pressed();
+ }
+ if ( t )
+ t->start( AUTO_REPEAT_PERIOD, TRUE );
+ }
+}
+
+/*!
+ Internal slot used for the second stage of animateClick().
+*/
+void QButton::animateTimeout()
+{
+ if ( !animation )
+ return;
+ animation = FALSE;
+ buttonDown = FALSE;
+ nextState();
+ emit released();
+ emit clicked();
+}
+
+
+void QButton::nextState()
+{
+ bool t = isToggleButton() && !( isOn() && isExclusiveToggle() );
+ bool was = stat != Off;
+ if ( t ) {
+ if ( toggleTyp == Tristate )
+ stat = ( stat + 1 ) % 3;
+ else
+ stat = stat ? Off : On;
+ }
+ if ( autoMask() )
+ updateMask();
+ repaint( FALSE );
+ if ( t ) {
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+ if ( was != (stat != Off) )
+ emit toggled( stat != Off );
+ emit stateChanged( stat );
+ }
+}
+
+/*! \reimp */
+void QButton::enabledChange( bool e )
+{
+ if ( !isEnabled() )
+ setDown( FALSE );
+ QWidget::enabledChange( e );
+}
+
+
+/*!
+ Toggles the state of a toggle button.
+
+ \sa isOn(), setOn(), toggled(), isToggleButton()
+*/
+void QButton::toggle()
+{
+ if ( isToggleButton() )
+ setOn( !isOn() );
+}
+
+/*!
+ Sets the toggle type of the button to \a type.
+
+ \a type can be set to \c SingleShot, \c Toggle and \c Tristate.
+*/
+void QButton::setToggleType( ToggleType type )
+{
+ toggleTyp = type;
+ if ( type != Tristate && stat == NoChange )
+ setState( On );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ else
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+}
+
+bool QButton::isExclusiveToggle() const
+{
+#ifndef QT_NO_BUTTONGROUP
+ return group() && ( group()->isExclusive() ||
+ group()->isRadioButtonExclusive() &&
+ ::qt_cast<QRadioButton*>(this) );
+#else
+ return FALSE;
+#endif
+}
+
+#endif
diff --git a/src/widgets/qbutton.h b/src/widgets/qbutton.h
new file mode 100644
index 0000000..c8a5ea1
--- /dev/null
+++ b/src/widgets/qbutton.h
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Definition of QButton widget class
+**
+** Created : 940206
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QBUTTON_H
+#define QBUTTON_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qkeysequence.h"
+#endif // QT_H
+
+#ifndef QT_NO_BUTTON
+
+
+class QButtonGroup;
+class QToolBar;
+class QButtonData;
+
+class Q_EXPORT QButton : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS( ToggleType ToggleState )
+ Q_PROPERTY( QString text READ text WRITE setText )
+ Q_PROPERTY( QPixmap pixmap READ pixmap WRITE setPixmap )
+ Q_PROPERTY( QKeySequence accel READ accel WRITE setAccel )
+ Q_PROPERTY( bool toggleButton READ isToggleButton )
+ Q_PROPERTY( ToggleType toggleType READ toggleType )
+ Q_PROPERTY( bool down READ isDown WRITE setDown DESIGNABLE false )
+ Q_PROPERTY( bool on READ isOn )
+ Q_PROPERTY( ToggleState toggleState READ state )
+ Q_PROPERTY( bool autoResize READ autoResize WRITE setAutoResize DESIGNABLE false )
+ Q_PROPERTY( bool autoRepeat READ autoRepeat WRITE setAutoRepeat )
+ Q_PROPERTY( bool exclusiveToggle READ isExclusiveToggle )
+
+public:
+ QButton( QWidget* parent=0, const char* name=0, WFlags f=0 );
+ ~QButton();
+
+ QString text() const;
+ virtual void setText( const QString &);
+ const QPixmap *pixmap() const;
+ virtual void setPixmap( const QPixmap & );
+
+#ifndef QT_NO_ACCEL
+ QKeySequence accel() const;
+ virtual void setAccel( const QKeySequence& );
+#endif
+
+ bool isToggleButton() const;
+
+ enum ToggleType { SingleShot, Toggle, Tristate };
+ ToggleType toggleType() const;
+
+ virtual void setDown( bool );
+ bool isDown() const;
+
+ bool isOn() const;
+
+ enum ToggleState { Off, NoChange, On };
+ ToggleState state() const;
+
+#ifndef QT_NO_COMPAT
+ bool autoResize() const;
+ void setAutoResize( bool );
+#endif
+
+ bool autoRepeat() const;
+ virtual void setAutoRepeat( bool );
+ bool isExclusiveToggle() const;
+
+ QButtonGroup *group() const;
+
+public slots:
+ void animateClick();
+ void toggle();
+
+signals:
+ void pressed();
+ void released();
+ void clicked();
+ void toggled( bool );
+ void stateChanged( int );
+
+protected:
+ void setToggleButton( bool );
+ virtual void setToggleType( ToggleType );
+ void setOn( bool );
+ virtual void setState( ToggleState );
+
+ virtual bool hitButton( const QPoint &pos ) const;
+ virtual void drawButton( QPainter * );
+ virtual void drawButtonLabel( QPainter * );
+
+ void keyPressEvent( QKeyEvent *);
+ void keyReleaseEvent( QKeyEvent *);
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void paintEvent( QPaintEvent * );
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+
+ void enabledChange( bool );
+
+private slots:
+ void animateTimeout();
+ void autoRepeatTimeout();
+ void emulateClick();
+
+private:
+ QString btext;
+ QPixmap *bpixmap;
+ uint toggleTyp : 2;
+ uint buttonDown : 1;
+ uint stat : 2;
+ uint mlbDown : 1;
+ uint autoresize : 1;
+ uint animation : 1;
+ uint repeat : 1;
+ QButtonData *d;
+
+ friend class QButtonGroup;
+ friend class QToolBar;
+ void ensureData();
+ virtual void setGroup( QButtonGroup* );
+ QTimer *timer();
+ void nextState();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QButton( const QButton & );
+ QButton &operator=( const QButton & );
+#endif
+};
+
+
+inline QString QButton::text() const
+{
+ return btext;
+}
+
+inline const QPixmap *QButton::pixmap() const
+{
+ return bpixmap;
+}
+
+inline bool QButton::isToggleButton() const
+{
+ return ToggleType(toggleTyp) != SingleShot;
+}
+
+inline bool QButton::isDown() const
+{
+ return buttonDown;
+}
+
+inline bool QButton::isOn() const
+{
+ return ToggleState(stat) != Off;
+}
+
+#ifndef QT_NO_COMPAT
+inline bool QButton::autoResize() const
+{
+ return autoresize;
+}
+#endif
+
+inline bool QButton::autoRepeat() const
+{
+ return repeat;
+}
+
+inline QButton::ToggleState QButton::state() const
+{
+ return ToggleState(stat);
+}
+
+inline void QButton::setToggleButton( bool b )
+{
+ setToggleType( b ? Toggle : SingleShot );
+}
+
+inline void QButton::setOn( bool y )
+{
+ setState( y ? On : Off );
+}
+
+inline QButton::ToggleType QButton::toggleType() const
+{
+ return ToggleType(toggleTyp);
+}
+
+
+#endif // QT_NO_BUTTON
+
+#endif // QBUTTON_H
diff --git a/src/widgets/qbuttongroup.cpp b/src/widgets/qbuttongroup.cpp
new file mode 100644
index 0000000..ebcc580
--- /dev/null
+++ b/src/widgets/qbuttongroup.cpp
@@ -0,0 +1,682 @@
+/****************************************************************************
+**
+** Implementation of QButtonGroup class
+**
+** Created : 950130
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qbuttongroup.h"
+#ifndef QT_NO_BUTTONGROUP
+#include "qbutton.h"
+#include "qptrlist.h"
+#include "qapplication.h"
+#include "qradiobutton.h"
+
+
+
+/*!
+ \class QButtonGroup qbuttongroup.h
+ \brief The QButtonGroup widget organizes QButton widgets in a group.
+
+ \ingroup organizers
+ \ingroup geomanagement
+ \ingroup appearance
+ \mainclass
+
+ A button group widget makes it easier to deal with groups of
+ buttons. Each button in a button group has a unique identifier.
+ The button group emits a clicked() signal with this identifier
+ when a button in the group is clicked. This makes a button group
+ particularly useful when you have several similar buttons and want
+ to connect all their clicked() signals to a single slot.
+
+ An \link setExclusive() exclusive\endlink button group switches
+ off all toggle buttons except the one that was clicked. A button
+ group is, by default, non-exclusive. Note that all radio buttons
+ that are inserted into a button group are mutually exclusive even
+ if the button group is non-exclusive. (See
+ setRadioButtonExclusive().)
+
+ There are two ways of using a button group:
+ \list
+ \i The button group is the parent widget of a number of buttons,
+ i.e. the button group is the parent argument in the button
+ constructor. The buttons are assigned identifiers 0, 1, 2, etc.,
+ in the order they are created. A QButtonGroup can display a frame
+ and a title because it inherits QGroupBox.
+ \i The button group is an invisible widget and the contained
+ buttons have some other parent widget. In this usage, each button
+ must be manually inserted, using insert(), into the button group
+ and given an identifier.
+ \endlist
+
+ A button can be removed from the group with remove(). A pointer to
+ a button with a given id can be obtained using find(). The id of a
+ button is available using id(). A button can be set \e on with
+ setButton(). The number of buttons in the group is returned by
+ count().
+
+ <img src=qbttngrp-m.png> <img src=qbttngrp-w.png>
+
+ \sa QPushButton, QCheckBox, QRadioButton
+*/
+
+/*!
+ \property QButtonGroup::exclusive
+ \brief whether the button group is exclusive
+
+ If this property is TRUE, then the buttons in the group are
+ toggled, and to untoggle a button you must click on another button
+ in the group. The default value is FALSE.
+*/
+
+/*!
+ \property QButtonGroup::radioButtonExclusive
+ \brief whether the radio buttons in the group are exclusive
+
+ If this property is TRUE (the default), the \link QRadioButton
+ radiobuttons\endlink in the group are treated exclusively.
+*/
+
+struct QButtonItem
+{
+ QButton *button;
+ int id;
+};
+
+
+class QButtonList: public QPtrList<QButtonItem>
+{
+public:
+ QButtonList() {}
+ ~QButtonList() {}
+};
+
+
+typedef QPtrListIterator<QButtonItem> QButtonListIt;
+
+
+/*!
+ Constructs a button group with no title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QButtonGroup::QButtonGroup( QWidget *parent, const char *name )
+ : QGroupBox( parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs a button group with the title \a title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QButtonGroup::QButtonGroup( const QString &title, QWidget *parent,
+ const char *name )
+ : QGroupBox( title, parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs a button group with no title. Child widgets will be
+ arranged in \a strips rows or columns (depending on \a
+ orientation).
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QButtonGroup::QButtonGroup( int strips, Orientation orientation,
+ QWidget *parent, const char *name )
+ : QGroupBox( strips, orientation, parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs a button group with title \a title. Child widgets will
+ be arranged in \a strips rows or columns (depending on \a
+ orientation).
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QButtonGroup::QButtonGroup( int strips, Orientation orientation,
+ const QString &title, QWidget *parent,
+ const char *name )
+ : QGroupBox( strips, orientation, title, parent, name )
+{
+ init();
+}
+
+/*!
+ Initializes the button group.
+*/
+
+void QButtonGroup::init()
+{
+ buttons = new QButtonList;
+ Q_CHECK_PTR( buttons );
+ buttons->setAutoDelete( TRUE );
+ excl_grp = FALSE;
+ radio_excl = TRUE;
+}
+
+/*! \reimp */
+
+QButtonGroup::~QButtonGroup()
+{
+ QButtonList * tmp = buttons;
+ QButtonItem *bi = tmp->first();
+ buttons = 0;
+ while( bi ) {
+ bi->button->setGroup(0);
+ bi = tmp->next();
+ }
+ delete tmp;
+}
+
+bool QButtonGroup::isExclusive() const
+{
+ return excl_grp;
+}
+
+void QButtonGroup::setExclusive( bool enable )
+{
+ excl_grp = enable;
+}
+
+
+/*!
+ Inserts the \a button with the identifier \a id into the button
+ group. Returns the button identifier.
+
+ Buttons are normally inserted into a button group automatically by
+ passing the button group as the parent when the button is
+ constructed. So it is not necessary to manually insert buttons
+ that have this button group as their parent widget. An exception
+ is when you want custom identifiers instead of the default 0, 1,
+ 2, etc., or if you want the buttons to have some other parent.
+
+ The button is assigned the identifier \a id or an automatically
+ generated identifier. It works as follows: If \a id >= 0, this
+ identifier is assigned. If \a id == -1 (default), the identifier
+ is equal to the number of buttons in the group. If \a id is any
+ other negative integer, for instance -2, a unique identifier
+ (negative integer \<= -2) is generated. No button has an id of -1.
+
+ \sa find(), remove(), setExclusive()
+*/
+
+int QButtonGroup::insert( QButton *button, int id )
+{
+ if ( button->group() )
+ button->group()->remove( button );
+
+ static int seq_no = -2;
+ QButtonItem *bi = new QButtonItem;
+ Q_CHECK_PTR( bi );
+
+ if ( id < -1 )
+ bi->id = seq_no--;
+ else if ( id == -1 )
+ bi->id = buttons->count();
+ else
+ bi->id = id;
+
+ bi->button = button;
+ button->setGroup(this);
+ buttons->append( bi );
+
+ connect( button, SIGNAL(pressed()) , SLOT(buttonPressed()) );
+ connect( button, SIGNAL(released()), SLOT(buttonReleased()) );
+ connect( button, SIGNAL(clicked()) , SLOT(buttonClicked()) );
+ connect( button, SIGNAL(toggled(bool)) , SLOT(buttonToggled(bool)) );
+
+ if ( button->isToggleButton() && !button->isOn() &&
+ selected() && (selected()->focusPolicy() & TabFocus) != 0 )
+ button->setFocusPolicy( (FocusPolicy)(button->focusPolicy() &
+ ~TabFocus) );
+
+ return bi->id;
+}
+
+/*!
+ Returns the number of buttons in the group.
+*/
+int QButtonGroup::count() const
+{
+ return buttons->count();
+}
+
+/*!
+ Removes the \a button from the button group.
+
+ \sa insert()
+*/
+
+void QButtonGroup::remove( QButton *button )
+{
+ if ( !buttons )
+ return;
+
+ QButtonListIt it( *buttons );
+ QButtonItem *i;
+ while ( (i=it.current()) != 0 ) {
+ ++it;
+ if ( i->button == button ) {
+ buttons->remove( i );
+ button->setGroup(0);
+ button->disconnect( this );
+ return;
+ }
+ }
+}
+
+
+/*!
+ Returns the button with the specified identifier \a id, or 0 if
+ the button was not found.
+*/
+
+QButton *QButtonGroup::find( int id ) const
+{
+ // introduce a QButtonListIt if calling anything
+ for ( QButtonItem *i=buttons->first(); i; i=buttons->next() )
+ if ( i->id == id )
+ return i->button;
+ return 0;
+}
+
+
+/*!
+ \fn void QButtonGroup::pressed( int id )
+
+ This signal is emitted when a button in the group is \link
+ QButton::pressed() pressed\endlink. The \a id argument is the
+ button's identifier.
+
+ \sa insert()
+*/
+
+/*!
+ \fn void QButtonGroup::released( int id )
+
+ This signal is emitted when a button in the group is \link
+ QButton::released() released\endlink. The \a id argument is the
+ button's identifier.
+
+ \sa insert()
+*/
+
+/*!
+ \fn void QButtonGroup::clicked( int id )
+
+ This signal is emitted when a button in the group is \link
+ QButton::clicked() clicked\endlink. The \a id argument is the
+ button's identifier.
+
+ \sa insert()
+*/
+
+
+/*!
+ \internal
+ This slot is activated when one of the buttons in the group emits the
+ QButton::pressed() signal.
+*/
+
+void QButtonGroup::buttonPressed()
+{
+ // introduce a QButtonListIt if calling anything
+ int id = -1;
+ QButton *bt = (QButton *)sender(); // object that sent the signal
+ for ( register QButtonItem *i=buttons->first(); i; i=buttons->next() )
+ if ( bt == i->button ) { // button was clicked
+ id = i->id;
+ break;
+ }
+ if ( id != -1 )
+ emit pressed( id );
+}
+
+/*!
+ \internal
+ This slot is activated when one of the buttons in the group emits the
+ QButton::released() signal.
+*/
+
+void QButtonGroup::buttonReleased()
+{
+ // introduce a QButtonListIt if calling anything
+ int id = -1;
+ QButton *bt = (QButton *)sender(); // object that sent the signal
+ for ( register QButtonItem *i=buttons->first(); i; i=buttons->next() )
+ if ( bt == i->button ) { // button was clicked
+ id = i->id;
+ break;
+ }
+ if ( id != -1 )
+ emit released( id );
+}
+
+/*!
+ \internal
+ This slot is activated when one of the buttons in the group emits the
+ QButton::clicked() signal.
+*/
+
+void QButtonGroup::buttonClicked()
+{
+ // introduce a QButtonListIt if calling anything
+ int id = -1;
+ QButton *bt = ::qt_cast<QButton*>(sender()); // object that sent the signal
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( bt );
+#endif
+ for ( register QButtonItem *i=buttons->first(); i; i=buttons->next() ) {
+ if ( bt == i->button ) { // button was clicked
+ id = i->id;
+ break;
+ }
+ }
+ if ( id != -1 )
+ emit clicked( id );
+}
+
+
+/*!
+ \internal
+ This slot is activated when one of the buttons in the group emits the
+ QButton::toggled() signal.
+*/
+
+void QButtonGroup::buttonToggled( bool on )
+{
+ // introduce a QButtonListIt if calling anything
+ if ( !on || !excl_grp && !radio_excl )
+ return;
+ QButton *bt = ::qt_cast<QButton*>(sender()); // object that sent the signal
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( bt );
+ Q_ASSERT( bt->isToggleButton() );
+#endif
+
+ if ( !excl_grp && !::qt_cast<QRadioButton*>(bt) )
+ return;
+ QButtonItem * i = buttons->first();
+ bool hasTabFocus = FALSE;
+
+ while( i != 0 && hasTabFocus == FALSE ) {
+ if ( ( excl_grp || ::qt_cast<QRadioButton*>(i->button) ) &&
+ (i->button->focusPolicy() & TabFocus) )
+ hasTabFocus = TRUE;
+ i = buttons->next();
+ }
+
+ i = buttons->first();
+ while( i ) {
+ if ( bt != i->button &&
+ i->button->isToggleButton() &&
+ i->button->isOn() &&
+ ( excl_grp || ::qt_cast<QRadioButton*>(i->button) ) )
+ i->button->setOn( FALSE );
+ if ( ( excl_grp || ::qt_cast<QRadioButton*>(i->button) ) &&
+ i->button->isToggleButton() &&
+ hasTabFocus )
+ i->button->setFocusPolicy( (FocusPolicy)(i->button->focusPolicy() &
+ ~TabFocus) );
+ i = buttons->next();
+ }
+
+ if ( hasTabFocus )
+ bt->setFocusPolicy( (FocusPolicy)(bt->focusPolicy() | TabFocus) );
+}
+
+
+
+void QButtonGroup::setButton( int id )
+{
+ QButton * b = find( id );
+ if ( b )
+ b->setOn( TRUE );
+}
+
+void QButtonGroup::setRadioButtonExclusive( bool on)
+{
+ radio_excl = on;
+}
+
+
+/*!
+ Moves the keyboard focus according to \a key, and if appropriate
+ checks the new focus item.
+
+ This function does nothing unless the keyboard focus points to one
+ of the button group members and \a key is one of \c Key_Up, \c
+ Key_Down, \c Key_Left and \c Key_Right.
+*/
+
+void QButtonGroup::moveFocus( int key )
+{
+ QWidget * f = qApp->focusWidget();
+
+ QButtonItem * i;
+ i = buttons->first();
+ while( i && i->button != f )
+ i = buttons->next();
+
+ if ( !i || !i->button )
+ return;
+
+ QWidget * candidate = 0;
+ int bestScore = -1;
+
+ QPoint goal( f->mapToGlobal( f->geometry().center() ) );
+
+ i = buttons->first();
+ while( i && i->button ) {
+ if ( i->button != f &&
+ i->button->isEnabled() ) {
+ QPoint p(i->button->mapToGlobal(i->button->geometry().center()));
+ int score = (p.y() - goal.y())*(p.y() - goal.y()) +
+ (p.x() - goal.x())*(p.x() - goal.x());
+ bool betterScore = score < bestScore || !candidate;
+ switch( key ) {
+ case Key_Up:
+ if ( p.y() < goal.y() && betterScore ) {
+ if ( QABS( p.x() - goal.x() ) < QABS( p.y() - goal.y() ) ) {
+ candidate = i->button;
+ bestScore = score;
+ } else if ( i->button->x() == f->x() ) {
+ candidate = i->button;
+ bestScore = score/2;
+ }
+ }
+ break;
+ case Key_Down:
+ if ( p.y() > goal.y() && betterScore ) {
+ if ( QABS( p.x() - goal.x() ) < QABS( p.y() - goal.y() ) ) {
+ candidate = i->button;
+ bestScore = score;
+ } else if ( i->button->x() == f->x() ) {
+ candidate = i->button;
+ bestScore = score/2;
+ }
+ }
+ break;
+ case Key_Left:
+ if ( p.x() < goal.x() && betterScore ) {
+ if ( QABS( p.y() - goal.y() ) < QABS( p.x() - goal.x() ) ) {
+ candidate = i->button;
+ bestScore = score;
+ } else if ( i->button->y() == f->y() ) {
+ candidate = i->button;
+ bestScore = score/2;
+ }
+ }
+ break;
+ case Key_Right:
+ if ( p.x() > goal.x() && betterScore ) {
+ if ( QABS( p.y() - goal.y() ) < QABS( p.x() - goal.x() ) ) {
+ candidate = i->button;
+ bestScore = score;
+ } else if ( i->button->y() == f->y() ) {
+ candidate = i->button;
+ bestScore = score/2;
+ }
+ }
+ break;
+ }
+ }
+ i = buttons->next();
+ }
+
+ QButton *buttoncand = ::qt_cast<QButton*>(candidate);
+ if ( buttoncand && ::qt_cast<QButton*>(f) &&
+ ((QButton*)f)->isOn() &&
+ buttoncand->isToggleButton() &&
+ ( isExclusive() || ( ::qt_cast<QRadioButton*>(f) &&
+ ::qt_cast<QRadioButton*>(candidate)))) {
+ if ( f->focusPolicy() & TabFocus ) {
+ f->setFocusPolicy( (FocusPolicy)(f->focusPolicy() & ~TabFocus) );
+ candidate->setFocusPolicy( (FocusPolicy)(candidate->focusPolicy()|
+ TabFocus) );
+ }
+ buttoncand->setOn( TRUE );
+ buttoncand->animateClick();
+ buttoncand->animateTimeout(); // ### crude l&f hack
+ }
+
+ if ( candidate ) {
+ if (key == Key_Up || key == Key_Left)
+ QFocusEvent::setReason(QFocusEvent::Backtab);
+ else
+ QFocusEvent::setReason(QFocusEvent::Tab);
+ candidate->setFocus();
+ QFocusEvent::resetReason();
+ }
+}
+
+
+/*!
+ Returns the selected toggle button if exactly one is selected;
+ otherwise returns 0.
+
+ \sa selectedId()
+*/
+
+QButton * QButtonGroup::selected() const
+{
+ if ( !buttons )
+ return 0;
+ QButtonListIt it( *buttons );
+ QButtonItem *i;
+ QButton *candidate = 0;
+
+ while ( (i = it.current()) != 0 ) {
+ ++it;
+ if ( i->button && i->button->isToggleButton() && i->button->isOn() ) {
+ if ( candidate != 0 )
+ return 0;
+ candidate = i->button;
+ }
+ }
+ return candidate;
+}
+
+/*!
+ \property QButtonGroup::selectedId
+ \brief the selected toggle button
+
+ The toggle button is specified as an ID.
+
+ If no toggle button is selected, this property holds -1.
+
+ If setButton() is called on an exclusive group, the button with
+ the given id will be set to on and all the others will be set to
+ off.
+
+ \sa selected()
+*/
+
+int QButtonGroup::selectedId() const
+{
+ return id( selected() );
+}
+
+
+/*!
+ Returns the id of \a button, or -1 if \a button is not a member of
+ this group.
+
+ \sa selectedId();
+*/
+
+int QButtonGroup::id( QButton * button ) const
+{
+ QButtonItem *i = buttons->first();
+ while ( i && i->button != button )
+ i = buttons->next();
+ return i ? i->id : -1;
+}
+
+
+/*!
+ \reimp
+*/
+bool QButtonGroup::event( QEvent * e )
+{
+ if ( e->type() == QEvent::ChildInserted ) {
+ QChildEvent * ce = (QChildEvent *) e;
+ if ( radio_excl && ::qt_cast<QRadioButton*>(ce->child()) ) {
+ QButton * button = (QButton *) ce->child();
+ if ( button->isToggleButton() && !button->isOn() &&
+ selected() && (selected()->focusPolicy() & TabFocus) != 0 )
+ button->setFocusPolicy( (FocusPolicy)(button->focusPolicy() &
+ ~TabFocus) );
+ }
+ }
+ return QGroupBox::event( e );
+}
+#endif
diff --git a/src/widgets/qbuttongroup.h b/src/widgets/qbuttongroup.h
new file mode 100644
index 0000000..3fd76f4
--- /dev/null
+++ b/src/widgets/qbuttongroup.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Definition of QButtonGroup class
+**
+** Created : 950130
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QBUTTONGROUP_H
+#define QBUTTONGROUP_H
+
+#ifndef QT_H
+#include "qgroupbox.h"
+#endif // QT_H
+
+#ifndef QT_NO_BUTTONGROUP
+
+
+class QButton;
+class QButtonList;
+
+
+class Q_EXPORT QButtonGroup : public QGroupBox
+{
+ Q_OBJECT
+ Q_PROPERTY( bool exclusive READ isExclusive WRITE setExclusive )
+ Q_PROPERTY( bool radioButtonExclusive READ isRadioButtonExclusive WRITE setRadioButtonExclusive )
+ Q_PROPERTY( int selectedId READ selectedId WRITE setButton )
+
+public:
+ QButtonGroup( QWidget* parent=0, const char* name=0 );
+ QButtonGroup( const QString &title,
+ QWidget* parent=0, const char* name=0 );
+ QButtonGroup( int columns, Orientation o,
+ QWidget* parent=0, const char* name=0 );
+ QButtonGroup( int columns, Orientation o, const QString &title,
+ QWidget* parent=0, const char* name=0 );
+ ~QButtonGroup();
+
+ bool isExclusive() const;
+ bool isRadioButtonExclusive() const { return radio_excl; }
+ virtual void setExclusive( bool );
+ virtual void setRadioButtonExclusive( bool );
+
+public:
+ int insert( QButton *, int id=-1 );
+ void remove( QButton * );
+ QButton *find( int id ) const;
+ int id( QButton * ) const;
+ int count() const;
+
+ virtual void setButton( int id );
+
+ virtual void moveFocus( int );
+
+ QButton *selected() const;
+ int selectedId() const;
+
+signals:
+ void pressed( int id );
+ void released( int id );
+ void clicked( int id );
+
+protected slots:
+ void buttonPressed();
+ void buttonReleased();
+ void buttonClicked();
+ void buttonToggled( bool on );
+
+protected:
+ bool event( QEvent * e );
+
+private:
+ void init();
+ bool excl_grp;
+ bool radio_excl;
+ QButtonList *buttons;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QButtonGroup( const QButtonGroup & );
+ QButtonGroup &operator=( const QButtonGroup & );
+#endif
+};
+
+
+#endif // QT_NO_BUTTONGROUP
+
+#endif // QBUTTONGROUP_H
diff --git a/src/widgets/qcheckbox.cpp b/src/widgets/qcheckbox.cpp
new file mode 100644
index 0000000..640f72a
--- /dev/null
+++ b/src/widgets/qcheckbox.cpp
@@ -0,0 +1,364 @@
+/****************************************************************************
+**
+** Implementation of QCheckBox class
+**
+** Created : 940222
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qcheckbox.h"
+#ifndef QT_NO_CHECKBOX
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qpixmap.h"
+#include "qpixmapcache.h"
+#include "qbitmap.h"
+#include "qtextstream.h"
+#include "qapplication.h"
+#include "qstyle.h"
+
+/*!
+ \class QCheckBox qcheckbox.h
+ \brief The QCheckBox widget provides a checkbox with a text label.
+
+ \ingroup basic
+ \mainclass
+
+ QCheckBox and QRadioButton are both option buttons. That is, they
+ can be switched on (checked) or off (unchecked). The classes
+ differ in how the choices for the user are restricted. Radio
+ buttons define a "one of many" choice, whereas checkboxes provide
+ "many of many" choices.
+
+ A QButtonGroup can be used to group check buttons visually.
+
+ Whenever a checkbox is checked or cleared it emits the signal
+ toggled(). 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.
+
+ \warning The toggled() signal can not be trusted for tristate
+ checkboxes.
+
+ 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 state() to query the current
+ toggle state. When a tristate checkbox changes state, it emits the
+ stateChanged() signal.
+
+ Just like QPushButton, a checkbox can display text or a pixmap.
+ The text can be set in the constructor or with setText(); the
+ pixmap is set with setPixmap().
+
+ \important text(), setText(), text(), pixmap(), setPixmap(),
+ accel(), setAccel(), isToggleButton(), setDown(), isDown(),
+ isOn(), state(), autoRepeat(), isExclusiveToggle(), group(),
+ setAutoRepeat(), toggle(), pressed(), released(), clicked(),
+ toggled(), state() stateChanged()
+
+ <img src=qchkbox-m.png> <img src=qchkbox-w.png>
+
+ \sa QButton QRadioButton
+ \link guibooks.html#fowler Fowler: Check Box \endlink
+*/
+
+/*!
+ \property QCheckBox::checked
+ \brief whether the checkbox is checked
+
+ The default is unchecked, i.e. FALSE.
+*/
+
+/*!
+ \property QCheckBox::autoMask
+ \brief whether the checkbox is automatically masked
+
+ \sa QWidget::setAutoMask()
+*/
+
+/*!
+ \property QCheckBox::tristate
+ \brief whether the checkbox is a tri-state checkbox
+
+ The default is two-state, i.e. tri-state is FALSE.
+*/
+
+/*!
+ Constructs a checkbox with no text.
+
+ The \a parent and \a name arguments are sent to the QWidget
+ constructor.
+*/
+
+QCheckBox::QCheckBox( QWidget *parent, const char *name )
+ : QButton( parent, name, WNoAutoErase | WMouseNoMask )
+{
+ setToggleButton( TRUE );
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+}
+
+/*!
+ Constructs a checkbox with text \a text.
+
+ The \a parent and \a name arguments are sent to the QWidget
+ constructor.
+*/
+
+QCheckBox::QCheckBox( const QString &text, QWidget *parent, const char *name )
+ : QButton( parent, name, WNoAutoErase | WMouseNoMask )
+{
+ setText( text );
+ setToggleButton( TRUE );
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+}
+
+/*!
+ Sets the checkbox to the "no change" state.
+
+ \sa setTristate()
+*/
+void QCheckBox::setNoChange()
+{
+ setTristate(TRUE);
+ setState( NoChange );
+}
+
+void QCheckBox::setTristate(bool y)
+{
+ setToggleType( y ? Tristate : Toggle );
+}
+
+bool QCheckBox::isTristate() const
+{
+ return toggleType() == Tristate;
+}
+
+
+/*!\reimp
+*/
+QSize QCheckBox::sizeHint() const
+{
+ // NB: QRadioButton::sizeHint() is similar
+ constPolish();
+
+ QPainter p(this);
+ QSize sz = style().itemRect(&p, QRect(0, 0, 1, 1), ShowPrefix, FALSE,
+ pixmap(), text()).size();
+
+ return (style().sizeFromContents(QStyle::CT_CheckBox, this, sz).
+ expandedTo(QApplication::globalStrut()));
+}
+
+
+/*!\reimp
+*/
+
+void QCheckBox::drawButton( QPainter *paint )
+{
+ QPainter *p = paint;
+ QRect irect = QStyle::visualRect( style().subRect(QStyle::SR_CheckBoxIndicator, this), this );
+ const QColorGroup &cg = colorGroup();
+
+#if !defined( QT_NO_TEXTSTREAM ) && !defined( Q_WS_MACX )
+# define SAVE_CHECKBOX_PIXMAPS
+#endif
+#if defined(SAVE_CHECKBOX_PIXMAPS)
+ QString pmkey; // pixmap key
+ int kf = 0;
+ if ( isDown() )
+ kf |= 1;
+ if ( isEnabled() )
+ kf |= 2;
+ if ( hasFocus() )
+ kf |= 4; // active vs. normal colorgroup
+ if( isActiveWindow() )
+ kf |= 8;
+ if ( hasMouse() )
+ kf |= 16;
+
+ kf |= state() << 5;
+ QTextOStream os(&pmkey);
+ os << "$qt_check_" << style().className() << "_"
+ << palette().serialNumber() << "_" << irect.width() << "x" << irect.height() << "_" << kf;
+ QPixmap *pm = QPixmapCache::find( pmkey );
+ if ( pm ) { // pixmap exists
+ p->drawPixmap( irect.topLeft(), *pm );
+ drawButtonLabel( p );
+ return;
+ }
+ bool use_pm = TRUE;
+ QPainter pmpaint;
+ int wx = 0, wy = 0;
+ if ( use_pm ) {
+ pm = new QPixmap( irect.size() ); // create new pixmap
+ Q_CHECK_PTR( pm );
+ pm->fill( cg.background() );
+ QPainter::redirect(this, pm);
+ pmpaint.begin(this);
+ p = &pmpaint; // draw in pixmap
+ wx = irect.x(); // save x,y coords
+ wy = irect.y();
+ irect.moveTopLeft(QPoint(0, 0));
+ p->setBackgroundColor( cg.background() );
+ }
+#endif
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if ( hasFocus() )
+ flags |= QStyle::Style_HasFocus;
+ if ( isDown() )
+ flags |= QStyle::Style_Down;
+ if ( hasMouse() )
+ flags |= QStyle::Style_MouseOver;
+ if ( state() == QButton::On )
+ flags |= QStyle::Style_On;
+ else if ( state() == QButton::Off )
+ flags |= QStyle::Style_Off;
+ else if ( state() == QButton::NoChange )
+ flags |= QStyle::Style_NoChange;
+
+ style().drawControl(QStyle::CE_CheckBox, p, this, irect, cg, flags);
+
+#if defined(SAVE_CHECKBOX_PIXMAPS)
+ if ( use_pm ) {
+ pmpaint.end();
+ QPainter::redirect( this, 0 );
+ if ( backgroundPixmap() || backgroundMode() == X11ParentRelative ) {
+ QBitmap bm( pm->size() );
+ bm.fill( color0 );
+ pmpaint.begin( &bm );
+ style().drawControlMask(QStyle::CE_CheckBox, &pmpaint, this, irect);
+ pmpaint.end();
+ pm->setMask( bm );
+ }
+ p = paint; // draw in default device
+ p->drawPixmap( wx, wy, *pm );
+ if (!QPixmapCache::insert(pmkey, pm) ) // save in cache
+ delete pm;
+ }
+#endif
+
+ drawButtonLabel( paint );
+}
+
+
+/*!\reimp
+*/
+void QCheckBox::drawButtonLabel( QPainter *p )
+{
+ QRect r =
+ QStyle::visualRect( style().subRect(QStyle::SR_CheckBoxContents, this), this );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ if (state() == QButton::On)
+ flags |= QStyle::Style_On;
+ else if (state() == QButton::Off)
+ flags |= QStyle::Style_Off;
+ else if (state() == QButton::NoChange)
+ flags |= QStyle::Style_NoChange;
+
+ style().drawControl(QStyle::CE_CheckBoxLabel, p, this, r, colorGroup(), flags);
+}
+
+/*!
+ \reimp
+*/
+void QCheckBox::resizeEvent( QResizeEvent *e )
+{
+ QButton::resizeEvent(e);
+ if ( isVisible() ) {
+ QPainter p(this);
+ QSize isz = style().itemRect(&p, QRect(0, 0, 1, 1), ShowPrefix, FALSE,
+ pixmap(), text()).size();
+ QSize wsz = (style().sizeFromContents(QStyle::CT_CheckBox, this, isz).
+ expandedTo(QApplication::globalStrut()));
+
+ update(wsz.width(), isz.width(), 0, wsz.height());
+ }
+ if (autoMask())
+ updateMask();
+}
+
+/*!
+ \reimp
+*/
+void QCheckBox::updateMask()
+{
+ QRect irect =
+ QStyle::visualRect( style().subRect(QStyle::SR_CheckBoxIndicator, this), this );
+
+ QBitmap bm(width(), height());
+ bm.fill(color0);
+
+ QPainter p( &bm, this );
+ style().drawControlMask(QStyle::CE_CheckBox, &p, this, irect);
+ if ( ! text().isNull() || ( pixmap() && ! pixmap()->isNull() ) ) {
+ QRect crect =
+ QStyle::visualRect( style().subRect( QStyle::SR_CheckBoxContents,
+ this ), this );
+ QRect frect =
+ QStyle::visualRect( style().subRect( QStyle::SR_CheckBoxFocusRect,
+ this ), this );
+ QRect label(crect.unite(frect));
+ p.fillRect(label, color1);
+ }
+ p.end();
+
+ setMask(bm);
+}
+
+/*!\reimp*/
+bool QCheckBox::hitButton( const QPoint &pos ) const
+{
+ QRect r = QStyle::visualRect( style().subRect( QStyle::SR_CheckBoxFocusRect, this ), this );
+ if ( qApp->reverseLayout() ) {
+ r.setRight( width() );
+ } else {
+ r.setLeft( 0 );
+ }
+ return r.contains( pos );
+}
+
+#endif
diff --git a/src/widgets/qcheckbox.h b/src/widgets/qcheckbox.h
new file mode 100644
index 0000000..81a92e9
--- /dev/null
+++ b/src/widgets/qcheckbox.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Definition of QCheckBox class
+**
+** Created : 940222
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QCHECKBOX_H
+#define QCHECKBOX_H
+
+#ifndef QT_H
+#include "qbutton.h"
+#endif // QT_H
+
+#ifndef QT_NO_CHECKBOX
+
+class Q_EXPORT QCheckBox : public QButton
+{
+ Q_OBJECT
+ Q_PROPERTY( bool checked READ isChecked WRITE setChecked )
+ Q_PROPERTY( bool tristate READ isTristate WRITE setTristate )
+ Q_OVERRIDE( bool autoMask DESIGNABLE true SCRIPTABLE true )
+
+public:
+ QCheckBox( QWidget *parent, const char* name=0 );
+ QCheckBox( const QString &text, QWidget *parent, const char* name=0 );
+
+ bool isChecked() const;
+
+ void setNoChange();
+
+ void setTristate(bool y=TRUE);
+ bool isTristate() const;
+
+ QSize sizeHint() const;
+
+public slots:
+ void setChecked( bool check );
+
+protected:
+ void resizeEvent( QResizeEvent* );
+ void drawButton( QPainter * );
+ void drawButtonLabel( QPainter * );
+ void updateMask();
+ bool hitButton( const QPoint &pos ) const;
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QCheckBox( const QCheckBox & );
+ QCheckBox &operator=( const QCheckBox & );
+#endif
+};
+
+
+inline bool QCheckBox::isChecked() const
+{ return isOn(); }
+
+inline void QCheckBox::setChecked( bool check )
+{ setOn( check ); }
+
+
+#endif // QT_NO_CHECKBOX
+
+#endif // QCHECKBOX_H
diff --git a/src/widgets/qcombobox.cpp b/src/widgets/qcombobox.cpp
new file mode 100644
index 0000000..1da559c
--- /dev/null
+++ b/src/widgets/qcombobox.cpp
@@ -0,0 +1,2334 @@
+/**********************************************************************
+**
+** Implementation of QComboBox widget class
+**
+** Created : 940426
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qcombobox.h"
+#ifndef QT_NO_COMBOBOX
+#include "qpopupmenu.h"
+#include "qlistbox.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qstrlist.h"
+#include "qpixmap.h"
+#include "qtimer.h"
+#include "qapplication.h"
+#include "qlineedit.h"
+#include "qbitmap.h"
+#include "qeffects_p.h"
+#include "qstringlist.h"
+#include "qcombobox.h"
+#include "qstyle.h"
+#include <limits.h>
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+/*!
+ \class QComboBox qcombobox.h
+ \brief The QComboBox widget is a combined button and popup list.
+
+ \ingroup basic
+ \mainclass
+
+ A combobox is a selection widget which displays the current item
+ and can pop up a list of items. A combobox may be editable in
+ which case the user can enter arbitrary strings.
+
+ Comboboxes provide a means of showing the user's current choice
+ out of a list of options in a way that takes up the minimum amount
+ of screen space.
+
+ QComboBox supports three different display styles: Aqua/Motif 1.x,
+ Motif 2.0 and Windows. In Motif 1.x, a combobox was called
+ XmOptionMenu. In Motif 2.0, OSF introduced an improved combobox
+ and named that XmComboBox. QComboBox provides both.
+
+ QComboBox provides two different constructors. The simplest
+ constructor creates an "old-style" combobox in Motif (or Aqua)
+ style:
+ \code
+ QComboBox *c = new QComboBox( this, "read-only combobox" );
+ \endcode
+
+ The other constructor creates a new-style combobox in Motif style,
+ and can create both read-only and editable comboboxes:
+ \code
+ QComboBox *c1 = new QComboBox( FALSE, this, "read-only combobox" );
+ QComboBox *c2 = new QComboBox( TRUE, this, "editable combobox" );
+ \endcode
+
+ New-style comboboxes use a list box in both Motif and Windows
+ styles, and both the content size and the on-screen size of the
+ list box can be limited with sizeLimit() and setMaxCount()
+ respectively. Old-style comboboxes use a popup in Aqua and Motif
+ style, and that popup will happily grow larger than the desktop if
+ you put enough data into it.
+
+ The two constructors create identical-looking comboboxes in
+ Windows style.
+
+ Comboboxes can contain pixmaps as well as strings; the
+ insertItem() and changeItem() functions are suitably overloaded.
+ For editable comboboxes, the function clearEdit() is provided,
+ to clear the displayed string without changing the combobox's
+ contents.
+
+ A combobox emits two signals, activated() and highlighted(), when
+ a new item has been activated (selected) or highlighted (made
+ current). Both signals exist in two versions, one with a \c
+ QString argument and one with an \c int argument. If the user
+ highlights or activates a pixmap, only the \c int signals are
+ emitted. Whenever the text of an editable combobox is changed the
+ textChanged() 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 \c AtBottom but you can change
+ this using setInsertionPolicy().
+
+ It is possible to constrain the input to an editable combobox
+ using QValidator; see setValidator(). By default, any input is
+ accepted.
+
+ If the combobox is not editable then it has a default
+ focusPolicy() of \c TabFocus, i.e. it will not grab focus if
+ clicked. This differs from both Windows and Motif. If the combobox
+ is editable then it has a default focusPolicy() of \c StrongFocus,
+ i.e. it will grab focus if clicked.
+
+ A combobox can be populated using the insert functions,
+ insertStringList() and insertItem() for example. Items can be
+ changed with changeItem(). 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 setCurrentItem() or setCurrentText(). 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 setAutoCompletion() and whether or not the user can add
+ duplicates is set with setDuplicatesEnabled().
+
+ <img src="qcombo1-m.png">(Motif 1, read-only)<br clear=all>
+ <img src="qcombo2-m.png">(Motif 2, editable)<br clear=all>
+ <img src="qcombo3-m.png">(Motif 2, read-only)<br clear=all>
+ <img src="qcombo1-w.png">(Windows style)
+
+ Depending on the style, QComboBox will use a QListBox or a
+ QPopupMenu to display the list of items. See setListBox() for
+ more information.
+
+ \sa QLineEdit QListBox QSpinBox QRadioButton QButtonGroup
+ \link guibooks.html#fowler GUI Design Handbook: Combo Box,\endlink
+ \link guibooks.html#fowler GUI Design Handbook: Drop-Down List Box.\endlink
+*/
+
+
+/*!
+ \enum QComboBox::Policy
+
+ This enum specifies what the QComboBox should do when a new string
+ is entered by the user.
+
+ \value NoInsertion the string will not be inserted into the
+ combobox.
+
+ \value AtTop insert the string as the first item in the combobox.
+
+ \value AtCurrent replace the previously selected item with the
+ string the user has entered.
+
+ \value AtBottom insert the string as the last item in the
+ combobox.
+
+ \value AfterCurrent insert the string after the previously
+ selected item.
+
+ \value BeforeCurrent insert the string before the previously
+ selected item.
+
+ activated() is always emitted when the string is entered.
+
+ If inserting the new string would cause the combobox to breach its
+ content size limit, the item at the other end of the list is
+ deleted. The definition of "other end" is
+ implementation-dependent.
+*/
+
+
+/*!
+ \fn void QComboBox::activated( int index )
+
+ This signal is emitted when a new item has been activated
+ (selected). The \a index is the position of the item in the
+ combobox.
+
+ This signal is not emitted if the item is changed
+ programmatically, e.g. using setCurrentItem().
+*/
+
+/*!
+ \overload void QComboBox::activated( const QString &string )
+
+ This signal is emitted when a new item has been activated
+ (selected). \a string is the selected string.
+
+ You can also use the activated(int) signal, but be aware that its
+ argument is meaningful only for selected strings, not for user
+ entered strings.
+*/
+
+/*!
+ \fn void QComboBox::highlighted( int index )
+
+ This signal is emitted when a new item has been set to be the
+ current item. The \a index is the position of the item in the
+ combobox.
+
+ This signal is not emitted if the item is changed
+ programmatically, e.g. using setCurrentItem().
+*/
+
+/*!
+ \overload void QComboBox::highlighted( const QString &string )
+
+ This signal is emitted when a new item has been set to be the
+ current item. \a string is the item's text.
+
+ You can also use the highlighted(int) signal.
+*/
+
+/*!
+ \fn void QComboBox::textChanged( const QString &string )
+
+ This signal is used for editable comboboxes. It is emitted
+ whenever the contents of the text entry field changes. \a string
+ contains the new text.
+*/
+
+/*!
+ \property QComboBox::autoCompletion
+ \brief whether auto-completion is enabled
+
+ This property can only be set for editable comboboxes, for
+ non-editable comboboxes it has no effect. It is FALSE by default.
+*/
+
+/*!
+ \property QComboBox::autoMask
+ \brief whether the combobox is automatically masked
+
+ \sa QWidget::setAutoMask()
+*/
+
+/*! \property QComboBox::autoResize
+ \brief whether auto resize is enabled
+ \obsolete
+
+ If this property is set to TRUE then the combobox will resize itself
+ whenever its contents change. The default is FALSE.
+*/
+
+/*!
+ \property QComboBox::count
+ \brief the number of items in the combobox
+*/
+
+/*!
+ \property QComboBox::currentItem
+ \brief the index of the current item in the combobox
+
+ Note that the activated() and highlighted() signals are only
+ emitted when the user changes the current item, not when it is
+ changed programmatically.
+*/
+
+/*!
+ \property QComboBox::currentText
+ \brief the text of the combobox's current item
+*/
+
+/*!
+ \property QComboBox::duplicatesEnabled
+ \brief whether duplicates are allowed
+
+ If the combobox is editable and the user enters some text in the
+ combobox's lineedit and presses Enter (and the insertionPolicy()
+ is not \c NoInsertion), then what happens is this:
+ \list
+ \i If the text is not already in the list, the text is inserted.
+ \i If the text is in the list and this property is TRUE (the
+ default), the text is inserted.
+ \i If the text is in the list and this property is FALSE, the text
+ is \e not inserted; instead the item which has matching text becomes
+ the current item.
+ \endlist
+
+ This property only affects user-interaction. You can use
+ insertItem() to insert duplicates if you wish regardless of this
+ setting.
+*/
+
+/*!
+ \property QComboBox::editable
+ \brief whether the combobox is editable
+
+ This property's default is FALSE. Note that the combobox will be
+ cleared if this property is set to TRUE for a 1.x Motif style
+ combobox. To avoid this, use setEditable() before inserting any
+ items. Also note that the 1.x version of Motif didn't have any
+ editable comboboxes, so the combobox will change it's appearance
+ to a 2.0 style Motif combobox is it is set to be editable.
+*/
+
+/*!
+ \property QComboBox::insertionPolicy
+ \brief the position of the items inserted by the user
+
+ The default insertion policy is \c AtBottom. See \l Policy.
+*/
+
+/*!
+ \property QComboBox::maxCount
+ \brief the maximum number of items allowed in the combobox
+*/
+
+/*!
+ \property QComboBox::sizeLimit
+ \brief the maximum on-screen size of the combobox.
+
+ This property is ignored for both Motif 1.x style and non-editable
+ comboboxes in Mac style. The default limit is ten
+ lines. If the number of items in the combobox is or grows larger
+ than lines, a scrollbar is added.
+*/
+
+class QComboBoxPopup : public QPopupMenu
+{
+public:
+ QComboBoxPopup( QWidget *parent=0, const char *name=0 )
+ : QPopupMenu( parent, name )
+ {
+ }
+
+ int itemHeight( int index )
+ {
+ return QPopupMenu::itemHeight( index );
+ }
+};
+
+static inline QString escapedComboString(const QString &str)
+{
+ QString stringToReturn = str;
+ return stringToReturn.replace('&', "&&");
+}
+
+class QComboBoxPopupItem : public QCustomMenuItem
+{
+ QListBoxItem *li;
+ QSize sc; // Size cache optimization
+public:
+ QComboBoxPopupItem(QListBoxItem *i) : QCustomMenuItem(), li(i), sc(0, 0) { }
+ virtual bool fullSpan() const { return TRUE; }
+ virtual void paint( QPainter*, const QColorGroup&, bool, bool, int, int, int, int);
+ virtual QSize sizeHint() { if (sc.isNull()) sc = QSize(li->width(li->listBox()), QMAX(25, li->height(li->listBox()))); return sc; }
+};
+void QComboBoxPopupItem::paint( QPainter* p, const QColorGroup&, bool,
+ bool, int x, int y, int, int)
+{
+ p->save();
+ p->translate(x, y + ((sizeHint().height() / 2) - (li->height(li->listBox()) / 2)));
+ li->paint(p);
+ p->restore();
+}
+
+
+class QComboBoxData
+{
+public:
+ QComboBoxData( QComboBox *cb ): ed( 0 ), usingLBox( FALSE ), pop( 0 ), lBox( 0 ), combo( cb )
+ {
+ duplicatesEnabled = TRUE;
+ cb->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+ }
+
+ inline bool usingListBox() { return usingLBox; }
+ inline QListBox * listBox() { return lBox; }
+ inline QComboBoxPopup * popup() { return pop; }
+ void updateLinedGeometry();
+ void setListBox( QListBox *l );
+ void setPopupMenu( QComboBoxPopup * pm, bool isPopup=TRUE );
+
+ int current;
+ int maxCount;
+ int sizeLimit;
+ QComboBox::Policy p;
+ bool autoresize;
+ bool poppedUp;
+ bool mouseWasInsidePopup;
+ bool arrowPressed;
+ bool arrowDown;
+ bool discardNextMousePress;
+ bool shortClick;
+ bool useCompletion;
+ bool completeNow;
+ int completeAt;
+ bool duplicatesEnabled;
+ int fullHeight, currHeight;
+
+ QLineEdit * ed; // /bin/ed rules!
+ QTimer *completionTimer;
+
+ QSize sizeHint;
+
+private:
+ bool usingLBox;
+ QComboBoxPopup *pop;
+ QListBox *lBox;
+ QComboBox *combo;
+
+};
+
+void QComboBoxData::updateLinedGeometry()
+{
+ if ( !ed || !combo )
+ return;
+ QRect r = QStyle::visualRect( combo->style().querySubControlMetrics(QStyle::CC_ComboBox, combo,
+ QStyle::SC_ComboBoxEditField), combo );
+
+ const QPixmap *pix = current < combo->count() ? combo->pixmap( current ) : 0;
+ if ( pix && pix->width() < r.width() )
+ r.setLeft( r.left() + pix->width() + 4 );
+ if ( r != ed->geometry() )
+ ed->setGeometry( r );
+}
+
+void QComboBoxData::setListBox( QListBox *l )
+{
+ lBox = l;
+ usingLBox = TRUE;
+ l->setMouseTracking( TRUE );
+#ifdef Q_WS_X11
+ l->x11SetWindowType( QWidget::X11WindowTypeCombo );
+ l->x11SetWindowTransient( combo->topLevelWidget());
+#endif
+}
+
+void QComboBoxData::setPopupMenu( QComboBoxPopup * pm, bool isPopup )
+{
+ pop = pm;
+ if(isPopup)
+ usingLBox = FALSE;
+#ifdef Q_WS_X11
+ if( pm ) {
+ pm->x11SetWindowType( QWidget::X11WindowTypeCombo );
+ pm->x11SetWindowTransient( combo->topLevelWidget());
+ }
+#endif
+}
+
+static inline bool checkInsertIndex( const char *method, const char * name,
+ int count, int *index)
+{
+ bool range_err = (*index > count);
+#if defined(QT_CHECK_RANGE)
+ if ( range_err )
+ qWarning( "QComboBox::%s: (%s) Index %d out of range",
+ method, name ? name : "<no name>", *index );
+#else
+ Q_UNUSED( method )
+ Q_UNUSED( name )
+#endif
+ if ( *index < 0 ) // append
+ *index = count;
+ return !range_err;
+}
+
+
+static inline bool checkIndex( const char *method, const char * name,
+ int count, int index )
+{
+ bool range_err = (index >= count);
+#if defined(QT_CHECK_RANGE)
+ if ( range_err )
+ qWarning( "QComboBox::%s: (%s) Index %i out of range",
+ method, name ? name : "<no name>", index );
+#else
+ Q_UNUSED( method )
+ Q_UNUSED( name )
+#endif
+ return !range_err;
+}
+
+
+
+/*!
+ Constructs a combobox widget with parent \a parent called \a name.
+
+ This constructor creates a popup list if the program uses Motif
+ (or Aqua) look and feel; this is compatible with Motif 1.x and
+ Aqua.
+
+ Note: If you use this constructor to create your QComboBox, then
+ the pixmap() function will always return 0. To workaround this,
+ use the other constructor.
+
+*/
+
+
+
+QComboBox::QComboBox( QWidget *parent, const char *name )
+ : QWidget( parent, name, WNoAutoErase )
+{
+ d = new QComboBoxData( this );
+ if ( style().styleHint(QStyle::SH_ComboBox_Popup, this) ||
+ style().styleHint(QStyle::SH_GUIStyle) == Qt::MotifStyle ) {
+ d->setPopupMenu( new QComboBoxPopup( this, "in-combo" ) );
+ d->popup()->setFont( font() );
+ connect( d->popup(), SIGNAL(activated(int)),
+ SLOT(internalActivate(int)) );
+ connect( d->popup(), SIGNAL(highlighted(int)),
+ SLOT(internalHighlight(int)) );
+ } else {
+ setUpListBox();
+ }
+ d->ed = 0;
+ d->current = 0;
+ d->maxCount = INT_MAX;
+ d->sizeLimit = 10;
+ d->p = AtBottom;
+ d->autoresize = FALSE;
+ d->poppedUp = FALSE;
+ d->arrowDown = FALSE;
+ d->arrowPressed = FALSE;
+ d->discardNextMousePress = FALSE;
+ d->shortClick = FALSE;
+ d->useCompletion = FALSE;
+ d->completeAt = 0;
+ d->completeNow = FALSE;
+ d->completionTimer = new QTimer( this );
+
+ setFocusPolicy( TabFocus );
+ setBackgroundMode( PaletteButton );
+}
+
+
+/*!
+ Constructs a combobox with a maximum size and either Motif 2.0 or
+ Windows look and feel.
+
+ The input field can be edited if \a rw is TRUE, otherwise the user
+ may only choose one of the items in the combobox.
+
+ The \a parent and \a name arguments are passed on to the QWidget
+ constructor.
+*/
+
+
+QComboBox::QComboBox( bool rw, QWidget *parent, const char *name )
+ : QWidget( parent, name, WNoAutoErase )
+{
+ d = new QComboBoxData( this );
+ setUpListBox();
+
+ if(d->popup() && style().styleHint(QStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = 0;
+ d->maxCount = INT_MAX;
+ setSizeLimit(10);
+ d->p = AtBottom;
+ d->autoresize = FALSE;
+ d->poppedUp = FALSE;
+ d->arrowDown = FALSE;
+ d->discardNextMousePress = FALSE;
+ d->shortClick = FALSE;
+ d->useCompletion = FALSE;
+ d->completeAt = 0;
+ d->completeNow = FALSE;
+ d->completionTimer = new QTimer( this );
+
+ setFocusPolicy( StrongFocus );
+
+ d->ed = 0;
+ if ( rw )
+ setUpLineEdit();
+ setBackgroundMode( PaletteButton, PaletteBase );
+}
+
+
+
+/*!
+ Destroys the combobox.
+*/
+
+QComboBox::~QComboBox()
+{
+ delete d;
+}
+
+void QComboBox::setDuplicatesEnabled( bool enable )
+{
+ d->duplicatesEnabled = enable;
+}
+
+bool QComboBox::duplicatesEnabled() const
+{
+ return d->duplicatesEnabled;
+}
+
+int QComboBox::count() const
+{
+ if ( d->usingListBox() )
+ return d->listBox()->count();
+ else
+ return d->popup()->count();
+}
+
+
+/*!
+ \overload
+
+ Inserts the \a list of strings at position \a index in the
+ combobox.
+
+ This is only for compatibility since it does not support Unicode
+ strings. See insertStringList().
+*/
+
+void QComboBox::insertStrList( const QStrList &list, int index )
+{
+ insertStrList( &list, index );
+}
+
+/*!
+ \overload
+
+ Inserts the \a list of strings at position \a index in the
+ combobox.
+
+ This is only for compatibility since it does not support Unicode
+ strings. See insertStringList().
+*/
+
+void QComboBox::insertStrList( const QStrList *list, int index )
+{
+ if ( !list ) {
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( list != 0 );
+#endif
+ return;
+ }
+ QStrListIterator it( *list );
+ const char* tmp;
+ if ( index < 0 )
+ index = count();
+ while ( (tmp=it.current()) ) {
+ ++it;
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( QString::fromLatin1(tmp), index );
+ else
+ d->popup()->insertItem( escapedComboString(QString::fromLatin1(tmp)), index, index );
+ if ( index++ == d->current && d->current < count() ) {
+ if ( d->ed ) {
+ d->ed->setText( text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ currentChanged();
+ }
+ }
+ if ( index != count() )
+ reIndex();
+}
+
+/*!
+ Inserts the \a list of strings at position \a index in the
+ combobox.
+*/
+
+void QComboBox::insertStringList( const QStringList &list, int index )
+{
+ QStringList::ConstIterator it = list.begin();
+ if ( index < 0 )
+ index = count();
+ while ( it != list.end() ) {
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( *it, index );
+ else
+ d->popup()->insertItem( escapedComboString(*it), index, index );
+ if ( index++ == d->current && d->current < count() ) {
+ if ( d->ed ) {
+ d->ed->setText( text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ currentChanged();
+ }
+ ++it;
+ }
+ if ( index != count() )
+ reIndex();
+}
+
+/*!
+ Inserts the array of char * \a strings at position \a index in the
+ combobox.
+
+ The \a numStrings argument is the number of strings. If \a
+ numStrings is -1 (default), the \a strings array must be
+ terminated with 0.
+
+ Example:
+ \code
+ static const char* items[] = { "red", "green", "blue", 0 };
+ combo->insertStrList( items );
+ \endcode
+
+ \sa insertStringList()
+*/
+
+void QComboBox::insertStrList( const char **strings, int numStrings, int index)
+{
+ if ( !strings ) {
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( strings != 0 );
+#endif
+ return;
+ }
+ if ( index < 0 )
+ index = count();
+ int i = 0;
+ while ( (numStrings<0 && strings[i]!=0) || i<numStrings ) {
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( QString::fromLatin1(strings[i]), index );
+ else
+ d->popup()->insertItem( escapedComboString(QString::fromLatin1(strings[i])), index, index );
+ i++;
+ if ( index++ == d->current && d->current < count() ) {
+ if ( d->ed ) {
+ d->ed->setText( text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ currentChanged();
+ }
+ }
+ if ( index != count() )
+ reIndex();
+}
+
+
+/*!
+ Inserts a text item with text \a t, at position \a index. The item
+ will be appended if \a index is negative.
+*/
+
+void QComboBox::insertItem( const QString &t, int index )
+{
+ int cnt = count();
+ if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( t, index );
+ else
+ d->popup()->insertItem( escapedComboString(t), index, index );
+ if ( index != cnt )
+ reIndex();
+ if ( index == d->current && d->current < count() ) {
+ if ( d->ed ) {
+ d->ed->setText( text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ }
+ if ( index == d->current )
+ currentChanged();
+}
+
+/*!
+ \overload
+
+ Inserts a \a pixmap item at position \a index. The item will be
+ appended if \a index is negative.
+*/
+
+void QComboBox::insertItem( const QPixmap &pixmap, int index )
+{
+ int cnt = count();
+ if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( pixmap, index );
+ else
+ d->popup()->insertItem( pixmap, index, index );
+ if ( index != cnt )
+ reIndex();
+ if ( index == d->current && d->current < count() ) {
+ if ( d->ed ) {
+ d->ed->setText( text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ }
+ if ( index == d->current )
+ currentChanged();
+}
+
+/*!
+ \overload
+
+ Inserts a \a pixmap item with additional text \a text at position
+ \a index. The item will be appended if \a index is negative.
+*/
+
+void QComboBox::insertItem( const QPixmap &pixmap, const QString& text, int index )
+{
+ int cnt = count();
+ if ( !checkInsertIndex( "insertItem", name(), cnt, &index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->insertItem( pixmap, text, index );
+ else
+ d->popup()->insertItem( pixmap, escapedComboString(text), index, index );
+ if ( index != cnt )
+ reIndex();
+ if ( index == d->current && d->current < count() ) {
+ if ( d->ed ) {
+ d->ed->setText( this->text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ }
+ if ( index == d->current )
+ currentChanged();
+}
+
+
+/*!
+ Removes the item at position \a index.
+*/
+
+void QComboBox::removeItem( int index )
+{
+ int cnt = count();
+ if ( !checkIndex( "removeItem", name(), cnt, index ) )
+ return;
+ if ( d->usingListBox() ) {
+ if ( style().styleHint(QStyle::SH_ComboBox_Popup, this) && d->popup() )
+ d->popup()->removeItemAt( index );
+ d->listBox()->removeItem( index );
+ } else {
+ d->popup()->removeItemAt( index );
+ }
+ if ( index != cnt-1 )
+ reIndex();
+ if ( index == d->current ) {
+ if ( d->ed ) {
+ QString s = QString::fromLatin1("");
+ if (d->current < cnt - 1)
+ s = text( d->current );
+ d->ed->setText( s );
+ d->updateLinedGeometry();
+ }
+ else {
+ if ( d->usingListBox() ) {
+ d->current = d->listBox()->currentItem();
+ } else {
+ if (d->current > count()-1 && d->current > 0)
+ d->current--;
+ }
+ update();
+ }
+ currentChanged();
+ }
+ else {
+ if ( !d->ed ) {
+ if (d->current < cnt - 1)
+ setCurrentItem( d->current );
+ else
+ setCurrentItem( d->current - 1 );
+ }
+ }
+
+}
+
+
+/*!
+ Removes all combobox items.
+*/
+
+void QComboBox::clear()
+{
+ if ( d->usingListBox() ) {
+ if ( style().styleHint(QStyle::SH_ComboBox_Popup, this) && d->popup() )
+ d->popup()->clear();
+ d->listBox()->resize( 0, 0 );
+ d->listBox()->clear();
+ } else {
+ d->popup()->clear();
+ }
+
+ if(d->popup() && style().styleHint(QStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = 0;
+ if ( d->ed ) {
+ d->ed->setText( QString::fromLatin1("") );
+ d->updateLinedGeometry();
+ }
+ currentChanged();
+}
+
+
+QString QComboBox::currentText() const
+{
+ if ( d->ed )
+ return d->ed->text();
+ else if ( d->current < count() )
+ return text( currentItem() );
+ else
+ return QString::null;
+}
+
+void QComboBox::setCurrentText( const QString& txt )
+{
+ int i;
+ for ( i = 0; i < count(); i++)
+ if ( text( i ) == txt )
+ break;
+ if ( i < count() )
+ setCurrentItem( i );
+ else if ( d->ed )
+ d->ed->setText( txt );
+ else
+ changeItem( txt, currentItem() );
+}
+
+
+/*!
+ Returns the text item at position \a index, or QString::null if
+ the item is not a string.
+
+ \sa currentText()
+*/
+
+QString QComboBox::text( int index ) const
+{
+ if ( !checkIndex( "text", name(), count(), index ) )
+ return QString::null;
+ if ( d->usingListBox() ) {
+ return d->listBox()->text( index );
+ } else {
+ QString retText = d->popup()->text(index);
+ retText.replace("&&", "&");
+ return retText;
+ }
+}
+
+/*!
+ Returns the pixmap item at position \a index, or 0 if the item is
+ not a pixmap.
+*/
+
+const QPixmap *QComboBox::pixmap( int index ) const
+{
+ if ( !checkIndex( "pixmap", name(), count(), index ) )
+ return 0;
+ if ( d->usingListBox() )
+ return d->listBox()->pixmap( index );
+ else
+ return d->popup()->pixmap( index );
+}
+
+/*!
+ Replaces the item at position \a index with the text \a t.
+*/
+
+void QComboBox::changeItem( const QString &t, int index )
+{
+ if ( !checkIndex( "changeItem", name(), count(), index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->changeItem( t, index );
+ else
+ d->popup()->changeItem( t, index );
+ if ( index == d->current ) {
+ if ( d->ed ) {
+ d->ed->setText( text( d->current ) );
+ d->updateLinedGeometry();
+ } else
+ update();
+ }
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with the pixmap \a im,
+ unless the combobox is editable.
+
+ \sa insertItem()
+*/
+
+void QComboBox::changeItem( const QPixmap &im, int index )
+{
+ if ( !checkIndex( "changeItem", name(), count(), index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->changeItem( im, index );
+ else
+ d->popup()->changeItem( im, index );
+ if ( index == d->current )
+ update();
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with the pixmap \a im and
+ the text \a t.
+
+ \sa insertItem()
+*/
+
+void QComboBox::changeItem( const QPixmap &im, const QString &t, int index )
+{
+ if ( !checkIndex( "changeItem", name(), count(), index ) )
+ return;
+ if ( d->usingListBox() )
+ d->listBox()->changeItem( im, t, index );
+ else
+ d->popup()->changeItem( im, t, index );
+ if ( index == d->current )
+ update();
+}
+
+
+int QComboBox::currentItem() const
+{
+ return d->current;
+}
+
+void QComboBox::setCurrentItem( int index )
+{
+ if ( index == d->current && !d->ed ) {
+ return;
+ }
+ if ( !checkIndex( "setCurrentItem", name(), count(), index ) ) {
+ return;
+ }
+
+ if ( d->usingListBox() && !( listBox()->item(index) && listBox()->item(index)->isSelectable() ) )
+ return;
+
+ if(d->popup() && style().styleHint(QStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = index;
+ d->completeAt = 0;
+ if ( d->ed ) {
+ d->ed->setText( text( index ) );
+ d->updateLinedGeometry();
+ }
+ // ### We want to keep ListBox's currentItem in sync, even if NOT popuped...
+ if ( d->usingListBox() && d->listBox() ) {
+ d->listBox()->setCurrentItem( index );
+ } else {
+ internalHighlight( index );
+ // internalActivate( index ); ### this leads to weird behavior, as in 3.0.1
+ }
+
+ currentChanged();
+}
+
+bool QComboBox::autoResize() const
+{
+ return d->autoresize;
+}
+
+void QComboBox::setAutoResize( bool enable )
+{
+ if ( (bool)d->autoresize != enable ) {
+ d->autoresize = enable;
+ if ( enable )
+ adjustSize();
+ }
+}
+
+
+/*!
+ \reimp
+
+ This implementation caches the size hint to avoid resizing when
+ the contents change dynamically. To invalidate the cached value
+ call setFont().
+*/
+QSize QComboBox::sizeHint() const
+{
+ if ( isVisible() && d->sizeHint.isValid() )
+ return d->sizeHint;
+
+ constPolish();
+ int i, w;
+ QFontMetrics fm = fontMetrics();
+
+ int maxW = count() ? 18 : 7 * fm.width(QChar('x')) + 18;
+ int maxH = QMAX( fm.lineSpacing(), 14 ) + 2;
+
+ if ( !d->usingListBox() ) {
+ w = d->popup()->sizeHint().width() - 2* d->popup()->frameWidth();
+ if ( w > maxW )
+ maxW = w;
+ } else {
+ for( i = 0; i < count(); i++ ) {
+ w = d->listBox()->item( i )->width( d->listBox() );
+ if ( w > maxW )
+ maxW = w;
+ }
+ }
+
+ d->sizeHint = (style().sizeFromContents(QStyle::CT_ComboBox, this,
+ QSize(maxW, maxH)).
+ expandedTo(QApplication::globalStrut()));
+
+ return d->sizeHint;
+}
+
+
+/*!
+ \internal
+ Receives activated signals from an internal popup list and emits
+ the activated() signal.
+*/
+
+void QComboBox::internalActivate( int index )
+{
+ if ( d->current != index ) {
+ if ( !d->usingListBox() || listBox()->item( index )->isSelectable() ) {
+ if(d->popup() && style().styleHint(QStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(d->current, FALSE);
+ d->current = index;
+ currentChanged();
+ }
+ }
+ if ( d->usingListBox() )
+ popDownListBox();
+ else
+ d->popup()->removeEventFilter( this );
+ d->poppedUp = FALSE;
+
+ QString t( text( index ) );
+ if ( d->ed ) {
+ d->ed->setText( t );
+ d->updateLinedGeometry();
+ }
+ emit activated( index );
+ emit activated( t );
+}
+
+/*!
+ \internal
+ Receives highlighted signals from an internal popup list and emits
+ the highlighted() signal.
+*/
+
+void QComboBox::internalHighlight( int index )
+{
+ emit highlighted( index );
+ QString t = text( index );
+ if ( !t.isNull() )
+ emit highlighted( t );
+}
+
+/*!
+ \internal
+ Receives timeouts after a click. Used to decide if a Motif style
+ popup should stay up or not after a click.
+*/
+void QComboBox::internalClickTimeout()
+{
+ d->shortClick = FALSE;
+}
+
+/*!
+ Sets the palette for both the combobox button and the combobox
+ popup list to \a palette.
+*/
+
+void QComboBox::setPalette( const QPalette &palette )
+{
+ QWidget::setPalette( palette );
+ if ( d->listBox() )
+ d->listBox()->setPalette( palette );
+ if ( d->popup() )
+ d->popup()->setPalette( palette );
+}
+
+/*!
+ Sets the font for both the combobox button and the combobox popup
+ list to \a font.
+*/
+
+void QComboBox::setFont( const QFont &font )
+{
+ d->sizeHint = QSize(); // invalidate size hint
+ QWidget::setFont( font );
+ if ( d->usingListBox() )
+ d->listBox()->setFont( font );
+ else
+ d->popup()->setFont( font );
+ if (d->ed)
+ d->ed->setFont( font );
+ if ( d->autoresize )
+ adjustSize();
+}
+
+
+/*!\reimp
+*/
+
+void QComboBox::resizeEvent( QResizeEvent * e )
+{
+ if ( d->ed )
+ d->updateLinedGeometry();
+ if ( d->listBox() )
+ d->listBox()->resize( width(), d->listBox()->height() );
+ QWidget::resizeEvent( e );
+}
+
+/*!\reimp
+*/
+
+void QComboBox::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ const QColorGroup & g = colorGroup();
+ p.setPen(g.text());
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+
+ if ( width() < 5 || height() < 5 ) {
+ qDrawShadePanel( &p, rect(), g, FALSE, 2,
+ &g.brush( QColorGroup::Button ) );
+ return;
+ }
+
+ bool reverse = QApplication::reverseLayout();
+ if ( !d->usingListBox() &&
+ style().styleHint(QStyle::SH_GUIStyle) == Qt::MotifStyle) { // motif 1.x style
+ int dist, buttonH, buttonW;
+ dist = 8;
+ buttonH = 7;
+ buttonW = 11;
+ int xPos;
+ int x0;
+ int w = width() - dist - buttonW - 1;
+ if ( reverse ) {
+ xPos = dist + 1;
+ x0 = xPos + 4;
+ } else {
+ xPos = w;
+ x0 = 4;
+ }
+ qDrawShadePanel( &p, rect(), g, FALSE,
+ style().pixelMetric(QStyle::PM_DefaultFrameWidth, this),
+ &g.brush( QColorGroup::Button ) );
+ qDrawShadePanel( &p, xPos, (height() - buttonH)/2,
+ buttonW, buttonH, g, FALSE,
+ style().pixelMetric(QStyle::PM_DefaultFrameWidth, this) );
+ QRect clip( x0, 2, w - 2 - 4 - 5, height() - 4 );
+ QString str = d->popup()->text( this->d->current );
+ if ( !str.isNull() ) {
+ p.drawText( clip, AlignCenter | SingleLine, str );
+ }
+
+ QPixmap *pix = d->popup()->pixmap( this->d->current );
+ QIconSet *iconSet = d->popup()->iconSet( this->d->current );
+ if (pix || iconSet) {
+ QPixmap pm = ( pix ? *pix : iconSet->pixmap() );
+ p.setClipRect( clip );
+ p.drawPixmap( 4, (height()-pm.height())/2, pm );
+ p.setClipping( FALSE );
+ }
+
+ if ( hasFocus() )
+ p.drawRect( xPos - 5, 4, width() - xPos + 1 , height() - 8 );
+ } else if(!d->usingListBox()) {
+ style().drawComplexControl( QStyle::CC_ComboBox, &p, this, rect(), g,
+ flags, (uint)QStyle::SC_All,
+ (d->arrowDown ?
+ QStyle::SC_ComboBoxArrow :
+ QStyle::SC_None ));
+
+ QRect re = style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxEditField );
+ re = QStyle::visualRect(re, this);
+ p.setClipRect( re );
+
+ QString str = d->popup()->text( this->d->current );
+ QPixmap *pix = d->popup()->pixmap( this->d->current );
+ if ( !str.isNull() ) {
+ p.save();
+ p.setFont(font());
+ QFontMetrics fm(font());
+ int x = re.x(), y = re.y() + fm.ascent();
+ if( pix )
+ x += pix->width() + 5;
+ p.drawText( x, y, str );
+ p.restore();
+ }
+ if ( pix ) {
+ p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(),
+ colorGroup().brush( QColorGroup::Base ) );
+ p.drawPixmap( re.x() + 2, re.y() +
+ ( re.height() - pix->height() ) / 2, *pix );
+ }
+ } else {
+ style().drawComplexControl( QStyle::CC_ComboBox, &p, this, rect(), g,
+ flags, (uint)QStyle::SC_All,
+ (d->arrowDown ?
+ QStyle::SC_ComboBoxArrow :
+ QStyle::SC_None ));
+
+ QRect re = style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxEditField );
+ re = QStyle::visualRect(re, this);
+ p.setClipRect( re );
+
+ if ( !d->ed ) {
+ QListBoxItem * item = d->listBox()->item( d->current );
+ if ( item ) {
+ int itemh = item->height( d->listBox() );
+ p.translate( re.x(), re.y() + (re.height() - itemh)/2 );
+ item->paint( &p );
+ }
+ } else if ( d->listBox() && d->listBox()->item( d->current ) ) {
+ QListBoxItem * item = d->listBox()->item( d->current );
+ const QPixmap *pix = item->pixmap();
+ if ( pix ) {
+ p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(),
+ colorGroup().brush( QColorGroup::Base ) );
+ p.drawPixmap( re.x() + 2, re.y() +
+ ( re.height() - pix->height() ) / 2, *pix );
+ }
+ }
+ p.setClipping( FALSE );
+ }
+}
+
+
+/*!\reimp
+*/
+
+void QComboBox::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+ if ( d->discardNextMousePress ) {
+ d->discardNextMousePress = FALSE;
+ return;
+ }
+ QRect arrowRect = style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxArrow);
+ arrowRect = QStyle::visualRect(arrowRect, this);
+
+ // Correction for motif style, where arrow is smaller
+ // and thus has a rect that doesn't fit the button.
+ arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) );
+
+ if ( count() && ( !editable() || arrowRect.contains( e->pos() ) ) ) {
+ d->arrowPressed = FALSE;
+
+ if ( d->usingListBox() ) {
+ listBox()->blockSignals( TRUE );
+ qApp->sendEvent( listBox(), e ); // trigger the listbox's autoscroll
+ listBox()->setCurrentItem(d->current);
+ listBox()->blockSignals( FALSE );
+ popup();
+ if ( arrowRect.contains( e->pos() ) ) {
+ d->arrowPressed = TRUE;
+ d->arrowDown = TRUE;
+ repaint( FALSE );
+ }
+ } else {
+ popup();
+ }
+ QTimer::singleShot( 200, this, SLOT(internalClickTimeout()));
+ d->shortClick = TRUE;
+ }
+}
+
+/*!\reimp
+*/
+
+void QComboBox::mouseMoveEvent( QMouseEvent * )
+{
+}
+
+/*!\reimp
+*/
+
+void QComboBox::mouseReleaseEvent( QMouseEvent * )
+{
+}
+
+/*!\reimp
+*/
+
+void QComboBox::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ mousePressEvent( e );
+}
+
+
+/*!\reimp
+*/
+
+void QComboBox::keyPressEvent( QKeyEvent *e )
+{
+ int c = currentItem();
+ if ( ( e->key() == Key_F4 && e->state() == 0 ) ||
+ ( e->key() == Key_Down && (e->state() & AltButton) ) ||
+ ( !d->ed && e->key() == Key_Space ) ) {
+ if ( count() ) {
+ if ( !d->usingListBox() )
+ d->popup()->setActiveItem( this->d->current );
+ popup();
+ }
+ return;
+ } else if ( d->usingListBox() && e->key() == Key_Up ) {
+ if ( c > 0 )
+ setCurrentItem( c-1 );
+ } else if ( d->usingListBox() && e->key() == Key_Down ) {
+ if ( ++c < count() )
+ setCurrentItem( c );
+ } else if ( d->usingListBox() && e->key() == Key_Home && ( !d->ed || !d->ed->hasFocus() ) ) {
+ setCurrentItem( 0 );
+ } else if ( d->usingListBox() && e->key() == Key_End && ( !d->ed || !d->ed->hasFocus() ) ) {
+ setCurrentItem( count()-1 );
+ } else if ( !d->ed && e->ascii() >= 32 && !e->text().isEmpty() ) {
+ if ( !d->completionTimer->isActive() ) {
+ d->completeAt = 0;
+ c = completionIndex( e->text(), ++c );
+ if ( c >= 0 ) {
+ setCurrentItem( c );
+ d->completeAt = e->text().length();
+ }
+ } else {
+ d->completionTimer->stop();
+ QString ct = currentText().left( d->completeAt ) + e->text();
+ c = completionIndex( ct, c );
+ if ( c < 0 && d->completeAt > 0 ) {
+ c = completionIndex( e->text(), 0 );
+ ct = e->text();
+ }
+ d->completeAt = 0;
+ if ( c >= 0 ) {
+ setCurrentItem( c );
+ d->completeAt = ct.length();
+ }
+ }
+ d->completionTimer->start( 400, TRUE );
+ } else {
+ e->ignore();
+ return;
+ }
+
+ c = currentItem();
+ if ( count() && !text( c ).isNull() )
+ emit activated( text( c ) );
+ emit activated( c );
+}
+
+
+/*!\reimp
+*/
+
+void QComboBox::focusInEvent( QFocusEvent * e )
+{
+ QWidget::focusInEvent( e );
+ d->completeNow = FALSE;
+ d->completeAt = 0;
+}
+
+/*!\reimp
+*/
+
+void QComboBox::focusOutEvent( QFocusEvent * e )
+{
+ QWidget::focusOutEvent( e );
+ d->completeNow = FALSE;
+ d->completeAt = 0;
+}
+
+/*!\reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QComboBox::wheelEvent( QWheelEvent *e )
+{
+ if ( d->poppedUp ) {
+ if ( d->usingListBox() ) {
+ QApplication::sendEvent( d->listBox(), e );
+ }
+ } else {
+ if ( e->delta() > 0 ) {
+ int c = currentItem();
+ if ( c > 0 ) {
+ setCurrentItem( c-1 );
+ emit activated( currentItem() );
+ emit activated( currentText() );
+ }
+ } else {
+ int c = currentItem();
+ if ( ++c < count() ) {
+ setCurrentItem( c );
+ emit activated( currentItem() );
+ emit activated( currentText() );
+ }
+ }
+ e->accept();
+ }
+}
+#endif
+
+/*!
+ \internal
+ Calculates the listbox height needed to contain all items, or as
+ many as the list box is supposed to contain.
+*/
+static int listHeight( QListBox *l, int sl )
+{
+ if ( l->count() > 0 )
+ return QMIN( l->count(), (uint)sl) * l->item( 0 )->height(l);
+ else
+ return l->sizeHint().height();
+}
+
+
+/*!
+ Pops up the combobox popup list.
+
+ If the list is empty, no items appear.
+*/
+
+void QComboBox::popup()
+{
+ if ( !count() || d->poppedUp )
+ return;
+
+ if( !d->usingListBox() || style().styleHint(QStyle::SH_ComboBox_Popup, this) ) {
+ if(d->usingListBox()) {
+ if(!d->popup()) {
+ QComboBoxPopup *p = new QComboBoxPopup( this, "in-combo" );
+ d->setPopupMenu( p, FALSE );
+ p->setFont( font() );
+ connect( p, SIGNAL(activated(int)), SLOT(internalActivate(int)) );
+ connect( p, SIGNAL(highlighted(int)), SLOT(internalHighlight(int)) );
+ }
+ d->popup()->clear();
+ for(unsigned int i = 0; i < d->listBox()->count(); i++) {
+ QListBoxItem *item = d->listBox()->item(i);
+ if(item->rtti() == QListBoxText::RTTI) {
+ d->popup()->insertItem(escapedComboString(item->text()), i, i);
+ } else if(item->rtti() == QListBoxPixmap::RTTI) {
+ if(item->pixmap())
+ d->popup()->insertItem(QIconSet(*item->pixmap()), escapedComboString(item->text()), i, i);
+ else
+ d->popup()->insertItem(escapedComboString(item->text()), i, i);
+ } else {
+ d->popup()->insertItem(new QComboBoxPopupItem(item), i, i);
+ }
+ }
+ }
+ d->popup()->installEventFilter( this );
+ if(d->popup() && style().styleHint(QStyle::SH_ComboBox_Popup, this))
+ d->popup()->setItemChecked(this->d->current, TRUE);
+ d->popup()->popup( mapToGlobal( QPoint(0,0) ), this->d->current );
+ update();
+ } else {
+ // Send all listbox events to eventFilter():
+ QListBox* lb = d->listBox();
+ lb->triggerUpdate( TRUE );
+ lb->installEventFilter( this );
+ d->mouseWasInsidePopup = FALSE;
+ int w = lb->variableWidth() ? lb->sizeHint().width() : width();
+ int h = listHeight( lb, d->sizeLimit ) + 2;
+ QRect screen = QApplication::desktop()->availableGeometry( this );
+
+ int sx = screen.x(); // screen pos
+ int sy = screen.y();
+ int sw = screen.width(); // screen width
+ int sh = screen.height(); // screen height
+ QPoint pos = mapToGlobal( QPoint(0,height()) );
+ // ## Similar code is in QPopupMenu
+ int x = pos.x();
+ int y = pos.y();
+
+ // the complete widget must be visible
+ if ( x + w > sx + sw )
+ x = sx+sw - w;
+ if ( x < sx )
+ x = sx;
+ if (y + h > sy+sh && y - h - height() >= 0 )
+ y = y - h - height();
+
+ QRect rect =
+ style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxListBoxPopup,
+ QStyleOption( x, y, w, h ) );
+ // work around older styles that don't implement the combobox
+ // listbox popup subcontrol
+ if ( rect.isNull() )
+ rect.setRect( x, y, w, h );
+ lb->setGeometry( rect );
+
+ lb->raise();
+ bool block = lb->signalsBlocked();
+ lb->blockSignals( TRUE );
+ QListBoxItem* currentLBItem = 0;
+ if ( editable() && currentText() != text( currentItem() ) )
+ currentLBItem = lb->findItem( currentText() );
+
+ currentLBItem = currentLBItem ? currentLBItem : lb->item( d->current );
+
+ lb->setCurrentItem( currentLBItem );
+ lb->setContentsPos( lb->contentsX(),
+ lb->viewportToContents( lb->itemRect( currentLBItem ).topLeft() ).y() );
+
+ // set the current item to also be the selected item if it isn't already
+ if ( currentLBItem && currentLBItem->isSelectable() && !currentLBItem->isSelected() )
+ lb->setSelected( currentLBItem, TRUE );
+ lb->blockSignals( block );
+ lb->setVScrollBarMode(QScrollView::Auto);
+
+#ifndef QT_NO_EFFECTS
+ if ( QApplication::isEffectEnabled( UI_AnimateCombo ) ) {
+ if ( lb->y() < mapToGlobal(QPoint(0,0)).y() )
+ qScrollEffect( lb, QEffects::UpScroll );
+ else
+ qScrollEffect( lb );
+ } else
+#endif
+ lb->show();
+ }
+ d->poppedUp = TRUE;
+}
+
+
+/*!
+ \reimp
+*/
+void QComboBox::updateMask()
+{
+ QBitmap bm( size() );
+ bm.fill( color0 );
+
+ {
+ QPainter p( &bm, this );
+ style().drawComplexControlMask(QStyle::CC_ComboBox, &p, this, rect());
+ }
+
+ setMask( bm );
+}
+
+/*!
+ \internal
+ Pops down (removes) the combobox popup list box.
+*/
+void QComboBox::popDownListBox()
+{
+ Q_ASSERT( d->usingListBox() );
+ d->listBox()->removeEventFilter( this );
+ d->listBox()->viewport()->removeEventFilter( this );
+ d->listBox()->hide();
+ d->listBox()->setCurrentItem( d->current );
+ if ( d->arrowDown ) {
+ d->arrowDown = FALSE;
+ repaint( FALSE );
+ }
+ d->poppedUp = FALSE;
+}
+
+
+/*!
+ \internal
+ Re-indexes the identifiers in the popup list.
+*/
+
+void QComboBox::reIndex()
+{
+ if ( !d->usingListBox() ) {
+ int cnt = count();
+ while ( cnt-- )
+ d->popup()->setId( cnt, cnt );
+ }
+}
+
+/*!
+ \internal
+ Repaints the combobox.
+*/
+
+void QComboBox::currentChanged()
+{
+ if ( d->autoresize )
+ adjustSize();
+ update();
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+/*! \reimp
+
+ \internal
+
+ The event filter steals events from the popup or listbox when they
+ are popped up. It makes the popup stay up after a short click in
+ motif style. In windows style it toggles the arrow button of the
+ combobox field, and activates an item and takes down the listbox
+ when the mouse button is released.
+*/
+
+bool QComboBox::eventFilter( QObject *object, QEvent *event )
+{
+ if ( !event )
+ return TRUE;
+ else if ( object == d->ed ) {
+ if ( event->type() == QEvent::KeyPress ) {
+ bool isAccepted = ( (QKeyEvent*)event )->isAccepted();
+ keyPressEvent( (QKeyEvent *)event );
+ if ( ((QKeyEvent *)event)->isAccepted() ) {
+ d->completeNow = FALSE;
+ return TRUE;
+ } else if ( ((QKeyEvent *)event)->key() != Key_End ) {
+ d->completeNow = TRUE;
+ d->completeAt = d->ed->cursorPosition();
+ }
+ if ( isAccepted )
+ ( (QKeyEvent*)event )->accept();
+ else
+ ( (QKeyEvent*)event )->ignore();
+ } else if ( event->type() == QEvent::KeyRelease ) {
+ keyReleaseEvent( (QKeyEvent *)event );
+ return ((QKeyEvent *)event)->isAccepted();
+ } else if ( event->type() == QEvent::FocusIn ) {
+ focusInEvent( (QFocusEvent *)event );
+ } else if ( event->type() == QEvent::FocusOut ) {
+ focusOutEvent( (QFocusEvent *)event );
+ } else if ( d->useCompletion && d->completeNow ) {
+ d->completeNow = FALSE;
+ if ( !d->ed->text().isNull() &&
+ d->ed->cursorPosition() > d->completeAt &&
+ d->ed->cursorPosition() == (int)d->ed->text().length() ) {
+ QString ct( d->ed->text() );
+ int i = completionIndex( ct, currentItem() );
+ if ( i > -1 ) {
+ QString it = text( i );
+ d->ed->validateAndSet( it, ct.length(),
+ ct.length(), it.length() );
+ d->current = i;
+ // ### sets current item without emitting signals. This is to
+ // make sure the right item is current if you change current with
+ // wheel/up/down. While typing current is not valid anyway. Fix properly
+ // in 4.0.
+ }
+ }
+ }
+ } else if ( d->usingListBox() && ( object == d->listBox() ||
+ object == d->listBox()->viewport() )) {
+ QMouseEvent *e = (QMouseEvent*)event;
+ switch( event->type() ) {
+ case QEvent::MouseMove:
+ if ( !d->mouseWasInsidePopup ) {
+ QPoint pos = e->pos();
+ if ( d->listBox()->rect().contains( pos ) )
+ d->mouseWasInsidePopup = TRUE;
+ // Check if arrow button should toggle
+ if ( d->arrowPressed ) {
+ QPoint comboPos;
+ comboPos = mapFromGlobal( d->listBox()->mapToGlobal(pos) );
+ QRect arrowRect =
+ style().querySubControlMetrics( QStyle::CC_ComboBox, this,
+ QStyle::SC_ComboBoxArrow);
+ arrowRect = QStyle::visualRect(arrowRect, this);
+ if ( arrowRect.contains( comboPos ) ) {
+ if ( !d->arrowDown ) {
+ d->arrowDown = TRUE;
+ repaint( FALSE );
+ }
+ } else {
+ if ( d->arrowDown ) {
+ d->arrowDown = FALSE;
+ repaint( FALSE );
+ }
+ }
+ }
+ } else if ((e->state() & ( RightButton | LeftButton | MidButton ) ) == 0 &&
+ style().styleHint(QStyle::SH_ComboBox_ListMouseTracking, this)) {
+ QWidget *mouseW = QApplication::widgetAt( e->globalPos(), TRUE );
+ if ( mouseW == d->listBox()->viewport() ) { //###
+ QMouseEvent m( QEvent::MouseMove, e->pos(), e->globalPos(),
+ LeftButton, LeftButton );
+ QApplication::sendEvent( object, &m ); //### Evil
+ return TRUE;
+ }
+ }
+
+ break;
+ case QEvent::MouseButtonRelease:
+ if ( d->listBox()->rect().contains( e->pos() ) ) {
+ QMouseEvent tmp( QEvent::MouseButtonDblClick,
+ e->pos(), e->button(), e->state() ) ;
+ // will hide popup
+ QApplication::sendEvent( object, &tmp );
+ return TRUE;
+ } else {
+ if ( d->mouseWasInsidePopup ) {
+ popDownListBox();
+ } else {
+ d->arrowPressed = FALSE;
+ if ( d->arrowDown ) {
+ d->arrowDown = FALSE;
+ repaint( FALSE );
+ }
+ }
+ }
+ break;
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonPress:
+ if ( !d->listBox()->rect().contains( e->pos() ) ) {
+ QPoint globalPos = d->listBox()->mapToGlobal(e->pos());
+ if ( QApplication::widgetAt( globalPos, TRUE ) == this ) {
+ d->discardNextMousePress = TRUE;
+ // avoid popping up again
+ }
+ popDownListBox();
+ return TRUE;
+ }
+ break;
+ case QEvent::KeyPress:
+ switch( ((QKeyEvent *)event)->key() ) {
+ case Key_Up:
+ case Key_Down:
+ if ( !(((QKeyEvent *)event)->state() & AltButton) )
+ break;
+ case Key_F4:
+ case Key_Escape:
+ if ( d->poppedUp ) {
+ popDownListBox();
+ return TRUE;
+ }
+ break;
+ case Key_Enter:
+ case Key_Return:
+ // work around QDialog's enter handling
+ return FALSE;
+ default:
+ break;
+ }
+ break;
+ case QEvent::Hide:
+ popDownListBox();
+ break;
+ default:
+ break;
+ }
+ } else if ( (!d->usingListBox() || style().styleHint(QStyle::SH_ComboBox_Popup, this)) &&
+ object == d->popup() ) {
+ QMouseEvent *e = (QMouseEvent*)event;
+ switch ( event->type() ) {
+ case QEvent::MouseButtonRelease:
+ if ( d->shortClick ) {
+ QMouseEvent tmp( QEvent::MouseMove,
+ e->pos(), e->button(), e->state() ) ;
+ // highlight item, but don't pop down:
+ QApplication::sendEvent( object, &tmp );
+ return TRUE;
+ }
+ break;
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonPress:
+ if ( !d->popup()->rect().contains( e->pos() ) ) {
+ d->poppedUp = FALSE;
+ d->arrowDown = FALSE;
+ // remove filter, event will take down popup:
+ d->popup()->removeEventFilter( this );
+ // ### uglehack!
+ // call internalHighlight so the highlighed signal
+ // will be emitted at least as often as necessary.
+ // it may be called more often than necessary
+ internalHighlight( d->current );
+ }
+ break;
+ case QEvent::Hide:
+ d->poppedUp = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+ return QWidget::eventFilter( object, event );
+}
+
+
+/*!
+ Returns the index of the first item \e after \a startingAt of
+ which \a prefix is a case-insensitive prefix. Returns -1 if no
+ items start with \a prefix.
+*/
+
+int QComboBox::completionIndex( const QString & prefix,
+ int startingAt = 0 ) const
+{
+ int start = startingAt;
+ if ( start < 0 || start >= count() )
+ start = 0;
+ if ( start >= count() )
+ return -1;
+ QString match = prefix.lower();
+ if ( match.length() < 1 )
+ return start;
+
+ QString current;
+ int i = start;
+ do {
+ current = text( i ).lower();
+ if ( current.startsWith( match ) )
+ return i;
+ i++;
+ if ( i == count() )
+ i = 0;
+ } while ( i != start );
+ return -1;
+}
+
+
+int QComboBox::sizeLimit() const
+{
+ return d ? d->sizeLimit : INT_MAX;
+}
+
+void QComboBox::setSizeLimit( int lines )
+{
+ d->sizeLimit = lines;
+}
+
+
+int QComboBox::maxCount() const
+{
+ return d ? d->maxCount : INT_MAX;
+}
+
+void QComboBox::setMaxCount( int count )
+{
+ int l = this->count();
+ while( --l > count )
+ removeItem( l );
+ d->maxCount = count;
+}
+
+QComboBox::Policy QComboBox::insertionPolicy() const
+{
+ return d->p;
+}
+
+void QComboBox::setInsertionPolicy( Policy policy )
+{
+ d->p = policy;
+}
+
+
+
+/*!
+ Internal slot to keep the line editor up to date.
+*/
+
+void QComboBox::returnPressed()
+{
+ QString s( d->ed->text() );
+
+ if ( s.isEmpty() )
+ return;
+
+ int c = 0;
+ bool doInsert = TRUE;
+ if ( !d->duplicatesEnabled ) {
+ for ( int i = 0; i < count(); ++i ) {
+ if ( s == text( i ) ) {
+ doInsert = FALSE;
+ c = i;
+ break;
+ }
+ }
+ }
+
+ if ( doInsert ) {
+ if ( insertionPolicy() != NoInsertion ) {
+ int cnt = count();
+ while ( cnt >= d->maxCount ) {
+ removeItem( --cnt );
+ }
+ }
+
+ switch ( insertionPolicy() ) {
+ case AtCurrent:
+ if (count() == 0)
+ insertItem(s);
+ else if ( s != text( currentItem() ) )
+ changeItem( s, currentItem() );
+ emit activated( currentItem() );
+ emit activated( s );
+ return;
+ case NoInsertion:
+ emit activated( s );
+ return;
+ case AtTop:
+ c = 0;
+ break;
+ case AtBottom:
+ c = count();
+ break;
+ case BeforeCurrent:
+ c = currentItem();
+ break;
+ case AfterCurrent:
+ c = count() == 0 ? 0 : currentItem() + 1;
+ break;
+ }
+ insertItem( s, c );
+ }
+
+ setCurrentItem( c );
+ emit activated( c );
+ emit activated( s );
+}
+
+
+/*! \reimp
+*/
+
+void QComboBox::setEnabled( bool enable )
+{
+ if ( !enable ) {
+ if ( d->usingListBox() ) {
+ popDownListBox();
+ } else {
+ d->popup()->removeEventFilter( this );
+ d->popup()->close();
+ d->poppedUp = FALSE;
+ }
+ }
+ QWidget::setEnabled( enable );
+}
+
+
+
+/*!
+ Applies the validator \a v to the combobox so that only text which
+ is valid according to \a v is accepted.
+
+ This function does nothing if the combobox is not editable.
+
+ \sa validator() clearValidator() QValidator
+*/
+
+void QComboBox::setValidator( const QValidator * v )
+{
+ if ( d && d->ed )
+ d->ed->setValidator( v );
+}
+
+
+/*!
+ Returns the validator which constrains editing for this combobox
+ if there is one; otherwise returns 0.
+
+ \sa setValidator() clearValidator() QValidator
+*/
+
+const QValidator * QComboBox::validator() const
+{
+ return d && d->ed ? d->ed->validator() : 0;
+}
+
+
+/*!
+ This slot is equivalent to setValidator( 0 ).
+*/
+
+void QComboBox::clearValidator()
+{
+ if ( d && d->ed )
+ d->ed->setValidator( 0 );
+}
+
+
+/*!
+ Sets the combobox to use \a newListBox instead of the current list
+ box or popup. As a side effect, it clears the combobox of its
+ current contents.
+
+ \warning QComboBox assumes that newListBox->text(n) returns
+ non-null for 0 \<= n \< newListbox->count(). This assumption is
+ necessary because of the line edit in QComboBox.
+*/
+
+void QComboBox::setListBox( QListBox * newListBox )
+{
+ clear();
+
+ if ( d->usingListBox() ) {
+ delete d->listBox();
+ } else {
+ delete d->popup();
+ d->setPopupMenu(0, FALSE);
+ }
+
+ newListBox->reparent( this, WType_Popup, QPoint(0,0), FALSE );
+ d->setListBox( newListBox );
+ d->listBox()->setFont( font() );
+ d->listBox()->setPalette( palette() );
+ d->listBox()->setVScrollBarMode(QScrollView::AlwaysOff);
+ d->listBox()->setHScrollBarMode(QScrollView::AlwaysOff);
+ d->listBox()->setFrameStyle( QFrame::Box | QFrame::Plain );
+ d->listBox()->setLineWidth( 1 );
+ d->listBox()->resize( 100, 10 );
+
+ connect( d->listBox(), SIGNAL(selected(int)),
+ SLOT(internalActivate(int)) );
+ connect( d->listBox(), SIGNAL(highlighted(int)),
+ SLOT(internalHighlight(int)));
+}
+
+
+/*!
+ Returns the current list box, or 0 if there is no list box.
+ (QComboBox can use QPopupMenu instead of QListBox.) Provided to
+ match setListBox().
+
+ \sa setListBox()
+*/
+
+QListBox * QComboBox::listBox() const
+{
+ return d && d->usingListBox() ? d->listBox() : 0;
+}
+
+/*!
+ Returns the line edit, or 0 if there is no line edit.
+
+ Only editable listboxes have a line editor.
+*/
+QLineEdit* QComboBox::lineEdit() const
+{
+ return d->ed;
+}
+
+
+
+/*!
+ Clears the line edit without changing the combobox's contents.
+ Does nothing if the combobox isn't editable.
+
+ This is particularly useful when using a combobox as a line edit
+ with history. For example you can connect the combobox's
+ activated() signal to clearEdit() in order to present the user
+ with a new, empty line as soon as Enter is pressed.
+
+ \sa setEditText()
+*/
+
+void QComboBox::clearEdit()
+{
+ if ( d && d->ed )
+ d->ed->clear();
+}
+
+
+/*!
+ Sets the text in the line edit to \a newText without changing the
+ combobox's contents. Does nothing if the combobox isn't editable.
+
+ This is useful e.g. for providing a good starting point for the
+ user's editing and entering the change in the combobox only when
+ the user presses Enter.
+
+ \sa clearEdit() insertItem()
+*/
+
+void QComboBox::setEditText( const QString &newText )
+{
+ if ( d && d->ed ) {
+ d->updateLinedGeometry();
+ d->ed->setText( newText );
+ }
+}
+
+void QComboBox::setAutoCompletion( bool enable )
+{
+ d->useCompletion = enable;
+ d->completeNow = FALSE;
+}
+
+
+bool QComboBox::autoCompletion() const
+{
+ return d->useCompletion;
+}
+
+/*!\reimp
+ */
+void QComboBox::styleChange( QStyle& s )
+{
+ d->sizeHint = QSize(); // invalidate size hint...
+ if ( d->ed )
+ d->updateLinedGeometry();
+ QWidget::styleChange( s );
+}
+
+bool QComboBox::editable() const
+{
+ return d->ed != 0;
+}
+
+void QComboBox::setEditable( bool y )
+{
+ if ( y == editable() )
+ return;
+ if ( y ) {
+ if ( !d->usingListBox() )
+ setUpListBox();
+ setUpLineEdit();
+ d->ed->show();
+ if ( currentItem() )
+ setEditText( currentText() );
+ } else {
+ delete d->ed;
+ d->ed = 0;
+ }
+
+ setFocusPolicy( StrongFocus );
+ updateGeometry();
+ update();
+}
+
+
+void QComboBox::setUpListBox()
+{
+ d->setListBox( new QListBox( this, "in-combo", WType_Popup ) );
+ d->listBox()->setFont( font() );
+ d->listBox()->setPalette( palette() );
+ d->listBox()->setVScrollBarMode( QListBox::AlwaysOff );
+ d->listBox()->setHScrollBarMode( QListBox::AlwaysOff );
+ d->listBox()->setFrameStyle( QFrame::Box | QFrame::Plain );
+ d->listBox()->setLineWidth( 1 );
+ d->listBox()->resize( 100, 10 );
+
+ connect( d->listBox(), SIGNAL(selected(int)),
+ SLOT(internalActivate(int)) );
+ connect( d->listBox(), SIGNAL(highlighted(int)),
+ SLOT(internalHighlight(int)));
+}
+
+
+void QComboBox::setUpLineEdit()
+{
+ if ( !d->ed )
+ setLineEdit( new QLineEdit( this, "combo edit" ) );
+}
+
+/*!
+ Sets the line edit to use \a edit instead of the current line edit.
+*/
+
+void QComboBox::setLineEdit( QLineEdit *edit )
+{
+ if ( !edit ) {
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( edit != 0 );
+#endif
+ return;
+ }
+
+ edit->setText( currentText() );
+ delete d->ed;
+ d->ed = edit;
+
+ if ( edit->parent() != this )
+ edit->reparent( this, QPoint(0,0), FALSE );
+
+ connect (edit, SIGNAL( textChanged(const QString&) ),
+ this, SIGNAL( textChanged(const QString&) ) );
+ connect( edit, SIGNAL(returnPressed()), SLOT(returnPressed()) );
+
+ edit->setFrame( FALSE );
+ d->updateLinedGeometry();
+ edit->installEventFilter( this );
+ setFocusProxy( edit );
+ setFocusPolicy( StrongFocus );
+ setInputMethodEnabled( TRUE );
+
+ if ( !d->usingListBox() )
+ setUpListBox();
+
+ if ( isVisible() )
+ edit->show();
+
+ updateGeometry();
+ update();
+}
+
+/*!
+ \reimp
+*/
+void QComboBox::hide()
+{
+ QWidget::hide();
+
+ if (listBox())
+ listBox()->hide();
+ else if (d->popup())
+ d->popup()->hide();
+}
+
+#endif // QT_NO_COMBOBOX
diff --git a/src/widgets/qcombobox.h b/src/widgets/qcombobox.h
new file mode 100644
index 0000000..dfc9dde
--- /dev/null
+++ b/src/widgets/qcombobox.h
@@ -0,0 +1,206 @@
+/**********************************************************************
+**
+** Definition of QComboBox class
+**
+** Created : 950426
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QCOMBOBOX_H
+#define QCOMBOBOX_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+
+#ifndef QT_NO_COMBOBOX
+
+
+class QStrList;
+class QStringList;
+class QLineEdit;
+class QValidator;
+class QListBox;
+class QComboBoxData;
+class QWheelEvent;
+
+class Q_EXPORT QComboBox : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS( Policy )
+ Q_PROPERTY( bool editable READ editable WRITE setEditable )
+ Q_PROPERTY( int count READ count )
+ Q_PROPERTY( QString currentText READ currentText WRITE setCurrentText DESIGNABLE false )
+ Q_PROPERTY( int currentItem READ currentItem WRITE setCurrentItem )
+ Q_PROPERTY( bool autoResize READ autoResize WRITE setAutoResize DESIGNABLE false )
+ Q_PROPERTY( int sizeLimit READ sizeLimit WRITE setSizeLimit )
+ Q_PROPERTY( int maxCount READ maxCount WRITE setMaxCount )
+ Q_PROPERTY( Policy insertionPolicy READ insertionPolicy WRITE setInsertionPolicy )
+ Q_PROPERTY( bool autoCompletion READ autoCompletion WRITE setAutoCompletion )
+ Q_PROPERTY( bool duplicatesEnabled READ duplicatesEnabled WRITE setDuplicatesEnabled )
+ Q_OVERRIDE( bool autoMask DESIGNABLE true SCRIPTABLE true )
+
+public:
+ QComboBox( QWidget* parent=0, const char* name=0 );
+ QComboBox( bool rw, QWidget* parent=0, const char* name=0 );
+ ~QComboBox();
+
+ int count() const;
+
+ void insertStringList( const QStringList &, int index=-1 );
+ void insertStrList( const QStrList &, int index=-1 );
+ void insertStrList( const QStrList *, int index=-1 );
+ void insertStrList( const char **, int numStrings=-1, int index=-1);
+
+ void insertItem( const QString &text, int index=-1 );
+ void insertItem( const QPixmap &pixmap, int index=-1 );
+ void insertItem( const QPixmap &pixmap, const QString &text, int index=-1 );
+
+ void removeItem( int index );
+
+ int currentItem() const;
+ virtual void setCurrentItem( int index );
+
+ QString currentText() const;
+ virtual void setCurrentText( const QString& );
+
+ QString text( int index ) const;
+ const QPixmap *pixmap( int index ) const;
+
+ void changeItem( const QString &text, int index );
+ void changeItem( const QPixmap &pixmap, int index );
+ void changeItem( const QPixmap &pixmap, const QString &text, int index );
+
+ bool autoResize() const;
+ virtual void setAutoResize( bool );
+ QSize sizeHint() const;
+
+ void setPalette( const QPalette & );
+ void setFont( const QFont & );
+ void setEnabled( bool );
+
+ virtual void setSizeLimit( int );
+ int sizeLimit() const;
+
+ virtual void setMaxCount( int );
+ int maxCount() const;
+
+ enum Policy { NoInsertion, AtTop, AtCurrent, AtBottom,
+ AfterCurrent, BeforeCurrent };
+
+ virtual void setInsertionPolicy( Policy policy );
+ Policy insertionPolicy() const;
+
+ virtual void setValidator( const QValidator * );
+ const QValidator * validator() const;
+
+ virtual void setListBox( QListBox * );
+ QListBox * listBox() const;
+
+ virtual void setLineEdit( QLineEdit *edit );
+ QLineEdit* lineEdit() const;
+
+ virtual void setAutoCompletion( bool );
+ bool autoCompletion() const;
+
+ bool eventFilter( QObject *object, QEvent *event );
+
+ void setDuplicatesEnabled( bool enable );
+ bool duplicatesEnabled() const;
+
+ bool editable() const;
+ void setEditable( bool );
+
+ virtual void popup();
+
+ void hide();
+
+public slots:
+ void clear();
+ void clearValidator();
+ void clearEdit();
+ virtual void setEditText( const QString &);
+
+signals:
+ void activated( int index );
+ void highlighted( int index );
+ void activated( const QString &);
+ void highlighted( const QString &);
+ void textChanged( const QString &);
+
+private slots:
+ void internalActivate( int );
+ void internalHighlight( int );
+ void internalClickTimeout();
+ void returnPressed();
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void resizeEvent( QResizeEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent *e );
+ void focusInEvent( QFocusEvent *e );
+ void focusOutEvent( QFocusEvent *e );
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent *e );
+#endif
+ void styleChange( QStyle& );
+
+ void updateMask();
+
+private:
+ void setUpListBox();
+ void setUpLineEdit();
+ void popDownListBox();
+ void reIndex();
+ void currentChanged();
+ int completionIndex( const QString &, int ) const;
+
+ QComboBoxData *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QComboBox( const QComboBox & );
+ QComboBox &operator=( const QComboBox & );
+#endif
+};
+
+
+#endif // QT_NO_COMBOBOX
+
+#endif // QCOMBOBOX_H
diff --git a/src/widgets/qdatetimeedit.cpp b/src/widgets/qdatetimeedit.cpp
new file mode 100644
index 0000000..6f6ca71
--- /dev/null
+++ b/src/widgets/qdatetimeedit.cpp
@@ -0,0 +1,2842 @@
+/****************************************************************************
+**
+** Implementation of date and time edit classes
+**
+** Created : 001103
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qdatetimeedit.h"
+
+#ifndef QT_NO_DATETIMEEDIT
+
+#include "../kernel/qinternal_p.h"
+#include "../kernel/qrichtext_p.h"
+#include "qrangecontrol.h"
+#include "qapplication.h"
+#include "qpixmap.h"
+#include "qapplication.h"
+#include "qvaluelist.h"
+#include "qstring.h"
+#include "qstyle.h"
+
+#if defined(Q_WS_WIN)
+#include "qt_windows.h"
+#endif
+
+#define QDATETIMEEDIT_HIDDEN_CHAR '0'
+
+class Q_EXPORT QNumberSection
+{
+public:
+ QNumberSection( int selStart = 0, int selEnd = 0, bool separat = TRUE, int actual = -1 )
+ : selstart( selStart ), selend( selEnd ), act( actual ), sep( separat )
+ {}
+ int selectionStart() const { return selstart; }
+ void setSelectionStart( int s ) { selstart = s; }
+ int selectionEnd() const { return selend; }
+ void setSelectionEnd( int s ) { selend = s; }
+ int width() const { return selend - selstart; }
+ int index() const { return act; }
+ bool separator() const { return sep; }
+ Q_DUMMY_COMPARISON_OPERATOR( QNumberSection )
+private:
+ int selstart :12;
+ int selend :12;
+ int act :7;
+ bool sep :1;
+};
+
+static QString *lDateSep = 0;
+static QString *lTimeSep = 0;
+static bool lAMPM = FALSE;
+static QString *lAM = 0;
+static QString *lPM = 0;
+static QDateEdit::Order lOrder = QDateEdit::YMD;
+static int refcount = 0;
+
+static void cleanup()
+{
+ delete lDateSep;
+ lDateSep = 0;
+ delete lTimeSep;
+ lTimeSep = 0;
+ delete lAM;
+ lAM = 0;
+ delete lPM;
+ lPM = 0;
+}
+
+/*!
+\internal
+try to get the order of DMY and the date/time separator from the locale settings
+*/
+static void readLocaleSettings()
+{
+ int dpos, mpos, ypos;
+ cleanup();
+
+ lDateSep = new QString();
+ lTimeSep = new QString();
+
+#if defined(Q_WS_WIN)
+ QT_WA( {
+ TCHAR data[10];
+ GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SDATE, data, 10 );
+ *lDateSep = QString::fromUcs2( (ushort*)data );
+ GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_STIME, data, 10 );
+ *lTimeSep = QString::fromUcs2( (ushort*)data );
+ GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_ITIME, data, 10 );
+ lAMPM = QString::fromUcs2( (ushort*)data ).toInt()==0;
+ GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_S1159, data, 10 );
+ QString am = QString::fromUcs2( (ushort*)data );
+ if ( !am.isEmpty() )
+ lAM = new QString( am );
+ GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_S2359, data, 10 );
+ QString pm = QString::fromUcs2( (ushort*)data );
+ if ( !pm.isEmpty() )
+ lPM = new QString( pm );
+ } , {
+ char data[10];
+ GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SDATE, (char*)&data, 10 );
+ *lDateSep = QString::fromLocal8Bit( data );
+ GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_STIME, (char*)&data, 10 );
+ *lTimeSep = QString::fromLocal8Bit( data );
+ GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_ITIME, (char*)&data, 10 );
+ lAMPM = QString::fromLocal8Bit( data ).toInt()==0;
+ GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_S1159, (char*)&data, 10 );
+ QString am = QString::fromLocal8Bit( data );
+ if ( !am.isEmpty() )
+ lAM = new QString( am );
+ GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_S2359, (char*)&data, 10 );
+ QString pm = QString::fromLocal8Bit( data );
+ if ( !pm.isEmpty() )
+ lPM = new QString( pm );
+ } );
+#else
+ *lDateSep = "-";
+ *lTimeSep = ":";
+#endif
+ QString d = QDate( 1999, 11, 22 ).toString( Qt::LocalDate );
+ dpos = d.find( "22" );
+ mpos = d.find( "11" );
+ ypos = d.find( "99" );
+ if ( dpos > -1 && mpos > -1 && ypos > -1 ) {
+ // test for DMY, MDY, YMD, YDM
+ if ( dpos < mpos && mpos < ypos ) {
+ lOrder = QDateEdit::DMY;
+ } else if ( mpos < dpos && dpos < ypos ) {
+ lOrder = QDateEdit::MDY;
+ } else if ( ypos < mpos && mpos < dpos ) {
+ lOrder = QDateEdit::YMD;
+ } else if ( ypos < dpos && dpos < mpos ) {
+ lOrder = QDateEdit::YDM;
+ } else {
+ // cannot determine the dateformat - use the default
+ return;
+ }
+
+ // this code needs to change if new formats are added
+
+#ifndef Q_WS_WIN
+ QString sep = d.mid( QMIN( dpos, mpos ) + 2, QABS( dpos - mpos ) - 2 );
+ if ( d.contains( sep ) == 2 ) {
+ *lDateSep = sep;
+ }
+#endif
+ }
+
+#ifndef Q_WS_WIN
+ QString t = QTime( 11, 22, 33 ).toString( Qt::LocalDate );
+ dpos = t.find( "11" );
+ mpos = t.find( "22" );
+ ypos = t.find( "33" );
+ // We only allow hhmmss
+ if ( dpos > -1 && dpos < mpos && mpos < ypos ) {
+ QString sep = t.mid( dpos + 2, mpos - dpos - 2 );
+ if ( sep == t.mid( mpos + 2, ypos - mpos - 2 ) ) {
+ *lTimeSep = sep;
+ }
+ }
+#endif
+}
+
+static QDateEdit::Order localOrder() {
+ if ( !lDateSep ) {
+ readLocaleSettings();
+ }
+ return lOrder;
+}
+
+static QString localDateSep() {
+ if ( !lDateSep ) {
+ readLocaleSettings();
+ }
+ return *lDateSep;
+}
+
+static QString localTimeSep() {
+ if ( !lTimeSep ) {
+ readLocaleSettings();
+ }
+ return *lTimeSep;
+}
+
+class QDateTimeEditorPrivate
+{
+public:
+ QDateTimeEditorPrivate()
+ : frm( TRUE ),
+ parag( new QTextParagraph( 0, 0, 0, FALSE ) ),
+ focusSec(0)
+ {
+ parag->formatter()->setWrapEnabled( FALSE );
+ cursor = new QTextCursor( 0 );
+ cursor->setParagraph( parag );
+ offset = 0;
+ sep = localDateSep();
+ refcount++;
+ }
+ ~QDateTimeEditorPrivate()
+ {
+ delete parag;
+ delete cursor;
+ if ( !--refcount )
+ cleanup();
+ }
+
+ void appendSection( const QNumberSection& sec )
+ {
+ sections.append( sec );
+
+ }
+ void clearSections()
+ {
+ sections.clear();
+ }
+ void setSectionSelection( int sec, int selstart, int selend )
+ {
+ if ( sec < 0 || sec > (int)sections.count() )
+ return;
+ sections[sec].setSelectionStart( selstart );
+ sections[sec].setSelectionEnd( selend );
+ }
+ uint sectionCount() const { return (uint)sections.count(); }
+ void setSeparator( const QString& s ) { sep = s; }
+ QString separator() const { return sep; }
+
+ void setFrame( bool f ) { frm = f; }
+ bool frame() const { return frm; }
+
+ int focusSection() const { return focusSec; }
+ int section( const QPoint& p )
+ {
+ cursor->place( p + QPoint( offset, 0 ), parag );
+ int idx = cursor->index();
+ for ( uint i = 0; i < sections.count(); ++i ) {
+ if ( idx >= sections[i].selectionStart() &&
+ idx <= sections[i].selectionEnd() )
+ return i;
+ }
+ return -1;
+ }
+ QNumberSection section( int idx ) const
+ {
+ return sections[idx];
+ }
+ bool setFocusSection( int idx )
+ {
+ if ( idx > (int)sections.count()-1 || idx < 0 )
+ return FALSE;
+ if ( idx != focusSec ) {
+ focusSec = idx;
+ applyFocusSelection();
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ bool inSectionSelection( int idx )
+ {
+ for ( uint i = 0; i < sections.count(); ++i ) {
+ if ( idx >= sections[i].selectionStart() &&
+ idx <= sections[i].selectionEnd() )
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ void paint( const QString& txt, bool focus, QPainter& p,
+ const QColorGroup& cg, const QRect& rect, QStyle& style )
+ {
+ int fw = 0;
+ if ( frm )
+ fw = style.pixelMetric(QStyle::PM_DefaultFrameWidth);
+
+ parag->truncate( 0 );
+ parag->append( txt );
+ if ( !focus )
+ parag->removeSelection( QTextDocument::Standard );
+ else {
+ applyFocusSelection();
+ }
+
+ /* color all QDATETIMEEDIT_HIDDEN_CHAR chars to background color */
+ QTextFormat *fb = parag->formatCollection()->format( p.font(),
+ cg.base() );
+ QTextFormat *nf = parag->formatCollection()->format( p.font(),
+ cg.text() );
+ for ( uint i = 0; i < txt.length(); ++i ) {
+ parag->setFormat( i, 1, nf );
+ if ( inSectionSelection( i ) )
+ continue;
+ if ( txt.at(i) == QDATETIMEEDIT_HIDDEN_CHAR )
+ parag->setFormat( i, 1, fb );
+ else
+ parag->setFormat( i, 1, nf );
+ }
+ fb->removeRef();
+ nf->removeRef();
+
+ QRect r( rect.x(), rect.y(), rect.width() - 2 * ( 2 + fw ), rect.height() );
+ parag->pseudoDocument()->docRect = r;
+ parag->invalidate(0);
+ parag->format();
+
+ int xoff = 2 + fw - offset;
+ int yoff = ( rect.height() - parag->rect().height() + 1 ) / 2;
+ if ( yoff < 0 )
+ yoff = 0;
+
+ p.translate( xoff, yoff );
+ parag->paint( p, cg, 0, TRUE );
+ if ( frm )
+ p.translate( -xoff, -yoff );
+ }
+
+ void resize( const QSize& size ) { sz = size; }
+
+ int mapSection( int sec )
+ {
+ return sections[sec].index();
+ }
+
+protected:
+ void applyFocusSelection()
+ {
+ if ( focusSec > -1 ) {
+ int selstart = sections[ focusSec ].selectionStart();
+ int selend = sections[ focusSec ].selectionEnd();
+ parag->setSelection( QTextDocument::Standard, selstart, selend );
+ parag->format();
+ if ( parag->at( selstart )->x < offset ||
+ parag->at( selend )->x + parag->string()->width( selend ) > offset + sz.width() ) {
+ offset = parag->at( selstart )->x;
+ }
+ }
+ }
+private:
+ bool frm;
+ QTextParagraph *parag;
+ QTextCursor *cursor;
+ QSize sz;
+ int focusSec;
+ QValueList< QNumberSection > sections;
+ QString sep;
+ int offset;
+};
+
+class QDateTimeEditor : public QWidget
+{
+ Q_OBJECT
+public:
+ QDateTimeEditor( QDateTimeEditBase * widget, QWidget *parent,
+ const char * name=0 );
+ ~QDateTimeEditor();
+
+ void setControlWidget( QDateTimeEditBase * widget );
+ QDateTimeEditBase * controlWidget() const;
+
+ void setSeparator( const QString& s );
+ QString separator() const;
+
+ int focusSection() const;
+ bool setFocusSection( int s );
+ void appendSection( const QNumberSection& sec );
+ void clearSections();
+ void setSectionSelection( int sec, int selstart, int selend );
+ bool eventFilter( QObject *o, QEvent *e );
+ int sectionAt( const QPoint &p );
+ int mapSection( int sec );
+
+protected:
+ void init();
+ bool event( QEvent *e );
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+ void mousePressEvent( QMouseEvent *e );
+
+private:
+ QDateTimeEditBase* cw;
+ QDateTimeEditorPrivate* d;
+};
+
+class QDateTimeSpinWidget : public QSpinWidget
+{
+public:
+ QDateTimeSpinWidget( QWidget *parent, const char *name )
+ : QSpinWidget( parent, name )
+ {
+ }
+
+ void enabledChange(bool notenabled)
+ {
+ QDateEdit *de = ::qt_cast<QDateEdit*>(parentWidget());
+ if (de && !notenabled) {
+ setUpEnabled(de->date() < de->maxValue());
+ setDownEnabled(de->date() > de->minValue());
+ } else {
+ setUpEnabled(!notenabled);
+ setDownEnabled(!notenabled);
+ }
+ }
+
+protected:
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent *e )
+ {
+ QDateTimeEditor *editor = (QDateTimeEditor*)editWidget()->qt_cast( "QDateTimeEditor" );
+ Q_ASSERT( editor );
+ if ( !editor )
+ return;
+
+ int section = editor->sectionAt( e->pos() );
+ editor->setFocusSection( section );
+
+ if ( section == -1 )
+ return;
+ QSpinWidget::wheelEvent( e );
+ }
+#endif
+};
+
+/*!
+ Constructs an empty datetime editor with parent \a parent and
+ called \a name.
+*/
+QDateTimeEditor::QDateTimeEditor( QDateTimeEditBase * widget, QWidget *parent,
+ const char * name )
+ : QWidget( parent, name, WNoAutoErase )
+{
+ d = new QDateTimeEditorPrivate();
+ cw = widget;
+ init();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QDateTimeEditor::~QDateTimeEditor()
+{
+ delete d;
+}
+
+/*! \internal
+
+*/
+
+void QDateTimeEditor::init()
+{
+ setBackgroundMode( PaletteBase );
+ setFocusSection( -1 );
+ installEventFilter( this );
+ setFocusPolicy( WheelFocus );
+}
+
+
+/*! \reimp
+
+*/
+
+bool QDateTimeEditor::event( QEvent *e )
+{
+ if ( e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut ) {
+ if ( e->type() == QEvent::FocusOut )
+ qApp->sendEvent( cw, e );
+ update( rect() );
+ } else if ( e->type() == QEvent::AccelOverride ) {
+ QKeyEvent* ke = (QKeyEvent*) e;
+ switch ( ke->key() ) {
+ case Key_Delete:
+ case Key_Backspace:
+ case Key_Up:
+ case Key_Down:
+ case Key_Left:
+ case Key_Right:
+ ke->accept();
+ default:
+ break;
+ }
+ }
+ return QWidget::event( e );
+}
+
+/*! \reimp
+
+*/
+
+void QDateTimeEditor::resizeEvent( QResizeEvent *e )
+{
+ d->resize( e->size() );
+ QWidget::resizeEvent( e );
+}
+
+
+/*! \reimp
+
+*/
+
+void QDateTimeEditor::paintEvent( QPaintEvent * )
+{
+ QString txt;
+ for ( uint i = 0; i < d->sectionCount(); ++i ) {
+ txt += cw->sectionFormattedText( i );
+ if ( i < d->sectionCount()-1 ) {
+ if ( d->section( i+1 ).separator() )
+ txt += d->separator();
+ else
+ txt += " ";
+ }
+ }
+
+ QSharedDoubleBuffer buffer( this );
+ const QBrush &bg =
+ colorGroup().brush( isEnabled() ? QColorGroup::Base : QColorGroup::Background );
+ buffer.painter()->fillRect( 0, 0, width(), height(), bg );
+ d->paint( txt, hasFocus(), *buffer.painter(), colorGroup(), rect(),
+ style() );
+ buffer.end();
+}
+
+
+/*!
+ Returns the section index at point \a p.
+*/
+int QDateTimeEditor::sectionAt( const QPoint &p )
+{
+ return d->section( p );
+}
+
+int QDateTimeEditor::mapSection( int sec )
+{
+ return d->mapSection( sec );
+}
+
+
+/*! \reimp
+
+*/
+
+void QDateTimeEditor::mousePressEvent( QMouseEvent *e )
+{
+ QPoint p( e->pos().x(), 0 );
+ int sec = sectionAt( p );
+ if ( sec != -1 ) {
+ cw->setFocusSection( sec );
+ repaint( rect(), FALSE );
+ }
+}
+
+/*! \reimp
+
+*/
+bool QDateTimeEditor::eventFilter( QObject *o, QEvent *e )
+{
+ if ( o == this ) {
+ if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ switch ( ke->key() ) {
+ case Key_Right:
+ if ( d->focusSection() < (int)d->sectionCount()-1 ) {
+ if ( cw->setFocusSection( focusSection()+1 ) )
+ repaint( rect(), FALSE );
+ }
+ return TRUE;
+ case Key_Left:
+ if ( d->focusSection() > 0 ) {
+ if ( cw->setFocusSection( focusSection()-1 ) )
+ repaint( rect(), FALSE );
+ }
+ return TRUE;
+ case Key_Up:
+ cw->stepUp();
+ return TRUE;
+ case Key_Down:
+ cw->stepDown();
+ return TRUE;
+ case Key_Backspace:
+ if ( ::qt_cast<QDateEdit*>(cw) )
+ ((QDateEdit*)cw)->removeFirstNumber( d->focusSection() );
+ else if ( ::qt_cast<QTimeEdit*>(cw) )
+ ((QTimeEdit*)cw)->removeFirstNumber( d->focusSection() );
+ return TRUE;
+ case Key_Delete:
+ cw->removeLastNumber( d->focusSection() );
+ return TRUE;
+ case Key_Tab:
+ case Key_BackTab: {
+ if ( ke->state() == Qt::ControlButton )
+ return FALSE;
+
+ QWidget *w = this;
+ bool hadDateEdit = FALSE;
+ while ( w ) {
+ if ( ::qt_cast<QDateTimeSpinWidget*>(w) && qstrcmp( w->name(), "qt_spin_widget" ) != 0 ||
+ ::qt_cast<QDateTimeEdit*>(w) )
+ break;
+ hadDateEdit = hadDateEdit || ::qt_cast<QDateEdit*>(w);
+ w = w->parentWidget();
+ }
+
+ if ( w ) {
+ if ( !::qt_cast<QDateTimeEdit*>(w) ) {
+ w = w->parentWidget();
+ } else {
+ QDateTimeEdit *ed = (QDateTimeEdit*)w;
+ if ( hadDateEdit && ke->key() == Key_Tab ) {
+ ed->timeEdit()->setFocus();
+ return TRUE;
+ } else if ( !hadDateEdit && ke->key() == Key_BackTab ) {
+ ed->dateEdit()->setFocus();
+ return TRUE;
+ } else {
+ while ( w && !::qt_cast<QDateTimeEdit*>(w) )
+ w = w->parentWidget();
+ }
+ }
+
+ qApp->sendEvent( w, e );
+ return TRUE;
+ }
+ } break;
+ default:
+ QString txt = ke->text().lower();
+ if ( !txt.isEmpty() && !separator().isEmpty() && txt[0] == separator()[0] ) {
+ // do the same thing as KEY_RIGHT when the user presses the separator key
+ if ( d->focusSection() < 2 ) {
+ if ( cw->setFocusSection( focusSection()+1 ) )
+ repaint( rect(), FALSE );
+ }
+ return TRUE;
+ } else if ( !txt.isEmpty() && ::qt_cast<QTimeEdit*>(cw) && focusSection() == (int) d->sectionCount()-1 ) {
+ // the first character of the AM/PM indicator toggles if the section has focus
+ QTimeEdit *te = (QTimeEdit*)cw;
+ QTime time = te->time();
+ if ( lAMPM && lAM && lPM && (te->display()&QTimeEdit::AMPM) ) {
+ if ( txt[0] == (*lAM).lower()[0] && time.hour() >= 12 ) {
+ time.setHMS( time.hour()-12, time.minute(), time.second(), time.msec() );
+ te->setTime( time );
+ } else if ( txt[0] == (*lPM).lower()[0] && time.hour() < 12 ) {
+ time.setHMS( time.hour()+12, time.minute(), time.second(), time.msec() );
+ te->setTime( time );
+ }
+ }
+ }
+
+ int num = txt[0].digitValue();
+ if ( num != -1 ) {
+ cw->addNumber( d->focusSection(), num );
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/*!
+ Appends the number section \a sec to the editor.
+*/
+
+void QDateTimeEditor::appendSection( const QNumberSection& sec )
+{
+ d->appendSection( sec );
+}
+
+/*!
+ Removes all sections from the editor.
+*/
+
+void QDateTimeEditor::clearSections()
+{
+ d->clearSections();
+}
+
+/*!
+ Sets the selection of \a sec to start at \a selstart and end at \a
+ selend.
+*/
+
+void QDateTimeEditor::setSectionSelection( int sec, int selstart, int selend )
+{
+ d->setSectionSelection( sec, selstart, selend );
+}
+
+/*!
+ Sets the separator for all numbered sections to \a s. Note that
+ currently, only the first character of \a s is used.
+*/
+
+void QDateTimeEditor::setSeparator( const QString& s )
+{
+ d->setSeparator( s );
+ update();
+}
+
+
+/*!
+ Returns the editor's separator.
+*/
+
+QString QDateTimeEditor::separator() const
+{
+ return d->separator();
+}
+
+/*!
+ Returns the number of the section that has focus.
+*/
+
+int QDateTimeEditor::focusSection() const
+{
+ return d->focusSection();
+}
+
+
+/*!
+ Sets the focus to section \a sec. If \a sec does not exist,
+ nothing happens.
+*/
+
+bool QDateTimeEditor::setFocusSection( int sec )
+{
+ return d->setFocusSection( sec );
+}
+
+/*! \class QDateTimeEditBase
+ \brief The QDateTimeEditBase class provides an abstraction for date and edit editors.
+
+ Small abstract class that provides some functions that are common
+ for both QDateEdit and QTimeEdit. It is used internally by
+ QDateTimeEditor.
+*/
+
+/*!
+ \fn QDateTimeEditBase::QDateTimeEditBase(QWidget *, const char*)
+ \internal
+*/
+
+/*!
+ \fn QDateTimeEditBase::setFocusSection(int)
+ \internal
+*/
+
+/*! \fn QString QDateTimeEditBase::sectionFormattedText( int sec )
+ \internal
+
+ Pure virtual function which returns the formatted text of section \a
+ sec.
+
+*/
+
+/*! \fn void QDateTimeEditBase::stepUp()
+ \internal
+
+ Pure virtual slot which is called whenever the user increases the
+ number in a section by pressing the widget's arrow buttons or the
+ keyboard's arrow keys.
+*/
+
+/*! \fn void QDateTimeEditBase::stepDown()
+ \internal
+
+ Pure virtual slot which is called whenever the user decreases the
+ number in a section by pressing the widget's arrow buttons or the
+ keyboard's arrow keys.
+
+*/
+
+/*! \fn void QDateTimeEditBase::addNumber( int sec, int num )
+ \internal
+
+ Pure virtual function which is called whenever the user types a number.
+ \a sec indicates the section where the number should be added. \a
+ num is the number that was pressed.
+*/
+
+/*! \fn void QDateTimeEditBase::removeLastNumber( int sec )
+ \internal
+
+ Pure virtual function which is called whenever the user tries to
+ remove the last number from \a sec by pressing the delete key.
+*/
+
+////////////////
+
+class QDateEditPrivate
+{
+public:
+ int y;
+ int m;
+ int d;
+ // remebers the last entry for the day.
+ // if the day is 31 and you cycle through the months,
+ // the day will be 31 again if you reach a month with 31 days
+ // otherwise it will be the highest day in the month
+ int dayCache;
+ int yearSection;
+ int monthSection;
+ int daySection;
+ QDateEdit::Order ord;
+ bool overwrite;
+ bool adv;
+ int timerId;
+ bool typing;
+ QDate min;
+ QDate max;
+ bool changed;
+ QDateTimeEditor *ed;
+ QSpinWidget *controls;
+};
+
+
+/*!
+ \class QDateEdit qdatetimeedit.h
+ \brief The QDateEdit class provides a date editor.
+
+ \ingroup advanced
+ \ingroup time
+ \mainclass
+
+ QDateEdit allows the user to edit dates by using the keyboard or
+ the arrow keys to increase/decrease date values. The arrow keys
+ can be used to move from section to section within the QDateEdit
+ box. Dates appear in accordance with the local date/time settings
+ or in year, month, day order if the system doesn't provide this
+ information. It is recommended that the QDateEdit be initialised
+ with a date, e.g.
+
+ \code
+ QDateEdit *dateEdit = new QDateEdit( QDate::currentDate(), this );
+ dateEdit->setRange( QDate::currentDate().addDays( -365 ),
+ QDate::currentDate().addDays( 365 ) );
+ dateEdit->setOrder( QDateEdit::MDY );
+ dateEdit->setAutoAdvance( TRUE );
+ \endcode
+
+ Here we've created a new QDateEdit object initialised 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. If the auto
+ advance property is TRUE (as we've set it here) when the user
+ completes a section of the date, e.g. enters two digits for the
+ month, they are automatically taken to the next section.
+
+ The maximum and minimum values for a date value in the date editor
+ default to the maximum and minimum values for a QDate. You can
+ change this by calling setMinValue(), setMaxValue() or setRange().
+
+ Terminology: A QDateEdit widget comprises three 'sections', one
+ each for the year, month and day. You can change the separator
+ character using QDateTimeEditor::setSeparator(), by default the
+ separator will be taken from the systems settings. If that is
+ not possible, it defaults to "-".
+
+ \img datetimewidgets.png Date Time Widgets
+
+ \sa QDate QTimeEdit QDateTimeEdit
+*/
+
+/*!
+ \enum QDateEdit::Order
+
+ This enum defines the order in which the sections that comprise a
+ date appear.
+ \value MDY month-day-year
+ \value DMY day-month-year
+ \value YMD year-month-day (the default)
+ \value YDM year-day-month (included for completeness; but should
+ not be used)
+*/
+
+/*!
+ \enum QTimeEdit::Display
+
+ This enum defines the sections that comprise a time
+
+ \value Hours The hours section
+ \value Minutes The minutes section
+ \value Seconds The seconds section
+ \value AMPM The AM/PM section
+
+ The values can be or'ed together to show any combination.
+*/
+
+/*!
+ Constructs an empty date editor which is a child of \a parent and
+ called name \a name.
+*/
+
+QDateEdit::QDateEdit( QWidget * parent, const char * name )
+ : QDateTimeEditBase( parent, name )
+{
+ init();
+ updateButtons();
+}
+
+/*!
+ \overload
+
+ Constructs a date editor with the initial value \a date, parent \a
+ parent and called \a name.
+
+ The date editor is initialized with \a date.
+*/
+
+QDateEdit::QDateEdit( const QDate& date, QWidget * parent, const char * name )
+ : QDateTimeEditBase( parent, name )
+{
+ init();
+ setDate( date );
+}
+
+/*! \internal
+*/
+void QDateEdit::init()
+{
+ d = new QDateEditPrivate();
+ d->controls = new QDateTimeSpinWidget( this, qstrcmp( name(), "qt_datetime_dateedit" ) == 0 ? "qt_spin_widget" : "date edit controls" );
+ d->ed = new QDateTimeEditor( this, d->controls, "date editor" );
+ d->controls->setEditWidget( d->ed );
+ setFocusProxy( d->ed );
+ connect( d->controls, SIGNAL( stepUpPressed() ), SLOT( stepUp() ) );
+ connect( d->controls, SIGNAL( stepDownPressed() ), SLOT( stepDown() ) );
+ connect( this, SIGNAL( valueChanged(const QDate&) ),
+ SLOT( updateButtons() ) );
+ d->ed->appendSection( QNumberSection( 0,4 ) );
+ d->ed->appendSection( QNumberSection( 5,7 ) );
+ d->ed->appendSection( QNumberSection( 8,10 ) );
+
+ d->yearSection = -1;
+ d->monthSection = -1;
+ d->daySection = -1;
+
+ d->y = 0;
+ d->m = 0;
+ d->d = 0;
+ d->dayCache = 0;
+ setOrder( localOrder() );
+ setFocusSection( 0 );
+ d->overwrite = TRUE;
+ d->adv = FALSE;
+ d->timerId = 0;
+ d->typing = FALSE;
+ d->min = QDate( 1752, 9, 14 );
+ d->max = QDate( 8000, 12, 31 );
+ d->changed = FALSE;
+
+ setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
+
+ refcount++;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QDateEdit::~QDateEdit()
+{
+ delete d;
+ if ( !--refcount )
+ cleanup();
+}
+
+/*!
+ \property QDateEdit::minValue
+
+ \brief the editor's minimum value
+
+ Setting the minimum date value is equivalent to calling
+ QDateEdit::setRange( \e d, maxValue() ), where \e d is the minimum
+ date. The default minimum date is 1752-09-14.
+
+ \sa maxValue setRange()
+*/
+
+QDate QDateEdit::minValue() const
+{
+ return d->min;
+}
+
+/*!
+ \property QDateEdit::maxValue
+
+ \brief the editor's maximum value
+
+ Setting the maximum date value for the editor is equivalent to
+ calling QDateEdit::setRange( minValue(), \e d ), where \e d is the
+ maximum date. The default maximum date is 8000-12-31.
+
+ \sa minValue setRange()
+*/
+
+QDate QDateEdit::maxValue() const
+{
+ return d->max;
+}
+
+
+/*!
+ Sets the valid input range for the editor to be from \a min to \a
+ max inclusive. If \a min is invalid no minimum date will be set.
+ Similarly, if \a max is invalid no maximum date will be set.
+*/
+
+void QDateEdit::setRange( const QDate& min, const QDate& max )
+{
+ if ( min.isValid() )
+ d->min = min;
+ if ( max.isValid() )
+ d->max = max;
+}
+
+/*!
+ Sets the separator to \a s. Note that currently only the first
+ character of \a s is used.
+*/
+
+void QDateEdit::setSeparator( const QString& s )
+{
+ d->ed->setSeparator( s );
+}
+
+/*!
+ Returns the editor's separator.
+*/
+
+QString QDateEdit::separator() const
+{
+ return d->ed->separator();
+}
+
+
+/*!
+ Enables/disables the push buttons according to the min/max date
+ for this widget.
+*/
+
+void QDateEdit::updateButtons()
+{
+ if ( !isEnabled() )
+ return;
+
+ bool upEnabled = date() < maxValue();
+ bool downEnabled = date() > minValue();
+
+ d->controls->setUpEnabled( upEnabled );
+ d->controls->setDownEnabled( downEnabled );
+}
+
+/*! \reimp
+ */
+void QDateEdit::resizeEvent( QResizeEvent * )
+{
+ d->controls->resize( width(), height() );
+}
+
+/*! \reimp
+
+*/
+QSize QDateEdit::sizeHint() const
+{
+ constPolish();
+ QFontMetrics fm( font() );
+ int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this );
+ int h = QMAX( fm.lineSpacing(), 14 ) + 2;
+ int w = 2 + fm.width( '9' ) * 8 + fm.width( d->ed->separator() ) * 2 + d->controls->upRect().width() + fw * 4;
+
+ return QSize( w, QMAX(h + fw * 2,20) ).expandedTo( QApplication::globalStrut() );
+}
+
+/*! \reimp
+
+*/
+QSize QDateEdit::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+
+/*!
+ Returns the formatted number for section \a sec. This will
+ correspond to either the year, month or day section, depending on
+ the current display order.
+
+ \sa setOrder()
+*/
+
+QString QDateEdit::sectionFormattedText( int sec )
+{
+ QString txt;
+ txt = sectionText( sec );
+ if ( d->typing && sec == d->ed->focusSection() )
+ d->ed->setSectionSelection( sec, sectionOffsetEnd( sec ) - txt.length(),
+ sectionOffsetEnd( sec ) );
+ else
+ d->ed->setSectionSelection( sec, sectionOffsetEnd( sec ) - sectionLength( sec ),
+ sectionOffsetEnd( sec ) );
+ txt = txt.rightJustify( sectionLength( sec ), QDATETIMEEDIT_HIDDEN_CHAR );
+ return txt;
+}
+
+
+/*!
+ Returns the desired length (number of digits) of section \a sec.
+ This will correspond to either the year, month or day section,
+ depending on the current display order.
+
+ \sa setOrder()
+*/
+
+int QDateEdit::sectionLength( int sec ) const
+{
+ int val = 0;
+ if ( sec == d->yearSection ) {
+ val = 4;
+ } else if ( sec == d->monthSection ) {
+ val = 2;
+ } else if ( sec == d->daySection ) {
+ val = 2;
+ }
+ return val;
+}
+
+/*!
+ Returns the text of section \a sec. This will correspond to either
+ the year, month or day section, depending on the current display
+ order.
+
+ \sa setOrder()
+*/
+
+QString QDateEdit::sectionText( int sec ) const
+{
+ int val = 0;
+ if ( sec == d->yearSection ) {
+ val = d->y;
+ } else if ( sec == d->monthSection ) {
+ val = d->m;
+ } else if ( sec == d->daySection ) {
+ val = d->d;
+ }
+ return QString::number( val );
+}
+
+/*! \internal
+
+ Returns the end of the section offset \a sec.
+
+*/
+
+int QDateEdit::sectionOffsetEnd( int sec ) const
+{
+ if ( sec == d->yearSection ) {
+ switch( d->ord ) {
+ case DMY:
+ case MDY:
+ return sectionOffsetEnd( sec-1) + separator().length() + sectionLength( sec );
+ case YMD:
+ case YDM:
+ return sectionLength( sec );
+ }
+ } else if ( sec == d->monthSection ) {
+ switch( d->ord ) {
+ case DMY:
+ case YDM:
+ case YMD:
+ return sectionOffsetEnd( sec-1) + separator().length() + sectionLength( sec );
+ case MDY:
+ return sectionLength( sec );
+ }
+ } else if ( sec == d->daySection ) {
+ switch( d->ord ) {
+ case DMY:
+ return sectionLength( sec );
+ case YMD:
+ case MDY:
+ case YDM:
+ return sectionOffsetEnd( sec-1 ) + separator().length() + sectionLength( sec );
+ }
+ }
+ return 0;
+}
+
+
+/*!
+ \property QDateEdit::order
+ \brief the order in which the year, month and day appear
+
+ The default order is locale dependent.
+
+ \sa Order
+*/
+
+void QDateEdit::setOrder( QDateEdit::Order order )
+{
+ d->ord = order;
+ switch( d->ord ) {
+ case DMY:
+ d->yearSection = 2;
+ d->monthSection = 1;
+ d->daySection = 0;
+ break;
+ case MDY:
+ d->yearSection = 2;
+ d->monthSection = 0;
+ d->daySection = 1;
+ break;
+ case YMD:
+ d->yearSection = 0;
+ d->monthSection = 1;
+ d->daySection = 2;
+ break;
+ case YDM:
+ d->yearSection = 0;
+ d->monthSection = 2;
+ d->daySection = 1;
+ break;
+ }
+ if ( isVisible() )
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+
+QDateEdit::Order QDateEdit::order() const
+{
+ return d->ord;
+}
+
+
+/*! \reimp
+
+*/
+void QDateEdit::stepUp()
+{
+ int sec = d->ed->focusSection();
+ bool accepted = FALSE;
+ if ( sec == d->yearSection ) {
+ if ( !outOfRange( d->y+1, d->m, d->d ) ) {
+ accepted = TRUE;
+ setYear( d->y+1 );
+ }
+ } else if ( sec == d->monthSection ) {
+ if ( !outOfRange( d->y, d->m+1, d->d ) ) {
+ accepted = TRUE;
+ setMonth( d->m+1 );
+ }
+ } else if ( sec == d->daySection ) {
+ if ( !outOfRange( d->y, d->m, d->d+1 ) ) {
+ accepted = TRUE;
+ setDay( d->d+1 );
+ }
+ }
+ if ( accepted ) {
+ d->changed = FALSE;
+ emit valueChanged( date() );
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+
+
+/*! \reimp
+
+*/
+
+void QDateEdit::stepDown()
+{
+ int sec = d->ed->focusSection();
+ bool accepted = FALSE;
+ if ( sec == d->yearSection ) {
+ if ( !outOfRange( d->y-1, d->m, d->d ) ) {
+ accepted = TRUE;
+ setYear( d->y-1 );
+ }
+ } else if ( sec == d->monthSection ) {
+ if ( !outOfRange( d->y, d->m-1, d->d ) ) {
+ accepted = TRUE;
+ setMonth( d->m-1 );
+ }
+ } else if ( sec == d->daySection ) {
+ if ( !outOfRange( d->y, d->m, d->d-1 ) ) {
+ accepted = TRUE;
+ setDay( d->d-1 );
+ }
+ }
+ if ( accepted ) {
+ d->changed = FALSE;
+ emit valueChanged( date() );
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+/*!
+ Sets the year to \a year, which must be a valid year. The range
+ currently supported is from 1752 to 8000.
+
+ \sa QDate
+*/
+
+void QDateEdit::setYear( int year )
+{
+ if ( year < 1752 )
+ year = 1752;
+ if ( year > 8000 )
+ year = 8000;
+ if ( !outOfRange( year, d->m, d->d ) ) {
+ d->y = year;
+ setMonth( d->m );
+ int tmp = d->dayCache;
+ setDay( d->dayCache );
+ d->dayCache = tmp;
+ }
+}
+
+
+/*!
+ Sets the month to \a month, which must be a valid month, i.e.
+ between 1 and 12.
+*/
+
+void QDateEdit::setMonth( int month )
+{
+ if ( month < 1 )
+ month = 1;
+ if ( month > 12 )
+ month = 12;
+ if ( !outOfRange( d->y, month, d->d ) ) {
+ d->m = month;
+ int tmp = d->dayCache;
+ setDay( d->dayCache );
+ d->dayCache = tmp;
+ }
+}
+
+
+/*!
+ Sets the day to \a day, which must be a valid day. The function
+ will ensure that the \a day set is valid for the month and year.
+*/
+
+void QDateEdit::setDay( int day )
+{
+ if ( day < 1 )
+ day = 1;
+ if ( day > 31 )
+ day = 31;
+ if ( d->m > 0 && d->y > 1752 ) {
+ while ( !QDate::isValid( d->y, d->m, day ) )
+ --day;
+ if ( !outOfRange( d->y, d->m, day ) )
+ d->d = day;
+ } else if ( d->m > 0 ) {
+ if ( day > 0 && day < 32 ) {
+ if ( !outOfRange( d->y, d->m, day ) )
+ d->d = day;
+ }
+ }
+ d->dayCache = d->d;
+}
+
+
+/*!
+ \property QDateEdit::date
+ \brief the editor's date value.
+
+ If the date property is not valid, the editor displays all zeroes
+ and QDateEdit::date() will return an invalid date. It is strongly
+ recommended that the editor is given a default date value (e.g.
+ currentDate()). That way, attempts to set the date property to an
+ invalid date will fail.
+
+ When changing the date property, if the date is less than
+ minValue(), or is greater than maxValue(), nothing happens.
+*/
+
+void QDateEdit::setDate( const QDate& date )
+{
+ if ( !date.isValid() ) {
+ d->y = 0;
+ d->m = 0;
+ d->d = 0;
+ d->dayCache = 0;
+ } else {
+ if ( date > maxValue() || date < minValue() )
+ return;
+ d->y = date.year();
+ d->m = date.month();
+ d->d = date.day();
+ d->dayCache = d->d;
+ emit valueChanged( date );
+ }
+ d->changed = FALSE;
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+QDate QDateEdit::date() const
+{
+ if ( QDate::isValid( d->y, d->m, d->d ) )
+ return QDate( d->y, d->m, d->d );
+ return QDate();
+}
+
+/*! \internal
+
+ Returns TRUE if \a y, \a m, \a d is out of range, otherwise returns
+ FALSE.
+
+ \sa setRange()
+
+*/
+
+bool QDateEdit::outOfRange( int y, int m, int d ) const
+{
+ if ( QDate::isValid( y, m, d ) ) {
+ QDate currentDate( y, m, d );
+ if ( currentDate > maxValue() ||
+ currentDate < minValue() ) {
+ //## outOfRange should set overwrite?
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return FALSE; /* assume ok */
+}
+
+/*! \reimp
+
+*/
+
+void QDateEdit::addNumber( int sec, int num )
+{
+ if ( sec == -1 )
+ return;
+ killTimer( d->timerId );
+ bool overwrite = FALSE;
+ bool accepted = FALSE;
+ d->typing = TRUE;
+ QString txt;
+ if ( sec == d->yearSection ) {
+ txt = QString::number( d->y );
+ if ( d->overwrite || txt.length() == 4 ) {
+ accepted = TRUE;
+ d->y = num;
+ } else {
+ txt += QString::number( num );
+ if ( txt.length() == 4 ) {
+ int val = txt.toInt();
+ if ( val < 1792 )
+ d->y = 1792;
+ else if ( val > 8000 )
+ d->y = 8000;
+ else if ( outOfRange( val, d->m, d->d ) )
+ txt = QString::number( d->y );
+ else {
+ accepted = TRUE;
+ d->y = val;
+ }
+ } else {
+ accepted = TRUE;
+ d->y = txt.toInt();
+ }
+ if ( d->adv && txt.length() == 4 ) {
+ d->ed->setFocusSection( d->ed->focusSection()+1 );
+ overwrite = TRUE;
+ }
+ }
+ } else if ( sec == d->monthSection ) {
+ txt = QString::number( d->m );
+ if ( d->overwrite || txt.length() == 2 ) {
+ accepted = TRUE;
+ d->m = num;
+ } else {
+ txt += QString::number( num );
+ int temp = txt.toInt();
+ if ( temp > 12 )
+ temp = num;
+ if ( outOfRange( d->y, temp, d->d ) )
+ txt = QString::number( d->m );
+ else {
+ accepted = TRUE;
+ d->m = temp;
+ }
+ if ( d->adv && txt.length() == 2 ) {
+ d->ed->setFocusSection( d->ed->focusSection()+1 );
+ overwrite = TRUE;
+ }
+ }
+ } else if ( sec == d->daySection ) {
+ txt = QString::number( d->d );
+ if ( d->overwrite || txt.length() == 2 ) {
+ accepted = TRUE;
+ d->d = num;
+ d->dayCache = d->d;
+ } else {
+ txt += QString::number( num );
+ int temp = txt.toInt();
+ if ( temp > 31 )
+ temp = num;
+ if ( outOfRange( d->y, d->m, temp ) )
+ txt = QString::number( d->d );
+ else {
+ accepted = TRUE;
+ d->d = temp;
+ d->dayCache = d->d;
+ }
+ if ( d->adv && txt.length() == 2 ) {
+ d->ed->setFocusSection( d->ed->focusSection()+1 );
+ overwrite = TRUE;
+ }
+ }
+ }
+ if ( accepted ) {
+ d->changed = FALSE;
+ emit valueChanged( date() );
+ }
+ d->overwrite = overwrite;
+ d->timerId = startTimer( qApp->doubleClickInterval()*4 );
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+
+/*! \reimp
+
+*/
+
+bool QDateEdit::setFocusSection( int s )
+{
+ if ( s != d->ed->focusSection() ) {
+ killTimer( d->timerId );
+ d->overwrite = TRUE;
+ d->typing = FALSE;
+ fix(); // will emit valueChanged if necessary
+ }
+ return d->ed->setFocusSection( s );
+}
+
+
+/*!
+ Attempts to fix any invalid date entries.
+
+ The rules applied are as follows:
+
+ \list
+ \i If the year has four digits it is left unchanged.
+ \i If the year has two digits, the year will be changed to four
+ digits in the range current year - 70 to current year + 29.
+ \i If the year has three digits in the range 100..999, the
+ current millennium, i.e. 2000, will be added giving a year
+ in the range 2100..2999.
+ \i If the day or month is 0 then it will be set to 1 or the
+ minimum valid day\month in the range.
+ \endlist
+
+*/
+
+void QDateEdit::fix()
+{
+ bool changed = FALSE;
+ int currentYear = QDate::currentDate().year();
+ int year = d->y;
+ if ( year < 100 ) {
+ int currentCentury = currentYear / 100;
+ year += currentCentury * 100;
+ if ( currentYear > year ) {
+ if ( currentYear > year + 70 )
+ year += 100;
+ } else {
+ if ( year >= currentYear + 30 )
+ year -= 100;
+ }
+ changed = TRUE;
+ } else if ( year < 1000 ) {
+ int currentMillennium = currentYear / 10;
+ year += currentMillennium * 10;
+ changed = TRUE;
+ } else if (d->d == 0) {
+ d->d = 1;
+ changed = TRUE;
+ } else if (d->m == 0) {
+ d->m = 1;
+ changed = TRUE;
+ }
+ if ( outOfRange( year, d->m, d->d ) ) {
+ if ( minValue().isValid() && date() < minValue() ) {
+ d->d = minValue().day();
+ d->dayCache = d->d;
+ d->m = minValue().month();
+ d->y = minValue().year();
+ }
+ if ( date() > maxValue() ) {
+ d->d = maxValue().day();
+ d->dayCache = d->d;
+ d->m = maxValue().month();
+ d->y = maxValue().year();
+ }
+ changed = TRUE;
+ } else if ( changed )
+ setYear( year );
+ if ( changed ) {
+ emit valueChanged( date() );
+ d->changed = FALSE;
+ }
+}
+
+
+/*! \reimp
+
+*/
+
+bool QDateEdit::event( QEvent *e )
+{
+ if( e->type() == QEvent::FocusOut ) {
+ d->typing = FALSE;
+ fix();
+ // the following can't be done in fix() because fix() called
+ // from all over the place and it will break the old behaviour
+ if ( !QDate::isValid( d->y, d->m, d->d ) ) {
+ d->dayCache = d->d;
+ int i = d->d;
+ for ( ; i > 0; i-- ) {
+ d->d = i;
+ if ( QDate::isValid( d->y, d->m, d->d ) )
+ break;
+ }
+ d->changed = TRUE;
+ }
+ if ( d->changed ) {
+ emit valueChanged( date() );
+ d->changed = FALSE;
+ }
+ } else if ( e->type() == QEvent::LocaleChange ) {
+ readLocaleSettings();
+ d->ed->setSeparator( localDateSep() );
+ setOrder( localOrder() );
+ }
+ return QDateTimeEditBase::event( e );
+}
+
+/*!
+ \internal
+
+ Function which is called whenever the user tries to
+ remove the first number from \a sec by pressing the backspace key.
+*/
+
+void QDateEdit::removeFirstNumber( int sec )
+{
+ if ( sec == -1 )
+ return;
+ QString txt;
+ if ( sec == d->yearSection ) {
+ txt = QString::number( d->y );
+ txt = txt.mid( 1, txt.length() ) + "0";
+ d->y = txt.toInt();
+ } else if ( sec == d->monthSection ) {
+ txt = QString::number( d->m );
+ txt = txt.mid( 1, txt.length() ) + "0";
+ d->m = txt.toInt();
+ } else if ( sec == d->daySection ) {
+ txt = QString::number( d->d );
+ txt = txt.mid( 1, txt.length() ) + "0";
+ d->d = txt.toInt();
+ d->dayCache = d->d;
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+/*! \reimp
+
+*/
+
+void QDateEdit::removeLastNumber( int sec )
+{
+ if ( sec == -1 )
+ return;
+ QString txt;
+ if ( sec == d->yearSection ) {
+ txt = QString::number( d->y );
+ txt = txt.mid( 0, txt.length()-1 );
+ d->y = txt.toInt();
+ } else if ( sec == d->monthSection ) {
+ txt = QString::number( d->m );
+ txt = txt.mid( 0, txt.length()-1 );
+ d->m = txt.toInt();
+ } else if ( sec == d->daySection ) {
+ txt = QString::number( d->d );
+ txt = txt.mid( 0, txt.length()-1 );
+ d->d = txt.toInt();
+ d->dayCache = d->d;
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+/*!
+ \property QDateEdit::autoAdvance
+ \brief whether the editor automatically advances to the next
+ section
+
+ If autoAdvance is TRUE, the editor will automatically advance
+ focus to the next date section if a user has completed a section.
+ The default is FALSE.
+*/
+
+void QDateEdit::setAutoAdvance( bool advance )
+{
+ d->adv = advance;
+}
+
+
+bool QDateEdit::autoAdvance() const
+{
+ return d->adv;
+}
+
+/*! \reimp
+*/
+
+void QDateEdit::timerEvent( QTimerEvent * )
+{
+ d->overwrite = TRUE;
+}
+
+/*!
+ \fn void QDateEdit::valueChanged( const QDate& date )
+
+ This signal is emitted whenever the editor's value changes. The \a
+ date parameter is the new value.
+*/
+
+///////////
+
+class QTimeEditPrivate
+{
+public:
+ int h;
+ int m;
+ int s;
+ uint display;
+ bool adv;
+ bool overwrite;
+ int timerId;
+ bool typing;
+ QTime min;
+ QTime max;
+ bool changed;
+ QDateTimeEditor *ed;
+ QSpinWidget *controls;
+};
+
+/*!
+ \class QTimeEdit qdatetimeedit.h
+ \brief The QTimeEdit class provides a time editor.
+
+ \ingroup advanced
+ \ingroup time
+ \mainclass
+
+ QTimeEdit allows the user to edit times by using the keyboard or
+ the arrow keys to increase/decrease time values. The arrow keys
+ can be used to move from section to section within the QTimeEdit
+ box. The user can automatically be moved to the next section once
+ they complete a section using setAutoAdvance(). Times appear in
+ hour, minute, second order. It is recommended that the QTimeEdit
+ is initialised with a time, e.g.
+ \code
+ QTime timeNow = QTime::currentTime();
+ QTimeEdit *timeEdit = new QTimeEdit( timeNow, this );
+ timeEdit->setRange( timeNow, timeNow.addSecs( 60 * 60 ) );
+ \endcode
+ Here we've created a QTimeEdit widget set to the current time.
+ We've also set the minimum value to the current time and the
+ maximum time to one hour from now.
+
+ The maximum and minimum values for a time value in the time editor
+ default to the maximum and minimum values for a QTime. You can
+ change this by calling setMinValue(), setMaxValue() or setRange().
+
+ Terminology: A QTimeWidget consists of three sections, one each
+ for the hour, minute and second. You can change the separator
+ character using setSeparator(), by default the separator is read
+ from the system's settings.
+
+ \img datetimewidgets.png Date Time Widgets
+
+ \sa QTime QDateEdit QDateTimeEdit
+*/
+
+
+/*!
+ Constructs an empty time edit with parent \a parent and called \a
+ name.
+*/
+
+QTimeEdit::QTimeEdit( QWidget * parent, const char * name )
+ : QDateTimeEditBase( parent, name )
+{
+ init();
+}
+
+/*!
+ \overload
+
+ Constructs a time edit with the initial time value, \a time,
+ parent \a parent and called \a name.
+*/
+
+QTimeEdit::QTimeEdit( const QTime& time, QWidget * parent, const char * name )
+ : QDateTimeEditBase( parent, name )
+{
+ init();
+ setTime( time );
+}
+
+/*! \internal
+ */
+
+void QTimeEdit::init()
+{
+ d = new QTimeEditPrivate();
+ d->controls = new QDateTimeSpinWidget( this, qstrcmp( name(), "qt_datetime_timeedit" ) == 0 ? "qt_spin_widget" : "time edit controls" );
+ d->ed = new QDateTimeEditor( this, d->controls, "time edit base" );
+ d->controls->setEditWidget( d->ed );
+ setFocusProxy( d->ed );
+ connect( d->controls, SIGNAL( stepUpPressed() ), SLOT( stepUp() ) );
+ connect( d->controls, SIGNAL( stepDownPressed() ), SLOT( stepDown() ) );
+
+ d->ed->appendSection( QNumberSection( 0,0, TRUE, 0 ) );
+ d->ed->appendSection( QNumberSection( 0,0, TRUE, 1 ) );
+ d->ed->appendSection( QNumberSection( 0,0, TRUE, 2 ) );
+ d->ed->setSeparator( localTimeSep() );
+
+ d->h = 0;
+ d->m = 0;
+ d->s = 0;
+ d->display = Hours | Minutes | Seconds;
+ if ( lAMPM ) {
+ d->display |= AMPM;
+ d->ed->appendSection( QNumberSection( 0,0, FALSE, 3 ) );
+ }
+ d->adv = FALSE;
+ d->overwrite = TRUE;
+ d->timerId = 0;
+ d->typing = FALSE;
+ d->min = QTime( 0, 0, 0 );
+ d->max = QTime( 23, 59, 59 );
+ d->changed = FALSE;
+
+ setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
+
+ refcount++;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QTimeEdit::~QTimeEdit()
+{
+ delete d;
+ if ( !--refcount )
+ cleanup();
+}
+
+/*!
+ \property QTimeEdit::minValue
+ \brief the minimum time value
+
+ Setting the minimum time value is equivalent to calling
+ QTimeEdit::setRange( \e t, maxValue() ), where \e t is the minimum
+ time. The default minimum time is 00:00:00.
+
+ \sa maxValue setRange()
+*/
+
+QTime QTimeEdit::minValue() const
+{
+ return d->min;
+}
+
+/*!
+ \property QTimeEdit::maxValue
+ \brief the maximum time value
+
+ Setting the maximum time value is equivalent to calling
+ QTimeEdit::setRange( minValue(), \e t ), where \e t is the maximum
+ time. The default maximum time is 23:59:59.
+
+ \sa minValue setRange()
+*/
+
+QTime QTimeEdit::maxValue() const
+{
+ return d->max;
+}
+
+
+/*!
+ Sets the valid input range for the editor to be from \a min to \a
+ max inclusive. If \a min is invalid no minimum time is set.
+ Similarly, if \a max is invalid no maximum time is set.
+*/
+
+void QTimeEdit::setRange( const QTime& min, const QTime& max )
+{
+ if ( min.isValid() )
+ d->min = min;
+ if ( max.isValid() )
+ d->max = max;
+}
+
+/*!
+ \property QTimeEdit::display
+ \brief the sections that are displayed in the time edit
+
+ The value can be any combination of the values in the Display enum.
+ By default, the widget displays hours, minutes and seconds.
+*/
+void QTimeEdit::setDisplay( uint display )
+{
+ if ( d->display == display )
+ return;
+
+ d->ed->clearSections();
+ d->display = display;
+ if ( d->display & Hours )
+ d->ed->appendSection( QNumberSection( 0,0, TRUE, 0 ) );
+ if ( d->display & Minutes )
+ d->ed->appendSection( QNumberSection( 0,0, TRUE, 1 ) );
+ if ( d->display & Seconds )
+ d->ed->appendSection( QNumberSection( 0,0, TRUE, 2 ) );
+ if ( d->display & AMPM )
+ d->ed->appendSection( QNumberSection( 0,0, FALSE, 3 ) );
+
+ d->ed->setFocusSection( 0 );
+ d->ed->update();
+}
+
+uint QTimeEdit::display() const
+{
+ return d->display;
+}
+
+/*!
+ \property QTimeEdit::time
+ \brief the editor's time value.
+
+ When changing the time property, if the time is less than
+ minValue(), or is greater than maxValue(), nothing happens.
+*/
+
+void QTimeEdit::setTime( const QTime& time )
+{
+ if ( !time.isValid() ) {
+ d->h = 0;
+ d->m = 0;
+ d->s = 0;
+ } else {
+ if ( time > maxValue() || time < minValue() )
+ return;
+ d->h = time.hour();
+ d->m = time.minute();
+ d->s = time.second();
+ emit valueChanged( time );
+ }
+ d->changed = FALSE;
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+QTime QTimeEdit::time() const
+{
+ if ( QTime::isValid( d->h, d->m, d->s ) )
+ return QTime( d->h, d->m, d->s );
+ return QTime();
+}
+
+/*!
+ \property QTimeEdit::autoAdvance
+ \brief whether the editor automatically advances to the next
+ section
+
+ If autoAdvance is TRUE, the editor will automatically advance
+ focus to the next time section if a user has completed a section.
+ The default is FALSE.
+*/
+
+void QTimeEdit::setAutoAdvance( bool advance )
+{
+ d->adv = advance;
+}
+
+bool QTimeEdit::autoAdvance() const
+{
+ return d->adv;
+}
+
+/*!
+ Sets the separator to \a s. Note that currently only the first
+ character of \a s is used.
+*/
+
+void QTimeEdit::setSeparator( const QString& s )
+{
+ d->ed->setSeparator( s );
+}
+
+/*!
+ Returns the editor's separator.
+*/
+
+QString QTimeEdit::separator() const
+{
+ return d->ed->separator();
+}
+
+
+/*!
+ \fn void QTimeEdit::valueChanged( const QTime& time )
+
+ This signal is emitted whenever the editor's value changes. The \a
+ time parameter is the new value.
+*/
+
+/*! \reimp
+
+*/
+
+bool QTimeEdit::event( QEvent *e )
+{
+ if ( e->type() == QEvent::FocusOut ) {
+ d->typing = FALSE;
+ if ( d->changed ) {
+ emit valueChanged( time() );
+ d->changed = FALSE;
+ }
+ } else if ( e->type() == QEvent::LocaleChange ) {
+ readLocaleSettings();
+ d->ed->setSeparator( localTimeSep() );
+ }
+ return QDateTimeEditBase::event( e );
+}
+
+/*! \reimp
+
+*/
+
+void QTimeEdit::timerEvent( QTimerEvent * )
+{
+ d->overwrite = TRUE;
+}
+
+
+/*! \reimp
+
+*/
+
+void QTimeEdit::stepUp()
+{
+ if (minValue() > maxValue()) {
+ return;
+ }
+ int sec = d->ed->mapSection( d->ed->focusSection() );
+ bool accepted = TRUE;
+ switch( sec ) {
+ case 0:
+ do {
+ d->h = (d->h + 1) % 24;
+ } while (outOfRange(d->h, d->m, d->s));
+ break;
+ case 1:
+ do {
+ d->m = (d->m + 1) % 60;
+ } while (outOfRange(d->h, d->m, d->s));
+ break;
+ case 2:
+ do {
+ d->s = (d->s + 1) % 60;
+ } while (outOfRange(d->h, d->m, d->s));
+ break;
+ case 3:
+ if ( d->h < 12 )
+ setHour( d->h+12 );
+ else
+ setHour( d->h-12 );
+ break;
+ default:
+ accepted = FALSE;
+#ifdef QT_CHECK_RANGE
+ qWarning( "QTimeEdit::stepUp: Focus section out of range!" );
+#endif
+ break;
+ }
+ if ( accepted ) {
+ d->changed = FALSE;
+ emit valueChanged( time() );
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+
+/*! \reimp
+
+*/
+
+void QTimeEdit::stepDown()
+{
+ if (minValue() > maxValue()) {
+ return;
+ }
+
+ int sec = d->ed->mapSection( d->ed->focusSection() );
+ bool accepted = TRUE;
+ switch( sec ) {
+ case 0:
+ do {
+ if (--d->h < 0)
+ d->h = 23;
+ } while (outOfRange(d->h, d->m, d->s));
+ break;
+ case 1:
+ do {
+ if (--d->m < 0)
+ d->m = 59;
+ } while (outOfRange(d->h, d->m, d->s));
+ break;
+ case 2:
+ do {
+ if (--d->s < 0)
+ d->s = 59;
+ } while (outOfRange(d->h, d->m, d->s));
+ break;
+ case 3:
+ if ( d->h > 11 )
+ setHour( d->h-12 );
+ else
+ setHour( d->h+12 );
+ break;
+ default:
+ accepted = FALSE;
+#ifdef QT_CHECK_RANGE
+ qWarning( "QTimeEdit::stepDown: Focus section out of range!" );
+#endif
+ break;
+ }
+ if ( accepted ) {
+ d->changed = FALSE;
+ emit valueChanged( time() );
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+
+/*!
+ Returns the formatted number for section \a sec. This will
+ correspond to either the hour, minute or second section, depending
+ on \a sec.
+*/
+
+QString QTimeEdit::sectionFormattedText( int sec )
+{
+ QString txt;
+ txt = sectionText( sec );
+ txt = txt.rightJustify( 2, QDATETIMEEDIT_HIDDEN_CHAR );
+ int offset = sec*2+sec*separator().length() + txt.length();
+ if ( d->typing && sec == d->ed->focusSection() )
+ d->ed->setSectionSelection( sec, offset - txt.length(), offset );
+ else
+ d->ed->setSectionSelection( sec, offset - txt.length(), offset );
+
+ return txt;
+}
+
+
+/*! \reimp
+
+*/
+
+bool QTimeEdit::setFocusSection( int sec )
+{
+ if ( sec != d->ed->focusSection() ) {
+ killTimer( d->timerId );
+ d->overwrite = TRUE;
+ d->typing = FALSE;
+ QString txt = sectionText( sec );
+ txt = txt.rightJustify( 2, QDATETIMEEDIT_HIDDEN_CHAR );
+ int offset = sec*2+sec*separator().length() + txt.length();
+ d->ed->setSectionSelection( sec, offset - txt.length(), offset );
+ if ( d->changed ) {
+ emit valueChanged( time() );
+ d->changed = FALSE;
+ }
+ }
+ return d->ed->setFocusSection( sec );
+}
+
+
+/*!
+ Sets the hour to \a h, which must be a valid hour, i.e. in the
+ range 0..24.
+*/
+
+void QTimeEdit::setHour( int h )
+{
+ if ( h < 0 )
+ h = 0;
+ if ( h > 23 )
+ h = 23;
+ d->h = h;
+}
+
+
+/*!
+ Sets the minute to \a m, which must be a valid minute, i.e. in the
+ range 0..59.
+*/
+
+void QTimeEdit::setMinute( int m )
+{
+ if ( m < 0 )
+ m = 0;
+ if ( m > 59 )
+ m = 59;
+ d->m = m;
+}
+
+
+/*!
+ Sets the second to \a s, which must be a valid second, i.e. in the
+ range 0..59.
+*/
+
+void QTimeEdit::setSecond( int s )
+{
+ if ( s < 0 )
+ s = 0;
+ if ( s > 59 )
+ s = 59;
+ d->s = s;
+}
+
+
+/*! \internal
+
+ Returns the text of section \a sec.
+
+*/
+
+QString QTimeEdit::sectionText( int sec )
+{
+ sec = d->ed->mapSection( sec );
+
+ QString txt;
+ switch( sec ) {
+ case 0:
+ if ( !(d->display & AMPM) || ( d->h < 13 && d->h ) ) { // I wished the day stared at 0:00 for everybody
+ txt = QString::number( d->h );
+ } else {
+ if ( d->h )
+ txt = QString::number( d->h - 12 );
+ else
+ txt = "12";
+ }
+ break;
+ case 1:
+ txt = QString::number( d->m );
+ break;
+ case 2:
+ txt = QString::number( d->s );
+ break;
+ case 3:
+ if ( d->h < 12 ) {
+ if ( lAM )
+ txt = *lAM;
+ else
+ txt = QString::fromLatin1( "AM" );
+ } else {
+ if ( lPM )
+ txt = *lPM;
+ else
+ txt = QString::fromLatin1( "PM" );
+ }
+ break;
+ default:
+ break;
+ }
+ return txt;
+}
+
+
+/*! \internal
+ Returns TRUE if \a h, \a m, and \a s are out of range.
+ */
+
+bool QTimeEdit::outOfRange( int h, int m, int s ) const
+{
+ if ( QTime::isValid( h, m, s ) ) {
+ QTime currentTime( h, m, s );
+ if ( currentTime > maxValue() ||
+ currentTime < minValue() )
+ return TRUE;
+ else
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*! \reimp
+
+*/
+
+void QTimeEdit::addNumber( int sec, int num )
+{
+ if ( sec == -1 )
+ return;
+ sec = d->ed->mapSection( sec );
+ killTimer( d->timerId );
+ bool overwrite = FALSE;
+ bool accepted = FALSE;
+ d->typing = TRUE;
+ QString txt;
+
+ switch( sec ) {
+ case 0:
+ txt = ( d->display & AMPM && d->h > 12 ) ?
+ QString::number( d->h - 12 ) : QString::number( d->h );
+
+ if ( d->overwrite || txt.length() == 2 ) {
+ if ( d->display & AMPM && num == 0 )
+ break; // Don't process 0 in 12 hour clock mode
+ if ( d->display & AMPM && d->h > 11 )
+ num += 12;
+ if ( !outOfRange( num, d->m, d->s ) ) {
+ accepted = TRUE;
+ d->h = num;
+ }
+ } else {
+ txt += QString::number( num );
+ int temp = txt.toInt();
+
+ if ( d->display & AMPM ) {
+ if ( temp == 12 ) {
+ if ( d->h < 12 ) {
+ temp = 0;
+ }
+ accepted = TRUE;
+ } else if ( outOfRange( temp + 12, d->m, d->s ) ) {
+ txt = QString::number( d->h );
+ } else {
+ if ( d->h > 11 ) {
+ temp += 12;
+ }
+ accepted = TRUE;
+ }
+ } else if ( !(d->display & AMPM) && outOfRange( temp, d->m, d->s ) ) {
+ txt = QString::number( d->h );
+ } else {
+ accepted = TRUE;
+ }
+
+ if ( accepted )
+ d->h = temp;
+
+ if ( d->adv && txt.length() == 2 ) {
+ setFocusSection( d->ed->focusSection()+1 );
+ overwrite = TRUE;
+ }
+ }
+ break;
+
+ case 1:
+ txt = QString::number( d->m );
+ if ( d->overwrite || txt.length() == 2 ) {
+ if ( !outOfRange( d->h, num, d->s ) ) {
+ accepted = TRUE;
+ d->m = num;
+ }
+ } else {
+ txt += QString::number( num );
+ int temp = txt.toInt();
+ if ( temp > 59 )
+ temp = num;
+ if ( outOfRange( d->h, temp, d->s ) )
+ txt = QString::number( d->m );
+ else {
+ accepted = TRUE;
+ d->m = temp;
+ }
+ if ( d->adv && txt.length() == 2 ) {
+ setFocusSection( d->ed->focusSection()+1 );
+ overwrite = TRUE;
+ }
+ }
+ break;
+
+ case 2:
+ txt = QString::number( d->s );
+ if ( d->overwrite || txt.length() == 2 ) {
+ if ( !outOfRange( d->h, d->m, num ) ) {
+ accepted = TRUE;
+ d->s = num;
+ }
+ } else {
+ txt += QString::number( num );
+ int temp = txt.toInt();
+ if ( temp > 59 )
+ temp = num;
+ if ( outOfRange( d->h, d->m, temp ) )
+ txt = QString::number( d->s );
+ else {
+ accepted = TRUE;
+ d->s = temp;
+ }
+ if ( d->adv && txt.length() == 2 ) {
+ setFocusSection( d->ed->focusSection()+1 );
+ overwrite = TRUE;
+ }
+ }
+ break;
+
+ case 3:
+ break;
+
+ default:
+ break;
+ }
+ d->changed = !accepted;
+ if ( accepted )
+ emit valueChanged( time() );
+ d->overwrite = overwrite;
+ d->timerId = startTimer( qApp->doubleClickInterval()*4 );
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+
+/*!
+ \internal
+
+ Function which is called whenever the user tries to
+ remove the first number from \a sec by pressing the backspace key.
+*/
+
+void QTimeEdit::removeFirstNumber( int sec )
+{
+ if ( sec == -1 )
+ return;
+ sec = d->ed->mapSection( sec );
+ QString txt;
+ switch( sec ) {
+ case 0:
+ txt = QString::number( d->h );
+ break;
+ case 1:
+ txt = QString::number( d->m );
+ break;
+ case 2:
+ txt = QString::number( d->s );
+ break;
+ }
+ txt = txt.mid( 1, txt.length() ) + "0";
+ switch( sec ) {
+ case 0:
+ d->h = txt.toInt();
+ break;
+ case 1:
+ d->m = txt.toInt();
+ break;
+ case 2:
+ d->s = txt.toInt();
+ break;
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+/*! \reimp
+
+*/
+void QTimeEdit::removeLastNumber( int sec )
+{
+ if ( sec == -1 )
+ return;
+ sec = d->ed->mapSection( sec );
+ QString txt;
+ switch( sec ) {
+ case 0:
+ txt = QString::number( d->h );
+ break;
+ case 1:
+ txt = QString::number( d->m );
+ break;
+ case 2:
+ txt = QString::number( d->s );
+ break;
+ }
+ txt = txt.mid( 0, txt.length()-1 );
+ switch( sec ) {
+ case 0:
+ d->h = txt.toInt();
+ break;
+ case 1:
+ d->m = txt.toInt();
+ break;
+ case 2:
+ d->s = txt.toInt();
+ break;
+ }
+ d->ed->repaint( d->ed->rect(), FALSE );
+}
+
+/*! \reimp
+ */
+void QTimeEdit::resizeEvent( QResizeEvent * )
+{
+ d->controls->resize( width(), height() );
+}
+
+/*! \reimp
+*/
+QSize QTimeEdit::sizeHint() const
+{
+ constPolish();
+ QFontMetrics fm( font() );
+ int fw = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this );
+ int h = fm.lineSpacing() + 2;
+ int w = 2 + fm.width( '9' ) * 6 + fm.width( d->ed->separator() ) * 2 +
+ d->controls->upRect().width() + fw * 4;
+ if ( d->display & AMPM ) {
+ if ( lAM )
+ w += fm.width( *lAM ) + 4;
+ else
+ w += fm.width( QString::fromLatin1( "AM" ) ) + 4;
+ }
+
+ return QSize( w, QMAX(h + fw * 2,20) ).expandedTo( QApplication::globalStrut() );
+}
+
+/*! \reimp
+*/
+QSize QTimeEdit::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+/*!
+ \internal
+ Enables/disables the push buttons according to the min/max time
+ for this widget.
+*/
+
+// ### Remove in 4.0?
+
+void QTimeEdit::updateButtons()
+{
+ if ( !isEnabled() )
+ return;
+
+ bool upEnabled = time() < maxValue();
+ bool downEnabled = time() > minValue();
+
+ d->controls->setUpEnabled( upEnabled );
+ d->controls->setDownEnabled( downEnabled );
+}
+
+
+class QDateTimeEditPrivate
+{
+public:
+ bool adv;
+};
+
+/*!
+ \class QDateTimeEdit qdatetimeedit.h
+ \brief The QDateTimeEdit class combines a QDateEdit and QTimeEdit
+ widget into a single widget for editing datetimes.
+
+ \ingroup advanced
+ \ingroup time
+ \mainclass
+
+ QDateTimeEdit consists of a QDateEdit and QTimeEdit widget placed
+ side by side and offers the functionality of both. The user can
+ edit the date and time by using the keyboard or the arrow keys to
+ increase/decrease date or time values. The Tab key can be used to
+ move from section to section within the QDateTimeEdit widget, and
+ the user can be moved automatically when they complete a section
+ using setAutoAdvance(). The datetime can be set with
+ setDateTime().
+
+ The date format is read from the system's locale settings. It is
+ set to year, month, day order if that is not possible. See
+ QDateEdit::setOrder() to change this. Times appear in the order
+ hours, minutes, seconds using the 24 hour clock.
+
+ It is recommended that the QDateTimeEdit is initialised with a
+ datetime, e.g.
+ \code
+ QDateTimeEdit *dateTimeEdit = new QDateTimeEdit( QDateTime::currentDateTime(), this );
+ dateTimeEdit->dateEdit()->setRange( QDateTime::currentDate(),
+ QDateTime::currentDate().addDays( 7 ) );
+ \endcode
+ Here we've created a new QDateTimeEdit set to the current date and
+ time, and set the date to have a minimum date of now and a maximum
+ date of a week from now.
+
+ Terminology: A QDateEdit widget consists of three 'sections', one
+ each for the year, month and day. Similarly a QTimeEdit consists
+ of three sections, one each for the hour, minute and second. The
+ character that separates each date section is specified with
+ setDateSeparator(); similarly setTimeSeparator() is used for the
+ time sections.
+
+ \img datetimewidgets.png Date Time Widgets
+
+ \sa QDateEdit QTimeEdit
+*/
+
+/*!
+ Constructs an empty datetime edit with parent \a parent and called
+ \a name.
+*/
+QDateTimeEdit::QDateTimeEdit( QWidget * parent, const char * name )
+ : QWidget( parent, name )
+{
+ init();
+}
+
+
+/*!
+ \overload
+
+ Constructs a datetime edit with the initial value \a datetime,
+ parent \a parent and called \a name.
+*/
+QDateTimeEdit::QDateTimeEdit( const QDateTime& datetime,
+ QWidget * parent, const char * name )
+ : QWidget( parent, name )
+{
+ init();
+ setDateTime( datetime );
+}
+
+
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QDateTimeEdit::~QDateTimeEdit()
+{
+ delete d;
+}
+
+
+/*!
+ \reimp
+
+ Intercepts and handles resize events which have special meaning
+ for the QDateTimeEdit.
+*/
+
+void QDateTimeEdit::resizeEvent( QResizeEvent * )
+{
+ int dw = de->sizeHint().width();
+ int tw = te->sizeHint().width();
+ int w = width();
+ int h = height();
+ int extra = w - ( dw + tw );
+
+ if ( tw + extra < 0 ) {
+ dw = w;
+ } else {
+ dw += 9 * extra / 16;
+ }
+ tw = w - dw;
+
+ de->setGeometry( 0, 0, dw, h );
+ te->setGeometry( dw, 0, tw, h );
+}
+
+/*! \reimp
+*/
+
+QSize QDateTimeEdit::minimumSizeHint() const
+{
+ QSize dsh = de->minimumSizeHint();
+ QSize tsh = te->minimumSizeHint();
+ return QSize( dsh.width() + tsh.width(),
+ QMAX( dsh.height(), tsh.height() ) );
+}
+
+/*! \internal
+ */
+
+void QDateTimeEdit::init()
+{
+ d = new QDateTimeEditPrivate();
+ de = new QDateEdit( this, "qt_datetime_dateedit" );
+ te = new QTimeEdit( this, "qt_datetime_timeedit" );
+ d->adv = FALSE;
+ connect( de, SIGNAL( valueChanged(const QDate&) ),
+ this, SLOT( newValue(const QDate&) ) );
+ connect( te, SIGNAL( valueChanged(const QTime&) ),
+ this, SLOT( newValue(const QTime&) ) );
+ setFocusProxy( de );
+ setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
+}
+
+/*! \reimp
+ */
+
+QSize QDateTimeEdit::sizeHint() const
+{
+ constPolish();
+ QSize dsh = de->sizeHint();
+ QSize tsh = te->sizeHint();
+ return QSize( dsh.width() + tsh.width(),
+ QMAX( dsh.height(), tsh.height() ) );
+}
+
+/*!
+ \property QDateTimeEdit::dateTime
+ \brief the editor's datetime value
+
+ The datetime edit's datetime which may be an invalid datetime.
+*/
+
+void QDateTimeEdit::setDateTime( const QDateTime & dt )
+{
+ if ( dt.isValid() ) {
+ de->setDate( dt.date() );
+ te->setTime( dt.time() );
+ emit valueChanged( dt );
+ }
+}
+
+QDateTime QDateTimeEdit::dateTime() const
+{
+ return QDateTime( de->date(), te->time() );
+}
+
+/*!
+ \fn void QDateTimeEdit::valueChanged( const QDateTime& datetime )
+
+ This signal is emitted every time the date or time changes. The \a
+ datetime argument is the new datetime.
+*/
+
+
+/*! \internal
+
+ Re-emits the value \a d.
+ */
+
+void QDateTimeEdit::newValue( const QDate& )
+{
+ QDateTime dt = dateTime();
+ emit valueChanged( dt );
+}
+
+/*! \internal
+ \overload
+ Re-emits the value \a t.
+ */
+
+void QDateTimeEdit::newValue( const QTime& )
+{
+ QDateTime dt = dateTime();
+ emit valueChanged( dt );
+}
+
+
+/*!
+ Sets the auto advance property of the editor to \a advance. If set
+ to TRUE, the editor will automatically advance focus to the next
+ date or time section if the user has completed a section.
+*/
+
+void QDateTimeEdit::setAutoAdvance( bool advance )
+{
+ de->setAutoAdvance( advance );
+ te->setAutoAdvance( advance );
+}
+
+/*!
+ Returns TRUE if auto-advance is enabled, otherwise returns FALSE.
+
+ \sa setAutoAdvance()
+*/
+
+bool QDateTimeEdit::autoAdvance() const
+{
+ return de->autoAdvance();
+}
+
+/*!
+ \fn QDateEdit* QDateTimeEdit::dateEdit()
+
+ Returns the internal widget used for editing the date part of the
+ datetime.
+*/
+
+/*!
+ \fn QTimeEdit* QDateTimeEdit::timeEdit()
+
+ Returns the internal widget used for editing the time part of the
+ datetime.
+*/
+
+#include "qdatetimeedit.moc"
+
+#endif
diff --git a/src/widgets/qdatetimeedit.h b/src/widgets/qdatetimeedit.h
new file mode 100644
index 0000000..b61781e
--- /dev/null
+++ b/src/widgets/qdatetimeedit.h
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** Definition of date and time edit classes
+**
+** Created : 001103
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QDATETIMEEDIT_H
+#define QDATETIMEEDIT_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qstring.h"
+#include "qdatetime.h"
+#endif // QT_H
+
+#ifndef QT_NO_DATETIMEEDIT
+
+class Q_EXPORT QDateTimeEditBase : public QWidget
+{
+ Q_OBJECT
+public:
+ QDateTimeEditBase( QWidget* parent=0, const char* name=0 )
+ : QWidget( parent, name ) {}
+
+ virtual bool setFocusSection( int sec ) = 0;
+ virtual QString sectionFormattedText( int sec ) = 0;
+ virtual void addNumber( int sec, int num ) = 0;
+ virtual void removeLastNumber( int sec ) = 0;
+
+public slots:
+ virtual void stepUp() = 0;
+ virtual void stepDown() = 0;
+
+private:
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ QDateTimeEditBase( const QDateTimeEditBase & );
+ QDateTimeEditBase &operator=( const QDateTimeEditBase & );
+#endif
+};
+
+class QDateEditPrivate;
+
+class Q_EXPORT QDateEdit : public QDateTimeEditBase
+{
+ Q_OBJECT
+ Q_ENUMS( Order )
+ Q_PROPERTY( Order order READ order WRITE setOrder )
+ Q_PROPERTY( QDate date READ date WRITE setDate )
+ Q_PROPERTY( bool autoAdvance READ autoAdvance WRITE setAutoAdvance )
+ Q_PROPERTY( QDate maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( QDate minValue READ minValue WRITE setMinValue )
+
+public:
+ QDateEdit( QWidget* parent=0, const char* name=0 );
+ QDateEdit( const QDate& date, QWidget* parent=0, const char* name=0 );
+ ~QDateEdit();
+
+ enum Order { DMY, MDY, YMD, YDM };
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+public slots:
+ virtual void setDate( const QDate& date );
+
+public:
+ QDate date() const;
+ virtual void setOrder( Order order );
+ Order order() const;
+ virtual void setAutoAdvance( bool advance );
+ bool autoAdvance() const;
+
+ virtual void setMinValue( const QDate& d ) { setRange( d, maxValue() ); }
+ QDate minValue() const;
+ virtual void setMaxValue( const QDate& d ) { setRange( minValue(), d ); }
+ QDate maxValue() const;
+ virtual void setRange( const QDate& min, const QDate& max );
+ QString separator() const;
+ virtual void setSeparator( const QString& s );
+
+ // Make removeFirstNumber() virtual in QDateTimeEditBase in 4.0
+ void removeFirstNumber( int sec );
+
+signals:
+ void valueChanged( const QDate& date );
+
+protected:
+ bool event( QEvent *e );
+ void timerEvent( QTimerEvent * );
+ void resizeEvent( QResizeEvent * );
+ void stepUp();
+ void stepDown();
+ QString sectionFormattedText( int sec );
+ void addNumber( int sec, int num );
+
+ void removeLastNumber( int sec );
+ bool setFocusSection( int s );
+
+ virtual void setYear( int year );
+ virtual void setMonth( int month );
+ virtual void setDay( int day );
+ virtual void fix();
+ virtual bool outOfRange( int y, int m, int d ) const;
+
+protected slots:
+ void updateButtons();
+
+private:
+ void init();
+ int sectionOffsetEnd( int sec ) const;
+ int sectionLength( int sec ) const;
+ QString sectionText( int sec ) const;
+ QDateEditPrivate* d;
+
+#if defined(Q_DISABLE_COPY)
+ QDateEdit( const QDateEdit & );
+ QDateEdit &operator=( const QDateEdit & );
+#endif
+};
+
+class QTimeEditPrivate;
+
+class Q_EXPORT QTimeEdit : public QDateTimeEditBase
+{
+ Q_OBJECT
+ Q_SETS( Display )
+ Q_PROPERTY( QTime time READ time WRITE setTime )
+ Q_PROPERTY( bool autoAdvance READ autoAdvance WRITE setAutoAdvance )
+ Q_PROPERTY( QTime maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( QTime minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( Display display READ display WRITE setDisplay )
+
+public:
+ enum Display {
+ Hours = 0x01,
+ Minutes = 0x02,
+ Seconds = 0x04,
+ /*Reserved = 0x08,*/
+ AMPM = 0x10
+ };
+
+ QTimeEdit( QWidget* parent=0, const char* name=0 );
+ QTimeEdit( const QTime& time, QWidget* parent=0, const char* name=0 );
+ ~QTimeEdit();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+public slots:
+ virtual void setTime( const QTime& time );
+
+public:
+ QTime time() const;
+ virtual void setAutoAdvance( bool advance );
+ bool autoAdvance() const;
+
+ virtual void setMinValue( const QTime& d ) { setRange( d, maxValue() ); }
+ QTime minValue() const;
+ virtual void setMaxValue( const QTime& d ) { setRange( minValue(), d ); }
+ QTime maxValue() const;
+ virtual void setRange( const QTime& min, const QTime& max );
+ QString separator() const;
+ virtual void setSeparator( const QString& s );
+
+ uint display() const;
+ void setDisplay( uint disp );
+
+ // Make removeFirstNumber() virtual in QDateTimeEditBase in 4.0
+ void removeFirstNumber( int sec );
+
+signals:
+ void valueChanged( const QTime& time );
+
+protected:
+ bool event( QEvent *e );
+ void timerEvent( QTimerEvent *e );
+ void resizeEvent( QResizeEvent * );
+ void stepUp();
+ void stepDown();
+ QString sectionFormattedText( int sec );
+ void addNumber( int sec, int num );
+ void removeLastNumber( int sec );
+ bool setFocusSection( int s );
+
+ virtual bool outOfRange( int h, int m, int s ) const;
+ virtual void setHour( int h );
+ virtual void setMinute( int m );
+ virtual void setSecond( int s );
+
+protected slots:
+ void updateButtons();
+
+private:
+ void init();
+ QString sectionText( int sec );
+ QTimeEditPrivate* d;
+
+#if defined(Q_DISABLE_COPY)
+ QTimeEdit( const QTimeEdit & );
+ QTimeEdit &operator=( const QTimeEdit & );
+#endif
+};
+
+
+class QDateTimeEditPrivate;
+
+class Q_EXPORT QDateTimeEdit : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY( QDateTime dateTime READ dateTime WRITE setDateTime )
+
+public:
+ QDateTimeEdit( QWidget* parent=0, const char* name=0 );
+ QDateTimeEdit( const QDateTime& datetime, QWidget* parent=0,
+ const char* name=0 );
+ ~QDateTimeEdit();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+public slots:
+ virtual void setDateTime( const QDateTime & dt );
+
+public:
+ QDateTime dateTime() const;
+
+ QDateEdit* dateEdit() { return de; }
+ QTimeEdit* timeEdit() { return te; }
+
+ virtual void setAutoAdvance( bool advance );
+ bool autoAdvance() const;
+
+signals:
+ void valueChanged( const QDateTime& datetime );
+
+protected:
+ // ### make init() private in Qt 4.0
+ void init();
+ void resizeEvent( QResizeEvent * );
+
+protected slots:
+ // ### make these two functions private in Qt 4.0,
+ // and merge them into one with no parameter
+ void newValue( const QDate& d );
+ void newValue( const QTime& t );
+
+private:
+ QDateEdit* de;
+ QTimeEdit* te;
+ QDateTimeEditPrivate* d;
+
+#if defined(Q_DISABLE_COPY)
+ QDateTimeEdit( const QDateTimeEdit & );
+ QDateTimeEdit &operator=( const QDateTimeEdit & );
+#endif
+};
+
+#endif
+#endif
diff --git a/src/widgets/qdial.cpp b/src/widgets/qdial.cpp
new file mode 100644
index 0000000..40041cd
--- /dev/null
+++ b/src/widgets/qdial.cpp
@@ -0,0 +1,976 @@
+/****************************************************************************
+**
+** Implementation of the dial widget
+**
+** Created : 979899
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qdial.h"
+
+#ifndef QT_NO_DIAL
+
+#include "qpainter.h"
+#include "qpointarray.h"
+#include "qcolor.h"
+#include "qapplication.h"
+#include "qregion.h"
+#include "qbitmap.h"
+#include "qstyle.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+#include <math.h> // sin(), cos(), atan()
+//### Forutsetter linking med math lib - Jfr kommentar i qpainter_x11.cpp!
+
+static const double m_pi = 3.14159265358979323846;
+static const double rad_factor = 180.0 / m_pi;
+
+
+class QDialPrivate
+{
+public:
+ QDialPrivate()
+ {
+ wrapping = FALSE;
+ tracking = TRUE;
+ doNotEmit = FALSE;
+ target = 3.7;
+ mousePressed = FALSE;
+ }
+
+ bool wrapping;
+ bool tracking;
+ bool doNotEmit;
+ double target;
+ QRect eraseArea;
+ bool eraseAreaValid;
+ bool showNotches;
+ bool onlyOutside;
+ bool mousePressed;
+
+ QPointArray lines;
+};
+
+
+/*!
+ \class QDial qdial.h
+
+ \brief The QDial class provides a rounded range control (like a speedometer or potentiometer).
+
+ \ingroup basic
+ \mainclass
+
+ QDial is used when the user needs to control a value within a
+ program-definable range, and the range either wraps around
+ (typically, 0..359 degrees) or the dialog layout needs a square
+ widget.
+
+ Both API- and UI-wise, the dial is very similar to a \link QSlider
+ slider. \endlink Indeed, when wrapping() is FALSE (the default)
+ there is no real difference between a slider and a dial. They
+ have the same signals, slots and member functions, all of which do
+ the same things. Which one you use depends only on your taste
+ and on the application.
+
+ The dial initially emits valueChanged() signals continuously while
+ the slider is being moved; you can make it emit the signal less
+ often by calling setTracking(FALSE). dialMoved() is emitted
+ continuously even when tracking() is FALSE.
+
+ The slider also emits dialPressed() and dialReleased() signals
+ when the mouse button is pressed and released. But note that the
+ dial's value can change without these signals being emitted; the
+ keyboard and wheel can be used to change the value.
+
+ Unlike the slider, QDial attempts to draw a "nice" number of
+ notches rather than one per lineStep(). If possible, the number
+ of notches drawn is one per lineStep(), but if there aren't enough
+ pixels to draw every one, QDial will draw every second, third
+ etc., notch. notchSize() returns the number of units per notch,
+ hopefully a multiple of lineStep(); setNotchTarget() sets the
+ target distance between neighbouring notches in pixels. The
+ default is 3.75 pixels.
+
+ Like the slider, the dial makes the QRangeControl functions
+ setValue(), addLine(), subtractLine(), addPage() and
+ subtractPage() available as slots.
+
+ The dial's keyboard interface is fairly simple: The left/up and
+ right/down arrow keys move by lineStep(), page up and page down by
+ pageStep() and Home and End to minValue() and maxValue().
+
+ <img src=qdial-m.png> <img src=qdial-w.png>
+
+ \sa QScrollBar QSpinBox
+ \link guibooks.html#fowler GUI Design Handbook: Slider\endlink
+*/
+
+
+
+
+/*!
+ Constructs a dial called \a name with parent \a parent. \a f is
+ propagated to the QWidget constructor. It has the default range of
+ a QRangeControl.
+*/
+
+QDial::QDial( QWidget *parent, const char *name, WFlags f )
+ : QWidget( parent, name, f | WNoAutoErase ), QRangeControl()
+{
+ d = new QDialPrivate;
+ d->eraseAreaValid = FALSE;
+ d->showNotches = FALSE;
+ d->onlyOutside = FALSE;
+ setFocusPolicy( QWidget::WheelFocus );
+}
+
+
+
+/*!
+ Constructs a dial called \a name with parent \a parent. The dial's
+ value can never be smaller than \a minValue or greater than \a
+ maxValue. Its page step size is \a pageStep, and its initial value
+ is \a value.
+
+ \a value is forced to be within the legal range.
+*/
+
+QDial::QDial( int minValue, int maxValue, int pageStep, int value,
+ QWidget *parent, const char *name )
+ : QWidget( parent, name, WNoAutoErase ),
+ QRangeControl( minValue, maxValue, 1, pageStep, value )
+{
+ d = new QDialPrivate;
+ d->eraseAreaValid = FALSE;
+ d->showNotches = FALSE;
+ d->onlyOutside = FALSE;
+ setFocusPolicy( QWidget::WheelFocus );
+}
+
+/*!
+ Destroys the dial.
+*/
+QDial::~QDial()
+{
+ delete d;
+}
+
+
+void QDial::setTracking( bool enable )
+{
+ d->tracking = enable;
+}
+
+
+/*!
+ \property QDial::tracking
+ \brief whether tracking is enabled
+
+ If TRUE (the default), tracking is enabled. This means that the
+ arrow can be moved using the mouse; otherwise the arrow cannot be
+ moved with the mouse.
+*/
+
+bool QDial::tracking() const
+{
+ return d ? d->tracking : TRUE;
+}
+
+void QDial::setValue( int newValue )
+{ // ### set doNotEmit? Matthias?
+ QRangeControl::setValue( newValue );
+}
+
+
+/*!
+ Increments the dial's value() by one lineStep().
+*/
+
+void QDial::addLine()
+{
+ QRangeControl::addLine();
+}
+
+
+/*!
+ Decrements the dial's value() by one lineStep().
+*/
+
+void QDial::subtractLine()
+{
+ QRangeControl::subtractLine();
+}
+
+
+/*! \reimp */
+
+void QDial::resizeEvent( QResizeEvent * e )
+{
+ d->lines.resize( 0 );
+ QWidget::resizeEvent( e );
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::paintEvent( QPaintEvent * e )
+{
+ repaintScreen( &e->rect() );
+}
+
+/*!
+ Paints the dial using clip region \a cr.
+*/
+
+void QDial::repaintScreen( const QRect *cr )
+{
+ QPainter p;
+ p.begin( this );
+
+ bool resetClipping = FALSE;
+
+ // calculate clip-region for erasing background
+ if ( cr ) {
+ p.setClipRect( *cr );
+ } else if ( !d->onlyOutside && d->eraseAreaValid ) {
+ QRegion reg = d->eraseArea;
+ double a;
+ reg = reg.subtract( calcArrow( a ) );
+ p.setClipRegion( reg );
+ resetClipping = TRUE;
+ }
+
+ QRect br( calcDial() );
+ p.setPen( NoPen );
+ // if ( style() == MotifStyle )
+ // p.setBrush( colorGroup().brush( QColorGroup::Mid ) );
+ // else {
+ QBrush b;
+ if ( colorGroup().brush( QColorGroup::Light ).pixmap() )
+ b = QBrush( colorGroup().brush( QColorGroup::Light ) );
+ else
+ b = QBrush( colorGroup().light(), Dense4Pattern );
+ p.setBrush( b );
+ p.setBackgroundMode( OpaqueMode );
+ // }
+
+ QRect te = br;
+ te.setWidth(te.width()+2);
+ te.setHeight(te.height()+2);
+ // erase background of dial
+ if ( !d->onlyOutside ) {
+ p.drawEllipse( te );
+ }
+
+ // erase remaining space around the dial
+ QRegion remaining( 0, 0, width(), height() );
+ remaining = remaining.subtract( QRegion( te, QRegion::Ellipse ) );
+ if ( p.hasClipping() )
+ remaining = remaining.intersect( p.clipRegion() );
+ erase(remaining);
+
+ if ( resetClipping ) {
+ if ( cr )
+ p.setClipRect( *cr );
+ else
+ p.setClipRect( QRect( 0, 0, width(), height() ) );
+ }
+
+ // draw notches
+ if ( d->showNotches ) {
+ calcLines();
+ p.setPen( colorGroup().foreground() );
+ p.drawLineSegments( d->lines );
+ }
+
+ // calculate and paint arrow
+ p.setPen( QPen( colorGroup().dark() ) );
+ p.drawArc( te, 60 * 16, 180 * 16 );
+ p.setPen( QPen( colorGroup().light() ) );
+ p.drawArc( te, 240 * 16, 180 * 16 );
+
+ double a;
+ QPointArray arrow( calcArrow( a ) );
+ QRect ea( arrow.boundingRect() );
+ d->eraseArea = ea;
+ d->eraseAreaValid = TRUE;
+
+ p.setPen( NoPen );
+ p.setBrush( colorGroup().brush( QColorGroup::Button ) );
+ if ( !d->onlyOutside )
+ p.drawPolygon( arrow );
+
+ a = angle( QPoint( width() / 2, height() / 2 ), arrow[ 0 ] );
+ p.setBrush( Qt::NoBrush );
+
+ // that's still a hack...
+ if ( a <= 0 || a > 200 ) {
+ p.setPen( colorGroup().light() );
+ p.drawLine( arrow[ 2 ], arrow[ 0 ] );
+ p.drawLine( arrow[ 1 ], arrow[ 2 ] );
+ p.setPen( colorGroup().dark() );
+ p.drawLine( arrow[ 0 ], arrow[ 1 ] );
+ } else if ( a > 0 && a < 45 ) {
+ p.setPen( colorGroup().light() );
+ p.drawLine( arrow[ 2 ], arrow[ 0 ] );
+ p.setPen( colorGroup().dark() );
+ p.drawLine( arrow[ 1 ], arrow[ 2 ] );
+ p.drawLine( arrow[ 0 ], arrow[ 1 ] );
+ } else if ( a >= 45 && a < 135 ) {
+ p.setPen( colorGroup().dark() );
+ p.drawLine( arrow[ 2 ], arrow[ 0 ] );
+ p.drawLine( arrow[ 1 ], arrow[ 2 ] );
+ p.setPen( colorGroup().light() );
+ p.drawLine( arrow[ 0 ], arrow[ 1 ] );
+ } else if ( a >= 135 && a < 200 ) {
+ p.setPen( colorGroup().dark() );
+ p.drawLine( arrow[ 2 ], arrow[ 0 ] );
+ p.setPen( colorGroup().light() );
+ p.drawLine( arrow[ 0 ], arrow[ 1 ] );
+ p.drawLine( arrow[ 1 ], arrow[ 2 ] );
+ }
+
+ // draw focus rect around the dial
+ if ( hasFocus() ) {
+ p.setClipping( FALSE );
+ br.setWidth( br.width() + 2 );
+ br.setHeight( br.height() + 2 );
+ if ( d->showNotches ) {
+ int r = QMIN( width(), height() ) / 2;
+ br.moveBy( -r / 6, - r / 6 );
+ br.setWidth( br.width() + r / 3 );
+ br.setHeight( br.height() + r / 3 );
+ }
+ // strange, but else we get redraw errors on Windows
+ p.end();
+ p.begin( this );
+ p.save();
+ p.setPen( QPen( colorGroup().background() ) );
+ p.setBrush( NoBrush );
+ p.drawRect( br );
+ p.restore();
+ style().drawPrimitive( QStyle::PE_FocusRect, &p, br, colorGroup());
+ }
+ p.end();
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::keyPressEvent( QKeyEvent * e )
+{
+ switch ( e->key() ) {
+ case Key_Left: case Key_Down:
+ subtractLine();
+ break;
+ case Key_Right: case Key_Up:
+ addLine();
+ break;
+ case Key_Prior:
+ subtractPage();
+ break;
+ case Key_Next:
+ addPage();
+ break;
+ case Key_Home:
+ setValue( minValue() );
+ break;
+ case Key_End:
+ setValue( maxValue() );
+ break;
+ default:
+ e->ignore();
+ break;
+ }
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::mousePressEvent( QMouseEvent * e )
+{
+ d->mousePressed = TRUE;
+ setValue( valueFromPoint( e->pos() ) );
+ emit dialPressed();
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::mouseReleaseEvent( QMouseEvent * e )
+{
+ d->mousePressed = FALSE;
+ setValue( valueFromPoint( e->pos() ) );
+ emit dialReleased();
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::mouseMoveEvent( QMouseEvent * e )
+{
+ if ( !d->mousePressed )
+ return;
+ if ( !d->tracking || (e->state() & LeftButton) == 0 )
+ return;
+ d->doNotEmit = TRUE;
+ setValue( valueFromPoint( e->pos() ) );
+ emit dialMoved( value() );
+ d->doNotEmit = FALSE;
+}
+
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QDial::wheelEvent( QWheelEvent *e )
+{
+ setValue( value() - e->delta() / 120 );
+}
+#endif
+
+/*!
+ \reimp
+*/
+
+void QDial::focusInEvent( QFocusEvent * )
+{
+ d->onlyOutside = TRUE;
+ repaintScreen();
+ d->onlyOutside = FALSE;
+}
+
+
+/*!
+ \reimp
+*/
+
+void QDial::focusOutEvent( QFocusEvent * )
+{
+ d->onlyOutside = TRUE;
+ repaintScreen();
+ d->onlyOutside = FALSE;
+}
+
+/*!
+ Reimplemented to ensure the display is correct and to emit the
+ valueChanged(int) signal when appropriate.
+*/
+
+void QDial::valueChange()
+{
+ d->lines.resize( 0 );
+ repaintScreen();
+ if ( d->tracking || !d->doNotEmit ) {
+ emit valueChanged( value() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+ }
+}
+
+
+/*!
+ Reimplemented to ensure tick-marks are consistent with the new range.
+*/
+
+void QDial::rangeChange()
+{
+ d->lines.resize( 0 );
+ repaintScreen();
+}
+
+
+/*!
+ \internal
+*/
+
+int QDial::valueFromPoint( const QPoint & p ) const
+{
+ double yy = (double)height()/2.0 - p.y();
+ double xx = (double)p.x() - width()/2.0;
+ double a = (xx || yy) ? atan2(yy, xx) : 0;
+
+ if ( a < m_pi/-2 )
+ a = a + m_pi*2;
+
+ int dist = 0;
+ int minv = minValue(), maxv = maxValue();
+
+ if ( minValue() < 0 ) {
+ dist = -minValue();
+ minv = 0;
+ maxv = maxValue() + dist;
+ }
+
+ int r = maxv - minv;
+ int v;
+ if ( d->wrapping )
+ v = (int)(0.5 + minv + r*(m_pi*3/2-a)/(2*m_pi));
+ else
+ v = (int)(0.5 + minv + r*(m_pi*4/3-a)/(m_pi*10/6));
+
+ if ( dist > 0 )
+ v -= dist;
+
+ return bound( v );
+}
+
+
+/*!
+ \internal
+*/
+
+double QDial::angle( const QPoint &p1, const QPoint &p2 ) const
+{
+ double _angle = 0.0;
+
+ if ( p1.x() == p2.x() ) {
+ if ( p1.y() < p2.y() )
+ _angle = 270.0;
+ else
+ _angle = 90.0;
+ } else {
+ double x1, x2, y1, y2;
+
+ if ( p1.x() <= p2.x() ) {
+ x1 = p1.x(); y1 = p1.y();
+ x2 = p2.x(); y2 = p2.y();
+ } else {
+ x2 = p1.x(); y2 = p1.y();
+ x1 = p2.x(); y1 = p2.y();
+ }
+
+ double m = -( y2 - y1 ) / ( x2 - x1 );
+ _angle = atan( m ) * rad_factor;
+
+ if ( p1.x() < p2.x() )
+ _angle = 180.0 - _angle;
+ else
+ _angle = -_angle;
+ }
+
+ return _angle;
+}
+
+void QDial::setWrapping( bool enable )
+{
+ if ( d->wrapping == enable )
+ return;
+ d->lines.resize( 0 );
+ d->wrapping = enable;
+ d->eraseAreaValid = FALSE;
+ repaintScreen();
+}
+
+
+/*!
+ \property QDial::wrapping
+ \brief whether wrapping is enabled
+
+ If TRUE, wrapping is enabled. This means that the arrow can be
+ turned around 360°. Otherwise there is some space at the bottom of
+ the dial which is skipped by the arrow.
+
+ This property's default is FALSE.
+*/
+
+bool QDial::wrapping() const
+{
+ 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 lineStep() that results in an
+ on-screen notch size near notchTarget().
+
+ \sa notchTarget() lineStep()
+*/
+
+int QDial::notchSize() const
+{
+ // radius of the arc
+ int r = QMIN( width(), height() )/2;
+ // length of the whole arc
+ int l = (int)(r*(d->wrapping ? 6 : 5)*m_pi/6);
+ // length of the arc from minValue() to minValue()+pageStep()
+ if ( maxValue() > minValue()+pageStep() )
+ l = (int)(0.5 + l * pageStep() / (maxValue()-minValue()));
+ // length of a lineStep() arc
+ l = l * lineStep() / pageStep();
+ if ( l < 1 )
+ l = 1;
+ // how many times lineStep 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 lineStep() * l;
+}
+
+void QDial::setNotchTarget( double target )
+{
+ d->lines.resize( 0 );
+ d->target = target;
+ d->eraseAreaValid = FALSE;
+ d->onlyOutside = TRUE;
+ repaintScreen();
+ d->onlyOutside = FALSE;
+}
+
+
+/*!
+ \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.
+*/
+
+double QDial::notchTarget() const
+{
+ return d->target;
+}
+
+
+/*!
+ Increments the dial's value() by one pageStep() of steps.
+*/
+
+void QDial::addPage()
+{
+ QRangeControl::addPage();
+}
+
+
+/*!
+ Decrements the dial's value() by one pageStep() of steps.
+*/
+
+void QDial::subtractPage()
+{
+ QRangeControl::subtractPage();
+}
+
+
+/*!
+ \fn void QDial::valueChanged( int value )
+
+ This signal is emitted whenever the dial's \a value changes. The
+ frequency of this signal is influenced by setTracking().
+*/
+
+/*!
+ \fn void QDial::dialPressed()
+
+ This signal is emitted when the user begins mouse interaction with
+ the dial.
+
+ \sa dialReleased()
+*/
+
+/*!
+ \fn void QDial::dialMoved( int value )
+
+ This signal is emitted whenever the dial \a value changes. The
+ frequency of this signal is \e not influenced by setTracking().
+
+ \sa valueChanged()
+*/
+
+/*!
+ \fn void QDial::dialReleased()
+
+ This signal is emitted when the user ends mouse interaction with
+ the dial.
+
+ \sa dialPressed()
+*/
+
+void QDial::setNotchesVisible( bool b )
+{
+ d->showNotches = b;
+ d->eraseAreaValid = FALSE;
+ d->onlyOutside = TRUE;
+ repaintScreen();
+ d->onlyOutside = FALSE;
+}
+
+/*!
+ \property QDial::notchesVisible
+ \brief whether the notches are shown
+
+ If TRUE, the notches are shown. If FALSE (the default) notches are
+ not shown.
+*/
+bool QDial::notchesVisible() const
+{
+ return d->showNotches;
+}
+
+/*!
+ \reimp
+*/
+
+QSize QDial::minimumSizeHint() const
+{
+ return QSize( 50, 50 );
+}
+
+/*!
+ \reimp
+*/
+
+QSize QDial::sizeHint() const
+{
+ return QSize( 100, 100 ).expandedTo( QApplication::globalStrut() );
+}
+
+
+
+/*!
+ \internal
+*/
+
+QPointArray QDial::calcArrow( double &a ) const
+{
+ int r = QMIN( width(), height() ) / 2;
+ if ( maxValue() == minValue() )
+ a = m_pi / 2;
+ else if ( d->wrapping )
+ a = m_pi * 3 / 2 - ( value() - minValue() ) * 2 * m_pi / ( maxValue() - minValue() );
+ else
+ a = ( m_pi * 8 - ( value() - minValue() ) * 10 * m_pi / ( maxValue() - minValue() ) ) / 6;
+
+ int xc = width() / 2;
+ int yc = height() / 2;
+
+ int len = r - calcBigLineSize() - 5;
+ if ( len < 5 )
+ len = 5;
+ int back = len / 4;
+ if ( back < 1 )
+ back = 1;
+
+ QPointArray arrow( 3 );
+ arrow[0] = QPoint( (int)( 0.5 + xc + len * cos(a) ),
+ (int)( 0.5 + yc -len * sin( a ) ) );
+ arrow[1] = QPoint( (int)( 0.5 + xc + back * cos( a + m_pi * 5 / 6 ) ),
+ (int)( 0.5 + yc - back * sin( a + m_pi * 5 / 6 ) ) );
+ arrow[2] = QPoint( (int)( 0.5 + xc + back * cos( a - m_pi * 5 / 6 ) ),
+ (int)( 0.5 + yc - back * sin( a - m_pi * 5 / 6 ) ) );
+ return arrow;
+}
+
+/*!
+ \internal
+*/
+
+QRect QDial::calcDial() const
+{
+ double r = QMIN( width(), height() ) / 2.0;
+ double d_ = r / 6.0;
+ double dx = d_ + ( width() - 2 * r ) / 2.0 + 1;
+ double dy = d_ + ( height() - 2 * r ) / 2.0 + 1;
+ return QRect( int(dx), int(dy),
+ int(r * 2 - 2 * d_ - 2), int(r * 2 - 2 * d_ - 2) );
+}
+
+/*!
+ \internal
+*/
+
+int QDial::calcBigLineSize() const
+{
+ int r = QMIN( width(), height() ) / 2;
+ int bigLineSize = r / 6;
+ if ( bigLineSize < 4 )
+ bigLineSize = 4;
+ if ( bigLineSize > r / 2 )
+ bigLineSize = r / 2;
+ return bigLineSize;
+}
+
+/*!
+ \internal
+*/
+
+void QDial::calcLines()
+{
+ if ( !d->lines.size() ) {
+ double r = QMIN( width(), height() ) / 2.0;
+ int bigLineSize = calcBigLineSize();
+ double xc = width() / 2.0;
+ double yc = height() / 2.0;
+ int ns = notchSize();
+ int notches = ( maxValue() + ns - 1 - minValue() ) / ns;
+ d->lines.resize( 2 + 2 * notches );
+ int smallLineSize = bigLineSize / 2;
+ int i;
+ for( i = 0; i <= notches; i++ ) {
+ double angle = d->wrapping
+ ? m_pi * 3 / 2 - i * 2 * m_pi / notches
+ : (m_pi * 8 - i * 10 * m_pi / notches) / 6;
+
+ double s = sin( angle ); // sin/cos aren't defined as const...
+ double c = cos( angle );
+ if ( i == 0 || ( ((ns * i ) % pageStep() ) == 0 ) ) {
+ d->lines[2*i] = QPoint( (int)( xc + ( r - bigLineSize ) * c ),
+ (int)( yc - ( r - bigLineSize ) * s ) );
+ d->lines[2*i+1] = QPoint( (int)( xc + r * c ),
+ (int)( yc - r * s ) );
+ } else {
+ d->lines[2*i] = QPoint( (int)( xc + ( r - 1 - smallLineSize ) * c ),
+ (int)( yc - ( r - 1 - smallLineSize ) * s ) );
+ d->lines[2*i+1] = QPoint( (int)( xc + ( r - 1 ) * c ),
+ (int)( yc -( r - 1 ) * s ) );
+ }
+ }
+ }
+}
+
+/*!
+ \property QDial::minValue
+ \brief the current minimum value
+
+ When setting this property, the \l QDial::maxValue is adjusted if
+ necessary to ensure that the range remains valid.
+
+ \sa setRange()
+*/
+int QDial::minValue() const
+{
+ return QRangeControl::minValue();
+}
+
+/*!
+ \property QDial::maxValue
+ \brief the current maximum value
+
+ When setting this property, the \l QDial::minValue is adjusted if
+ necessary to ensure that the range remains valid.
+
+ \sa setRange()
+*/
+int QDial::maxValue() const
+{
+ return QRangeControl::maxValue();
+}
+
+void QDial::setMinValue( int minVal )
+{
+ QRangeControl::setMinValue( minVal );
+}
+
+void QDial::setMaxValue( int maxVal )
+{
+ QRangeControl::setMaxValue( maxVal );
+}
+
+/*!
+ \property QDial::lineStep
+ \brief the current line step
+
+ setLineStep() calls the virtual stepChange() function if the new
+ line step is different from the previous setting.
+
+ \sa QRangeControl::setSteps() pageStep setRange()
+*/
+
+int QDial::lineStep() const
+{
+ return QRangeControl::lineStep();
+}
+
+/*!
+ \property QDial::pageStep
+ \brief the current page step
+
+ setPageStep() calls the virtual stepChange() function if the new
+ page step is different from the previous setting.
+
+ \sa stepChange()
+*/
+int QDial::pageStep() const
+{
+ return QRangeControl::pageStep();
+}
+
+void QDial::setLineStep( int i )
+{
+ setSteps( i, pageStep() );
+}
+
+void QDial::setPageStep( int i )
+{
+ setSteps( lineStep(), i );
+}
+
+/*!
+ \property QDial::value
+ \brief the current dial value
+
+ This is guaranteed to be within the range
+ \l{QDial::minValue}..\l{QDial::maxValue}.
+
+ \sa minValue maxValue
+*/
+
+int QDial::value() const
+{
+ return QRangeControl::value();
+}
+
+#endif // QT_FEATURE_DIAL
diff --git a/src/widgets/qdial.h b/src/widgets/qdial.h
new file mode 100644
index 0000000..3249b2c
--- /dev/null
+++ b/src/widgets/qdial.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Definition of the dial widget
+**
+** Created : 990104
+**
+** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+
+#ifndef QDIAL_H
+#define QDIAL_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qrangecontrol.h"
+#endif // QT_H
+
+#ifndef QT_NO_DIAL
+
+class QDialPrivate;
+
+class Q_EXPORT QDial: public QWidget, public QRangeControl
+{
+ Q_OBJECT
+ Q_PROPERTY( bool tracking READ tracking WRITE setTracking )
+ Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
+ Q_PROPERTY( int notchSize READ notchSize )
+ Q_PROPERTY( double notchTarget READ notchTarget WRITE setNotchTarget )
+ Q_PROPERTY( bool notchesVisible READ notchesVisible WRITE setNotchesVisible )
+ Q_PROPERTY( int minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( int lineStep READ lineStep WRITE setLineStep )
+ Q_PROPERTY( int pageStep READ pageStep WRITE setPageStep )
+ Q_PROPERTY( int value READ value WRITE setValue )
+
+public:
+ QDial( QWidget* parent=0, const char* name=0, WFlags f = 0 );
+ QDial( int minValue, int maxValue, int pageStep, int value,
+ QWidget* parent=0, const char* name=0 );
+ ~QDial();
+
+ bool tracking() const;
+
+ bool wrapping() const;
+
+ int notchSize() const;
+
+ virtual void setNotchTarget( double );
+ double notchTarget() const;
+
+ bool notchesVisible() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ int minValue() const;
+ int maxValue() const;
+ void setMinValue( int );
+ void setMaxValue( int );
+ int lineStep() const;
+ int pageStep() const;
+ void setLineStep( int );
+ void setPageStep( int );
+ int value() const;
+
+public slots:
+ virtual void setValue( int );
+ void addLine();
+ void subtractLine();
+ void addPage();
+ void subtractPage();
+ virtual void setNotchesVisible( bool b );
+ virtual void setWrapping( bool on );
+ virtual void setTracking( bool enable );
+
+signals:
+ void valueChanged( int value );
+ void dialPressed();
+ void dialMoved( int value );
+ void dialReleased();
+
+protected:
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+
+ void keyPressEvent( QKeyEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent * );
+#endif
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+
+ void valueChange();
+ void rangeChange();
+
+ virtual void repaintScreen( const QRect *cr = 0 );
+
+private:
+ QDialPrivate * d;
+
+ int valueFromPoint( const QPoint & ) const;
+ double angle( const QPoint &, const QPoint & ) const;
+ QPointArray calcArrow( double &a ) const;
+ QRect calcDial() const;
+ int calcBigLineSize() const;
+ void calcLines();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QDial( const QDial & );
+ QDial &operator=( const QDial & );
+#endif
+
+};
+
+#endif // QT_NO_DIAL
+
+#endif
diff --git a/src/widgets/qdialogbuttons.cpp b/src/widgets/qdialogbuttons.cpp
new file mode 100644
index 0000000..787a406
--- /dev/null
+++ b/src/widgets/qdialogbuttons.cpp
@@ -0,0 +1,456 @@
+/****************************************************************************
+**
+** Implementation of QDialogButtons class
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qdialogbuttons_p.h"
+#ifndef QT_NO_DIALOGBUTTONS
+
+#include <qapplication.h>
+#include <qpushbutton.h>
+#include <qguardedptr.h>
+#include <qmap.h>
+#include <qvariant.h>
+#ifndef QT_NO_DIALOG
+#include <qdialog.h>
+#endif // QT_NO_DIALOG
+#include <qlayout.h>
+#include <qstyle.h>
+#include <qmap.h>
+
+struct QDialogButtonsPrivate
+{
+ QMap<int, QString> text;
+ QMap<QDialogButtons::Button, QWidget *> buttons;
+ QGuardedPtr<QWidget> custom;
+ Q_UINT32 enabled, visible;
+ QDialogButtons::Button def;
+ Qt::Orientation orient;
+ bool questionMode;
+};
+
+#ifndef QT_NO_DIALOG
+QDialogButtons::QDialogButtons(QDialog *parent, bool autoConnect, Q_UINT32 buttons,
+ Orientation orient, const char *name ) : QWidget(parent, name)
+{
+ init(buttons, orient);
+ if(parent && autoConnect) {
+ QObject::connect(this, SIGNAL(acceptClicked()), parent, SLOT(accept()));
+ QObject::connect(this, SIGNAL(rejectClicked()), parent, SLOT(reject()));
+ }
+}
+#endif // QT_NO_DIALOG
+
+QDialogButtons::QDialogButtons(QWidget *parent, Q_UINT32 buttons,
+ Orientation orient, const char *name ) : QWidget(parent, name)
+{
+ init(buttons, orient);
+}
+
+void
+QDialogButtons::init(Q_UINT32 buttons, Orientation orient)
+{
+ if(buttons == All) {
+ qWarning("QDialogButtons: cannot specify All by itself!");
+ buttons = None;
+ }
+ d = new QDialogButtonsPrivate;
+ d->questionMode = FALSE;
+ d->orient = orient;
+ d->def = (Button)style().styleHint(QStyle::SH_DialogButtons_DefaultButton, this);
+ d->enabled = d->visible = buttons;
+}
+
+QDialogButtons::~QDialogButtons()
+{
+ delete (QWidget *)d->custom;
+ delete d;
+}
+
+void
+QDialogButtons::setQuestionMode(bool b)
+{
+ d->questionMode = b;
+}
+
+bool
+QDialogButtons::questionMode() const
+{
+ return d->questionMode;
+}
+
+void
+QDialogButtons::setButtonEnabled(Button button, bool enabled)
+{
+ if(enabled)
+ d->enabled |= button;
+ else
+ d->enabled ^= button;
+ if(d->buttons.contains(button))
+ d->buttons[button]->setEnabled(enabled);
+}
+
+bool
+QDialogButtons::isButtonEnabled(Button button) const
+{
+ return ((int)(d->enabled & button)) == button;
+}
+
+void
+QDialogButtons::setButtonVisible(Button button, bool visible)
+{
+ if(visible) {
+ if(d->buttons.contains(button))
+ d->buttons[button]->show();
+ d->visible |= button;
+ } else {
+ if(d->buttons.contains(button))
+ d->buttons[button]->hide();
+ d->visible ^= button;
+ }
+ layoutButtons();
+}
+
+bool
+QDialogButtons::isButtonVisible(Button button) const
+{
+ return ((int)(d->visible & button)) == button;
+}
+
+void
+QDialogButtons::addWidget(QWidget *w)
+{
+ QBoxLayout *lay = NULL;
+ if(!d->custom) {
+ d->custom = new QWidget(this, "dialog_custom_area");
+ if(orientation() == Horizontal)
+ lay = new QHBoxLayout(d->custom);
+ else
+ lay = new QVBoxLayout(d->custom);
+ layoutButtons();
+ } else {
+ lay = (QBoxLayout*)d->custom->layout();
+ }
+ if(w->parent() != d->custom)
+ w->reparent(d->custom, 0, QPoint(0, 0), TRUE);
+ lay->addWidget(w);
+}
+
+void
+QDialogButtons::setDefaultButton(Button button)
+{
+ if(!((int)(d->visible & button) == button)) {
+ qWarning("QDialogButtons: Button '%d' is not visible (so cannot be default)", button);
+ return;
+ }
+ if(d->def != button) {
+#ifndef QT_NO_PROPERTIES
+ if(d->buttons.contains(d->def))
+ d->buttons[d->def]->setProperty("default", QVariant(FALSE,0));
+#endif
+ d->def = button;
+#ifndef QT_NO_PROPERTIES
+ if(d->buttons.contains(d->def))
+ d->buttons[d->def]->setProperty("default", QVariant(FALSE,0));
+#endif
+ }
+}
+
+QDialogButtons::Button
+QDialogButtons::defaultButton() const
+{
+ return d->def;
+}
+
+void
+QDialogButtons::setButtonText(Button button, const QString &str)
+{
+ d->text[button] = str;
+#ifndef QT_NO_PROPERTIES
+ if(d->buttons.contains(button))
+ d->buttons[button]->setProperty("text", QVariant(str));
+#endif
+ layoutButtons();
+}
+
+QString
+QDialogButtons::buttonText(Button b) const
+{
+ if(d->text.contains(b))
+ return d->text[b];
+ return QString(); //null if it is default..
+}
+
+void
+QDialogButtons::setOrientation(Orientation orient)
+{
+ if(d->orient != orient) {
+ d->orient = orient;
+ if(d->custom && d->custom->layout())
+ ((QBoxLayout*)d->custom->layout())->setDirection(orient == Horizontal ? QBoxLayout::LeftToRight :
+ QBoxLayout::TopToBottom);
+ layoutButtons();
+ }
+}
+
+Qt::Orientation
+QDialogButtons::orientation() const
+{
+ return d->orient;
+}
+
+QWidget *
+QDialogButtons::createButton(Button b)
+{
+ QPushButton *ret = new QPushButton(this, "qdialog_button");
+ QObject::connect(ret, SIGNAL(clicked()), this, SLOT(handleClicked()));
+ if(d->text.contains(b)) {
+ ret->setText(d->text[b]);
+ } else {
+ switch(b) {
+ case All: {
+ QString txt = buttonText(defaultButton());
+ if(txt.isNull()) {
+ if(defaultButton() == Accept) {
+ if(questionMode())
+ txt = tr("Yes to All");
+ else
+ txt = tr("OK to All");
+ } else {
+ if(questionMode())
+ txt = tr("No to All");
+ else
+ txt = tr("Cancel All");
+ }
+ } else {
+ txt += tr(" to All"); //ick, I can't really do this!!
+ }
+ ret->setText(txt);
+ break; }
+ case Accept:
+ if(questionMode())
+ ret->setText(tr("Yes"));
+ else
+ ret->setText(tr("OK"));
+ break;
+ case Reject:
+ if(questionMode())
+ ret->setText(tr("No"));
+ else
+ ret->setText(tr("Cancel"));
+ break;
+ case Apply:
+ ret->setText(tr("Apply"));
+ break;
+ case Ignore:
+ ret->setText(tr("Ignore"));
+ break;
+ case Retry:
+ ret->setText(tr("Retry"));
+ break;
+ case Abort:
+ ret->setText(tr("Abort"));
+ break;
+ case Help:
+ ret->setText(tr("Help"));
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+
+void
+QDialogButtons::handleClicked()
+{
+ const QObject *s = sender();
+ if(!s)
+ return;
+
+ for(QMapIterator<QDialogButtons::Button, QWidget *> it = d->buttons.begin(); it != d->buttons.end(); ++it) {
+ if(it.data() == s) {
+ emit clicked((QDialogButtons::Button)it.key());
+ switch(it.key()) {
+ case Retry:
+ emit retryClicked();
+ break;
+ case Ignore:
+ emit ignoreClicked();
+ break;
+ case Abort:
+ emit abortClicked();
+ break;
+ case All:
+ emit allClicked();
+ break;
+ case Accept:
+ emit acceptClicked();
+ break;
+ case Reject:
+ emit rejectClicked();
+ break;
+ case Apply:
+ emit applyClicked();
+ break;
+ case Help:
+ emit helpClicked();
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ }
+}
+
+void
+QDialogButtons::resizeEvent(QResizeEvent *)
+{
+ layoutButtons();
+}
+
+void
+QDialogButtons::showEvent(QShowEvent *)
+{
+ layoutButtons();
+}
+
+void
+QDialogButtons::styleChanged(QStyle &old)
+{
+ layoutButtons();
+ QWidget::styleChange(old);
+}
+
+void
+QDialogButtons::layoutButtons()
+{
+ if(!isVisible()) //nah..
+ return;
+
+ QStyle::SubRect rects[] = {
+ QStyle::SR_DialogButtonAccept, QStyle::SR_DialogButtonReject,
+ QStyle::SR_DialogButtonApply, QStyle::SR_DialogButtonHelp,
+ QStyle::SR_DialogButtonCustom, QStyle::SR_DialogButtonAll,
+ QStyle::SR_DialogButtonRetry, QStyle::SR_DialogButtonIgnore,
+ QStyle::SR_DialogButtonAbort };
+ for(unsigned int i = 0; i < (sizeof(rects) / sizeof(rects[0])); i++) {
+ QWidget *w = NULL;
+ if(rects[i] == QStyle::SR_DialogButtonCustom) {
+ w = d->custom;
+ } else {
+ Button b = None;
+ if(rects[i] == QStyle::SR_DialogButtonApply)
+ b = Apply;
+ else if(rects[i] == QStyle::SR_DialogButtonAll)
+ b = All;
+ else if(rects[i] == QStyle::SR_DialogButtonAccept)
+ b = Accept;
+ else if(rects[i] == QStyle::SR_DialogButtonReject)
+ b = Reject;
+ else if(rects[i] == QStyle::SR_DialogButtonHelp)
+ b = Help;
+ else if(rects[i] == QStyle::SR_DialogButtonRetry)
+ b = Retry;
+ else if(rects[i] == QStyle::SR_DialogButtonAbort)
+ b = Abort;
+ else if(rects[i] == QStyle::SR_DialogButtonIgnore)
+ b = Ignore;
+ if(b != None) {
+ if(d->buttons.contains(b)) {
+ w = d->buttons[b];
+ if(!(d->visible & b)) {
+ w->hide();
+ continue;
+ }
+ } else if(d->visible & b) {
+ w = createButton(b);
+ d->buttons.insert(b, w);
+ } else {
+ continue;
+ }
+ if(w) {
+ if(b == d->def) {
+ w->setFocus();
+#ifndef QT_NO_PROPERTIES
+ w->setProperty("default", QVariant(TRUE,0));
+#endif
+ }
+ w->setEnabled(d->enabled & b);
+ }
+ }
+ }
+ if(w) {
+ w->show();
+ w->setGeometry(style().subRect(rects[i], this));
+ }
+ }
+}
+
+QSize
+QDialogButtons::sizeHint() const
+{
+ constPolish();
+ QSize s;
+ if(d->custom)
+ s = d->custom->sizeHint();
+ return (style().sizeFromContents(QStyle::CT_DialogButtons, this, s.
+ expandedTo(QApplication::globalStrut())));
+}
+
+QSize
+QDialogButtons::sizeHint(QDialogButtons::Button button) const
+{
+ QWidget *w = NULL;
+ if(d->visible & button) {
+ if(!d->buttons.contains(button)) {
+ QDialogButtons *that = (QDialogButtons*)this; //ick, constness..
+ w = that->createButton(button);
+ that->d->buttons.insert(button, w);
+ } else {
+ w = d->buttons[button];
+ }
+ }
+ return w->sizeHint();
+}
+
+QSize
+QDialogButtons::minimumSizeHint() const
+{
+ return sizeHint();
+}
+#endif
diff --git a/src/widgets/qdialogbuttons_p.h b/src/widgets/qdialogbuttons_p.h
new file mode 100644
index 0000000..73bbfee
--- /dev/null
+++ b/src/widgets/qdialogbuttons_p.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Definition of QDialogButtons class.
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QDIALOGBUTTONS_P_H
+#define QDIALOGBUTTONS_P_H
+
+#ifndef QT_H
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+#endif
+
+#ifndef QT_NO_DIALOGBUTTONS
+struct QDialogButtonsPrivate;
+
+class
+QDialogButtons : public QWidget
+{
+ Q_OBJECT
+public:
+ enum Button { None=0, Accept=0x01, Reject=0x02, Help=0x04, Apply=0x08, All=0x10, Abort=0x20, Retry=0x40, Ignore=0x80 };
+#ifndef QT_NO_DIALOG
+ QDialogButtons(QDialog *parent, bool autoConnect = TRUE, Q_UINT32 buttons = Accept | Reject,
+ Orientation orient = Horizontal, const char *name = NULL);
+#endif // QT_NO_DIALOG
+ QDialogButtons(QWidget *parent, Q_UINT32 buttons = Accept | Reject,
+ Orientation orient = Horizontal, const char *name = NULL);
+ ~QDialogButtons();
+
+ void setQuestionMode(bool);
+ bool questionMode() const;
+
+ void setButtonEnabled(Button button, bool enabled);
+ bool isButtonEnabled(Button) const;
+
+ inline void showButton(Button b) { setButtonVisible(b, TRUE) ; }
+ inline void hideButton(Button b) { setButtonVisible(b, FALSE); }
+ virtual void setButtonVisible(Button, bool visible);
+ bool isButtonVisible(Button) const;
+
+ void addWidget(QWidget *);
+
+ virtual void setDefaultButton(Button);
+ Button defaultButton() const;
+
+ virtual void setButtonText(Button, const QString &);
+ QString buttonText(Button) const;
+
+ void setOrientation(Orientation);
+ Orientation orientation() const;
+
+ virtual QSize sizeHint(Button) const;
+ QSize minimumSizeHint() const;
+ QSize sizeHint() const;
+
+protected:
+ void layoutButtons();
+ virtual QWidget *createButton(Button);
+
+ void showEvent(QShowEvent *);
+ void resizeEvent(QResizeEvent *);
+ void styleChanged(QStyle &);
+
+private slots:
+ void handleClicked();
+
+signals:
+ void clicked(Button);
+ void acceptClicked();
+ void rejectClicked();
+ void helpClicked();
+ void applyClicked();
+ void allClicked();
+ void retryClicked();
+ void ignoreClicked();
+ void abortClicked();
+
+private:
+ QDialogButtonsPrivate *d;
+ void init(Q_UINT32, Orientation);
+};
+#endif //QT_NO_DIALOGBUTTONS
+#endif //QDIALOGBUTTONS_P_H
diff --git a/src/widgets/qdockarea.cpp b/src/widgets/qdockarea.cpp
new file mode 100644
index 0000000..2d4d957
--- /dev/null
+++ b/src/widgets/qdockarea.cpp
@@ -0,0 +1,1320 @@
+/****************************************************************************
+**
+** Implementation of the QDockArea class
+**
+** Created : 001010
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the workspace module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qdockarea.h"
+
+#ifndef QT_NO_MAINWINDOW
+#include "qsplitter.h"
+#include "qlayout.h"
+#include "qptrvector.h"
+#include "qapplication.h"
+#include "qpainter.h"
+#include "qwidgetlist.h"
+#include "qmap.h"
+#include "qmainwindow.h"
+
+//#define QDOCKAREA_DEBUG
+
+struct Q_EXPORT DockData
+{
+ DockData() : w( 0 ), rect() {}
+ DockData( QDockWindow *dw, const QRect &r ) : w( dw ), rect( r ) {}
+ QDockWindow *w;
+ QRect rect;
+
+ Q_DUMMY_COMPARISON_OPERATOR( DockData )
+};
+
+static int fix_x( QDockWindow* w, int width = -1 ) {
+ if ( QApplication::reverseLayout() ) {
+ if ( width < 0 )
+ width = w->width();
+ return w->parentWidget()->width() - w->x() - width;
+ }
+ return w->x();
+}
+static int fix_x( QDockWindow* w, int x, int width = -1 ) {
+ if ( QApplication::reverseLayout() ) {
+ if ( width < 0 )
+ width = w->width();
+ return w->parentWidget()->width() - x - width;
+ }
+ return x;
+}
+
+static QPoint fix_pos( QDockWindow* w ) {
+ if ( QApplication::reverseLayout() ) {
+ QPoint p = w->pos();
+ p.rx() = w->parentWidget()->width() - p.x() - w->width();
+ return p;
+ }
+ return w->pos();
+}
+
+
+void QDockAreaLayout::setGeometry( const QRect &r )
+{
+ QLayout::setGeometry( r );
+ layoutItems( r );
+}
+
+QLayoutIterator QDockAreaLayout::iterator()
+{
+ return 0;
+}
+
+QSize QDockAreaLayout::sizeHint() const
+{
+ if ( !dockWindows || !dockWindows->first() )
+ return QSize( 0, 0 );
+
+ if ( dirty ) {
+ QDockAreaLayout *that = (QDockAreaLayout *) this;
+ that->layoutItems( geometry() );
+ }
+
+ int w = 0;
+ int h = 0;
+ QPtrListIterator<QDockWindow> it( *dockWindows );
+ QDockWindow *dw = 0;
+ it.toFirst();
+ int y = -1;
+ int x = -1;
+ int ph = 0;
+ int pw = 0;
+ while ( ( dw = it.current() ) != 0 ) {
+ int plush = 0, plusw = 0;
+ ++it;
+ if ( dw->isHidden() )
+ continue;
+ if ( hasHeightForWidth() ) {
+ if ( y != dw->y() )
+ plush = ph;
+ y = dw->y();
+ ph = dw->height();
+ } else {
+ if ( x != dw->x() )
+ plusw = pw;
+ x = dw->x();
+ pw = dw->width();
+ }
+ h = QMAX( h, dw->height() + plush );
+ w = QMAX( w, dw->width() + plusw );
+ }
+
+ if ( hasHeightForWidth() )
+ return QSize( 0, h );
+ return QSize( w, 0 );
+}
+
+bool QDockAreaLayout::hasHeightForWidth() const
+{
+ return orient == Horizontal;
+}
+
+void QDockAreaLayout::init()
+{
+ dirty = TRUE;
+ cached_width = 0;
+ cached_height = 0;
+ cached_hfw = -1;
+ cached_wfh = -1;
+}
+
+void QDockAreaLayout::invalidate()
+{
+ dirty = TRUE;
+ cached_width = 0;
+ cached_height = 0;
+}
+
+static int start_pos( const QRect &r, Qt::Orientation o )
+{
+ if ( o == Qt::Horizontal ) {
+ return QMAX( 0, r.x() );
+ } else {
+ return QMAX( 0, r.y() );
+ }
+}
+
+static void add_size( int s, int &pos, Qt::Orientation o )
+{
+ if ( o == Qt::Horizontal ) {
+ pos += s;
+ } else {
+ pos += s;
+ }
+}
+
+static int space_left( const QRect &r, int pos, Qt::Orientation o )
+{
+ if ( o == Qt::Horizontal ) {
+ return ( r.x() + r.width() ) - pos;
+ } else {
+ return ( r.y() + r.height() ) - pos;
+ }
+}
+
+static int dock_extent( QDockWindow *w, Qt::Orientation o, int maxsize )
+{
+ if ( o == Qt::Horizontal )
+ return QMIN( maxsize, QMAX( w->sizeHint().width(), w->fixedExtent().width() ) );
+ else
+ return QMIN( maxsize, QMAX( w->sizeHint().height(), w->fixedExtent().height() ) );
+}
+
+static int dock_strut( QDockWindow *w, Qt::Orientation o )
+{
+ if ( o != Qt::Horizontal ) {
+ int wid;
+ if ( ( wid = w->fixedExtent().width() ) != -1 )
+ return QMAX( wid, QMAX( w->minimumSize().width(), w->minimumSizeHint().width() ) );
+ return QMAX( w->sizeHint().width(), QMAX( w->minimumSize().width(), w->minimumSizeHint().width() ) );
+ } else {
+ int hei;
+ if ( ( hei = w->fixedExtent().height() ) != -1 )
+ return QMAX( hei, QMAX( w->minimumSizeHint().height(), w->minimumSize().height() ) );
+ return QMAX( w->sizeHint().height(), QMAX( w->minimumSizeHint().height(), w->minimumSize().height() ) );
+ }
+}
+
+static void set_geometry( QDockWindow *w, int pos, int sectionpos, int extent, int strut, Qt::Orientation o )
+{
+ if ( o == Qt::Horizontal )
+ w->setGeometry( fix_x( w, pos, extent), sectionpos, extent, strut );
+ else
+ w->setGeometry( sectionpos, pos, strut, extent );
+}
+
+static int size_extent( const QSize &s, Qt::Orientation o, bool swap = FALSE )
+{
+ return o == Qt::Horizontal ? ( swap ? s.height() : s.width() ) : ( swap ? s.width() : s.height() );
+}
+
+static int point_pos( const QPoint &p, Qt::Orientation o, bool swap = FALSE )
+{
+ return o == Qt::Horizontal ? ( swap ? p.y() : p.x() ) : ( swap ? p.x() : p.y() );
+}
+
+static void shrink_extend( QDockWindow *dw, int &dockExtend, int /*spaceLeft*/, Qt::Orientation o )
+{
+ QToolBar *tb = ::qt_cast<QToolBar*>(dw);
+ if ( o == Qt::Horizontal ) {
+ int mw = 0;
+ if ( !tb )
+ mw = dw->minimumWidth();
+ else
+ mw = dw->sizeHint().width();
+ dockExtend = mw;
+ } else {
+ int mh = 0;
+ if ( !tb )
+ mh = dw->minimumHeight();
+ else
+ mh = dw->sizeHint().height();
+ dockExtend = mh;
+ }
+}
+
+static void place_line( QValueList<DockData> &lastLine, Qt::Orientation o, int linestrut, int fullextent, int tbstrut, int maxsize, QDockAreaLayout * )
+{
+ QDockWindow *last = 0;
+ QRect lastRect;
+ for ( QValueList<DockData>::Iterator it = lastLine.begin(); it != lastLine.end(); ++it ) {
+ if ( tbstrut != -1 && ::qt_cast<QToolBar*>((*it).w) )
+ (*it).rect.setHeight( tbstrut );
+ if ( !last ) {
+ last = (*it).w;
+ lastRect = (*it).rect;
+ continue;
+ }
+ if ( !last->isStretchable() ) {
+ int w = QMIN( lastRect.width(), maxsize );
+ set_geometry( last, lastRect.x(), lastRect.y(), w, lastRect.height(), o );
+ } else {
+ int w = QMIN( (*it).rect.x() - lastRect.x(), maxsize );
+ set_geometry( last, lastRect.x(), lastRect.y(), w,
+ last->isResizeEnabled() ? linestrut : lastRect.height(), o );
+ }
+ last = (*it).w;
+ lastRect = (*it).rect;
+ }
+ if ( !last )
+ return;
+ if ( !last->isStretchable() ) {
+ int w = QMIN( lastRect.width(), maxsize );
+ set_geometry( last, lastRect.x(), lastRect.y(), w, lastRect.height(), o );
+ } else {
+ int w = QMIN( fullextent - lastRect.x() - ( o == Qt::Vertical ? 1 : 0 ), maxsize );
+ set_geometry( last, lastRect.x(), lastRect.y(), w,
+ last->isResizeEnabled() ? linestrut : lastRect.height(), o );
+ }
+}
+
+
+QSize QDockAreaLayout::minimumSize() const
+{
+ if ( !dockWindows || !dockWindows->first() )
+ return QSize( 0, 0 );
+
+ if ( dirty ) {
+ QDockAreaLayout *that = (QDockAreaLayout *) this;
+ that->layoutItems( geometry() );
+ }
+
+ int s = 0;
+
+ QPtrListIterator<QDockWindow> it( *dockWindows );
+ QDockWindow *dw = 0;
+ while ( ( dw = it.current() ) != 0 ) {
+ ++it;
+ if ( dw->isHidden() )
+ continue;
+ s = QMAX( s, dock_strut( dw, orientation() ) );
+ }
+
+ return orientation() == Horizontal ? QSize( 0, s ? s+2 : 0 ) : QSize( s, 0 );
+}
+
+
+
+int QDockAreaLayout::layoutItems( const QRect &rect, bool testonly )
+{
+ if ( !dockWindows || !dockWindows->first() )
+ return 0;
+
+ dirty = FALSE;
+
+ // some corrections
+ QRect r = rect;
+ if ( orientation() == Vertical )
+ r.setHeight( r.height() - 3 );
+
+ // init
+ lines.clear();
+ ls.clear();
+ QPtrListIterator<QDockWindow> it( *dockWindows );
+ QDockWindow *dw = 0;
+ int start = start_pos( r, orientation() );
+ int pos = start;
+ int sectionpos = 0;
+ int linestrut = 0;
+ QValueList<DockData> lastLine;
+ int tbstrut = -1;
+ int maxsize = size_extent( rect.size(), orientation() );
+ int visibleWindows = 0;
+
+ // go through all widgets in the dock
+ while ( ( dw = it.current() ) != 0 ) {
+ ++it;
+ if ( dw->isHidden() )
+ continue;
+ ++visibleWindows;
+ // find position for the widget: This is the maximum of the
+ // end of the previous widget and the offset of the widget. If
+ // the position + the width of the widget dosn't fit into the
+ // dock, try moving it a bit back, if possible.
+ int op = pos;
+ int dockExtend = dock_extent( dw, orientation(), maxsize );
+ if ( !dw->isStretchable() ) {
+ pos = QMAX( pos, dw->offset() );
+ if ( pos + dockExtend > size_extent( r.size(), orientation() ) - 1 )
+ pos = QMAX( op, size_extent( r.size(), orientation() ) - 1 - dockExtend );
+ }
+ if ( !lastLine.isEmpty() && !dw->newLine() && space_left( rect, pos, orientation() ) < dockExtend )
+ shrink_extend( dw, dockExtend, space_left( rect, pos, orientation() ), orientation() );
+ // if the current widget doesn't fit into the line anymore and it is not the first widget of the line
+ if ( !lastLine.isEmpty() &&
+ ( space_left( rect, pos, orientation() ) < dockExtend || dw->newLine() ) ) {
+ if ( !testonly ) // place the last line, if not in test mode
+ place_line( lastLine, orientation(), linestrut, size_extent( r.size(), orientation() ), tbstrut, maxsize, this );
+ // remember the line coordinats of the last line
+ if ( orientation() == Horizontal )
+ lines.append( QRect( 0, sectionpos, r.width(), linestrut ) );
+ else
+ lines.append( QRect( sectionpos, 0, linestrut, r.height() ) );
+ // do some clearing for the next line
+ lastLine.clear();
+ sectionpos += linestrut;
+ linestrut = 0;
+ pos = start;
+ tbstrut = -1;
+ }
+
+ // remeber first widget of a line
+ if ( lastLine.isEmpty() ) {
+ ls.append( dw );
+ // try to make the best position
+ int op = pos;
+ if ( !dw->isStretchable() )
+ pos = QMAX( pos, dw->offset() );
+ if ( pos + dockExtend > size_extent( r.size(), orientation() ) - 1 )
+ pos = QMAX( op, size_extent( r.size(), orientation() ) - 1 - dockExtend );
+ }
+ // do some calculations and add the remember the rect which the docking widget requires for the placing
+ QRect dwRect(pos, sectionpos, dockExtend, dock_strut( dw, orientation() ) );
+ lastLine.append( DockData( dw, dwRect ) );
+ if ( ::qt_cast<QToolBar*>(dw) )
+ tbstrut = QMAX( tbstrut, dock_strut( dw, orientation() ) );
+ linestrut = QMAX( dock_strut( dw, orientation() ), linestrut );
+ add_size( dockExtend, pos, orientation() );
+ }
+
+ // if some stuff was not placed/stored yet, do it now
+ if ( !testonly )
+ place_line( lastLine, orientation(), linestrut, size_extent( r.size(), orientation() ), tbstrut, maxsize, this );
+ if ( orientation() == Horizontal )
+ lines.append( QRect( 0, sectionpos, r.width(), linestrut ) );
+ else
+ lines.append( QRect( sectionpos, 0, linestrut, r.height() ) );
+ if ( *(--lines.end()) == *(--(--lines.end())) )
+ lines.remove( lines.at( lines.count() - 1 ) );
+
+ it.toFirst();
+ bool hadResizable = FALSE;
+ while ( ( dw = it.current() ) != 0 ) {
+ ++it;
+ if ( !dw->isVisibleTo( parentWidget ) )
+ continue;
+ hadResizable = hadResizable || dw->isResizeEnabled();
+ dw->updateSplitterVisibility( visibleWindows > 1 ); //!dw->area()->isLastDockWindow( dw ) );
+ }
+ return sectionpos + linestrut;
+}
+
+int QDockAreaLayout::heightForWidth( int w ) const
+{
+ if ( dockWindows->isEmpty() && parentWidget )
+ return parentWidget->minimumHeight();
+
+ if ( cached_width != w ) {
+ QDockAreaLayout * mthis = (QDockAreaLayout*)this;
+ mthis->cached_width = w;
+ int h = mthis->layoutItems( QRect( 0, 0, w, 0 ), TRUE );
+ mthis->cached_hfw = h;
+ return h;
+ }
+
+ return cached_hfw;
+}
+
+int QDockAreaLayout::widthForHeight( int h ) const
+{
+ if ( cached_height != h ) {
+ QDockAreaLayout * mthis = (QDockAreaLayout*)this;
+ mthis->cached_height = h;
+ int w = mthis->layoutItems( QRect( 0, 0, 0, h ), TRUE );
+ mthis->cached_wfh = w;
+ return w;
+ }
+ return cached_wfh;
+}
+
+
+
+
+/*!
+ \class QDockArea qdockarea.h
+ \brief The QDockArea class manages and lays out QDockWindows.
+
+ \ingroup application
+
+ A QDockArea is a container which manages a list of
+ \l{QDockWindow}s which it lays out within its area. In cooperation
+ with the \l{QDockWindow}s it is responsible for the docking and
+ undocking of \l{QDockWindow}s and moving them inside the dock
+ area. QDockAreas also handle the wrapping of \l{QDockWindow}s to
+ fill the available space as compactly as possible. QDockAreas can
+ contain QToolBars since QToolBar is a QDockWindow subclass.
+
+ QMainWindow contains four QDockAreas which you can use for your
+ QToolBars and QDockWindows, so in most situations you do not need
+ to use the QDockArea class directly. Although QMainWindow contains
+ support for its own dock areas it isn't convenient for adding new
+ QDockAreas. If you need to create your own dock areas we suggest
+ that you create a subclass of QWidget and add your QDockAreas to
+ your subclass.
+
+ \img qmainwindow-qdockareas.png QMainWindow's QDockAreas
+
+ \target lines
+ \e Lines. QDockArea uses the concept of lines. A line is a
+ horizontal region which may contain dock windows side-by-side. A
+ dock area may have room for more than one line. When dock windows
+ are docked into a dock area they are usually added at the right
+ hand side of the top-most line that has room (unless manually
+ placed by the user). When users move dock windows they may leave
+ empty lines or gaps in non-empty lines. Dock windows can be lined
+ up to minimize wasted space using the lineUp() function.
+
+ The QDockArea class maintains a position list of all its child
+ dock windows. Dock windows are added to a dock area from position
+ 0 onwards. Dock windows are laid out sequentially in position
+ order from left to right, and in the case of multiple lines of
+ dock windows, from top to bottom. If a dock window is floated it
+ still retains its position since this is where the window will
+ return if the user double clicks its caption. A dock window's
+ position can be determined with hasDockWindow(). The position can
+ be changed with moveDockWindow().
+
+ To dock or undock a dock window use QDockWindow::dock() and
+ QDockWindow::undock() respectively. If you want to control which
+ dock windows can dock in a dock area use setAcceptDockWindow(). To
+ see if a dock area contains a particular dock window use
+ \l{hasDockWindow()}; to see how many dock windows a dock area
+ contains use count().
+
+ The streaming operators can write the positions of the dock
+ windows in the dock area to a QTextStream. The positions can be
+ read back later to restore the saved positions.
+
+ Save the positions to a QTextStream:
+ \code
+ ts << *myDockArea;
+ \endcode
+
+ Restore the positions from a QTextStream:
+ \code
+ ts >> *myDockArea;
+ \endcode
+*/
+
+/*!
+ \property QDockArea::handlePosition
+ \brief where the dock window splitter handle is placed in the dock
+ area
+
+ The default position is \c Normal.
+*/
+
+/*!
+ \property QDockArea::orientation
+ \brief the dock area's orientation
+
+ There is no default value; the orientation is specified in the
+ constructor.
+*/
+
+/*!
+ \enum QDockArea::HandlePosition
+
+ A dock window has two kinds of handles, the dock window handle
+ used for dragging the dock window, and the splitter handle used to
+ resize the dock window in relation to other dock windows using a
+ splitter. (The splitter handle is only visible for docked
+ windows.)
+
+ This enum specifies where the dock window splitter handle is
+ placed in the dock area.
+
+ \value Normal The splitter handles of dock windows are placed at
+ the right or bottom.
+
+ \value Reverse The splitter handles of dock windows are placed at
+ the left or top.
+*/
+
+/*!
+ Constructs a QDockArea with orientation \a o, HandlePosition \a h,
+ parent \a parent and called \a name.
+*/
+
+QDockArea::QDockArea( Orientation o, HandlePosition h, QWidget *parent, const char *name )
+ : QWidget( parent, name ), orient( o ), layout( 0 ), hPos( h )
+{
+ dockWindows = new QPtrList<QDockWindow>;
+ layout = new QDockAreaLayout( this, o, dockWindows, 0, 0, "toollayout" );
+ installEventFilter( this );
+}
+
+/*!
+ Destroys the dock area and all the dock windows docked in the dock
+ area.
+
+ Does not affect any floating dock windows or dock windows in other
+ dock areas, even if they first appeared in this dock area.
+ Floating dock windows are effectively top level windows and are
+ not child windows of the dock area. When a floating dock window is
+ docked (dragged into a dock area) its parent becomes the dock
+ area.
+*/
+
+QDockArea::~QDockArea()
+{
+ dockWindows->setAutoDelete( TRUE );
+ delete dockWindows;
+ dockWindows = 0;
+}
+
+/*!
+ Moves the QDockWindow \a w within the dock area. If \a w is not
+ already docked in this area, \a w is docked first. If \a index is
+ -1 or larger than the number of docked widgets, \a w is appended
+ at the end, otherwise it is inserted at the position \a index.
+*/
+
+void QDockArea::moveDockWindow( QDockWindow *w, int index )
+{
+ invalidateFixedSizes();
+ QDockWindow *dockWindow = 0;
+ int dockWindowIndex = findDockWindow( w );
+ if ( dockWindowIndex == -1 ) {
+ dockWindow = w;
+ dockWindow->reparent( this, QPoint( 0, 0 ), TRUE );
+ w->installEventFilter( this );
+ updateLayout();
+ setSizePolicy( QSizePolicy( orientation() == Horizontal ? QSizePolicy::Expanding : QSizePolicy::Minimum,
+ orientation() == Vertical ? QSizePolicy::Expanding : QSizePolicy::Minimum ) );
+ dockWindows->append( w );
+ } else {
+ if ( w->parent() != this )
+ w->reparent( this, QPoint( 0, 0 ), TRUE );
+ if ( index == - 1 ) {
+ dockWindows->removeRef( w );
+ dockWindows->append( w );
+ }
+ }
+
+ w->dockArea = this;
+ w->curPlace = QDockWindow::InDock;
+ w->updateGui();
+
+ if ( index != -1 && index < (int)dockWindows->count() ) {
+ dockWindows->removeRef( w );
+ dockWindows->insert( index, w );
+ }
+}
+
+/*!
+ Returns TRUE if the dock area contains the dock window \a w;
+ otherwise returns FALSE. If \a index is not 0 it will be set as
+ follows: if the dock area contains the dock window \a *index is
+ set to \a w's index position; otherwise \a *index is set to -1.
+*/
+
+bool QDockArea::hasDockWindow( QDockWindow *w, int *index )
+{
+ int i = dockWindows->findRef( w );
+ if ( index )
+ *index = i;
+ return i != -1;
+}
+
+int QDockArea::lineOf( int index )
+{
+ QPtrList<QDockWindow> lineStarts = layout->lineStarts();
+ int i = 0;
+ for ( QDockWindow *w = lineStarts.first(); w; w = lineStarts.next(), ++i ) {
+ if ( dockWindows->find( w ) >= index )
+ return i;
+ }
+ return i;
+}
+
+/*!
+ \overload
+
+ Moves the dock window \a w inside the dock area where \a p is the
+ new position (in global screen coordinates), \a r is the suggested
+ rectangle of the dock window and \a swap specifies whether or not
+ the orientation of the docked widget needs to be changed.
+
+ This function is used internally by QDockWindow. You shouldn't
+ need to call it yourself.
+*/
+
+void QDockArea::moveDockWindow( QDockWindow *w, const QPoint &p, const QRect &r, bool swap )
+{
+ invalidateFixedSizes();
+ int mse = -10;
+ bool hasResizable = FALSE;
+ for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
+ if ( dw->isHidden() )
+ continue;
+ if ( dw->isResizeEnabled() )
+ hasResizable = TRUE;
+ if ( orientation() != Qt::Horizontal )
+ mse = QMAX( QMAX( dw->fixedExtent().width(), dw->width() ), mse );
+ else
+ mse = QMAX( QMAX( dw->fixedExtent().height(), dw->height() ), mse );
+ }
+ if ( !hasResizable && w->isResizeEnabled() ) {
+ if ( orientation() != Qt::Horizontal )
+ mse = QMAX( w->fixedExtent().width(), mse );
+ else
+ mse = QMAX( w->fixedExtent().height(), mse );
+ }
+
+ QDockWindow *dockWindow = 0;
+ int dockWindowIndex = findDockWindow( w );
+ QPtrList<QDockWindow> lineStarts = layout->lineStarts();
+ QValueList<QRect> lines = layout->lineList();
+ bool wasAloneInLine = FALSE;
+ QPoint pos = mapFromGlobal( p );
+ QRect lr = *lines.at( lineOf( dockWindowIndex ) );
+ if ( dockWindowIndex != -1 ) {
+ if ( lineStarts.find( w ) != -1 &&
+ ( dockWindowIndex < (int)dockWindows->count() - 1 && lineStarts.find( dockWindows->at( dockWindowIndex + 1 ) ) != -1 ||
+ dockWindowIndex == (int)dockWindows->count() - 1 ) )
+ wasAloneInLine = TRUE;
+ dockWindow = dockWindows->take( dockWindowIndex );
+ if ( !wasAloneInLine ) { // only do the pre-layout if the widget isn't the only one in its line
+ if ( lineStarts.findRef( dockWindow ) != -1 && dockWindowIndex < (int)dockWindows->count() )
+ dockWindows->at( dockWindowIndex )->setNewLine( TRUE );
+ layout->layoutItems( QRect( 0, 0, width(), height() ), TRUE );
+ }
+ } else {
+ dockWindow = w;
+ dockWindow->reparent( this, QPoint( 0, 0 ), TRUE );
+ if ( swap )
+ dockWindow->resize( dockWindow->height(), dockWindow->width() );
+ w->installEventFilter( this );
+ }
+
+ lineStarts = layout->lineStarts();
+ lines = layout->lineList();
+
+ QRect rect = QRect( mapFromGlobal( r.topLeft() ), r.size() );
+ if ( orientation() == Horizontal && QApplication::reverseLayout() ) {
+ rect = QRect( width() - rect.x() - rect.width(), rect.y(), rect.width(), rect.height() );
+ pos.rx() = width() - pos.x();
+ }
+ dockWindow->setOffset( point_pos( rect.topLeft(), orientation() ) );
+ if ( orientation() == Horizontal ) {
+ int offs = dockWindow->offset();
+ if ( width() - offs < dockWindow->minimumWidth() )
+ dockWindow->setOffset( width() - dockWindow->minimumWidth() );
+ } else {
+ int offs = dockWindow->offset();
+ if ( height() - offs < dockWindow->minimumHeight() )
+ dockWindow->setOffset( height() - dockWindow->minimumHeight() );
+ }
+
+ if ( dockWindows->isEmpty() ) {
+ dockWindows->append( dockWindow );
+ } else {
+ int dockLine = -1;
+ bool insertLine = FALSE;
+ int i = 0;
+ QRect lineRect;
+ // find the line which we touched with the mouse
+ for ( QValueList<QRect>::Iterator it = lines.begin(); it != lines.end(); ++it, ++i ) {
+ if ( point_pos( pos, orientation(), TRUE ) >= point_pos( (*it).topLeft(), orientation(), TRUE ) &&
+ point_pos( pos, orientation(), TRUE ) <= point_pos( (*it).topLeft(), orientation(), TRUE ) +
+ size_extent( (*it).size(), orientation(), TRUE ) ) {
+ dockLine = i;
+ lineRect = *it;
+ break;
+ }
+ }
+ if ( dockLine == -1 ) { // outside the dock...
+ insertLine = TRUE;
+ if ( point_pos( pos, orientation(), TRUE ) < 0 ) // insert as first line
+ dockLine = 0;
+ else
+ dockLine = (int)lines.count(); // insert after the last line ### size_t/int cast
+ } else { // inside the dock (we have found a dockLine)
+ if ( point_pos( pos, orientation(), TRUE ) <
+ point_pos( lineRect.topLeft(), orientation(), TRUE ) + 4 ) { // mouse was at the very beginning of the line
+ insertLine = TRUE; // insert a new line before that with the docking widget
+ } else if ( point_pos( pos, orientation(), TRUE ) >
+ point_pos( lineRect.topLeft(), orientation(), TRUE ) +
+ size_extent( lineRect.size(), orientation(), TRUE ) - 4 ) { // mouse was at the very and of the line
+ insertLine = TRUE; // insert a line after that with the docking widget
+ dockLine++;
+ }
+ }
+
+ if ( !insertLine && wasAloneInLine && lr.contains( pos ) ) // if we are alone in a line and just moved in there, re-insert it
+ insertLine = TRUE;
+
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "insert in line %d, and insert that line: %d", dockLine, insertLine );
+ qDebug( " (btw, we have %d lines)", lines.count() );
+#endif
+ QDockWindow *dw = 0;
+ if ( dockLine >= (int)lines.count() ) { // insert after last line
+ dockWindows->append( dockWindow );
+ dockWindow->setNewLine( TRUE );
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "insert at the end" );
+#endif
+ } else if ( dockLine == 0 && insertLine ) { // insert before first line
+ dockWindows->insert( 0, dockWindow );
+ dockWindows->at( 1 )->setNewLine( TRUE );
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "insert at the begin" );
+#endif
+ } else { // insert somewhere in between
+ // make sure each line start has a new line
+ for ( dw = lineStarts.first(); dw; dw = lineStarts.next() )
+ dw->setNewLine( TRUE );
+
+ // find the index of the first widget in the search line
+ int searchLine = dockLine;
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "search line start of %d", searchLine );
+#endif
+ QDockWindow *lsw = lineStarts.at( searchLine );
+ int index = dockWindows->find( lsw );
+ if ( index == -1 ) { // the linestart widget hasn't been found, try to find it harder
+ if ( lsw == w && dockWindowIndex <= (int)dockWindows->count())
+ index = dockWindowIndex;
+ else
+ index = 0;
+ if ( index < (int)dockWindows->count() )
+ (void)dockWindows->at( index ); // move current to index
+ }
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( " which starts at %d", index );
+#endif
+ if ( !insertLine ) { // if we insert the docking widget in the existing line
+ // find the index for the widget
+ bool inc = TRUE;
+ bool firstTime = TRUE;
+ for ( dw = dockWindows->current(); dw; dw = dockWindows->next() ) {
+ if ( orientation() == Horizontal )
+ dw->setFixedExtentWidth( -1 );
+ else
+ dw->setFixedExtentHeight( -1 );
+ if ( !firstTime && lineStarts.find( dw ) != -1 ) // we are in the next line, so break
+ break;
+ if ( point_pos( pos, orientation() ) <
+ point_pos( fix_pos( dw ), orientation() ) + size_extent( dw->size(), orientation() ) / 2 ) {
+ inc = FALSE;
+ }
+ if ( inc )
+ index++;
+ firstTime = FALSE;
+ }
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "insert at index: %d", index );
+#endif
+ // if we insert it just before a widget which has a new line, transfer the newline to the docking widget
+ // but not if we didn't only mave a widget in its line which was alone in the line before
+ if ( !( wasAloneInLine && lr.contains( pos ) )
+ && index >= 0 && index < (int)dockWindows->count() &&
+ dockWindows->at( index )->newLine() && lineOf( index ) == dockLine ) {
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "get rid of the old newline and get me one" );
+#endif
+ dockWindows->at( index )->setNewLine( FALSE );
+ dockWindow->setNewLine( TRUE );
+ } else if ( wasAloneInLine && lr.contains( pos ) ) {
+ dockWindow->setNewLine( TRUE );
+ } else { // if we are somewhere in a line, get rid of the newline
+ dockWindow->setNewLine( FALSE );
+ }
+ } else { // insert in a new line, so make sure the dock widget and the widget which will be after it have a newline
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "insert a new line" );
+#endif
+ if ( index < (int)dockWindows->count() ) {
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "give the widget at %d a newline", index );
+#endif
+ QDockWindow* nldw = dockWindows->at( index );
+ if ( nldw )
+ nldw->setNewLine( TRUE );
+ }
+#if defined(QDOCKAREA_DEBUG)
+ qDebug( "give me a newline" );
+#endif
+ dockWindow->setNewLine( TRUE );
+ }
+ // finally insert the widget
+ dockWindows->insert( index, dockWindow );
+ }
+ }
+
+ if ( mse != -10 && w->isResizeEnabled() ) {
+ if ( orientation() != Qt::Horizontal )
+ w->setFixedExtentWidth( QMIN( QMAX( w->minimumWidth(), mse ), w->sizeHint().width() ) );
+ else
+ w->setFixedExtentHeight( QMIN( QMAX( w->minimumHeight(), mse ), w->sizeHint().height() ) );
+ }
+
+ updateLayout();
+ setSizePolicy( QSizePolicy( orientation() == Horizontal ? QSizePolicy::Expanding : QSizePolicy::Minimum,
+ orientation() == Vertical ? QSizePolicy::Expanding : QSizePolicy::Minimum ) );
+}
+
+/*!
+ Removes the dock window \a w from the dock area. If \a
+ makeFloating is TRUE, \a w gets floated, and if \a swap is TRUE,
+ the orientation of \a w gets swapped. If \a fixNewLines is TRUE
+ (the default) newlines in the area will be fixed.
+
+ You should never need to call this function yourself. Use
+ QDockWindow::dock() and QDockWindow::undock() instead.
+*/
+
+void QDockArea::removeDockWindow( QDockWindow *w, bool makeFloating, bool swap, bool fixNewLines )
+{
+ w->removeEventFilter( this );
+ QDockWindow *dockWindow = 0;
+ int i = findDockWindow( w );
+ if ( i == -1 )
+ return;
+ dockWindow = dockWindows->at( i );
+ dockWindows->remove( i );
+ QPtrList<QDockWindow> lineStarts = layout->lineStarts();
+ if ( fixNewLines && lineStarts.findRef( dockWindow ) != -1 && i < (int)dockWindows->count() )
+ dockWindows->at( i )->setNewLine( TRUE );
+ if ( makeFloating ) {
+ QWidget *p = parentWidget() ? parentWidget() : topLevelWidget();
+ dockWindow->reparent( p, WType_Dialog | WStyle_Customize | WStyle_NoBorder | WStyle_Tool, QPoint( 0, 0 ), FALSE );
+ }
+ if ( swap )
+ dockWindow->resize( dockWindow->height(), dockWindow->width() );
+ updateLayout();
+ if ( dockWindows->isEmpty() )
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+}
+
+int QDockArea::findDockWindow( QDockWindow *w )
+{
+ return dockWindows ? dockWindows->findRef( w ) : -1;
+}
+
+void QDockArea::updateLayout()
+{
+ layout->invalidate();
+ layout->activate();
+}
+
+/*! \reimp
+ */
+
+bool QDockArea::eventFilter( QObject *o, QEvent *e )
+{
+ if ( e->type() == QEvent::Close ) {
+ if ( ::qt_cast<QDockWindow*>(o) ) {
+ o->removeEventFilter( this );
+ QApplication::sendEvent( o, e );
+ if ( ( (QCloseEvent*)e )->isAccepted() )
+ removeDockWindow( (QDockWindow*)o, FALSE, FALSE );
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*! \internal
+
+ Invalidates the offset of the next dock window in the dock area.
+ */
+
+void QDockArea::invalidNextOffset( QDockWindow *dw )
+{
+ int i = dockWindows->find( dw );
+ if ( i == -1 || i >= (int)dockWindows->count() - 1 )
+ return;
+ if ( ( dw = dockWindows->at( ++i ) ) )
+ dw->setOffset( 0 );
+}
+
+/*!
+ \property QDockArea::count
+ \brief the number of dock windows in the dock area
+*/
+int QDockArea::count() const
+{
+ return dockWindows->count();
+}
+
+/*!
+ \property QDockArea::empty
+ \brief whether the dock area is empty
+*/
+
+bool QDockArea::isEmpty() const
+{
+ return dockWindows->isEmpty();
+}
+
+
+/*!
+ Returns a list of the dock windows in the dock area.
+*/
+
+QPtrList<QDockWindow> QDockArea::dockWindowList() const
+{
+ return *dockWindows;
+}
+
+/*!
+ Lines up the dock windows in this dock area to minimize wasted
+ space. If \a keepNewLines is TRUE, only space within lines is
+ cleaned up. If \a keepNewLines is FALSE the number of lines might
+ be changed.
+*/
+
+void QDockArea::lineUp( bool keepNewLines )
+{
+ for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
+ dw->setOffset( 0 );
+ if ( !keepNewLines )
+ dw->setNewLine( FALSE );
+ }
+ layout->activate();
+}
+
+QDockArea::DockWindowData *QDockArea::dockWindowData( QDockWindow *w )
+{
+ DockWindowData *data = new DockWindowData;
+ data->index = findDockWindow( w );
+ if ( data->index == -1 ) {
+ delete data;
+ return 0;
+ }
+ QPtrList<QDockWindow> lineStarts = layout->lineStarts();
+ int i = -1;
+ for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
+ if ( lineStarts.findRef( dw ) != -1 )
+ ++i;
+ if ( dw == w )
+ break;
+ }
+ data->line = i;
+ data->offset = point_pos( QPoint( fix_x(w), w->y() ), orientation() );
+ data->area = this;
+ data->fixedExtent = w->fixedExtent();
+ return data;
+}
+
+void QDockArea::dockWindow( QDockWindow *dockWindow, DockWindowData *data )
+{
+ if ( !data )
+ return;
+
+ dockWindow->reparent( this, QPoint( 0, 0 ), FALSE );
+ dockWindow->installEventFilter( this );
+ dockWindow->dockArea = this;
+ dockWindow->updateGui();
+
+ if ( dockWindows->isEmpty() ) {
+ dockWindows->append( dockWindow );
+ } else {
+ QPtrList<QDockWindow> lineStarts = layout->lineStarts();
+ int index = 0;
+ if ( (int)lineStarts.count() > data->line )
+ index = dockWindows->find( lineStarts.at( data->line ) );
+ if ( index == -1 ) {
+ index = 0;
+ (void)dockWindows->at( index );
+ }
+ bool firstTime = TRUE;
+ int offset = data->offset;
+ for ( QDockWindow *dw = dockWindows->current(); dw; dw = dockWindows->next() ) {
+ if ( !firstTime && lineStarts.find( dw ) != -1 )
+ break;
+ if ( offset <
+ point_pos( fix_pos( dw ), orientation() ) + size_extent( dw->size(), orientation() ) / 2 )
+ break;
+ index++;
+ firstTime = FALSE;
+ }
+ if ( index >= 0 && index < (int)dockWindows->count() &&
+ dockWindows->at( index )->newLine() && lineOf( index ) == data->line ) {
+ dockWindows->at( index )->setNewLine( FALSE );
+ dockWindow->setNewLine( TRUE );
+ } else {
+ dockWindow->setNewLine( FALSE );
+ }
+
+ dockWindows->insert( index, dockWindow );
+ }
+ dockWindow->show();
+
+ dockWindow->setFixedExtentWidth( data->fixedExtent.width() );
+ dockWindow->setFixedExtentHeight( data->fixedExtent.height() );
+
+ updateLayout();
+ setSizePolicy( QSizePolicy( orientation() == Horizontal ? QSizePolicy::Expanding : QSizePolicy::Minimum,
+ orientation() == Vertical ? QSizePolicy::Expanding : QSizePolicy::Minimum ) );
+
+}
+
+/*!
+ Returns TRUE if dock window \a dw could be docked into the dock
+ area; otherwise returns FALSE.
+
+ \sa setAcceptDockWindow()
+*/
+
+bool QDockArea::isDockWindowAccepted( QDockWindow *dw )
+{
+ if ( !dw )
+ return FALSE;
+ if ( forbiddenWidgets.findRef( dw ) != -1 )
+ return FALSE;
+
+ QMainWindow *mw = ::qt_cast<QMainWindow*>(parentWidget());
+ if ( !mw )
+ return TRUE;
+ if ( !mw->hasDockWindow( dw ) )
+ return FALSE;
+ if ( !mw->isDockEnabled( this ) )
+ return FALSE;
+ if ( !mw->isDockEnabled( dw, this ) )
+ return FALSE;
+ return TRUE;
+}
+
+/*!
+ If \a accept is TRUE, dock window \a dw can be docked in the dock
+ area. If \a accept is FALSE, dock window \a dw cannot be docked in
+ the dock area.
+
+ \sa isDockWindowAccepted()
+*/
+
+void QDockArea::setAcceptDockWindow( QDockWindow *dw, bool accept )
+{
+ if ( accept )
+ forbiddenWidgets.removeRef( dw );
+ else if ( forbiddenWidgets.findRef( dw ) == -1 )
+ forbiddenWidgets.append( dw );
+}
+
+void QDockArea::invalidateFixedSizes()
+{
+ for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
+ if ( orientation() == Qt::Horizontal )
+ dw->setFixedExtentWidth( -1 );
+ else
+ dw->setFixedExtentHeight( -1 );
+ }
+}
+
+int QDockArea::maxSpace( int hint, QDockWindow *dw )
+{
+ int index = findDockWindow( dw );
+ if ( index == -1 || index + 1 >= (int)dockWindows->count() ) {
+ if ( orientation() == Horizontal )
+ return dw->width();
+ return dw->height();
+ }
+
+ QDockWindow *w = 0;
+ int i = 0;
+ do {
+ w = dockWindows->at( index + (++i) );
+ } while ( i + 1 < (int)dockWindows->count() && ( !w || w->isHidden() ) );
+ if ( !w || !w->isResizeEnabled() || i >= (int)dockWindows->count() ) {
+ if ( orientation() == Horizontal )
+ return dw->width();
+ return dw->height();
+ }
+ int min = 0;
+ QToolBar *tb = ::qt_cast<QToolBar*>(w);
+ if ( orientation() == Horizontal ) {
+ w->setFixedExtentWidth( -1 );
+ if ( !tb )
+ min = QMAX( w->minimumSize().width(), w->minimumSizeHint().width() );
+ else
+ min = w->sizeHint().width();
+ } else {
+ w->setFixedExtentHeight( -1 );
+ if ( !tb )
+ min = QMAX( w->minimumSize().height(), w->minimumSizeHint().height() );
+ else
+ min = w->sizeHint().height();
+ }
+
+ int diff = hint - ( orientation() == Horizontal ? dw->width() : dw->height() );
+
+ if ( ( orientation() == Horizontal ? w->width() : w->height() ) - diff < min )
+ hint = ( orientation() == Horizontal ? dw->width() : dw->height() ) + ( orientation() == Horizontal ? w->width() : w->height() ) - min;
+
+ diff = hint - ( orientation() == Horizontal ? dw->width() : dw->height() );
+ if ( orientation() == Horizontal )
+ w->setFixedExtentWidth( w->width() - diff );
+ else
+ w->setFixedExtentHeight( w->height() - diff );
+ return hint;
+}
+
+void QDockArea::setFixedExtent( int d, QDockWindow *dw )
+{
+ QPtrList<QDockWindow> lst;
+ QDockWindow *w;
+ for ( w = dockWindows->first(); w; w = dockWindows->next() ) {
+ if ( w->isHidden() )
+ continue;
+ if ( orientation() == Horizontal ) {
+ if ( dw->y() != w->y() )
+ continue;
+ } else {
+ if ( dw->x() != w->x() )
+ continue;
+ }
+ if ( orientation() == Horizontal )
+ d = QMAX( d, w->minimumHeight() );
+ else
+ d = QMAX( d, w->minimumWidth() );
+ if ( w->isResizeEnabled() )
+ lst.append( w );
+ }
+ for ( w = lst.first(); w; w = lst.next() ) {
+ if ( orientation() == Horizontal )
+ w->setFixedExtentHeight( d );
+ else
+ w->setFixedExtentWidth( d );
+ }
+}
+
+bool QDockArea::isLastDockWindow( QDockWindow *dw )
+{
+ int i = dockWindows->find( dw );
+ if ( i == -1 || i >= (int)dockWindows->count() - 1 )
+ return TRUE;
+ QDockWindow *w = 0;
+ if ( ( w = dockWindows->at( ++i ) ) ) {
+ if ( orientation() == Horizontal && dw->y() < w->y() )
+ return TRUE;
+ if ( orientation() == Vertical && dw->x() < w->x() )
+ return TRUE;
+ } else {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#ifndef QT_NO_TEXTSTREAM
+
+/*!
+ \relates QDockArea
+
+ Writes the layout of the dock windows in dock area \a dockArea to
+ the text stream \a ts.
+
+ \sa operator>>()
+*/
+
+QTextStream &operator<<( QTextStream &ts, const QDockArea &dockArea )
+{
+ QString str;
+ QPtrList<QDockWindow> l = dockArea.dockWindowList();
+
+ for ( QDockWindow *dw = l.first(); dw; dw = l.next() )
+ str += "[" + QString( dw->caption() ) + "," + QString::number( (int)dw->offset() ) +
+ "," + QString::number( (int)dw->newLine() ) + "," + QString::number( dw->fixedExtent().width() ) +
+ "," + QString::number( dw->fixedExtent().height() ) + "," + QString::number( (int)!dw->isHidden() ) + "]";
+ ts << str << endl;
+
+ return ts;
+}
+
+/*!
+ \relates QDockArea
+
+ Reads the layout description of the dock windows in dock area \a
+ dockArea from the text stream \a ts and restores it. The layout
+ description must have been previously written by the operator<<()
+ function.
+
+ \sa operator<<()
+*/
+
+QTextStream &operator>>( QTextStream &ts, QDockArea &dockArea )
+{
+ QString s = ts.readLine();
+
+ QString name, offset, newLine, width, height, visible;
+
+ enum State { Pre, Name, Offset, NewLine, Width, Height, Visible, Post };
+ int state = Pre;
+ QChar c;
+ QPtrList<QDockWindow> l = dockArea.dockWindowList();
+
+ for ( int i = 0; i < (int)s.length(); ++i ) {
+ c = s[ i ];
+ if ( state == Pre && c == '[' ) {
+ state++;
+ continue;
+ }
+ if ( c == ',' &&
+ ( state == Name || state == Offset || state == NewLine || state == Width || state == Height ) ) {
+ state++;
+ continue;
+ }
+ if ( state == Visible && c == ']' ) {
+ for ( QDockWindow *dw = l.first(); dw; dw = l.next() ) {
+ if ( QString( dw->caption() ) == name ) {
+ dw->setNewLine( (bool)newLine.toInt() );
+ dw->setOffset( offset.toInt() );
+ dw->setFixedExtentWidth( width.toInt() );
+ dw->setFixedExtentHeight( height.toInt() );
+ if ( !(bool)visible.toInt() )
+ dw->hide();
+ else
+ dw->show();
+ break;
+ }
+ }
+
+ name = offset = newLine = width = height = visible = "";
+
+ state = Pre;
+ continue;
+ }
+ if ( state == Name )
+ name += c;
+ else if ( state == Offset )
+ offset += c;
+ else if ( state == NewLine )
+ newLine += c;
+ else if ( state == Width )
+ width += c;
+ else if ( state == Height )
+ height += c;
+ else if ( state == Visible )
+ visible += c;
+ }
+
+ dockArea.QWidget::layout()->invalidate();
+ dockArea.QWidget::layout()->activate();
+ return ts;
+}
+#endif
+
+#endif //QT_NO_MAINWINDOW
diff --git a/src/widgets/qdockarea.h b/src/widgets/qdockarea.h
new file mode 100644
index 0000000..c780d3c
--- /dev/null
+++ b/src/widgets/qdockarea.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Definition of the QDockArea class
+**
+** Created : 001010
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the workspace module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QDOCKAREA_H
+#define QDOCKAREA_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qptrlist.h"
+#include "qdockwindow.h"
+#include "qlayout.h"
+#include "qvaluelist.h"
+#include "qguardedptr.h"
+#include "qtextstream.h"
+#endif // QT_H
+
+#ifndef QT_NO_MAINWINDOW
+
+class QSplitter;
+class QBoxLayout;
+class QDockAreaLayout;
+class QMouseEvent;
+class QDockWindowResizeHandle;
+class QDockAreaPrivate;
+
+class Q_EXPORT QDockAreaLayout : public QLayout
+{
+ Q_OBJECT
+ friend class QDockArea;
+
+public:
+ QDockAreaLayout( QWidget* parent, Qt::Orientation o, QPtrList<QDockWindow> *wl, int space = -1, int margin = -1, const char *name = 0 )
+ : QLayout( parent, space, margin, name ), orient( o ), dockWindows( wl ), parentWidget( parent ) { init(); }
+ ~QDockAreaLayout() {}
+
+ void addItem( QLayoutItem * ) {}
+ bool hasHeightForWidth() const;
+ int heightForWidth( int ) const;
+ int widthForHeight( int ) const;
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ QLayoutIterator iterator();
+ QSizePolicy::ExpandData expanding() const { return QSizePolicy::NoDirection; }
+ void invalidate();
+ Qt::Orientation orientation() const { return orient; }
+ QValueList<QRect> lineList() const { return lines; }
+ QPtrList<QDockWindow> lineStarts() const { return ls; }
+
+protected:
+ void setGeometry( const QRect& );
+
+private:
+ void init();
+ int layoutItems( const QRect&, bool testonly = FALSE );
+ Qt::Orientation orient;
+ bool dirty;
+ int cached_width, cached_height;
+ int cached_hfw, cached_wfh;
+ QPtrList<QDockWindow> *dockWindows;
+ QWidget *parentWidget;
+ QValueList<QRect> lines;
+ QPtrList<QDockWindow> ls;
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ QDockAreaLayout( const QDockAreaLayout & );
+ QDockAreaLayout &operator=( const QDockAreaLayout & );
+#endif
+};
+
+class Q_EXPORT QDockArea : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS( HandlePosition )
+ Q_PROPERTY( Orientation orientation READ orientation )
+ Q_PROPERTY( int count READ count )
+ Q_PROPERTY( bool empty READ isEmpty )
+ Q_PROPERTY( HandlePosition handlePosition READ handlePosition )
+
+ friend class QDockWindow;
+ friend class QDockWindowResizeHandle;
+ friend class QDockAreaLayout;
+
+public:
+ enum HandlePosition { Normal, Reverse };
+
+ QDockArea( Orientation o, HandlePosition h = Normal, QWidget* parent=0, const char* name=0 );
+ ~QDockArea();
+
+ void moveDockWindow( QDockWindow *w, const QPoint &globalPos, const QRect &rect, bool swap );
+ void removeDockWindow( QDockWindow *w, bool makeFloating, bool swap, bool fixNewLines = TRUE );
+ void moveDockWindow( QDockWindow *w, int index = -1 );
+ bool hasDockWindow( QDockWindow *w, int *index = 0 );
+
+ void invalidNextOffset( QDockWindow *dw );
+
+ Orientation orientation() const { return orient; }
+ HandlePosition handlePosition() const { return hPos; }
+
+ bool eventFilter( QObject *, QEvent * );
+ bool isEmpty() const;
+ int count() const;
+ QPtrList<QDockWindow> dockWindowList() const;
+
+ bool isDockWindowAccepted( QDockWindow *dw );
+ void setAcceptDockWindow( QDockWindow *dw, bool accept );
+
+public slots:
+ void lineUp( bool keepNewLines );
+
+private:
+ struct DockWindowData
+ {
+ int index;
+ int offset;
+ int line;
+ QSize fixedExtent;
+ QGuardedPtr<QDockArea> area;
+ };
+
+ int findDockWindow( QDockWindow *w );
+ int lineOf( int index );
+ DockWindowData *dockWindowData( QDockWindow *w );
+ void dockWindow( QDockWindow *dockWindow, DockWindowData *data );
+ void updateLayout();
+ void invalidateFixedSizes();
+ int maxSpace( int hint, QDockWindow *dw );
+ void setFixedExtent( int d, QDockWindow *dw );
+ bool isLastDockWindow( QDockWindow *dw );
+
+private:
+ Orientation orient;
+ QPtrList<QDockWindow> *dockWindows;
+ QDockAreaLayout *layout;
+ HandlePosition hPos;
+ QPtrList<QDockWindow> forbiddenWidgets;
+ QDockAreaPrivate *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QDockArea( const QDockArea & );
+ QDockArea& operator=( const QDockArea & );
+#endif
+
+};
+
+#ifndef QT_NO_TEXTSTREAM
+Q_EXPORT QTextStream &operator<<( QTextStream &, const QDockArea & );
+Q_EXPORT QTextStream &operator>>( QTextStream &, QDockArea & );
+#endif
+
+#define Q_DEFINED_QDOCKAREA
+#include "qwinexport.h"
+#endif
+
+#endif //QT_NO_MAINWINDOW
diff --git a/src/widgets/qdockwindow.cpp b/src/widgets/qdockwindow.cpp
new file mode 100644
index 0000000..8646ec9
--- /dev/null
+++ b/src/widgets/qdockwindow.cpp
@@ -0,0 +1,2123 @@
+/****************************************************************************
+**
+** Implementation of the QDockWindow class
+**
+** Created : 001010
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the workspace module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qdockwindow.h"
+
+#ifndef QT_NO_MAINWINDOW
+#include "qdesktopwidget.h"
+#include "qdockarea.h"
+#include "qwidgetresizehandler_p.h"
+#include "qtitlebar_p.h"
+#include "qpainter.h"
+#include "qapplication.h"
+#include "qtoolbutton.h"
+#include "qtoolbar.h"
+#include "qlayout.h"
+#include "qmainwindow.h"
+#include "qtimer.h"
+#include "qtooltip.h"
+#include "qguardedptr.h"
+#include "qcursor.h"
+#include "qstyle.h"
+
+#if defined(Q_WS_MAC9)
+#define MAC_DRAG_HACK
+#endif
+#ifdef Q_WS_MACX
+static bool default_opaque = TRUE;
+#else
+static bool default_opaque = FALSE;
+#endif
+
+class QDockWindowPrivate
+{
+};
+
+class QDockWindowResizeHandle : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QDockWindowResizeHandle( Qt::Orientation o, QWidget *parent, QDockWindow *w, const char* /*name*/=0 );
+ void setOrientation( Qt::Orientation o );
+ Qt::Orientation orientation() const { return orient; }
+
+ QSize sizeHint() const;
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+
+private:
+ void startLineDraw();
+ void endLineDraw();
+ void drawLine( const QPoint &globalPos );
+
+private:
+ Qt::Orientation orient;
+ bool mousePressed;
+ QPainter *unclippedPainter;
+ QPoint lastPos, firstPos;
+ QDockWindow *dockWindow;
+
+};
+
+QDockWindowResizeHandle::QDockWindowResizeHandle( Qt::Orientation o, QWidget *parent,
+ QDockWindow *w, const char * )
+ : QWidget( parent, "qt_dockwidget_internal" ), mousePressed( FALSE ), unclippedPainter( 0 ), dockWindow( w )
+{
+ setOrientation( o );
+}
+
+QSize QDockWindowResizeHandle::sizeHint() const
+{
+ int sw = 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3;
+ return (style().sizeFromContents(QStyle::CT_DockWindow, this, QSize(sw, sw)).
+ expandedTo(QApplication::globalStrut()));
+}
+
+void QDockWindowResizeHandle::setOrientation( Qt::Orientation o )
+{
+ orient = o;
+ if ( o == QDockArea::Horizontal ) {
+#ifndef QT_NO_CURSOR
+ setCursor( splitVCursor );
+#endif
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
+ } else {
+#ifndef QT_NO_CURSOR
+ setCursor( splitHCursor );
+#endif
+ setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ) );
+ }
+}
+
+void QDockWindowResizeHandle::mousePressEvent( QMouseEvent *e )
+{
+ e->ignore();
+ if ( e->button() != LeftButton )
+ return;
+ e->accept();
+ mousePressed = TRUE;
+ if ( !dockWindow->opaqueMoving() )
+ startLineDraw();
+ lastPos = firstPos = e->globalPos();
+ if ( !dockWindow->opaqueMoving() )
+ drawLine( e->globalPos() );
+}
+
+void QDockWindowResizeHandle::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !mousePressed )
+ return;
+ if ( !dockWindow->opaqueMoving() ) {
+ if ( orientation() != dockWindow->area()->orientation() ) {
+ if ( orientation() == Horizontal ) {
+ int minpos = dockWindow->area()->mapToGlobal( QPoint( 0, 0 ) ).y();
+ int maxpos = dockWindow->area()->mapToGlobal( QPoint( 0, 0 ) ).y() + dockWindow->area()->height();
+ if ( e->globalPos().y() < minpos || e->globalPos().y() > maxpos )
+ return;
+ } else {
+ int minpos = dockWindow->area()->mapToGlobal( QPoint( 0, 0 ) ).x();
+ int maxpos = dockWindow->area()->mapToGlobal( QPoint( 0, 0 ) ).x() + dockWindow->area()->width();
+ if ( e->globalPos().x() < minpos || e->globalPos().x() > maxpos )
+ return;
+ }
+ } else {
+ QWidget *w = dockWindow->area()->topLevelWidget();
+ if ( w ) {
+ if ( orientation() == Horizontal ) {
+ int minpos = w->mapToGlobal( QPoint( 0, 0 ) ).y();
+ int maxpos = w->mapToGlobal( QPoint( 0, 0 ) ).y() + w->height();
+ if ( e->globalPos().y() < minpos || e->globalPos().y() > maxpos )
+ return;
+ } else {
+ int minpos = w->mapToGlobal( QPoint( 0, 0 ) ).x();
+ int maxpos = w->mapToGlobal( QPoint( 0, 0 ) ).x() + w->width();
+ if ( e->globalPos().x() < minpos || e->globalPos().x() > maxpos )
+ return;
+ }
+ }
+ }
+ }
+
+ if ( !dockWindow->opaqueMoving() )
+ drawLine( lastPos );
+ lastPos = e->globalPos();
+ if ( dockWindow->opaqueMoving() ) {
+ mouseReleaseEvent( e );
+ mousePressed = TRUE;
+ firstPos = e->globalPos();
+ }
+ if ( !dockWindow->opaqueMoving() )
+ drawLine( e->globalPos() );
+}
+
+void QDockWindowResizeHandle::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( mousePressed ) {
+ if ( !dockWindow->opaqueMoving() ) {
+ drawLine( lastPos );
+ endLineDraw();
+ }
+ if ( orientation() != dockWindow->area()->orientation() )
+ dockWindow->area()->invalidNextOffset( dockWindow );
+ if ( orientation() == Horizontal ) {
+ int dy;
+ if ( dockWindow->area()->handlePosition() == QDockArea::Normal || orientation() != dockWindow->area()->orientation() )
+ dy = e->globalPos().y() - firstPos.y();
+ else
+ dy = firstPos.y() - e->globalPos().y();
+ int d = dockWindow->height() + dy;
+ if ( orientation() != dockWindow->area()->orientation() ) {
+ dockWindow->setFixedExtentHeight( -1 );
+ d = QMAX( d, dockWindow->minimumHeight() );
+ int ms = dockWindow->area()->maxSpace( d, dockWindow );
+ d = QMIN( d, ms );
+ dockWindow->setFixedExtentHeight( d );
+ } else {
+ dockWindow->area()->setFixedExtent( d, dockWindow );
+ }
+ } else {
+ int dx;
+ if ( dockWindow->area()->handlePosition() == QDockArea::Normal || orientation() != dockWindow->area()->orientation() )
+ dx = e->globalPos().x() - firstPos.x();
+ else
+ dx = firstPos.x() - e->globalPos().x();
+ int d = dockWindow->width() + dx;
+ if ( orientation() != dockWindow->area()->orientation() ) {
+ dockWindow->setFixedExtentWidth( -1 );
+ d = QMAX( d, dockWindow->minimumWidth() );
+ int ms = dockWindow->area()->maxSpace( d, dockWindow );
+ d = QMIN( d, ms );
+ dockWindow->setFixedExtentWidth( d );
+ } else {
+ dockWindow->area()->setFixedExtent( d, dockWindow );
+ }
+ }
+ }
+
+ QApplication::postEvent( dockWindow->area(), new QEvent( QEvent::LayoutHint ) );
+ mousePressed = FALSE;
+}
+
+void QDockWindowResizeHandle::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ style().drawPrimitive(QStyle::PE_DockWindowResizeHandle, &p, rect(), colorGroup(),
+ (isEnabled() ?
+ QStyle::Style_Enabled : QStyle::Style_Default) |
+ (orientation() == Qt::Horizontal ?
+ QStyle::Style_Horizontal : QStyle::Style_Default ));
+}
+
+void QDockWindowResizeHandle::startLineDraw()
+{
+ if ( unclippedPainter )
+ endLineDraw();
+#ifdef MAC_DRAG_HACK
+ QWidget *paint_on = topLevelWidget();
+#else
+ int scr = QApplication::desktop()->screenNumber( this );
+ QWidget *paint_on = QApplication::desktop()->screen( scr );
+#endif
+ unclippedPainter = new QPainter( paint_on, TRUE );
+ unclippedPainter->setPen( QPen( gray, orientation() == Horizontal ? height() : width() ) );
+ unclippedPainter->setRasterOp( XorROP );
+}
+
+void QDockWindowResizeHandle::endLineDraw()
+{
+ if ( !unclippedPainter )
+ return;
+ delete unclippedPainter;
+ unclippedPainter = 0;
+}
+
+void QDockWindowResizeHandle::drawLine( const QPoint &globalPos )
+{
+#ifdef MAC_DRAG_HACK
+ QPoint start = mapTo(topLevelWidget(), QPoint(0, 0));
+ QPoint starta = dockWindow->area()->mapTo(topLevelWidget(), QPoint(0, 0));
+ QPoint end = globalPos - topLevelWidget()->pos();
+#else
+ QPoint start = mapToGlobal( QPoint( 0, 0 ) );
+ QPoint starta = dockWindow->area()->mapToGlobal( QPoint( 0, 0 ) );
+ QPoint end = globalPos;
+#endif
+
+ if ( orientation() == Horizontal ) {
+ if ( orientation() == dockWindow->orientation() )
+ unclippedPainter->drawLine( starta.x() , end.y(), starta.x() + dockWindow->area()->width(), end.y() );
+ else
+ unclippedPainter->drawLine( start.x(), end.y(), start.x() + width(), end.y() );
+ } else {
+ if ( orientation() == dockWindow->orientation() )
+ unclippedPainter->drawLine( end.x(), starta.y(), end.x(), starta.y() + dockWindow->area()->height() );
+ else
+ unclippedPainter->drawLine( end.x(), start.y(), end.x(), start.y() + height() );
+ }
+}
+
+static QPoint realWidgetPos( QDockWindow *w )
+{
+ if ( !w->parentWidget() || w->place() == QDockWindow::OutsideDock )
+ return w->pos();
+ return w->parentWidget()->mapToGlobal( w->geometry().topLeft() );
+}
+
+class QDockWindowHandle : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY( QString caption READ caption )
+ friend class QDockWindow;
+ friend class QDockWindowTitleBar;
+
+public:
+ QDockWindowHandle( QDockWindow *dw );
+ void updateGui();
+
+ QSize minimumSizeHint() const;
+ QSize minimumSize() const { return minimumSizeHint(); }
+ QSize sizeHint() const { return minimumSize(); }
+ QSizePolicy sizePolicy() const;
+ void setOpaqueMoving( bool b ) { opaque = b; }
+
+ QString caption() const { return dockWindow->caption(); }
+
+signals:
+ void doubleClicked();
+
+protected:
+ void paintEvent( QPaintEvent *e );
+ void resizeEvent( QResizeEvent *e );
+ void mousePressEvent( QMouseEvent *e );
+ void mouseMoveEvent( QMouseEvent *e );
+ void mouseReleaseEvent( QMouseEvent *e );
+ void mouseDoubleClickEvent( QMouseEvent *e );
+ void keyPressEvent( QKeyEvent *e );
+ void keyReleaseEvent( QKeyEvent *e );
+#ifndef QT_NO_STYLE
+ void styleChange( QStyle& );
+#endif
+
+private slots:
+ void minimize();
+
+private:
+ QDockWindow *dockWindow;
+ QPoint offset;
+ QToolButton *closeButton;
+ QTimer *timer;
+ uint opaque : 1;
+ uint mousePressed : 1;
+ uint hadDblClick : 1;
+ uint ctrlDown : 1;
+ QGuardedPtr<QWidget> oldFocus;
+};
+
+class QDockWindowTitleBar : public QTitleBar
+{
+ Q_OBJECT
+ friend class QDockWindow;
+ friend class QDockWindowHandle;
+
+public:
+ QDockWindowTitleBar( QDockWindow *dw );
+ void updateGui();
+ void setOpaqueMoving( bool b ) { opaque = b; }
+
+protected:
+ void resizeEvent( QResizeEvent *e );
+ void mousePressEvent( QMouseEvent *e );
+ void mouseMoveEvent( QMouseEvent *e );
+ void mouseReleaseEvent( QMouseEvent *e );
+ void mouseDoubleClickEvent( QMouseEvent *e );
+ void keyPressEvent( QKeyEvent *e );
+ void keyReleaseEvent( QKeyEvent *e );
+
+private:
+ QDockWindow *dockWindow;
+ QPoint offset;
+ uint mousePressed : 1;
+ uint hadDblClick : 1;
+ uint opaque : 1;
+ uint ctrlDown : 1;
+ QGuardedPtr<QWidget> oldFocus;
+
+};
+
+QDockWindowHandle::QDockWindowHandle( QDockWindow *dw )
+ : QWidget( dw, "qt_dockwidget_internal", WNoAutoErase ), dockWindow( dw ),
+ closeButton( 0 ), opaque( default_opaque ), mousePressed( FALSE )
+{
+ ctrlDown = FALSE;
+ timer = new QTimer( this );
+ connect( timer, SIGNAL( timeout() ), this, SLOT( minimize() ) );
+#ifdef Q_WS_WIN
+ setCursor( SizeAllCursor );
+#endif
+}
+
+void QDockWindowHandle::paintEvent( QPaintEvent *e )
+{
+ if ( (!dockWindow->dockArea || mousePressed) && !opaque )
+ return;
+ erase();
+ QPainter p( this );
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if ( !dockWindow->area() || dockWindow->area()->orientation() == Horizontal )
+ flags |= QStyle::Style_Horizontal;
+
+ style().drawPrimitive( QStyle::PE_DockWindowHandle, &p,
+ QStyle::visualRect( style().subRect( QStyle::SR_DockWindowHandleRect,
+ this ), this ),
+ colorGroup(), flags );
+ QWidget::paintEvent( e );
+}
+
+void QDockWindowHandle::keyPressEvent( QKeyEvent *e )
+{
+ if ( !mousePressed )
+ return;
+ if ( e->key() == Key_Control ) {
+ ctrlDown = TRUE;
+ dockWindow->handleMove( mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque );
+ }
+}
+
+void QDockWindowHandle::keyReleaseEvent( QKeyEvent *e )
+{
+ if ( !mousePressed )
+ return;
+ if ( e->key() == Key_Control ) {
+ ctrlDown = FALSE;
+ dockWindow->handleMove( mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque );
+ }
+}
+
+void QDockWindowHandle::mousePressEvent( QMouseEvent *e )
+{
+ if ( !dockWindow->dockArea )
+ return;
+ ctrlDown = ( e->state() & ControlButton ) == ControlButton;
+ oldFocus = qApp->focusWidget();
+ setFocus();
+ e->ignore();
+ if ( e->button() != LeftButton )
+ return;
+ e->accept();
+ hadDblClick = FALSE;
+ mousePressed = TRUE;
+ offset = e->pos();
+ dockWindow->startRectDraw( mapToGlobal( e->pos() ), !opaque );
+ if ( !opaque )
+ qApp->installEventFilter( dockWindow );
+}
+
+void QDockWindowHandle::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !mousePressed || e->pos() == offset )
+ return;
+ ctrlDown = ( e->state() & ControlButton ) == ControlButton;
+ dockWindow->handleMove( e->pos() - offset, e->globalPos(), !opaque );
+ if ( opaque )
+ dockWindow->updatePosition( e->globalPos() );
+}
+
+void QDockWindowHandle::mouseReleaseEvent( QMouseEvent *e )
+{
+ ctrlDown = FALSE;
+ qApp->removeEventFilter( dockWindow );
+ if ( oldFocus )
+ oldFocus->setFocus();
+ if ( !mousePressed )
+ return;
+ dockWindow->endRectDraw( !opaque );
+ mousePressed = FALSE;
+#ifdef Q_WS_MAC
+ releaseMouse();
+#endif
+ if ( !hadDblClick && offset == e->pos() ) {
+ timer->start( QApplication::doubleClickInterval(), TRUE );
+ } else if ( !hadDblClick ) {
+ dockWindow->updatePosition( e->globalPos() );
+ }
+ if ( opaque )
+ dockWindow->titleBar->mousePressed = FALSE;
+}
+
+void QDockWindowHandle::minimize()
+{
+ if ( !dockWindow->area() )
+ return;
+
+ QMainWindow *mw = ::qt_cast<QMainWindow*>(dockWindow->area()->parentWidget());
+ if ( mw && mw->isDockEnabled( dockWindow, Qt::DockMinimized ) )
+ mw->moveDockWindow( dockWindow, Qt::DockMinimized );
+}
+
+void QDockWindowHandle::resizeEvent( QResizeEvent * )
+{
+ updateGui();
+}
+
+void QDockWindowHandle::updateGui()
+{
+ if ( !closeButton ) {
+ closeButton = new QToolButton( this, "qt_close_button1" );
+#ifndef QT_NO_CURSOR
+ closeButton->setCursor( arrowCursor );
+#endif
+ closeButton->setPixmap( style().stylePixmap( QStyle::SP_DockWindowCloseButton, closeButton ) );
+ closeButton->setFixedSize( 12, 12 );
+ connect( closeButton, SIGNAL( clicked() ),
+ dockWindow, SLOT( hide() ) );
+ }
+
+ if ( dockWindow->isCloseEnabled() && dockWindow->area() )
+ closeButton->show();
+ else
+ closeButton->hide();
+
+ if ( !dockWindow->area() )
+ return;
+
+ if ( dockWindow->area()->orientation() == Horizontal ) {
+ int off = ( width() - closeButton->width() - 1 ) / 2;
+ closeButton->move( off, 2 );
+ } else {
+ int off = ( height() - closeButton->height() - 1 ) / 2;
+ int x = QApplication::reverseLayout() ? 2 : width() - closeButton->width() - 2;
+ closeButton->move( x, off );
+ }
+}
+
+#ifndef QT_NO_STYLE
+void QDockWindowHandle::styleChange( QStyle& )
+{
+ if ( closeButton )
+ closeButton->setPixmap( style().stylePixmap( QStyle::SP_DockWindowCloseButton, closeButton ) );
+}
+#endif
+
+QSize QDockWindowHandle::minimumSizeHint() const
+{
+ if ( !dockWindow->dockArea )
+ return QSize( 0, 0 );
+ int wh = dockWindow->isCloseEnabled() ? 17 : style().pixelMetric( QStyle::PM_DockWindowHandleExtent, this );
+ if ( dockWindow->orientation() == Horizontal )
+ return QSize( wh, 0 );
+ return QSize( 0, wh );
+}
+
+QSizePolicy QDockWindowHandle::sizePolicy() const
+{
+ if ( dockWindow->orientation() != Horizontal )
+ return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
+ return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
+}
+
+void QDockWindowHandle::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ e->ignore();
+ if ( e->button() != LeftButton )
+ return;
+ e->accept();
+ timer->stop();
+ emit doubleClicked();
+ hadDblClick = TRUE;
+}
+
+QDockWindowTitleBar::QDockWindowTitleBar( QDockWindow *dw )
+ : QTitleBar( 0, dw, "qt_dockwidget_internal" ), dockWindow( dw ),
+ mousePressed( FALSE ), hadDblClick( FALSE ), opaque( default_opaque )
+{
+ setWFlags( getWFlags() | WStyle_Tool );
+ ctrlDown = FALSE;
+ setMouseTracking( TRUE );
+ setFixedHeight( style().pixelMetric( QStyle::PM_TitleBarHeight, this ) );
+ connect( this, SIGNAL(doClose()), dockWindow, SLOT(hide()) );
+}
+
+void QDockWindowTitleBar::keyPressEvent( QKeyEvent *e )
+{
+ if ( !mousePressed )
+ return;
+ if ( e->key() == Key_Control ) {
+ ctrlDown = TRUE;
+ dockWindow->handleMove( mapFromGlobal( QCursor::pos() ) - offset, QCursor::pos(), !opaque );
+ }
+}
+
+void QDockWindowTitleBar::keyReleaseEvent( QKeyEvent *e )
+{
+ if ( !mousePressed )
+ return;
+ if ( e->key() == Key_Control ) {
+ ctrlDown = FALSE;
+ dockWindow->handleMove( mapFromGlobal( QCursor::pos() ) - offset, QCursor::pos(), !opaque );
+ }
+}
+
+void QDockWindowTitleBar::mousePressEvent( QMouseEvent *e )
+{
+ QStyle::SubControl tbctrl = style().querySubControl( QStyle::CC_TitleBar, this, e->pos() );
+ if ( tbctrl > QStyle::SC_TitleBarLabel ) {
+ QTitleBar::mousePressEvent( e );
+ return;
+ }
+
+ ctrlDown = ( e->state() & ControlButton ) == ControlButton;
+ oldFocus = qApp->focusWidget();
+// setFocus activates the window, which deactivates the main window
+// not what we want, and not required anyway on Windows
+#ifndef Q_WS_WIN
+ setFocus();
+#endif
+
+ e->ignore();
+ if ( e->button() != LeftButton )
+ return;
+ if ( e->y() < 3 && dockWindow->isResizeEnabled() )
+ return;
+
+ e->accept();
+ bool oldPressed = mousePressed;
+ mousePressed = TRUE;
+ hadDblClick = FALSE;
+ offset = e->pos();
+ dockWindow->startRectDraw( mapToGlobal( e->pos() ), !opaque );
+// grabMouse resets the Windows mouse press count, so we never receive a double click on Windows
+// not required on Windows, and did work on X11, too, but no problem there in the first place
+#ifndef Q_WS_WIN
+ if(!oldPressed && dockWindow->opaqueMoving())
+ grabMouse();
+#else
+ Q_UNUSED( oldPressed );
+#endif
+}
+
+void QDockWindowTitleBar::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !mousePressed ) {
+ QTitleBar::mouseMoveEvent( e );
+ return;
+ }
+
+ ctrlDown = ( e->state() & ControlButton ) == ControlButton;
+ e->accept();
+ dockWindow->handleMove( e->pos() - offset, e->globalPos(), !opaque );
+}
+
+void QDockWindowTitleBar::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !mousePressed ) {
+ QTitleBar::mouseReleaseEvent( e );
+ return;
+ }
+
+ ctrlDown = FALSE;
+ qApp->removeEventFilter( dockWindow );
+ if ( oldFocus )
+ oldFocus->setFocus();
+
+ if ( dockWindow->place() == QDockWindow::OutsideDock )
+ dockWindow->raise();
+
+ if(dockWindow->opaqueMoving())
+ releaseMouse();
+ if ( !mousePressed )
+ return;
+ dockWindow->endRectDraw( !opaque );
+ mousePressed = FALSE;
+ if ( !hadDblClick )
+ dockWindow->updatePosition( e->globalPos() );
+ if ( opaque ) {
+ dockWindow->horHandle->mousePressed = FALSE;
+ dockWindow->verHandle->mousePressed = FALSE;
+ }
+}
+
+void QDockWindowTitleBar::resizeEvent( QResizeEvent *e )
+{
+ updateGui();
+ QTitleBar::resizeEvent( e );
+}
+
+void QDockWindowTitleBar::updateGui()
+{
+ if ( dockWindow->isCloseEnabled() ) {
+ setWFlags( getWFlags() | WStyle_SysMenu );
+ } else {
+ setWFlags( getWFlags() & ~WStyle_SysMenu );
+ }
+}
+
+void QDockWindowTitleBar::mouseDoubleClickEvent( QMouseEvent * )
+{
+ emit doubleClicked();
+ hadDblClick = TRUE;
+}
+
+/*!
+ \class QDockWindow qdockwindow.h
+ \brief The QDockWindow class provides a widget which can be docked
+ inside a QDockArea or floated as a top level window on the
+ desktop.
+
+ \ingroup application
+ \mainclass
+
+ This class handles moving, resizing, docking and undocking dock
+ windows. QToolBar is a subclass of QDockWindow so the
+ functionality provided for dock windows is available with the same
+ API for toolbars.
+
+ \img qmainwindow-qdockareas.png QDockWindows in a QDockArea
+ \caption Two QDockWindows (\l{QToolBar}s) in a \l QDockArea
+
+ \img qdockwindow.png A QDockWindow
+ \caption A Floating QDockWindow
+
+ If the user drags the dock window into the dock area the dock
+ window will be docked. If the user drags the dock area outside any
+ dock areas the dock window will be undocked (floated) and will
+ become a top level window. Double clicking a floating dock
+ window's titlebar will dock the dock window to the last dock area
+ it was docked in. Double clicking a docked dock window's handle
+ will undock (float) the dock window.
+ \omit
+ Single clicking a docked dock window's handle will minimize the
+ dock window (only its handle will appear, below the menu bar).
+ Single clicking the minimized handle will restore the dock window
+ to the last dock area that it was docked in.
+ \endomit
+ If the user clicks the close button (which does not appear on
+ dock windows by default - see \l closeMode) the dock window will
+ disappear. You can control whether or not a dock window has a
+ close button with setCloseMode().
+
+ QMainWindow provides four dock areas (top, left, right and bottom)
+ which can be used by dock windows. For many applications using the
+ dock areas provided by QMainWindow is sufficient. (See the \l
+ QDockArea documentation if you want to create your own dock
+ areas.) In QMainWindow a right-click popup menu (the dock window
+ menu) is available which lists dock windows and can be used to
+ show or hide them. (The popup menu only lists dock windows that
+ have a \link setCaption() caption\endlink.)
+
+ When you construct a dock window you \e must pass it a QDockArea
+ or a QMainWindow as its parent if you want it docked. Pass 0 for
+ the parent if you want it floated.
+
+ \code
+ QToolBar *fileTools = new QToolBar( this, "File Actions" );
+ moveDockWindow( fileTools, Left );
+ \endcode
+
+ In the example above we create a new QToolBar in the constructor
+ of a QMainWindow subclass (so that the \e this pointer points to
+ the QMainWindow). By default the toolbar will be added to the \c
+ Top dock area, but we've moved it to the \c Left dock area.
+
+ A dock window is often used to contain a single widget. In these
+ cases the widget can be set by calling setWidget(). If you're
+ constructing a dock window that contains multiple widgets, e.g. a
+ toolbar, arrange the widgets within a box layout inside the dock
+ window. To do this use the boxLayout() function to get a pointer
+ to the dock window's box layout, then add widgets to the layout
+ using the box layout's QBoxLayout::addWidget() function. The dock
+ window will dynamically set the orientation of the layout to be
+ vertical or horizontal as necessary, although you can control this
+ yourself with setOrientation().
+
+ Although a common use of dock windows is for toolbars, they can be
+ used with any widgets. (See the \link designer-manual.book Qt
+ Designer\endlink and \link linguist-manual.book Qt
+ Linguist\endlink applications, for example.) When using larger
+ widgets it may make sense for the dock window to be resizable by
+ calling setResizeEnabled(). Resizable dock windows are given
+ splitter-like handles to allow the user to resize them within
+ their dock area. When resizable dock windows are undocked they
+ become top level windows and can be resized like any other top
+ level windows, e.g. by dragging a corner or edge.
+
+ Dock windows can be docked and undocked using dock() and undock().
+ A dock window's orientation can be set with setOrientation(). You
+ can also use QDockArea::moveDockWindow(). If you're using a
+ QMainWindow, QMainWindow::moveDockWindow() and
+ QMainWindow::removeDockWindow() are available.
+
+ A dock window can have some preferred settings, for example, you
+ can set a preferred offset from the left edge (or top edge for
+ vertical dock areas) of the dock area using setOffset(). If you'd
+ prefer a dock window to start on a new \link qdockarea.html#lines
+ line\endlink when it is docked use setNewLine(). The
+ setFixedExtentWidth() and setFixedExtentHeight() functions can be
+ used to define the dock window's preferred size, and the
+ setHorizontallyStretchable() and setVerticallyStretchable()
+ functions set whether the dock window can be stretched or not.
+ Dock windows can be moved by default, but this can be changed with
+ setMovingEnabled(). When a dock window is moved it is shown as a
+ rectangular outline, but it can be shown normally using
+ setOpaqueMoving().
+
+ When a dock window's visibility changes, i.e. it is shown or
+ hidden, the visibilityChanged() signal is emitted. When a dock
+ window is docked, undocked or moved inside the dock area the
+ placeChanged() signal is emitted.
+*/
+
+/*!
+ \enum QDockWindow::Place
+
+ This enum specifies the possible locations for a QDockWindow:
+
+ \value InDock Inside a QDockArea.
+ \value OutsideDock Floating as a top level window on the desktop.
+*/
+
+/*!
+ \enum QDockWindow::CloseMode
+
+ This enum type specifies when (if ever) a dock window has a close
+ button.
+
+ \value Never The dock window never has a close button and cannot
+ be closed by the user.
+ \value Docked The dock window has a close button only when
+ docked.
+ \value Undocked The dock window has a close button only when
+ floating.
+ \value Always The dock window always has a close button.
+ \omit
+ Note that dock windows can always be minimized if the user clicks
+ their dock window handle when they are docked.
+ \endomit
+*/
+
+/*!
+ \fn void QDockWindow::setHorizontalStretchable( bool b )
+ \obsolete
+*/
+/*!
+ \fn void QDockWindow::setVerticalStretchable( bool b )
+ \obsolete
+*/
+/*!
+ \fn bool QDockWindow::isHorizontalStretchable() const
+ \obsolete
+*/
+/*!
+ \fn bool QDockWindow::isVerticalStretchable() const
+ \obsolete
+*/
+/*!
+ \fn void QDockWindow::orientationChanged( Orientation o )
+
+ This signal is emitted when the orientation of the dock window is
+ changed. The new orientation is \a o.
+*/
+
+/*!
+ \fn void QDockWindow::placeChanged( QDockWindow::Place p )
+
+ This signal is emitted when the dock window is docked (\a p is \c
+ InDock), undocked (\a p is \c OutsideDock) or moved inside the
+ the dock area.
+
+ \sa QDockArea::moveDockWindow(), QDockArea::removeDockWindow(),
+ QMainWindow::moveDockWindow(), QMainWindow::removeDockWindow()
+*/
+
+/*!
+ \fn void QDockWindow::visibilityChanged( bool visible )
+
+ This signal is emitted when the visibility of the dock window
+ relatively to its dock area is changed. If \a visible is TRUE, the
+ QDockWindow is now visible to the dock area, otherwise it has been
+ hidden.
+
+ A dock window can be hidden if it has a close button which the
+ user has clicked. In the case of a QMainWindow a dock window can
+ have its visibility changed (hidden or shown) by clicking its name
+ in the dock window menu that lists the QMainWindow's dock windows.
+*/
+
+/*!
+ \fn QDockArea *QDockWindow::area() const
+
+ Returns the dock area in which this dock window is docked, or 0 if
+ the dock window is floating.
+*/
+
+// DOC: Can't use \property 'cos it thinks the thing returns a bool.
+/*!
+ \fn Place QDockWindow::place() const
+
+ This function returns where the dock window is placed. This is
+ either \c InDock or \c OutsideDock.
+
+ \sa QDockArea::moveDockWindow(), QDockArea::removeDockWindow(),
+ QMainWindow::moveDockWindow(), QMainWindow::removeDockWindow()
+*/
+
+
+/*!
+ Constructs a QDockWindow with parent \a parent, called \a name and
+ with widget flags \a f.
+*/
+
+QDockWindow::QDockWindow( QWidget* parent, const char* name, WFlags f )
+ : QFrame( parent, name, f | WType_Dialog | WStyle_Customize | WStyle_NoBorder )
+{
+ curPlace = InDock;
+ isToolbar = FALSE;
+ init();
+}
+
+/*!
+ Constructs a QDockWindow with parent \a parent, called \a name and
+ with widget flags \a f.
+
+ If \a p is \c InDock, the dock window is docked into a dock area
+ and \a parent \e must be a QDockArea or a QMainWindow. If the \a
+ parent is a QMainWindow the dock window will be docked in the main
+ window's \c Top dock area.
+
+ If \a p is \c OutsideDock, the dock window is created as a floating
+ window.
+
+ We recommend creating the dock area \c InDock with a QMainWindow
+ as parent then calling QMainWindow::moveDockWindow() to move the
+ dock window where you want it.
+*/
+
+QDockWindow::QDockWindow( Place p, QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f | WType_Dialog | WStyle_Customize | WStyle_NoBorder )
+{
+ curPlace = p;
+ isToolbar = FALSE;
+ init();
+}
+
+/*! \internal
+*/
+
+QDockWindow::QDockWindow( Place p, QWidget *parent, const char *name, WFlags f, bool toolbar )
+ : QFrame( parent, name, f | WType_Dialog | WStyle_Customize | WStyle_NoBorder )
+{
+ curPlace = p;
+ isToolbar = toolbar;
+ init();
+}
+
+class QDockWindowGridLayout : public QGridLayout
+{
+public:
+ QDockWindowGridLayout( QWidget *parent, int nRows, int nCols )
+ : QGridLayout( parent, nRows, nCols ) {};
+
+ QSizePolicy::ExpandData expanding() const
+ {
+ return QSizePolicy::NoDirection;
+ }
+};
+
+void QDockWindow::init()
+{
+ wid = 0;
+ unclippedPainter = 0;
+ dockArea = 0;
+ tmpDockArea = 0;
+ resizeEnabled = FALSE;
+ moveEnabled = TRUE;
+ nl = FALSE;
+ opaque = default_opaque;
+ cMode = Never;
+ offs = 0;
+ fExtent = QSize( -1, -1 );
+ dockWindowData = 0;
+ lastPos = QPoint( -1, -1 );
+ lastSize = QSize( -1, -1 );
+
+ widgetResizeHandler = new QWidgetResizeHandler( this );
+ widgetResizeHandler->setMovingEnabled( FALSE );
+
+ titleBar = new QDockWindowTitleBar( this );
+ verHandle = new QDockWindowHandle( this );
+ horHandle = new QDockWindowHandle( this );
+
+ vHandleLeft = new QDockWindowResizeHandle( Qt::Vertical, this, this, "vert. handle" );
+ vHandleRight = new QDockWindowResizeHandle( Qt::Vertical, this, this, "vert. handle" );
+ hHandleTop = new QDockWindowResizeHandle( Qt::Horizontal, this, this, "horz. handle" );
+ hHandleBottom = new QDockWindowResizeHandle( Qt::Horizontal, this, this, "horz. handle" );
+
+ // Creating inner layout
+ hbox = new QVBoxLayout();
+ vbox = new QHBoxLayout();
+ childBox = new QBoxLayout(QBoxLayout::LeftToRight);
+ vbox->addWidget( verHandle );
+ vbox->addLayout( childBox );
+
+ hbox->setResizeMode( QLayout::FreeResize );
+ hbox->setMargin( isResizeEnabled() || curPlace == OutsideDock ? 2 : 0 );
+ hbox->setSpacing( 1 );
+ hbox->addWidget( titleBar );
+ hbox->addWidget( horHandle );
+ hbox->addLayout( vbox );
+
+ // Set up the initial handle layout for Vertical
+ // Handle layout will change on calls to setOrienation()
+ QGridLayout *glayout = new QDockWindowGridLayout( this, 3, 3 );
+ glayout->setResizeMode( QLayout::Minimum );
+ glayout->addMultiCellWidget( hHandleTop, 0, 0, 1, 1 );
+ glayout->addMultiCellWidget( hHandleBottom, 2, 2, 1, 1 );
+ glayout->addMultiCellWidget( vHandleLeft, 0, 2, 0, 0 );
+ glayout->addMultiCellWidget( vHandleRight, 0, 2, 2, 2 );
+ glayout->addLayout( hbox, 1, 1 );
+ glayout->setRowStretch( 1, 1 );
+ glayout->setColStretch( 1, 1 );
+
+ hHandleBottom->hide();
+ vHandleRight->hide();
+ hHandleTop->hide();
+ vHandleLeft->hide();
+ setFrameStyle( QFrame::StyledPanel | QFrame::Raised );
+ setLineWidth( 2 );
+
+ if ( parentWidget() )
+ parentWidget()->installEventFilter( this );
+ QWidget *mw = parentWidget();
+ QDockArea *da = ::qt_cast<QDockArea*>(parentWidget());
+ if ( da ) {
+ if ( curPlace == InDock )
+ da->moveDockWindow( this );
+ mw = da->parentWidget();
+ }
+ if ( ::qt_cast<QMainWindow*>(mw) ) {
+ if ( place() == InDock ) {
+ Dock myDock = Qt::DockTop;
+ // make sure we put the window in the correct dock.
+ if ( dockArea ) {
+ QMainWindow *mainw = (QMainWindow*)mw;
+ // I'm not checking if it matches the top because I've
+ // done the assignment to it above.
+ if ( dockArea == mainw->leftDock() )
+ myDock = Qt::DockLeft;
+ else if ( dockArea == mainw->rightDock() )
+ myDock = Qt::DockRight;
+ else if ( dockArea == mainw->bottomDock() )
+ myDock = Qt::DockBottom;
+ }
+ ( (QMainWindow*)mw )->addDockWindow( this, myDock );
+ }
+ moveEnabled = ((QMainWindow*)mw)->dockWindowsMovable();
+ opaque = ((QMainWindow*)mw)->opaqueMoving();
+ }
+
+ updateGui();
+ stretchable[ Horizontal ] = FALSE;
+ stretchable[ Vertical ] = FALSE;
+
+ connect( titleBar, SIGNAL( doubleClicked() ), this, SLOT( dock() ) );
+ connect( verHandle, SIGNAL( doubleClicked() ), this, SLOT( undock() ) );
+ connect( horHandle, SIGNAL( doubleClicked() ), this, SLOT( undock() ) );
+ connect( this, SIGNAL( orientationChanged(Orientation) ),
+ this, SLOT( setOrientation(Orientation) ) );
+}
+
+/*!
+ Sets the orientation of the dock window to \a o. The orientation
+ is propagated to the layout boxLayout().
+
+ \warning All undocked QToolBars will always have a horizontal orientation.
+*/
+
+void QDockWindow::setOrientation( Orientation o )
+{
+ QGridLayout *glayout = (QGridLayout*)layout();
+ glayout->remove( hHandleTop );
+ glayout->remove( hHandleBottom );
+ glayout->remove( vHandleLeft );
+ glayout->remove( vHandleRight );
+
+ if ( o == Horizontal ) {
+ // Set up the new layout as
+ // 3 3 3 1 = vHandleLeft 4 = hHandleBottom
+ // 1 X 2 2 = vHandleRight X = Inner Layout
+ // 4 4 4 3 = hHandleTop
+ glayout->addMultiCellWidget( hHandleTop, 0, 0, 0, 2 );
+ glayout->addMultiCellWidget( hHandleBottom, 2, 2, 0, 2 );
+ glayout->addMultiCellWidget( vHandleLeft, 1, 1, 0, 0 );
+ glayout->addMultiCellWidget( vHandleRight, 1, 1, 2, 2 );
+ } else {
+ // Set up the new layout as
+ // 1 3 2 1 = vHandleLeft 4 = hHandleBottom
+ // 1 X 2 2 = vHandleRight X = Inner Layout
+ // 1 4 2 3 = hHandleTop
+ glayout->addMultiCellWidget( hHandleTop, 0, 0, 1, 1 );
+ glayout->addMultiCellWidget( hHandleBottom, 2, 2, 1, 1 );
+ glayout->addMultiCellWidget( vHandleLeft, 0, 2, 0, 0 );
+ glayout->addMultiCellWidget( vHandleRight, 0, 2, 2, 2 );
+ }
+ boxLayout()->setDirection( o == Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom );
+ QApplication::sendPostedEvents( this, QEvent::LayoutHint );
+ QEvent *e = new QEvent( QEvent::LayoutHint );
+ QApplication::postEvent( this, e );
+}
+
+/*!
+ \reimp
+
+ Destroys the dock window and its child widgets.
+*/
+
+QDockWindow::~QDockWindow()
+{
+ qApp->removeEventFilter( this );
+ if ( area() )
+ area()->removeDockWindow( this, FALSE, FALSE );
+ QDockArea *a = area();
+ if ( !a && dockWindowData )
+ a = ( (QDockArea::DockWindowData*)dockWindowData )->area;
+ QMainWindow *mw = a ? ::qt_cast<QMainWindow*>(a->parentWidget()) : 0;
+ if ( mw )
+ mw->removeDockWindow( this );
+
+ delete (QDockArea::DockWindowData*)dockWindowData;
+}
+
+/*! \reimp
+*/
+
+void QDockWindow::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+ updateGui();
+}
+
+
+void QDockWindow::swapRect( QRect &r, Qt::Orientation o, const QPoint &offset, QDockArea * )
+{
+ QBoxLayout *bl = boxLayout()->createTmpCopy();
+ bl->setDirection( o == Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom );
+ bl->activate();
+ r.setSize( bl->sizeHint() );
+ bl->data = 0;
+ delete bl;
+ bool reverse = QApplication::reverseLayout();
+ if ( o == Qt::Horizontal )
+ r.moveBy( -r.width()/2, 0 );
+ else
+ r.moveBy( reverse ? - r.width() : 0, -r.height() / 2 );
+ r.moveBy( offset.x(), offset.y() );
+}
+
+QWidget *QDockWindow::areaAt( const QPoint &gp )
+{
+ QWidget *w = qApp->widgetAt( gp, TRUE );
+
+ if ( w && ( w == this || w == titleBar ) && parentWidget() )
+ w = parentWidget()->childAt( parentWidget()->mapFromGlobal( gp ) );
+
+ while ( w ) {
+ if ( ::qt_cast<QDockArea*>(w) ) {
+ QDockArea *a = (QDockArea*)w;
+ if ( a->isDockWindowAccepted( this ) )
+ return w;
+ }
+ if ( ::qt_cast<QMainWindow*>(w) ) {
+ QMainWindow *mw = (QMainWindow*)w;
+ QDockArea *a = mw->dockingArea( mw->mapFromGlobal( gp ) );
+ if ( a && a->isDockWindowAccepted( this ) )
+ return a;
+ }
+ w = w->parentWidget( TRUE );
+ }
+ return 0;
+}
+
+void QDockWindow::handleMove( const QPoint &pos, const QPoint &gp, bool drawRect )
+{
+ if ( !unclippedPainter )
+ return;
+
+ if ( drawRect ) {
+ QRect dr(currRect);
+#ifdef MAC_DRAG_HACK
+ dr.moveBy(-topLevelWidget()->geometry().x(), -topLevelWidget()->geometry().y());
+#endif
+ unclippedPainter->drawRect( dr );
+ }
+ currRect = QRect( realWidgetPos( this ), size() );
+ QWidget *w = areaAt( gp );
+ if ( titleBar->ctrlDown || horHandle->ctrlDown || verHandle->ctrlDown )
+ w = 0;
+ currRect.moveBy( pos.x(), pos.y() );
+ if ( !::qt_cast<QDockArea*>(w) ) {
+ if ( startOrientation != Horizontal && ::qt_cast<QToolBar*>(this) )
+ swapRect( currRect, Horizontal, startOffset, (QDockArea*)w );
+ if ( drawRect ) {
+ unclippedPainter->setPen( QPen( gray, 3 ) );
+ QRect dr(currRect);
+#ifdef MAC_DRAG_HACK
+ dr.moveBy(-topLevelWidget()->geometry().x(), -topLevelWidget()->geometry().y());
+#endif
+ unclippedPainter->drawRect( dr );
+ } else {
+ QPoint mp( mapToGlobal( pos ));
+ if(place() == InDock) {
+ undock();
+ if(titleBar) {
+ mp = QPoint(titleBar->width() / 2, titleBar->height() / 2);
+ QMouseEvent me(QEvent::MouseButtonPress, mp, LeftButton, 0);
+ QApplication::sendEvent(titleBar, &me);
+ mp = titleBar->mapToGlobal( mp );
+ }
+ }
+ move( mp );
+ }
+ state = OutsideDock;
+ return;
+ }
+
+ QDockArea *area = (QDockArea*)w;
+ if( area->isVisible() ) {
+ state = InDock;
+ Orientation o = ( area ? area->orientation() :
+ ( boxLayout()->direction() == QBoxLayout::LeftToRight ||
+ boxLayout()->direction() == QBoxLayout::RightToLeft ?
+ Horizontal : Vertical ) );
+ if ( startOrientation != o )
+ swapRect( currRect, o, startOffset, area );
+ if ( drawRect ) {
+ unclippedPainter->setPen( QPen( gray, 1 ) );
+ QRect dr(currRect);
+#ifdef MAC_DRAG_HACK
+ dr.moveBy(-topLevelWidget()->geometry().x(), -topLevelWidget()->geometry().y());
+#endif
+ unclippedPainter->drawRect( dr );
+ }
+ tmpDockArea = area;
+ }
+}
+
+void QDockWindow::updateGui()
+{
+ if ( curPlace == OutsideDock ) {
+ hbox->setMargin( 2 );
+ horHandle->hide();
+ verHandle->hide();
+ if ( moveEnabled )
+ titleBar->show();
+ else
+ titleBar->hide();
+ titleBar->updateGui();
+ hHandleTop->hide();
+ vHandleLeft->hide();
+ hHandleBottom->hide();
+ vHandleRight->hide();
+ setLineWidth( 2 );
+ widgetResizeHandler->setActive( isResizeEnabled() );
+ } else {
+ hbox->setMargin( isResizeEnabled() ? 0 : 2 );
+ titleBar->hide();
+ if ( orientation() == Horizontal ) {
+ horHandle->hide();
+ if ( moveEnabled )
+ verHandle->show();
+ else
+ verHandle->hide();
+#ifdef Q_WS_MAC
+ if(horHandle->mousePressed) {
+ horHandle->mousePressed = FALSE;
+ verHandle->mousePressed = TRUE;
+ verHandle->grabMouse();
+ }
+#endif
+ verHandle->updateGui();
+ } else {
+ if ( moveEnabled )
+ horHandle->show();
+ else
+ horHandle->hide();
+ horHandle->updateGui();
+#ifdef Q_WS_MAC
+ if(verHandle->mousePressed) {
+ verHandle->mousePressed = FALSE;
+ horHandle->mousePressed = TRUE;
+ horHandle->grabMouse();
+ }
+#endif
+ verHandle->hide();
+ }
+ if ( isResizeEnabled() ) {
+ if ( orientation() == Horizontal ) {
+ hHandleBottom->raise();
+ hHandleTop->raise();
+ } else {
+ vHandleRight->raise();
+ vHandleLeft->raise();
+ }
+
+ if ( area() ) {
+ if ( orientation() == Horizontal ) {
+ if ( area()->handlePosition() == QDockArea::Normal ) {
+ hHandleBottom->show();
+ hHandleTop->hide();
+ } else {
+ hHandleTop->show();
+ hHandleBottom->hide();
+ }
+ if ( !area()->isLastDockWindow( this ) )
+ vHandleRight->show();
+ else
+ vHandleRight->hide();
+ vHandleLeft->hide();
+ } else {
+ if ( (area()->handlePosition() == QDockArea::Normal) != QApplication::reverseLayout() ) {
+ vHandleRight->show();
+ vHandleLeft->hide();
+ } else {
+ vHandleLeft->show();
+ vHandleRight->hide();
+ }
+ if ( !area()->isLastDockWindow( this ) )
+ hHandleBottom->show();
+ else
+ hHandleBottom->hide();
+ hHandleTop->hide();
+ }
+ }
+ } else if ( area() ) { // hide resize handles if resizing is disabled
+ if ( orientation() == Horizontal ) {
+ hHandleTop->hide();
+ hHandleBottom->hide();
+ } else {
+ vHandleLeft->hide();
+ vHandleRight->hide();
+ }
+ }
+#ifndef Q_OS_TEMP
+ if ( moveEnabled )
+ setLineWidth( 1 );
+ else
+ setLineWidth( 0 );
+ hbox->setMargin( lineWidth() );
+#else
+ hbox->setMargin( 2 );
+#endif
+ widgetResizeHandler->setActive( FALSE );
+ }
+}
+
+void QDockWindow::updatePosition( const QPoint &globalPos )
+{
+ if ( curPlace == OutsideDock && state == InDock )
+ lastSize = size();
+
+ bool doAdjustSize = curPlace != state && state == OutsideDock;
+ bool doUpdate = TRUE;
+ bool doOrientationChange = TRUE;
+ if ( state != curPlace && state == InDock ) {
+ doUpdate = FALSE;
+ curPlace = state;
+ updateGui();
+ QApplication::sendPostedEvents();
+ }
+ Orientation oo = orientation();
+
+ if ( state == InDock ) {
+ if ( tmpDockArea ) {
+ bool differentDocks = FALSE;
+ if ( dockArea && dockArea != tmpDockArea ) {
+ differentDocks = TRUE;
+ delete (QDockArea::DockWindowData*)dockWindowData;
+ dockWindowData = dockArea->dockWindowData( this );
+ dockArea->removeDockWindow( this, FALSE, FALSE );
+ }
+ dockArea = tmpDockArea;
+ if ( differentDocks ) {
+ if ( doUpdate ) {
+ doUpdate = FALSE;
+ curPlace = state;
+ updateGui();
+ }
+ emit orientationChanged( tmpDockArea->orientation() );
+ doOrientationChange = FALSE;
+ } else {
+ updateGui();
+ }
+ dockArea->moveDockWindow( this, globalPos, currRect, startOrientation != oo );
+ }
+ } else {
+ if ( dockArea ) {
+ QMainWindow *mw = (QMainWindow*)dockArea->parentWidget();
+ if ( ::qt_cast<QMainWindow*>(mw) &&
+ ( !mw->isDockEnabled( QMainWindow::DockTornOff ) ||
+ !mw->isDockEnabled( this, QMainWindow::DockTornOff ) ) )
+ return;
+ delete (QDockArea::DockWindowData*)dockWindowData;
+ dockWindowData = dockArea->dockWindowData( this );
+ dockArea->removeDockWindow( this, TRUE,
+ startOrientation != Horizontal && ::qt_cast<QToolBar*>(this) );
+ }
+ dockArea = 0;
+ QPoint topLeft = currRect.topLeft();
+ QRect screen = qApp->desktop()->availableGeometry( topLeft );
+ if ( !screen.contains( topLeft ) ) {
+ topLeft.setY(QMAX(topLeft.y(), screen.top()));
+ topLeft.setY(QMIN(topLeft.y(), screen.bottom()-height()));
+ topLeft.setX(QMAX(topLeft.x(), screen.left()));
+ topLeft.setX(QMIN(topLeft.x(), screen.right()-width()));
+ }
+ move( topLeft );
+ }
+
+ if ( curPlace == InDock && state == OutsideDock && !::qt_cast<QToolBar*>(this) ) {
+ if ( lastSize != QSize( -1, -1 ) )
+ resize( lastSize );
+ }
+
+ if ( doUpdate ) {
+ curPlace = state;
+ updateGui();
+ }
+ if ( doOrientationChange )
+ emit orientationChanged( orientation() );
+ tmpDockArea = 0;
+ if ( doAdjustSize ) {
+ QApplication::sendPostedEvents( this, QEvent::LayoutHint );
+ if ( ::qt_cast<QToolBar*>(this) )
+ adjustSize();
+ if (lastSize == QSize(-1, -1))
+ clearWState(WState_Resized); // Ensures size is recalculated (non-opaque).
+ show();
+ if ( parentWidget() && isTopLevel() )
+ parentWidget()->setActiveWindow();
+
+ }
+
+ emit placeChanged( curPlace );
+}
+
+/*!
+ Sets the dock window's main widget to \a w.
+
+ \sa boxLayout()
+*/
+
+void QDockWindow::setWidget( QWidget *w )
+{
+ wid = w;
+ boxLayout()->addWidget( w );
+ updateGui();
+}
+
+/*!
+ Returns the dock window's main widget.
+
+ \sa setWidget()
+*/
+
+QWidget *QDockWindow::widget() const
+{
+ return wid;
+}
+
+void QDockWindow::startRectDraw( const QPoint &so, bool drawRect )
+{
+ state = place();
+ if ( unclippedPainter )
+ endRectDraw( !opaque );
+#ifdef MAC_DRAG_HACK
+ QWidget *paint_on = topLevelWidget();
+#else
+ int scr = QApplication::desktop()->screenNumber( this );
+ QWidget *paint_on = QApplication::desktop()->screen( scr );
+#endif
+ unclippedPainter = new QPainter( paint_on, TRUE );
+ unclippedPainter->setPen( QPen( gray, curPlace == OutsideDock ? 3 : 1 ) );
+ unclippedPainter->setRasterOp( XorROP );
+ currRect = QRect( realWidgetPos( this ), size() );
+ if ( drawRect ) {
+ QRect dr(currRect);
+#ifdef MAC_DRAG_HACK
+ dr.moveBy(-topLevelWidget()->geometry().x(), -topLevelWidget()->geometry().y());
+#endif
+ unclippedPainter->drawRect( dr );
+ }
+ startOrientation = orientation();
+ startOffset = mapFromGlobal( so );
+}
+
+void QDockWindow::endRectDraw( bool drawRect )
+{
+ if ( !unclippedPainter )
+ return;
+ if ( drawRect ) {
+ QRect dr(currRect);
+#ifdef MAC_DRAG_HACK
+ dr.moveBy(-topLevelWidget()->geometry().x(), -topLevelWidget()->geometry().y());
+#endif
+ unclippedPainter->drawRect( dr );
+ }
+ delete unclippedPainter;
+ unclippedPainter = 0;
+}
+
+/*!
+ \reimp
+*/
+void QDockWindow::drawFrame( QPainter *p )
+{
+ if ( place() == InDock ) {
+ QFrame::drawFrame( p );
+ return;
+ }
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ QStyleOption opt(lineWidth(),midLineWidth());
+
+ if ( titleBar->isActive() )
+ flags |= QStyle::Style_Active;
+
+ style().drawPrimitive( QStyle::PE_WindowFrame, p, rect(), colorGroup(), flags, opt );
+}
+
+/*!
+ \reimp
+*/
+void QDockWindow::drawContents( QPainter *p )
+{
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( titleBar->isActive() )
+ flags |= QStyle::Style_Active;
+ style().drawControl( QStyle::CE_DockWindowEmptyArea, p, this,
+ rect(), colorGroup(), flags );
+}
+
+/*!
+ \property QDockWindow::resizeEnabled
+ \brief whether the dock window is resizeable
+
+ A resizeable dock window can be resized using splitter-like
+ handles inside a dock area and like every other top level window
+ when floating.
+
+ A dock window is both horizontally and vertically stretchable if
+ you call setResizeEnabled(TRUE).
+
+ This property is FALSE by default.
+
+ \sa setVerticallyStretchable() setHorizontallyStretchable()
+*/
+
+void QDockWindow::setResizeEnabled( bool b )
+{
+ resizeEnabled = b;
+ hbox->setMargin( b ? 0 : 2 );
+ updateGui();
+}
+
+/*!
+ \property QDockWindow::movingEnabled
+ \brief whether the user can move the dock window within the dock
+ area, move the dock window to another dock area, or float the dock
+ window.
+
+ This property is TRUE by default.
+*/
+
+void QDockWindow::setMovingEnabled( bool b )
+{
+ moveEnabled = b;
+ updateGui();
+}
+
+bool QDockWindow::isResizeEnabled() const
+{
+ return resizeEnabled;
+}
+
+bool QDockWindow::isMovingEnabled() const
+{
+ return moveEnabled;
+}
+
+/*!
+ \property QDockWindow::closeMode
+ \brief the close mode of a dock window
+
+ Defines when (if ever) the dock window has a close button. The
+ choices are \c Never, \c Docked (i.e. only when docked), \c
+ Undocked (only when undocked, i.e. floated) or \c Always.
+
+ The default is \c Never.
+*/
+
+void QDockWindow::setCloseMode( int m )
+{
+ cMode = m;
+ if ( place() == InDock ) {
+ horHandle->updateGui();
+ verHandle->updateGui();
+ } else {
+ titleBar->updateGui();
+ }
+}
+
+/*!
+ Returns TRUE if the dock window has a close button; otherwise
+ returns FALSE. The result depends on the dock window's \l Place
+ and its \l CloseMode.
+
+ \sa setCloseMode()
+*/
+
+bool QDockWindow::isCloseEnabled() const
+{
+ return ( ( cMode & Docked ) == Docked && place() == InDock ||
+ ( cMode & Undocked ) == Undocked && place() == OutsideDock );
+}
+
+int QDockWindow::closeMode() const
+{
+ return cMode;
+}
+
+/*!
+ \property QDockWindow::horizontallyStretchable
+ \brief whether the dock window is horizontally stretchable.
+
+ A dock window is horizontally stretchable if you call
+ setHorizontallyStretchable(TRUE) or setResizeEnabled(TRUE).
+
+ \sa setResizeEnabled()
+
+ \bug Strecthability is broken. You must call setResizeEnabled(TRUE) to get
+ proper behavior and even then QDockWindow does not limit stretchablilty.
+*/
+
+void QDockWindow::setHorizontallyStretchable( bool b )
+{
+ stretchable[ Horizontal ] = b;
+}
+
+/*!
+ \property QDockWindow::verticallyStretchable
+ \brief whether the dock window is vertically stretchable.
+
+ A dock window is vertically stretchable if you call
+ setVerticallyStretchable(TRUE) or setResizeEnabled(TRUE).
+
+ \sa setResizeEnabled()
+
+ \bug Strecthability is broken. You must call setResizeEnabled(TRUE) to get
+ proper behavior and even then QDockWindow does not limit stretchablilty.
+*/
+
+void QDockWindow::setVerticallyStretchable( bool b )
+{
+ stretchable[ Vertical ] = b;
+}
+
+bool QDockWindow::isHorizontallyStretchable() const
+{
+ return isResizeEnabled() || stretchable[ Horizontal ];
+}
+
+bool QDockWindow::isVerticallyStretchable() const
+{
+ return isResizeEnabled() || stretchable[ Vertical ];
+}
+
+/*!
+ \property QDockWindow::stretchable
+ \brief whether the dock window is stretchable in the current
+ orientation()
+
+ This property can be set using setHorizontallyStretchable() and
+ setVerticallyStretchable(), or with setResizeEnabled().
+
+ \sa setResizeEnabled()
+
+ \bug Strecthability is broken. You must call setResizeEnabled(TRUE) to get
+ proper behavior and even then QDockWindow does not limit stretchablilty.
+*/
+
+bool QDockWindow::isStretchable() const
+{
+ if ( orientation() == Horizontal )
+ return isHorizontallyStretchable();
+ return isVerticallyStretchable();
+}
+
+/*!
+ Returns the orientation of the dock window.
+
+ \sa orientationChanged()
+*/
+
+Qt::Orientation QDockWindow::orientation() const
+{
+ if ( dockArea )
+ return dockArea->orientation();
+ if ( ::qt_cast<QToolBar*>(this) )
+ return Horizontal;
+ return ( ((QDockWindow*)this)->boxLayout()->direction() == QBoxLayout::LeftToRight ||
+ ((QDockWindow*)this)->boxLayout()->direction() == QBoxLayout::RightToLeft ?
+ Horizontal : Vertical );
+}
+
+int QDockWindow::offset() const
+{
+ return offs;
+}
+
+/*!
+ \property QDockWindow::offset
+ \brief the dock window's preferred offset from the dock area's
+ left edge (top edge for vertical dock areas)
+
+ The default is 0.
+*/
+
+void QDockWindow::setOffset( int o )
+{
+ offs = o;
+}
+
+/*!
+ Returns the dock window's preferred size (fixed extent).
+
+ \sa setFixedExtentWidth() setFixedExtentHeight()
+*/
+
+QSize QDockWindow::fixedExtent() const
+{
+ return fExtent;
+}
+
+/*!
+ Sets the dock window's preferred width for its fixed extent (size)
+ to \a w.
+
+ \sa setFixedExtentHeight()
+*/
+
+void QDockWindow::setFixedExtentWidth( int w )
+{
+ fExtent.setWidth( w );
+}
+
+/*!
+ Sets the dock window's preferred height for its fixed extent
+ (size) to \a h.
+
+ \sa setFixedExtentWidth()
+*/
+
+void QDockWindow::setFixedExtentHeight( int h )
+{
+ fExtent.setHeight( h );
+}
+
+/*!
+ \property QDockWindow::newLine
+ \brief whether the dock window prefers to start a new line in the
+ dock area.
+
+ The default is FALSE, i.e. the dock window doesn't require a new
+ line in the dock area.
+*/
+
+void QDockWindow::setNewLine( bool b )
+{
+ nl = b;
+}
+
+bool QDockWindow::newLine() const
+{
+ return nl;
+}
+
+/*!
+ Returns the layout which is used for adding widgets to the dock
+ window. The layout's orientation is set automatically to match the
+ orientation of the dock window. You can add widgets to the layout
+ using the box layout's QBoxLayout::addWidget() function.
+
+ If the dock window only needs to contain a single widget use
+ setWidget() instead.
+
+ \sa setWidget() setOrientation()
+*/
+
+QBoxLayout *QDockWindow::boxLayout()
+{
+ return childBox;
+}
+
+/*! \reimp
+ */
+
+QSize QDockWindow::sizeHint() const
+{
+ QSize sh( QFrame::sizeHint() );
+ if ( place() == InDock )
+ sh = sh.expandedTo( fixedExtent() );
+ sh = sh.expandedTo( QSize( 16, 16 ) );
+ if ( area() ) {
+ if ( area()->orientation() == Horizontal && !vHandleRight->isVisible() )
+ sh.setWidth( sh.width() + 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3 );
+ else if ( area()->orientation() == Vertical && !hHandleBottom->isVisible() )
+ sh.setHeight( sh.height() + 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3 );
+ }
+ return sh;
+}
+
+/*! \reimp
+ */
+
+QSize QDockWindow::minimumSize() const
+{
+ QSize ms( QFrame::minimumSize() );
+ if ( place() == InDock )
+ ms = ms.expandedTo( fixedExtent() );
+ ms = ms.expandedTo( QSize( 16, 16 ) );
+ if ( area() ) {
+ if ( area()->orientation() == Horizontal && !vHandleRight->isVisible() )
+ ms.setWidth( ms.width() + 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3 );
+ else if ( area()->orientation() == Vertical && !hHandleBottom->isVisible() )
+ ms.setHeight( ms.height() + 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3 );
+ }
+ return ms;
+}
+
+/*! \reimp
+ */
+
+QSize QDockWindow::minimumSizeHint() const
+{
+ QSize msh( QFrame::minimumSize() );
+ if ( place() == InDock )
+ msh = msh.expandedTo( fixedExtent() );
+ msh = msh.expandedTo( QSize( 16, 16 ) );
+ if ( area() ) {
+ if ( area()->orientation() == Horizontal && !vHandleRight->isVisible() )
+ msh.setWidth( msh.width() + 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3 );
+ else if ( area()->orientation() == Vertical && !hHandleBottom->isVisible() )
+ msh.setHeight( msh.height() + 2 * style().pixelMetric(QStyle::PM_SplitterWidth, this) / 3 );
+ }
+ return msh;
+}
+
+/*! \internal */
+void QDockWindow::undock( QWidget *w )
+{
+ QMainWindow *mw = 0;
+ if ( area() )
+ mw = ::qt_cast<QMainWindow*>(area()->parentWidget());
+ if ( mw && !mw->isDockEnabled( this, DockTornOff ) )
+ return;
+ if ( (place() == OutsideDock && !w) )
+ return;
+
+ QPoint p( 50, 50 );
+ if ( topLevelWidget() )
+ p = topLevelWidget()->pos() + QPoint( 20, 20 );
+ if ( dockArea ) {
+ delete (QDockArea::DockWindowData*)dockWindowData;
+ dockWindowData = dockArea->dockWindowData( this );
+ dockArea->removeDockWindow( this, TRUE, orientation() != Horizontal && ::qt_cast<QToolBar*>(this) );
+ }
+ dockArea = 0;
+ if ( lastPos != QPoint( -1, -1 ) && lastPos.x() > 0 && lastPos.y() > 0 )
+ move( lastPos );
+ else
+ move( p );
+ if ( lastSize != QSize( -1, -1 ) )
+ resize( lastSize );
+ curPlace = OutsideDock;
+ updateGui();
+ emit orientationChanged( orientation() );
+ QApplication::sendPostedEvents( this, QEvent::LayoutHint );
+ if ( ::qt_cast<QToolBar*>(this) )
+ adjustSize();
+ if ( !w ) {
+ if ( !parentWidget() || parentWidget()->isVisible() ) {
+ if (lastSize == QSize(-1, -1))
+ clearWState(WState_Resized); // Ensures size is recalculated (opaque).
+ show();
+ }
+ } else {
+ reparent( w, 0, QPoint( 0, 0 ), FALSE );
+ move( -width() - 5, -height() - 5 );
+ resize( 1, 1 );
+ show();
+ }
+ if ( parentWidget() && isTopLevel() )
+ parentWidget()->setActiveWindow();
+ emit placeChanged( place() );
+}
+
+/*!
+ \fn void QDockWindow::undock()
+
+ Undocks the QDockWindow from its current dock area if it is
+ docked; otherwise does nothing.
+
+ \sa dock() QDockArea::moveDockWindow(),
+ QDockArea::removeDockWindow(), QMainWindow::moveDockWindow(),
+ QMainWindow::removeDockWindow()
+*/
+
+void QDockWindow::removeFromDock( bool fixNewLines )
+{
+ if ( dockArea )
+ dockArea->removeDockWindow( this, FALSE, FALSE, fixNewLines );
+}
+
+/*!
+ Docks the dock window into the last dock area in which it was
+ docked.
+
+ If the dock window has no last dock area (e.g. it was created as a
+ floating window and has never been docked), or if the last dock
+ area it was docked in does not exist (e.g. the dock area has been
+ deleted), nothing happens.
+
+ The dock window will dock with the dock area regardless of the return value
+ of QDockArea::isDockWindowAccepted().
+
+ \sa undock() QDockArea::moveDockWindow(),
+ QDockArea::removeDockWindow(), QMainWindow::moveDockWindow(),
+ QMainWindow::removeDockWindow(), QDockArea::isDockWindowAccepted()
+
+*/
+
+void QDockWindow::dock()
+{
+ if ( !(QDockArea::DockWindowData*)dockWindowData ||
+ !( (QDockArea::DockWindowData*)dockWindowData )->area )
+ return;
+ curPlace = InDock;
+ lastPos = pos();
+ lastSize = size();
+ ( (QDockArea::DockWindowData*)dockWindowData )->
+ area->dockWindow( this, (QDockArea::DockWindowData*)dockWindowData );
+ emit orientationChanged( orientation() );
+ emit placeChanged( place() );
+}
+
+/*! \reimp
+ */
+
+void QDockWindow::hideEvent( QHideEvent *e )
+{
+ QFrame::hideEvent( e );
+}
+
+/*! \reimp
+ */
+
+void QDockWindow::showEvent( QShowEvent *e )
+{
+ if (curPlace == OutsideDock && (parent() && strcmp(parent()->name(), "qt_hide_dock") != 0)) {
+ QRect sr = qApp->desktop()->availableGeometry( this );
+ if ( !sr.contains( pos() ) ) {
+ int nx = QMIN( QMAX( x(), sr.x() ), sr.right()-width() );
+ int ny = QMIN( QMAX( y(), sr.y() ), sr.bottom()-height() );
+ move( nx, ny );
+ }
+ }
+
+ QFrame::showEvent( e );
+}
+
+/*!
+ \property QDockWindow::opaqueMoving
+ \brief whether the dock window will be shown normally whilst it is
+ being moved.
+
+ If this property is FALSE, (the default), the dock window will be
+ represented by an outline rectangle whilst it is being moved.
+
+ \warning Currently opaque moving has some problems and we do not
+ recommend using it at this time. We expect to fix these problems
+ in a future release.
+*/
+
+void QDockWindow::setOpaqueMoving( bool b )
+{
+ opaque = b;
+ horHandle->setOpaqueMoving( b );
+ verHandle->setOpaqueMoving( b );
+ titleBar->setOpaqueMoving( b );
+}
+
+bool QDockWindow::opaqueMoving() const
+{
+ return opaque;
+}
+
+/*! \reimp */
+
+void QDockWindow::setCaption( const QString &s )
+{
+ titleBar->setCaption( s );
+ verHandle->update();
+ horHandle->update();
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ QFrame::setCaption( s );
+#endif
+#ifndef QT_NO_TOOLTIP
+ QToolTip::remove( horHandle );
+ QToolTip::remove( verHandle );
+ if ( !s.isEmpty() ) {
+ QToolTip::add( horHandle, s );
+ QToolTip::add( verHandle, s );
+ }
+#endif
+}
+
+void QDockWindow::updateSplitterVisibility( bool visible )
+{
+ if ( area() && isResizeEnabled() ) {
+ if ( orientation() == Horizontal ) {
+ if ( visible )
+ vHandleRight->show();
+ else
+ vHandleRight->hide();
+ vHandleLeft->hide();
+ } else {
+ if ( visible )
+ hHandleBottom->show();
+ else
+ hHandleBottom->hide();
+ hHandleTop->hide();
+ }
+ }
+}
+
+/*! \reimp */
+bool QDockWindow::eventFilter( QObject * o, QEvent *e )
+{
+ if ( !o->isWidgetType() )
+ return FALSE;
+
+ if ( e->type() == QEvent::KeyPress &&
+ ( horHandle->mousePressed ||
+ verHandle->mousePressed ||
+ titleBar->mousePressed ) ) {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if ( ke->key() == Key_Escape ) {
+ horHandle->mousePressed =
+ verHandle->mousePressed =
+ titleBar->mousePressed = FALSE;
+ endRectDraw( !opaque );
+ qApp->removeEventFilter( this );
+ return TRUE;
+ }
+ } else if ( ((QWidget*)o)->topLevelWidget() != this && place() == OutsideDock && isTopLevel() ) {
+ if ( (e->type() == QEvent::WindowDeactivate ||
+ e->type() == QEvent::WindowActivate ) )
+ event( e );
+ }
+ return FALSE;
+}
+
+/*! \reimp */
+bool QDockWindow::event( QEvent *e )
+{
+ switch ( e->type() ) {
+ case QEvent::WindowDeactivate:
+ if ( place() == OutsideDock && isTopLevel() && parentWidget()
+ && parentWidget()->isActiveWindow() )
+ return TRUE;
+ case QEvent::Hide:
+ if ( !isHidden() )
+ break;
+ // fall through
+ case QEvent::HideToParent:
+ emit visibilityChanged( FALSE );
+ break;
+ case QEvent::Show:
+ if ( e->spontaneous() )
+ break;
+ case QEvent::ShowToParent:
+ emit visibilityChanged( TRUE );
+ break;
+ default:
+ break;
+ }
+ return QFrame::event( e );
+}
+
+#ifdef QT_NO_WIDGET_TOPEXTRA
+QString QDockWindow::caption() const
+{
+ return titleBar->caption();
+}
+#endif
+
+/*! \reimp */
+void QDockWindow::contextMenuEvent( QContextMenuEvent *e )
+{
+ QObject *o = this;
+ while ( o ) {
+ if ( ::qt_cast<QMainWindow*>(o) )
+ break;
+ o = o->parent();
+ }
+ if ( !o || ! ( (QMainWindow*)o )->showDockMenu( e->globalPos() ) )
+ e->ignore();
+}
+
+#include "qdockwindow.moc"
+
+#endif //QT_NO_MAINWINDOW
diff --git a/src/widgets/qdockwindow.h b/src/widgets/qdockwindow.h
new file mode 100644
index 0000000..0e37f0b
--- /dev/null
+++ b/src/widgets/qdockwindow.h
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Definition of the QDockWindow class
+**
+** Created : 001010
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the workspace module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QDOCKWINDOW_H
+#define QDOCKWINDOW_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_MAINWINDOW
+
+class QDockWindowHandle;
+class QDockWindowTitleBar;
+class QPainter;
+class QDockWindowResizeHandle;
+class QBoxLayout;
+class QHBoxLayout;
+class QVBoxLayout;
+class QDockArea;
+class QWidgetResizeHandler;
+class QMainWindow;
+class QDockAreaLayout;
+class QDockWindowPrivate;
+class QToolBar;
+class QWindowsXPStyle;
+
+class Q_EXPORT QDockWindow : public QFrame
+{
+ Q_OBJECT
+ Q_ENUMS( CloseMode Place )
+ Q_PROPERTY( int closeMode READ closeMode WRITE setCloseMode ) //### this shouldn't be of type int?!
+ Q_PROPERTY( bool resizeEnabled READ isResizeEnabled WRITE setResizeEnabled )
+ Q_PROPERTY( bool movingEnabled READ isMovingEnabled WRITE setMovingEnabled )
+ Q_PROPERTY( bool horizontallyStretchable READ isHorizontallyStretchable WRITE setHorizontallyStretchable )
+ Q_PROPERTY( bool verticallyStretchable READ isVerticallyStretchable WRITE setVerticallyStretchable )
+ Q_PROPERTY( bool stretchable READ isStretchable )
+ Q_PROPERTY( bool newLine READ newLine WRITE setNewLine )
+ Q_PROPERTY( bool opaqueMoving READ opaqueMoving WRITE setOpaqueMoving )
+ Q_PROPERTY( int offset READ offset WRITE setOffset )
+ Q_PROPERTY( Place place READ place )
+
+ friend class QDockWindowHandle;
+ friend class QDockWindowTitleBar;
+ friend class QDockArea;
+ friend class QDockAreaLayout;
+ friend class QMainWindow;
+ friend class QCEMainWindow;
+ friend class QToolBar;
+ friend class QWindowsXPStyle;
+
+public:
+ enum Place { InDock, OutsideDock };
+ enum CloseMode { Never = 0, Docked = 1, Undocked = 2, Always = Docked | Undocked };
+
+ QDockWindow( Place p = InDock, QWidget* parent=0, const char* name=0, WFlags f = 0 );
+ QDockWindow( QWidget* parent, const char* name=0, WFlags f = 0 );
+ ~QDockWindow();
+
+ virtual void setWidget( QWidget *w );
+ QWidget *widget() const;
+
+ Place place() const { return curPlace; }
+
+ QDockArea *area() const;
+
+ virtual void setCloseMode( int m );
+ bool isCloseEnabled() const;
+ int closeMode() const;
+
+ virtual void setResizeEnabled( bool b );
+ virtual void setMovingEnabled( bool b );
+ bool isResizeEnabled() const;
+ bool isMovingEnabled() const;
+
+ virtual void setHorizontallyStretchable( bool b );
+ virtual void setVerticallyStretchable( bool b );
+ bool isHorizontallyStretchable() const;
+ bool isVerticallyStretchable() const;
+ void setHorizontalStretchable( bool b ) { setHorizontallyStretchable( b ); }
+ void setVerticalStretchable( bool b ) { setVerticallyStretchable( b ); }
+ bool isHorizontalStretchable() const { return isHorizontallyStretchable(); }
+ bool isVerticalStretchable() const { return isVerticallyStretchable(); }
+ bool isStretchable() const;
+
+ virtual void setOffset( int o );
+ int offset() const;
+
+ virtual void setFixedExtentWidth( int w );
+ virtual void setFixedExtentHeight( int h );
+ QSize fixedExtent() const;
+
+ virtual void setNewLine( bool b );
+ bool newLine() const;
+
+ Qt::Orientation orientation() const;
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ QSize minimumSizeHint() const;
+
+ QBoxLayout *boxLayout();
+
+ virtual void setOpaqueMoving( bool b );
+ bool opaqueMoving() const;
+
+ bool eventFilter( QObject *o, QEvent *e );
+
+#ifdef QT_NO_WIDGET_TOPEXTRA
+ QString caption() const;
+#endif
+
+signals:
+ void orientationChanged( Orientation o );
+ void placeChanged( QDockWindow::Place p );
+ void visibilityChanged( bool );
+
+public slots:
+ virtual void undock( QWidget *w );
+ virtual void undock() { undock( 0 ); }
+ virtual void dock();
+ virtual void setOrientation( Orientation o );
+ void setCaption( const QString &s );
+
+protected:
+ void resizeEvent( QResizeEvent *e );
+ void showEvent( QShowEvent *e );
+ void hideEvent( QHideEvent *e );
+ void contextMenuEvent( QContextMenuEvent *e );
+
+ void drawFrame( QPainter * );
+ void drawContents( QPainter * );
+
+ bool event( QEvent *e );
+
+private slots:
+ void toggleVisible() { if ( !isVisible() ) show(); else hide(); }
+
+private:
+ QDockWindow( Place p, QWidget* parent, const char* name, WFlags f, bool toolbar );
+
+ void handleMove( const QPoint &pos, const QPoint &gp, bool drawRect );
+ void updateGui();
+ void updateSplitterVisibility( bool visible );
+
+ void startRectDraw( const QPoint &so, bool drawRect );
+ void endRectDraw( bool drawRect );
+ void updatePosition( const QPoint &globalPos );
+ QWidget *areaAt( const QPoint &gp );
+ void removeFromDock( bool fixNewLines = TRUE );
+ void swapRect( QRect &r, Qt::Orientation o, const QPoint &offset, QDockArea *area );
+ void init();
+
+private:
+ QDockWindowHandle *horHandle, *verHandle;
+ QDockWindowTitleBar *titleBar;
+ QWidget *wid;
+ QPainter *unclippedPainter;
+ QDockArea *dockArea, *tmpDockArea;
+ QRect currRect;
+ Place curPlace;
+ Place state;
+ bool resizeEnabled : 1;
+ bool moveEnabled : 1;
+ bool nl : 1;
+ bool opaque : 1;
+ bool isToolbar : 1;
+ bool stretchable[ 3 ];
+ Orientation startOrientation;
+ int cMode;
+ QPoint startOffset;
+ int offs;
+ QSize fExtent;
+ QDockWindowResizeHandle *hHandleTop, *hHandleBottom, *vHandleLeft, *vHandleRight;
+ QVBoxLayout *hbox;
+ QHBoxLayout *vbox;
+ QBoxLayout *childBox;
+ void *dockWindowData;
+ QPoint lastPos;
+ QSize lastSize;
+ QWidgetResizeHandler *widgetResizeHandler;
+ QDockWindowPrivate *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QDockWindow( const QDockWindow & );
+ QDockWindow& operator=( const QDockWindow & );
+#endif
+};
+
+inline QDockArea *QDockWindow::area() const
+{
+ return dockArea;
+}
+
+#define Q_DEFINED_QDOCKWINDOW
+#include "qwinexport.h"
+#endif
+
+#endif // QDOCKWINDOW_H
diff --git a/src/widgets/qeffects.cpp b/src/widgets/qeffects.cpp
new file mode 100644
index 0000000..50e104f
--- /dev/null
+++ b/src/widgets/qeffects.cpp
@@ -0,0 +1,675 @@
+/****************************************************************************
+**
+** Implementation of QEffects functions
+**
+** Created : 000621
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qapplication.h"
+#ifndef QT_NO_EFFECTS
+#include "qwidget.h"
+#include "qeffects_p.h"
+#include "qpixmap.h"
+#include "qimage.h"
+#include "qtimer.h"
+#include "qdatetime.h"
+#include "qguardedptr.h"
+#include "qscrollview.h"
+
+/*
+ Internal class to get access to protected QWidget-members
+*/
+
+class QAccessWidget : public QWidget
+{
+ friend class QAlphaWidget;
+ friend class QRollEffect;
+public:
+ QAccessWidget( QWidget* parent=0, const char* name=0, WFlags f = 0 )
+ : QWidget( parent, name, f ) {}
+};
+
+/*
+ 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, WFlags f = 0 );
+
+ void run( int time );
+
+protected:
+ void paintEvent( QPaintEvent* e );
+ void closeEvent( QCloseEvent* );
+ bool eventFilter( QObject* o, QEvent* e );
+ void alphaBlend();
+
+protected slots:
+ void render();
+
+private:
+ QPixmap pm;
+ double alpha;
+ QImage back;
+ QImage front;
+ QImage mixed;
+ QGuardedPtr<QAccessWidget> widget;
+ int duration;
+ int elapsed;
+ bool showWidget;
+ QTimer anim;
+ QTime checkTime;
+};
+
+static QAlphaWidget* q_blend = 0;
+
+/*
+ Constructs a QAlphaWidget.
+*/
+QAlphaWidget::QAlphaWidget( QWidget* w, WFlags f )
+ : QWidget( QApplication::desktop()->screen(QApplication::desktop()->screenNumber(w)),
+ "qt internal alpha effect widget", f )
+{
+#if 1 //ndef Q_WS_WIN
+ setEnabled( FALSE );
+#endif
+
+ pm.setOptimization( QPixmap::BestOptim );
+ setBackgroundMode( NoBackground );
+ widget = (QAccessWidget*)w;
+ alpha = 0;
+}
+
+/*
+ \reimp
+*/
+void QAlphaWidget::paintEvent( QPaintEvent* )
+{
+ bitBlt( this, QPoint(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;
+ qApp->installEventFilter( this );
+
+ widget->setWState( WState_Visible );
+
+ move( widget->geometry().x(),widget->geometry().y() );
+ resize( widget->size().width(), widget->size().height() );
+
+ front = QImage( widget->size(), 32 );
+ front = QPixmap::grabWidget( widget );
+
+ back = QImage( widget->size(), 32 );
+ back = QPixmap::grabWindow( QApplication::desktop()->winId(),
+ widget->geometry().x(), widget->geometry().y(),
+ widget->geometry().width(), widget->geometry().height() );
+
+ if ( !back.isNull() && checkTime.elapsed() < duration / 2 ) {
+ mixed = back.copy();
+ pm = mixed;
+ show();
+ setEnabled(FALSE);
+
+ connect( &anim, SIGNAL(timeout()), this, SLOT(render()));
+ anim.start( 1 );
+ } else {
+ duration = 0;
+ render();
+ }
+}
+
+/*
+ \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:
+#ifndef QT_NO_SCROLLVIEW
+ if ( ::qt_cast<QScrollView*>(o) )
+ break;
+#endif
+ case QEvent::MouseButtonDblClick:
+ setEnabled(TRUE);
+ showWidget = FALSE;
+ render();
+ break;
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if ( ke->key() == 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 ( alpha >= 1 || !showWidget) {
+ anim.stop();
+ qApp->removeEventFilter( this );
+
+ if ( widget ) {
+ if ( !showWidget ) {
+#ifdef Q_WS_WIN
+ setEnabled(TRUE);
+ setFocus();
+#endif
+ widget->hide();
+ widget->setWState( WState_ForceHide );
+ widget->clearWState( WState_Visible );
+ } else if ( duration ) {
+ BackgroundMode bgm = widget->backgroundMode();
+ QColor erc = widget->eraseColor();
+ const QPixmap *erp = widget->erasePixmap();
+
+ widget->clearWState( WState_Visible );
+ widget->setBackgroundMode( NoBackground );
+ widget->show();
+ if ( bgm != FixedColor && bgm != FixedPixmap ) {
+ widget->clearWState( WState_Visible ); // prevent update in setBackgroundMode
+ widget->setBackgroundMode( bgm );
+ widget->setWState( WState_Visible );
+ }
+ if ( erc.isValid() ) {
+ widget->setEraseColor( erc );
+ } else if ( erp ) {
+ widget->setErasePixmap( *erp );
+ }
+ } else {
+ widget->clearWState( WState_Visible );
+ widget->show();
+ }
+ }
+ q_blend = 0;
+ deleteLater();
+ } else {
+ if (widget)
+ widget->clearWState( WState_ForceHide );
+ alphaBlend();
+ pm = mixed;
+ repaint( FALSE );
+ }
+}
+
+/*
+ Calculate an alphablended image.
+*/
+void QAlphaWidget::alphaBlend()
+{
+ const double ia = 1-alpha;
+ const int sw = front.width();
+ const int sh = front.height();
+ switch( front.depth() ) {
+ case 32:
+ {
+ Q_UINT32** md = (Q_UINT32**)mixed.jumpTable();
+ Q_UINT32** bd = (Q_UINT32**)back.jumpTable();
+ Q_UINT32** fd = (Q_UINT32**)front.jumpTable();
+
+ for (int sy = 0; sy < sh; sy++ ) {
+ Q_UINT32* bl = ((Q_UINT32*)bd[sy]);
+ Q_UINT32* fl = ((Q_UINT32*)fd[sy]);
+ for (int sx = 0; sx < sw; sx++ ) {
+ Q_UINT32 bp = bl[sx];
+ Q_UINT32 fp = fl[sx];
+
+ ((Q_UINT32*)(md[sy]))[sx] = qRgb(int (qRed(bp)*ia + qRed(fp)*alpha),
+ int (qGreen(bp)*ia + qGreen(fp)*alpha),
+ int (qBlue(bp)*ia + qBlue(fp)*alpha) );
+ }
+ }
+ }
+ 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, WFlags f, DirFlags orient );
+
+ void run( int time );
+
+protected:
+ void paintEvent( QPaintEvent* );
+ bool eventFilter( QObject*, QEvent* );
+ void closeEvent( QCloseEvent* );
+
+private slots:
+ void scroll();
+
+private:
+ QGuardedPtr<QAccessWidget> widget;
+
+ int currentHeight;
+ int currentWidth;
+ int totalHeight;
+ int totalWidth;
+
+ int duration;
+ int elapsed;
+ bool done;
+ bool showWidget;
+ int orientation;
+
+ QTimer anim;
+ QTime checkTime;
+
+ QPixmap pm;
+};
+
+static QRollEffect* q_roll = 0;
+
+/*
+ Construct a QRollEffect widget.
+*/
+QRollEffect::QRollEffect( QWidget* w, WFlags f, DirFlags orient )
+ : QWidget( QApplication::desktop()->screen(QApplication::desktop()->screenNumber(w)),
+ "qt internal roll effect widget", f ), orientation(orient)
+{
+#if 1 //ndef Q_WS_WIN
+ setEnabled( FALSE );
+#endif
+ widget = (QAccessWidget*) w;
+ Q_ASSERT( widget );
+
+ setBackgroundMode( NoBackground );
+
+ if ( widget->testWState( WState_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.setOptimization( QPixmap::BestOptim );
+ 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;
+
+ bitBlt( this, x, y, &pm,
+ 0, 0, pm.width(), pm.height(), CopyROP, TRUE );
+}
+
+/*
+ \reimp
+*/
+bool QRollEffect::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 || done )
+ break;
+ setEnabled(TRUE);
+ showWidget = FALSE;
+ done = TRUE;
+ scroll();
+ break;
+ case QEvent::MouseButtonPress:
+#ifndef QT_NO_SCROLLVIEW
+ if ( ::qt_cast<QScrollView*>(o) )
+ break;
+#endif
+ case QEvent::MouseButtonDblClick:
+ if ( done )
+ break;
+ setEnabled(TRUE);
+ showWidget = FALSE;
+ done = TRUE;
+ scroll();
+ break;
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if ( ke->key() == Key_Escape )
+ showWidget = FALSE;
+ done = TRUE;
+ scroll();
+ break;
+ }
+ default:
+ break;
+ }
+ return QWidget::eventFilter( o, e );
+}
+
+/*
+ \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()));
+
+ widget->setWState( WState_Visible );
+
+ move( widget->geometry().x(),widget->geometry().y() );
+ resize( QMIN( currentWidth, totalWidth ), QMIN( currentHeight, totalHeight ) );
+
+ 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) {
+ widget->clearWState( WState_ForceHide );
+ 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( FALSE );
+ }
+ if ( done ) {
+ anim.stop();
+ qApp->removeEventFilter( this );
+ if ( widget ) {
+ if ( !showWidget ) {
+#ifdef Q_WS_WIN
+ setEnabled(TRUE);
+ setFocus();
+#endif
+ widget->hide();
+ widget->setWState( WState_ForceHide );
+ widget->clearWState( WState_Visible );
+ } else {
+ BackgroundMode bgm = widget->backgroundMode();
+ QColor erc = widget->eraseColor();
+ const QPixmap *erp = widget->erasePixmap();
+
+ widget->clearWState( WState_Visible );
+ widget->setBackgroundMode( NoBackground );
+ widget->show();
+ if ( bgm != FixedColor && bgm != FixedPixmap ) {
+ widget->clearWState( WState_Visible ); // prevent update in setBackgroundMode
+ widget->setBackgroundMode( bgm );
+ widget->setWState( WState_Visible );
+ }
+ if ( erc.isValid() ) {
+ widget->setEraseColor( erc );
+ } else if ( erp ) {
+ widget->setErasePixmap( *erp );
+ }
+ }
+ }
+ q_roll = 0;
+ deleteLater();
+ }
+}
+
+/*
+ Delete this after timeout
+*/
+
+#include "qeffects.moc"
+
+/*!
+ 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 ) {
+ delete q_roll;
+ q_roll = 0;
+ }
+
+ qApp->sendPostedEvents( w, QEvent::Move );
+ qApp->sendPostedEvents( w, QEvent::Resize );
+#ifdef Q_WS_X11
+ uint flags = Qt::WStyle_Customize | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop
+ | (w->isPopup() ? Qt::WType_Popup : (Qt::WX11BypassWM | Qt::WStyle_Tool));
+#else
+ uint flags = Qt::WStyle_Customize | Qt::WType_Popup | Qt::WX11BypassWM | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop;
+#endif
+
+ // those can 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 ) {
+ delete q_blend;
+ q_blend = 0;
+ }
+
+ qApp->sendPostedEvents( w, QEvent::Move );
+ qApp->sendPostedEvents( w, QEvent::Resize );
+
+#ifdef Q_WS_X11
+ uint flags = Qt::WStyle_Customize | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop
+ | (w->isPopup() ? Qt::WType_Popup : (Qt::WX11BypassWM | Qt::WStyle_Tool));
+#else
+ uint flags = Qt::WStyle_Customize | Qt::WType_Popup | Qt::WX11BypassWM | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop;
+#endif
+
+ // those can popups - they would steal the focus, but are disabled
+ q_blend = new QAlphaWidget( w, flags );
+
+ q_blend->run( time );
+}
+#endif //QT_NO_EFFECTS
diff --git a/src/widgets/qeffects_p.h b/src/widgets/qeffects_p.h
new file mode 100644
index 0000000..b9a6228
--- /dev/null
+++ b/src/widgets/qeffects_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Definition of QEffects functions
+**
+** Created : 000621
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#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.
+//
+//
+
+#ifndef QT_H
+#include "qnamespace.h"
+#endif // QT_H
+
+#ifndef QT_NO_EFFECTS
+class QWidget;
+
+struct QEffects
+{
+ enum Direction {
+ LeftScroll = 0x0001,
+ RightScroll = 0x0002,
+ UpScroll = 0x0004,
+ DownScroll = 0x0008
+ };
+
+ typedef uint DirFlags;
+};
+
+extern void Q_EXPORT qScrollEffect( QWidget*, QEffects::DirFlags dir = QEffects::DownScroll, int time = -1 );
+extern void Q_EXPORT qFadeEffect( QWidget*, int time = -1 );
+#endif // QT_NO_EFFECTS
+
+#endif // QEFFECTS_P_H
diff --git a/src/widgets/qframe.cpp b/src/widgets/qframe.cpp
new file mode 100644
index 0000000..414274e
--- /dev/null
+++ b/src/widgets/qframe.cpp
@@ -0,0 +1,754 @@
+/****************************************************************************
+**
+** Implementation of QFrame widget class
+**
+** Created : 950201
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qframe.h"
+#ifndef QT_NO_FRAME
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qframe.h"
+#include "qbitmap.h"
+#include "qstyle.h"
+
+/*!
+ \class QFrame
+ \brief The QFrame class is the base class of widgets that can have a frame.
+
+ \ingroup abstractwidgets
+
+ It draws a frame and calls a virtual function, drawContents(), to
+ fill in the frame. This function is reimplemented by subclasses.
+ There are also two other less useful functions: drawFrame() and
+ frameChanged().
+
+ QPopupMenu 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.
+
+ \code
+ QLabel label(...);
+ label.setFrameStyle( QFrame::Panel | QFrame::Raised );
+ label.setLineWidth( 2 );
+
+ QProgressBar pbar(...);
+ label.setFrameStyle( QFrame::NoFrame );
+ \endcode
+
+ The QFrame class can also be used directly for creating simple
+ frames without any contents, although usually you would use a
+ QHBox or QVBox because they automatically lay out the widgets you
+ put inside the frame.
+
+ A frame widget has four attributes: frameStyle(), lineWidth(),
+ midLineWidth(), and margin().
+
+ The frame style is specified by a \link QFrame::Shape frame
+ shape\endlink and a \link QFrame::Shadow shadow style\endlink. The
+ frame shapes are \c NoFrame, \c Box, \c Panel, \c StyledPanel, \c
+ PopupPanel, \c WinPanel, \c ToolBarPanel, \c MenuBarPanel, \c
+ HLine and \c VLine; the shadow styles are \c Plain, \c Raised and
+ \c Sunken.
+
+ The line width is the width of the frame border.
+
+ 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 \c Box, \c
+ HLine and \c VLine frames that are raised or sunken.
+
+ The margin is the gap between the frame and the contents of the
+ frame.
+
+ \target picture
+ This table shows the most useful combinations of styles and widths
+ (and some rather useless ones):
+
+ \img frames.png Table of frame styles
+*/
+
+
+/*!
+ \enum QFrame::Shape
+
+ This enum type defines the shapes of a QFrame's frame.
+
+ \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 GroupBoxPanel draws a rectangular panel
+ \value WinPanel draws a rectangular panel that can be raised or
+ sunken like those in Windows 95. Specifying this shape sets
+ the line width to 2 pixels. WinPanel is provided for compatibility.
+ For GUI style independence we recommend using StyledPanel instead.
+ \value ToolBarPanel
+ \value MenuBarPanel
+ \value PopupPanel
+ \value LineEditPanel is used to draw a frame suitable for line edits. The
+ look depends upon the current GUI style.
+ \value TabWidgetPanel is used to draw a frame suitable for tab widgets. The
+ look depends upon the current GUI style.
+ \value MShape internal mask
+
+ When it does not call QStyle, Shape interacts with QFrame::Shadow,
+ the lineWidth() and the midLineWidth() to create the total result.
+ See the \link #picture picture of the frames\endlink in the class
+ description.
+
+ \sa QFrame::Shadow QFrame::style() QStyle::drawPrimitive()
+*/
+
+
+/*!
+ \enum QFrame::Shadow
+
+ This enum type defines the 3D effect used for QFrame's frame.
+
+ \value Plain the frame and contents appear level with the
+ surroundings; draws using the palette foreground 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
+ \value MShadow internal; mask for the shadow
+
+ Shadow interacts with QFrame::Shape, the lineWidth() and the
+ midLineWidth(). See the \link #picture picture of the frames\endlink
+ in the class description.
+
+ \sa QFrame::Shape lineWidth() midLineWidth()
+*/
+
+
+/*!
+ Constructs a frame widget with frame style \c NoFrame and a
+ 1-pixel frame width.
+
+ The \a parent, \a name and \a f arguments are passed to the
+ QWidget constructor.
+*/
+
+QFrame::QFrame( QWidget *parent, const char *name, WFlags f )
+ : QWidget( parent, name, f )
+{
+ frect = QRect( 0, 0, 0, 0 );
+ fstyle = NoFrame | Plain;
+ lwidth = 1;
+ mwidth = 0;
+ mlwidth = 0;
+ updateFrameWidth();
+}
+
+static const int wpwidth = 2; // WinPanel lwidth
+
+/*!
+ \fn int QFrame::frameStyle() const
+
+ Returns the frame style.
+
+ The default value is QFrame::NoFrame.
+
+ \sa setFrameStyle(), frameShape(), frameShadow()
+*/
+
+/*!
+ \property QFrame::frameShape
+ \brief the frame shape value from the frame style
+
+ \sa frameStyle(), frameShadow()
+*/
+
+/*!
+ \property QFrame::frameShadow
+ \brief the frame shadow value from the frame style
+
+ \sa frameStyle(), frameShape()
+*/
+
+/*!
+ 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 \link #picture illustration\endlink in the
+ 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 \c Raised or \c Sunken \c Box, \c HLine, and \c
+ VLine frames. The mid-color of the current color group is used for
+ drawing middle lines.
+
+ \sa \link #picture Illustration\endlink, frameStyle(),
+ colorGroup(), QColorGroup
+*/
+
+void QFrame::setFrameStyle( int style )
+{
+ if ( !testWState( WState_OwnSizePolicy ) ) {
+ switch ( style & MShape ) {
+ case HLine:
+ setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
+ break;
+ case VLine:
+ setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum );
+ break;
+ default:
+ if ( (fstyle & MShape) == HLine || (fstyle & MShape) == VLine)
+ setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+ }
+ clearWState( WState_OwnSizePolicy );
+ }
+ fstyle = (short)style;
+ updateFrameWidth( TRUE );
+}
+
+/*!
+ \property QFrame::lineWidth
+ \brief the line width
+
+ Note that the \e total line width for \c HLine and \c VLine is
+ given by frameWidth(), not lineWidth().
+
+ The default value is 1.
+
+ \sa midLineWidth(), frameWidth()
+*/
+
+void QFrame::setLineWidth( int w )
+{
+ lwidth = (short)w;
+ updateFrameWidth();
+}
+
+/*!
+ \property QFrame::midLineWidth
+ \brief the width of the mid-line
+
+ The default value is 0.
+
+ \sa lineWidth(), frameWidth()
+*/
+
+void QFrame::setMidLineWidth( int w )
+{
+ mlwidth = (short)w;
+ updateFrameWidth();
+}
+
+
+
+/*!
+ \property QFrame::margin
+ \brief the width of the margin
+
+ The margin is the distance between the innermost pixel of the
+ frame and the outermost pixel of contentsRect(). It is included in
+ frameWidth().
+
+ The margin is filled according to backgroundMode().
+
+ The default value is 0.
+
+ \sa setMargin(), lineWidth(), frameWidth()
+*/
+
+void QFrame::setMargin( int w )
+{
+ mwidth = (short)w;
+ updateFrameWidth();
+}
+
+
+/*!
+ \internal
+ Updated the fwidth parameter.
+*/
+
+void QFrame::updateFrameWidth( bool resetLineMetrics )
+{
+ int frameType = fstyle & MShape;
+ int frameStyle = fstyle & MShadow;
+
+ if ( resetLineMetrics ) {
+ switch ( frameType ) {
+ case MenuBarPanel:
+ mwidth = 0;
+ lwidth = style().pixelMetric( QStyle::PM_MenuBarFrameWidth, this );
+ break;
+ case ToolBarPanel:
+ mwidth = 0;
+ lwidth = style().pixelMetric( QStyle::PM_DockWindowFrameWidth, this );
+ break;
+ case LineEditPanel:
+ case TabWidgetPanel:
+ case PopupPanel:
+ mwidth = 0;
+ lwidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth, this );
+ break;
+ }
+ }
+
+ fwidth = -1;
+
+ switch ( frameType ) {
+
+ case NoFrame:
+ fwidth = 0;
+ break;
+
+ case Box:
+ switch ( frameStyle ) {
+ case Plain:
+ fwidth = lwidth;
+ break;
+ case Raised:
+ case Sunken:
+ fwidth = (short)(lwidth*2 + midLineWidth() );
+ break;
+ }
+ break;
+
+
+ case LineEditPanel:
+ case TabWidgetPanel:
+ case PopupPanel:
+ case GroupBoxPanel:
+ case Panel:
+ case StyledPanel:
+ switch ( frameStyle ) {
+ case Plain:
+ case Raised:
+ case Sunken:
+ fwidth = lwidth;
+ break;
+ }
+ break;
+
+ case WinPanel:
+ switch ( frameStyle ) {
+ case Plain:
+ case Raised:
+ case Sunken:
+ fwidth = wpwidth; //WinPanel does not use lwidth!
+ break;
+ }
+ break;
+ case MenuBarPanel:
+ fwidth = lwidth;
+ break;
+ case ToolBarPanel:
+ fwidth = lwidth;
+ break;
+ case HLine:
+ case VLine:
+ switch ( frameStyle ) {
+ case Plain:
+ fwidth = lwidth;
+ break;
+ case Raised:
+ case Sunken:
+ fwidth = (short)(lwidth*2 + midLineWidth());
+ break;
+ }
+ break;
+ }
+
+ if ( fwidth == -1 ) // invalid style
+ fwidth = 0;
+
+ fwidth += margin();
+
+ frameChanged();
+}
+
+
+/*!
+ \property QFrame::frameWidth
+ \brief the width of the frame that is drawn.
+
+ Note that the frame width depends on the \link
+ QFrame::setFrameStyle() frame style \endlink, not only the line
+ width and the mid-line width. For example, the style \c NoFrame
+ always has a frame width of 0, whereas the style \c Panel has a
+ frame width equivalent to the line width. The frame width also
+ includes the margin.
+
+ \sa lineWidth(), midLineWidth(), frameStyle(), margin()
+*/
+
+/*!
+ \property QFrame::frameRect
+ \brief the frame rectangle
+
+ The frame rectangle is the rectangle the frame is drawn in. By
+ default, this is the entire widget. Setting this property does \e
+ not cause a widget update.
+
+ If this property is set to a null rectangle (for example
+ \c{QRect(0, 0, 0, 0)}), then the frame rectangle is equivalent to
+ the \link QWidget::rect() widget rectangle\endlink.
+
+ \sa contentsRect()
+*/
+
+QRect QFrame::frameRect() const
+{
+ if ( frect.isNull() )
+ return rect();
+ else
+ return frect;
+}
+
+void QFrame::setFrameRect( const QRect &r )
+{
+ frect = r.isValid() ? r : rect();
+}
+
+
+/*!
+ \property QFrame::contentsRect
+ \brief the rectangle inside the frame
+
+ \sa frameRect(), drawContents()
+*/
+
+QRect QFrame::contentsRect() const
+{
+ QRect r = frameRect();
+ int w = frameWidth(); // total width
+ int frameType = fstyle & MShape;
+ if (frameType == PopupPanel) {
+ int vExtra = style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this);
+ int hExtra = style().pixelMetric(QStyle::PM_PopupMenuFrameHorizontalExtra, this);
+ r.setRect( r.x()+w+hExtra, r.y()+w+vExtra, r.width()-w*2-hExtra*2, r.height()-w*2-vExtra*2 );
+ } else {
+ r.setRect( r.x()+w, r.y()+w, r.width()-w*2, r.height()-w*2 );
+ }
+ return r;
+}
+
+/*!\reimp
+*/
+QSize QFrame::sizeHint() const
+{
+ // 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 (fstyle & MShape) {
+ case HLine:
+ return QSize(-1,3);
+ case VLine:
+ return QSize(3,-1);
+ default:
+ return QWidget::sizeHint();
+ }
+}
+
+/*!
+ Processes the paint event \a event.
+
+ Paints the frame and the contents.
+
+ Opens the painter on the frame and calls drawFrame(), then
+ drawContents().
+*/
+
+void QFrame::paintEvent( QPaintEvent *event )
+{
+ const int m = margin();
+ if ( m && testWFlags( WNoAutoErase ) ) {
+ QRect r = contentsRect();
+ r.addCoords( -m, -m, m, m );
+ erase( event->region().intersect( QRegion( r ) - contentsRect() ) );
+ }
+
+ QPainter paint( this );
+
+ if ( !contentsRect().contains( event->rect() ) ) {
+ paint.save();
+ paint.setClipRegion( event->region().intersect(frameRect()) );
+ drawFrame( &paint );
+ paint.restore();
+ }
+ if ( event->rect().intersects( contentsRect() ) &&
+ (fstyle & MShape) != HLine && (fstyle & MShape) != VLine ) {
+ paint.setClipRegion( event->region().intersect( contentsRect() ) );
+ drawContents( &paint );
+ }
+}
+
+
+/*!
+ Processes the resize event \a e.
+
+ Adjusts the frame rectangle for the resized widget. The frame
+ rectangle is elastic, and the surrounding area is static.
+
+ The resulting frame rectangle may be null or invalid. You can use
+ setMinimumSize() to avoid those possibilities.
+
+ Nothing is done if the frame rectangle is a \link QRect::isNull()
+ null rectangle\endlink already.
+*/
+
+void QFrame::resizeEvent( QResizeEvent *e )
+{
+ if ( !frect.isNull() ) {
+ QRect r( frect.x(), frect.y(),
+ width() - (e->oldSize().width() - frect.width()),
+ height() - (e->oldSize().height() - frect.height()) );
+ setFrameRect( r );
+ }
+ QWidget::resizeEvent( e );
+}
+
+
+/*!
+ Draws the frame using the painter \a p and the current frame
+ attributes and color group. The rectangle inside the frame is not
+ affected.
+
+ This function is virtual, but in general you do not need to
+ reimplement it. If you do, note that the QPainter is already open
+ and must remain open.
+
+ \sa frameRect(), contentsRect(), drawContents(), frameStyle(), setPalette()
+*/
+
+void QFrame::drawFrame( QPainter *p )
+{
+ QPoint p1, p2;
+ QRect r = frameRect();
+ int type = fstyle & MShape;
+ int cstyle = fstyle & MShadow;
+#ifdef QT_NO_DRAWUTIL
+ p->setPen( black ); // ####
+ p->drawRect( r ); //### a bit too simple
+#else
+ const QColorGroup & g = colorGroup();
+
+#ifndef QT_NO_STYLE
+ QStyleOption opt(lineWidth(),midLineWidth());
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (cstyle == Sunken)
+ flags |= QStyle::Style_Sunken;
+ else if (cstyle == Raised)
+ flags |= QStyle::Style_Raised;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (hasMouse())
+ flags |= QStyle::Style_MouseOver;
+#endif // QT_NO_STYLE
+
+ switch ( type ) {
+
+ case Box:
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ qDrawShadeRect( p, r, g, cstyle == Sunken, lwidth,
+ midLineWidth() );
+ break;
+
+ case LineEditPanel:
+ style().drawPrimitive( QStyle::PE_PanelLineEdit, p, r, g, flags, opt );
+ break;
+
+ case GroupBoxPanel:
+ style().drawPrimitive( QStyle::PE_PanelGroupBox, p, r, g, flags, opt );
+ break;
+
+ case TabWidgetPanel:
+ style().drawPrimitive( QStyle::PE_PanelTabWidget, p, r, g, flags, opt );
+ break;
+
+ case MenuBarPanel:
+#ifndef QT_NO_STYLE
+ style().drawPrimitive(QStyle::PE_PanelMenuBar, p, r, g, flags, opt);
+ break;
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case ToolBarPanel:
+#ifndef QT_NO_STYLE
+ style().drawPrimitive( QStyle::PE_PanelDockWindow, p, rect(), g, flags, opt);
+ break;
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case StyledPanel:
+#ifndef QT_NO_STYLE
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ style().drawPrimitive(QStyle::PE_Panel, p, r, g, flags, opt);
+ break;
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case PopupPanel:
+#ifndef QT_NO_STYLE
+ {
+ int vextra = style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this),
+ hextra = style().pixelMetric(QStyle::PM_PopupMenuFrameHorizontalExtra, this);
+ if(vextra > 0 || hextra > 0) {
+ QRect fr = frameRect();
+ int fw = frameWidth();
+ if(vextra > 0) {
+ style().drawControl(QStyle::CE_PopupMenuVerticalExtra, p, this,
+ QRect(fr.x() + fw, fr.y() + fw, fr.width() - (fw*2), vextra),
+ g, flags, opt);
+ style().drawControl(QStyle::CE_PopupMenuVerticalExtra, p, this,
+ QRect(fr.x() + fw, fr.bottom() - fw - vextra, fr.width() - (fw*2), vextra),
+ g, flags, opt);
+ }
+ if(hextra > 0) {
+ style().drawControl(QStyle::CE_PopupMenuHorizontalExtra, p, this,
+ QRect(fr.x() + fw, fr.y() + fw + vextra, hextra, fr.height() - (fw*2) - vextra),
+ g, flags, opt);
+ style().drawControl(QStyle::CE_PopupMenuHorizontalExtra, p, this,
+ QRect(fr.right() - fw - hextra, fr.y() + fw + vextra, hextra, fr.height() - (fw*2) - vextra),
+ g, flags, opt);
+ }
+ }
+
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ style().drawPrimitive(QStyle::PE_PanelPopup, p, r, g, flags, opt);
+ break;
+ }
+#endif // fall through to Panel if QT_NO_STYLE
+
+ case Panel:
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), lwidth );
+ else
+ qDrawShadePanel( p, r, g, cstyle == Sunken, lwidth );
+ break;
+
+ case WinPanel:
+ if ( cstyle == Plain )
+ qDrawPlainRect( p, r, g.foreground(), wpwidth );
+ else
+ qDrawWinPanel( p, r, g, cstyle == Sunken );
+ break;
+ case HLine:
+ case VLine:
+ if ( type == HLine ) {
+ p1 = QPoint( r.x(), r.height()/2 );
+ p2 = QPoint( r.x()+r.width(), p1.y() );
+ }
+ else {
+ p1 = QPoint( r.x()+r.width()/2, 0 );
+ p2 = QPoint( p1.x(), r.height() );
+ }
+ if ( cstyle == Plain ) {
+ QPen oldPen = p->pen();
+ p->setPen( QPen(g.foreground(),lwidth) );
+ p->drawLine( p1, p2 );
+ p->setPen( oldPen );
+ }
+ else
+ qDrawShadeLine( p, p1, p2, g, cstyle == Sunken,
+ lwidth, midLineWidth() );
+ break;
+ }
+#endif // QT_NO_DRAWUTIL
+}
+
+
+/*!
+ Virtual function that draws the contents of the frame.
+
+ The QPainter is already open when you get it, and you must leave
+ it open. Painter \link QPainter::setWorldMatrix()
+ transformations\endlink are switched off on entry. If you
+ transform the painter, remember to take the frame into account and
+ \link QPainter::resetXForm() reset transformation\endlink before
+ returning.
+
+ This function is reimplemented by subclasses that draw something
+ inside the frame. It should only draw inside contentsRect(). The
+ default function does nothing.
+
+ \sa contentsRect(), QPainter::setClipRect()
+*/
+
+void QFrame::drawContents( QPainter * )
+{
+}
+
+
+/*!
+ Virtual function that is called when the frame style, line width
+ or mid-line width changes.
+
+ This function can be reimplemented by subclasses that need to know
+ when the frame attributes change.
+
+ The default implementation calls update().
+*/
+
+void QFrame::frameChanged()
+{
+ update();
+ updateGeometry();
+}
+
+/*!\reimp
+ */
+void QFrame::styleChange( QStyle& old )
+{
+ updateFrameWidth( TRUE );
+ QWidget::styleChange( old );
+}
+
+#endif //QT_NO_FRAME
diff --git a/src/widgets/qframe.h b/src/widgets/qframe.h
new file mode 100644
index 0000000..3e0fabf
--- /dev/null
+++ b/src/widgets/qframe.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Definition of QFrame widget class
+**
+** Created : 950201
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QFRAME_H
+#define QFRAME_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+
+#ifndef QT_NO_FRAME
+
+class Q_EXPORT QFrame : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS( Shape Shadow )
+ Q_PROPERTY( int frameWidth READ frameWidth )
+ Q_PROPERTY( QRect contentsRect READ contentsRect )
+ 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 margin READ margin WRITE setMargin )
+ Q_PROPERTY( int midLineWidth READ midLineWidth WRITE setMidLineWidth )
+ Q_PROPERTY( QRect frameRect READ frameRect WRITE setFrameRect DESIGNABLE false )
+
+public:
+ QFrame( QWidget* parent=0, const char* name=0, WFlags f=0 );
+
+ int frameStyle() const;
+ virtual void setFrameStyle( int );
+
+ int frameWidth() const;
+ QRect contentsRect() const;
+
+#ifndef Q_QDOC
+ bool lineShapesOk() const { return TRUE; }
+#endif
+
+ 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
+ PopupPanel = 0x0007, // rectangular panel depending on the GUI style
+ MenuBarPanel = 0x0008,
+ ToolBarPanel = 0x0009,
+ LineEditPanel = 0x000a,
+ TabWidgetPanel = 0x000b,
+ GroupBoxPanel = 0x000c,
+ MShape = 0x000f // mask for the shape
+ };
+ enum Shadow { Plain = 0x0010, // plain line
+ Raised = 0x0020, // raised shadow effect
+ Sunken = 0x0030, // sunken shadow effect
+ MShadow = 0x00f0 }; // mask for the shadow
+
+ Shape frameShape() const;
+ void setFrameShape( Shape );
+ Shadow frameShadow() const;
+ void setFrameShadow( Shadow );
+
+ int lineWidth() const;
+ virtual void setLineWidth( int );
+
+ int margin() const;
+ virtual void setMargin( int );
+
+ int midLineWidth() const;
+ virtual void setMidLineWidth( int );
+
+ QRect frameRect() const;
+ virtual void setFrameRect( const QRect & );
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void resizeEvent( QResizeEvent * );
+ virtual void drawFrame( QPainter * );
+ virtual void drawContents( QPainter * );
+ virtual void frameChanged();
+ void styleChange( QStyle& );
+
+private:
+ void updateFrameWidth(bool=FALSE);
+ QRect frect;
+ int fstyle;
+ short lwidth;
+ short mwidth;
+ short mlwidth;
+ short fwidth;
+
+ void * d;
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QFrame( const QFrame & );
+ QFrame &operator=( const QFrame & );
+#endif
+};
+
+
+inline int QFrame::frameStyle() const
+{ return fstyle; }
+
+inline QFrame::Shape QFrame::frameShape() const
+{ return (Shape) ( fstyle & MShape ); }
+
+inline QFrame::Shadow QFrame::frameShadow() const
+{ return (Shadow) ( fstyle & MShadow ); }
+
+inline void QFrame::setFrameShape( QFrame::Shape s )
+{ setFrameStyle( ( fstyle & MShadow ) | s ); }
+
+inline void QFrame::setFrameShadow( QFrame::Shadow s )
+{ setFrameStyle( ( fstyle & MShape ) | s ); }
+
+inline int QFrame::lineWidth() const
+{ return lwidth; }
+
+inline int QFrame::midLineWidth() const
+{ return mlwidth; }
+
+inline int QFrame::margin() const
+{ return mwidth; }
+
+inline int QFrame::frameWidth() const
+{ return fwidth; }
+
+
+#endif // QT_NO_FRAME
+
+#endif // QFRAME_H
diff --git a/src/widgets/qgrid.cpp b/src/widgets/qgrid.cpp
new file mode 100644
index 0000000..47fe88c
--- /dev/null
+++ b/src/widgets/qgrid.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+
+#include "qgrid.h"
+#ifndef QT_NO_GRID
+#include "qlayout.h"
+#include "qapplication.h"
+
+/*!
+ \class QGrid qgrid.h
+ \brief The QGrid widget provides simple geometry management of its children.
+
+ \ingroup geomanagement
+ \ingroup appearance
+
+ The grid places its widgets either in columns or in rows depending
+ on its orientation.
+
+ The number of rows \e or columns is defined in the constructor.
+ All the grid's children will be placed and sized in accordance
+ with their sizeHint() and sizePolicy().
+
+ Use setMargin() to add space around the grid itself, and
+ setSpacing() to add space between the widgets.
+
+ \img qgrid-m.png QGrid
+
+ \sa QVBox QHBox QGridLayout
+*/
+
+/*! \enum QGrid::Direction
+ \internal
+*/
+
+/*!
+ Constructs a grid widget with parent \a parent, called \a name.
+ If \a orient is \c Horizontal, \a n specifies the number of
+ columns. If \a orient is \c Vertical, \a n specifies the number of
+ rows. The widget flags \a f are passed to the QFrame constructor.
+*/
+QGrid::QGrid( int n, Orientation orient, QWidget *parent, const char *name,
+ WFlags f )
+ : QFrame( parent, name, f )
+{
+ int nCols, nRows;
+ if ( orient == Horizontal ) {
+ nCols = n;
+ nRows = -1;
+ } else {
+ nCols = -1;
+ nRows = n;
+ }
+ lay = new QGridLayout( this, nRows, nCols, 0, 0, name );
+ lay->setAutoAdd( TRUE );
+}
+
+
+
+/*!
+ Constructs a grid widget with parent \a parent, called \a name.
+ \a n specifies the number of columns. The widget flags \a f are
+ passed to the QFrame constructor.
+ */
+QGrid::QGrid( int n, QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f )
+{
+ lay = new QGridLayout( this, -1, n, 0, 0, name );
+ lay->setAutoAdd( TRUE );
+}
+
+
+/*!
+ Sets the spacing between the child widgets to \a space.
+*/
+
+void QGrid::setSpacing( int space )
+{
+ if ( layout() )
+ layout()->setSpacing( space );
+}
+
+
+/*!\reimp
+ */
+void QGrid::frameChanged()
+{
+ if ( !layout() )
+ return;
+ layout()->setMargin( frameWidth() );
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize QGrid::sizeHint() const
+{
+ QWidget *mThis = (QWidget*)this;
+ QApplication::sendPostedEvents( mThis, QEvent::ChildInserted );
+ return QFrame::sizeHint();
+}
+#endif
diff --git a/src/widgets/qgrid.h b/src/widgets/qgrid.h
new file mode 100644
index 0000000..24ec9b6
--- /dev/null
+++ b/src/widgets/qgrid.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QGRID_H
+#define QGRID_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_GRID
+
+class QGridLayout;
+
+class Q_EXPORT QGrid : public QFrame
+{
+ Q_OBJECT
+public:
+ QGrid( int n, QWidget* parent=0, const char* name=0, WFlags f = 0 );
+ QGrid( int n, Orientation orient, QWidget* parent=0, const char* name=0,
+ WFlags f = 0 );
+
+ void setSpacing( int );
+ QSize sizeHint() const;
+
+#ifndef QT_NO_COMPAT
+ typedef Orientation Direction;
+#endif
+
+protected:
+ void frameChanged();
+
+private:
+ QGridLayout *lay;
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QGrid( const QGrid & );
+ QGrid& operator=( const QGrid & );
+#endif
+};
+
+#endif // QT_NO_GRID
+
+#endif // QGRID_H
diff --git a/src/widgets/qgridview.cpp b/src/widgets/qgridview.cpp
new file mode 100644
index 0000000..902d14c
--- /dev/null
+++ b/src/widgets/qgridview.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Implementation of QGridView class
+**
+** Created : 010523
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+
+#include "qgridview.h"
+
+#ifndef QT_NO_GRIDVIEW
+
+#include "qpainter.h"
+
+/*!
+ \class QGridView qgridview.h
+ \brief The QGridView class provides an abstract base for
+ fixed-size grids.
+
+ \ingroup abstractwidgets
+
+ A grid view consists of a number of abstract cells organized in
+ rows and columns. The cells have a fixed size and are identified
+ with a row index and a column index. The top-left cell is in row
+ 0, column 0. The bottom-right cell is in row numRows()-1, column
+ numCols()-1.
+
+ You can define \l numRows, \l numCols, \l cellWidth and \l
+ cellHeight. Reimplement the pure virtual function paintCell() to
+ draw the contents of a cell.
+
+ With ensureCellVisible(), you can ensure a certain cell is
+ visible. With rowAt() and columnAt() you can find a cell based on
+ the given x- and y-coordinates.
+
+ If you need to monitor changes to the grid's dimensions (i.e. when
+ numRows or numCols is changed), reimplement the dimensionChange()
+ change handler.
+
+ Note: the row and column indices are always given in the order,
+ row (vertical offset) then column (horizontal offset). This order
+ is the opposite of all pixel operations, which are given in the
+ order x (horizontal offset), y (vertical offset).
+
+ QGridView is a very simple abstract class based on QScrollView. It
+ is designed to simplify the task of drawing many cells of the same
+ size in a potentially scrollable canvas. If you need rows and
+ columns with different sizes, use a QTable instead. If you need a
+ simple list of items, use a QListBox. If you need to present
+ hierachical data use a QListView, and if you need random objects
+ at random positions, consider using either a QIconView or a
+ QCanvas.
+*/
+
+
+/*!
+ Constructs a grid view.
+
+ The \a parent, \a name and widget flag, \a f, arguments are passed
+ to the QScrollView constructor.
+*/
+QGridView::QGridView( QWidget *parent, const char *name, WFlags f )
+ :QScrollView( parent, name, f | WStaticContents ),
+ nrows( 5 ), ncols( 5 ), cellw( 12 ), cellh( 12 )
+{
+ viewport()->setBackgroundMode( PaletteBase );
+ setBackgroundMode( PaletteBackground, PaletteBase );
+ viewport()->setFocusProxy( this );
+}
+
+/*!
+ Destroys the grid view.
+*/
+QGridView::~QGridView()
+{
+}
+
+void QGridView::updateGrid()
+{
+ resizeContents( ncols * cellw, nrows * cellh );
+}
+
+/*!
+ \property QGridView::numRows
+ \brief The number of rows in the grid
+
+ \sa numCols
+*/
+void QGridView::setNumRows( int numRows )
+{
+ int oldnrows = nrows;
+ nrows = numRows;
+ dimensionChange( oldnrows, ncols );
+ updateGrid();
+}
+
+/*!
+ \property QGridView::numCols
+ \brief The number of columns in the grid
+
+ \sa numRows
+*/
+void QGridView::setNumCols( int numCols )
+{
+ int oldncols = ncols;
+ ncols = numCols;
+ dimensionChange( nrows, oldncols );
+ updateGrid();
+}
+
+/*!
+ \property QGridView::cellWidth
+ \brief The width of a grid column
+
+ All columns in a grid view have the same width.
+
+ \sa cellHeight
+*/
+void QGridView::setCellWidth( int cellWidth )
+{
+ cellw = cellWidth;
+ updateGrid();
+ updateContents();
+}
+
+/*!
+ \property QGridView::cellHeight
+ \brief The height of a grid row
+
+ All rows in a grid view have the same height.
+
+ \sa cellWidth
+*/
+void QGridView::setCellHeight( int cellHeight )
+{
+ cellh = cellHeight;
+ updateGrid();
+ updateContents();
+}
+
+/*!
+ Returns the geometry of cell (\a row, \a column) in the content
+ coordinate system.
+
+ \sa cellRect()
+ */
+QRect QGridView::cellGeometry( int row, int column )
+{
+ QRect r;
+ if ( row >= 0 && row < nrows && column >= 0 && column < ncols )
+ r.setRect( cellw * column, cellh * row, cellw, cellh );
+ return r;
+}
+
+/*!
+ Repaints cell (\a row, \a column).
+
+ If \a erase is TRUE, Qt erases the area of the cell before the
+ paintCell() call; otherwise no erasing takes place.
+
+ \sa QWidget::repaint()
+*/
+void QGridView::repaintCell( int row, int column, bool erase )
+{
+ repaintContents( cellGeometry( row, column ), erase );
+}
+
+/*!
+ Updates cell (\a row, \a column).
+
+ \sa QWidget::update()
+*/
+void QGridView::updateCell( int row, int column )
+{
+ updateContents( cellGeometry( row, column ) );
+}
+
+/*!
+ Ensures cell (\a row, \a column) is visible, scrolling the grid
+ view if necessary.
+*/
+void QGridView::ensureCellVisible( int row, int column )
+{
+ QRect r = cellGeometry( row, column );
+ ensureVisible( r.x(), r.y(), r.width(), r.height() );
+}
+
+/*!
+ This function fills the \a cw pixels wide and \a ch pixels high
+ rectangle starting at position (\a cx, \a cy) with the background
+ color using the painter \a p.
+
+ paintEmptyArea() is invoked by drawContents() to erase or fill
+ unused areas.
+*/
+
+void QGridView::paintEmptyArea( QPainter *p, int cx ,int cy, int cw, int ch)
+{
+ if ( gridSize().width() >= contentsWidth() && gridSize().height() >= contentsHeight() )
+ return;
+ // Region of the rect we should draw
+ contentsToViewport( cx, cy, cx, cy );
+ QRegion reg( QRect( cx, cy, cw, ch ) );
+ // Subtract the table from it
+ reg = reg.subtract( QRect( contentsToViewport( QPoint( 0, 0 ) ), gridSize() ) );
+
+ // And draw the rectangles (transformed as needed)
+ QMemArray<QRect> r = reg.rects();
+ const QBrush &brush = backgroundBrush();
+ for ( int i = 0; i < (int)r.count(); ++i)
+ p->fillRect( r[ i ], brush );
+}
+
+/*!\reimp
+ */
+void QGridView::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
+{
+ int colfirst = columnAt( cx );
+ int collast = columnAt( cx + cw );
+ int rowfirst = rowAt( cy );
+ int rowlast = rowAt( cy + ch );
+
+ if ( rowfirst == -1 || colfirst == -1 ) {
+ paintEmptyArea( p, cx, cy, cw, ch );
+ return;
+ }
+
+ if ( collast < 0 || collast >= ncols )
+ collast = ncols-1;
+ if ( rowlast < 0 || rowlast >= nrows )
+ rowlast = nrows-1;
+
+ // Go through the rows
+ for ( int r = rowfirst; r <= rowlast; ++r ) {
+ // get row position and height
+ int rowp = r * cellh;
+
+ // Go through the columns in the row r
+ // if we know from where to where, go through [colfirst, collast],
+ // else go through all of them
+ for ( int c = colfirst; c <= collast; ++c ) {
+ // get position and width of column c
+ int colp = c * cellw;
+ // Translate painter and draw the cell
+ p->translate( colp, rowp );
+ paintCell( p, r, c );
+ p->translate( -colp, -rowp );
+ }
+ }
+
+ // Paint empty rects
+ paintEmptyArea( p, cx, cy, cw, ch );
+}
+
+/*!
+ \reimp
+
+ (Implemented to get rid of a compiler warning.)
+*/
+void QGridView::drawContents( QPainter * )
+{
+}
+
+/*!
+ \fn void QGridView::dimensionChange( int oldNumRows, int oldNumCols )
+
+ This change handler is called whenever any of the grid's
+ dimensions change. \a oldNumRows and \a oldNumCols contain the
+ old dimensions, numRows() and numCols() contain the new
+ dimensions.
+*/
+void QGridView::dimensionChange( int, int ) {}
+
+
+
+/*!
+ \fn int QGridView::rowAt( int y ) const
+
+ Returns the number of the row at position \a y. \a y must be given
+ in content coordinates.
+
+ \sa columnAt()
+*/
+
+/*!
+ \fn int QGridView::columnAt( int x ) const
+
+ Returns the number of the column at position \a x. \a x must be
+ given in content coordinates.
+
+ \sa rowAt()
+*/
+
+/*!
+ \fn void QGridView::paintCell( QPainter *p, int row, int col )
+
+ This pure virtual function is called to paint the single cell at
+ (\a row, \a col) using painter \a p. The painter must be open when
+ paintCell() is called and must remain open.
+
+ The coordinate system is \link QPainter::translate() translated
+ \endlink so that the origin is at the top-left corner of the cell
+ to be painted, i.e. \e cell coordinates. Do not scale or shear
+ the coordinate system (or if you do, restore the transformation
+ matrix before you return).
+
+ The painter is not clipped by default in order to get maximum
+ efficiency. If you want clipping, use
+
+ \code
+ p->setClipRect( cellRect(), QPainter::CoordPainter );
+ //... your drawing code
+ p->setClipping( FALSE );
+
+ \endcode
+*/
+
+/*!
+ \fn QRect QGridView::cellRect() const
+
+ Returns the geometry of a cell in a cell's coordinate system. This
+ is a convenience function useful in paintCell(). It is equivalent
+ to QRect( 0, 0, cellWidth(), cellHeight() ).
+
+ \sa cellGeometry()
+
+*/
+
+/*!
+ \fn QSize QGridView::gridSize() const
+
+ Returns the size of the grid in pixels.
+
+*/
+
+#endif // QT_NO_GRIDVIEW
diff --git a/src/widgets/qgridview.h b/src/widgets/qgridview.h
new file mode 100644
index 0000000..860aa37
--- /dev/null
+++ b/src/widgets/qgridview.h
@@ -0,0 +1,139 @@
+/**********************************************************************
+**
+** Definition of QGridView class
+**
+** Created : 010523
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QGRIDVIEW_H
+#define QGRIDVIEW_H
+
+#ifndef QT_H
+#include "qscrollview.h"
+#endif // QT_H
+
+#ifndef QT_NO_GRIDVIEW
+
+class QGridViewPrivate;
+
+class Q_EXPORT QGridView : public QScrollView
+{
+ Q_OBJECT
+ Q_PROPERTY( int numRows READ numRows WRITE setNumRows )
+ Q_PROPERTY( int numCols READ numCols WRITE setNumCols )
+ Q_PROPERTY( int cellWidth READ cellWidth WRITE setCellWidth )
+ Q_PROPERTY( int cellHeight READ cellHeight WRITE setCellHeight )
+public:
+
+ QGridView( QWidget *parent=0, const char *name=0, WFlags f=0 );
+ ~QGridView();
+
+ int numRows() const;
+ virtual void setNumRows( int );
+ int numCols() const;
+ virtual void setNumCols( int );
+
+ int cellWidth() const;
+ virtual void setCellWidth( int );
+ int cellHeight() const;
+ virtual void setCellHeight( int );
+
+ QRect cellRect() const;
+ QRect cellGeometry( int row, int column );
+ QSize gridSize() const;
+
+ int rowAt( int y ) const;
+ int columnAt( int x ) const;
+
+ void repaintCell( int row, int column, bool erase=TRUE );
+ void updateCell( int row, int column );
+ void ensureCellVisible( int row, int column );
+
+protected:
+ virtual void paintCell( QPainter *, int row, int col ) = 0;
+ virtual void paintEmptyArea( QPainter *p, int cx, int cy, int cw, int ch );
+
+ void drawContents( QPainter *p, int cx, int cy, int cw, int ch );
+
+ virtual void dimensionChange( int, int );
+
+private:
+ void drawContents( QPainter* );
+ void updateGrid();
+
+ int nrows;
+ int ncols;
+ int cellw;
+ int cellh;
+ QGridViewPrivate* d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QGridView( const QGridView & );
+ QGridView &operator=( const QGridView & );
+#endif
+};
+
+inline int QGridView::cellWidth() const
+{ return cellw; }
+
+inline int QGridView::cellHeight() const
+{ return cellh; }
+
+inline int QGridView::rowAt( int y ) const
+{ return y / cellh; }
+
+inline int QGridView::columnAt( int x ) const
+{ return x / cellw; }
+
+inline int QGridView::numRows() const
+{ return nrows; }
+
+inline int QGridView::numCols() const
+{return ncols; }
+
+inline QRect QGridView::cellRect() const
+{ return QRect( 0, 0, cellw, cellh ); }
+
+inline QSize QGridView::gridSize() const
+{ return QSize( ncols * cellw, nrows * cellh ); }
+
+
+
+#endif // QT_NO_GRIDVIEW
+
+
+#endif // QTABLEVIEW_H
diff --git a/src/widgets/qgroupbox.cpp b/src/widgets/qgroupbox.cpp
new file mode 100644
index 0000000..6097ece
--- /dev/null
+++ b/src/widgets/qgroupbox.cpp
@@ -0,0 +1,989 @@
+/**********************************************************************
+**
+** Implementation of QGroupBox widget class
+**
+** Created : 950203
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qgroupbox.h"
+#ifndef QT_NO_GROUPBOX
+#include "qlayout.h"
+#include "qpainter.h"
+#include "qbitmap.h"
+#include "qaccel.h"
+#include "qradiobutton.h"
+#include "qfocusdata.h"
+#include "qobjectlist.h"
+#include "qdrawutil.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qcheckbox.h"
+#include "qbuttongroup.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+/*!
+ \class QGroupBox qgroupbox.h
+ \brief The QGroupBox widget provides a group box frame with a title.
+
+ \ingroup organizers
+ \ingroup geomanagement
+ \ingroup appearance
+ \mainclass
+
+ 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, and the child widgets are usually laid out
+ horizontally (or vertically) inside the frame.
+
+ The simplest way to use it is to create a group box with the
+ desired number of columns (or rows) and orientation, and then just
+ create widgets with the group box as parent.
+
+ It is also possible to change the orientation() and number of
+ columns() after construction, or to ignore all the automatic
+ layout support and manage the layout yourself. You can add 'empty'
+ spaces to the group box with addSpace().
+
+ QGroupBox also lets you set the title() (normally set in the
+ constructor) and the title's alignment().
+
+ You can change the spacing used by the group box with
+ setInsideMargin() and setInsideSpacing(). To minimize space
+ consumption, you can remove the right, left and bottom edges of
+ the frame with setFlat().
+
+ <img src=qgrpbox-w.png>
+
+ \sa QButtonGroup
+*/
+
+class QCheckBox;
+
+class QGroupBoxPrivate
+{
+public:
+ QGroupBoxPrivate():
+ spacer( 0 ),
+ checkbox( 0 ) {}
+
+ QSpacerItem *spacer;
+ QCheckBox *checkbox;
+};
+
+
+
+
+/*!
+ Constructs a group box widget with no title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+
+ This constructor does not do automatic layout.
+*/
+
+QGroupBox::QGroupBox( QWidget *parent, const char *name )
+ : QFrame( parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs a group box with the title \a title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+
+ This constructor does not do automatic layout.
+*/
+
+QGroupBox::QGroupBox( const QString &title, QWidget *parent, const char *name )
+ : QFrame( parent, name )
+{
+ init();
+ setTitle( title );
+}
+
+/*!
+ Constructs a group box with no title. Child widgets will be
+ arranged in \a strips rows or columns (depending on \a
+ orientation).
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QGroupBox::QGroupBox( int strips, Orientation orientation,
+ QWidget *parent, const char *name )
+ : QFrame( parent, name )
+{
+ init();
+ setColumnLayout( strips, orientation );
+}
+
+/*!
+ Constructs a group box titled \a title. Child widgets will be
+ arranged in \a strips rows or columns (depending on \a
+ orientation).
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QGroupBox::QGroupBox( int strips, Orientation orientation,
+ const QString &title, QWidget *parent,
+ const char *name )
+ : QFrame( parent, name )
+{
+ init();
+ setTitle( title );
+ setColumnLayout( strips, orientation );
+}
+
+/*!
+ Destroys the group box.
+*/
+QGroupBox::~QGroupBox()
+{
+ delete d;
+}
+
+void QGroupBox::init()
+{
+ align = AlignAuto;
+ setFrameStyle( QFrame::GroupBoxPanel | QFrame::Sunken );
+#ifndef QT_NO_ACCEL
+ accel = 0;
+#endif
+ vbox = 0;
+ grid = 0;
+ d = new QGroupBoxPrivate();
+ lenvisible = 0;
+ nCols = nRows = 0;
+ dir = Horizontal;
+ marg = 11;
+ spac = 5;
+ bFlat = FALSE;
+}
+
+void QGroupBox::setTextSpacer()
+{
+ if ( !d->spacer )
+ return;
+ int h = 0;
+ int w = 0;
+ if ( isCheckable() || lenvisible ) {
+ QFontMetrics fm = fontMetrics();
+ int fh = fm.height();
+ if ( isCheckable() ) {
+#ifndef QT_NO_CHECKBOX
+ fh = d->checkbox->sizeHint().height() + 2;
+ w = d->checkbox->sizeHint().width() + 2*fm.width( "xx" );
+#endif
+ } else {
+ fh = fm.height();
+ w = fm.width( str, lenvisible ) + 2*fm.width( "xx" );
+ }
+ h = frameRect().y();
+ if ( layout() ) {
+ int m = layout()->margin();
+ int sp = layout()->spacing();
+ // do we have a child layout?
+ for ( QLayoutIterator it = layout()->iterator(); it.current(); ++it ) {
+ if ( it.current()->layout() ) {
+ m += it.current()->layout()->margin();
+ sp = QMAX( sp, it.current()->layout()->spacing() );
+ break;
+ }
+ }
+ h = QMAX( fh-m, h );
+ h += QMAX( sp - (h+m - fh), 0 );
+ }
+ }
+ d->spacer->changeSize( w, h, QSizePolicy::Minimum, QSizePolicy::Fixed );
+}
+
+
+void QGroupBox::setTitle( const QString &title )
+{
+ if ( str == title ) // no change
+ return;
+ str = title;
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ delete accel;
+ accel = 0;
+ int s = QAccel::shortcutKey( title );
+ if ( s ) {
+ accel = new QAccel( this, "automatic focus-change accelerator" );
+ accel->connectItem( accel->insertItem( s, 0 ),
+ this, SLOT(fixFocus()) );
+ }
+#endif
+#ifndef QT_NO_CHECKBOX
+ if ( d->checkbox ) {
+ d->checkbox->setText( str );
+ updateCheckBoxGeometry();
+ }
+#endif
+ calculateFrame();
+ setTextSpacer();
+
+ update();
+ updateGeometry();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::NameChanged );
+#endif
+}
+
+/*!
+ \property QGroupBox::title
+ \brief the group box title text.
+
+ The group box title text will have a focus-change keyboard
+ accelerator if the title contains \&, followed by a letter.
+
+ \code
+ g->setTitle( "&User information" );
+ \endcode
+ This produces "<u>U</u>ser information"; Alt+U moves the keyboard
+ focus to the group box.
+
+ There is no default title text.
+*/
+
+/*!
+ \property QGroupBox::alignment
+ \brief the alignment of the group box title.
+
+ The title is always placed on the upper frame line. The horizontal
+ alignment can be specified by the alignment parameter.
+
+ The alignment is one of the following flags:
+ \list
+ \i \c AlignAuto aligns the title according to the language,
+ usually to the left.
+ \i \c AlignLeft aligns the title text to the left.
+ \i \c AlignRight aligns the title text to the right.
+ \i \c AlignHCenter aligns the title text centered.
+ \endlist
+
+ The default alignment is \c AlignAuto.
+
+ \sa Qt::AlignmentFlags
+*/
+
+void QGroupBox::setAlignment( int alignment )
+{
+ align = alignment;
+#ifndef QT_NO_CHECKBOX
+ updateCheckBoxGeometry();
+#endif
+ update();
+}
+
+/*! \reimp
+*/
+void QGroupBox::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent(e);
+#ifndef QT_NO_CHECKBOX
+ if ( align & AlignRight || align & AlignCenter ||
+ ( QApplication::reverseLayout() && !(align & AlignLeft) ) )
+ updateCheckBoxGeometry();
+#endif
+ calculateFrame();
+}
+
+/*! \reimp
+
+ \internal
+ overrides QFrame::paintEvent
+*/
+
+void QGroupBox::paintEvent( QPaintEvent *event )
+{
+ QPainter paint( this );
+
+ if ( lenvisible && !isCheckable() ) { // draw title
+ QFontMetrics fm = paint.fontMetrics();
+ int h = fm.height();
+ int tw = fm.width( str, lenvisible ) + fm.width(QChar(' '));
+ int x;
+ int marg = bFlat ? 0 : 8;
+ if ( align & AlignHCenter ) // center alignment
+ x = frameRect().width()/2 - tw/2;
+ else if ( align & AlignRight ) // right alignment
+ x = frameRect().width() - tw - marg;
+ else if ( align & AlignLeft ) // left alignment
+ x = marg;
+ else { // auto align
+ if( QApplication::reverseLayout() )
+ x = frameRect().width() - tw - marg;
+ else
+ x = marg;
+ }
+ QRect r( x, 0, tw, h );
+ int va = style().styleHint(QStyle::SH_GroupBox_TextLabelVerticalAlignment, this);
+ if(va & AlignTop)
+ r.moveBy(0, fm.descent());
+ QColor pen( (QRgb) style().styleHint(QStyle::SH_GroupBox_TextLabelColor, this ) );
+ if (!style().styleHint(QStyle::SH_UnderlineAccelerator, this))
+ va |= NoAccel;
+ style().drawItem( &paint, r, ShowPrefix | AlignHCenter | va, colorGroup(),
+ isEnabled(), 0, str, -1, ownPalette() ? 0 : &pen );
+ paint.setClipRegion( event->region().subtract( r ) ); // clip everything but title
+#ifndef QT_NO_CHECKBOX
+ } else if ( d->checkbox ) {
+ QRect cbClip = d->checkbox->geometry();
+ QFontMetrics fm = paint.fontMetrics();
+ cbClip.setX( cbClip.x() - fm.width(QChar(' ')) );
+ cbClip.setWidth( cbClip.width() + fm.width(QChar(' ')) );
+ paint.setClipRegion( event->region().subtract( cbClip ) );
+#endif
+ }
+ if ( bFlat ) {
+ QRect fr = frameRect();
+ QPoint p1( fr.x(), fr.y() + 1 );
+ QPoint p2( fr.x() + fr.width(), p1.y() );
+ // ### This should probably be a style primitive.
+ qDrawShadeLine( &paint, p1, p2, colorGroup(), TRUE,
+ lineWidth(), midLineWidth() );
+ } else {
+ drawFrame(&paint);
+ }
+ drawContents( &paint ); // draw the contents
+}
+
+
+/*!
+ Adds an empty cell at the next free position. If \a size is
+ greater than 0, the empty cell takes \a size to be its fixed width
+ (if orientation() is \c Horizontal) or height (if orientation() is
+ \c Vertical).
+
+ Use this method to separate the widgets in the group box or to
+ skip the next free cell. For performance reasons, call this method
+ after calling setColumnLayout() or by changing the \l
+ QGroupBox::columns or \l QGroupBox::orientation properties. It is
+ generally a good idea to call these methods first (if needed at
+ all), and insert the widgets and spaces afterwards.
+*/
+void QGroupBox::addSpace( int size )
+{
+ QApplication::sendPostedEvents( this, QEvent::ChildInserted );
+
+ if ( nCols <= 0 || nRows <= 0 )
+ return;
+
+ if ( row >= nRows || col >= nCols )
+ grid->expand( row+1, col+1 );
+
+ if ( size > 0 ) {
+ QSpacerItem *spacer
+ = new QSpacerItem( ( dir == Horizontal ) ? 0 : size,
+ ( dir == Vertical ) ? 0 : size,
+ QSizePolicy::Fixed, QSizePolicy::Fixed );
+ grid->addItem( spacer, row, col );
+ }
+
+ skip();
+}
+
+/*!
+ \property QGroupBox::columns
+ \brief the number of columns or rows (depending on \l QGroupBox::orientation) in the group box
+
+ Usually it is not a good idea to set this property because it is
+ slow (it does a complete layout). It is best to set the number
+ of columns directly in the constructor.
+*/
+int QGroupBox::columns() const
+{
+ if ( dir == Horizontal )
+ return nCols;
+ return nRows;
+}
+
+void QGroupBox::setColumns( int c )
+{
+ setColumnLayout( c, dir );
+}
+
+/*!
+ Returns the width of the empty space between the items in the
+ group and the frame of the group.
+
+ Only applies if the group box has a defined orientation.
+
+ The default is usually 11, by may vary depending on the platform
+ and style.
+
+ \sa setInsideMargin(), orientation
+*/
+int QGroupBox::insideMargin() const
+{
+ return marg;
+}
+
+/*!
+ Returns the width of the empty space between each of the items
+ in the group.
+
+ Only applies if the group box has a defined orientation.
+
+ The default is usually 5, by may vary depending on the platform
+ and style.
+
+ \sa setInsideSpacing(), orientation
+*/
+int QGroupBox::insideSpacing() const
+{
+ return spac;
+}
+
+/*!
+ Sets the the width of the inside margin to \a m pixels.
+
+ \sa insideMargin()
+*/
+void QGroupBox::setInsideMargin( int m )
+{
+ marg = m;
+ setColumnLayout( columns(), dir );
+}
+
+/*!
+ Sets the width of the empty space between each of the items in
+ the group to \a s pixels.
+
+ \sa insideSpacing()
+*/
+void QGroupBox::setInsideSpacing( int s )
+{
+ spac = s;
+ setColumnLayout( columns(), dir );
+}
+
+/*!
+ \property QGroupBox::orientation
+ \brief the group box's orientation
+
+ A horizontal group box arranges it's children in columns, while a
+ vertical group box arranges them in rows.
+
+ Usually it is not a good idea to set this property because it is
+ slow (it does a complete layout). It is better to set the
+ orientation directly in the constructor.
+*/
+void QGroupBox::setOrientation( Qt::Orientation o )
+{
+ setColumnLayout( columns(), o );
+}
+
+/*!
+ Changes the layout of the group box. This function is only useful
+ in combination with the default constructor that does not take any
+ layout information. This function will put all existing children
+ in the new layout. It is not good Qt programming style to call
+ this function after children have been inserted. Sets the number
+ of columns or rows to be \a strips, depending on \a direction.
+
+ \sa orientation columns
+*/
+void QGroupBox::setColumnLayout(int strips, Orientation direction)
+{
+ if ( layout() )
+ delete layout();
+
+ vbox = 0;
+ grid = 0;
+
+ if ( strips < 0 ) // if 0, we create the vbox but not the grid. See below.
+ return;
+
+ vbox = new QVBoxLayout( this, marg, 0 );
+
+ d->spacer = new QSpacerItem( 0, 0, QSizePolicy::Minimum,
+ QSizePolicy::Fixed );
+
+ setTextSpacer();
+ vbox->addItem( d->spacer );
+
+ nCols = 0;
+ nRows = 0;
+ dir = direction;
+
+ // Send all child events and ignore them. Otherwise we will end up
+ // with doubled insertion. This won't do anything because nCols ==
+ // nRows == 0.
+ QApplication::sendPostedEvents( this, QEvent::ChildInserted );
+
+ // if 0 or smaller , create a vbox-layout but no grid. This allows
+ // the designer to handle its own grid layout in a group box.
+ if ( strips <= 0 )
+ return;
+
+ dir = direction;
+ if ( dir == Horizontal ) {
+ nCols = strips;
+ nRows = 1;
+ } else {
+ nCols = 1;
+ nRows = strips;
+ }
+ grid = new QGridLayout( nRows, nCols, spac );
+ row = col = 0;
+ grid->setAlignment( AlignTop );
+ vbox->addLayout( grid );
+
+ // Add all children
+ if ( children() ) {
+ QObjectListIt it( *children() );
+ QWidget *w;
+ while( (w=(QWidget *)it.current()) != 0 ) {
+ ++it;
+ if ( w->isWidgetType()
+#ifndef QT_NO_CHECKBOX
+ && w != d->checkbox
+#endif
+ )
+ insertWid( w );
+ }
+ }
+}
+
+
+/*! \reimp */
+bool QGroupBox::event( QEvent * e )
+{
+ if ( e->type() == QEvent::LayoutHint && layout() )
+ setTextSpacer();
+ return QFrame::event( e );
+}
+
+/*!\reimp */
+void QGroupBox::childEvent( QChildEvent *c )
+{
+ if ( !c->inserted() || !c->child()->isWidgetType() )
+ return;
+ QWidget *w = (QWidget*)c->child();
+#ifndef QT_NO_CHECKBOX
+ if ( d->checkbox ) {
+ if ( w == d->checkbox )
+ return;
+ if ( d->checkbox->isChecked() ) {
+ if ( !w->testWState( WState_ForceDisabled ) )
+ w->setEnabled( TRUE );
+ } else {
+ if ( w->isEnabled() ) {
+ w->setEnabled( FALSE );
+ ((QGroupBox*)w)->clearWState( WState_ForceDisabled );
+ }
+ }
+ }
+#endif
+ if ( !grid )
+ return;
+ insertWid( w );
+}
+
+void QGroupBox::insertWid( QWidget* w )
+{
+ if ( row >= nRows || col >= nCols )
+ grid->expand( row+1, col+1 );
+ grid->addWidget( w, row, col );
+ skip();
+ QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
+}
+
+
+void QGroupBox::skip()
+{
+ // Same as QGrid::skip()
+ if ( dir == Horizontal ) {
+ if ( col+1 < nCols ) {
+ col++;
+ } else {
+ col = 0;
+ row++;
+ }
+ } else { //Vertical
+ if ( row+1 < nRows ) {
+ row++;
+ } else {
+ row = 0;
+ col++;
+ }
+ }
+}
+
+
+/*!
+ \internal
+
+ This private slot finds a widget in this group box that can accept
+ focus, and gives the focus to that widget.
+*/
+
+void QGroupBox::fixFocus()
+{
+ QFocusData * fd = focusData();
+ QWidget * orig = fd->home();
+ QWidget * best = 0;
+ QWidget * candidate = 0;
+ QWidget * w = orig;
+ do {
+ QWidget * p = w;
+ while( p && p != this && !p->isTopLevel() )
+ p = p->parentWidget();
+ if ( p == this && ( w->focusPolicy() & TabFocus ) == TabFocus
+ && w->isVisibleTo(this) ) {
+ if ( w->hasFocus()
+#ifndef QT_NO_RADIOBUTTON
+ || ( !best && ::qt_cast<QRadioButton*>(w)
+ && ((QRadioButton*)w)->isChecked() )
+#endif
+ )
+ // 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;
+ }
+ w = fd->next();
+ } while( w != orig );
+ if ( best )
+ best->setFocus();
+ else if ( candidate )
+ candidate->setFocus();
+}
+
+
+/*
+ Sets the right frame rect depending on the title. Also calculates
+ the visible part of the title.
+*/
+void QGroupBox::calculateFrame()
+{
+ lenvisible = str.length();
+
+ if ( lenvisible && !isCheckable() ) { // do we have a label?
+ QFontMetrics fm = fontMetrics();
+ while ( lenvisible ) {
+ int tw = fm.width( str, lenvisible ) + 4*fm.width(QChar(' '));
+ if ( tw < width() )
+ break;
+ lenvisible--;
+ }
+ if ( lenvisible ) { // but do we also have a visible label?
+ QRect r = rect();
+ int va = style().styleHint(QStyle::SH_GroupBox_TextLabelVerticalAlignment, this);
+ if(va & AlignVCenter)
+ r.setTop( fm.height()/2 ); // frame rect should be
+ else if(va & AlignTop)
+ r.setTop(fm.ascent());
+ setFrameRect( r ); // smaller than client rect
+ return;
+ }
+ } else if ( isCheckable() ) {
+#ifndef QT_NO_CHECKBOX
+ QRect r = rect();
+ int va = style().styleHint(QStyle::SH_GroupBox_TextLabelVerticalAlignment, this);
+ if( va & AlignVCenter )
+ r.setTop( d->checkbox->rect().height()/2 );
+ else if( va & AlignTop )
+ r.setTop( fontMetrics().ascent() );
+ setFrameRect( r );
+ return;
+#endif
+ }
+
+ // no visible label
+ setFrameRect( QRect(0,0,0,0) ); // then use client rect
+}
+
+
+
+/*! \reimp
+ */
+void QGroupBox::focusInEvent( QFocusEvent * )
+{ // note no call to super
+ fixFocus();
+}
+
+
+/*!\reimp
+ */
+void QGroupBox::fontChange( const QFont & oldFont )
+{
+ QWidget::fontChange( oldFont );
+#ifndef QT_NO_CHECKBOX
+ updateCheckBoxGeometry();
+#endif
+ calculateFrame();
+ setTextSpacer();
+}
+
+/*!
+ \reimp
+*/
+
+QSize QGroupBox::sizeHint() const
+{
+ QFontMetrics fm( font() );
+ int tw, th;
+ if ( isCheckable() ) {
+#ifndef QT_NO_CHECKBOX
+ tw = d->checkbox->sizeHint().width() + 2*fm.width( "xx" );
+ th = d->checkbox->sizeHint().height() + fm.width( QChar(' ') );
+#endif
+ } else {
+ tw = fm.width( title() ) + 2 * fm.width( "xx" );
+ th = fm.height() + fm.width( QChar(' ') );
+ }
+
+ QSize s;
+ if ( layout() ) {
+ s = QFrame::sizeHint();
+ return s.expandedTo( QSize( tw, 0 ) );
+ } else {
+ QRect r = childrenRect();
+ QSize s( 100, 50 );
+ s = s.expandedTo( QSize( tw, th ) );
+ if ( r.isNull() )
+ return s;
+
+ return s.expandedTo( QSize( r.width() + 2 * r.x(), r.height()+ 2 * r.y() ) );
+ }
+}
+
+/*!
+ \property QGroupBox::flat
+ \brief whether the group box is painted flat or has a frame
+
+ By default a group box has a surrounding frame, with the title
+ being placed on the upper frame line. In flat mode the right, left
+ and bottom frame lines are omitted, and only the thin line at the
+ top is drawn.
+
+ \sa title
+*/
+bool QGroupBox::isFlat() const
+{
+ return bFlat;
+}
+
+void QGroupBox::setFlat( bool b )
+{
+ if ( (bool)bFlat == b )
+ return;
+ bFlat = b;
+ update();
+}
+
+
+/*!
+ \property QGroupBox::checkable
+ \brief Whether the group box has a checkbox in its title.
+
+ If this property is TRUE, the group box has a checkbox. If the
+ checkbox is checked (which is the default), the group box's
+ children are enabled.
+
+ setCheckable() controls whether or not the group box has a
+ checkbox, and isCheckable() controls whether the checkbox is
+ checked or not.
+*/
+#ifndef QT_NO_CHECKBOX
+void QGroupBox::setCheckable( bool b )
+{
+ if ( (d->checkbox != 0) == b )
+ return;
+
+ if ( b ) {
+ if ( !d->checkbox ) {
+ d->checkbox = new QCheckBox( title(), this, "qt_groupbox_checkbox" );
+ if (QButtonGroup *meAsButtonGroup = ::qt_cast<QButtonGroup*>(this))
+ meAsButtonGroup->remove(d->checkbox);
+ setChecked( TRUE );
+ setChildrenEnabled( TRUE );
+ connect( d->checkbox, SIGNAL( toggled(bool) ),
+ this, SLOT( setChildrenEnabled(bool) ) );
+ connect( d->checkbox, SIGNAL( toggled(bool) ),
+ this, SIGNAL( toggled(bool) ) );
+ updateCheckBoxGeometry();
+ }
+ d->checkbox->show();
+ } else {
+ setChildrenEnabled( TRUE );
+ delete d->checkbox;
+ d->checkbox = 0;
+ }
+ calculateFrame();
+ setTextSpacer();
+ update();
+}
+#endif //QT_NO_CHECKBOX
+
+bool QGroupBox::isCheckable() const
+{
+#ifndef QT_NO_CHECKBOX
+ return ( d->checkbox != 0 );
+#else
+ return FALSE;
+#endif
+}
+
+
+bool QGroupBox::isChecked() const
+{
+#ifndef QT_NO_CHECKBOX
+ return d->checkbox && d->checkbox->isChecked();
+#else
+ return FALSE;
+#endif
+}
+
+
+/*!
+ \fn void QGroupBox::toggled( bool on )
+
+ If the group box has a check box (see \l isCheckable()) this signal
+ is emitted when the check box is toggled. \a on is TRUE if the check
+ box is checked; otherwise it is FALSE.
+*/
+
+/*!
+ \property QGroupBox::checked
+ \brief Whether the group box's checkbox is checked.
+
+ If the group box has a check box (see \l isCheckable()), and the
+ check box is checked (see \l isChecked()), the group box's children
+ are enabled. If the checkbox is unchecked the children are
+ disabled.
+*/
+#ifndef QT_NO_CHECKBOX
+void QGroupBox::setChecked( bool b )
+{
+ if ( d->checkbox )
+ d->checkbox->setChecked( b );
+}
+#endif
+
+/*
+ sets all children of the group box except the qt_groupbox_checkbox
+ to either disabled/enabled
+*/
+void QGroupBox::setChildrenEnabled( bool b )
+{
+ if ( !children() )
+ return;
+ QObjectListIt it( *children() );
+ QObject *o;
+ while( (o = it.current()) ) {
+ ++it;
+ if ( o->isWidgetType()
+#ifndef QT_NO_CHECKBOX
+ && o != d->checkbox
+#endif
+ ) {
+ QWidget *w = (QWidget*)o;
+ if ( b ) {
+ if ( !w->testWState( WState_ForceDisabled ) )
+ w->setEnabled( TRUE );
+ } else {
+ if ( w->isEnabled() ) {
+ w->setEnabled( FALSE );
+ ((QGroupBox*)w)->clearWState( WState_ForceDisabled );
+ }
+ }
+ }
+ }
+}
+
+/*! \reimp */
+void QGroupBox::setEnabled(bool on)
+{
+ QFrame::setEnabled(on);
+ if ( !d->checkbox || !on )
+ return;
+
+#ifndef QT_NO_CHECKBOX
+ // we are being enabled - disable children
+ if ( !d->checkbox->isChecked() )
+ setChildrenEnabled( FALSE );
+#endif
+}
+
+/*
+ recalculates and sets the checkbox setGeometry
+*/
+#ifndef QT_NO_CHECKBOX
+void QGroupBox::updateCheckBoxGeometry()
+{
+ if ( d->checkbox ) {
+ QSize cbSize = d->checkbox->sizeHint();
+ QRect cbRect( 0, 0, cbSize.width(), cbSize.height() );
+
+ int marg = bFlat ? 2 : 8;
+ marg += fontMetrics().width( QChar(' ') );
+
+ if ( align & AlignHCenter ) {
+ cbRect.moveCenter( frameRect().center() );
+ cbRect.moveTop( 0 );
+ } else if ( align & AlignRight ) {
+ cbRect.moveRight( frameRect().right() - marg );
+ } else if ( align & AlignLeft ) {
+ cbRect.moveLeft( frameRect().left() + marg );
+ } else { // auto align
+ if( QApplication::reverseLayout() )
+ cbRect.moveRight( frameRect().right() - marg );
+ else
+ cbRect.moveLeft( frameRect().left() + marg );
+ }
+
+ d->checkbox->setGeometry( cbRect );
+ }
+}
+#endif //QT_NO_CHECKBOX
+
+
+#endif //QT_NO_GROUPBOX
diff --git a/src/widgets/qgroupbox.h b/src/widgets/qgroupbox.h
new file mode 100644
index 0000000..ba464ef
--- /dev/null
+++ b/src/widgets/qgroupbox.h
@@ -0,0 +1,165 @@
+/**********************************************************************
+**
+** Definition of QGroupBox widget class
+**
+** Created : 950203
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QGROUPBOX_H
+#define QGROUPBOX_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_GROUPBOX
+
+
+class QAccel;
+class QGroupBoxPrivate;
+class QVBoxLayout;
+class QGridLayout;
+class QSpacerItem;
+
+class Q_EXPORT QGroupBox : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( QString title READ title WRITE setTitle )
+ Q_PROPERTY( Alignment alignment READ alignment WRITE setAlignment )
+ Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation DESIGNABLE false )
+ Q_PROPERTY( int columns READ columns WRITE setColumns DESIGNABLE false )
+ Q_PROPERTY( bool flat READ isFlat WRITE setFlat )
+#ifndef QT_NO_CHECKBOX
+ Q_PROPERTY( bool checkable READ isCheckable WRITE setCheckable )
+ Q_PROPERTY( bool checked READ isChecked WRITE setChecked )
+#endif
+public:
+ QGroupBox( QWidget* parent=0, const char* name=0 );
+ QGroupBox( const QString &title,
+ QWidget* parent=0, const char* name=0 );
+ QGroupBox( int strips, Orientation o,
+ QWidget* parent=0, const char* name=0 );
+ QGroupBox( int strips, Orientation o, const QString &title,
+ QWidget* parent=0, const char* name=0 );
+ ~QGroupBox();
+
+ virtual void setColumnLayout(int strips, Orientation o);
+
+ QString title() const { return str; }
+ virtual void setTitle( const QString &);
+
+ int alignment() const { return align; }
+ virtual void setAlignment( int );
+
+ int columns() const;
+ void setColumns( int );
+
+ Orientation orientation() const { return dir; }
+ void setOrientation( Orientation );
+
+ int insideMargin() const;
+ int insideSpacing() const;
+ void setInsideMargin( int m );
+ void setInsideSpacing( int s );
+
+ void addSpace( int );
+ QSize sizeHint() const;
+
+ bool isFlat() const;
+ void setFlat( bool b );
+ bool isCheckable() const;
+#ifndef QT_NO_CHECKBOX
+ void setCheckable( bool b );
+#endif
+ bool isChecked() const;
+ void setEnabled(bool on);
+
+#ifndef QT_NO_CHECKBOX
+public slots:
+ void setChecked( bool b );
+
+signals:
+ void toggled( bool );
+#endif
+protected:
+ bool event( QEvent * );
+ void childEvent( QChildEvent * );
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+ void focusInEvent( QFocusEvent * );
+ void fontChange( const QFont & );
+
+private slots:
+ void fixFocus();
+ void setChildrenEnabled( bool b );
+
+private:
+ void skip();
+ void init();
+ void calculateFrame();
+ void insertWid( QWidget* );
+ void setTextSpacer();
+#ifndef QT_NO_CHECKBOX
+ void updateCheckBoxGeometry();
+#endif
+ QString str;
+ int align;
+ int lenvisible;
+#ifndef QT_NO_ACCEL
+ QAccel * accel;
+#endif
+ QGroupBoxPrivate * d;
+
+ QVBoxLayout *vbox;
+ QGridLayout *grid;
+ int row;
+ int col : 30;
+ uint bFlat : 1;
+ int nRows, nCols;
+ Orientation dir;
+ int spac, marg;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QGroupBox( const QGroupBox & );
+ QGroupBox &operator=( const QGroupBox & );
+#endif
+};
+
+
+#endif // QT_NO_GROUPBOX
+
+#endif // QGROUPBOX_H
diff --git a/src/widgets/qhbox.cpp b/src/widgets/qhbox.cpp
new file mode 100644
index 0000000..bed032b
--- /dev/null
+++ b/src/widgets/qhbox.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qhbox.h"
+#ifndef QT_NO_HBOX
+#include "qlayout.h"
+#include "qapplication.h"
+#include "qobjectlist.h"
+
+
+/*!
+ \class QHBox qhbox.h
+ \brief The QHBox widget provides horizontal geometry management
+ for its child widgets.
+
+ \ingroup organizers
+ \ingroup geomanagement
+ \ingroup appearance
+
+ All the horizontal box's child widgets will be placed alongside
+ each other and sized according to their sizeHint()s.
+
+ Use setMargin() to add space around the edges, and use
+ setSpacing() to add space between the widgets. Use
+ setStretchFactor() if you want the widgets to be different sizes
+ in proportion to one another. (See \link layout.html
+ Layouts\endlink for more information on stretch factors.)
+
+ \img qhbox-m.png QHBox
+
+ \sa QHBoxLayout QVBox QGrid
+*/
+
+
+/*!
+ Constructs an hbox widget with parent \a parent, called \a name.
+ The parent, name and widget flags, \a f, are passed to the QFrame
+ constructor.
+*/
+QHBox::QHBox( QWidget *parent, const char *name, WFlags f )
+ :QFrame( parent, name, f )
+{
+ lay = new QHBoxLayout( this, frameWidth(), frameWidth(), name );
+ lay->setAutoAdd( TRUE );
+}
+
+
+/*!
+ Constructs a horizontal hbox if \a horizontal is TRUE, otherwise
+ constructs a vertical hbox (also known as a vbox).
+
+ This constructor is provided for the QVBox class. You should never
+ need to use it directly.
+
+ The \a parent, \a name and widget flags, \a f, are passed to the
+ QFrame constructor.
+*/
+
+QHBox::QHBox( bool horizontal, QWidget *parent , const char *name, WFlags f )
+ :QFrame( parent, name, f )
+{
+ lay = new QBoxLayout( this,
+ horizontal ? QBoxLayout::LeftToRight : QBoxLayout::Down,
+ frameWidth(), frameWidth(), name );
+ lay->setAutoAdd( TRUE );
+}
+
+/*!\reimp
+ */
+void QHBox::frameChanged()
+{
+ if ( !layout() )
+ return;
+ layout()->setMargin( frameWidth() );
+}
+
+
+/*!
+ Sets the spacing between the child widgets to \a space.
+*/
+
+void QHBox::setSpacing( int space )
+{
+ if ( layout() ) // ### why not use this->lay?
+ layout()->setSpacing( space );
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize QHBox::sizeHint() const
+{
+ QWidget *mThis = (QWidget*)this;
+ QApplication::sendPostedEvents( mThis, QEvent::ChildInserted );
+ return QFrame::sizeHint();
+}
+
+/*!
+ Sets the stretch factor of widget \a w to \a stretch. Returns TRUE if
+ \a w is found. Otherwise returns FALSE.
+
+ \sa QBoxLayout::setStretchFactor() \link layout.html Layouts\endlink
+*/
+bool QHBox::setStretchFactor( QWidget* w, int stretch )
+{
+ QWidget *mThis = (QWidget*)this;
+ QApplication::sendPostedEvents( mThis, QEvent::ChildInserted );
+ return lay->setStretchFactor( w, stretch );
+}
+#endif
diff --git a/src/widgets/qhbox.h b/src/widgets/qhbox.h
new file mode 100644
index 0000000..f52e358
--- /dev/null
+++ b/src/widgets/qhbox.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+
+#ifndef QHBOX_H
+#define QHBOX_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+
+#ifndef QT_NO_HBOX
+
+#include "qframe.h"
+
+class QBoxLayout;
+
+class Q_EXPORT QHBox : public QFrame
+{
+ Q_OBJECT
+public:
+ QHBox( QWidget* parent=0, const char* name=0, WFlags f=0 );
+
+ void setSpacing( int );
+ bool setStretchFactor( QWidget*, int stretch );
+ QSize sizeHint() const;
+
+protected:
+ QHBox( bool horizontal, QWidget* parent, const char* name, WFlags f = 0 );
+ void frameChanged();
+
+private:
+ QBoxLayout *lay;
+
+#if defined(Q_DISABLE_COPY)
+ QHBox( const QHBox & );
+ QHBox &operator=( const QHBox & );
+#endif
+};
+
+#endif // QT_NO_HBOX
+
+#endif // QHBOX_H
diff --git a/src/widgets/qhbuttongroup.cpp b/src/widgets/qhbuttongroup.cpp
new file mode 100644
index 0000000..d300833
--- /dev/null
+++ b/src/widgets/qhbuttongroup.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Implementation of QHButtonGroup class
+**
+** Created : 990602
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qhbuttongroup.h"
+#ifndef QT_NO_HBUTTONGROUP
+
+/*!
+ \class QHButtonGroup qhbuttongroup.h
+ \brief The QHButtonGroup widget organizes QButton widgets in a
+ group with one horizontal row.
+
+ \ingroup organizers
+ \ingroup geomanagement
+ \ingroup appearance
+
+ QHButtonGroup is a convenience class that offers a thin layer on
+ top of QButtonGroup. From a layout point of view it is effectively
+ a QHBox that offers a frame with a title and is specifically
+ designed for buttons. From a functionality point of view it is a
+ QButtonGroup.
+
+ \img qbuttongroup-h.png QButtonGroup
+
+ \sa QVButtonGroup
+*/
+
+/*!
+ Constructs a horizontal button group with no title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+QHButtonGroup::QHButtonGroup( QWidget *parent, const char *name )
+ : QButtonGroup( 1, Vertical /* sic! */, parent, name )
+{
+}
+
+/*!
+ Constructs a horizontal button group with the title \a title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QHButtonGroup::QHButtonGroup( const QString &title, QWidget *parent,
+ const char *name )
+ : QButtonGroup( 1, Vertical /* sic! */, title, parent, name )
+{
+}
+
+/*!
+ Destroys the horizontal button group, deleting its child widgets.
+*/
+QHButtonGroup::~QHButtonGroup()
+{
+}
+#endif
diff --git a/src/widgets/qhbuttongroup.h b/src/widgets/qhbuttongroup.h
new file mode 100644
index 0000000..839c026
--- /dev/null
+++ b/src/widgets/qhbuttongroup.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Definition of QHButtonGroup class
+**
+** Created : 990602
+**
+** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QHBUTTONGROUP_H
+#define QHBUTTONGROUP_H
+
+#ifndef QT_H
+#include "qbuttongroup.h"
+#endif // QT_H
+
+#ifndef QT_NO_HBUTTONGROUP
+
+class Q_EXPORT QHButtonGroup : public QButtonGroup
+{
+ Q_OBJECT
+public:
+ QHButtonGroup( QWidget* parent=0, const char* name=0 );
+ QHButtonGroup( const QString &title, QWidget* parent=0, const char* name=0 );
+ ~QHButtonGroup();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QHButtonGroup( const QHButtonGroup & );
+ QHButtonGroup &operator=( const QHButtonGroup & );
+#endif
+};
+
+
+#endif // QT_NO_HBUTTONGROUP
+
+#endif // QHBUTTONGROUP_H
diff --git a/src/widgets/qheader.cpp b/src/widgets/qheader.cpp
new file mode 100644
index 0000000..82fd012
--- /dev/null
+++ b/src/widgets/qheader.cpp
@@ -0,0 +1,2049 @@
+/****************************************************************************
+**
+** Implementation of QHeader widget class (table header)
+**
+** Created : 961105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qheader.h"
+#ifndef QT_NO_HEADER
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qpixmap.h"
+#include "qbitarray.h"
+#include "qptrvector.h"
+#include "qapplication.h"
+#include "qstyle.h"
+
+class QHeaderData
+{
+public:
+ QHeaderData(int n)
+ {
+ count = n;
+ labels.setAutoDelete( TRUE );
+ iconsets.setAutoDelete( TRUE );
+ sizes.resize(n);
+ positions.resize(n);
+ labels.resize(n);
+ if ( int( iconsets.size() ) < n )
+ iconsets.resize( n );
+ i2s.resize(n);
+ s2i.resize(n);
+ clicks.resize(n);
+ resize.resize(n);
+ int p =0;
+ for ( int i = 0; i < n; i ++ ) {
+ sizes[i] = 88;
+ i2s[i] = i;
+ s2i[i] = i;
+ positions[i] = p;
+ p += sizes[i];
+ }
+ clicks_default = TRUE;
+ resize_default = TRUE;
+ clicks.fill( clicks_default );
+ resize.fill( resize_default );
+ move = TRUE;
+ sortSection = -1;
+ sortDirection = TRUE;
+ positionsDirty = TRUE;
+ lastPos = 0;
+ fullSize = -2;
+ pos_dirty = FALSE;
+ is_a_table_header = FALSE;
+ focusIdx = 0;
+ }
+
+
+ QMemArray<QCOORD> sizes;
+ int height; // we abuse the heights as widths for vertical layout
+ bool heightDirty;
+ QMemArray<QCOORD> positions; // sorted by index
+ QPtrVector<QString> labels;
+ QPtrVector<QIconSet> iconsets;
+ QMemArray<int> i2s;
+ QMemArray<int> s2i;
+
+ QBitArray clicks;
+ QBitArray resize;
+ uint move : 1;
+ uint clicks_default : 1; // default value for new clicks bits
+ uint resize_default : 1; // default value for new resize bits
+ uint pos_dirty : 1;
+ uint is_a_table_header : 1;
+ bool sortDirection;
+ bool positionsDirty;
+ int sortSection;
+ int count;
+ int lastPos;
+ int fullSize;
+ int focusIdx;
+ int pressDelta;
+
+ int sectionAt( int pos ) {
+ // positions is sorted by index, not by section
+ if ( !count )
+ return -1;
+ int l = 0;
+ int r = count - 1;
+ int i = ( (l+r+1) / 2 );
+ while ( r - l ) {
+ if ( positions[i] > pos )
+ r = i -1;
+ else
+ l = i;
+ i = ( (l+r+1) / 2 );
+ }
+ if ( positions[i] <= pos && pos <= positions[i] + sizes[ i2s[i] ] )
+ return i2s[i];
+ return -1;
+ }
+};
+
+
+/*!
+ \class QHeader qheader.h
+ \brief The QHeader class provides a header row or column, e.g. for
+ tables and listviews.
+
+ \ingroup advanced
+
+ This class provides a header, e.g. a vertical header to display
+ row labels, or a horizontal header to display column labels. It is
+ used by QTable and QListView for example.
+
+ A header is composed of one or more \e sections, each of which can
+ display a text label and an \link QIconSet iconset\endlink. A sort
+ indicator (an arrow) can also be displayed using
+ setSortIndicator().
+
+ Sections are added with addLabel() and removed with removeLabel().
+ The label and iconset are set in addLabel() and can be changed
+ later with setLabel(). Use count() to retrieve the number of
+ sections in the header.
+
+ The orientation of the header is set with setOrientation(). If
+ setStretchEnabled() is TRUE, the sections will expand to take up
+ the full width (height for vertical headers) of the header. The
+ user can resize the sections manually if setResizeEnabled() is
+ TRUE. Call adjustHeaderSize() to have the sections resize to
+ occupy the full width (or height).
+
+ A section can be moved with moveSection(). If setMovingEnabled()
+ is TRUE (the default)the user may drag a section from one position
+ to another. If a section is moved, the index positions at which
+ sections were added (with addLabel()), may not be the same after the
+ move. You don't have to worry about this in practice because the
+ QHeader API works in terms of section numbers, so it doesn't matter
+ where a particular section has been moved to.
+
+ If you want the current index position of a section call
+ mapToIndex() giving it the section number. (This is the number
+ returned by the addLabel() call which created the section.) If you
+ want to get the section number of a section at a particular index
+ position call mapToSection() giving it the index number.
+
+ Here's an example to clarify mapToSection() and mapToIndex():
+
+ \table
+ \header \i41 Index positions
+ \row \i 0 \i 1 \i 2 \i 3
+ \header \i41 Original section ordering
+ \row \i Sect 0 \i Sect 1 \i Sect 2 \i Sect 3
+ \header \i41 Ordering after the user moves a section
+ \row \i Sect 0 \i Sect 2 \i Sect 3 \i Sect 1
+ \endtable
+
+ \table
+ \header \i \e k \i mapToSection(\e k) \i mapToIndex(\e k)
+ \row \i 0 \i 0 \i 0
+ \row \i 1 \i 2 \i 3
+ \row \i 2 \i 3 \i 1
+ \row \i 3 \i 1 \i 2
+ \endtable
+
+ In the example above, if we wanted to find out which section is at
+ index position 3 we'd call mapToSection(3) and get a section
+ number of 1 since section 1 was moved. Similarly, if we wanted to
+ know which index position section 2 occupied we'd call
+ mapToIndex(2) and get an index of 1.
+
+ QHeader provides the clicked(), pressed() and released() signals.
+ If the user changes the size of a section, the sizeChange() signal
+ is emitted. If you want to have a sizeChange() signal emitted
+ continuously whilst the user is resizing (rather than just after
+ the resizing is finished), use setTracking(). If the user moves a
+ section the indexChange() signal is emitted.
+
+ <img src=qheader-m.png> <img src=qheader-w.png>
+
+ \sa QListView QTable
+*/
+
+
+
+/*!
+ Constructs a horizontal header called \a name, with parent \a
+ parent.
+*/
+
+QHeader::QHeader( QWidget *parent, const char *name )
+ : QWidget( parent, name, WStaticContents )
+{
+ orient = Horizontal;
+ init( 0 );
+}
+
+/*!
+ Constructs a horizontal header called \a name, with \a n sections
+ and parent \a parent.
+*/
+
+QHeader::QHeader( int n, QWidget *parent, const char *name )
+ : QWidget( parent, name, WStaticContents )
+{
+ orient = Horizontal;
+ init( n );
+}
+
+/*!
+ Destroys the header and all its sections.
+*/
+
+QHeader::~QHeader()
+{
+ delete d;
+ d = 0;
+}
+
+/*! \reimp
+ */
+
+void QHeader::showEvent( QShowEvent *e )
+{
+ calculatePositions();
+ QWidget::showEvent( e );
+}
+
+/*!
+ \fn void QHeader::sizeChange( int section, int oldSize, int newSize )
+
+ This signal is emitted when the user has changed the size of a \a
+ section from \a oldSize to \a newSize. This signal is typically
+ connected to a slot that repaints the table or list that contains
+ the header.
+*/
+
+/*!
+ \fn void QHeader::clicked( int section )
+
+ If isClickEnabled() is TRUE, this signal is emitted when the user
+ clicks section \a section.
+
+ \sa pressed(), released()
+*/
+
+/*!
+ \fn void QHeader::pressed( int section )
+
+ This signal is emitted when the user presses section \a section
+ down.
+
+ \sa released()
+*/
+
+/*!
+ \fn void QHeader::released( int section )
+
+ This signal is emitted when section \a section is released.
+
+ \sa pressed()
+*/
+
+
+/*!
+ \fn void QHeader::indexChange( int section, int fromIndex, int toIndex )
+
+ This signal is emitted when the user moves section \a section from
+ index position \a fromIndex, to index position \a toIndex.
+*/
+
+/*!
+ \fn void QHeader::moved( int fromIndex, int toIndex )
+ \obsolete
+
+ Use indexChange() instead.
+
+ This signal is emitted when the user has moved the section which
+ is displayed at the index \a fromIndex to the index \a toIndex.
+*/
+
+/*!
+ \fn void QHeader::sectionClicked( int index )
+ \obsolete
+
+ Use clicked() instead.
+
+ This signal is emitted when a part of the header is clicked. \a
+ index is the index at which the section is displayed.
+
+ In a list view this signal would typically be connected to a slot
+ that sorts the specified column (or row).
+*/
+
+/*! \fn int QHeader::cellSize( int ) const
+ \obsolete
+
+ Use sectionSize() instead.
+
+ Returns the size in pixels of the section that is displayed at
+ the index \a i.
+*/
+
+/*!
+ \fn void QHeader::sectionHandleDoubleClicked( int section )
+
+ This signal is emitted when the user doubleclicks on the edge
+ (handle) of section \a section.
+*/
+
+/*!
+ \obsolete
+
+ Use sectionPos() instead.
+
+ Returns the position in pixels of the section that is displayed at the
+ index \a i. The position is measured from the start of the header.
+*/
+
+int QHeader::cellPos( int i ) const
+{
+ if ( i == count() && i > 0 )
+ return d->positions[i-1] + d->sizes[d->i2s[i-1]]; // compatibility
+ return sectionPos( mapToSection(i) );
+}
+
+
+/*!
+ \property QHeader::count
+ \brief the number of sections in the header
+*/
+
+int QHeader::count() const
+{
+ return d->count;
+}
+
+
+/*!
+ \property QHeader::tracking
+ \brief whether the sizeChange() signal is emitted continuously
+
+ If tracking is on, the sizeChange() signal is emitted continuously
+ while the mouse is moved (i.e. when the header is resized),
+ otherwise it is only emitted when the mouse button is released at
+ the end of resizing.
+
+ Tracking defaults to FALSE.
+*/
+
+
+/*
+ Initializes with \a n columns.
+*/
+void QHeader::init( int n )
+{
+ state = Idle;
+ cachedPos = 0; // unused
+ d = new QHeaderData( n );
+ d->height = 0;
+ d->heightDirty = TRUE;
+ offs = 0;
+ if( reverse() )
+ offs = d->lastPos - width();
+ oldHandleIdx = oldHIdxSize = handleIdx = 0;
+
+ setMouseTracking( TRUE );
+ trackingIsOn = FALSE;
+ setBackgroundMode( PaletteButton );
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+}
+
+/*!
+ \property QHeader::orientation
+ \brief the header's orientation
+
+ The orientation is either \c Vertical or \c Horizontal (the
+ default).
+
+ Call setOrientation() before adding labels if you don't provide a
+ size parameter otherwise the sizes will be incorrect.
+*/
+
+void QHeader::setOrientation( Orientation orientation )
+{
+ if ( orient == orientation )
+ return;
+ orient = orientation;
+ if ( orient == Horizontal )
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+ else
+ setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred ) );
+ update();
+ updateGeometry();
+}
+
+
+/*
+ Paints a rectangle starting at \a p, with length \s.
+*/
+void QHeader::paintRect( int p, int s )
+{
+ QPainter paint( this );
+ paint.setPen( QPen( black, 1, DotLine ) );
+ if ( reverse() )
+ paint.drawRect( p - s, 3, s, height() - 5 );
+ else if ( orient == Horizontal )
+ paint.drawRect( p, 3, s, height() - 5 );
+ else
+ paint.drawRect( 3, p, height() - 5, s );
+}
+
+/*
+ Marks the division line at \a idx.
+*/
+void QHeader::markLine( int idx )
+{
+ QPainter paint( this );
+ paint.setPen( QPen( black, 1, DotLine ) );
+ int MARKSIZE = style().pixelMetric( QStyle::PM_HeaderMarkSize );
+ int p = pPos( idx );
+ int x = p - MARKSIZE/2;
+ int y = 2;
+ int x2 = p + MARKSIZE/2;
+ int y2 = height() - 3;
+ if ( orient == Vertical ) {
+ int t = x; x = y; y = t;
+ t = x2; x2 = y2; y2 = t;
+ }
+
+ paint.drawLine( x, y, x2, y );
+ paint.drawLine( x, y+1, x2, y+1 );
+
+ paint.drawLine( x, y2, x2, y2 );
+ paint.drawLine( x, y2-1, x2, y2-1 );
+
+ paint.drawLine( x, y, x, y2 );
+ paint.drawLine( x+1, y, x+1, y2 );
+
+ paint.drawLine( x2, y, x2, y2 );
+ paint.drawLine( x2-1, y, x2-1, y2 );
+}
+
+/*
+ Removes the mark at the division line at \a idx.
+*/
+void QHeader::unMarkLine( int idx )
+{
+ if ( idx < 0 )
+ return;
+ int MARKSIZE = style().pixelMetric( QStyle::PM_HeaderMarkSize );
+ int p = pPos( idx );
+ int x = p - MARKSIZE/2;
+ int y = 2;
+ int x2 = p + MARKSIZE/2;
+ int y2 = height() - 3;
+ if ( orient == Vertical ) {
+ int t = x; x = y; y = t;
+ t = x2; x2 = y2; y2 = t;
+ }
+ repaint( x, y, x2-x+1, y2-y+1 );
+}
+
+/*! \fn int QHeader::cellAt( int ) const
+ \obsolete
+
+ Use sectionAt() instead.
+
+ Returns the index at which the section is displayed, which contains
+ \a pos in widget coordinates, or -1 if \a pos is outside the header
+ sections.
+*/
+
+/*
+ Tries to find a line that is not a neighbor of \c handleIdx.
+*/
+int QHeader::findLine( int c )
+{
+ int i = 0;
+ if ( c > d->lastPos || (reverse() && c < 0 )) {
+ return d->count;
+ } else {
+ int section = sectionAt( c );
+ if ( section < 0 )
+ return handleIdx;
+ i = d->s2i[section];
+ }
+ int MARKSIZE = style().pixelMetric( QStyle::PM_HeaderMarkSize );
+ if ( i == handleIdx )
+ return i;
+ if ( i == handleIdx - 1 && pPos( handleIdx ) - c > MARKSIZE/2 )
+ return i;
+ if ( i == handleIdx + 1 && c - pPos( i ) > MARKSIZE/2 )
+ return i + 1;
+ if ( c - pPos( i ) > pSize( i ) / 2 )
+ return i + 1;
+ else
+ return i;
+}
+
+/*!
+ Returns the handle at position \a p, or -1 if there is no handle at \a p.
+*/
+int QHeader::handleAt(int p)
+{
+ int section = d->sectionAt( p );
+ if ( section >= 0 ) {
+ int GripMargin = (bool)d->resize[ section ] ?
+ style().pixelMetric( QStyle::PM_HeaderGripMargin ) : 0;
+ int index = d->s2i[section];
+ if ( (index > 0 && p < d->positions[index] + GripMargin) ||
+ (p > d->positions[index] + d->sizes[section] - GripMargin) ) {
+ if ( index > 0 && p < d->positions[index] + GripMargin )
+ section = d->i2s[--index];
+ // dont show icon if streaching is enabled it is at the end of the last section
+ if ( d->resize.testBit(section) && (d->fullSize == -2 || index != count() - 1)) {
+ return section;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/*!
+ \obsolete
+
+ Use moveSection() instead.
+
+ Moves the section that is currently displayed at index \a fromIdx
+ to index \a toIdx.
+*/
+
+void QHeader::moveCell( int fromIdx, int toIdx )
+{
+ moveSection( mapToSection(fromIdx), toIdx );
+}
+
+
+
+/*!
+ Move and signal and repaint.
+ */
+
+void QHeader::handleColumnMove( int fromIdx, int toIdx )
+{
+ int s = d->i2s[fromIdx];
+ if ( fromIdx < toIdx )
+ toIdx++; //Convert to
+ QRect r = sRect( fromIdx );
+ r |= sRect( toIdx );
+ moveSection( s, toIdx );
+ update( r );
+ emit moved( fromIdx, toIdx );
+ emit indexChange( s, fromIdx, toIdx );
+}
+
+/*!
+ \reimp
+*/
+void QHeader::keyPressEvent( QKeyEvent *e )
+{
+ int i = d->focusIdx;
+ if ( e->key() == Key_Space ) {
+ //don't do it if we're doing something with the mouse
+ if ( state == Idle && d->clicks[ d->i2s[d->focusIdx] ] ) {
+ handleIdx = i;
+ state = Pressed;
+ repaint( sRect( handleIdx ) );
+ emit pressed( d->i2s[i] );
+ }
+ } else if ( orientation() == Horizontal &&
+ (e->key() == Key_Right || e->key() == Key_Left)
+ || orientation() == Vertical &&
+ (e->key() == Key_Up || e->key() == Key_Down) ) {
+ int dir = e->key() == Key_Right || e->key() == Key_Down ? 1 : -1;
+ int s = d->i2s[i];
+ if ( e->state() & ControlButton && d->resize[s] ) {
+ //resize
+ int step = e->state() & ShiftButton ? dir : 10*dir;
+ int c = d->positions[i] + d->sizes[s] + step;
+ handleColumnResize( i, c, TRUE );
+ } else if ( e->state() & (AltButton|MetaButton) && d->move ) {
+ //move section
+ int i2 = ( i + count() + dir ) % count();
+ d->focusIdx = i2;
+ handleColumnMove( i, i2 );
+ } else {
+ //focus on different section
+ QRect r = sRect( d->focusIdx );
+ d->focusIdx = (d->focusIdx + count() + dir) % count();
+ r |= sRect( d->focusIdx );
+ update( r );
+ }
+ } else {
+ e->ignore();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QHeader::keyReleaseEvent( QKeyEvent *e )
+{
+ switch ( e->key() ) {
+ case Key_Space:
+ //double check that this wasn't started with the mouse
+ if ( state == Pressed && handleIdx == d->focusIdx ) {
+ repaint(sRect( handleIdx ), FALSE);
+ int section = d->i2s[d->focusIdx];
+ emit released( section );
+ emit sectionClicked( handleIdx );
+ emit clicked( section );
+ state = Idle;
+ handleIdx = -1;
+ }
+ break;
+ default:
+ e->ignore();
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QHeader::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton || state != Idle )
+ return;
+ oldHIdxSize = handleIdx;
+ handleIdx = 0;
+ int c = orient == Horizontal ? e->pos().x() : e->pos().y();
+ c += offset();
+ if ( reverse() )
+ c = d->lastPos - c;
+
+ int section = d->sectionAt( c );
+ if ( section < 0 )
+ return;
+ int GripMargin = (bool)d->resize[ section ] ?
+ style().pixelMetric( QStyle::PM_HeaderGripMargin ) : 0;
+ int index = d->s2i[section];
+
+ if ( (index > 0 && c < d->positions[index] + GripMargin) ||
+ (c > d->positions[index] + d->sizes[section] - GripMargin) ) {
+ if ( c < d->positions[index] + GripMargin )
+ handleIdx = index-1;
+ else
+ handleIdx = index;
+ if ( d->lastPos <= ( orient == Horizontal ? width() :
+ height() ) && d->fullSize != -2 && handleIdx == count() - 1 ) {
+ handleIdx = -1;
+ return;
+ }
+ oldHIdxSize = d->sizes[ d->i2s[handleIdx] ];
+ state = d->resize[ d->i2s[handleIdx] ] ? Sliding : Blocked;
+ } else if ( index >= 0 ) {
+ oldHandleIdx = handleIdx = index;
+ moveToIdx = -1;
+ state = d->clicks[ d->i2s[handleIdx] ] ? Pressed : Blocked;
+ clickPos = c;
+ repaint( sRect( handleIdx ) );
+ if(oldHandleIdx != handleIdx)
+ repaint( sRect( oldHandleIdx ) );
+ emit pressed( section );
+ }
+
+ d->pressDelta = c - ( d->positions[handleIdx] + d->sizes[ d->i2s[handleIdx] ] );
+}
+
+/*!
+ \reimp
+*/
+void QHeader::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+ int oldOldHandleIdx = oldHandleIdx;
+ State oldState = state;
+ state = Idle;
+ switch ( oldState ) {
+ case Pressed: {
+ int section = d->i2s[handleIdx];
+ emit released( section );
+ if ( sRect( handleIdx ).contains( e->pos() ) ) {
+ oldHandleIdx = handleIdx;
+ emit sectionClicked( handleIdx );
+ emit clicked( section );
+ } else {
+ handleIdx = oldHandleIdx;
+ }
+ repaint(sRect( handleIdx ), FALSE);
+ if ( oldOldHandleIdx != handleIdx )
+ repaint(sRect(oldOldHandleIdx ), FALSE );
+ } break;
+ case Sliding: {
+ int c = orient == Horizontal ? e->pos().x() : e->pos().y();
+ c += offset();
+ if ( reverse() )
+ c = d->lastPos - c;
+ handleColumnResize( handleIdx, c - d->pressDelta, TRUE );
+ } break;
+ case Moving: {
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ int section = d->i2s[handleIdx];
+ if ( handleIdx != moveToIdx && moveToIdx != -1 ) {
+ moveSection( section, moveToIdx );
+ handleIdx = oldHandleIdx;
+ emit moved( handleIdx, moveToIdx );
+ emit indexChange( section, handleIdx, moveToIdx );
+ emit released( section );
+ repaint(); // a bit overkill, but removes the handle as well
+ } else {
+ if ( sRect( handleIdx).contains( e->pos() ) ) {
+ oldHandleIdx = handleIdx;
+ emit released( section );
+ emit sectionClicked( handleIdx );
+ emit clicked( section );
+ } else {
+ handleIdx = oldHandleIdx;
+ }
+ repaint(sRect( handleIdx ), FALSE );
+ if(oldOldHandleIdx != handleIdx)
+ repaint(sRect(oldOldHandleIdx ), FALSE );
+ }
+ break;
+ }
+ case Blocked:
+ //nothing
+ break;
+ default:
+ // empty, probably. Idle, at any rate.
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QHeader::mouseMoveEvent( QMouseEvent *e )
+{
+ int c = orient == Horizontal ? e->pos().x() : e->pos().y();
+ c += offset();
+
+ int pos = c;
+ if( reverse() )
+ c = d->lastPos - c;
+
+ switch( state ) {
+ case Idle:
+#ifndef QT_NO_CURSOR
+ if ( handleAt(c) < 0 )
+ unsetCursor();
+ else if ( orient == Horizontal )
+ setCursor( splitHCursor );
+ else
+ setCursor( splitVCursor );
+#endif
+ break;
+ case Blocked:
+ break;
+ case Pressed:
+ if ( QABS( c - clickPos ) > 4 && d->move ) {
+ state = Moving;
+ moveToIdx = -1;
+#ifndef QT_NO_CURSOR
+ if ( orient == Horizontal )
+ setCursor( sizeHorCursor );
+ else
+ setCursor( sizeVerCursor );
+#endif
+ }
+ break;
+ case Sliding:
+ handleColumnResize( handleIdx, c, FALSE, FALSE );
+ break;
+ case Moving: {
+ int newPos = findLine( pos );
+ if ( newPos != moveToIdx ) {
+ if ( moveToIdx == handleIdx || moveToIdx == handleIdx + 1 )
+ repaint( sRect(handleIdx) );
+ else
+ unMarkLine( moveToIdx );
+ moveToIdx = newPos;
+ if ( moveToIdx == handleIdx || moveToIdx == handleIdx + 1 )
+ paintRect( pPos( handleIdx ), pSize( handleIdx ) );
+ else
+ markLine( moveToIdx );
+ }
+ break;
+ }
+ default:
+ qWarning( "QHeader::mouseMoveEvent: (%s) unknown state", name() );
+ break;
+ }
+}
+
+/*! \reimp */
+
+void QHeader::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ int p = orient == Horizontal ? e->pos().x() : e->pos().y();
+ p += offset();
+ if( reverse() )
+ p = d->lastPos - p;
+
+ int header = handleAt(p);
+ if (header >= 0)
+ emit sectionHandleDoubleClicked( header );
+}
+
+/*
+ Handles resizing of sections. This means it redraws the relevant parts
+ of the header.
+*/
+
+void QHeader::handleColumnResize( int index, int c, bool final, bool recalcAll )
+{
+ int section = d->i2s[index];
+ int GripMargin = (bool)d->resize[ section ] ?
+ style().pixelMetric( QStyle::PM_HeaderGripMargin ) : 0;
+ int lim = d->positions[index] + 2*GripMargin;
+ if ( c == lim )
+ return;
+ if ( c < lim )
+ c = lim;
+ int oldSize = d->sizes[section];
+ int newSize = c - d->positions[index];
+ d->sizes[section] = newSize;
+
+ calculatePositions( !recalcAll, !recalcAll ? section : 0 );
+
+ int pos = d->positions[index]-offset();
+ if( reverse() ) // repaint the whole thing. Could be optimized (lars)
+ repaint( 0, 0, width(), height() );
+ else if ( orient == Horizontal )
+ repaint( pos, 0, width() - pos, height() );
+ else
+ repaint( 0, pos, width(), height() - pos );
+
+ int os = 0, ns = 0;
+ if ( tracking() && oldSize != newSize ) {
+ os = oldSize;
+ ns = newSize;
+ emit sizeChange( section, oldSize, newSize );
+ } else if ( !tracking() && final && oldHIdxSize != newSize ) {
+ os = oldHIdxSize;
+ ns = newSize;
+ emit sizeChange( section, oldHIdxSize, newSize );
+ }
+
+ if ( os != ns ) {
+ if ( d->fullSize == -1 ) {
+ d->fullSize = count() - 1;
+ adjustHeaderSize();
+ d->fullSize = -1;
+ } else if ( d->fullSize >= 0 ) {
+ int old = d->fullSize;
+ d->fullSize = count() - 1;
+ adjustHeaderSize();
+ d->fullSize = old;
+ }
+ }
+}
+
+/*!
+ Returns the rectangle covered by the section at index \a index.
+*/
+
+QRect QHeader::sRect( int index )
+{
+
+ int section = mapToSection( index );
+ if ( count() > 0 && index >= count() ) {
+ int s = d->positions[count() - 1] - offset() +
+ d->sizes[mapToSection(count() - 1)];
+ if ( orient == Horizontal )
+ return QRect( s, 0, width() - s + 10, height() );
+ else
+ return QRect( 0, s, width(), height() - s + 10 );
+ }
+ if ( section < 0 )
+ return rect(); // ### eeeeevil
+
+ if ( reverse() )
+ return QRect( d->lastPos - d->positions[index] - d->sizes[section] -offset(),
+ 0, d->sizes[section], height() );
+ else if ( orient == Horizontal )
+ return QRect( d->positions[index]-offset(), 0, d->sizes[section], height() );
+ else
+ return QRect( 0, d->positions[index]-offset(), width(), d->sizes[section] );
+}
+
+/*!
+ Returns the rectangle covered by section \a section.
+*/
+
+QRect QHeader::sectionRect( int section ) const
+{
+ int index = mapToIndex( section );
+ if ( section < 0 )
+ return rect(); // ### eeeeevil
+
+ if ( reverse() )
+ return QRect( d->lastPos - d->positions[index] - d->sizes[section] -offset(),
+ 0, d->sizes[section], height() );
+ else if ( orient == Horizontal )
+ return QRect( d->positions[index]-offset(), 0, d->sizes[section], height() );
+ else
+ return QRect( 0, d->positions[index]-offset(), width(), d->sizes[section] );
+}
+
+/*!
+ \overload
+
+ Sets the icon for section \a section to \a iconset and the text to
+ \a s. The section's width is set to \a size if \a size \>= 0;
+ otherwise it is left unchanged.
+
+ If the section does not exist, nothing happens.
+*/
+
+void QHeader::setLabel( int section, const QIconSet& iconset,
+ const QString &s, int size )
+{
+ if ( section < 0 || section >= count() )
+ return;
+ d->iconsets.insert( section, new QIconSet( iconset ) );
+ setLabel( section, s, size );
+}
+
+/*!
+ Sets the text of section \a section to \a s. The section's width
+ is set to \a size if \a size \>= 0; otherwise it is left
+ unchanged. Any icon set that has been set for this section remains
+ unchanged.
+
+ If the section does not exist, nothing happens.
+*/
+void QHeader::setLabel( int section, const QString &s, int size )
+{
+ if ( section < 0 || section >= count() )
+ return;
+ if ( s.isNull() )
+ d->labels.remove( section );
+ else
+ d->labels.insert( section, new QString( s ) );
+
+ setSectionSizeAndHeight( section, size );
+
+ if ( isUpdatesEnabled() ) {
+ updateGeometry();
+ calculatePositions();
+ update();
+ }
+}
+
+
+bool qt_qheader_label_return_null_strings = FALSE;
+/*!
+ Returns the text for section \a section. If the section does not
+ exist, a QString::null is returned.
+*/
+QString QHeader::label( int section ) const
+{
+ if ( section < 0 || section >= count() )
+ return QString::null;
+ if ( d->labels[ section ] )
+ return *( d->labels[ section ] );
+ else if ( qt_qheader_label_return_null_strings )
+ return QString::null;
+ else
+ return QString::number( section + 1 );
+}
+
+/*!
+ Returns the icon set for section \a section. If the section does
+ not exist, 0 is returned.
+*/
+
+QIconSet *QHeader::iconSet( int section ) const
+{
+ if ( section < 0 || section >= count() )
+ return 0;
+ return d->iconsets[ section ];
+}
+
+
+/*!
+ \overload
+
+ Adds a new section with iconset \a iconset and label text \a s.
+ Returns the index position where the section was added (at the
+ right for horizontal headers, at the bottom for vertical headers).
+ The section's width is set to \a size, unless size is negative in
+ which case the size is calculated taking account of the size of
+ the text.
+*/
+int QHeader::addLabel( const QIconSet& iconset, const QString &s, int size )
+{
+ int n = count() + 1;
+ d->iconsets.resize( n + 1 );
+ d->iconsets.insert( n - 1, new QIconSet( iconset ) );
+ return addLabel( s, size );
+}
+
+/*!
+ Removes section \a section. If the section does not exist, nothing
+ happens.
+*/
+void QHeader::removeLabel( int section )
+{
+ if ( section < 0 || section > count() - 1 )
+ return;
+
+ int index = d->s2i[section];
+ int n = --d->count;
+ int i;
+ for ( i = section; i < n; ++i ) {
+ d->sizes[i] = d->sizes[i+1];
+ d->labels.insert( i, d->labels.take( i + 1 ) );
+ d->iconsets.insert( i, d->iconsets.take( i + 1 ) );
+ }
+
+ d->sizes.resize( n );
+ d->positions.resize( n );
+ d->labels.resize( n );
+ d->iconsets.resize( n );
+
+ for ( i = section; i < n; ++i )
+ d->s2i[i] = d->s2i[i+1];
+ d->s2i.resize( n );
+
+ if ( isUpdatesEnabled() ) {
+ for ( i = 0; i < n; ++i )
+ if ( d->s2i[i] > index )
+ --d->s2i[i];
+ }
+
+ for ( i = index; i < n; ++i )
+ d->i2s[i] = d->i2s[i+1];
+ d->i2s.resize( n );
+
+ if ( isUpdatesEnabled() ) {
+ for ( i = 0; i < n; ++i )
+ if ( d->i2s[i] > section )
+ --d->i2s[i];
+ }
+
+ if ( isUpdatesEnabled() ) {
+ updateGeometry();
+ calculatePositions();
+ update();
+ }
+}
+
+QSize QHeader::sectionSizeHint( int section, const QFontMetrics& fm ) const
+{
+ int iw = 0;
+ int ih = 0;
+ if ( d->iconsets[section] != 0 ) {
+ QSize isize = d->iconsets[section]->pixmap( QIconSet::Small,
+ QIconSet::Normal ).size();
+ iw = isize.width() + 2;
+ ih = isize.height();
+ }
+
+ QRect bound;
+ QString *label = d->labels[section];
+ if ( label ) {
+ int lines = label->contains( '\n' ) + 1;
+ int w = 0;
+ if (lines > 1) {
+ bound.setHeight(fm.height() + fm.lineSpacing() * (lines - 1));
+ QStringList list = QStringList::split('\n', *label);
+ for (int i=0; i <(int)list.count(); ++i) {
+ int tmpw = fm.width(*(list.at(i)));
+ w = QMAX(w, tmpw);
+ }
+ } else {
+ bound.setHeight(fm.height());
+ w = fm.width(*label);
+ }
+ bound.setWidth( w );
+ }
+ int arrowWidth = 0;
+ if ( d->sortSection == section )
+ arrowWidth = ( ( orient == Qt::Horizontal ? height() : width() ) / 2 ) + 8;
+ int height = QMAX( bound.height() + 2, ih ) + 4;
+ int width = bound.width() + style().pixelMetric( QStyle::PM_HeaderMargin ) * 4
+ + iw + arrowWidth;
+ return QSize( width, height );
+}
+
+/*
+ Sets d->sizes[\a section] to a bounding rect based on its size
+ hint and font metrics, but constrained by \a size. It also updates
+ d->height.
+*/
+void QHeader::setSectionSizeAndHeight( int section, int size )
+{
+ QSize sz = sectionSizeHint( section, fontMetrics() );
+
+ if ( size < 0 ) {
+ if ( d->sizes[section] < 0 )
+ d->sizes[section] = ( orient == Horizontal ) ? sz.width()
+ : sz.height();
+ } else {
+ d->sizes[section] = size;
+ }
+
+ int newHeight = ( orient == Horizontal ) ? sz.height() : sz.width();
+ if ( newHeight > d->height ) {
+ d->height = newHeight;
+ } else if ( newHeight < d->height ) {
+ /*
+ We could be smarter, but we aren't. This makes a difference
+ only for users with many columns and '\n's in their headers
+ at the same time.
+ */
+ d->heightDirty = TRUE;
+ }
+}
+
+/*!
+ Adds a new section with label text \a s. Returns the index
+ position where the section was added (at the right for horizontal
+ headers, at the bottom for vertical headers). The section's width
+ is set to \a size. If \a size \< 0, an appropriate size for the
+ text \a s is chosen.
+*/
+int QHeader::addLabel( const QString &s, int size )
+{
+ int n = ++d->count;
+ if ( (int)d->iconsets.size() < n )
+ d->iconsets.resize( n );
+ if ( (int)d->sizes.size() < n ) {
+ d->labels.resize( n );
+ d->sizes.resize( n );
+ d->positions.resize( n );
+ d->i2s.resize( n );
+ d->s2i.resize( n );
+ d->clicks.resize( n );
+ d->resize.resize( n );
+ }
+ int section = d->count - 1;
+ if ( !d->is_a_table_header || !s.isNull() )
+ d->labels.insert( section, new QString( s ) );
+
+ if ( size >= 0 && s.isNull() && d->is_a_table_header ) {
+ d->sizes[section] = size;
+ } else {
+ d->sizes[section] = -1;
+ setSectionSizeAndHeight( section, size );
+ }
+
+ int index = section;
+ d->positions[index] = d->lastPos;
+
+ d->s2i[section] = index;
+ d->i2s[index] = section;
+ d->clicks.setBit( section, d->clicks_default );
+ d->resize.setBit( section, d->resize_default );
+
+ if ( isUpdatesEnabled() ) {
+ updateGeometry();
+ calculatePositions();
+ update();
+ }
+ return index;
+}
+
+void QHeader::resizeArrays( int size )
+{
+ d->iconsets.resize( size );
+ d->labels.resize( size );
+ d->sizes.resize( size );
+ d->positions.resize( size );
+ d->i2s.resize( size );
+ d->s2i.resize( size );
+ d->clicks.resize( size );
+ d->resize.resize( size );
+}
+
+void QHeader::setIsATableHeader( bool b )
+{
+ d->is_a_table_header = b;
+}
+
+/*! \reimp */
+QSize QHeader::sizeHint() const
+{
+ int width;
+ int height;
+
+ constPolish();
+ QFontMetrics fm = fontMetrics();
+
+ if ( d->heightDirty ) {
+ d->height = fm.lineSpacing() + 6;
+ for ( int i = 0; i < count(); i++ ) {
+ int h = orient == Horizontal ?
+ sectionSizeHint( i, fm ).height() : sectionSizeHint( i, fm ).width();
+ d->height = QMAX( d->height, h );
+ }
+ d->heightDirty = FALSE;
+ }
+
+ if ( orient == Horizontal ) {
+ height = fm.lineSpacing() + 6;
+ width = 0;
+ height = QMAX( height, d->height );
+ for ( int i = 0; i < count(); i++ )
+ width += d->sizes[i];
+ } else {
+ width = fm.width( ' ' );
+ height = 0;
+ width = QMAX( width, d->height );
+ for ( int i = 0; i < count(); i++ )
+ height += d->sizes[i];
+ }
+ return (style().sizeFromContents(QStyle::CT_Header, this,
+ QSize(width, height)).expandedTo(QApplication::globalStrut()));
+}
+
+/*!
+ \property QHeader::offset
+ \brief the header's left-most (or top-most) visible pixel
+
+ Setting this property will scroll the header so that \e offset
+ becomes the left-most (or top-most for vertical headers) visible
+ pixel.
+*/
+int QHeader::offset() const
+{
+ if ( reverse() )
+ return d->lastPos - width() - offs;
+ return offs;
+}
+
+void QHeader::setOffset( int x )
+{
+ int oldOff = offset();
+ offs = x;
+ if( d->lastPos < ( orient == Horizontal ? width() : height() ) )
+ offs = 0;
+ else if ( reverse() )
+ offs = d->lastPos - width() - x;
+ if ( orient == Horizontal )
+ scroll( oldOff-offset(), 0 );
+ else
+ scroll( 0, oldOff-offset());
+}
+
+
+
+/*
+ Returns the position of actual division line \a i in widget
+ coordinates. May return a position outside the widget.
+
+ Note that the last division line is numbered count(). (There is one
+ more line than the number of sections).
+*/
+int QHeader::pPos( int i ) const
+{
+ int pos;
+ if ( i == count() )
+ pos = d->lastPos;
+ else
+ pos = d->positions[i];
+ if ( reverse() )
+ pos = d->lastPos - pos;
+ return pos - offset();
+}
+
+
+/*
+ Returns the size of the section at index position \a i.
+*/
+int QHeader::pSize( int i ) const
+{
+ return d->sizes[ d->i2s[i] ];
+}
+
+/*!
+ \obsolete
+
+ Use mapToSection() instead.
+
+ Translates from actual index \a a (index at which the section is displayed) to
+ logical index of the section. Returns -1 if \a a is outside the legal range.
+
+ \sa mapToActual()
+*/
+
+int QHeader::mapToLogical( int a ) const
+{
+ return mapToSection( a );
+}
+
+
+/*!
+ \obsolete
+
+ Use mapToIndex() instead.
+
+ Translates from logical index \a l to actual index (index at which the section \a l is displayed) .
+ Returns -1 if \a l is outside the legal range.
+
+ \sa mapToLogical()
+*/
+
+int QHeader::mapToActual( int l ) const
+{
+ return mapToIndex( l );
+}
+
+
+/*!
+ \obsolete
+
+ Use resizeSection() instead.
+
+ Sets the size of the section \a section to \a s pixels.
+
+ \warning does not repaint or send out signals
+*/
+
+void QHeader::setCellSize( int section, int s )
+{
+ if ( section < 0 || section >= count() )
+ return;
+ d->sizes[ section ] = s;
+ if ( isUpdatesEnabled() )
+ calculatePositions();
+}
+
+
+/*!
+ If \a enable is TRUE the user may resize section \a section;
+ otherwise the section may not be manually resized.
+
+ If \a section is negative (the default) then the \a enable value
+ is set for all existing sections and will be applied to any new
+ sections that are added.
+ Example:
+ \code
+ // Allow resizing of all current and future sections
+ header->setResizeEnabled(TRUE);
+ // Disable resizing of section 3, (the fourth section added)
+ header->setResizeEnabled(FALSE, 3);
+ \endcode
+
+ If the user resizes a section, a sizeChange() signal is emitted.
+
+ \sa setMovingEnabled() setClickEnabled() setTracking()
+*/
+
+void QHeader::setResizeEnabled( bool enable, int section )
+{
+ if ( section < 0 ) {
+ d->resize.fill( enable );
+ // and future ones...
+ d->resize_default = enable;
+ } else if ( section < count() ) {
+ d->resize[ section ] = enable;
+ }
+}
+
+
+/*!
+ \property QHeader::moving
+ \brief whether the header sections can be moved
+
+ If this property is TRUE (the default) the user can move sections.
+ If the user moves a section the indexChange() signal is emitted.
+
+ \sa setClickEnabled(), setResizeEnabled()
+*/
+
+void QHeader::setMovingEnabled( bool enable )
+{
+ d->move = enable;
+}
+
+
+/*!
+ If \a enable is TRUE, any clicks on section \a section will result
+ in clicked() signals being emitted; otherwise the section will
+ ignore clicks.
+
+ If \a section is -1 (the default) then the \a enable value is set
+ for all existing sections and will be applied to any new sections
+ that are added.
+
+ \sa setMovingEnabled(), setResizeEnabled()
+*/
+
+void QHeader::setClickEnabled( bool enable, int section )
+{
+ if ( section < 0 ) {
+ d->clicks.fill( enable );
+ // and future ones...
+ d->clicks_default = enable;
+ } else if ( section < count() ) {
+ d->clicks[ section ] = enable;
+ }
+}
+
+
+/*!
+ Paints the section at position \a index, inside rectangle \a fr
+ (which uses widget coordinates) using painter \a p.
+
+ Calls paintSectionLabel().
+*/
+
+void QHeader::paintSection( QPainter *p, int index, const QRect& fr )
+{
+ int section = mapToSection( index );
+
+ if ( section < 0 ) {
+ style().drawPrimitive( QStyle::PE_HeaderSection, p, fr,
+ colorGroup(), QStyle::Style_Raised |
+ (isEnabled() ? QStyle::Style_Enabled : 0) |
+ ( orient == Horizontal ? QStyle::Style_Horizontal : 0 ),
+ QStyleOption( this ) );
+ return;
+ }
+
+ if ( sectionSize( section ) <= 0 )
+ return;
+
+ QStyle::SFlags flags = (orient == Horizontal ? QStyle::Style_Horizontal : QStyle::Style_Default);
+ //pass in some hint about the sort indicator if it is used
+ if(d->sortSection != section)
+ flags |= QStyle::Style_Off;
+ else if(!d->sortDirection)
+ flags |= QStyle::Style_Up;
+ if(isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if(isClickEnabled(section)) {
+ if(section == d->sortSection)
+ flags |= QStyle::Style_Sunken; //currently selected
+ if((state == Pressed || state == Moving) && index == handleIdx)
+ flags |= QStyle::Style_Down; //currently pressed
+
+ }
+ if(!(flags & QStyle::Style_Down))
+ flags |= QStyle::Style_Raised;
+ p->setBrushOrigin( fr.topLeft() );
+ if ( d->clicks[section] ) {
+ style().drawPrimitive( QStyle::PE_HeaderSection, p, fr,
+ colorGroup(), flags,
+ QStyleOption( this ) );
+ } else {
+ p->save();
+ p->setClipRect( fr ); // hack to keep styles working
+ if ( orientation() == Horizontal ) {
+ style().drawPrimitive( QStyle::PE_HeaderSection, p,
+ QRect(fr.x() - 2, fr.y() - 2, fr.width() + 4, fr.height() + 4),
+ colorGroup(), flags,
+ QStyleOption( this ) );
+
+ p->setPen( colorGroup().color( QColorGroup::Mid ) );
+ p->drawLine( fr.x(), fr.y() + fr.height() - 1,
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 1 );
+ p->drawLine( fr.x() + fr.width() - 1, fr.y(),
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 1 );
+ p->setPen( colorGroup().color( QColorGroup::Light ) );
+ if ( index > 0 )
+ p->drawLine( fr.x(), fr.y(), fr.x(), fr.y() + fr.height() - 1 );
+ if ( index == count() - 1 ) {
+ p->drawLine( fr.x() + fr.width() - 1, fr.y(),
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 1 );
+ p->setPen( colorGroup().color( QColorGroup::Mid ) );
+ p->drawLine( fr.x() + fr.width() - 2, fr.y(),
+ fr.x() + fr.width() - 2, fr.y() + fr.height() - 1 );
+ }
+ } else {
+ style().drawPrimitive( QStyle::PE_HeaderSection, p,
+ QRect(fr.x() - 2, fr.y() - 2, fr.width() + 4, fr.height() + 4),
+ colorGroup(), flags,
+ QStyleOption( this ) );
+
+ p->setPen( colorGroup().color( QColorGroup::Mid ) );
+ p->drawLine( fr.x() + width() - 1, fr.y(),
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 1 );
+ p->drawLine( fr.x(), fr.y() + fr.height() - 1,
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 1 );
+ p->setPen( colorGroup().color( QColorGroup::Light ) );
+ if ( index > 0 )
+ p->drawLine( fr.x(), fr.y(), fr.x() + fr.width() - 1, fr.y() );
+ if ( index == count() - 1 ) {
+ p->drawLine( fr.x(), fr.y() + fr.height() - 1,
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 1 );
+ p->setPen( colorGroup().color( QColorGroup::Mid ) );
+ p->drawLine( fr.x(), fr.y() + fr.height() - 2,
+ fr.x() + fr.width() - 1, fr.y() + fr.height() - 2 );
+ }
+ }
+ p->restore();
+ }
+
+ paintSectionLabel( p, index, fr );
+}
+
+/*!
+ Paints the label of the section at position \a index, inside
+ rectangle \a fr (which uses widget coordinates) using painter \a
+ p.
+
+ Called by paintSection()
+*/
+void QHeader::paintSectionLabel( QPainter *p, int index, const QRect& fr )
+{
+ int section = mapToSection( index );
+ if ( section < 0 )
+ return;
+
+ int dx = 0, dy = 0;
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( index == handleIdx && ( state == Pressed || state == Moving ) ) {
+ dx = style().pixelMetric( QStyle::PM_ButtonShiftHorizontal, this );
+ dy = style().pixelMetric( QStyle::PM_ButtonShiftVertical, this );
+ flags |= QStyle::Style_Sunken;
+ }
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+
+
+ QRect r( fr.x() + style().pixelMetric( QStyle::PM_HeaderMargin ) + dx, fr.y() + 2 + dy,
+ fr.width() - 6, fr.height() - 4 );
+
+ style().drawControl( QStyle::CE_HeaderLabel, p, this, r, colorGroup(), flags,
+ QStyleOption( section ) );
+
+ int arrowWidth = ( orient == Qt::Horizontal ? height() : width() ) / 2;
+ int arrowHeight = fr.height() - 6;
+ QSize ssh = sectionSizeHint( section, p->fontMetrics() );
+ int tw = ( orient == Qt::Horizontal ? ssh.width() : ssh.height() );
+ int ew = 0;
+
+ if ( style().styleHint( QStyle::SH_Header_ArrowAlignment, this ) & AlignRight )
+ ew = fr.width() - tw - 8;
+ if ( d->sortSection == section && tw <= fr.width() ) {
+ if ( reverse() ) {
+ tw = fr.width() - tw;
+ ew = fr.width() - ew - tw;
+ }
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if ( d->sortDirection )
+ flags |= QStyle::Style_Down;
+ else
+ flags |= QStyle::Style_Up;
+ QRect ar(fr.x() + tw - arrowWidth - 6 + ew, 4, arrowWidth, arrowHeight);
+ if (label(section).isRightToLeft())
+ ar.moveBy( 2*(fr.right() - ar.right()) + ar.width() - fr.width(), 0 );
+ style().drawPrimitive( QStyle::PE_HeaderArrow, p,
+ ar, colorGroup(), flags, QStyleOption( this ) );
+ }
+}
+
+
+/*! \reimp */
+void QHeader::paintEvent( QPaintEvent *e )
+{
+ QPainter p( this );
+ p.setPen( colorGroup().buttonText() );
+ int pos = orient == Horizontal ? e->rect().left() : e->rect().top();
+ int id = mapToIndex( sectionAt( pos + offset() ) );
+ if ( id < 0 ) {
+ if ( pos > 0 )
+ id = d->count;
+ else if ( reverse() )
+ id = d->count - 1;
+ else
+ id = 0;
+ }
+ if ( reverse() ) {
+ for ( int i = id; i >= 0; i-- ) {
+ QRect r = sRect( i );
+ paintSection( &p, i, r );
+ if ( r.right() >= e->rect().right() )
+ return;
+ }
+ } else {
+ if ( count() > 0 ) {
+ for ( int i = id; i <= count(); i++ ) {
+ QRect r = sRect( i );
+ /*
+ If the last section is clickable (and thus is
+ painted raised), draw the virtual section count()
+ as well. Otherwise it looks ugly.
+ */
+ if ( i < count() || d->clicks[ mapToSection( count() - 1 ) ] )
+ paintSection( &p, i, r );
+ if ( hasFocus() && d->focusIdx == i ) {
+ QRect fr( r.x()+2, r.y()+2, r.width()-4, r.height()-4 );
+ style().drawPrimitive( QStyle::PE_FocusRect, &p, fr,
+ colorGroup() );
+ }
+ if ( orient == Horizontal && r. right() >= e->rect().right() ||
+ orient == Vertical && r. bottom() >= e->rect().bottom() )
+ return;
+ }
+ }
+ }
+}
+
+/*! \overload
+ \obsolete
+ Use the other overload instead.
+*/
+
+void QHeader::setSortIndicator( int section, bool ascending )
+{
+ d->sortSection = section;
+ if ( section != -1 )
+ oldHandleIdx = section;
+ d->sortDirection = ascending;
+ update();
+ updateGeometry();
+}
+
+/*!
+ \fn void QHeader::setSortIndicator(int section, SortOrder order)
+
+ Sets a sort indicator onto the specified \a section. The indicator's
+ \a order is either Ascending or Descending.
+
+ Only one section can show a sort indicator at any one time. If you
+ don't want any section to show a sort indicator pass a \a section
+ number of -1.
+
+ \sa sortIndicatorSection(), sortIndicatorOrder()
+*/
+
+/*!
+ Returns the section showing the sort indicator or -1 if there is no sort indicator.
+
+ \sa setSortIndicator(), sortIndicatorOrder()
+*/
+
+int QHeader::sortIndicatorSection() const
+{
+ return d->sortSection;
+}
+
+/*!
+ Returns the implied sort order of the QHeaders sort indicator.
+
+ \sa setSortIndicator(), sortIndicatorSection()
+*/
+
+Qt::SortOrder QHeader::sortIndicatorOrder() const
+{
+ return d->sortDirection ? Ascending : Descending;
+}
+
+/*!
+ Resizes section \a section to \a s pixels wide (or high).
+*/
+
+void QHeader::resizeSection( int section, int s )
+{
+ setCellSize( section, s );
+ update();
+}
+
+/*!
+ Returns the width (or height) of the \a section in pixels.
+*/
+
+int QHeader::sectionSize( int section ) const
+{
+ if ( section < 0 || section >= count() )
+ return 0;
+ return d->sizes[section];
+}
+
+/*!
+ Returns the position (in pixels) at which the \a section starts.
+
+ \sa offset()
+*/
+
+int QHeader::sectionPos( int section ) const
+{
+ if ( d->positionsDirty )
+ ((QHeader *)this)->calculatePositions();
+ if ( section < 0 || section >= count() )
+ return 0;
+ return d->positions[ d->s2i[section] ];
+}
+
+/*!
+ Returns the index of the section which contains the position \a
+ pos given in pixels from the left (or top).
+
+ \sa offset()
+*/
+
+int QHeader::sectionAt( int pos ) const
+{
+ if ( reverse() )
+ pos = d->lastPos - pos;
+ return d->sectionAt( pos );
+}
+
+/*!
+ Returns the number of the section that corresponds to the specified \a index.
+
+ \warning If QTable is used to move header sections as a result of user
+ interaction, the mapping exposed by this function will not reflect the
+ order of the headers in the table; i.e., QTable does not call moveSection()
+ to move sections but handles move operations internally.
+
+ \sa mapToIndex()
+*/
+
+int QHeader::mapToSection( int index ) const
+{
+ return ( index >= 0 && index < count() ) ? d->i2s[ index ] : -1;
+}
+
+/*!
+ Returns the index position corresponding to the specified \a section number.
+
+ \warning If QTable is used to move header sections as a result of user
+ interaction, the mapping exposed by this function will not reflect the
+ order of the headers in the table; i.e., QTable does not call moveSection()
+ to move sections but handles move operations internally.
+
+ \sa mapToSection()
+*/
+
+int QHeader::mapToIndex( int section ) const
+{
+ return ( section >= 0 && section < count() ) ? d->s2i[ section ] : -1;
+}
+
+/*!
+ Moves section \a section to index position \a toIndex.
+*/
+
+void QHeader::moveSection( int section, int toIndex )
+{
+ int fromIndex = mapToIndex( section );
+ if ( fromIndex == toIndex ||
+ fromIndex < 0 || fromIndex > count() ||
+ toIndex < 0 || toIndex > count() )
+ return;
+ int i;
+ int idx = d->i2s[fromIndex];
+ if ( fromIndex < toIndex ) {
+ for ( i = fromIndex; i < toIndex - 1; i++ ) {
+ int t;
+ d->i2s[i] = t = d->i2s[i+1];
+ d->s2i[t] = i;
+ }
+ d->i2s[toIndex-1] = idx;
+ d->s2i[idx] = toIndex-1;
+ } else {
+ for ( i = fromIndex; i > toIndex; i-- ) {
+ int t;
+ d->i2s[i] = t = d->i2s[i-1];
+ d->s2i[t] = i;
+ }
+ d->i2s[toIndex] = idx;
+ d->s2i[idx] = toIndex;
+ }
+ calculatePositions();
+}
+
+/*!
+ Returns TRUE if section \a section is clickable; otherwise returns
+ FALSE.
+
+ If \a section is out of range (negative or larger than count() -
+ 1): returns TRUE if all sections are clickable; otherwise returns
+ FALSE.
+
+ \sa setClickEnabled()
+*/
+
+bool QHeader::isClickEnabled( int section ) const
+{
+ if ( section >= 0 && section < count() ) {
+ return (bool)d->clicks[ section ];
+ }
+
+ for ( int i = 0; i < count(); ++i ) {
+ if ( !d->clicks[ i ] )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*!
+ Returns TRUE if section \a section is resizeable; otherwise
+ returns FALSE.
+
+ If \a section is -1 then this function applies to all sections,
+ i.e. returns TRUE if all sections are resizeable; otherwise
+ returns FALSE.
+
+ \sa setResizeEnabled()
+*/
+
+bool QHeader::isResizeEnabled( int section ) const
+{
+ if ( section >= 0 && section < count() ) {
+ return (bool)d->resize[ section ];
+ }
+
+ for ( int i = 0; i < count();++i ) {
+ if ( !d->resize[ i ] )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool QHeader::isMovingEnabled() const
+{
+ return d->move;
+}
+
+/*! \reimp */
+
+void QHeader::setUpdatesEnabled( bool enable )
+{
+ if ( enable )
+ calculatePositions();
+ QWidget::setUpdatesEnabled( enable );
+}
+
+
+bool QHeader::reverse () const
+{
+#if 0
+ return ( orient == Qt::Horizontal && QApplication::reverseLayout() );
+#else
+ return FALSE;
+#endif
+}
+
+/*! \reimp */
+void QHeader::resizeEvent( QResizeEvent *e )
+{
+ if ( e )
+ QWidget::resizeEvent( e );
+
+ if( d->lastPos < width() ) {
+ offs = 0;
+ }
+
+ if ( e ) {
+ adjustHeaderSize( orientation() == Horizontal ?
+ width() - e->oldSize().width() : height() - e->oldSize().height() );
+ if ( (orientation() == Horizontal && height() != e->oldSize().height())
+ || (orientation() == Vertical && width() != e->oldSize().width()) )
+ update();
+ } else
+ adjustHeaderSize();
+}
+
+/*!
+ \fn void QHeader::adjustHeaderSize()
+
+ Adjusts the size of the sections to fit the size of the header as
+ completely as possible. Only sections for which isStretchEnabled()
+ is TRUE will be resized.
+*/
+
+void QHeader::adjustHeaderSize( int diff )
+{
+ if ( !count() )
+ return;
+
+ // we skip the adjustHeaderSize when trying to resize the last column which is set to stretchable
+ if ( d->fullSize == (count() -1) &&
+ (d->lastPos - d->sizes[count() -1]) > ( orient == Horizontal ? width() : height() ) )
+ return;
+
+ if ( d->fullSize >= 0 ) {
+ int sec = mapToSection( d->fullSize );
+ int lsec = mapToSection( count() - 1 );
+ int ns = sectionSize( sec ) +
+ ( orientation() == Horizontal ?
+ width() : height() ) - ( sectionPos( lsec ) + sectionSize( lsec ) );
+ int os = sectionSize( sec );
+ if ( ns < 20 )
+ ns = 20;
+ setCellSize( sec, ns );
+ repaint( FALSE );
+ emit sizeChange( sec, os, ns );
+ } else if ( d->fullSize == -1 ) {
+ int df = diff / count();
+ int part = orientation() == Horizontal ? width() / count() : height() / count();
+ for ( int i = 0; i < count() - 1; ++i ) {
+ int sec = mapToIndex( i );
+ int os = sectionSize( sec );
+ int ns = diff != -1 ? os + df : part;
+ if ( ns < 20 )
+ ns = 20;
+ setCellSize( sec, ns );
+ emit sizeChange( sec, os, ns );
+ }
+ int sec = mapToIndex( count() - 1 );
+ int ns = ( orientation() == Horizontal ? width() : height() ) - sectionPos( sec );
+ int os = sectionSize( sec );
+ if ( ns < 20 )
+ ns = 20;
+ setCellSize( sec, ns );
+ repaint( FALSE );
+ emit sizeChange( sec, os, ns );
+ }
+}
+
+/*!
+ Returns the total width of all the header columns.
+*/
+int QHeader::headerWidth() const
+{
+ if ( d->pos_dirty ) {
+ ( (QHeader*)this )->calculatePositions();
+ d->pos_dirty = FALSE;
+ }
+ return d->lastPos;
+}
+
+void QHeader::calculatePositions( bool onlyVisible, int start )
+{
+ d->positionsDirty = FALSE;
+ d->lastPos = count() > 0 ? d->positions[start] : 0;
+ for ( int i = start; i < count(); i++ ) {
+ d->positions[i] = d->lastPos;
+ d->lastPos += d->sizes[d->i2s[i]];
+ if ( onlyVisible && d->lastPos > offset() +
+ ( orientation() == Horizontal ? width() : height() ) )
+ break;
+ }
+ d->pos_dirty = onlyVisible;
+}
+
+
+/*!
+ \property QHeader::stretching
+ \brief whether the header sections always take up the full width
+ (or height) of the header
+*/
+
+
+/*!
+ If \a b is TRUE, section \a section will be resized when the
+ header is resized, so that the sections take up the full width (or
+ height for vertical headers) of the header; otherwise section \a
+ section will be set to be unstretchable and will not resize when
+ the header is resized.
+
+ If \a section is -1, and if \a b is TRUE, then all sections will
+ be resized equally when the header is resized so that they take up
+ the full width (or height for vertical headers) of the header;
+ otherwise all the sections will be set to be unstretchable and
+ will not resize when the header is resized.
+
+ \sa adjustHeaderSize()
+*/
+
+void QHeader::setStretchEnabled( bool b, int section )
+{
+ if ( b )
+ d->fullSize = section;
+ else
+ d->fullSize = -2;
+ adjustHeaderSize();
+}
+
+bool QHeader::isStretchEnabled() const
+{
+ return d->fullSize == -1;
+}
+
+/*!
+ \overload
+
+ Returns TRUE if section \a section will resize to take up the full
+ width (or height) of the header; otherwise returns FALSE. If at
+ least one section has stretch enabled the sections will always
+ take up the full width of the header.
+
+ \sa setStretchEnabled()
+*/
+
+bool QHeader::isStretchEnabled( int section ) const
+{
+ return d->fullSize == section;
+}
+
+/*!
+ \reimp
+*/
+void QHeader::fontChange( const QFont &oldFont )
+{
+ QFontMetrics fm = fontMetrics();
+ d->height = ( orient == Horizontal ) ? fm.lineSpacing() + 6 : fm.width( ' ' );
+ QWidget::fontChange( oldFont );
+}
+
+#endif // QT_NO_HEADER
diff --git a/src/widgets/qheader.h b/src/widgets/qheader.h
new file mode 100644
index 0000000..1f5cf03
--- /dev/null
+++ b/src/widgets/qheader.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Definition of QHeader widget class (table header)
+**
+** Created : 961105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QHEADER_H
+#define QHEADER_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qstring.h"
+#include "qiconset.h" // conversion QPixmap->QIconset
+#endif // QT_H
+
+#ifndef QT_NO_HEADER
+
+class QShowEvent;
+class QHeaderData;
+class QTable;
+
+class Q_EXPORT QHeader : public QWidget
+{
+ friend class QTable;
+ friend class QTableHeader;
+ friend class QListView;
+
+ Q_OBJECT
+ Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation )
+ Q_PROPERTY( bool tracking READ tracking WRITE setTracking )
+ Q_PROPERTY( int count READ count )
+ Q_PROPERTY( int offset READ offset WRITE setOffset )
+ Q_PROPERTY( bool moving READ isMovingEnabled WRITE setMovingEnabled )
+ Q_PROPERTY( bool stretching READ isStretchEnabled WRITE setStretchEnabled )
+
+public:
+ QHeader( QWidget* parent=0, const char* name=0 );
+ QHeader( int, QWidget* parent=0, const char* name=0 );
+ ~QHeader();
+
+ int addLabel( const QString &, int size = -1 );
+ int addLabel( const QIconSet&, const QString &, int size = -1 );
+ void removeLabel( int section );
+ virtual void setLabel( int, const QString &, int size = -1 );
+ virtual void setLabel( int, const QIconSet&, const QString &, int size = -1 );
+ QString label( int section ) const;
+ QIconSet* iconSet( int section ) const;
+
+ virtual void setOrientation( Orientation );
+ Orientation orientation() const;
+ virtual void setTracking( bool enable );
+ bool tracking() const;
+
+ virtual void setClickEnabled( bool, int section = -1 );
+ virtual void setResizeEnabled( bool, int section = -1 );
+ virtual void setMovingEnabled( bool );
+ virtual void setStretchEnabled( bool b, int section );
+ void setStretchEnabled( bool b ) { setStretchEnabled( b, -1 ); }
+ bool isClickEnabled( int section = -1 ) const;
+ bool isResizeEnabled( int section = -1 ) const;
+ bool isMovingEnabled() const;
+ bool isStretchEnabled() const;
+ bool isStretchEnabled( int section ) const;
+
+ void resizeSection( int section, int s );
+ int sectionSize( int section ) const;
+ int sectionPos( int section ) const;
+ int sectionAt( int pos ) const;
+ int count() const;
+ int headerWidth() const;
+ QRect sectionRect( int section ) const;
+
+ virtual void setCellSize( int , int ); // obsolete, do not use
+ int cellSize( int i ) const { return sectionSize( mapToSection(i) ); } // obsolete, do not use
+ int cellPos( int ) const; // obsolete, do not use
+ int cellAt( int pos ) const { return mapToIndex( sectionAt(pos + offset()) ); } // obsolete, do not use
+
+ int offset() const;
+
+ QSize sizeHint() const;
+
+ int mapToSection( int index ) const;
+ int mapToIndex( int section ) const;
+ int mapToLogical( int ) const; // obsolete, do not use
+ int mapToActual( int ) const; // obsolete, do not use
+
+ void moveSection( int section, int toIndex );
+ virtual void moveCell( int, int); // obsolete, do not use
+
+ void setSortIndicator( int section, bool ascending = TRUE ); // obsolete, do not use
+ inline void setSortIndicator( int section, SortOrder order )
+ { setSortIndicator( section, (order == Ascending) ); }
+ int sortIndicatorSection() const;
+ SortOrder sortIndicatorOrder() const;
+
+ void adjustHeaderSize() { adjustHeaderSize( -1 ); }
+
+public slots:
+ void setUpdatesEnabled( bool enable );
+ virtual void setOffset( int pos );
+
+signals:
+ void clicked( int section );
+ void pressed( int section );
+ void released( int section );
+ void sizeChange( int section, int oldSize, int newSize );
+ void indexChange( int section, int fromIndex, int toIndex );
+ void sectionClicked( int ); // obsolete, do not use
+ void moved( int, int ); // obsolete, do not use
+ void sectionHandleDoubleClicked( int section );
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void showEvent( QShowEvent *e );
+ void resizeEvent( QResizeEvent *e );
+ QRect sRect( int index );
+
+ virtual void paintSection( QPainter *p, int index, const QRect& fr);
+ virtual void paintSectionLabel( QPainter* p, int index, const QRect& fr );
+
+ void fontChange( const QFont & );
+
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+
+ void keyPressEvent( QKeyEvent * );
+ void keyReleaseEvent( QKeyEvent * );
+
+private:
+ void handleColumnMove( int fromIdx, int toIdx );
+ void adjustHeaderSize( int diff );
+ void init( int );
+
+ void paintRect( int p, int s );
+ void markLine( int idx );
+ void unMarkLine( int idx );
+ int pPos( int i ) const;
+ int pSize( int i ) const;
+ int findLine( int );
+ int handleAt( int p );
+ bool reverse() const;
+ void calculatePositions( bool onlyVisible = FALSE, int start = 0 );
+ void handleColumnResize(int, int, bool, bool = TRUE );
+ QSize sectionSizeHint( int section, const QFontMetrics& fm ) const;
+ void setSectionSizeAndHeight( int section, int size );
+
+ void resizeArrays( int size );
+ void setIsATableHeader( bool b );
+ int offs;
+ int handleIdx;
+ int oldHIdxSize;
+ int moveToIdx;
+ enum State { Idle, Sliding, Pressed, Moving, Blocked };
+ State state;
+ QCOORD clickPos;
+ bool trackingIsOn;
+ int oldHandleIdx;
+ int cachedPos; // not used
+ Orientation orient;
+
+ QHeaderData *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QHeader( const QHeader & );
+ QHeader &operator=( const QHeader & );
+#endif
+};
+
+
+inline QHeader::Orientation QHeader::orientation() const
+{
+ return orient;
+}
+
+inline void QHeader::setTracking( bool enable ) { trackingIsOn = enable; }
+inline bool QHeader::tracking() const { return trackingIsOn; }
+
+extern Q_EXPORT bool qt_qheader_label_return_null_strings; // needed for professional edition
+
+#endif // QT_NO_HEADER
+
+#endif // QHEADER_H
diff --git a/src/widgets/qhgroupbox.cpp b/src/widgets/qhgroupbox.cpp
new file mode 100644
index 0000000..5cc4555
--- /dev/null
+++ b/src/widgets/qhgroupbox.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Implementation of QHGroupBox class
+**
+** Created : 990602
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qhgroupbox.h"
+#ifndef QT_NO_HGROUPBOX
+
+/*!
+ \class QHGroupBox qhgroupbox.h
+
+ \brief The QHGroupBox widget organizes widgets in a group with one
+ horizontal row.
+
+ \ingroup organizers
+ \ingroup geomanagement
+ \ingroup appearance
+
+ QHGroupBox is a convenience class that offers a thin layer on top
+ of QGroupBox. Think of it as a QHBox that offers a frame with a
+ title.
+
+ \img qgroupboxes.png Group Boxes
+
+ \sa QVGroupBox
+*/
+
+/*!
+ Constructs a horizontal group box with no title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+QHGroupBox::QHGroupBox( QWidget *parent, const char *name )
+ : QGroupBox( 1, Vertical /* sic! */, parent, name )
+{
+}
+
+/*!
+ Constructs a horizontal group box with the title \a title.
+
+ The \a parent and \a name arguments are passed to the QWidget
+ constructor.
+*/
+
+QHGroupBox::QHGroupBox( const QString &title, QWidget *parent,
+ const char *name )
+ : QGroupBox( 1, Vertical /* sic! */, title, parent, name )
+{
+}
+
+/*!
+ Destroys the horizontal group box, deleting its child widgets.
+*/
+QHGroupBox::~QHGroupBox()
+{
+}
+#endif
diff --git a/src/widgets/qhgroupbox.h b/src/widgets/qhgroupbox.h
new file mode 100644
index 0000000..66b4809
--- /dev/null
+++ b/src/widgets/qhgroupbox.h
@@ -0,0 +1,67 @@
+/**********************************************************************
+**
+** Definition of QHGroupBox widget class
+**
+** Created : 990602
+**
+** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QHGROUPBOX_H
+#define QHGROUPBOX_H
+
+#ifndef QT_H
+#include "qgroupbox.h"
+#endif // QT_H
+
+#ifndef QT_NO_HGROUPBOX
+
+class Q_EXPORT QHGroupBox : public QGroupBox
+{
+ Q_OBJECT
+public:
+ QHGroupBox( QWidget* parent=0, const char* name=0 );
+ QHGroupBox( const QString &title, QWidget* parent=0, const char* name=0 );
+ ~QHGroupBox();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QHGroupBox( const QHGroupBox & );
+ QHGroupBox &operator=( const QHGroupBox & );
+#endif
+};
+
+#endif // QT_NO_HGROUPBOX
+
+#endif // QHGROUPBOX_H
diff --git a/src/widgets/qlabel.cpp b/src/widgets/qlabel.cpp
new file mode 100644
index 0000000..40f2b38
--- /dev/null
+++ b/src/widgets/qlabel.cpp
@@ -0,0 +1,1190 @@
+/**********************************************************************
+**
+** Implementation of QLabel widget class
+**
+** Created : 941215
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qlabel.h"
+#ifndef QT_NO_LABEL
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qaccel.h"
+#include "qmovie.h"
+#include "qimage.h"
+#include "qbitmap.h"
+#include "qpicture.h"
+#include "qapplication.h"
+#include "qsimplerichtext.h"
+#include "qstylesheet.h"
+#include "qstyle.h"
+
+class QLabelPrivate
+{
+public:
+ QLabelPrivate()
+ :img(0), pix(0), valid_hints( -1 )
+ {}
+ QImage* img; // for scaled contents
+ QPixmap* pix; // for scaled contents
+ QSize sh;
+ QSize msh;
+ int valid_hints; // stores the frameWidth() for the stored size hint, -1 otherwise
+};
+
+
+/*!
+ \class QLabel qlabel.h
+ \brief The QLabel widget provides a text or image display.
+
+ \ingroup basic
+ \ingroup text
+ \mainclass
+
+ 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 accelerator key for another widget.
+
+ A QLabel can contain any of the following content types:
+ \table
+ \header \i Content \i Setting
+ \row \i Plain text
+ \i Pass a QString to setText().
+ \row \i Rich text
+ \i Pass a QString that contains rich text to setText().
+ \row \i A pixmap
+ \i Pass a QPixmap to setPixmap().
+ \row \i A movie
+ \i Pass a QMovie to setMovie().
+ \row \i A number
+ \i Pass an \e int or a \e double to setNum(), which converts
+ the number to plain text.
+ \row \i Nothing
+ \i The same as an empty plain text. This is the default. Set
+ by clear().
+ \endtable
+
+ When the content is changed using any of these functions, any
+ previous content is cleared.
+
+ The look of a QLabel can be tuned in several ways. All the
+ settings of QFrame are available for specifying a widget frame.
+ The positioning of the content within the QLabel widget area can
+ be tuned with setAlignment() and setIndent(). 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):
+ \code
+ QLabel *label = new QLabel( this );
+ label->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ label->setText( "first line\nsecond line" );
+ label->setAlignment( AlignBottom | AlignRight );
+ \endcode
+
+ A QLabel is often used as a label for an interactive widget. For
+ this use QLabel provides a useful mechanism for adding an
+ accelerator key (see QAccel) that will set the keyboard focus to
+ the other widget (called the QLabel's "buddy"). For example:
+ \code
+ QLineEdit* phoneEdit = new QLineEdit( this, "phoneEdit" );
+ QLabel* phoneLabel = new QLabel( phoneEdit, "&Phone:", this, "phoneLabel" );
+ \endcode
+
+ In this example, keyboard focus is transferred to the label's
+ buddy (the QLineEdit) when the user presses Alt+P. You can
+ also use the setBuddy() function to accomplish the same thing.
+
+ <img src=qlabel-m.png> <img src=qlabel-w.png>
+
+ \sa QLineEdit, QTextEdit, QPixmap, QMovie,
+ \link guibooks.html#fowler GUI Design Handbook: Label\endlink
+*/
+
+/*!
+ \fn QPicture * QLabel::picture() const
+
+ Returns the label's picture or 0 if the label doesn't have a
+ picture.
+*/
+
+
+/*!
+ 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, WFlags f )
+ : QFrame( parent, name, f | WMouseNoMask )
+{
+ init();
+}
+
+
+/*!
+ 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,
+ WFlags f )
+ : QFrame( parent, name, f | WMouseNoMask )
+{
+ init();
+ setText( text );
+}
+
+
+/*!
+ 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, \&), and the text is in plain text format, 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, WFlags f )
+ : QFrame( parent, name, f | WMouseNoMask )
+{
+ init();
+#ifndef QT_NO_ACCEL
+ setBuddy( buddy );
+#endif
+ setText( text );
+}
+
+/*!
+ Destroys the label.
+*/
+
+QLabel::~QLabel()
+{
+ clearContents();
+ delete d;
+}
+
+
+void QLabel::init()
+{
+ lpixmap = 0;
+#ifndef QT_NO_MOVIE
+ lmovie = 0;
+#endif
+#ifndef QT_NO_ACCEL
+ lbuddy = 0;
+ accel = 0;
+#endif
+ lpixmap = 0;
+#ifndef QT_NO_PICTURE
+ lpicture = 0;
+#endif
+ align = AlignAuto | AlignVCenter | ExpandTabs;
+ extraMargin = -1;
+ autoresize = FALSE;
+ scaledcontents = FALSE;
+ textformat = Qt::AutoText;
+#ifndef QT_NO_RICHTEXT
+ doc = 0;
+#endif
+
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+ d = new QLabelPrivate;
+}
+
+
+/*!
+ \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, unless they are the same.
+
+ The text will be interpreted either as a plain text or as a rich
+ text, depending on the text format setting; see setTextFormat().
+ The default setting is \c AutoText, i.e. QLabel will try to
+ auto-detect the format of the text set.
+
+ If the text is interpreted as a plain text and a buddy has been
+ set, the buddy accelerator key is updated from the new text.
+
+ The label resizes itself if auto-resizing is enabled.
+
+ Note that Qlabel is well-suited to display small rich text
+ documents, i.e. those 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 will flicker less on resize
+ and can also provide a scrollbar when necessary.
+
+ \sa text, setTextFormat(), setBuddy(), alignment
+*/
+
+void QLabel::setText( const QString &text )
+{
+ if ( ltext == text )
+ return;
+ QSize osh = sizeHint();
+#ifndef QT_NO_RICHTEXT
+ bool hadRichtext = doc != 0;
+#endif
+ clearContents();
+ ltext = text;
+#ifndef QT_NO_RICHTEXT
+ bool useRichText = (textformat == RichText ||
+ ( ( textformat == AutoText ) && QStyleSheet::mightBeRichText(ltext) ) );
+#else
+ bool useRichText = TRUE;
+#endif
+#ifndef QT_NO_ACCEL
+ // ### Setting accelerators for rich text labels will not work.
+ // Eg. <b>&gt;Hello</b> will return ALT+G which is clearly
+ // not intended.
+ if ( !useRichText ) {
+ int p = QAccel::shortcutKey( ltext );
+ if ( p ) {
+ if ( !accel )
+ accel = new QAccel( this, "accel label accel" );
+ accel->connectItem( accel->insertItem( p ),
+ this, SLOT(acceleratorSlot()) );
+ }
+ }
+#endif
+#ifndef QT_NO_RICHTEXT
+ if ( useRichText ) {
+ if ( !hadRichtext )
+ align |= WordBreak;
+ QString t = ltext;
+ if ( align & AlignRight )
+ t.prepend( "<div align=\"right\">");
+ else if ( align & AlignHCenter )
+ t.prepend( "<div align=\"center\">");
+ if ( (align & WordBreak) == 0 )
+ t.prepend( "<nobr>" );
+ doc = new QSimpleRichText( t, font() );
+ }
+#endif
+
+ updateLabel( osh );
+}
+
+
+/*!
+ Clears any label contents. Equivalent to setText( "" ).
+*/
+
+void QLabel::clear()
+{
+ setText( QString::fromLatin1("") );
+}
+
+/*!
+ \property QLabel::pixmap
+ \brief the label's pixmap
+
+ If no pixmap has been set this will return an invalid pixmap.
+
+ Setting the pixmap clears any previous content, and resizes the
+ label if \l QLabel::autoResize() is TRUE. The buddy accelerator,
+ if any, is disabled.
+*/
+void QLabel::setPixmap( const QPixmap &pixmap )
+{
+ QSize osh = sizeHint();
+
+ if ( !lpixmap || lpixmap->serialNumber() != pixmap.serialNumber() ) {
+ clearContents();
+ lpixmap = new QPixmap( pixmap );
+ }
+
+ if ( lpixmap->depth() == 1 && !lpixmap->mask() )
+ lpixmap->setMask( *((QBitmap *)lpixmap) );
+
+ updateLabel( osh );
+}
+
+#ifndef QT_NO_PICTURE
+/*!
+ Sets the label contents to \a picture. Any previous content is
+ cleared.
+
+ The buddy accelerator, if any, is disabled.
+
+ \sa picture(), setBuddy()
+*/
+
+void QLabel::setPicture( const QPicture &picture )
+{
+ QSize osh = sizeHint();
+ clearContents();
+ lpicture = new QPicture( picture );
+
+ updateLabel( osh );
+}
+#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 accelerator, if any, is disabled.
+
+ The label resizes itself if auto-resizing is enabled.
+
+ \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 accelerator, if any, is disabled.
+
+ The label resizes itself if auto-resizing is enabled.
+
+ \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
+
+ The alignment is a bitwise OR of \c Qt::AlignmentFlags and \c
+ Qt::TextFlags values. The \c ExpandTabs, \c SingleLine and \c
+ ShowPrefix flags apply only if the label contains plain text;
+ otherwise they are ignored. The \c DontClip flag is always
+ ignored. \c WordBreak applies to both rich text and plain text
+ labels. The \c BreakAnywhere flag is not supported in QLabel.
+
+ If the label has a buddy, the \c ShowPrefix flag is forced to
+ TRUE.
+
+ The default alignment is \c{AlignAuto | AlignVCenter | ExpandTabs}
+ if the label doesn't have a buddy and \c{AlignAuto | AlignVCenter
+ | ExpandTabs | ShowPrefix} if the label has a buddy. If the label
+ contains rich text, additionally \c WordBreak is turned on.
+
+ \sa Qt::AlignmentFlags, alignment, setBuddy(), text
+*/
+
+void QLabel::setAlignment( int alignment )
+{
+ if ( alignment == align )
+ return;
+ QSize osh = sizeHint();
+#ifndef QT_NO_ACCEL
+ if ( lbuddy )
+ align = alignment | ShowPrefix;
+ else
+#endif
+ align = alignment;
+
+#ifndef QT_NO_RICHTEXT
+ QString t = ltext;
+ if ( !t.isNull() ) {
+ ltext = QString::null;
+ setText( t );
+ }
+#endif
+
+ updateLabel( osh );
+}
+
+
+/*!
+ \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 \c AlignLeft, to the right edge if alignment() is
+ \c AlignRight, to the top edge if alignment() is \c AlignTop, and
+ to to the bottom edge if alignment() is \c 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().
+
+ \sa alignment, frameWidth(), font()
+*/
+
+void QLabel::setIndent( int indent )
+{
+ extraMargin = indent;
+ updateLabel( QSize( -1, -1 ) );
+}
+
+
+/*!
+ \fn bool QLabel::autoResize() const
+
+ \obsolete
+
+ Returns TRUE if auto-resizing is enabled, or FALSE if auto-resizing
+ is disabled.
+
+ Auto-resizing is disabled by default.
+
+ \sa setAutoResize()
+*/
+
+/*! \obsolete
+ Enables auto-resizing if \a enable is TRUE, or disables it if \a
+ enable is FALSE.
+
+ When auto-resizing is enabled the label will resize itself to fit
+ the contents whenever the contents change. The top-left corner is
+ not moved. This is useful for QLabel widgets that are not managed by
+ a QLayout (e.g., top-level widgets).
+
+ Auto-resizing is disabled by default.
+
+ \sa autoResize(), adjustSize(), sizeHint()
+*/
+
+void QLabel::setAutoResize( bool enable )
+{
+ if ( (bool)autoresize != enable ) {
+ autoresize = enable;
+ if ( autoresize )
+ adjustSize(); // calls resize which repaints
+ }
+}
+
+
+
+/*!
+ 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.
+*/
+
+QSize QLabel::sizeForWidth( int w ) const
+{
+ QRect br;
+ QPixmap *pix = pixmap();
+#ifndef QT_NO_PICTURE
+ QPicture *pic = picture();
+#else
+ const int pic = 0;
+#endif
+#ifndef QT_NO_MOVIE
+ QMovie *mov = movie();
+#else
+ const int mov = 0;
+#endif
+ int hextra = 2 * frameWidth();
+ int vextra = hextra;
+ QFontMetrics fm( fontMetrics() );
+ int xw = fm.width( 'x' );
+ if ( !mov && !pix && !pic ) {
+ int m = indent();
+ if ( m < 0 && hextra ) // no indent, but we do have a frame
+ m = xw / 2 - margin();
+ if ( m >= 0 ) {
+ int horizAlign = QApplication::horizontalAlignment( align );
+ if ( (horizAlign & AlignLeft) || (horizAlign & AlignRight ) )
+ hextra += m;
+ if ( (align & AlignTop) || (align & AlignBottom ) )
+ vextra += m;
+ }
+ }
+
+ if ( pix )
+ br = pix->rect();
+#ifndef QT_NO_PICTURE
+ else if ( pic )
+ br = pic->boundingRect();
+#endif
+#ifndef QT_NO_MOVIE
+ else if ( mov )
+ br = mov->framePixmap().rect();
+#endif
+#ifndef QT_NO_RICHTEXT
+ else if ( doc ) {
+ int oldW = doc->width();
+ if ( align & WordBreak ) {
+ if ( w < 0 )
+ doc->adjustSize();
+ else
+ doc->setWidth( w-hextra );
+ }
+ br = QRect( 0, 0, doc->widthUsed(), doc->height() );
+ doc->setWidth( oldW );
+ }
+#endif
+ else {
+ bool tryWidth = (w < 0) && (align & WordBreak);
+ if ( tryWidth )
+ w = xw * 80;
+ else if ( w < 0 )
+ w = 2000;
+ w -= hextra;
+ br = fm.boundingRect( 0, 0, w ,2000, alignment(), text() );
+ if ( tryWidth && br.height() < 4*fm.lineSpacing() && br.width() > w/2 )
+ br = fm.boundingRect( 0, 0, w/2, 2000, alignment(), text() );
+ if ( tryWidth && br.height() < 2*fm.lineSpacing() && br.width() > w/4 )
+ br = fm.boundingRect( 0, 0, w/4, 2000, alignment(), text() );
+ }
+ int wid = br.width() + hextra;
+ int hei = br.height() + vextra;
+
+ return QSize( wid, hei );
+}
+
+
+/*!
+ \reimp
+*/
+
+int QLabel::heightForWidth( int w ) const
+{
+ if (
+#ifndef QT_NO_RICHTEXT
+ doc ||
+#endif
+ (align & WordBreak) )
+ return sizeForWidth( w ).height();
+ return QWidget::heightForWidth( w );
+}
+
+
+
+/*!\reimp
+*/
+QSize QLabel::sizeHint() const
+{
+ if ( d->valid_hints != frameWidth() )
+ (void) QLabel::minimumSizeHint();
+ return d->sh;
+}
+
+/*!
+ \reimp
+*/
+
+QSize QLabel::minimumSizeHint() const
+{
+ if ( d->valid_hints == frameWidth() )
+ return d->msh;
+
+ constPolish();
+ d->valid_hints = frameWidth();
+ d->sh = sizeForWidth( -1 );
+ QSize sz( -1, -1 );
+
+ if (
+#ifndef QT_NO_RICHTEXT
+ !doc &&
+#endif
+ (align & WordBreak) == 0 ) {
+ sz = d->sh;
+ } else {
+ // think about caching these for performance
+ sz.rwidth() = sizeForWidth( 0 ).width();
+ sz.rheight() = sizeForWidth(QWIDGETSIZE_MAX).height();
+ if ( d->sh.height() < sz.height() )
+ sz.rheight() = d->sh.height();
+ }
+ if ( sizePolicy().horData() == QSizePolicy::Ignored )
+ sz.rwidth() = -1;
+ if ( sizePolicy().verData() == QSizePolicy::Ignored )
+ sz.rheight() = -1;
+ d->msh = sz;
+ return sz;
+}
+
+/*!
+ \reimp
+*/
+void QLabel::resizeEvent( QResizeEvent* e )
+{
+ QFrame::resizeEvent( e );
+
+#ifdef QT_NO_RICHTEXT
+ static const bool doc = FALSE;
+#endif
+
+ // optimize for standard labels
+ if ( frameShape() == NoFrame && (align & WordBreak) == 0 && !doc &&
+ ( e->oldSize().width() >= e->size().width() && (align & AlignLeft ) == AlignLeft )
+ && ( e->oldSize().height() >= e->size().height() && (align & AlignTop ) == AlignTop ) ) {
+ setWFlags( WResizeNoErase );
+ return;
+ }
+
+ clearWFlags( WResizeNoErase );
+ QRect cr = contentsRect();
+ if ( !lpixmap || !cr.isValid() ||
+ // masked pixmaps can only reduce flicker when being top/left
+ // aligned and when we do not perform scaled contents
+ ( lpixmap->hasAlpha() && ( scaledcontents || ( ( align & (AlignLeft|AlignTop) ) != (AlignLeft|AlignTop) ) ) ) )
+ return;
+
+ setWFlags( WResizeNoErase );
+
+ if ( !scaledcontents ) {
+ // don't we all love QFrame? Reduce pixmap flicker
+ QRegion reg = QRect( QPoint(0, 0), e->size() );
+ reg = reg.subtract( cr );
+ int x = cr.x();
+ int y = cr.y();
+ int w = lpixmap->width();
+ int h = lpixmap->height();
+ if ( (align & Qt::AlignVCenter) == Qt::AlignVCenter )
+ y += cr.height()/2 - h/2;
+ else if ( (align & Qt::AlignBottom) == Qt::AlignBottom)
+ y += cr.height() - h;
+ if ( (align & Qt::AlignRight) == Qt::AlignRight )
+ x += cr.width() - w;
+ else if ( (align & Qt::AlignHCenter) == Qt::AlignHCenter )
+ x += cr.width()/2 - w/2;
+ if ( x > cr.x() )
+ reg = reg.unite( QRect( cr.x(), cr.y(), x - cr.x(), cr.height() ) );
+ if ( y > cr.y() )
+ reg = reg.unite( QRect( cr.x(), cr.y(), cr.width(), y - cr.y() ) );
+
+ if ( x + w < cr.right() )
+ reg = reg.unite( QRect( x + w, cr.y(), cr.right() - x - w, cr.height() ) );
+ if ( y + h < cr.bottom() )
+ reg = reg.unite( QRect( cr.x(), y + h, cr.width(), cr.bottom() - y - h ) );
+
+ erase( reg );
+ }
+}
+
+
+/*!
+ Draws the label contents using the painter \a p.
+*/
+
+void QLabel::drawContents( QPainter *p )
+{
+ QRect cr = contentsRect();
+
+ QPixmap *pix = pixmap();
+#ifndef QT_NO_PICTURE
+ QPicture *pic = picture();
+#else
+ const int pic = 0;
+#endif
+#ifndef QT_NO_MOVIE
+ QMovie *mov = movie();
+#else
+ const int mov = 0;
+#endif
+
+ if ( !mov && !pix && !pic ) {
+ int m = indent();
+ if ( m < 0 && frameWidth() ) // no indent, but we do have a frame
+ m = fontMetrics().width('x') / 2 - margin();
+ if ( m > 0 ) {
+ int hAlign = QApplication::horizontalAlignment( align );
+ if ( hAlign & AlignLeft )
+ cr.setLeft( cr.left() + m );
+ if ( hAlign & AlignRight )
+ cr.setRight( cr.right() - m );
+ if ( align & AlignTop )
+ cr.setTop( cr.top() + m );
+ if ( align & AlignBottom )
+ cr.setBottom( cr.bottom() - m );
+ }
+ }
+
+#ifndef QT_NO_MOVIE
+ if ( mov ) {
+ // ### should add movie to qDrawItem
+ QRect r = style().itemRect( p, cr, align, isEnabled(), &(mov->framePixmap()),
+ QString::null );
+ // ### could resize movie frame at this point
+ p->drawPixmap(r.x(), r.y(), mov->framePixmap() );
+ }
+ else
+#endif
+#ifndef QT_NO_RICHTEXT
+ if ( doc ) {
+ doc->setWidth(p, cr.width() );
+ int rh = doc->height();
+ int yo = 0;
+ if ( align & AlignVCenter )
+ yo = (cr.height()-rh)/2;
+ else if ( align & AlignBottom )
+ yo = cr.height()-rh;
+ if (! isEnabled() &&
+ style().styleHint(QStyle::SH_EtchDisabledText, this)) {
+ QColorGroup cg = colorGroup();
+ cg.setColor( QColorGroup::Text, cg.light() );
+ doc->draw(p, cr.x()+1, cr.y()+yo+1, cr, cg, 0);
+ }
+
+ // QSimpleRichText always draws with QColorGroup::Text as with
+ // background mode PaletteBase. QLabel typically has
+ // background mode PaletteBackground, so we create a temporary
+ // color group with the text color adjusted.
+ QColorGroup cg = colorGroup();
+ if ( backgroundMode() != PaletteBase && isEnabled() )
+ cg.setColor( QColorGroup::Text, paletteForegroundColor() );
+
+ doc->draw(p, cr.x(), cr.y()+yo, cr, cg, 0);
+ } else
+#endif
+#ifndef QT_NO_PICTURE
+ if ( pic ) {
+ QRect br = pic->boundingRect();
+ int rw = br.width();
+ int rh = br.height();
+ if ( scaledcontents ) {
+ p->save();
+ p->translate( cr.x(), cr.y() );
+#ifndef QT_NO_TRANSFORMATIONS
+ p->scale( (double)cr.width()/rw, (double)cr.height()/rh );
+#endif
+ p->drawPicture( -br.x(), -br.y(), *pic );
+ p->restore();
+ } else {
+ int xo = 0;
+ int yo = 0;
+ if ( align & AlignVCenter )
+ yo = (cr.height()-rh)/2;
+ else if ( align & AlignBottom )
+ yo = cr.height()-rh;
+ if ( align & AlignRight )
+ xo = cr.width()-rw;
+ else if ( align & AlignHCenter )
+ xo = (cr.width()-rw)/2;
+ p->drawPicture( cr.x()+xo-br.x(), cr.y()+yo-br.y(), *pic );
+ }
+ } else
+#endif
+ {
+#ifndef QT_NO_IMAGE_SMOOTHSCALE
+ if ( scaledcontents && pix ) {
+ if ( !d->img )
+ d->img = new QImage( lpixmap->convertToImage() );
+
+ if ( !d->pix )
+ d->pix = new QPixmap;
+ if ( d->pix->size() != cr.size() )
+ d->pix->convertFromImage( d->img->smoothScale( cr.width(), cr.height() ) );
+ pix = d->pix;
+ }
+#endif
+ int alignment = align;
+ if ((align & ShowPrefix) && !style().styleHint(QStyle::SH_UnderlineAccelerator, this))
+ alignment |= NoAccel;
+ // ordinary text or pixmap label
+ style().drawItem( p, cr, alignment, colorGroup(), isEnabled(),
+ pix, ltext );
+ }
+}
+
+
+/*!
+ Updates the label, but not the frame.
+*/
+
+void QLabel::updateLabel( QSize oldSizeHint )
+{
+ d->valid_hints = -1;
+ QSizePolicy policy = sizePolicy();
+ bool wordBreak = align & WordBreak;
+ policy.setHeightForWidth( wordBreak );
+ if ( policy != sizePolicy() )
+ setSizePolicy( policy );
+ if ( sizeHint() != oldSizeHint )
+ updateGeometry();
+ if ( autoresize ) {
+ adjustSize();
+ update( contentsRect() );
+ } else {
+ update( contentsRect() );
+ }
+}
+
+
+/*!
+ \internal
+
+ Internal slot, used to set focus for accelerator labels.
+*/
+#ifndef QT_NO_ACCEL
+void QLabel::acceleratorSlot()
+{
+ if ( !lbuddy )
+ return;
+ QWidget * w = lbuddy;
+ while ( w->focusProxy() )
+ w = w->focusProxy();
+ if ( !w->hasFocus() &&
+ w->isEnabled() &&
+ w->isVisible() &&
+ w->focusPolicy() != NoFocus ) {
+ QFocusEvent::setReason( QFocusEvent::Shortcut );
+ w->setFocus();
+ QFocusEvent::resetReason();
+ }
+}
+#endif
+
+/*!
+ \internal
+
+ Internal slot, used to clean up if the buddy widget dies.
+*/
+#ifndef QT_NO_ACCEL
+void QLabel::buddyDied() // I can't remember if I cried.
+{
+ lbuddy = 0;
+}
+
+/*!
+ Sets this label's buddy to \a buddy.
+
+ When the user presses the accelerator 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
+ plain text in which one letter is prefixed with an ampersand, \&.
+ This letter is set as the accelerator key. The letter is displayed
+ underlined, and the '\&' is not displayed (i.e. the \c ShowPrefix
+ alignment flag is turned on; see setAlignment()).
+
+ 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:
+ \code
+ QLineEdit *nameEd = new QLineEdit( this );
+ QLabel *nameLb = new QLabel( "&Name:", this );
+ nameLb->setBuddy( nameEd );
+ QLineEdit *phoneEd = new QLineEdit( this );
+ QLabel *phoneLb = new QLabel( "&Phone:", this );
+ phoneLb->setBuddy( phoneEd );
+ // ( layout setup not shown )
+ \endcode
+
+ 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(), QAccel, setAlignment()
+*/
+
+void QLabel::setBuddy( QWidget *buddy )
+{
+ if ( buddy )
+ setAlignment( alignment() | ShowPrefix );
+ else
+ setAlignment( alignment() & ~ShowPrefix );
+
+ if ( lbuddy )
+ disconnect( lbuddy, SIGNAL(destroyed()), this, SLOT(buddyDied()) );
+
+ lbuddy = buddy;
+
+ if ( !lbuddy )
+ return;
+#ifndef QT_NO_RICHTEXT
+ if ( !( textformat == RichText || (textformat == AutoText &&
+ QStyleSheet::mightBeRichText(ltext) ) ) )
+#endif
+ {
+ int p = QAccel::shortcutKey( ltext );
+ if ( p ) {
+ if ( !accel )
+ accel = new QAccel( this, "accel label accel" );
+ accel->connectItem( accel->insertItem( p ),
+ this, SLOT(acceleratorSlot()) );
+ }
+ }
+
+ connect( lbuddy, SIGNAL(destroyed()), this, SLOT(buddyDied()) );
+}
+
+
+/*!
+ Returns this label's buddy, or 0 if no buddy is currently set.
+
+ \sa setBuddy()
+*/
+
+QWidget * QLabel::buddy() const
+{
+ return lbuddy;
+}
+#endif //QT_NO_ACCEL
+
+
+#ifndef QT_NO_MOVIE
+void QLabel::movieUpdated(const QRect& rect)
+{
+ QMovie *mov = movie();
+ if ( mov && !mov->isNull() ) {
+ QRect r = contentsRect();
+ r = style().itemRect( 0, r, align, isEnabled(), &(mov->framePixmap()),
+ QString::null );
+ r.moveBy(rect.x(), rect.y());
+ r.setWidth(QMIN(r.width(), rect.width()));
+ r.setHeight(QMIN(r.height(), rect.height()));
+ repaint( r, mov->framePixmap().mask() != 0 );
+ }
+}
+
+void QLabel::movieResized( const QSize& size )
+{
+ d->valid_hints = -1;
+ if ( autoresize )
+ adjustSize();
+ movieUpdated( QRect( QPoint(0,0), size ) );
+ updateGeometry();
+}
+
+/*!
+ Sets the label contents to \a movie. Any previous content is
+ cleared.
+
+ The buddy accelerator, if any, is disabled.
+
+ The label resizes itself if auto-resizing is enabled.
+
+ \sa movie(), setBuddy()
+*/
+
+void QLabel::setMovie( const QMovie& movie )
+{
+ QSize osh = sizeHint();
+ clearContents();
+
+ lmovie = new QMovie( movie );
+ lmovie->connectResize(this, SLOT(movieResized(const QSize&)));
+ lmovie->connectUpdate(this, SLOT(movieUpdated(const QRect&)));
+
+ if ( !lmovie->running() ) // Assume that if the movie is running,
+ updateLabel( osh ); // resize/update signals will come soon enough
+}
+
+#endif // QT_NO_MOVIE
+
+/*!
+ \internal
+
+ Clears any contents, without updating/repainting the label.
+*/
+
+void QLabel::clearContents()
+{
+#ifndef QT_NO_RICHTEXT
+ delete doc;
+ doc = 0;
+#endif
+
+ delete lpixmap;
+ lpixmap = 0;
+#ifndef QT_NO_PICTURE
+ delete lpicture;
+ lpicture = 0;
+#endif
+ delete d->img;
+ d->img = 0;
+ delete d->pix;
+ d->pix = 0;
+
+ ltext = QString::null;
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ accel->clear();
+#endif
+#ifndef QT_NO_MOVIE
+ if ( lmovie ) {
+ lmovie->disconnectResize(this, SLOT(movieResized(const QSize&)));
+ lmovie->disconnectUpdate(this, SLOT(movieUpdated(const QRect&)));
+ delete lmovie;
+ lmovie = 0;
+ }
+#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
+{
+ return lmovie;
+}
+
+#endif // QT_NO_MOVIE
+
+/*!
+ \property QLabel::backgroundMode
+ \brief the label's background mode
+
+ Get this property with backgroundMode().
+
+ \sa QWidget::setBackgroundMode()
+*/
+
+/*!
+ \property QLabel::textFormat
+ \brief the label's text format
+
+ See the \c Qt::TextFormat enum for an explanation of the possible
+ options.
+
+ The default format is \c AutoText.
+
+ \sa text
+*/
+
+Qt::TextFormat QLabel::textFormat() const
+{
+ return textformat;
+}
+
+void QLabel::setTextFormat( Qt::TextFormat format )
+{
+ if ( format != textformat ) {
+ textformat = format;
+ QString t = ltext;
+ if ( !t.isNull() ) {
+ ltext = QString::null;
+ setText( t );
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QLabel::fontChange( const QFont & )
+{
+ if ( !ltext.isEmpty() ) {
+#ifndef QT_NO_RICHTEXT
+ if ( doc )
+ doc->setDefaultFont( font() );
+#endif
+ updateLabel( QSize( -1, -1 ) );
+ }
+}
+
+#ifndef QT_NO_IMAGE_SMOOTHSCALE
+/*!
+ \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.
+
+ \sa setScaledContents()
+*/
+bool QLabel::hasScaledContents() const
+{
+ return scaledcontents;
+}
+
+void QLabel::setScaledContents( bool enable )
+{
+ if ( (bool)scaledcontents == enable )
+ return;
+ scaledcontents = enable;
+ if ( !enable ) {
+ delete d->img;
+ d->img = 0;
+ delete d->pix;
+ d->pix = 0;
+ }
+ update( contentsRect() );
+}
+
+#endif // QT_NO_IMAGE_SMOOTHSCALE
+
+/*!
+ Sets the font used on the QLabel to font \a f.
+*/
+
+void QLabel::setFont( const QFont &f )
+{
+ QFrame::setFont( f );
+}
+
+#endif // QT_NO_LABEL
diff --git a/src/widgets/qlabel.h b/src/widgets/qlabel.h
new file mode 100644
index 0000000..ac1b83b
--- /dev/null
+++ b/src/widgets/qlabel.h
@@ -0,0 +1,174 @@
+/**********************************************************************
+**
+** Definition of QLabel widget class
+**
+** Created : 941215
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QLABEL_H
+#define QLABEL_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_LABEL
+
+class QSimpleRichText;
+class QLabelPrivate;
+
+class Q_EXPORT QLabel : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( QString text READ text WRITE setText )
+ Q_PROPERTY( TextFormat textFormat READ textFormat WRITE setTextFormat )
+ Q_PROPERTY( QPixmap pixmap READ pixmap WRITE setPixmap )
+ Q_PROPERTY( bool scaledContents READ hasScaledContents WRITE setScaledContents )
+ Q_PROPERTY( Alignment alignment READ alignment WRITE setAlignment )
+ Q_PROPERTY( int indent READ indent WRITE setIndent )
+ Q_OVERRIDE( BackgroundMode backgroundMode DESIGNABLE true)
+
+public:
+ QLabel( QWidget *parent, const char* name=0, WFlags f=0 );
+ QLabel( const QString &text, QWidget *parent, const char* name=0,
+ WFlags f=0 );
+ QLabel( QWidget *buddy, const QString &,
+ QWidget *parent, const char* name=0, WFlags f=0 );
+ ~QLabel();
+
+ QString text() const { return ltext; }
+ QPixmap *pixmap() const { return lpixmap; }
+#ifndef QT_NO_PICTURE
+ QPicture *picture() const { return lpicture; }
+#endif
+#ifndef QT_NO_MOVIE
+ QMovie *movie() const;
+#endif
+
+ TextFormat textFormat() const;
+ void setTextFormat( TextFormat );
+
+ int alignment() const { return align; }
+ virtual void setAlignment( int );
+ int indent() const { return extraMargin; }
+ void setIndent( int );
+
+ bool autoResize() const { return autoresize; }
+ virtual void setAutoResize( bool );
+#ifndef QT_NO_IMAGE_SMOOTHSCALE
+ bool hasScaledContents() const;
+ void setScaledContents( bool );
+#endif
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+#ifndef QT_NO_ACCEL
+ virtual void setBuddy( QWidget * );
+ QWidget *buddy() const;
+#endif
+ int heightForWidth(int) const;
+
+ void setFont( const QFont &f );
+
+public slots:
+ virtual void setText( const QString &);
+ virtual void setPixmap( const QPixmap & );
+#ifndef QT_NO_PICTURE
+ virtual void setPicture( const QPicture & );
+#endif
+#ifndef QT_NO_MOVIE
+ virtual void setMovie( const QMovie & );
+#endif
+ virtual void setNum( int );
+ virtual void setNum( double );
+ void clear();
+
+protected:
+ void drawContents( QPainter * );
+ void fontChange( const QFont & );
+ void resizeEvent( QResizeEvent* );
+
+private slots:
+#ifndef QT_NO_ACCEL
+ void acceleratorSlot();
+ void buddyDied();
+#endif
+#ifndef QT_NO_MOVIE
+ void movieUpdated(const QRect&);
+ void movieResized(const QSize&);
+#endif
+
+private:
+ void init();
+ void clearContents();
+ void updateLabel( QSize oldSizeHint );
+ QSize sizeForWidth( int w ) const;
+ QString ltext;
+ QPixmap *lpixmap;
+#ifndef QT_NO_PICTURE
+ QPicture *lpicture;
+#endif
+#ifndef QT_NO_MOVIE
+ QMovie * lmovie;
+#endif
+#ifndef QT_NO_ACCEL
+ QWidget * lbuddy;
+#endif
+ ushort align;
+ short extraMargin;
+ uint autoresize:1;
+ uint scaledcontents :1;
+ TextFormat textformat;
+#ifndef QT_NO_RICHTEXT
+ QSimpleRichText* doc;
+#endif
+#ifndef QT_NO_ACCEL
+ QAccel * accel;
+#endif
+ QLabelPrivate* d;
+
+ friend class QTipLabel;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QLabel( const QLabel & );
+ QLabel &operator=( const QLabel & );
+#endif
+};
+
+
+#endif // QT_NO_LABEL
+
+#endif // QLABEL_H
diff --git a/src/widgets/qlcdnumber.cpp b/src/widgets/qlcdnumber.cpp
new file mode 100644
index 0000000..4398907
--- /dev/null
+++ b/src/widgets/qlcdnumber.cpp
@@ -0,0 +1,1170 @@
+/****************************************************************************
+**
+** Implementation of QLCDNumber class
+**
+** Created : 940518
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qlcdnumber.h"
+#ifndef QT_NO_LCDNUMBER
+#include "qbitarray.h"
+#include "qpainter.h"
+
+
+/*!
+ \class QLCDNumber qlcdnumber.h
+
+ \brief The QLCDNumber widget displays a number with LCD-like digits.
+
+ \ingroup basic
+ \mainclass
+
+ 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 setNumDigits(),
+ 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
+ back to a BASIC program on the \link
+ http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm
+ Sinclair Spectrum\endlink.
+
+ <img src=qlcdnum-m.png> <img src=qlcdnum-w.png>
+
+ \sa QLabel, QFrame
+*/
+
+/*!
+ \enum QLCDNumber::Mode
+
+ This type determines how numbers are shown.
+
+ \value Hex Hexadecimal
+ \value Dec Decimal
+ \value Oct Octal
+ \value Bin Binary
+
+ 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 brush.
+ \value Filled gives raised segments filled with the foreground brush.
+ \value Flat gives flat segments filled with the foreground brush.
+*/
+
+
+
+/*!
+ \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 setNumDigits().
+*/
+
+
+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( ' ', len );
+ s += QString::fromLatin1(p);
+ }
+ break;
+ }
+ if ( negative ) {
+ for ( int i=0; i<(int)s.length(); i++ ) {
+ if ( s[i] != ' ' ) {
+ if ( i != 0 ) {
+ s[i-1] = '-';
+ } else {
+ s.insert( 0, '-' );
+ }
+ 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.find('e');
+ if ( i > 0 && s[i+1]=='+' ) {
+ s[i] = ' ';
+ s[i+1] = '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];
+}
+
+
+/*!
+ 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 setNumDigits(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber( QWidget *parent, const char *name )
+ : QFrame( parent, name )
+{
+ ndigits = 5;
+ 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 Outline.
+
+ The \a parent and \a name arguments are passed to the QFrame
+ constructor.
+
+ \sa setNumDigits(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber( uint numDigits, QWidget *parent, const char *name )
+ : QFrame( parent, name )
+{
+ ndigits = numDigits;
+ init();
+}
+
+/*!
+ \internal
+*/
+
+void QLCDNumber::init()
+{
+ setFrameStyle( QFrame::Box | QFrame::Raised );
+ val = 0;
+ base = DEC;
+ smallPoint = FALSE;
+ setNumDigits( ndigits );
+ setSegmentStyle( Outline );
+ d = 0;
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+}
+
+/*!
+ Destroys the LCD number.
+*/
+
+QLCDNumber::~QLCDNumber()
+{
+}
+
+
+/*!
+ \property QLCDNumber::numDigits
+ \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.
+
+ \sa numDigits, smallDecimalPoint
+*/
+
+void QLCDNumber::setNumDigits( int numDigits )
+{
+ if ( numDigits > 99 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
+ name( "unnamed" ) );
+#endif
+ numDigits = 99;
+ }
+ if (numDigits < 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
+ name( "unnamed" ) );
+#endif
+ numDigits = 0;
+ }
+ if ( digitStr.isNull() ) { // from constructor
+ ndigits = numDigits;
+ digitStr.fill( ' ', ndigits );
+ points.fill( 0, ndigits );
+ digitStr[ndigits - 1] = '0'; // "0" is the default number
+ } else {
+ bool doDisplay = ndigits == 0;
+ if ( numDigits == ndigits ) // no change
+ return;
+ register int i;
+ int dif;
+ if ( numDigits > ndigits ) { // expand
+ dif = numDigits - ndigits;
+ QString buf;
+ buf.fill( ' ', dif );
+ digitStr.insert( 0, buf );
+ points.resize( numDigits );
+ for ( i=numDigits-1; i>=dif; i-- )
+ points.setBit( i, points.testBit(i-dif) );
+ for ( i=0; i<dif; i++ )
+ points.clearBit( i );
+ } else { // shrink
+ dif = ndigits - numDigits;
+ digitStr = digitStr.right( numDigits );
+ QBitArray tmpPoints = points.copy();
+ points.resize( numDigits );
+ for ( i=0; i<(int)numDigits; i++ )
+ points.setBit( i, tmpPoints.testBit(i+dif) );
+ }
+ ndigits = numDigits;
+ if ( doDisplay )
+ display( value() );
+ update();
+ }
+}
+
+
+/*!
+ \overload
+
+ Returns TRUE if \a num is too big to be displayed in its entirety;
+ otherwise returns FALSE.
+
+ \sa display(), numDigits(), smallDecimalPoint()
+*/
+
+bool QLCDNumber::checkOverflow( int num ) const
+{
+ bool of;
+ int2string( num, base, ndigits, &of );
+ return of;
+}
+
+
+/*!
+ Returns TRUE if \a num is too big to be displayed in its entirety;
+ otherwise returns FALSE.
+
+ \sa display(), numDigits(), smallDecimalPoint()
+*/
+
+bool QLCDNumber::checkOverflow( double num ) const
+{
+ bool of;
+ double2string( num, base, 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
+{
+ return (QLCDNumber::Mode) base;
+}
+
+void QLCDNumber::setMode( Mode m )
+{
+ base = m;
+
+ display( 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.
+*/
+
+double QLCDNumber::value() const
+{
+ return val;
+}
+
+/*!
+ \overload
+
+ Displays the number \a num.
+*/
+void QLCDNumber::display( double num )
+{
+ val = num;
+ bool of;
+ QString s = double2string( num, base, ndigits, &of );
+ if ( of )
+ emit overflow();
+ else
+ 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.
+*/
+int QLCDNumber::intValue() const
+{
+ return (int)(val < 0 ? val - 0.5 : val + 0.5);
+}
+
+
+/*!
+ \overload
+
+ Displays the number \a num.
+*/
+void QLCDNumber::display( int num )
+{
+ val = (double)num;
+ bool of;
+ QString s = int2string( num, base, ndigits, &of );
+ if ( of )
+ emit overflow();
+ else
+ 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 )
+{
+ val = 0;
+ bool ok = FALSE;
+ double v = s.toDouble( &ok );
+ if ( ok )
+ val = v;
+ 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 )
+{
+ smallPoint = b;
+}
+
+
+/*!
+ Draws the LCD number using painter \a p. This function is called
+ from QFrame::paintEvent().
+*/
+
+
+void QLCDNumber::drawContents( QPainter *p )
+{
+ if ( smallPoint )
+ drawString( digitStr, *p, &points, FALSE );
+ else
+ drawString( digitStr, *p, 0, FALSE );
+}
+
+
+/*!
+ \internal
+*/
+
+void QLCDNumber::internalDisplay( const QString & )
+{
+ // Not used anymore
+}
+
+void QLCDNumber::internalSetString( const QString& s )
+{
+ QString buffer;
+ int i;
+ int len = s.length();
+ QBitArray newPoints(ndigits);
+
+ if ( !smallPoint ) {
+ if ( len == ndigits )
+ buffer = s;
+ else
+ buffer = s.right( ndigits ).rightJustify( ndigits, ' ' );
+ } else {
+ int index = -1;
+ bool lastWasPoint = TRUE;
+ newPoints.clearBit(0);
+ for ( i=0; i<len; i++ ) {
+ if ( s[i] == '.' ) {
+ if ( lastWasPoint ) { // point already set for digit?
+ if ( index == ndigits - 1 ) // no more digits
+ break;
+ index++;
+ buffer[index] = ' '; // 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] = ' ';
+ newPoints.clearBit(i);
+ }
+ }
+ }
+
+ if ( buffer == digitStr )
+ return;
+
+ if ( backgroundMode() == FixedPixmap
+ || colorGroup().brush( QColorGroup::Background ).pixmap() ) {
+ digitStr = buffer;
+ if ( smallPoint )
+ points = newPoints;
+ repaint( contentsRect() );
+ } else {
+ QPainter p( this );
+ if ( !smallPoint )
+ drawString( buffer, p );
+ else
+ drawString( buffer, p, &newPoints );
+ }
+}
+
+/*!
+ \internal
+*/
+
+void QLCDNumber::drawString( const QString &s, QPainter &p,
+ QBitArray *newPoints, bool newString )
+{
+ QPoint pos;
+
+ int digitSpace = smallPoint ? 2 : 1;
+ int xSegLen = width()*5/(ndigits*(5 + digitSpace) + digitSpace);
+ int ySegLen = height()*5/12;
+ int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
+ int xAdvance = segLen*( 5 + digitSpace )/5;
+ int xOffset = ( width() - ndigits*xAdvance + segLen/5 )/2;
+ int yOffset = ( 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], digitStr[i].latin1() );
+ else
+ drawDigit( pos, p, segLen, s[i]);
+ 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;
+ if ( (int)digitStr.length() > ndigits )
+ digitStr.truncate( ndigits );
+ if ( newPoints )
+ points = *newPoints;
+ }
+}
+
+
+/*!
+ \internal
+*/
+
+void QLCDNumber::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( QPointArray &a, const QPoint &p )
+{
+ uint n = a.size();
+ a.resize( n + 1 );
+ a.setPoint( n, p );
+}
+
+/*!
+ \internal
+*/
+
+void QLCDNumber::drawSegment( const QPoint &pos, char segmentNo, QPainter &p,
+ int segLen, bool erase )
+{
+ QPoint pt = pos;
+ int width = segLen/5;
+
+ const QColorGroup & g = colorGroup();
+ QColor lightColor,darkColor,fgColor;
+ if ( erase ){
+ lightColor = backgroundColor();
+ darkColor = lightColor;
+ fgColor = lightColor;
+ } else {
+ lightColor = g.light();
+ darkColor = g.dark();
+ fgColor = g.foreground();
+ }
+
+#define LINETO(X,Y) addPoint( a, QPoint(pt.x() + (X),pt.y() + (Y)))
+#define LIGHT
+#define DARK
+
+ if ( fill ) {
+ QPointArray a(0);
+
+ //The following is an exact copy of the switch below.
+ //don't make any changes here
+ switch ( segmentNo ) {
+ case 0 :
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+#if defined(QT_CHECK_RANGE)
+ default :
+ qWarning( "QLCDNumber::drawSegment: (%s) Internal error."
+ " Illegal segment id: %d\n",
+ name( "unnamed" ), segmentNo );
+#endif
+ }
+ // End exact copy
+ p.setPen( fgColor );
+ p.setBrush( fgColor );
+ p.drawPolygon( a );
+ p.setBrush( NoBrush );
+
+ pt = pos;
+ }
+#undef LINETO
+#undef LIGHT
+#undef DARK
+
+#define LINETO(X,Y) p.lineTo(QPoint(pt.x() + (X),pt.y() + (Y)))
+#define LIGHT p.setPen(lightColor)
+#define DARK p.setPen(darkColor)
+ if ( shadow )
+ switch ( segmentNo ) {
+ case 0 :
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(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);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+#if defined(QT_CHECK_RANGE)
+ default :
+ qWarning( "QLCDNumber::drawSegment: (%s) Internal error."
+ " Illegal segment id: %d\n",
+ name( "unnamed" ), segmentNo );
+#endif
+ }
+
+#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
+ (this is the default).
+ \row \i \c Filled
+ \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
+ QColorGroup::light() and QColorGroup::dark() for shadow effects.
+*/
+void QLCDNumber::setSegmentStyle( SegmentStyle s )
+{
+ fill = ( s == Flat || s == Filled );
+ shadow = ( s == Outline || s == Filled );
+ update();
+}
+
+QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const
+{
+ Q_ASSERT( fill || shadow );
+ if ( !fill && shadow )
+ return Outline;
+ if ( fill && shadow )
+ return Filled;
+ return Flat;
+}
+
+
+/*!\reimp
+*/
+QSize QLCDNumber::sizeHint() const
+{
+ return QSize( 10 + 9 * (numDigits() + (smallDecimalPoint() ? 0 : 1)), 23 );
+}
+
+#endif // QT_NO_LCDNUMBER
diff --git a/src/widgets/qlcdnumber.h b/src/widgets/qlcdnumber.h
new file mode 100644
index 0000000..fb4780a
--- /dev/null
+++ b/src/widgets/qlcdnumber.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Definition of QLCDNumber class
+**
+** Created : 940518
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QLCDNUMBER_H
+#define QLCDNUMBER_H
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qbitarray.h"
+#endif // QT_H
+
+#ifndef QT_NO_LCDNUMBER
+
+
+class QLCDNumberPrivate;
+
+class Q_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( 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:
+ QLCDNumber( QWidget* parent=0, const char* name=0 );
+ QLCDNumber( uint numDigits, QWidget* parent=0, const char* name=0 );
+ ~QLCDNumber();
+
+ enum Mode { Hex, Dec, Oct, Bin, HEX = Hex, DEC = Dec, OCT = Oct,
+ BIN = Bin };
+ enum SegmentStyle { Outline, Filled, Flat };
+
+ bool smallDecimalPoint() const;
+
+ int numDigits() const;
+ virtual void setNumDigits( int nDigits );
+
+ bool checkOverflow( double num ) const;
+ bool checkOverflow( int num ) const;
+
+ Mode mode() const;
+ virtual void setMode( Mode );
+
+ SegmentStyle segmentStyle() const;
+ virtual void setSegmentStyle( SegmentStyle );
+
+ double value() const;
+ int intValue() const;
+
+ QSize sizeHint() const;
+
+public slots:
+ void display( const QString &str );
+ void display( int num );
+ void display( double num );
+ virtual void setHexMode();
+ virtual void setDecMode();
+ virtual void setOctMode();
+ virtual void setBinMode();
+ virtual void setSmallDecimalPoint( bool );
+
+signals:
+ void overflow();
+
+protected:
+ void drawContents( QPainter * );
+
+private:
+ void init();
+ void internalDisplay( const QString &);
+ 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;
+ QLCDNumberPrivate * d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QLCDNumber( const QLCDNumber & );
+ QLCDNumber &operator=( const QLCDNumber & );
+#endif
+};
+
+inline bool QLCDNumber::smallDecimalPoint() const
+{ return (bool)smallPoint; }
+
+inline int QLCDNumber::numDigits() const
+{ return ndigits; }
+
+
+#endif // QT_NO_LCDNUMBER
+
+#endif // QLCDNUMBER_H
diff --git a/src/widgets/qlineedit.cpp b/src/widgets/qlineedit.cpp
new file mode 100644
index 0000000..d786829
--- /dev/null
+++ b/src/widgets/qlineedit.cpp
@@ -0,0 +1,2925 @@
+/**********************************************************************
+**
+** Implementation of QLineEdit widget class
+**
+** Created : 941011
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qlineedit.h"
+#ifndef QT_NO_LINEEDIT
+
+// Keep this position to avoid patch rejection
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#endif
+
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qfontmetrics.h"
+#include "qpixmap.h"
+#include "qclipboard.h"
+#include "qapplication.h"
+#include "qvalidator.h"
+#include "qdragobject.h"
+#include "qtimer.h"
+#include "qpopupmenu.h"
+#include "qstringlist.h"
+#include "qguardedptr.h"
+#include "qstyle.h"
+#include "qwhatsthis.h"
+#include "../kernel/qinternal_p.h"
+#include "private/qtextlayout_p.h"
+#include "qvaluevector.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+#ifndef QT_NO_ACCEL
+#include "qkeysequence.h"
+#define ACCEL_KEY(k) "\t" + QString(QKeySequence( Qt::CTRL | Qt::Key_ ## k ))
+#else
+#define ACCEL_KEY(k) "\t" + QString("Ctrl+" #k)
+#endif
+
+#define innerMargin 1
+
+struct QLineEditPrivate : public Qt
+{
+ QLineEditPrivate( QLineEdit *q )
+ : q(q), cursor(0), cursorTimer(0), tripleClickTimer(0), frame(1),
+ cursorVisible(0), separator(0), readOnly(0), modified(0),
+ direction(QChar::DirON), dragEnabled(1), alignment(0),
+ echoMode(0), textDirty(0), selDirty(0), validInput(1),
+ ascent(0), maxLength(32767), menuId(0),
+ hscroll(0), validator(0), maskData(0),
+ undoState(0), selstart(0), selend(0),
+ imstart(0), imend(0), imselstart(0), imselend(0)
+#ifndef QT_NO_DRAGANDDROP
+ ,dndTimer(0)
+#endif
+ {}
+ void init( const QString&);
+
+ QLineEdit *q;
+ QString text;
+ int cursor;
+ int cursorTimer;
+ QPoint tripleClick;
+ int tripleClickTimer;
+ uint frame : 1;
+ uint cursorVisible : 1;
+ uint separator : 1;
+ uint readOnly : 1;
+ uint modified : 1;
+ uint direction : 5;
+ uint dragEnabled : 1;
+ uint alignment : 3;
+ uint echoMode : 2;
+ uint textDirty : 1;
+ uint selDirty : 1;
+ uint validInput : 1;
+ int ascent;
+ int maxLength;
+ int menuId;
+ int hscroll;
+ QChar passwordChar; // obsolete
+
+ void finishChange( int validateFromState = -1, bool setModified = TRUE );
+
+ const QValidator* validator;
+ struct MaskInputData {
+ enum Casemode { NoCaseMode, Upper, Lower };
+ QChar maskChar; // either the separator char or the inputmask
+ bool separator;
+ Casemode caseMode;
+ };
+ QString inputMask;
+ QChar blank;
+ MaskInputData *maskData;
+ inline int nextMaskBlank( int pos ) {
+ int c = findInMask( pos, TRUE, FALSE );
+ separator |= ( c != pos );
+ return ( c != -1 ? c : maxLength );
+ }
+ inline int prevMaskBlank( int pos ) {
+ int c = findInMask( pos, FALSE, FALSE );
+ separator |= ( c != pos );
+ return ( c != -1 ? c : 0 );
+ }
+
+ void setCursorVisible( bool visible );
+
+
+ // undo/redo handling
+ enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection };
+ struct Command {
+ inline Command(){}
+ inline Command( CommandType type, int pos, QChar c )
+ :type(type),c(c),pos(pos){}
+ uint type : 4;
+ QChar c;
+ int pos;
+ };
+ int undoState;
+ QValueVector<Command> history;
+ void addCommand( const Command& cmd );
+ void insert( const QString& s );
+ void del( bool wasBackspace = FALSE );
+ void remove( int pos );
+
+ inline void separate() { separator = TRUE; }
+ inline void undo( int until = -1 ) {
+ if ( !isUndoAvailable() )
+ return;
+ deselect();
+ while ( undoState && undoState > until ) {
+ Command& cmd = history[--undoState];
+ switch ( cmd.type ) {
+ case Insert:
+ text.remove( cmd.pos, 1);
+ cursor = cmd.pos;
+ break;
+ case Remove:
+ case RemoveSelection:
+ text.insert( cmd.pos, cmd.c );
+ cursor = cmd.pos + 1;
+ break;
+ case Delete:
+ case DeleteSelection:
+ text.insert( cmd.pos, cmd.c );
+ cursor = cmd.pos;
+ break;
+ case Separator:
+ continue;
+ }
+ if ( until < 0 && undoState ) {
+ Command& next = history[undoState-1];
+ if ( next.type != cmd.type && next.type < RemoveSelection
+ && !( cmd.type >= RemoveSelection && next.type != Separator ) )
+ break;
+ }
+ }
+ modified = ( undoState != 0 );
+ textDirty = TRUE;
+ }
+ inline void redo() {
+ if ( !isRedoAvailable() )
+ return;
+ deselect();
+ while ( undoState < (int)history.size() ) {
+ Command& cmd = history[undoState++];
+ switch ( cmd.type ) {
+ case Insert:
+ text.insert( cmd.pos, cmd.c );
+ cursor = cmd.pos + 1;
+ break;
+ case Remove:
+ case Delete:
+ case RemoveSelection:
+ case DeleteSelection:
+ text.remove( cmd.pos, 1 );
+ cursor = cmd.pos;
+ break;
+ case Separator:
+ continue;
+ }
+ if ( undoState < (int)history.size() ) {
+ Command& next = history[undoState];
+ if ( next.type != cmd.type && cmd.type < RemoveSelection
+ && !( next.type >= RemoveSelection && cmd.type != Separator ) )
+ break;
+ }
+ }
+ textDirty = TRUE;
+ }
+ inline bool isUndoAvailable() const { return !readOnly && undoState; }
+ inline bool isRedoAvailable() const { return !readOnly && undoState < (int)history.size(); }
+
+ // bidi
+ inline bool isRightToLeft() const { return direction==QChar::DirON?text.isRightToLeft():(direction==QChar::DirR); }
+
+ // selection
+ int selstart, selend;
+ inline bool allSelected() const { return !text.isEmpty() && selstart == 0 && selend == (int)text.length(); }
+ inline bool hasSelectedText() const { return !text.isEmpty() && selend > selstart; }
+ inline void deselect() { selDirty |= (selend > selstart); selstart = selend = 0; }
+ void removeSelectedText();
+#ifndef QT_NO_CLIPBOARD
+ void copy( bool clipboard = TRUE ) const;
+#endif
+ inline bool inSelection( int x ) const
+ { if ( selstart >= selend ) return FALSE;
+ int pos = xToPos( x, QTextItem::OnCharacters ); return pos >= selstart && pos < selend; }
+
+ // masking
+ void parseInputMask( const QString &maskFields );
+ bool isValidInput( QChar key, QChar mask ) 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;
+
+ // input methods
+ int imstart, imend, imselstart, imselend;
+ bool composeMode() const { return preeditLength(); }
+ bool hasIMSelection() const { return imSelectionLength(); }
+ int preeditLength() const { return ( imend - imstart ); }
+ int imSelectionLength() const { return ( imselend - imselstart ); }
+
+ // complex text layout
+ QTextLayout textLayout;
+ void updateTextLayout();
+ void moveCursor( int pos, bool mark = FALSE );
+ void setText( const QString& txt );
+ int xToPosInternal( int x, QTextItem::CursorPosition ) const;
+ int xToPos( int x, QTextItem::CursorPosition = QTextItem::BetweenCharacters ) const;
+ inline int visualAlignment() const { return alignment ? alignment : int( isRightToLeft() ? AlignRight : AlignLeft ); }
+ QRect cursorRect() const;
+ void updateMicroFocusHint();
+
+#ifndef QT_NO_DRAGANDDROP
+ // drag and drop
+ QPoint dndPos;
+ int dndTimer;
+ bool drag();
+#endif
+};
+
+
+/*!
+ \class QLineEdit
+ \brief The QLineEdit widget is a one-line text editor.
+
+ \ingroup basic
+ \mainclass
+
+ 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.
+
+ 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 Return or Enter key is pressed the returnPressed() signal is
+ emitted. Note that if there is a validator set on the line edit,
+ the returnPressed() signal will only be emitted if the validator
+ returns \c 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 Moves the cursor to the beginning of the line.
+ \row \i Ctrl+B \i Moves the cursor one character to the left.
+ \row \i Ctrl+C \i Copies the selected text to the clipboard.
+ (Windows also supports Ctrl+Insert for this operation.)
+ \row \i Ctrl+D \i Deletes the character to the right of the cursor.
+ \row \i Ctrl+E \i Moves the cursor to the end of the line.
+ \row \i Ctrl+F \i Moves the cursor one character to the right.
+ \row \i Ctrl+H \i Deletes the character to the left of the cursor.
+ \row \i Ctrl+K \i Deletes to the end of the line.
+ \row \i Ctrl+V \i Pastes the clipboard text into line edit.
+ (Windows also supports Shift+Insert for this operation.)
+ \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
+ (Windows also supports Shift+Delete for this operation.)
+ \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.
+
+ <img src=qlined-m.png> <img src=qlined-w.png>
+
+ \sa QTextEdit QLabel QComboBox
+ \link guibooks.html#fowler GUI Design Handbook: Field, Entry\endlink
+*/
+
+
+/*!
+ \fn void QLineEdit::textChanged( const QString& )
+
+ This signal is emitted whenever the text changes. The argument is
+ the new text.
+*/
+
+/*!
+ \fn void QLineEdit::selectionChanged()
+
+ This signal is emitted whenever the selection changes.
+
+ \sa hasSelectedText(), selectedText()
+*/
+
+/*!
+ \fn void QLineEdit::lostFocus()
+
+ This signal is emitted when the line edit has lost focus.
+
+ \sa hasFocus(), QWidget::focusInEvent(), QWidget::focusOutEvent()
+*/
+
+
+
+/*!
+ 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 )
+ : QFrame( parent, name, WNoAutoErase ), d(new QLineEditPrivate( this ))
+{
+ d->init( QString::null );
+}
+
+/*!
+ 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 )
+ : QFrame( parent, name, WNoAutoErase ), d(new QLineEditPrivate( this ))
+{
+ 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 )
+ : QFrame( parent, name, WNoAutoErase ), d(new QLineEditPrivate( this ))
+{
+ d->parseInputMask( inputMask );
+ if ( d->maskData ) {
+ QString ms = d->maskString( 0, contents );
+ d->init( ms + d->clearString( ms.length(), d->maxLength - ms.length() ) );
+ d->cursor = d->nextMaskBlank( ms.length() );
+ } else {
+ d->init( contents );
+ }
+}
+
+/*!
+ Destroys the line edit.
+*/
+
+QLineEdit::~QLineEdit()
+{
+ delete [] d->maskData;
+ delete d;
+}
+
+
+/*!
+ \property QLineEdit::text
+ \brief the line edit's text
+
+ Note that setting this property clears the selection, clears the
+ undo/redo history, moves the cursor to the end of the line and
+ resets the \c modified property to FALSE. The text is not
+ validated when inserted with setText().
+
+ The text is truncated to maxLength() length.
+
+ \sa insert()
+*/
+QString QLineEdit::text() const
+{
+ QString res = d->text;
+ if ( d->maskData )
+ res = d->stripString( d->text );
+ return ( res.isNull() ? QString::fromLatin1("") : res );
+}
+
+void QLineEdit::setText( const QString& text)
+{
+ resetInputContext();
+ d->setText( text );
+ d->modified = FALSE;
+ d->finishChange( -1, FALSE );
+}
+
+
+/*!
+ \property QLineEdit::displayText
+ \brief the displayed text
+
+ If \c EchoMode is \c Normal this returns the same as text(); if
+ \c EchoMode is \c Password it returns a string of asterisks
+ text().length() characters long, e.g. "******"; if \c EchoMode is
+ \c NoEcho returns an empty string, "".
+
+ \sa setEchoMode() text() EchoMode
+*/
+
+QString QLineEdit::displayText() const
+{
+ if ( d->echoMode == NoEcho )
+ return QString::fromLatin1("");
+ QString res = d->text;
+ if ( d->echoMode == Password )
+ res.fill( passwordChar() );
+ return ( res.isNull() ? QString::fromLatin1("") : res );
+}
+
+
+/*!
+ \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.
+
+ \sa inputMask
+*/
+
+int QLineEdit::maxLength() const
+{
+ return d->maxLength;
+}
+
+void QLineEdit::setMaxLength( int maxLength )
+{
+ if ( d->maskData )
+ return;
+ d->maxLength = maxLength;
+ setText( d->text );
+}
+
+
+
+/*!
+ \property QLineEdit::frame
+ \brief whether the line edit draws itself with a frame
+
+ If enabled (the default) the line edit draws itself inside a
+ two-pixel frame, otherwise the line edit draws itself without any
+ frame.
+*/
+bool QLineEdit::frame() const
+{
+ return frameShape() != NoFrame;
+}
+
+
+void QLineEdit::setFrame( bool enable )
+{
+ setFrameStyle( enable ? ( LineEditPanel | Sunken ) : NoFrame );
+}
+
+
+/*!
+ \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.
+
+ \sa setEchoMode() echoMode()
+*/
+
+
+/*!
+ \property QLineEdit::echoMode
+ \brief the line edit's echo mode
+
+ The initial setting is \c Normal, but QLineEdit also supports \c
+ NoEcho and \c Password modes.
+
+ The widget's display and the ability to copy or drag the text is
+ affected by this setting.
+
+ \sa EchoMode displayText()
+*/
+
+QLineEdit::EchoMode QLineEdit::echoMode() const
+{
+ return (EchoMode) d->echoMode;
+}
+
+void QLineEdit::setEchoMode( EchoMode mode )
+{
+ if (mode == (EchoMode)d->echoMode)
+ return;
+ d->echoMode = mode;
+ d->updateTextLayout();
+ setInputMethodEnabled( mode == Normal );
+ update();
+}
+
+
+
+/*!
+ Returns a pointer to the current input validator, or 0 if no
+ validator has been set.
+
+ \sa setValidator()
+*/
+
+const QValidator * QLineEdit::validator() const
+{
+ return d->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 )
+{
+ if ( d->validator )
+ disconnect( (QObject*)d->validator, SIGNAL( destroyed() ),
+ this, SLOT( clearValidator() ) );
+ d->validator = v;
+ if ( d->validator )
+ connect( (QObject*)d->validator, SIGNAL( destroyed() ),
+ this, SLOT( clearValidator() ) );
+}
+
+
+
+/*!
+ 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
+{
+ constPolish();
+ QFontMetrics fm( font() );
+ int h = QMAX(fm.lineSpacing(), 14) + 2*innerMargin;
+ int w = fm.width( 'x' ) * 17; // "some"
+ int m = frameWidth() * 2;
+ return (style().sizeFromContents(QStyle::CT_LineEdit, this,
+ QSize( w + m, h + m ).
+ expandedTo(QApplication::globalStrut())));
+}
+
+
+/*!
+ Returns a minimum size for the line edit.
+
+ The width returned is enough for at least one character.
+*/
+
+QSize QLineEdit::minimumSizeHint() const
+{
+ constPolish();
+ QFontMetrics fm = fontMetrics();
+ int h = fm.height() + QMAX( 2*innerMargin, fm.leading() );
+ int w = fm.maxWidth();
+ int m = frameWidth() * 2;
+ return QSize( w + m, h + m );
+}
+
+
+/*!
+ \property QLineEdit::cursorPosition
+ \brief the current cursor position for this line edit
+
+ Setting the cursor position causes a repaint when appropriate.
+*/
+
+int QLineEdit::cursorPosition() const
+{
+ return d->cursor;
+}
+
+
+void QLineEdit::setCursorPosition( int pos )
+{
+ if (pos < 0)
+ pos = 0;
+
+ if ( pos <= (int) d->text.length() )
+ d->moveCursor( pos );
+}
+
+
+/*! \obsolete Use setText(), setCursorPosition() and setSelection() instead.
+*/
+
+bool QLineEdit::validateAndSet( const QString &newText, int newPos,
+ int newMarkAnchor, int newMarkDrag )
+{
+ int priorState = d->undoState;
+ d->selstart = 0;
+ d->selend = d->text.length();
+ d->removeSelectedText();
+ d->insert( newText );
+ d->finishChange( priorState );
+ if ( d->undoState > priorState ) {
+ d->cursor = newPos;
+ d->selstart = QMIN( newMarkAnchor, newMarkDrag );
+ d->selend = QMAX( newMarkAnchor, newMarkDrag );
+ d->updateMicroFocusHint();
+ update();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*!
+ \property QLineEdit::alignment
+ \brief the alignment of the line edit
+
+ Possible Values are \c Qt::AlignAuto, \c Qt::AlignLeft, \c
+ Qt::AlignRight and \c Qt::AlignHCenter.
+
+ Attempting to set the alignment to an illegal flag combination
+ does nothing.
+
+ \sa Qt::AlignmentFlags
+*/
+
+int QLineEdit::alignment() const
+{
+ return d->alignment;
+}
+
+void QLineEdit::setAlignment( int flag )
+{
+ d->alignment = flag & 0x7;
+ update();
+}
+
+
+/*!
+ \obsolete
+ \fn void QLineEdit::cursorRight( bool, int )
+
+ Use cursorForward() instead.
+
+ \sa cursorForward()
+*/
+
+/*!
+ \obsolete
+ \fn void QLineEdit::cursorLeft( bool, int )
+ For compatibilty with older applications only. Use cursorBackward()
+ instead.
+ \sa cursorBackward()
+*/
+
+/*!
+ 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 )
+{
+ int cursor = d->cursor;
+ if ( steps > 0 ) {
+ while( steps-- )
+ cursor = d->textLayout.nextCursorPosition( cursor );
+ } else if ( steps < 0 ) {
+ while ( steps++ )
+ cursor = d->textLayout.previousCursorPosition( cursor );
+ }
+ d->moveCursor( cursor, mark );
+}
+
+
+/*!
+ 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 )
+{
+ d->moveCursor( d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords), mark );
+}
+
+/*!
+ Moves the cursor one word backward. If \a mark is TRUE, the word
+ is also selected.
+
+ \sa cursorWordForward()
+*/
+
+void QLineEdit::cursorWordBackward( bool mark )
+{
+ d->moveCursor( d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords), 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()
+{
+ int priorState = d->undoState;
+ if ( d->hasSelectedText() ) {
+ d->removeSelectedText();
+ } else if ( d->cursor ) {
+ --d->cursor;
+ if ( d->maskData )
+ d->cursor = d->prevMaskBlank( d->cursor );
+ d->del( TRUE );
+ }
+ d->finishChange( priorState );
+}
+
+/*!
+ 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()
+{
+ int priorState = d->undoState;
+ if ( d->hasSelectedText() ) {
+ d->removeSelectedText();
+ } else {
+ int n = d->textLayout.nextCursorPosition( d->cursor ) - d->cursor;
+ while ( n-- )
+ d->del();
+ }
+ d->finishChange( priorState );
+}
+
+/*!
+ 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 )
+{
+ d->moveCursor( 0, 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 )
+{
+ d->moveCursor( d->text.length(), 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 clearModified() or setText() resets the modified flag to
+ FALSE.
+*/
+
+bool QLineEdit::isModified() const
+{
+ return d->modified;
+}
+
+/*!
+ Resets the modified flag to FALSE.
+
+ \sa isModified()
+*/
+void QLineEdit::clearModified()
+{
+ d->modified = FALSE;
+ d->history.clear();
+ d->undoState = 0;
+}
+
+/*!
+ \obsolete
+ \property QLineEdit::edited
+ \brief whether the line edit has been edited. Use modified instead.
+*/
+bool QLineEdit::edited() const { return d->modified; }
+void QLineEdit::setEdited( bool on ) { d->modified = on; }
+
+/*!
+ \obsolete
+ \property QLineEdit::hasMarkedText
+ \brief whether part of the text has been selected by the user. Use hasSelectedText instead.
+*/
+
+/*!
+ \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.
+
+ \sa selectedText()
+*/
+
+
+bool QLineEdit::hasSelectedText() const
+{
+ return d->hasSelectedText();
+}
+
+/*!
+ \obsolete
+ \property QLineEdit::markedText
+ \brief the text selected by the user. Use selectedText instead.
+*/
+
+/*!
+ \property QLineEdit::selectedText
+ \brief the selected text
+
+ If there is no selected text this property's value is
+ QString::null.
+
+ \sa hasSelectedText()
+*/
+
+QString QLineEdit::selectedText() const
+{
+ if ( d->hasSelectedText() )
+ return d->text.mid( d->selstart, d->selend - d->selstart );
+ return QString::null;
+}
+
+/*!
+ 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
+{
+ return d->hasSelectedText() ? d->selstart : -1;
+}
+
+/*! \obsolete use selectedText(), selectionStart() */
+bool QLineEdit::getSelection( int *start, int *end )
+{
+ if ( d->hasSelectedText() && start && end ) {
+ *start = d->selstart;
+ *end = d->selend;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*!
+ Selects text from position \a start and for \a length characters.
+
+ Note that this function sets the cursor's position to the end of
+ the selection regardless of its current position.
+
+ \sa deselect() selectAll() getSelection() cursorForward() cursorBackward()
+*/
+
+void QLineEdit::setSelection( int start, int length )
+{
+ if ( start < 0 || start > (int)d->text.length() || length < 0 ) {
+ d->selstart = d->selend = 0;
+ } else {
+ d->selstart = start;
+ d->selend = QMIN( start + length, (int)d->text.length() );
+ d->cursor = d->selend;
+ }
+ update();
+}
+
+
+/*!
+ \property QLineEdit::undoAvailable
+ \brief whether undo is available
+*/
+
+bool QLineEdit::isUndoAvailable() const
+{
+ return d->isUndoAvailable();
+}
+
+/*!
+ \property QLineEdit::redoAvailable
+ \brief whether redo is available
+*/
+
+bool QLineEdit::isRedoAvailable() const
+{
+ return d->isRedoAvailable();
+}
+
+/*!
+ \property QLineEdit::dragEnabled
+ \brief whether the lineedit starts a drag if the user presses and
+ moves the mouse on some selected text
+*/
+
+bool QLineEdit::dragEnabled() const
+{
+ return d->dragEnabled;
+}
+
+void QLineEdit::setDragEnabled( bool b )
+{
+ d->dragEnabled = b;
+}
+
+/*!
+ \property QLineEdit::acceptableInput
+ \brief whether the input satisfies the inputMask and the
+ validator.
+
+ \sa setInputMask(), setValidator()
+*/
+bool QLineEdit::hasAcceptableInput() const
+{
+#ifndef QT_NO_VALIDATOR
+ QString text = d->text;
+ int cursor = d->cursor;
+ if ( d->validator && d->validator->validate( text, cursor ) != QValidator::Acceptable )
+ return FALSE;
+#endif
+
+ if ( !d->maskData )
+ return TRUE;
+
+ if ( d->text.length() != (uint)d->maxLength )
+ return FALSE;
+
+ for ( uint i=0; i < (uint)d->maxLength; i++) {
+ if ( d->maskData[i].separator ) {
+ if ( d->text[(int)i] != d->maskData[i].maskChar )
+ return FALSE;
+ } else {
+ if ( !d->isValidInput( d->text[(int)i], d->maskData[i].maskChar ) )
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*!
+ \property QLineEdit::inputMask
+ \brief The validation input mask
+
+ If no mask is set, inputMask() returns QString::null.
+
+ 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 mask format understands these mask characters:
+ \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 > \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>\\</tt> \i Use <tt>\\</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 semi-colon and the character used for
+ blanks: the blank characters are always removed from the text
+ after editing. The default blank character is space.
+
+ Examples:
+ \table
+ \header \i Mask \i Notes
+ \row \i \c 000.000.000.000;_ \i IP address; blanks are \c{_}.
+ \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
+{
+ return ( d->maskData ? d->inputMask + ';' + d->blank : QString::null );
+}
+
+void QLineEdit::setInputMask( const QString &inputMask )
+{
+ d->parseInputMask( inputMask );
+ if ( d->maskData )
+ d->moveCursor( d->nextMaskBlank( 0 ) );
+}
+
+/*!
+ 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()
+{
+ d->selstart = d->selend = d->cursor = 0;
+ d->moveCursor( d->text.length(), TRUE );
+}
+
+/*!
+ Deselects any selected text.
+
+ \sa setSelection() selectAll()
+*/
+
+void QLineEdit::deselect()
+{
+ d->deselect();
+ d->finishChange();
+}
+
+
+/*!
+ This slot is equivalent to setValidator(0).
+*/
+
+void QLineEdit::clearValidator()
+{
+ setValidator( 0 );
+}
+
+/*!
+ 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.
+*/
+void QLineEdit::insert( const QString &newText )
+{
+// q->resetInputContext(); //#### FIX ME IN QT
+ int priorState = d->undoState;
+ d->removeSelectedText();
+ d->insert( newText );
+ d->finishChange( priorState );
+}
+
+/*!
+ Clears the contents of the line edit.
+*/
+void QLineEdit::clear()
+{
+ int priorState = d->undoState;
+ resetInputContext();
+ d->selstart = 0;
+ d->selend = d->text.length();
+ d->removeSelectedText();
+ d->separate();
+ d->finishChange( priorState );
+}
+
+/*!
+ 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()
+{
+ resetInputContext();
+ d->undo();
+ d->finishChange( -1, FALSE );
+}
+
+/*!
+ Redoes the last operation if redo is \link
+ QLineEdit::redoAvailable available\endlink.
+*/
+void QLineEdit::redo()
+{
+ resetInputContext();
+ d->redo();
+ d->finishChange();
+}
+
+
+/*!
+ \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 \c Normal),
+ but cannot edit it.
+
+ QLineEdit does not show a cursor in read-only mode.
+
+ \sa setEnabled()
+*/
+
+bool QLineEdit::isReadOnly() const
+{
+ return d->readOnly;
+}
+
+void QLineEdit::setReadOnly( bool enable )
+{
+ d->readOnly = enable;
+#ifndef QT_NO_CURSOR
+ setCursor( enable ? arrowCursor : 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 \c 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 \c Normal.
+
+ \sa cut() paste()
+*/
+
+void QLineEdit::copy() const
+{
+ d->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()
+{
+ insert( QApplication::clipboard()->text( QClipboard::Clipboard ) );
+}
+
+void QLineEditPrivate::copy( bool clipboard ) const
+{
+ QString t = q->selectedText();
+ if ( !t.isEmpty() && echoMode == QLineEdit::Normal ) {
+ q->disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), q, 0);
+ QApplication::clipboard()->setText( t, clipboard ? QClipboard::Clipboard : QClipboard::Selection );
+ q->connect( QApplication::clipboard(), SIGNAL(selectionChanged()),
+ q, SLOT(clipboardChanged()) );
+ }
+}
+
+#endif // !QT_NO_CLIPBOARD
+
+/*!\reimp
+*/
+
+void QLineEdit::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+}
+
+/*! \reimp
+*/
+bool QLineEdit::event( QEvent * e )
+{
+ if ( e->type() == QEvent::AccelOverride && !d->readOnly ) {
+ QKeyEvent* ke = (QKeyEvent*) e;
+ if ( ke->state() == NoButton || ke->state() == ShiftButton
+ || ke->state() == Keypad ) {
+ if ( ke->key() < Key_Escape ) {
+ ke->accept();
+ } else {
+ switch ( ke->key() ) {
+ case Key_Delete:
+ case Key_Home:
+ case Key_End:
+ case Key_Backspace:
+ case Key_Left:
+ case Key_Right:
+ ke->accept();
+ default:
+ break;
+ }
+ }
+ } else if ( ke->state() & ControlButton ) {
+ switch ( ke->key() ) {
+// Those are too frequently used for application functionality
+/* case Key_A:
+ case Key_B:
+ case Key_D:
+ case Key_E:
+ case Key_F:
+ case Key_H:
+ case Key_K:
+*/
+ case Key_C:
+ case Key_V:
+ case Key_X:
+ case Key_Y:
+ case Key_Z:
+ case Key_Left:
+ case Key_Right:
+#if defined (Q_WS_WIN)
+ case Key_Insert:
+ case Key_Delete:
+#endif
+ ke->accept();
+ default:
+ break;
+ }
+ }
+ } else if ( e->type() == QEvent::Timer ) {
+ // should be timerEvent, is here for binary compatibility
+ int timerId = ((QTimerEvent*)e)->timerId();
+ if ( timerId == d->cursorTimer ) {
+ if(!hasSelectedText() || style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ))
+ d->setCursorVisible( !d->cursorVisible );
+#ifndef QT_NO_DRAGANDDROP
+ } else if ( timerId == d->dndTimer ) {
+ if( !d->drag() )
+ return TRUE;
+#endif
+ } else if ( timerId == d->tripleClickTimer ) {
+ killTimer( d->tripleClickTimer );
+ d->tripleClickTimer = 0;
+ }
+ }
+ return QWidget::event( e );
+}
+
+/*! \reimp
+*/
+void QLineEdit::mousePressEvent( QMouseEvent* e )
+{
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+ if ( e->button() == RightButton )
+ return;
+ if ( d->tripleClickTimer && ( e->pos() - d->tripleClick ).manhattanLength() <
+ QApplication::startDragDistance() ) {
+ selectAll();
+ return;
+ }
+ bool mark = e->state() & ShiftButton;
+ int cursor = d->xToPos( e->pos().x() );
+#ifndef QT_NO_DRAGANDDROP
+ if ( !mark && d->dragEnabled && d->echoMode == Normal &&
+ e->button() == LeftButton && d->inSelection( e->pos().x() ) ) {
+ d->cursor = cursor;
+ d->updateMicroFocusHint();
+ update();
+ d->dndPos = e->pos();
+ if ( !d->dndTimer )
+ d->dndTimer = startTimer( QApplication::startDragTime() );
+ } else
+#endif
+ {
+ d->moveCursor( cursor, mark );
+ }
+}
+
+/*! \reimp
+*/
+void QLineEdit::mouseMoveEvent( QMouseEvent * e )
+{
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+#ifndef QT_NO_CURSOR
+ if ( ( e->state() & MouseButtonMask ) == 0 ) {
+ if ( !d->readOnly && d->dragEnabled
+#ifndef QT_NO_WHATSTHIS
+ && !QWhatsThis::inWhatsThisMode()
+#endif
+ )
+ setCursor( ( d->inSelection( e->pos().x() ) ? arrowCursor : ibeamCursor ) );
+ }
+#endif
+
+ if ( e->state() & LeftButton ) {
+#ifndef QT_NO_DRAGANDDROP
+ if ( d->dndTimer ) {
+ if ( ( d->dndPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() )
+ d->drag();
+ } else
+#endif
+ {
+ d->moveCursor( d->xToPos( e->pos().x() ), TRUE );
+ }
+ }
+}
+
+/*! \reimp
+*/
+void QLineEdit::mouseReleaseEvent( QMouseEvent* e )
+{
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+#ifndef QT_NO_DRAGANDDROP
+ if ( e->button() == LeftButton ) {
+ if ( d->dndTimer ) {
+ killTimer( d->dndTimer );
+ d->dndTimer = 0;
+ deselect();
+ return;
+ }
+ }
+#endif
+#ifndef QT_NO_CLIPBOARD
+ if (QApplication::clipboard()->supportsSelection() ) {
+ if ( e->button() == LeftButton ) {
+ d->copy( FALSE );
+ } else if ( !d->readOnly && e->button() == MidButton ) {
+ d->deselect();
+ insert( QApplication::clipboard()->text( QClipboard::Selection ) );
+ }
+ }
+#endif
+}
+
+/*! \reimp
+*/
+void QLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
+{
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+ if ( e->button() == Qt::LeftButton ) {
+ deselect();
+ d->cursor = d->xToPos( e->pos().x() );
+ d->cursor = d->textLayout.previousCursorPosition( d->cursor, QTextLayout::SkipWords );
+ // ## text layout should support end of words.
+ int end = d->textLayout.nextCursorPosition( d->cursor, QTextLayout::SkipWords );
+ while ( end > d->cursor && d->text[end-1].isSpace() )
+ --end;
+ d->moveCursor( end, TRUE );
+ d->tripleClickTimer = startTimer( QApplication::doubleClickInterval() );
+ 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 \c Acceptable.
+*/
+
+/*!
+ Converts key press event \a e 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 \link #desc detailed
+ description.\endlink
+*/
+
+void QLineEdit::keyPressEvent( QKeyEvent * e )
+{
+ d->setCursorVisible( TRUE );
+ if ( e->key() == Key_Enter || e->key() == Key_Return ) {
+ const QValidator * v = d->validator;
+ if ( hasAcceptableInput() ) {
+ emit returnPressed();
+ }
+#ifndef QT_NO_VALIDATOR
+ else if ( v && v->validate( d->text, d->cursor ) != QValidator::Acceptable ) {
+ QString vstr = d->text;
+ v->fixup( vstr );
+ if ( vstr != d->text ) {
+ setText( vstr );
+ if ( hasAcceptableInput() )
+ emit returnPressed();
+ }
+ }
+#endif
+ e->ignore();
+ return;
+ }
+ if ( !d->readOnly ) {
+ QString t = e->text();
+ if ( !t.isEmpty() && (!e->ascii() || e->ascii()>=32) &&
+ e->key() != Key_Delete &&
+ e->key() != Key_Backspace ) {
+#ifdef Q_WS_X11
+ extern bool qt_hebrew_keyboard_hack;
+ if ( qt_hebrew_keyboard_hack ) {
+ // the X11 keyboard layout is broken and does not reverse
+ // braces correctly. This is a hack to get halfway correct
+ // behaviour
+ if ( d->isRightToLeft() ) {
+ QChar *c = (QChar *)t.unicode();
+ int l = t.length();
+ while( l-- ) {
+ if ( c->mirrored() )
+ *c = c->mirroredChar();
+ c++;
+ }
+ }
+ }
+#endif
+ insert( t );
+ return;
+ }
+ }
+ bool unknown = FALSE;
+ if ( e->state() & ControlButton ) {
+ switch ( e->key() ) {
+ case Key_A:
+#if defined(Q_WS_X11)
+ home( e->state() & ShiftButton );
+#else
+ selectAll();
+#endif
+ break;
+ case Key_B:
+ cursorForward( e->state() & ShiftButton, -1 );
+ break;
+#ifndef QT_NO_CLIPBOARD
+ case Key_C:
+ copy();
+ break;
+#endif
+ case Key_D:
+ if ( !d->readOnly ) {
+ del();
+ }
+ break;
+ case Key_E:
+ end( e->state() & ShiftButton );
+ break;
+ case Key_F:
+ cursorForward( e->state() & ShiftButton, 1 );
+ break;
+ case Key_H:
+ if ( !d->readOnly ) {
+ backspace();
+ }
+ break;
+ case Key_K:
+ if ( !d->readOnly ) {
+ int priorState = d->undoState;
+ d->deselect();
+ while ( d->cursor < (int) d->text.length() )
+ d->del();
+ d->finishChange( priorState );
+ }
+ break;
+#if defined(Q_WS_X11)
+ case Key_U:
+ if ( !d->readOnly )
+ clear();
+ break;
+#endif
+#ifndef QT_NO_CLIPBOARD
+ case Key_V:
+ if ( !d->readOnly )
+ paste();
+ break;
+ case Key_X:
+ if ( !d->readOnly && d->hasSelectedText() && echoMode() == Normal ) {
+ copy();
+ del();
+ }
+ break;
+#if defined (Q_WS_WIN)
+ case Key_Insert:
+ copy();
+ break;
+#endif
+#endif
+ case Key_Delete:
+ if ( !d->readOnly ) {
+ cursorWordForward( TRUE );
+ del();
+ }
+ break;
+ case Key_Backspace:
+ if ( !d->readOnly ) {
+ cursorWordBackward( TRUE );
+ del();
+ }
+ break;
+ case Key_Right:
+ case Key_Left:
+ if ( d->isRightToLeft() == (e->key() == Key_Right) ) {
+ if ( echoMode() == Normal )
+ cursorWordBackward( e->state() & ShiftButton );
+ else
+ home( e->state() & ShiftButton );
+ } else {
+ if ( echoMode() == Normal )
+ cursorWordForward( e->state() & ShiftButton );
+ else
+ end( e->state() & ShiftButton );
+ }
+ break;
+ case Key_Z:
+ if ( !d->readOnly ) {
+ if(e->state() & ShiftButton)
+ redo();
+ else
+ undo();
+ }
+ break;
+ case Key_Y:
+ if ( !d->readOnly )
+ redo();
+ break;
+ default:
+ unknown = TRUE;
+ }
+ } else { // ### check for *no* modifier
+ switch ( e->key() ) {
+ case Key_Shift:
+ // ### TODO
+ break;
+ case Key_Left:
+ case Key_Right: {
+ int step = (d->isRightToLeft() == (e->key() == Key_Right)) ? -1 : 1;
+ cursorForward( e->state() & ShiftButton, step );
+ }
+ break;
+ case Key_Backspace:
+ if ( !d->readOnly ) {
+ backspace();
+ }
+ break;
+ case Key_Home:
+#ifdef Q_WS_MACX
+ case Key_Up:
+#endif
+ home( e->state() & ShiftButton );
+ break;
+ case Key_End:
+#ifdef Q_WS_MACX
+ case Key_Down:
+#endif
+ end( e->state() & ShiftButton );
+ break;
+ case Key_Delete:
+ if ( !d->readOnly ) {
+#if defined (Q_WS_WIN)
+ if ( e->state() & ShiftButton ) {
+ cut();
+ break;
+ }
+#endif
+ del();
+ }
+ break;
+#if defined (Q_WS_WIN)
+ case Key_Insert:
+ if ( !d->readOnly && e->state() & ShiftButton )
+ paste();
+ else
+ unknown = TRUE;
+ break;
+#endif
+ case Key_F14: // Undo key on Sun keyboards
+ if ( !d->readOnly )
+ undo();
+ break;
+#ifndef QT_NO_CLIPBOARD
+ case Key_F16: // Copy key on Sun keyboards
+ copy();
+ break;
+ case Key_F18: // Paste key on Sun keyboards
+ if ( !d->readOnly )
+ paste();
+ break;
+ case Key_F20: // Cut key on Sun keyboards
+ if ( !d->readOnly && hasSelectedText() && echoMode() == Normal ) {
+ copy();
+ del();
+ }
+ break;
+#endif
+ default:
+ unknown = TRUE;
+ }
+ }
+ if ( e->key() == Key_Direction_L || e->key() == Key_Direction_R ) {
+ d->direction = (e->key() == Key_Direction_L) ? QChar::DirL : QChar::DirR;
+ d->updateTextLayout();
+ update();
+ }
+
+ if ( unknown )
+ e->ignore();
+}
+
+
+/*!
+ This function is not intended as polymorphic usage. Just a shared code
+ fragment that calls QWidget::sendMouseEventToInputContext() easily for this
+ class.
+ */
+bool QLineEdit::sendMouseEventToInputContext( QMouseEvent *e )
+{
+#ifndef QT_NO_IM
+ if ( d->composeMode() ) {
+ int cursor = d->xToPosInternal( e->pos().x(), QTextItem::OnCharacters );
+ int mousePos = cursor - d->imstart;
+ if ( mousePos >= 0 && mousePos < d->preeditLength() ) {
+ QWidget::sendMouseEventToInputContext( mousePos, e->type(),
+ e->button(), e->state() );
+ } else if ( e->type() != QEvent::MouseMove ) {
+ // send button events on out of preedit
+ QWidget::sendMouseEventToInputContext( -1, e->type(),
+ e->button(), e->state() );
+ }
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+
+/*! \reimp
+ */
+void QLineEdit::imStartEvent( QIMEvent *e )
+{
+ if ( d->readOnly ) {
+ e->ignore();
+ return;
+ }
+ d->removeSelectedText();
+ d->updateMicroFocusHint();
+ d->imstart = d->imend = d->imselstart = d->imselend = d->cursor;
+}
+
+/*! \reimp
+ */
+void QLineEdit::imComposeEvent( QIMEvent *e )
+{
+ if ( d->readOnly ) {
+ e->ignore();
+ return;
+ }
+ d->text.replace( d->imstart, d->imend - d->imstart, e->text() );
+ d->imend = d->imstart + e->text().length();
+ d->imselstart = d->imstart + e->cursorPos();
+ d->imselend = d->imselstart + e->selectionLength();
+ d->cursor = d->imstart + e->cursorPos();
+ d->updateTextLayout();
+ d->updateMicroFocusHint();
+ update();
+}
+
+/*! \reimp
+ */
+void QLineEdit::imEndEvent( QIMEvent *e )
+{
+ if ( d->readOnly) {
+ e->ignore();
+ return;
+ }
+ d->text.remove( d->imstart, d->imend - d->imstart );
+ d->cursor = d->imselstart = d->imselend = d->imend = d->imstart;
+ d->textDirty = TRUE;
+ insert( e->text() );
+}
+
+/*!\reimp
+*/
+
+void QLineEdit::focusInEvent( QFocusEvent* )
+{
+ if ( QFocusEvent::reason() == QFocusEvent::Tab ||
+ QFocusEvent::reason() == QFocusEvent::Backtab ||
+ QFocusEvent::reason() == QFocusEvent::Shortcut )
+ d->maskData ? d->moveCursor( d->nextMaskBlank( 0 ) ) : selectAll();
+ if ( !d->cursorTimer ) {
+ int cft = QApplication::cursorFlashTime();
+ d->cursorTimer = cft ? startTimer( cft/2 ) : -1;
+ }
+ if( !hasSelectedText() || style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ) )
+ d->setCursorVisible( TRUE );
+ if ( d->hasIMSelection() )
+ d->cursor = d->imselstart;
+ d->updateMicroFocusHint();
+}
+
+/*!\reimp
+*/
+
+void QLineEdit::focusOutEvent( QFocusEvent* )
+{
+ if ( QFocusEvent::reason() != QFocusEvent::ActiveWindow &&
+ QFocusEvent::reason() != QFocusEvent::Popup )
+ deselect();
+ d->setCursorVisible( FALSE );
+ if ( d->cursorTimer > 0 )
+ killTimer( d->cursorTimer );
+ d->cursorTimer = 0;
+ if (QFocusEvent::reason() != QFocusEvent::Popup)
+ emit lostFocus();
+}
+
+/*!\reimp
+*/
+void QLineEdit::drawContents( QPainter *p )
+{
+ const QColorGroup& cg = colorGroup();
+ QRect cr = contentsRect();
+ QFontMetrics fm = fontMetrics();
+ QRect lineRect( cr.x() + innerMargin, cr.y() + (cr.height() - fm.height() + 1) / 2,
+ cr.width() - 2*innerMargin, fm.height() );
+ QBrush bg = QBrush( paletteBackgroundColor() );
+ if ( paletteBackgroundPixmap() )
+ bg = QBrush( cg.background(), *paletteBackgroundPixmap() );
+ else if ( !isEnabled() )
+ bg = cg.brush( QColorGroup::Background );
+ QPoint brushOrigin = p->brushOrigin();
+ p->save();
+ p->setClipRegion( QRegion(cr) - lineRect );
+ p->setBrushOrigin(brushOrigin - backgroundOffset());
+ p->fillRect( cr, bg );
+ p->restore();
+ QSharedDoubleBuffer buffer( p, lineRect.x(), lineRect.y(),
+ lineRect.width(), lineRect.height(),
+ hasFocus() ? QSharedDoubleBuffer::Force : 0 );
+ p = buffer.painter();
+ brushOrigin = p->brushOrigin();
+ p->setBrushOrigin(brushOrigin - backgroundOffset());
+ p->fillRect( lineRect, bg );
+ p->setBrushOrigin(brushOrigin);
+
+ // locate cursor position
+ int cix = 0;
+ QTextItem ci = d->textLayout.findItem( d->cursor );
+ if ( ci.isValid() ) {
+ if ( d->cursor != (int)d->text.length() && d->cursor == ci.from() + ci.length()
+ && ci.isRightToLeft() != d->isRightToLeft() )
+ ci = d->textLayout.findItem( d->cursor + 1 );
+ cix = ci.x() + ci.cursorToX( d->cursor - ci.from() );
+ }
+
+ // horizontal scrolling
+ int minLB = QMAX( 0, -fm.minLeftBearing() );
+ int minRB = QMAX( 0, -fm.minRightBearing() );
+ int widthUsed = d->textLayout.widthUsed() + 1 + minRB;
+ if ( (minLB + widthUsed) <= lineRect.width() ) {
+ switch ( d->visualAlignment() ) {
+ case AlignRight:
+ d->hscroll = widthUsed - lineRect.width() + 1;
+ break;
+ case AlignHCenter:
+ d->hscroll = ( widthUsed - lineRect.width() ) / 2;
+ break;
+ default:
+ d->hscroll = 0;
+ break;
+ }
+ d->hscroll -= minLB;
+ } else if ( cix - d->hscroll >= lineRect.width() ) {
+ d->hscroll = cix - lineRect.width() + 1;
+ } else if ( cix - d->hscroll < 0 ) {
+ d->hscroll = cix;
+ } else if ( widthUsed - d->hscroll < lineRect.width() ) {
+ d->hscroll = widthUsed - lineRect.width() + 1;
+ } else if (d->hscroll < 0) {
+ d->hscroll = 0;
+ }
+ // This updateMicroFocusHint() is corresponding to update() at
+ // IMCompose event. Although the function is invoked from various
+ // other points, some situations such as "candidate selection on
+ // AlignHCenter'ed text" need this invocation because
+ // updateMicroFocusHint() requires updated contentsRect(), and
+ // there are no other chances in such situation that invoke the
+ // function.
+ d->updateMicroFocusHint();
+ // 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->ascent-fm.ascent());
+
+ // draw text, selections and cursors
+ p->setPen( cg.text() );
+ bool supressCursor = d->readOnly, hasRightToLeft = d->isRightToLeft();
+ int textflags = 0;
+ if ( font().underline() )
+ textflags |= Qt::Underline;
+ if ( font().strikeOut() )
+ textflags |= Qt::StrikeOut;
+ if ( font().overline() )
+ textflags |= Qt::Overline;
+
+ for ( int i = 0; i < d->textLayout.numItems(); i++ ) {
+ QTextItem ti = d->textLayout.itemAt( i );
+ hasRightToLeft |= ti.isRightToLeft();
+ int tix = topLeft.x() + ti.x();
+ int first = ti.from();
+ int last = ti.from() + ti.length() - 1;
+
+ // text and selection
+ if ( d->selstart < d->selend && (last >= d->selstart && first < d->selend ) ) {
+ QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->selstart - first, 0 ) ),
+ lineRect.top() ),
+ QPoint( tix + ti.cursorToX( QMIN( d->selend - first, last - first + 1 ) ) - 1,
+ lineRect.bottom() ) ).normalize();
+ p->save();
+ p->setClipRegion( QRegion( lineRect ) - highlight, QPainter::CoordPainter );
+ p->drawTextItem( topLeft, ti, textflags );
+ p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
+ p->fillRect( highlight, cg.highlight() );
+ p->setPen( cg.highlightedText() );
+ p->drawTextItem( topLeft, ti, textflags );
+ p->restore();
+ } else {
+ p->drawTextItem( topLeft, ti, textflags );
+ }
+
+ // input method edit area
+ if ( d->composeMode() && (last >= d->imstart && first < d->imend ) ) {
+ QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->imstart - first, 0 ) ), lineRect.top() ),
+ QPoint( tix + ti.cursorToX( QMIN( d->imend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
+ p->save();
+ p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
+
+ int h1, s1, v1, h2, s2, v2;
+ cg.color( QColorGroup::Base ).hsv( &h1, &s1, &v1 );
+ cg.color( QColorGroup::Background ).hsv( &h2, &s2, &v2 );
+ QColor imCol;
+ imCol.setHsv( h1, s1, ( v1 + v2 ) / 2 );
+ p->fillRect( highlight, imCol );
+ p->drawTextItem( topLeft, ti, textflags );
+ // draw preedit's underline
+ if (d->imend - d->imstart > 0) {
+ p->setPen( cg.text() );
+ p->drawLine( highlight.bottomLeft(), highlight.bottomRight() );
+ }
+ p->restore();
+ }
+
+ // input method selection
+ if ( d->hasIMSelection() && (last >= d->imselstart && first < d->imselend ) ) {
+ QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->imselstart - first, 0 ) ), lineRect.top() ),
+ QPoint( tix + ti.cursorToX( QMIN( d->imselend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
+ p->save();
+ p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
+ p->fillRect( highlight, cg.text() );
+ p->setPen( paletteBackgroundColor() );
+ p->drawTextItem( topLeft, ti, textflags );
+ p->restore();
+ supressCursor = TRUE;
+ }
+
+ // overwrite cursor
+ if ( d->cursorVisible && d->maskData &&
+ d->selend <= d->selstart && (last >= d->cursor && first <= d->cursor ) ) {
+ QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->cursor - first, 0 ) ), lineRect.top() ),
+ QPoint( tix + ti.cursorToX( QMIN( d->cursor + 1 - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
+ p->save();
+ p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
+ p->fillRect( highlight, cg.text() );
+ p->setPen( paletteBackgroundColor() );
+ p->drawTextItem( topLeft, ti, textflags );
+ p->restore();
+ supressCursor = TRUE;
+ }
+ }
+
+ // draw cursor
+ //
+ // Asian users regard IM selection text as cursor on candidate
+ // selection phase of input method, so ordinary cursor should be
+ // invisible if IM selection text exists.
+ if ( d->cursorVisible && !supressCursor && !d->hasIMSelection() ) {
+ QPoint from( topLeft.x() + cix, lineRect.top() );
+ QPoint to = from + QPoint( 0, lineRect.height() );
+ p->drawLine( from, to );
+ if ( hasRightToLeft ) {
+ bool rtl = ci.isValid() ? ci.isRightToLeft() : TRUE;
+ to = from + QPoint( (rtl ? -2 : 2), 2 );
+ p->drawLine( from, to );
+ from.ry() += 4;
+ p->drawLine( from, to );
+ }
+ }
+ buffer.end();
+}
+
+
+#ifndef QT_NO_DRAGANDDROP
+/*!\reimp
+*/
+void QLineEdit::dragMoveEvent( QDragMoveEvent *e )
+{
+ if ( !d->readOnly && QTextDrag::canDecode(e) ) {
+ e->acceptAction();
+ d->cursor = d->xToPos( e->pos().x() );
+ d->cursorVisible = TRUE;
+ update();
+ }
+}
+
+/*!\reimp */
+void QLineEdit::dragEnterEvent( QDragEnterEvent * e )
+{
+ QLineEdit::dragMoveEvent( e );
+}
+
+/*!\reimp */
+void QLineEdit::dragLeaveEvent( QDragLeaveEvent *)
+{
+ if ( d->cursorVisible ) {
+ d->cursorVisible = FALSE;
+ update();
+ }
+}
+
+/*!\reimp */
+void QLineEdit::dropEvent( QDropEvent* e )
+{
+ QString str;
+ // try text/plain
+ QCString plain = "plain";
+ bool decoded = QTextDrag::decode(e, str, plain);
+ // otherwise we'll accept any kind of text (like text/uri-list)
+ if (! decoded)
+ decoded = QTextDrag::decode(e, str);
+
+ if ( decoded && !d->readOnly ) {
+ if ( e->source() == this && e->action() == QDropEvent::Copy )
+ deselect();
+ d->cursor =d->xToPos( e->pos().x() );
+ int selStart = d->cursor;
+ int oldSelStart = d->selstart;
+ int oldSelEnd = d->selend;
+ d->cursorVisible = FALSE;
+ e->acceptAction();
+ insert( str );
+ if ( e->source() == this ) {
+ if ( e->action() == QDropEvent::Move ) {
+ 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();
+ }
+}
+
+bool QLineEditPrivate::drag()
+{
+ q->killTimer( dndTimer );
+ dndTimer = 0;
+ QTextDrag *tdo = new QTextDrag( q->selectedText(), q );
+
+ QGuardedPtr<QLineEdit> gptr = q;
+ bool r = tdo->drag();
+ if ( !gptr )
+ return FALSE;
+
+ // ### fix the check QDragObject::target() != q in Qt4 (should not be needed)
+ if ( r && !readOnly && QDragObject::target() != q ) {
+ int priorState = undoState;
+ removeSelectedText();
+ finishChange( priorState );
+ }
+#ifndef QT_NO_CURSOR
+ q->setCursor( readOnly ? arrowCursor : ibeamCursor );
+#endif
+ return TRUE;
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
+
+/*!\reimp
+*/
+void QLineEdit::contextMenuEvent( QContextMenuEvent * e )
+{
+#ifndef QT_NO_POPUPMENU
+#ifndef QT_NO_IM
+ if ( d->composeMode() )
+ return;
+#endif
+ d->separate();
+ QPopupMenu *menu = createPopupMenu();
+ if (!menu)
+ return;
+ QGuardedPtr<QPopupMenu> popup = menu;
+ QGuardedPtr<QLineEdit> that = this;
+ QPoint pos = e->reason() == QContextMenuEvent::Mouse ? e->globalPos() :
+ mapToGlobal( QPoint(e->pos().x(), 0) ) + QPoint( width() / 2, height() / 2 );
+ int r = popup->exec( pos );
+ delete (QPopupMenu*)popup;
+ if ( that && d->menuId ) {
+ switch ( d->menuId - r ) {
+ case IdClear: clear(); break;
+ case IdSelectAll: selectAll(); break;
+ case IdUndo: undo(); break;
+ case IdRedo: redo(); break;
+#ifndef QT_NO_CLIPBOARD
+ case IdCut: cut(); break;
+ case IdCopy: copy(); break;
+ case IdPaste: paste(); break;
+#endif
+ default:
+ ; // nothing selected or lineedit destroyed. Be careful.
+ }
+ }
+#endif //QT_NO_POPUPMENU
+}
+
+/*!
+ This function is called to create the popup menu which is shown
+ when the user clicks on the line edit with the right mouse button.
+ If you want to create a custom popup menu, reimplement this
+ function and return the popup menu you create. The popup menu's
+ ownership is transferred to the caller.
+*/
+
+QPopupMenu *QLineEdit::createPopupMenu()
+{
+#ifndef QT_NO_POPUPMENU
+ QPopupMenu *popup = new QPopupMenu( this, "qt_edit_menu" );
+ int id = d->menuId = popup->insertItem( tr( "&Undo" ) + ACCEL_KEY( Z ) );
+ popup->insertItem( tr( "&Redo" ) + ACCEL_KEY( Y ) );
+ popup->insertSeparator();
+ popup->insertItem( tr( "Cu&t" ) + ACCEL_KEY( X ) );
+ popup->insertItem( tr( "&Copy" ) + ACCEL_KEY( C ) );
+ popup->insertItem( tr( "&Paste" ) + ACCEL_KEY( V ) );
+ popup->insertItem( tr( "Clear" ) );
+ popup->insertSeparator();
+ popup->insertItem( tr( "Select All" )
+#ifndef Q_WS_X11
+ + ACCEL_KEY( A )
+#endif
+ );
+
+#ifndef QT_NO_IM
+ QInputContext *qic = getInputContext();
+ if ( qic )
+ qic->addMenusTo( popup );
+#endif
+
+ popup->setItemEnabled( id - IdUndo, d->isUndoAvailable() );
+ popup->setItemEnabled( id - IdRedo, d->isRedoAvailable() );
+#ifndef QT_NO_CLIPBOARD
+ popup->setItemEnabled( id - IdCut, !d->readOnly && d->hasSelectedText() );
+ popup->setItemEnabled( id - IdCopy, d->hasSelectedText() );
+ popup->setItemEnabled( id - IdPaste, !d->readOnly && !QApplication::clipboard()->text().isEmpty() );
+#else
+ popup->setItemVisible( id - IdCut, FALSE );
+ popup->setItemVisible( id - IdCopy, FALSE );
+ popup->setItemVisible( id - IdPaste, FALSE );
+#endif
+ popup->setItemEnabled( id - IdClear, !d->readOnly && !d->text.isEmpty() );
+ popup->setItemEnabled( id - IdSelectAll, !d->text.isEmpty() && !d->allSelected() );
+ return popup;
+#else
+ return 0;
+#endif
+}
+
+/*! \reimp */
+void QLineEdit::windowActivationChange( bool b )
+{
+ //### remove me with WHighlightSelection attribute
+ if ( palette().active() != palette().inactive() )
+ update();
+ QWidget::windowActivationChange( b );
+}
+
+/*! \reimp */
+
+void QLineEdit::setPalette( const QPalette & p )
+{
+ //### remove me with WHighlightSelection attribute
+ QWidget::setPalette( p );
+ update();
+}
+
+/*!
+ \obsolete
+ \fn void QLineEdit::repaintArea( int from, int to )
+ Repaints all characters from \a from to \a to. If cursorPos is
+ between from and to, ensures that cursorPos is visible.
+*/
+
+/*! \reimp
+ */
+void QLineEdit::setFont( const QFont & f )
+{
+ QWidget::setFont( f );
+ d->updateTextLayout();
+}
+
+/*! \obsolete
+*/
+int QLineEdit::characterAt( int xpos, QChar *chr ) const
+{
+ int pos = d->xToPos( xpos + contentsRect().x() - d->hscroll + innerMargin );
+ if ( chr && pos < (int) d->text.length() )
+ *chr = d->text.at( pos );
+ return pos;
+}
+
+/*!
+ \internal
+
+ Sets the password character to \a c.
+
+ \sa passwordChar()
+*/
+
+void QLineEdit::setPasswordChar( QChar c )
+{
+ d->passwordChar = c;
+}
+
+/*!
+ \internal
+
+ Returns the password character.
+
+ \sa setPasswordChar()
+*/
+QChar QLineEdit::passwordChar() const
+{
+ return ( d->passwordChar.isNull() ? QChar( style().styleHint( QStyle::SH_LineEdit_PasswordCharacter, this ) ) : d->passwordChar );
+}
+
+void QLineEdit::clipboardChanged()
+{
+}
+
+void QLineEditPrivate::init( const QString& txt )
+{
+#ifndef QT_NO_CURSOR
+ q->setCursor( readOnly ? arrowCursor : ibeamCursor );
+#endif
+ q->setFocusPolicy( QWidget::StrongFocus );
+ q->setInputMethodEnabled( TRUE );
+ // 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 ) );
+ q->setBackgroundMode( PaletteBase );
+ q->setKeyCompression( TRUE );
+ q->setMouseTracking( TRUE );
+ q->setAcceptDrops( TRUE );
+ q->setFrame( TRUE );
+ text = txt;
+ updateTextLayout();
+ cursor = text.length();
+}
+
+void QLineEditPrivate::updateTextLayout()
+{
+ // replace all non-printable characters with spaces (to avoid
+ // drawing boxes when using fonts that don't have glyphs for such
+ // characters)
+ const QString &displayText = q->displayText();
+ QString str(displayText.unicode(), displayText.length());
+ QChar* uc = (QChar*)str.unicode();
+ for (int i = 0; i < (int)str.length(); ++i) {
+ if (! uc[i].isPrint())
+ uc[i] = QChar(0x0020);
+ }
+ textLayout.setText( str, q->font() );
+ textLayout.setDirection((QChar::Direction)direction);
+ textLayout.beginLayout(QTextLayout::SingleLine);
+ textLayout.beginLine( INT_MAX );
+ while ( !textLayout.atEnd() )
+ textLayout.addCurrentItem();
+ ascent = 0;
+ textLayout.endLine(0, 0, Qt::AlignLeft|Qt::SingleLine, &ascent);
+}
+
+int QLineEditPrivate::xToPosInternal( int x, QTextItem::CursorPosition betweenOrOn ) const
+{
+ x-= q->contentsRect().x() - hscroll + innerMargin;
+ for ( int i = 0; i < textLayout.numItems(); ++i ) {
+ QTextItem ti = textLayout.itemAt( i );
+ QRect tir = ti.rect();
+ if ( x >= tir.left() && x <= tir.right() )
+ return ti.xToCursor( x - tir.x(), betweenOrOn ) + ti.from();
+ }
+ return x < 0 ? -1 : text.length();
+}
+
+int QLineEditPrivate::xToPos( int x, QTextItem::CursorPosition betweenOrOn ) const
+{
+ int pos = xToPosInternal( x, betweenOrOn );
+ return ( pos < 0 ) ? 0 : pos;
+}
+
+
+QRect QLineEditPrivate::cursorRect() const
+{
+ QRect cr = q->contentsRect();
+ int cix = cr.x() - hscroll + innerMargin;
+ QTextItem ci = textLayout.findItem( cursor );
+ if ( ci.isValid() ) {
+ if ( cursor != (int)text.length() && cursor == ci.from() + ci.length()
+ && ci.isRightToLeft() != isRightToLeft() )
+ ci = textLayout.findItem( cursor + 1 );
+ cix += ci.x() + ci.cursorToX( cursor - ci.from() );
+ }
+ int ch = q->fontMetrics().height();
+ return QRect( cix-4, cr.y() + ( cr.height() - ch + 1) / 2, 8, ch + 1 );
+}
+
+void QLineEditPrivate::updateMicroFocusHint()
+{
+ // To reduce redundant microfocus update notification, we remember
+ // the old rect and update the microfocus if actual update is
+ // required. The rect o is intentionally static because some
+ // notifyee requires the microfocus information as global update
+ // rather than per notifyee update to place shared widget around
+ // microfocus.
+ static QRect o;
+ if ( q->hasFocus() ) {
+ QRect r = cursorRect();
+ if ( o != r ) {
+ o = r;
+ q->setMicroFocusHint( r.x(), r.y(), r.width(), r.height() );
+ }
+ }
+}
+
+void QLineEditPrivate::moveCursor( int pos, bool mark )
+{
+ if ( pos != cursor )
+ separate();
+ if ( maskData && pos > cursor )
+ pos = nextMaskBlank( pos );
+ else if ( maskData && pos < cursor )
+ pos = prevMaskBlank( pos );
+ bool fullUpdate = mark || hasSelectedText();
+ if ( mark ) {
+ int anchor;
+ if ( selend > selstart && cursor == selstart )
+ anchor = selend;
+ else if ( selend > selstart && cursor == selend )
+ anchor = selstart;
+ else
+ anchor = cursor;
+ selstart = QMIN( anchor, pos );
+ selend = QMAX( anchor, pos );
+ } else {
+ deselect();
+ }
+ if ( fullUpdate ) {
+ cursor = pos;
+ q->update();
+ } else {
+ setCursorVisible( FALSE );
+ cursor = pos;
+ setCursorVisible( TRUE );
+ }
+ updateMicroFocusHint();
+ if ( mark && !q->style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ) )
+ setCursorVisible( FALSE );
+ if ( mark || selDirty ) {
+ selDirty = FALSE;
+ emit q->selectionChanged();
+ }
+}
+
+void QLineEditPrivate::finishChange( int validateFromState, bool setModified )
+{
+ bool lineDirty = selDirty;
+ if ( textDirty ) {
+ // do validation
+ bool wasValidInput = validInput;
+ validInput = TRUE;
+#ifndef QT_NO_VALIDATOR
+ if ( validator && validateFromState >= 0 ) {
+ QString textCopy = text;
+ int cursorCopy = cursor;
+ validInput = ( validator->validate( textCopy, cursorCopy ) != QValidator::Invalid );
+ if ( validInput ) {
+ if ( text != textCopy ) {
+ q->setText( textCopy );
+ cursor = cursorCopy;
+ return;
+ }
+ cursor = cursorCopy;
+ }
+ }
+#endif
+ if ( validateFromState >= 0 && wasValidInput && !validInput ) {
+ undo( validateFromState );
+ history.resize( undoState );
+ validInput = TRUE;
+ textDirty = setModified = FALSE;
+ }
+ updateTextLayout();
+ updateMicroFocusHint();
+ lineDirty |= textDirty;
+ if ( setModified )
+ modified = TRUE;
+ if ( textDirty ) {
+ textDirty = FALSE;
+ emit q->textChanged( maskData ? stripString(text) : text );
+ }
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( q, 0, QAccessible::ValueChanged );
+#endif
+ }
+ if ( selDirty ) {
+ selDirty = FALSE;
+ emit q->selectionChanged();
+ }
+ if ( lineDirty || !setModified )
+ q->update();
+}
+
+void QLineEditPrivate::setText( const QString& txt )
+{
+ deselect();
+ QString oldText = text;
+ if ( maskData ) {
+ text = maskString( 0, txt, TRUE );
+ text += clearString( text.length(), maxLength - text.length() );
+ } else {
+ text = txt.isEmpty() ? txt : txt.left( maxLength );
+ }
+ history.clear();
+ undoState = 0;
+ cursor = text.length();
+ textDirty = ( oldText != text );
+}
+
+
+void QLineEditPrivate::setCursorVisible( bool visible )
+{
+ if ( (bool)cursorVisible == visible )
+ return;
+ if ( cursorTimer )
+ cursorVisible = visible;
+ QRect r = cursorRect();
+ if ( maskData || !q->contentsRect().contains( r ) )
+ q->update();
+ else
+ q->update( r );
+}
+
+void QLineEditPrivate::addCommand( const Command& cmd )
+{
+ if ( separator && undoState && history[undoState-1].type != Separator ) {
+ history.resize( undoState + 2 );
+ history[undoState++] = Command( Separator, 0, 0 );
+ } else {
+ history.resize( undoState + 1);
+ }
+ separator = FALSE;
+ history[ undoState++ ] = cmd;
+}
+
+void QLineEditPrivate::insert( const QString& s )
+{
+ if ( maskData ) {
+ QString ms = maskString( cursor, s );
+ for ( int i = 0; i < (int) ms.length(); ++i ) {
+ addCommand ( Command( DeleteSelection, cursor+i, text.at(cursor+i) ) );
+ addCommand( Command( Insert, cursor+i, ms.at(i) ) );
+ }
+ text.replace( cursor, ms.length(), ms );
+ cursor += ms.length();
+ cursor = nextMaskBlank( cursor );
+ } else {
+ int remaining = maxLength - text.length();
+ text.insert( cursor, s.left(remaining) );
+ for ( int i = 0; i < (int) s.left(remaining).length(); ++i )
+ addCommand( Command( Insert, cursor++, s.at(i) ) );
+ }
+ textDirty = TRUE;
+}
+
+void QLineEditPrivate::del( bool wasBackspace )
+{
+ if ( cursor < (int) text.length() ) {
+ addCommand ( Command( (CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), cursor, text.at(cursor) ) );
+ if ( maskData ) {
+ text.replace( cursor, 1, clearString( cursor, 1 ) );
+ addCommand( Command( Insert, cursor, text.at( cursor ) ) );
+ } else {
+ text.remove( cursor, 1 );
+ }
+ textDirty = TRUE;
+ }
+}
+
+void QLineEditPrivate::removeSelectedText()
+{
+ if ( selstart < selend && selend <= (int) text.length() ) {
+ separate();
+ int i ;
+ if ( selstart <= cursor && cursor < selend ) {
+ // cursor is within the selection. Split up the commands
+ // to be able to restore the correct cursor position
+ for ( i = cursor; i >= selstart; --i )
+ addCommand ( Command( DeleteSelection, i, text.at(i) ) );
+ for ( i = selend - 1; i > cursor; --i )
+ addCommand ( Command( DeleteSelection, i - cursor + selstart - 1, text.at(i) ) );
+ } else {
+ for ( i = selend-1; i >= selstart; --i )
+ addCommand ( Command( RemoveSelection, i, text.at(i) ) );
+ }
+ if ( maskData ) {
+ text.replace( selstart, selend - selstart, clearString( selstart, selend - selstart ) );
+ for ( int i = 0; i < selend - selstart; ++i )
+ addCommand( Command( Insert, selstart + i, text.at( selstart + i ) ) );
+ } else {
+ text.remove( selstart, selend - selstart );
+ }
+ if ( cursor > selstart )
+ cursor -= QMIN( cursor, selend ) - selstart;
+ deselect();
+ textDirty = TRUE;
+ }
+}
+
+void QLineEditPrivate::parseInputMask( const QString &maskFields )
+{
+ if ( maskFields.isEmpty() || maskFields.section( ';', 0, 0 ).isEmpty() ) {
+ if ( maskData ) {
+ delete [] maskData;
+ maskData = 0;
+ maxLength = 32767;
+ q->setText( QString::null );
+ }
+ return;
+ }
+
+ inputMask = maskFields.section( ';', 0, 0 );
+ blank = maskFields.section( ';', 1, 1 ).at(0);
+ if ( blank.isNull() )
+ blank = ' ';
+
+ // calculate maxLength / maskData length
+ maxLength = 0;
+ QChar c = 0;
+ uint i;
+ for ( i=0; i<inputMask.length(); i++ ) {
+ c = inputMask.at(i);
+ if ( i > 0 && inputMask.at( i-1 ) == '\\' ) {
+ maxLength++;
+ continue;
+ }
+ if ( c != '\\' && c != '!' &&
+ c != '<' && c != '>' &&
+ c != '{' && c != '}' &&
+ c != '[' && c != ']' )
+ maxLength++;
+ }
+
+ delete [] maskData;
+ maskData = new MaskInputData[ maxLength ];
+
+ MaskInputData::Casemode m = MaskInputData::NoCaseMode;
+ c = 0;
+ bool s;
+ bool escape = FALSE;
+ int index = 0;
+ for ( i = 0; i < inputMask.length(); i++ ) {
+ c = inputMask.at(i);
+ if ( escape ) {
+ s = TRUE;
+ maskData[ index ].maskChar = c;
+ maskData[ index ].separator = s;
+ maskData[ index ].caseMode = m;
+ index++;
+ escape = FALSE;
+ } else if ( c == '<' || c == '>' || c == '!') {
+ switch ( c ) {
+ case '<':
+ m = MaskInputData::Lower;
+ break;
+ case '>':
+ m = MaskInputData::Upper;
+ break;
+ case '!':
+ m = MaskInputData::NoCaseMode;
+ break;
+ }
+ } else if ( c != '{' && c != '}' && c != '[' && c != ']' ) {
+ switch ( c ) {
+ case 'A':
+ case 'a':
+ case 'N':
+ case 'n':
+ case 'X':
+ case 'x':
+ case '9':
+ case '0':
+ case 'D':
+ case 'd':
+ case '#':
+ s = FALSE;
+ break;
+ case '\\':
+ escape = TRUE;
+ default:
+ s = TRUE;
+ break;
+ }
+
+ if ( !escape ) {
+ maskData[ index ].maskChar = c;
+ maskData[ index ].separator = s;
+ maskData[ index ].caseMode = m;
+ index++;
+ }
+ }
+ }
+ q->setText( QString::null );
+}
+
+
+/* checks if the key is valid compared to the inputMask */
+bool QLineEditPrivate::isValidInput( QChar key, QChar mask ) const
+{
+ switch ( mask ) {
+ case 'A':
+ if ( key.isLetter() && key != blank )
+ return TRUE;
+ break;
+ case 'a':
+ if ( key.isLetter() || key == blank )
+ return TRUE;
+ break;
+ case 'N':
+ if ( key.isLetterOrNumber() && key != blank )
+ return TRUE;
+ break;
+ case 'n':
+ if ( key.isLetterOrNumber() || key == blank )
+ return TRUE;
+ break;
+ case 'X':
+ if ( key.isPrint() && key != blank )
+ return TRUE;
+ break;
+ case 'x':
+ if ( key.isPrint() || key == blank )
+ return TRUE;
+ break;
+ case '9':
+ if ( key.isNumber() && key != blank )
+ return TRUE;
+ break;
+ case '0':
+ if ( key.isNumber() || key == blank )
+ return TRUE;
+ break;
+ case 'D':
+ if ( key.isNumber() && key.digitValue() > 0 && key != blank )
+ return TRUE;
+ break;
+ case 'd':
+ if ( (key.isNumber() && key.digitValue() > 0) || key == blank )
+ return TRUE;
+ break;
+ case '#':
+ if ( key.isNumber() || key == '+' || key == '-' || key == blank )
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ 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 QLineEditPrivate::maskString( uint pos, const QString &str, bool clear) const
+{
+ if ( pos >= (uint)maxLength )
+ return QString::fromLatin1("");
+
+ QString fill;
+ fill = clear ? clearString( 0, maxLength ) : text;
+
+ uint strIndex = 0;
+ QString s = QString::fromLatin1("");
+ int i = pos;
+ while ( i < maxLength ) {
+ if ( strIndex < str.length() ) {
+ if ( maskData[ i ].separator ) {
+ s += maskData[ i ].maskChar;
+ if ( str[(int)strIndex] == maskData[ i ].maskChar )
+ strIndex++;
+ ++i;
+ } else {
+ if ( isValidInput( str[(int)strIndex], maskData[ i ].maskChar ) ) {
+ switch ( maskData[ i ].caseMode ) {
+ case MaskInputData::Upper:
+ s += str[(int)strIndex].upper();
+ break;
+ case MaskInputData::Lower:
+ s += str[(int)strIndex].lower();
+ 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 && (!maskData[i-1].separator || 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 blank if not
+ n = findInMask( i, TRUE, FALSE, str[(int)strIndex] );
+ if ( n != -1 ) {
+ s += fill.mid( i, n-i );
+ switch ( maskData[ n ].caseMode ) {
+ case MaskInputData::Upper:
+ s += str[(int)strIndex].upper();
+ break;
+ case MaskInputData::Lower:
+ s += str[(int)strIndex].lower();
+ break;
+ default:
+ s += str[(int)strIndex];
+ }
+ i = n + 1; // updates i to find + 1
+ }
+ }
+ }
+ strIndex++;
+ }
+ } else
+ break;
+ }
+
+ return s;
+}
+
+
+
+/*
+ Returns a "cleared" string with only separators and blank chars.
+ Calling this when no inputMask is set is undefined.
+*/
+QString QLineEditPrivate::clearString( uint pos, uint len ) const
+{
+ if ( pos >= (uint)maxLength )
+ return QString::null;
+
+ QString s;
+ int end = QMIN( (uint)maxLength, pos + len );
+ for ( int i=pos; i<end; i++ )
+ if ( maskData[ i ].separator )
+ s += maskData[ i ].maskChar;
+ else
+ s += blank;
+
+ return s;
+}
+
+/*
+ Strips blank parts of the input in a QLineEdit when an inputMask is set,
+ separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
+*/
+QString QLineEditPrivate::stripString( const QString &str ) const
+{
+ if ( !maskData )
+ return str;
+
+ QString s;
+ int end = QMIN( maxLength, (int)str.length() );
+ for (int i=0; i < end; i++ )
+ if ( maskData[ i ].separator )
+ s += maskData[ i ].maskChar;
+ else
+ if ( str[i] != blank )
+ s += str[i];
+
+ return s;
+}
+
+/* searches forward/backward in maskData for either a separator or a blank */
+int QLineEditPrivate::findInMask( int pos, bool forward, bool findSeparator, QChar searchChar ) const
+{
+ if ( pos >= maxLength || pos < 0 )
+ return -1;
+
+ int end = forward ? maxLength : -1;
+ int step = forward ? 1 : -1;
+ int i = pos;
+
+ while ( i != end ) {
+ if ( findSeparator ) {
+ if ( maskData[ i ].separator && maskData[ i ].maskChar == searchChar )
+ return i;
+ } else {
+ if ( !maskData[ i ].separator ) {
+ if ( searchChar.isNull() )
+ return i;
+ else if ( isValidInput( searchChar, maskData[ i ].maskChar ) )
+ return i;
+ }
+ }
+ i += step;
+ }
+ return -1;
+}
+
+
+#endif // QT_NO_LINEEDIT
diff --git a/src/widgets/qlineedit.h b/src/widgets/qlineedit.h
new file mode 100644
index 0000000..3778e2a
--- /dev/null
+++ b/src/widgets/qlineedit.h
@@ -0,0 +1,232 @@
+/**********************************************************************
+**
+** Definition of QLineEdit widget class
+**
+** Created : 941011
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QLINEEDIT_H
+#define QLINEEDIT_H
+
+struct QLineEditPrivate;
+
+class QValidator;
+class QPopupMenu;
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qstring.h"
+#endif // QT_H
+
+#ifndef QT_NO_LINEEDIT
+
+class QTextParagraph;
+class QTextCursor;
+
+class Q_EXPORT QLineEdit : public QFrame
+{
+ Q_OBJECT
+ Q_ENUMS( EchoMode )
+ Q_PROPERTY( QString text READ text WRITE setText )
+ Q_PROPERTY( int maxLength READ maxLength WRITE setMaxLength )
+ Q_PROPERTY( bool frame READ frame 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( Alignment alignment READ alignment WRITE setAlignment )
+ Q_PROPERTY( bool edited READ edited WRITE setEdited DESIGNABLE false )
+ Q_PROPERTY( bool modified READ isModified )
+ Q_PROPERTY( bool hasMarkedText READ hasMarkedText DESIGNABLE false )
+ Q_PROPERTY( bool hasSelectedText READ hasSelectedText )
+ Q_PROPERTY( QString markedText READ markedText DESIGNABLE false )
+ 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( QString inputMask READ inputMask WRITE setInputMask )
+ Q_PROPERTY( bool acceptableInput READ hasAcceptableInput )
+
+public:
+ QLineEdit( QWidget* parent, const char* name=0 );
+ QLineEdit( const QString &, QWidget* parent, const char* name=0 );
+ QLineEdit( const QString &, const QString &, QWidget* parent, const char* name=0 );
+ ~QLineEdit();
+
+ QString text() const;
+
+ QString displayText() const;
+
+ int maxLength() const;
+
+ bool frame() const;
+
+ enum EchoMode { Normal, NoEcho, Password };
+ EchoMode echoMode() const;
+
+ bool isReadOnly() const;
+
+ const QValidator * validator() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ int cursorPosition() const;
+ bool validateAndSet( const QString &, int, int, int ); // obsolete
+
+ int alignment() const;
+
+#ifndef QT_NO_COMPAT
+ void cursorLeft( bool mark, int steps = 1 ) { cursorForward( mark, -steps ); }
+ void cursorRight( bool mark, int steps = 1 ) { cursorForward( mark, steps ); }
+#endif
+ 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 clearModified();
+
+ bool edited() const; // obsolete, use isModified()
+ void setEdited( bool ); // obsolete, use clearModified()
+
+ bool hasSelectedText() const;
+ QString selectedText() const;
+ int selectionStart() const;
+
+ bool isUndoAvailable() const;
+ bool isRedoAvailable() const;
+
+#ifndef QT_NO_COMPAT
+ bool hasMarkedText() const { return hasSelectedText(); }
+ QString markedText() const { return selectedText(); }
+#endif
+
+ bool dragEnabled() const;
+
+ QString inputMask() const;
+ void setInputMask( const QString &inputMask );
+ bool hasAcceptableInput() const;
+
+public slots:
+ virtual void setText( const QString &);
+ virtual void selectAll();
+ virtual void deselect();
+ virtual void clearValidator();
+ virtual void insert( const QString &);
+ virtual void clear();
+ virtual void undo();
+ virtual void redo();
+ virtual void setMaxLength( int );
+ virtual void setFrame( bool );
+ virtual void setEchoMode( EchoMode );
+ virtual void setReadOnly( bool );
+ virtual void setValidator( const QValidator * );
+ virtual void setFont( const QFont & );
+ virtual void setPalette( const QPalette & );
+ virtual void setSelection( int, int );
+ virtual void setCursorPosition( int );
+ virtual void setAlignment( int flag );
+#ifndef QT_NO_CLIPBOARD
+ virtual void cut();
+ virtual void copy() const;
+ virtual void paste();
+#endif
+ virtual void setDragEnabled( bool b );
+
+signals:
+ void textChanged( const QString &);
+ void returnPressed();
+ void lostFocus();
+ void selectionChanged();
+
+protected:
+ bool event( QEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent * );
+ void imStartEvent( QIMEvent * );
+ void imComposeEvent( QIMEvent * );
+ void imEndEvent( QIMEvent * );
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+ void resizeEvent( QResizeEvent * );
+ void drawContents( QPainter * );
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent( QDragEnterEvent * );
+ void dragMoveEvent( QDragMoveEvent *e );
+ void dragLeaveEvent( QDragLeaveEvent *e );
+ void dropEvent( QDropEvent * );
+#endif
+ void contextMenuEvent( QContextMenuEvent * );
+ bool sendMouseEventToInputContext( QMouseEvent *e );
+ virtual QPopupMenu *createPopupMenu();
+ void windowActivationChange( bool );
+#ifndef QT_NO_COMPAT
+ void repaintArea( int, int ) { update(); }
+#endif
+
+private slots:
+ void clipboardChanged();
+
+public:
+ void setPasswordChar( QChar c ); // internal obsolete
+ QChar passwordChar() const; // obsolete internal
+ int characterAt( int, QChar* ) const; // obsolete
+ bool getSelection( int *, int * ); // obsolete
+
+private:
+ friend struct QLineEditPrivate;
+ QLineEditPrivate * d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QLineEdit( const QLineEdit & );
+ QLineEdit &operator=( const QLineEdit & );
+#endif
+};
+
+
+#endif // QT_NO_LINEEDIT
+
+#endif // QLINEEDIT_H
diff --git a/src/widgets/qlistbox.cpp b/src/widgets/qlistbox.cpp
new file mode 100644
index 0000000..f5e0057
--- /dev/null
+++ b/src/widgets/qlistbox.cpp
@@ -0,0 +1,4693 @@
+/**********************************************************************
+**
+** Implementation of QListBox widget class
+**
+** Created : 941121
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qglobal.h"
+#if defined(Q_CC_BOR)
+// needed for qsort() because of a std namespace problem on Borland
+#include "qplatformdefs.h"
+#endif
+
+#include "qlistbox.h"
+#ifndef QT_NO_LISTBOX
+#include "qmemarray.h"
+#include "qfontmetrics.h"
+#include "qpainter.h"
+#include "qstrlist.h"
+#include "qpixmap.h"
+#include "qapplication.h"
+#include "qptrdict.h"
+#include "qtimer.h"
+#include "qstringlist.h"
+#include "qstyle.h"
+#include "qpopupmenu.h"
+#include "qguardedptr.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+#include <stdlib.h>
+
+class QListBoxPrivate
+{
+public:
+ QListBoxPrivate( QListBox *lb ):
+ head( 0 ), last( 0 ), cache( 0 ), cacheIndex( -1 ), current( 0 ),
+ highlighted( 0 ), tmpCurrent( 0 ), columnPos( 1 ), rowPos( 1 ), rowPosCache( 0 ),
+ columnPosOne( 0 ), rowMode( QListBox::FixedNumber ),
+ columnMode( QListBox::FixedNumber ), numRows( 1 ), numColumns( 1 ),
+ currentRow( 0 ), currentColumn( 0 ),
+ mousePressRow( -1 ), mousePressColumn( -1 ),
+ mouseMoveRow( -1 ), mouseMoveColumn( -1 ), mouseInternalPress( FALSE ),
+ scrollTimer( 0 ), updateTimer( 0 ), visibleTimer( 0 ),
+ selectionMode( QListBox::Single ),
+ count( 0 ),
+ listBox( lb ), currInputString( QString::null ),
+ rowModeWins( FALSE ),
+ ignoreMoves( FALSE ),
+ layoutDirty( TRUE ),
+ mustPaintAll( TRUE ),
+ dragging( FALSE ),
+ dirtyDrag ( FALSE ),
+ variableHeight( TRUE /* !!! ### FALSE */ ),
+ variableWidth( FALSE ),
+ inMenuMode( FALSE )
+ {}
+ int findItemByName( int item, const QString &text );
+ ~QListBoxPrivate();
+
+ QListBoxItem * head, *last, *cache;
+ int cacheIndex;
+ QListBoxItem * current, *highlighted, *tmpCurrent;
+
+ QMemArray<int> columnPos;
+ QMemArray<int> rowPos;
+ int rowPosCache;
+ int columnPosOne;
+
+ QListBox::LayoutMode rowMode;
+ QListBox::LayoutMode columnMode;
+ int numRows;
+ int numColumns;
+
+ int currentRow;
+ int currentColumn;
+ int mousePressRow;
+ int mousePressColumn;
+ int mouseMoveRow;
+ int mouseMoveColumn;
+ bool mouseInternalPress;
+
+ QTimer * scrollTimer;
+ QTimer * updateTimer;
+ QTimer * visibleTimer;
+ QTimer * resizeTimer;
+
+ QPoint scrollPos;
+
+ QListBox::SelectionMode selectionMode;
+
+ int count;
+
+
+ QListBox *listBox;
+ QString currInputString;
+ QTimer *inputTimer;
+
+ QListBoxItem *pressedItem, *selectAnchor;
+
+ uint select :1;
+ uint pressedSelected :1;
+ uint rowModeWins :1;
+ uint ignoreMoves :1;
+ uint clearing :1;
+ uint layoutDirty :1;
+ uint mustPaintAll :1;
+ uint dragging :1;
+ uint dirtyDrag :1;
+ uint variableHeight :1;
+ uint variableWidth :1;
+ uint inMenuMode :1;
+
+ QRect *rubber;
+ QPtrDict<bool> selectable;
+
+ struct SortableItem {
+ QListBoxItem *item;
+ };
+};
+
+
+QListBoxPrivate::~QListBoxPrivate()
+{
+ Q_ASSERT( !head );
+}
+
+
+/*!
+ \class QListBoxItem qlistbox.h
+ \brief The QListBoxItem class is the base class of all list box items.
+
+ This class is an abstract base class used for all list box items.
+ If you need to insert customized items into a QListBox you must
+ inherit this class and reimplement paint(), height() and width().
+
+ \sa QListBox
+*/
+
+/*!
+ \fn bool QListBox::dragSelect() const
+ \internal
+*/
+
+/*!
+ \fn void QListBox::setDragSelect( bool )
+ \internal
+*/
+
+/*!
+ \fn bool QListBox::autoScroll() const
+ \internal
+*/
+
+/*!
+ \fn void QListBox::setAutoScroll( bool )
+ \internal
+*/
+
+/*!
+ \fn bool QListBox::autoScrollBar() const
+
+ \obsolete
+
+ Returns TRUE if vScrollBarMode() is \c Auto; otherwise returns
+ FALSE.
+*/
+
+/*!
+ \fn void QListBox::setAutoScrollBar( bool enable )
+
+ \obsolete
+
+ If \a enable is TRUE sets setVScrollBarMode() to \c AlwaysOn;
+ otherwise sets setVScrollBarMode() to \c AlwaysOff.
+*/
+
+/*!
+ \fn bool QListBox::scrollBar() const
+
+ \obsolete
+
+ Returns FALSE if vScrollBarMode() is \c AlwaysOff; otherwise
+ returns TRUE.
+*/
+
+/*!
+ \fn void QListBox::setScrollBar( bool enable )
+
+ \obsolete
+
+ If \a enable is TRUE sets setVScrollBarMode() to \c AlwaysOn;
+ otherwise sets setVScrollBarMode() to \c AlwaysOff.
+*/
+
+/*!
+ \fn bool QListBox::autoBottomScrollBar() const
+
+ \obsolete
+
+ Returns TRUE if hScrollBarMode() is \c Auto; otherwise returns
+ FALSE.
+*/
+
+/*!
+ \fn void QListBox::setAutoBottomScrollBar( bool enable )
+
+ \obsolete
+
+ If \a enable is TRUE sets setHScrollBarMode() to \c AlwaysOn;
+ otherwise sets setHScrollBarMode() to \c AlwaysOff.
+*/
+
+/*!
+ \fn bool QListBox::bottomScrollBar() const
+
+ \obsolete
+
+ Returns FALSE if vScrollBarMode() is \c AlwaysOff; otherwise
+ returns TRUE.
+*/
+
+/*!
+ \fn void QListBox::setBottomScrollBar( bool enable )
+
+ \obsolete
+
+ If \a enable is TRUE sets setHScrollBarMode() to \c AlwaysOn;
+ otherwise sets setHScrollBarMode() to \c AlwaysOff.
+*/
+
+/*!
+ \fn bool QListBox::smoothScrolling() const
+ \internal
+*/
+
+/*!
+ \fn void QListBox::setSmoothScrolling( bool )
+ \internal
+*/
+
+/*!
+ \fn bool QListBox::autoUpdate() const
+ \internal
+*/
+
+/*!
+ \fn void QListBox::setAutoUpdate( bool )
+ \internal
+*/
+
+/*!
+ \fn void QListBox::setFixedVisibleLines( int lines )
+ \internal
+*/
+
+/*!
+ \obsolete
+ \fn int QListBox::cellHeight( int i ) const
+ Returns the item height of item \a i.
+ \sa itemHeight()
+*/
+
+/*!
+ \obsolete
+ \overload int QListBox::cellHeight() const
+ Returns the item height of the first item, item 0.
+ \sa itemHeight()
+*/
+
+/*!
+ \obsolete
+ \fn int QListBox::cellWidth() const
+ Returns the maximum item width.
+ \sa maxItemWidth()
+*/
+
+/*!
+ \overload int QListBox::cellWidth(int i) const
+ \internal
+*/
+
+/*!
+ \obsolete
+ \fn int QListBox::numCols() const
+ Returns the number of columns.
+ \sa numColumns()
+*/
+
+/*!
+ \fn void QListBox::updateCellWidth()
+ \internal
+*/
+
+/*!
+ \obsolete
+ \fn int QListBox::totalWidth() const
+ Returns contentsWidth().
+*/
+
+/*!
+ \obsolete
+ \fn int QListBox::totalHeight() const
+ Returns contentsHeight().
+*/
+
+/*!
+ \obsolete
+ \fn int QListBox::findItem( int yPos ) const
+ Returns the index of the item a point (0, \a yPos).
+ \sa index() itemAt()
+*/
+
+
+/*!
+ Constructs an empty list box item in the list box \a listbox.
+*/
+
+QListBoxItem::QListBoxItem( QListBox* listbox )
+{
+ lbox = listbox;
+ s = FALSE;
+ dirty = TRUE;
+ custom_highlight = FALSE;
+ p = n = 0;
+
+ // just something that'll look noticeable in the debugger
+ x = y = 42;
+
+ if (listbox)
+ listbox->insertItem( this );
+}
+
+/*!
+ Constructs an empty list box item in the list box \a listbox and
+ inserts it after the item \a after or at the beginning if \a after
+ is 0.
+*/
+
+QListBoxItem::QListBoxItem( QListBox* listbox, QListBoxItem *after )
+{
+ lbox = listbox;
+ s = FALSE;
+ dirty = TRUE;
+ custom_highlight = FALSE;
+ p = n = 0;
+
+ // just something that'll be noticeable in the debugger
+ x = y = 42;
+
+ if (listbox)
+ listbox->insertItem( this, after );
+}
+
+
+/*!
+ Destroys the list box item.
+*/
+
+QListBoxItem::~QListBoxItem()
+{
+ if ( lbox )
+ lbox->takeItem( this );
+}
+
+
+/*!
+ Defines whether the list box item is responsible for drawing
+ itself in a highlighted state when being selected.
+
+ If \a b is FALSE (the default), the list box will draw some
+ default highlight indicator before calling paint().
+
+ \sa selected(), paint()
+*/
+void QListBoxItem::setCustomHighlighting( bool b )
+{
+ custom_highlight = b;
+}
+
+/*!
+ \fn void QListBoxItem::paint( QPainter *p )
+
+ Implement this function to draw your item. The painter, \a p, is
+ already open for painting.
+
+ \sa height(), width()
+*/
+
+/*!
+ \fn int QListBoxItem::width( const QListBox* lb ) const
+
+ Reimplement this function to return the width of your item. The \a
+ lb parameter is the same as listBox() and is provided for
+ convenience and compatibility.
+
+ The default implementation returns
+ \l{QApplication::globalStrut()}'s width.
+
+ \sa paint(), height()
+*/
+int QListBoxItem::width(const QListBox*) const
+{
+ return QApplication::globalStrut().width();
+}
+
+/*!
+ \fn int QListBoxItem::height( const QListBox* lb ) const
+
+ Implement this function to return the height of your item. The \a
+ lb parameter is the same as listBox() and is provided for
+ convenience and compatibility.
+
+ The default implementation returns
+ \l{QApplication::globalStrut()}'s height.
+
+ \sa paint(), width()
+*/
+int QListBoxItem::height(const QListBox*) const
+{
+ return QApplication::globalStrut().height();
+}
+
+
+/*!
+ Returns the text of the item. This text is also used for sorting.
+
+ \sa setText()
+*/
+QString QListBoxItem::text() const
+{
+ return txt;
+}
+
+/*!
+ Returns the pixmap associated with the item, or 0 if there isn't
+ one.
+
+ The default implementation returns 0.
+*/
+const QPixmap *QListBoxItem::pixmap() const
+{
+ return 0;
+}
+
+/*!
+ If \a b is TRUE (the default) then this item can be selected by
+ the user; otherwise this item cannot be selected by the user.
+
+ \sa isSelectable()
+*/
+
+void QListBoxItem::setSelectable( bool b )
+{
+ if ( !listBox() )
+ return;
+ bool *sel = listBox()->d->selectable.find( this );
+ if ( !sel )
+ listBox()->d->selectable.insert( this, new bool( b ) );
+ else
+ listBox()->d->selectable.replace( this, new bool( b ) );
+}
+
+/*!
+ Returns TRUE if this item is selectable (the default); otherwise
+ returns FALSE.
+
+ \sa setSelectable()
+*/
+
+bool QListBoxItem::isSelectable() const
+{
+ if ( !listBox() )
+ return TRUE;
+ bool *sel = listBox()->d->selectable.find( ( (QListBoxItem*)this ) );
+ if ( !sel )
+ return TRUE;
+ else
+ return *sel;
+}
+
+/*!
+ \fn void QListBoxItem::setText( const QString &text )
+
+ Sets the text of the QListBoxItem to \a text. This \a text is also
+ used for sorting. The text is not shown unless explicitly drawn in
+ paint().
+
+ \sa text()
+*/
+
+
+/*!
+ \class QListBoxText qlistbox.h
+ \brief The QListBoxText class provides list box items that display text.
+
+ \ingroup advanced
+
+ The text is drawn in the widget's current font. If you need
+ several different fonts, you must implement your own subclass of
+ QListBoxItem.
+
+ \sa QListBox, QListBoxItem
+*/
+
+
+/*!
+ Constructs a list box item in list box \a listbox showing the text
+ \a text.
+*/
+QListBoxText::QListBoxText( QListBox *listbox, const QString &text )
+ :QListBoxItem( listbox )
+{
+ setText( text );
+}
+
+/*!
+ Constructs a list box item showing the text \a text.
+*/
+
+QListBoxText::QListBoxText( const QString &text )
+ :QListBoxItem()
+{
+ setText( text );
+}
+
+/*!
+ Constructs a list box item in list box \a listbox showing the text
+ \a text. The item is inserted after the item \a after, or at the
+ beginning if \a after is 0.
+*/
+
+QListBoxText::QListBoxText( QListBox* listbox, const QString &text, QListBoxItem *after )
+ : QListBoxItem( listbox, after )
+{
+ setText( text );
+}
+
+/*!
+ Destroys the item.
+*/
+
+QListBoxText::~QListBoxText()
+{
+}
+
+/*!
+ Draws the text using \a painter.
+*/
+
+void QListBoxText::paint( QPainter *painter )
+{
+ int itemHeight = height( listBox() );
+ QFontMetrics fm = painter->fontMetrics();
+ int yPos = ( ( itemHeight - fm.height() ) / 2 ) + fm.ascent();
+ painter->drawText( 3, yPos, text() );
+}
+
+/*!
+ Returns the height of a line of text in list box \a lb.
+
+ \sa paint(), width()
+*/
+
+int QListBoxText::height( const QListBox* lb ) const
+{
+ int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0;
+ return QMAX( h, QApplication::globalStrut().height() );
+}
+
+/*!
+ Returns the width of this line in list box \a lb.
+
+ \sa paint(), height()
+*/
+
+int QListBoxText::width( const QListBox* lb ) const
+{
+ int w = lb ? lb->fontMetrics().width( text() ) + 6 : 0;
+ return QMAX( w, QApplication::globalStrut().width() );
+}
+
+int QListBoxText::RTTI = 1;
+
+/*!
+ \fn int QListBoxText::rtti() const
+
+ \reimp
+
+ Returns 1.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between listbox items. You should use values
+ greater than 1000 preferably a large random number, to allow for
+ extensions to this class.
+*/
+
+int QListBoxText::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ \class QListBoxPixmap qlistbox.h
+ \brief The QListBoxPixmap class provides list box items with a
+ pixmap and optional text.
+
+ \ingroup advanced
+
+ Items of this class are drawn with the pixmap on the left with the
+ optional text to the right of the pixmap.
+
+ \sa QListBox, QListBoxItem
+*/
+
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pixmap.
+*/
+
+QListBoxPixmap::QListBoxPixmap( QListBox* listbox, const QPixmap &pixmap )
+ : QListBoxItem( listbox )
+{
+ pm = pixmap;
+}
+
+/*!
+ Constructs a new list box item showing the pixmap \a pixmap.
+*/
+
+QListBoxPixmap::QListBoxPixmap( const QPixmap &pixmap )
+ : QListBoxItem()
+{
+ pm = pixmap;
+}
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pixmap. The item gets inserted after the item \a after,
+ or at the beginning if \a after is 0.
+*/
+
+QListBoxPixmap::QListBoxPixmap( QListBox* listbox, const QPixmap &pixmap, QListBoxItem *after )
+ : QListBoxItem( listbox, after )
+{
+ pm = pixmap;
+}
+
+
+/*!
+ Destroys the item.
+*/
+
+QListBoxPixmap::~QListBoxPixmap()
+{
+}
+
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pix and the text \a text.
+*/
+QListBoxPixmap::QListBoxPixmap( QListBox* listbox, const QPixmap &pix, const QString& text)
+ : QListBoxItem( listbox )
+{
+ pm = pix;
+ setText( text );
+}
+
+/*!
+ Constructs a new list box item showing the pixmap \a pix and the
+ text to \a text.
+*/
+QListBoxPixmap::QListBoxPixmap( const QPixmap & pix, const QString& text)
+ : QListBoxItem()
+{
+ pm = pix;
+ setText( text );
+}
+
+/*!
+ Constructs a new list box item in list box \a listbox showing the
+ pixmap \a pix and the string \a text. The item gets inserted after
+ the item \a after, or at the beginning if \a after is 0.
+*/
+QListBoxPixmap::QListBoxPixmap( QListBox* listbox, const QPixmap & pix, const QString& text,
+ QListBoxItem *after )
+ : QListBoxItem( listbox, after )
+{
+ pm = pix;
+ setText( text );
+}
+
+/*!
+ \fn const QPixmap *QListBoxPixmap::pixmap() const
+
+ Returns the pixmap associated with the item.
+*/
+
+
+/*!
+ Draws the pixmap using \a painter.
+*/
+
+void QListBoxPixmap::paint( QPainter *painter )
+{
+ int itemHeight = height( listBox() );
+ int yPos;
+
+ const QPixmap *pm = pixmap();
+ if ( pm && ! pm->isNull() ) {
+ yPos = ( itemHeight - pm->height() ) / 2;
+ painter->drawPixmap( 3, yPos, *pm);
+ }
+
+ if ( !text().isEmpty() ) {
+ QFontMetrics fm = painter->fontMetrics();
+ yPos = ( ( itemHeight - fm.height() ) / 2 ) + fm.ascent();
+ painter->drawText( pm->width() + 5, yPos, text() );
+ }
+}
+
+/*!
+ Returns the height of the pixmap in list box \a lb.
+
+ \sa paint(), width()
+*/
+
+int QListBoxPixmap::height( const QListBox* lb ) const
+{
+ int h;
+ if ( text().isEmpty() )
+ h = pm.height();
+ else
+ h = QMAX( pm.height(), lb->fontMetrics().lineSpacing() + 2 );
+ return QMAX( h, QApplication::globalStrut().height() );
+}
+
+/*!
+ Returns the width of the pixmap plus some margin in list box \a lb.
+
+ \sa paint(), height()
+*/
+
+int QListBoxPixmap::width( const QListBox* lb ) const
+{
+ if ( text().isEmpty() )
+ return QMAX( pm.width() + 6, QApplication::globalStrut().width() );
+ return QMAX( pm.width() + lb->fontMetrics().width( text() ) + 6,
+ QApplication::globalStrut().width() );
+}
+
+int QListBoxPixmap::RTTI = 2;
+
+/*!
+ \fn int QListBoxPixmap::rtti() const
+
+ \reimp
+
+ Returns 2.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between listbox items. You should use values
+ greater than 1000 preferably a large random number, to allow for
+ extensions to this class.
+*/
+
+int QListBoxPixmap::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ \class QListBox qlistbox.h
+ \brief The QListBox widget provides a list of selectable, read-only items.
+
+ \ingroup advanced
+ \mainclass
+
+ This is typically a single-column list in which either no item or
+ one item is selected, but it can also be used in many other ways.
+
+ QListBox will add scroll bars as necessary, but it isn't intended
+ for \e really big lists. If you want more than a few thousand
+ items, it's probably better to use a different widget mainly
+ because the scroll bars won't provide very good navigation, but
+ also because QListBox may become slow with huge lists. (See
+ QListView and QTable for possible alternatives.)
+
+ There are a variety of selection modes described in the
+ QListBox::SelectionMode documentation. The default is \c Single
+ selection mode, but you can change it using setSelectionMode().
+ (setMultiSelection() is still provided for compatibility with Qt
+ 1.x. We recommend using setSelectionMode() in all code.)
+
+ Because QListBox offers multiple selection it must display
+ keyboard focus and selection state separately. Therefore there are
+ functions both to set the selection state of an item, i.e.
+ setSelected(), and to set which item displays keyboard focus, i.e.
+ setCurrentItem().
+
+ The list box normally arranges its items in a single column and
+ adds a vertical scroll bar if required. It is possible to have a
+ different fixed number of columns (setColumnMode()), or as many
+ columns as will fit in the list box's assigned screen space
+ (setColumnMode(FitToWidth)), or to have a fixed number of rows
+ (setRowMode()) or as many rows as will fit in the list box's
+ assigned screen space (setRowMode(FitToHeight)). In all these
+ cases QListBox will add scroll bars, as appropriate, in at least
+ one direction.
+
+ If multiple rows are used, each row can be as high as necessary
+ (the normal setting), or you can request that all items will have
+ the same height by calling setVariableHeight(FALSE). The same
+ applies to a column's width, see setVariableWidth().
+
+ The QListBox's items are QListBoxItem objects. QListBox provides
+ methods to insert new items as strings, as pixmaps, and as
+ QListBoxItem * (insertItem() with various arguments), and to
+ replace an existing item with a new string, pixmap or QListBoxItem
+ (changeItem() with various arguments). You can also remove items
+ singly with removeItem() or clear() the entire list box. Note that
+ if you create a QListBoxItem yourself and insert it, QListBox
+ takes ownership of the item.
+
+ You can also create a QListBoxItem, such as QListBoxText or
+ QListBoxPixmap, with the list box as first parameter. The item
+ will then append itself. When you delete an item it is
+ automatically removed from the list box.
+
+ The list of items can be arbitrarily large; QListBox will add
+ scroll bars if necessary. QListBox can display a single-column
+ (the common case) or multiple-columns, and offers both single and
+ multiple selection. QListBox does not support multiple-column
+ items (but QListView and QTable do), or tree hierarchies (but
+ QListView does).
+
+ The list box items can be accessed both as QListBoxItem objects
+ (recommended) and using integer indexes (the original QListBox
+ implementation used an array of strings internally, and the API
+ still supports this mode of operation). Everything can be done
+ using the new objects, and most things can be done using indexes.
+
+ Each item in a QListBox contains a QListBoxItem. One of the items
+ can be the current item. The currentChanged() signal and the
+ highlighted() signal are emitted when a new item becomes current,
+ e.g. because the user clicks on it or QListBox::setCurrentItem()
+ is called. The selected() signal is emitted when the user
+ double-clicks on an item or presses Enter on the current item.
+
+ If the user does not select anything, no signals are emitted and
+ currentItem() returns -1.
+
+ A list box has \c WheelFocus as a default focusPolicy(), i.e. it
+ can get keyboard focus by tabbing, clicking and through the use of
+ the mouse wheel.
+
+ New items can be inserted using insertItem(), insertStrList() or
+ insertStringList(). inSort() is obsolete because this method is
+ quite inefficient. It's preferable to insert the items normally
+ and call sort() afterwards, or to insert a sorted QStringList().
+
+ By default, vertical and horizontal scroll bars are added and
+ removed as necessary. setHScrollBarMode() and setVScrollBarMode()
+ can be used to change this policy.
+
+ If you need to insert types other than strings and pixmaps, you
+ must define new classes which inherit QListBoxItem.
+
+ \warning The list box assumes ownership of all list box items and
+ will delete them when it does not need them any more.
+
+ <img src=qlistbox-m.png> <img src=qlistbox-w.png>
+
+ \sa QListView QComboBox QButtonGroup
+ \link guibooks.html#fowler GUI Design Handbook: List Box (two
+ sections)\endlink
+*/
+
+/*!
+ \enum QListBox::SelectionMode
+
+ This enumerated type is used by QListBox to indicate how it reacts
+ to selection by the user.
+
+ \value Single When the user selects an item, any already-selected
+ item becomes unselected and the user cannot unselect the selected
+ item. This means that the user can never clear the selection, even
+ though the selection may be cleared by the application programmer
+ using QListBox::clearSelection().
+
+ \value Multi When the user selects an item the selection status
+ of that item is toggled and the other items are left alone. Also,
+ multiple items can be selected by dragging the mouse while the
+ left mouse button is kept pressed.
+
+ \value Extended When the user selects an item the selection is
+ cleared and the new item selected. However, if the user presses
+ the Ctrl key when clicking on an item, the clicked item gets
+ toggled and all other items are left untouched. And if the user
+ presses the Shift key while clicking on an item, all items between
+ the current item and the clicked item get selected or unselected,
+ depending on the state of the clicked item. Also, multiple items
+ can be selected by dragging the mouse while the left mouse button
+ is kept pressed.
+
+ \value NoSelection Items cannot be selected.
+
+ In other words, \c Single is a real single-selection list box, \c
+ Multi is a real multi-selection list box, \c Extended is a list
+ box in which users can select multiple items but usually want to
+ select either just one or a range of contiguous items, and \c
+ NoSelection is for a list box where the user can look but not
+ touch.
+*/
+
+
+/*!
+ \enum QListBox::LayoutMode
+
+ This enum type is used to specify how QListBox lays out its rows
+ and columns.
+
+ \value FixedNumber There is a fixed number of rows (or columns).
+
+ \value FitToWidth There are as many columns as will fit
+ on-screen.
+
+ \value FitToHeight There are as many rows as will fit on-screen.
+
+ \value Variable There are as many rows as are required by the
+ column mode. (Or as many columns as required by the row mode.)
+
+ Example: When you call setRowMode( FitToHeight ), columnMode()
+ automatically becomes \c Variable to accommodate the row mode
+ you've set.
+*/
+
+/*!
+ \fn void QListBox::onItem( QListBoxItem *i )
+
+ This signal is emitted when the user moves the mouse cursor onto
+ an item, similar to the QWidget::enterEvent() function. \a i is
+ the QListBoxItem that the mouse has moved on.
+*/
+
+// ### bug here too? enter/leave event may noit considered. move the
+// mouse out of the window and back in, to the same item - does it
+// work?
+
+/*!
+ \fn void QListBox::onViewport()
+
+ This signal is emitted when the user moves the mouse cursor from
+ an item to an empty part of the list box.
+*/
+
+
+/*!
+ Constructs a new empty list box called \a name and with parent \a
+ parent.
+
+ Performance is boosted by modifying the widget flags \a f so that
+ only part of the QListBoxItem children is redrawn. This may be
+ unsuitable for custom QListBoxItem classes, in which case \c
+ WStaticContents and \c WNoAutoErase should be cleared
+ immediately after construction.
+
+ \sa QWidget::clearWFlags() Qt::WidgetFlags
+*/
+
+QListBox::QListBox( QWidget *parent, const char *name, WFlags f )
+ : QScrollView( parent, name, f | WStaticContents | WNoAutoErase )
+{
+ d = new QListBoxPrivate( this );
+ d->updateTimer = new QTimer( this, "listbox update timer" );
+ d->visibleTimer = new QTimer( this, "listbox visible timer" );
+ d->inputTimer = new QTimer( this, "listbox input timer" );
+ d->resizeTimer = new QTimer( this, "listbox resize timer" );
+ d->clearing = FALSE;
+ d->pressedItem = 0;
+ d->selectAnchor = 0;
+ d->select = FALSE;
+ d->rubber = 0;
+ d->selectable.setAutoDelete( TRUE );
+
+ setMouseTracking( TRUE );
+ viewport()->setMouseTracking( TRUE );
+
+ connect( d->updateTimer, SIGNAL(timeout()),
+ this, SLOT(refreshSlot()) );
+ connect( d->visibleTimer, SIGNAL(timeout()),
+ this, SLOT(ensureCurrentVisible()) );
+ connect( d->resizeTimer, SIGNAL( timeout() ),
+ this, SLOT( adjustItems() ) );
+ viewport()->setBackgroundMode( PaletteBase );
+ setBackgroundMode( PaletteBackground, PaletteBase );
+ viewport()->setFocusProxy( this );
+ viewport()->setFocusPolicy( WheelFocus );
+}
+
+
+QListBox * QListBox::changedListBox = 0;
+
+/*!
+ Destroys the list box. Deletes all list box items.
+*/
+
+QListBox::~QListBox()
+{
+ if ( changedListBox == this )
+ changedListBox = 0;
+ clear();
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn void QListBox::pressed( QListBoxItem *item )
+
+ This signal is emitted when the user presses any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ Note that you must not delete any QListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \overload void QListBox::pressed( QListBoxItem *item, const QPoint &pnt )
+
+ This signal is emitted when the user presses any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ \a pnt is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()).
+
+ Note that you must not delete any QListBoxItem objects in slots
+ connected to this signal.
+
+ \sa mouseButtonPressed() rightButtonPressed() clicked()
+*/
+
+/*!
+ \fn void QListBox::clicked( QListBoxItem *item )
+
+ This signal is emitted when the user clicks any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ Note that you must not delete any QListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \overload void QListBox::clicked( QListBoxItem *item, const QPoint &pnt )
+
+ This signal is emitted when the user clicks any mouse button. If
+ \a item is not 0, the cursor is on \a item. If \a item is 0, the
+ mouse cursor isn't on any item.
+
+ \a pnt is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differs by a pixel or two, \a pnt is the
+ position at release time.)
+
+ Note that you must not delete any QListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListBox::mouseButtonClicked (int button, QListBoxItem * item, const QPoint & pos)
+
+ This signal is emitted when the user clicks mouse button \a
+ button. If \a item is not 0, the cursor is on \a item. If \a item
+ is 0, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()). (If the click's
+ press and release differs by a pixel or two, \a pos is the
+ position at release time.)
+
+ Note that you must not delete any QListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListBox::mouseButtonPressed (int button, QListBoxItem * item, const QPoint & pos)
+
+ This signal is emitted when the user presses mouse button \a
+ button. If \a item is not 0, the cursor is on \a item. If \a item
+ is 0, the mouse cursor isn't on any item.
+
+ \a pos is the position of the mouse cursor in the global
+ coordinate system (QMouseEvent::globalPos()).
+
+ Note that you must not delete any QListBoxItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListBox::doubleClicked( QListBoxItem *item )
+
+ This signal is emitted whenever an item is double-clicked. It's
+ emitted on the second button press, not the second button release.
+ If \a item is not 0, the cursor is on \a item. If \a item is 0,
+ the mouse cursor isn't on any item.
+*/
+
+
+/*!
+ \fn void QListBox::returnPressed( QListBoxItem * )
+
+ This signal is emitted when Enter or Return is pressed. The
+ argument is currentItem().
+*/
+
+/*!
+ \fn void QListBox::rightButtonClicked( QListBoxItem *, const QPoint& )
+
+ This signal is emitted when the right button is clicked (i.e. when
+ it's released at the same point where it was pressed). The
+ arguments are the relevant QListBoxItem (may be 0) and the point
+ in global coordinates.
+*/
+
+
+/*!
+ \fn void QListBox::rightButtonPressed (QListBoxItem *, const QPoint & )
+
+ This signal is emitted when the right button is pressed. The
+ arguments are the relevant QListBoxItem (may be 0) and the point
+ in global coordinates.
+*/
+
+/*!
+ \fn void QListBox::contextMenuRequested( QListBoxItem *item, const QPoint & pos )
+
+ This signal is emitted when the user invokes a context menu with
+ the right mouse button or with special system keys, with \a item
+ being the item under the mouse cursor or the current item,
+ respectively.
+
+ \a pos is the position for the context menu in the global
+ coordinate system.
+*/
+
+/*!
+ \fn void QListBox::selectionChanged()
+
+ This signal is emitted when the selection set of a list box
+ changes. This signal is emitted in each selection mode. If the
+ user selects five items by drag-selecting, QListBox tries to emit
+ just one selectionChanged() signal so the signal can be connected
+ to computationally expensive slots.
+
+ \sa selected() currentItem()
+*/
+
+/*!
+ \overload void QListBox::selectionChanged( QListBoxItem *item )
+
+ This signal is emitted when the selection in a \c Single selection
+ list box changes. \a item is the newly selected list box item.
+
+ \sa selected() currentItem()
+*/
+
+/*!
+ \fn void QListBox::currentChanged( QListBoxItem *item )
+
+ This signal is emitted when the user makes a new item the current
+ item. \a item is the new current list box item.
+
+ \sa setCurrentItem() currentItem()
+*/
+
+/*!
+ \fn void QListBox::highlighted( int index )
+
+ This signal is emitted when the user makes a new item the current
+ item. \a index is the index of the new current item.
+
+ \sa currentChanged() selected() currentItem() selectionChanged()
+*/
+
+/*!
+ \overload void QListBox::highlighted( QListBoxItem * )
+
+ This signal is emitted when the user makes a new item the current
+ item. The argument is a pointer to the new current item.
+
+ \sa currentChanged() selected() currentItem() selectionChanged()
+*/
+
+/*!
+ \overload void QListBox::highlighted( const QString & )
+
+ This signal is emitted when the user makes a new item the current
+ item and the item is (or has) a string. The argument is the text
+ of the new current item.
+
+ \sa currentChanged() selected() currentItem() selectionChanged()
+*/
+
+/*!
+ \fn void QListBox::selected( int index )
+
+ This signal is emitted when the user double-clicks on an item or
+ presses Enter on the current item. \a index is the index of the
+ selected item.
+
+ \sa currentChanged() highlighted() selectionChanged()
+*/
+
+/*!
+ \overload void QListBox::selected( QListBoxItem * )
+
+ This signal is emitted when the user double-clicks on an item or
+ presses Enter on the current item. The argument is a pointer to
+ the new selected item.
+
+ \sa currentChanged() highlighted() selectionChanged()
+*/
+
+/*!
+ \overload void QListBox::selected( const QString &)
+
+ This signal is emitted when the user double-clicks on an item or
+ presses Enter on the current item, and the item is (or has) a
+ string. The argument is the text of the selected item.
+
+ \sa currentChanged() highlighted() selectionChanged()
+*/
+
+/*! \reimp */
+
+void QListBox::setFont( const QFont &font )
+{
+ QScrollView::setFont( font );
+ triggerUpdate( TRUE );
+}
+
+
+/*!
+ \property QListBox::count
+ \brief the number of items in the list box
+*/
+
+uint QListBox::count() const
+{
+ return d->count;
+}
+
+
+/*!
+ Inserts the string list \a list into the list at position \a
+ index.
+
+ If \a index is negative, \a list is inserted at the end of the
+ list. If \a index is too large, the operation is ignored.
+
+ \warning This function uses \c{const char *} rather than QString,
+ so we recommend against using it. It is provided so that legacy
+ code will continue to work, and so that programs that certainly
+ will not need to handle code outside a single 8-bit locale can use
+ it. See insertStringList() which uses real QStrings.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStringList()
+*/
+
+void QListBox::insertStrList( const QStrList *list, int index )
+{
+ if ( !list ) {
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( list != 0 );
+#endif
+ return;
+ }
+ insertStrList( *list, index );
+}
+
+
+
+/*!
+ Inserts the string list \a list into the list at position \a
+ index.
+
+ If \a index is negative, \a list is inserted at the end of the
+ list. If \a index is too large, the operation is ignored.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStrList()
+*/
+
+void QListBox::insertStringList( const QStringList & list, int index )
+{
+ if ( index < 0 )
+ index = count();
+ for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
+ insertItem( new QListBoxText(*it), index++ );
+}
+
+
+
+/*!
+ \overload
+
+ Inserts the string list \a list into the list at position \a
+ index.
+
+ If \a index is negative, \a list is inserted at the end of the
+ list. If \a index is too large, the operation is ignored.
+
+ \warning This function uses \c{const char *} rather than QString,
+ so we recommend against using it. It is provided so that legacy
+ code will continue to work, and so that programs that certainly
+ will not need to handle code outside a single 8-bit locale can use
+ it. See insertStringList() which uses real QStrings.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStringList()
+*/
+
+void QListBox::insertStrList( const QStrList & list, int index )
+{
+ QStrListIterator it( list );
+ const char* txt;
+ if ( index < 0 )
+ index = count();
+ while ( (txt=it.current()) ) {
+ ++it;
+ insertItem( new QListBoxText(QString::fromLatin1(txt)),
+ index++ );
+ }
+ if ( hasFocus() && !d->current )
+ setCurrentItem( d->head );
+}
+
+
+/*!
+ \overload
+
+ Inserts the \a numStrings strings of the array \a strings into the
+ list at position \a index.
+
+ If \a index is negative, insertStrList() inserts \a strings at the
+ end of the list. If \a index is too large, the operation is
+ ignored.
+
+ \warning This function uses \c{const char *} rather than QString,
+ so we recommend against using it. It is provided so that legacy
+ code will continue to work, and so that programs that certainly
+ will not need to handle code outside a single 8-bit locale can use
+ it. See insertStringList() which uses real QStrings.
+
+ \warning This function is never significantly faster than a loop
+ around insertItem().
+
+ \sa insertItem(), insertStringList()
+*/
+
+void QListBox::insertStrList( const char **strings, int numStrings, int index )
+{
+ if ( !strings ) {
+#if defined(QT_CHECK_NULL)
+ Q_ASSERT( strings != 0 );
+#endif
+ return;
+ }
+ if ( index < 0 )
+ index = count();
+ int i = 0;
+ while ( (numStrings<0 && strings[i]!=0) || i<numStrings ) {
+ insertItem( new QListBoxText( QString::fromLatin1(strings[i])),
+ index + i );
+ i++;
+ }
+ if ( hasFocus() && !d->current )
+ setCurrentItem( d->head );
+}
+
+/*!
+ Inserts the item \a lbi into the list at position \a index.
+
+ If \a index is negative or larger than the number of items in the
+ list box, \a lbi is inserted at the end of the list.
+
+ \sa insertStrList()
+*/
+
+void QListBox::insertItem( const QListBoxItem *lbi, int index )
+{
+#if defined ( QT_CHECK_NULL )
+ Q_ASSERT( lbi != 0 );
+#else
+ if ( !lbi )
+ return;
+#endif
+
+ if ( index < 0 )
+ index = d->count;
+
+ if ( index >= d->count ) {
+ insertItem( lbi, d->last );
+ return;
+ }
+
+ QListBoxItem * item = (QListBoxItem *)lbi;
+ d->count++;
+ d->cache = 0;
+
+ item->lbox = this;
+ if ( !d->head || index == 0 ) {
+ item->n = d->head;
+ item->p = 0;
+ d->head = item;
+ item->dirty = TRUE;
+ if ( item->n )
+ item->n->p = item;
+ } else {
+ QListBoxItem * i = d->head;
+ while ( i->n && index > 1 ) {
+ i = i->n;
+ index--;
+ }
+ if ( i->n ) {
+ item->n = i->n;
+ item->p = i;
+ item->n->p = item;
+ item->p->n = item;
+ } else {
+ i->n = item;
+ item->p = i;
+ item->n = 0;
+ }
+ }
+
+ if ( hasFocus() && !d->current ) {
+ d->current = d->head;
+ updateItem( d->current );
+ emit highlighted( d->current );
+ emit highlighted( d->current->text() );
+ emit highlighted( index );
+ }
+
+ triggerUpdate( TRUE );
+}
+
+/*!
+ \overload
+
+ Inserts the item \a lbi into the list after the item \a after, or
+ at the beginning if \a after is 0.
+
+ \sa insertStrList()
+*/
+
+void QListBox::insertItem( const QListBoxItem *lbi, const QListBoxItem *after )
+{
+#if defined ( QT_CHECK_NULL )
+ Q_ASSERT( lbi != 0 );
+#else
+ if ( !lbi )
+ return;
+#endif
+
+ QListBoxItem * item = (QListBoxItem*)lbi;
+ d->count++;
+ d->cache = 0;
+
+ item->lbox = this;
+ if ( !d->head || !after ) {
+ item->n = d->head;
+ item->p = 0;
+ d->head = item;
+ item->dirty = TRUE;
+ if ( item->n )
+ item->n->p = item;
+ } else {
+ QListBoxItem * i = (QListBoxItem*) after;
+ if ( i ) {
+ item->n = i->n;
+ item->p = i;
+ if ( item->n )
+ item->n->p = item;
+ if ( item->p )
+ item->p->n = item;
+ }
+ }
+
+ if ( after == d->last )
+ d->last = (QListBoxItem*) lbi;
+
+ if ( hasFocus() && !d->current ) {
+ d->current = d->head;
+ updateItem( d->current );
+ emit highlighted( d->current );
+ emit highlighted( d->current->text() );
+ emit highlighted( index( d->current ) );
+ }
+
+ triggerUpdate( TRUE );
+}
+
+/*!
+ \overload
+
+ Inserts a new list box text item with the text \a text into the
+ list at position \a index.
+
+ If \a index is negative, \a text is inserted at the end of the
+ list.
+
+ \sa insertStrList()
+*/
+
+void QListBox::insertItem( const QString &text, int index )
+{
+ insertItem( new QListBoxText(text), index );
+}
+
+/*!
+ \overload
+
+ Inserts a new list box pixmap item with the pixmap \a pixmap into
+ the list at position \a index.
+
+ If \a index is negative, \a pixmap is inserted at the end of the
+ list.
+
+ \sa insertStrList()
+*/
+
+void QListBox::insertItem( const QPixmap &pixmap, int index )
+{
+ insertItem( new QListBoxPixmap(pixmap), index );
+}
+
+/*!
+ \overload
+
+ Inserts a new list box pixmap item with the pixmap \a pixmap and
+ the text \a text into the list at position \a index.
+
+ If \a index is negative, \a pixmap is inserted at the end of the
+ list.
+
+ \sa insertStrList()
+*/
+
+void QListBox::insertItem( const QPixmap &pixmap, const QString &text, int index )
+{
+ insertItem( new QListBoxPixmap(pixmap, text), index );
+}
+
+/*!
+ Removes and deletes the item at position \a index. If \a index is
+ equal to currentItem(), a new item becomes current and the
+ currentChanged() and highlighted() signals are emitted.
+
+ \sa insertItem(), clear()
+*/
+
+void QListBox::removeItem( int index )
+{
+ bool wasVisible = itemVisible( currentItem() );
+ delete item( index );
+ triggerUpdate( TRUE );
+ if ( wasVisible )
+ ensureCurrentVisible();
+}
+
+
+/*!
+ Deletes all the items in the list.
+
+ \sa removeItem()
+*/
+
+void QListBox::clear()
+{
+ setContentsPos( 0, 0 );
+ bool blocked = signalsBlocked();
+ blockSignals( TRUE );
+ d->clearing = TRUE;
+ d->current = 0;
+ d->tmpCurrent = 0;
+ QListBoxItem * i = d->head;
+ d->head = 0;
+ while ( i ) {
+ QListBoxItem * n = i->n;
+ i->n = i->p = 0;
+ delete i;
+ i = n;
+ }
+ d->count = 0;
+ d->numRows = 1;
+ d->numColumns = 1;
+ d->currentRow = 0;
+ d->currentColumn = 0;
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->mouseMoveRow = -1;
+ d->mouseMoveColumn = -1;
+ d->selectable.clear();
+ clearSelection();
+ blockSignals( blocked );
+ triggerUpdate( TRUE );
+ d->last = 0;
+ d->clearing = FALSE;
+}
+
+
+/*!
+ Returns the text at position \a index, or QString::null if there
+ is no text at that position.
+
+ \sa pixmap()
+*/
+
+QString QListBox::text( int index ) const
+{
+ QListBoxItem * i = item( index );
+ if ( i )
+ return i->text();
+ return QString::null;
+}
+
+
+/*!
+ Returns a pointer to the pixmap at position \a index, or 0 if
+ there is no pixmap there.
+
+ \sa text()
+*/
+
+const QPixmap *QListBox::pixmap( int index ) const
+{
+ QListBoxItem * i = item( index );
+ if ( i )
+ return i->pixmap();
+ return 0;
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with a new list box text
+ item with text \a text.
+
+ The operation is ignored if \a index is out of range.
+
+ \sa insertItem(), removeItem()
+*/
+
+void QListBox::changeItem( const QString &text, int index )
+{
+ if( index >= 0 && index < (int)count() )
+ changeItem( new QListBoxText(text), index );
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with a new list box pixmap
+ item with pixmap \a pixmap.
+
+ The operation is ignored if \a index is out of range.
+
+ \sa insertItem(), removeItem()
+*/
+
+void QListBox::changeItem( const QPixmap &pixmap, int index )
+{
+ if( index >= 0 && index < (int)count() )
+ changeItem( new QListBoxPixmap(pixmap), index );
+}
+
+/*!
+ \overload
+
+ Replaces the item at position \a index with a new list box pixmap
+ item with pixmap \a pixmap and text \a text.
+
+ The operation is ignored if \a index is out of range.
+
+ \sa insertItem(), removeItem()
+*/
+
+void QListBox::changeItem( const QPixmap &pixmap, const QString &text, int index )
+{
+ if( index >= 0 && index < (int)count() )
+ changeItem( new QListBoxPixmap(pixmap, text), index );
+}
+
+
+
+/*!
+ Replaces the item at position \a index with \a lbi. If \a index is
+ negative or too large, changeItem() does nothing.
+
+ The item that has been changed will become selected.
+
+ \sa insertItem(), removeItem()
+*/
+
+void QListBox::changeItem( const QListBoxItem *lbi, int index )
+{
+ if ( !lbi || index < 0 || index >= (int)count() )
+ return;
+
+ removeItem( index );
+ insertItem( lbi, index );
+ setCurrentItem( index );
+}
+
+
+/*!
+ \property QListBox::numItemsVisible
+ \brief the number of visible items.
+
+ Both partially and entirely visible items are counted.
+*/
+
+int QListBox::numItemsVisible() const
+{
+ doLayout();
+
+ int columns = 0;
+
+ int x = contentsX();
+ int i=0;
+ while ( i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] < x )
+ i++;
+ if ( i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] > x )
+ columns++;
+ x += visibleWidth();
+ while ( i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] < x ) {
+ i++;
+ columns++;
+ }
+
+ int y = contentsY();
+ int rows = 0;
+ while ( i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] < y )
+ i++;
+ if ( i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] > y )
+ rows++;
+ y += visibleHeight();
+ while ( i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] < y ) {
+ i++;
+ rows++;
+ }
+
+ return rows*columns;
+}
+
+int QListBox::currentItem() const
+{
+ if ( !d->current || !d->head )
+ return -1;
+
+ return index( d->current );
+}
+
+
+/*!
+ \property QListBox::currentText
+ \brief the text of the current item.
+
+ This is equivalent to text(currentItem()).
+*/
+
+
+/*!
+ \property QListBox::currentItem
+ \brief the current highlighted item
+
+ When setting this property, the highlighting is moved to the item
+ and the list box scrolled as necessary.
+
+ If no item is current, currentItem() returns -1.
+*/
+
+void QListBox::setCurrentItem( int index )
+{
+ setCurrentItem( item( index ) );
+}
+
+
+/*!
+ \overload
+
+ Sets the current item to the QListBoxItem \a i.
+*/
+void QListBox::setCurrentItem( QListBoxItem * i )
+{
+ if ( !i || d->current == i || numRows() == 0 )
+ return;
+
+ QRect mfrect = itemRect( i );
+ if ( mfrect.isValid() )
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+
+ QListBoxItem * o = d->current;
+ d->current = i;
+ int ind = index( i );
+
+ if ( i && selectionMode() == Single ) {
+ bool changed = FALSE;
+ if ( o && o->s ) {
+ changed = TRUE;
+ o->s = FALSE;
+ }
+ if ( i && !i->s && d->selectionMode != NoSelection && i->isSelectable() ) {
+ i->s = TRUE;
+ changed = TRUE;
+ emit selectionChanged( i );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::StateChanged );
+#endif
+ }
+ if ( changed ) {
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+#endif
+ }
+ }
+
+ d->currentColumn = ind / numRows();
+ d->currentRow = ind % numRows();
+ if ( o )
+ updateItem( o );
+ if ( i )
+ updateItem( i );
+ // scroll after the items are redrawn
+ d->visibleTimer->start( 1, TRUE );
+
+ QString tmp;
+ if ( i )
+ tmp = i->text();
+ emit highlighted( i );
+ if ( !tmp.isNull() )
+ emit highlighted( tmp );
+ emit highlighted( ind );
+ emit currentChanged( i );
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::Focus );
+#endif
+}
+
+
+/*!
+ Returns a pointer to the item at position \a index, or 0 if \a
+ index is out of bounds.
+
+ \sa index()
+*/
+
+QListBoxItem *QListBox::item( int index ) const
+{
+ if ( index < 0 || index > d->count -1 )
+ return 0;
+
+ QListBoxItem * i = d->head;
+
+ if ( d->cache && index > 0 ) {
+ i = d->cache;
+ int idx = d->cacheIndex;
+ while ( i && idx < index ) {
+ idx++;
+ i = i->n;
+ }
+ while ( i && idx > index ) {
+ idx--;
+ i = i->p;
+ }
+ } else {
+ int idx = index;
+ while ( i && idx > 0 ) {
+ idx--;
+ i = i->n;
+ }
+ }
+
+ if ( index > 0 ) {
+ d->cache = i;
+ d->cacheIndex = index;
+ }
+
+ return i;
+}
+
+
+/*!
+ Returns the index of \a lbi, or -1 if the item is not in this list
+ box or \a lbi is 0.
+
+ \sa item()
+*/
+
+int QListBox::index( const QListBoxItem * lbi ) const
+{
+ if ( !lbi )
+ return -1;
+ QListBoxItem * i_n = d->head;
+ int c_n = 0;
+ if ( d->cache ) {
+ i_n = d->cache;
+ c_n = d->cacheIndex;
+ }
+ QListBoxItem* i_p = i_n;
+ int c_p = c_n;
+ while ( ( i_n != 0 || i_p != 0 ) && i_n != lbi && i_p != lbi ) {
+ if ( i_n ) {
+ c_n++;
+ i_n = i_n->n;
+ }
+ if ( i_p ) {
+ c_p--;
+ i_p = i_p->p;
+ }
+ }
+ if ( i_p == lbi )
+ return c_p;
+ if ( i_n == lbi )
+ return c_n;
+ return -1;
+}
+
+
+
+/*!
+ Returns TRUE if the item at position \a index is at least partly
+ visible; otherwise returns FALSE.
+*/
+
+bool QListBox::itemVisible( int index )
+{
+ QListBoxItem * i = item( index );
+ return i ? itemVisible( i ) : FALSE;
+}
+
+
+/*!
+ \overload
+
+ Returns TRUE if \a item is at least partly visible; otherwise
+ returns FALSE.
+*/
+
+bool QListBox::itemVisible( const QListBoxItem * item )
+{
+ if ( d->layoutDirty )
+ doLayout();
+
+ int i = index( item );
+ int col = i / numRows();
+ int row = i % numRows();
+ return ( d->columnPos[col] < contentsX()+visibleWidth() &&
+ d->rowPos[row] < contentsY()+visibleHeight() &&
+ d->columnPos[col+1] > contentsX() &&
+ d->rowPos[row+1] > contentsY() );
+}
+
+
+/*! \reimp */
+
+void QListBox::mousePressEvent( QMouseEvent *e )
+{
+ mousePressEventEx( e );
+}
+
+void QListBox::mousePressEventEx( QMouseEvent *e )
+{
+ d->mouseInternalPress = TRUE;
+ QListBoxItem * i = itemAt( e->pos() );
+
+ if ( !i && !d->current && d->head ) {
+ d->current = d->head;
+ updateItem( d->head );
+ }
+
+ if ( !i && ( d->selectionMode != Single || e->button() == RightButton )
+ && !( e->state() & ControlButton ) )
+ clearSelection();
+
+ d->select = d->selectionMode == Multi ? ( i ? !i->isSelected() : FALSE ) : TRUE;
+ d->pressedSelected = i && i->s;
+
+ if ( i )
+ d->selectAnchor = i;
+ if ( i ) {
+ switch( selectionMode() ) {
+ default:
+ case Single:
+ if ( !i->s || i != d->current ) {
+ if ( i->isSelectable() )
+ setSelected( i, TRUE );
+ else
+ setCurrentItem( i );
+ }
+ break;
+ case Extended:
+ if ( i ) {
+ if ( !(e->state() & QMouseEvent::ShiftButton) &&
+ !(e->state() & QMouseEvent::ControlButton) ) {
+ if ( !i->isSelected() ) {
+ bool b = signalsBlocked();
+ blockSignals( TRUE );
+ clearSelection();
+ blockSignals( b );
+ }
+ setSelected( i, TRUE );
+ d->dragging = TRUE; // always assume dragging
+ } else if ( e->state() & ShiftButton ) {
+ d->pressedSelected = FALSE;
+ QListBoxItem *oldCurrent = item( currentItem() );
+ bool down = index( oldCurrent ) < index( i );
+
+ QListBoxItem *lit = down ? oldCurrent : i;
+ bool select = d->select;
+ bool blocked = signalsBlocked();
+ blockSignals( TRUE );
+ for ( ;; lit = lit->n ) {
+ if ( !lit ) {
+ triggerUpdate( FALSE );
+ break;
+ }
+ if ( down && lit == i ) {
+ setSelected( i, select );
+ triggerUpdate( FALSE );
+ break;
+ }
+ if ( !down && lit == oldCurrent ) {
+ setSelected( oldCurrent, select );
+ triggerUpdate( FALSE );
+ break;
+ }
+ setSelected( lit, select );
+ }
+ blockSignals( blocked );
+ emit selectionChanged();
+ } else if ( e->state() & ControlButton ) {
+ setSelected( i, !i->isSelected() );
+ d->pressedSelected = FALSE;
+ }
+ setCurrentItem( i );
+ }
+ break;
+ case Multi:
+ //d->current = i;
+ setSelected( i, !i->s );
+ setCurrentItem( i );
+ break;
+ case NoSelection:
+ setCurrentItem( i );
+ break;
+ }
+ } else {
+ bool unselect = TRUE;
+ if ( e->button() == LeftButton ) {
+ if ( d->selectionMode == Multi ||
+ d->selectionMode == Extended ) {
+ d->tmpCurrent = d->current;
+ d->current = 0;
+ updateItem( d->tmpCurrent );
+ if ( d->rubber )
+ delete d->rubber;
+ d->rubber = 0;
+ d->rubber = new QRect( e->x(), e->y(), 0, 0 );
+
+ if ( d->selectionMode == Extended && !( e->state() & ControlButton ) )
+ selectAll( FALSE );
+ unselect = FALSE;
+ }
+ if ( unselect && ( e->button() == RightButton ||
+ ( selectionMode() == Multi || selectionMode() == Extended ) ) )
+ clearSelection();
+ }
+ }
+
+ // for sanity, in case people are event-filtering or whatnot
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ if ( i ) {
+ d->mousePressColumn = d->currentColumn;
+ d->mousePressRow = d->currentRow;
+ } else {
+ d->mousePressColumn = -1;
+ d->mousePressRow = -1;
+ }
+ d->ignoreMoves = FALSE;
+
+ d->pressedItem = i;
+
+ emit pressed( i );
+ emit pressed( i, e->globalPos() );
+ emit mouseButtonPressed( e->button(), i, e->globalPos() );
+ if ( e->button() == RightButton )
+ emit rightButtonPressed( i, e->globalPos() );
+}
+
+
+/*! \reimp */
+
+void QListBox::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( d->selectionMode == Extended &&
+ d->dragging ) {
+ d->dragging = FALSE;
+ if (d->current != d->pressedItem) {
+ updateSelection(); // when we drag, we get an update after we release
+ }
+ }
+
+ if ( d->rubber ) {
+ drawRubber();
+ delete d->rubber;
+ d->rubber = 0;
+ d->current = d->tmpCurrent;
+ updateItem( d->current );
+ }
+ if ( d->scrollTimer )
+ mouseMoveEvent( e );
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ d->ignoreMoves = FALSE;
+
+ if ( d->selectionMode == Extended &&
+ d->current == d->pressedItem &&
+ d->pressedSelected && d->current ) {
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ clearSelection();
+ blockSignals( block );
+ d->current->s = TRUE;
+ emit selectionChanged();
+ }
+
+ QListBoxItem * i = itemAt( e->pos() );
+ bool emitClicked = d->mousePressColumn != -1 && d->mousePressRow != -1 || !d->pressedItem;
+ emitClicked = emitClicked && d->pressedItem == i;
+ d->pressedItem = 0;
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->mouseInternalPress = FALSE;
+ if ( emitClicked ) {
+ emit clicked( i );
+ emit clicked( i, e->globalPos() );
+ emit mouseButtonClicked( e->button(), i, e->globalPos() );
+ if ( e->button() == RightButton )
+ emit rightButtonClicked( i, e->globalPos() );
+ }
+}
+
+
+/*! \reimp */
+
+void QListBox::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ bool ok = TRUE;
+ QListBoxItem *i = itemAt( e->pos() );
+ if ( !i || selectionMode() == NoSelection )
+ ok = FALSE;
+
+ d->ignoreMoves = TRUE;
+
+ if ( d->current && ok ) {
+ QListBoxItem * i = d->current;
+ QString tmp = d->current->text();
+ emit selected( currentItem() );
+ emit selected( i );
+ if ( !tmp.isNull() )
+ emit selected( tmp );
+ emit doubleClicked( i );
+ }
+}
+
+
+/*! \reimp */
+
+void QListBox::mouseMoveEvent( QMouseEvent *e )
+{
+ QListBoxItem * i = itemAt( e->pos() );
+ if ( i != d->highlighted ) {
+ if ( i ) {
+ emit onItem( i );
+ } else {
+ emit onViewport();
+ }
+ d->highlighted = i;
+ }
+
+ if ( d->rubber ) {
+ QRect r = d->rubber->normalize();
+ drawRubber();
+ d->rubber->setCoords( d->rubber->x(), d->rubber->y(), e->x(), e->y() );
+ doRubberSelection( r, d->rubber->normalize() );
+ drawRubber();
+ return;
+ }
+
+ if ( ( (e->state() & ( RightButton | LeftButton | MidButton ) ) == 0 ) ||
+ d->ignoreMoves )
+ return;
+
+ // hack to keep the combo (and what else?) working: if we get a
+ // move outside the listbox without having seen a press, discard
+ // it.
+ if ( !QRect( 0, 0, visibleWidth(), visibleHeight() ).contains( e->pos() ) &&
+ ( d->mousePressColumn < 0 && d->mousePressRow < 0 ||
+ (e->state() == NoButton && !d->pressedItem) ) )
+ return;
+
+ // figure out in what direction to drag-select and perhaps scroll
+ int dx = 0;
+ int x = e->x();
+ if ( x >= visibleWidth() ) {
+ x = visibleWidth()-1;
+ dx = 1;
+ } else if ( x < 0 ) {
+ x = 0;
+ dx = -1;
+ }
+ d->mouseMoveColumn = columnAt( x + contentsX() );
+
+ // sanitize mousePressColumn, if we got here without a mouse press event
+ if ( d->mousePressColumn < 0 && d->mouseMoveColumn >= 0 )
+ d->mousePressColumn = d->mouseMoveColumn;
+ if ( d->mousePressColumn < 0 && d->currentColumn >= 0 )
+ d->mousePressColumn = d->currentColumn;
+
+ // if it's beyond the last column, use the last one
+ if ( d->mouseMoveColumn < 0 )
+ d->mouseMoveColumn = dx >= 0 ? numColumns()-1 : 0;
+
+ // repeat for y
+ int dy = 0;
+ int y = e->y();
+ if ( y >= visibleHeight() ) {
+ y = visibleHeight()-1;
+ dy = 1;
+ } else if ( y < 0 ) {
+ y = 0;
+ dy = -1;
+ }
+ d->mouseMoveRow = rowAt( y + contentsY() );
+
+ if ( d->mousePressRow < 0 && d->mouseMoveRow >= 0 )
+ d->mousePressRow = d->mouseMoveRow;
+ if ( d->mousePressRow < 0 && d->currentRow >= 0 )
+ d->mousePressRow = d->currentRow;
+
+ if ( d->mousePressRow < 0 )
+ d->mousePressRow = rowAt( x + contentsX() );
+
+ d->scrollPos = QPoint( dx, dy );
+
+ if ( ( dx || dy ) && !d->scrollTimer && e->state() == LeftButton && e->button() != LeftButton ) {
+ // start autoscrolling if necessary
+ d->scrollTimer = new QTimer( this );
+ connect( d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()) );
+ d->scrollTimer->start( 100, FALSE );
+ doAutoScroll();
+ } else if ( !d->scrollTimer ) {
+ // or just select the required bits
+ updateSelection();
+ }
+}
+
+
+
+void QListBox::updateSelection()
+{
+ if ( d->mouseMoveColumn >= 0 && d->mouseMoveRow >= 0 &&
+ d->mousePressColumn >= 0 && d->mousePressRow >= 0 ) {
+ QListBoxItem * i = item( d->mouseMoveColumn * numRows() +
+ d->mouseMoveRow );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ int ind = index(i);
+#endif
+ if ( selectionMode() == Single || selectionMode() == NoSelection ) {
+ if ( i && ( d->mouseInternalPress || testWFlags(WType_Popup) ) )
+ setCurrentItem( i );
+ } else {
+ if ( d->selectionMode == Extended && (
+ ( d->current == d->pressedItem && d->pressedSelected ) ||
+ (d->dirtyDrag && !d->dragging) ) ) {
+ if (d->dirtyDrag && !d->dragging) // emit after dragging stops
+ d->dirtyDrag = FALSE;
+ else
+ clearSelection(); // dont reset drag-selected items
+ d->pressedItem = 0;
+ if ( i && i->isSelectable() ) {
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ i->s = TRUE;
+ blockSignals( block );
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::StateChanged );
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::SelectionAdd );
+#endif
+ }
+ triggerUpdate( FALSE );
+ } else {
+ int c = QMIN( d->mouseMoveColumn, d->mousePressColumn );
+ int r = QMIN( d->mouseMoveRow, d->mousePressRow );
+ int c2 = QMAX( d->mouseMoveColumn, d->mousePressColumn );
+ int r2 = QMAX( d->mouseMoveRow, d->mousePressRow );
+ bool changed = FALSE;
+ while( c <= c2 ) {
+ QListBoxItem * i = item( c*numRows()+r );
+ int rtmp = r;
+ while( i && rtmp <= r2 ) {
+ if ( (bool)i->s != (bool)d->select && i->isSelectable() ) {
+ i->s = d->select;
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::StateChanged );
+ QAccessible::updateAccessibility( viewport(), ind+1, d->select ? QAccessible::SelectionAdd : QAccessible::SelectionRemove );
+#endif
+ i->dirty = TRUE;
+ d->dirtyDrag = changed = TRUE;
+ }
+ i = i->n;
+ rtmp++;
+ }
+ c++;
+ }
+ if ( changed ) {
+ if (!d->dragging) // emit after dragging stops instead
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+#endif
+ triggerUpdate( FALSE );
+ }
+ }
+ if ( i )
+ setCurrentItem( i );
+ }
+ }
+}
+
+void QListBox::repaintSelection()
+{
+ if ( d->numColumns == 1 ) {
+ for ( uint i = topItem(); itemVisible( i ) && i < count(); ++i ) {
+ QListBoxItem *it = item(i);
+ if ( !it )
+ break;
+ if ( it->isSelected() )
+ updateItem( it );
+ }
+ } else {
+ for ( uint i = 0; i < count(); ++i ) {
+ QListBoxItem *it = item(i);
+ if ( !it )
+ break;
+ if ( it->isSelected() )
+ updateItem( it );
+ }
+ }
+}
+
+/*! \reimp
+*/
+
+void QListBox::contentsContextMenuEvent( QContextMenuEvent *e )
+{
+ if ( !receivers( SIGNAL(contextMenuRequested(QListBoxItem*,const QPoint&)) ) ) {
+ e->ignore();
+ return;
+ }
+ if ( e->reason() == QContextMenuEvent::Keyboard ) {
+ QListBoxItem *i = item( currentItem() );
+ if ( i ) {
+ QRect r = itemRect( i );
+ emit contextMenuRequested( i, mapToGlobal( r.topLeft() + QPoint( width() / 2, r.height() / 2 ) ) );
+ }
+ } else {
+ QListBoxItem * i = itemAt( contentsToViewport( e->pos() ) );
+ emit contextMenuRequested( i, e->globalPos() );
+ }
+}
+
+/*!\reimp
+*/
+void QListBox::keyPressEvent( QKeyEvent *e )
+{
+ if ( ( e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab )
+ && e->state() & Qt::ControlButton )
+ e->ignore();
+
+ if ( count() == 0 ) {
+ e->ignore();
+ return;
+ }
+
+ QGuardedPtr<QListBox> selfCheck = this;
+
+ QListBoxItem *old = d->current;
+ if ( !old ) {
+ setCurrentItem( d->head );
+ if ( d->selectionMode == Single )
+ setSelected( d->head, TRUE );
+ e->ignore();
+ return;
+ }
+
+ bool selectCurrent = FALSE;
+ switch ( e->key() ) {
+ case Key_Up:
+ {
+ d->currInputString = QString::null;
+ if ( currentItem() > 0 ) {
+ setCurrentItem( currentItem() - 1 );
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ }
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Down:
+ {
+ d->currInputString = QString::null;
+ if ( currentItem() < (int)count() - 1 ) {
+ setCurrentItem( currentItem() + 1 );
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ }
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Left:
+ {
+ d->currInputString = QString::null;
+ if ( currentColumn() > 0 ) {
+ setCurrentItem( currentItem() - numRows() );
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ } else if ( numColumns() > 1 && currentItem() > 0 ) {
+ int row = currentRow();
+ setCurrentItem( currentRow() - 1 + ( numColumns() - 1 ) * numRows() );
+
+ if ( currentItem() == -1 )
+ setCurrentItem( row - 1 + ( numColumns() - 2 ) * numRows() );
+
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ } else {
+ QApplication::sendEvent( horizontalScrollBar(), e );
+ }
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Right:
+ {
+ d->currInputString = QString::null;
+ if ( currentColumn() < numColumns()-1 ) {
+ int row = currentRow();
+ int i = currentItem();
+ QListBoxItem *it = item( i + numRows() );
+ if ( !it )
+ it = item( count()-1 );
+ setCurrentItem( it );
+
+ if ( currentItem() == -1 ) {
+ if ( row < numRows() - 1 )
+ setCurrentItem( row + 1 );
+ else
+ setCurrentItem( i );
+ }
+
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ } else if ( numColumns() > 1 && currentRow() < numRows() ) {
+ if ( currentRow() + 1 < numRows() ) {
+ setCurrentItem( currentRow() + 1 );
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ }
+ } else {
+ QApplication::sendEvent( horizontalScrollBar(), e );
+ }
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Next:
+ {
+ d->currInputString = QString::null;
+ int i = 0;
+ if ( numColumns() == 1 ) {
+ i = currentItem() + numItemsVisible();
+ i = i > (int)count() - 1 ? (int)count() - 1 : i;
+ setCurrentItem( i );
+ setBottomItem( i );
+ } else {
+ // I'm not sure about this behavior...
+ if ( currentRow() == numRows() - 1 )
+ i = currentItem() + numRows();
+ else
+ i = currentItem() + numRows() - currentRow() - 1;
+ i = i > (int)count() - 1 ? (int)count() - 1 : i;
+ setCurrentItem( i );
+ }
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Prior:
+ {
+ selectCurrent = TRUE;
+ d->currInputString = QString::null;
+ int i;
+ if ( numColumns() == 1 ) {
+ i = currentItem() - numItemsVisible();
+ i = i < 0 ? 0 : i;
+ setCurrentItem( i );
+ setTopItem( i );
+ } else {
+ // I'm not sure about this behavior...
+ if ( currentRow() == 0 )
+ i = currentItem() - numRows();
+ else
+ i = currentItem() - currentRow();
+ i = i < 0 ? 0 : i;
+ setCurrentItem( i );
+ }
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Space:
+ {
+ selectCurrent = TRUE;
+ d->currInputString = QString::null;
+ toggleCurrentItem();
+ if ( selectionMode() == Extended && d->current->isSelected() )
+ emit highlighted( currentItem() );
+ if (selfCheck && (!( e->state() & ShiftButton ) || !d->selectAnchor))
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Return:
+ case Key_Enter:
+ {
+ selectCurrent = TRUE;
+ d->currInputString = QString::null;
+ if ( currentItem() >= 0 && selectionMode() != NoSelection ) {
+ QString tmp = item( currentItem() )->text();
+ emit selected( currentItem());
+ emit selected( item( currentItem() ) );
+ if ( !tmp.isEmpty() )
+ emit selected( tmp );
+ emit returnPressed( item( currentItem() ) );
+ }
+ if (selfCheck && (!( e->state() & ShiftButton ) || !d->selectAnchor))
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_Home:
+ {
+ selectCurrent = TRUE;
+ d->currInputString = QString::null;
+ setCurrentItem( 0 );
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ case Key_End:
+ {
+ selectCurrent = TRUE;
+ d->currInputString = QString::null;
+ int i = (int)count() - 1;
+ setCurrentItem( i );
+ handleItemChange( old, e->state() & ShiftButton, e->state() & ControlButton );
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = d->current;
+ }
+ break;
+ default:
+ {
+ if ( !e->text().isEmpty() && e->text()[ 0 ].isPrint() && count() ) {
+ int curItem = currentItem();
+ if ( curItem == -1 )
+ curItem = 0;
+ if ( !d->inputTimer->isActive() ) {
+ d->currInputString = e->text();
+ curItem = d->findItemByName( ++curItem, d->currInputString );
+ } else {
+ d->inputTimer->stop();
+ d->currInputString += e->text();
+ int oldCurItem = curItem;
+ curItem = d->findItemByName( curItem, d->currInputString );
+ if ( curItem < 0 ) {
+ curItem = d->findItemByName( ++oldCurItem, e->text() );
+ d->currInputString = e->text();
+ }
+ }
+ if ( curItem >= 0 )
+ setCurrentItem( curItem );
+ if ( curItem >= 0 && selectionMode() == QListBox::Extended ) {
+ bool changed = FALSE;
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ selectAll( FALSE );
+ blockSignals( block );
+ QListBoxItem *i = item( curItem );
+ if ( !i->s && i->isSelectable() ) {
+ changed = TRUE;
+ i->s = TRUE;
+ updateItem( i );
+ }
+ if ( changed )
+ emit selectionChanged();
+ }
+ d->inputTimer->start( 400, TRUE );
+ } else {
+ d->currInputString = QString::null;
+ if ( e->state() & ControlButton ) {
+ switch ( e->key() ) {
+ case Key_A:
+ selectAll( TRUE );
+ break;
+ }
+ } else {
+ e->ignore();
+ }
+ }
+ }
+ }
+
+ if (selfCheck && selectCurrent && selectionMode() == Single &&
+ d->current && !d->current->s ) {
+ updateItem( d->current );
+ setSelected( d->current, TRUE );
+ }
+}
+
+
+/*!\reimp
+*/
+void QListBox::focusInEvent( QFocusEvent* )
+{
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->inMenuMode = FALSE;
+ if ( QFocusEvent::reason() != QFocusEvent::Mouse && !d->current && d->head ) {
+ d->current = d->head;
+ QListBoxItem *i = d->current;
+ QString tmp;
+ if ( i )
+ tmp = i->text();
+ int tmp2 = index( i );
+ emit highlighted( i );
+ if ( !tmp.isNull() )
+ emit highlighted( tmp );
+ emit highlighted( tmp2 );
+ emit currentChanged( i );
+ }
+ if ( style().styleHint( QStyle::SH_ItemView_ChangeHighlightOnFocus, this ) )
+ repaintSelection();
+
+ if ( d->current ) {
+ updateItem( currentItem() );
+ QRect mfrect = itemRect( d->current );
+ if ( mfrect.isValid() )
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+ }
+}
+
+
+/*!\reimp
+*/
+void QListBox::focusOutEvent( QFocusEvent* )
+{
+ if (style().styleHint( QStyle::SH_ItemView_ChangeHighlightOnFocus, this )) {
+ d->inMenuMode =
+ QFocusEvent::reason() == QFocusEvent::Popup ||
+ (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
+ if ( !d->inMenuMode )
+ repaintSelection();
+ }
+
+ if ( d->current )
+ updateItem( currentItem() );
+}
+
+/*!\reimp
+*/
+bool QListBox::eventFilter( QObject *o, QEvent *e )
+{
+ //### remove in 4.0
+ return QScrollView::eventFilter( o, e );
+}
+
+/*!
+ Repaints the item at position \a index in the list.
+*/
+
+void QListBox::updateItem( int index )
+{
+ if ( index >= 0 )
+ updateItem( item( index ) );
+}
+
+
+/*!
+ \overload
+
+ Repaints the QListBoxItem \a i.
+*/
+
+void QListBox::updateItem( QListBoxItem * i )
+{
+ if ( !i )
+ return;
+ i->dirty = TRUE;
+ d->updateTimer->start( 0, TRUE );
+}
+
+
+/*!
+ \property QListBox::selectionMode
+ \brief the selection mode of the list box
+
+ Sets the list box's selection mode, which may be one of \c Single
+ (the default), \c Extended, \c Multi or \c NoSelection.
+
+ \sa SelectionMode
+*/
+
+void QListBox::setSelectionMode( SelectionMode mode )
+{
+ if ( d->selectionMode == mode )
+ return;
+
+ if ( ( selectionMode() == Multi || selectionMode() == Extended )
+ && ( mode == QListBox::Single || mode == QListBox::NoSelection ) ){
+ clearSelection();
+ if ( ( mode == QListBox::Single ) && currentItem() )
+ setSelected( currentItem(), TRUE );
+ }
+
+ d->selectionMode = mode;
+ triggerUpdate( TRUE );
+}
+
+
+QListBox::SelectionMode QListBox::selectionMode() const
+{
+ return d->selectionMode;
+}
+
+
+/*!
+ \obsolete
+ \property QListBox::multiSelection
+ \brief whether or not the list box is in Multi selection mode
+
+ Consider using the \l QListBox::selectionMode property instead of
+ this property.
+
+ When setting this property, Multi selection mode is used if set to TRUE and
+ to Single selection mode if set to FALSE.
+
+ When getting this property, TRUE is returned if the list box is in
+ Multi selection mode or Extended selection mode, and FALSE if it is
+ in Single selection mode or NoSelection mode.
+
+ \sa selectionMode
+*/
+
+bool QListBox::isMultiSelection() const
+{
+ return selectionMode() == Multi || selectionMode() == Extended;
+}
+
+void QListBox::setMultiSelection( bool enable )
+{
+ setSelectionMode( enable ? Multi : Single );
+}
+
+
+/*!
+ Toggles the selection status of currentItem() and repaints if the
+ list box is a \c Multi selection list box.
+
+ \sa setMultiSelection()
+*/
+
+void QListBox::toggleCurrentItem()
+{
+ if ( selectionMode() == Single ||
+ selectionMode() == NoSelection ||
+ !d->current )
+ return;
+
+ if ( d->current->s || d->current->isSelectable() ) {
+ d->current->s = !d->current->s;
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ int ind = index( d->current );
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::StateChanged );
+ QAccessible::updateAccessibility( viewport(), ind+1, d->current->s ? QAccessible::SelectionAdd : QAccessible::SelectionRemove );
+#endif
+ }
+ updateItem( d->current );
+}
+
+
+/*!
+ \overload
+
+ If \a select is TRUE the item at position \a index is selected;
+ otherwise the item is deselected.
+*/
+
+void QListBox::setSelected( int index, bool select )
+{
+ setSelected( item( index ), select );
+}
+
+
+/*!
+ Selects \a item if \a select is TRUE or unselects it if \a select
+ is FALSE, and repaints the item appropriately.
+
+ If the list box is a \c Single selection list box and \a select is
+ TRUE, setSelected() calls setCurrentItem().
+
+ If the list box is a \c Single selection list box, \a select is
+ FALSE, setSelected() calls clearSelection().
+
+ \sa setMultiSelection(), setCurrentItem(), clearSelection(), currentItem()
+*/
+
+void QListBox::setSelected( QListBoxItem * item, bool select )
+{
+ if ( !item || !item->isSelectable() ||
+ (bool)item->s == select || d->selectionMode == NoSelection )
+ return;
+
+ int ind = index( item );
+ bool emitHighlighted = (d->current != item) ||
+ ( item->s != (uint) select && select );
+ if ( selectionMode() == Single ) {
+ if ( d->current != item ) {
+ QListBoxItem *o = d->current;
+ if ( d->current && d->current->s )
+ d->current->s = FALSE;
+ d->current = item;
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::Focus );
+#endif
+ d->currentColumn = ind / numRows();
+ d->currentRow = ind % numRows();
+
+ if ( o )
+ updateItem( o );
+ }
+ }
+
+ item->s = (uint)select;
+ updateItem( item );
+
+ if ( d->selectionMode == Single && select ) {
+ emit selectionChanged( item );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), ind+1, QAccessible::StateChanged );
+#endif
+ }
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+ if ( d->selectionMode != Single )
+ QAccessible::updateAccessibility( viewport(), ind+1, select ? QAccessible::SelectionAdd : QAccessible::SelectionRemove );
+#endif
+
+ if ( emitHighlighted ) {
+ QString tmp;
+ if ( d->current )
+ tmp = d->current->text();
+ int tmp2 = index( d->current );
+ emit highlighted( d->current );
+ if ( !tmp.isNull() )
+ emit highlighted( tmp );
+ emit highlighted( tmp2 );
+ emit currentChanged( d->current );
+ }
+}
+
+
+/*!
+ Returns TRUE if item \a i is selected; otherwise returns FALSE.
+*/
+
+bool QListBox::isSelected( int i ) const
+{
+ if ( selectionMode() == Single && i != currentItem() )
+ return FALSE;
+
+ QListBoxItem * lbi = item( i );
+ if ( !lbi )
+ return FALSE; // should not happen
+ return lbi->s;
+}
+
+
+/*!
+ \overload
+
+ Returns TRUE if item \a i is selected; otherwise returns FALSE.
+*/
+
+bool QListBox::isSelected( const QListBoxItem * i ) const
+{
+ if ( !i )
+ return FALSE;
+
+ return i->s;
+}
+
+/*! Returns the selected item if the list box is in
+single-selection mode and an item is selected.
+
+If no items are selected or the list box is in another selection mode
+this function returns 0.
+
+\sa setSelected() setMultiSelection()
+*/
+
+QListBoxItem* QListBox::selectedItem() const
+{
+ if ( d->selectionMode != Single )
+ return 0;
+ if ( isSelected( currentItem() ) )
+ return d->current;
+ return 0;
+}
+
+
+/*!
+ Deselects all items, if possible.
+
+ Note that a \c Single selection list box will automatically select
+ an item if it has keyboard focus.
+*/
+
+void QListBox::clearSelection()
+{
+ selectAll( FALSE );
+}
+
+/*!
+ In \c Multi and \c Extended modes, this function sets all items to
+ be selected if \a select is TRUE, and to be unselected if \a
+ select is FALSE.
+
+ In \c Single and \c NoSelection modes, this function only changes
+ the selection status of currentItem().
+*/
+
+void QListBox::selectAll( bool select )
+{
+ if ( selectionMode() == Multi || selectionMode() == Extended ) {
+ bool b = signalsBlocked();
+ blockSignals( TRUE );
+ for ( int i = 0; i < (int)count(); i++ )
+ setSelected( i, select );
+ blockSignals( b );
+ emit selectionChanged();
+ } else if ( d->current ) {
+ QListBoxItem * i = d->current;
+ setSelected( i, select );
+ }
+}
+
+/*!
+ Inverts the selection. Only works in \c Multi and \c Extended
+ selection mode.
+*/
+
+void QListBox::invertSelection()
+{
+ if ( d->selectionMode == Single ||
+ d->selectionMode == NoSelection )
+ return;
+
+ bool b = signalsBlocked();
+ blockSignals( TRUE );
+ for ( int i = 0; i < (int)count(); i++ )
+ setSelected( i, !item( i )->isSelected() );
+ blockSignals( b );
+ emit selectionChanged();
+}
+
+
+/*!
+ \obsolete
+ Not used anymore; provided for binary compatibility
+*/
+
+void QListBox::emitChangedSignal( bool )
+{
+}
+
+
+/*! \reimp */
+
+QSize QListBox::sizeHint() const
+{
+ if ( cachedSizeHint().isValid() )
+ return cachedSizeHint();
+
+ constPolish();
+ doLayout();
+
+ int i=0;
+ while( i < 10 &&
+ i < (int)d->columnPos.size()-1 &&
+ d->columnPos[i] < 200 )
+ i++;
+ int x;
+ x = QMIN( 200, d->columnPos[i] +
+ 2 * style().pixelMetric( QStyle::PM_DefaultFrameWidth ) );
+ x = QMAX( 40, x );
+
+ i = 0;
+ while( i < 10 &&
+ i < (int)d->rowPos.size()-1 &&
+ d->rowPos[i] < 200 )
+ i++;
+ int y;
+ y = QMIN( 200, d->rowPos[i] +
+ 2 * style().pixelMetric( QStyle::PM_DefaultFrameWidth ) );
+ y = QMAX( 40, y );
+
+ QSize s( x, y );
+ setCachedSizeHint( s );
+ return s;
+}
+
+/*!
+ \reimp
+*/
+
+QSize QListBox::minimumSizeHint() const
+{
+ return QScrollView::minimumSizeHint();
+}
+
+
+/*!
+ Ensures that a single paint event will occur at the end of the
+ current event loop iteration. If \a doLayout is TRUE, the layout
+ is also redone.
+*/
+
+void QListBox::triggerUpdate( bool doLayout )
+{
+ if ( doLayout )
+ d->layoutDirty = d->mustPaintAll = TRUE;
+ d->updateTimer->start( 0, TRUE );
+}
+
+
+void QListBox::setColumnMode( LayoutMode mode )
+{
+ if ( mode == Variable )
+ return;
+ d->rowModeWins = FALSE;
+ d->columnMode = mode;
+ triggerUpdate( TRUE );
+}
+
+
+void QListBox::setColumnMode( int columns )
+{
+ if ( columns < 1 )
+ columns = 1;
+ d->columnMode = FixedNumber;
+ d->numColumns = columns;
+ d->rowModeWins = FALSE;
+ triggerUpdate( TRUE );
+}
+
+void QListBox::setRowMode( LayoutMode mode )
+{
+ if ( mode == Variable )
+ return;
+ d->rowModeWins = TRUE;
+ d->rowMode = mode;
+ triggerUpdate( TRUE );
+}
+
+
+void QListBox::setRowMode( int rows )
+{
+ if ( rows < 1 )
+ rows = 1;
+ d->rowMode = FixedNumber;
+ d->numRows = rows;
+ d->rowModeWins = TRUE;
+ triggerUpdate( TRUE );
+}
+
+/*!
+ \property QListBox::columnMode
+ \brief the column layout mode for this list box.
+
+ setColumnMode() sets the layout mode and adjusts the number of
+ displayed columns. The row layout mode automatically becomes \c
+ Variable, unless the column mode is \c Variable.
+
+ \sa setRowMode() columnMode() rowMode numColumns
+*/
+
+
+QListBox::LayoutMode QListBox::columnMode() const
+{
+ if ( d->rowModeWins )
+ return Variable;
+ else
+ return d->columnMode;
+}
+
+
+/*!
+ \property QListBox::rowMode
+ \brief the row layout mode for this list box
+
+ This property is normally \c Variable.
+
+ setRowMode() sets the layout mode and adjusts the number of
+ displayed rows. The column layout mode automatically becomes \c
+ Variable, unless the row mode is \c Variable.
+
+ \sa columnMode rowMode
+*/
+
+
+QListBox::LayoutMode QListBox::rowMode() const
+{
+ if ( d->rowModeWins )
+ return d->rowMode;
+ else
+ return Variable;
+}
+
+
+/*!
+ \property QListBox::numColumns
+ \brief the number of columns in the list box
+
+ This is normally 1, but can be different if \l
+ QListBox::columnMode or \l QListBox::rowMode has been set.
+
+ \sa columnMode rowMode numRows
+*/
+
+int QListBox::numColumns() const
+{
+ if ( count() == 0 )
+ return 0;
+ if ( !d->rowModeWins && d->columnMode == FixedNumber )
+ return d->numColumns;
+ doLayout();
+ return d->columnPos.size()-1;
+}
+
+
+/*!
+ \property QListBox::numRows
+ \brief the number of rows in the list box.
+
+ This is equal to the number of items in the default single-column
+ layout, but can be different.
+
+ \sa columnMode rowMode numColumns
+*/
+
+int QListBox::numRows() const
+{
+ if ( count() == 0 )
+ return 0;
+ if ( d->rowModeWins && d->rowMode == FixedNumber )
+ return d->numRows;
+ doLayout();
+ return d->rowPos.size()-1;
+}
+
+
+/*!
+ This function does the hard layout work. You should never need to
+ call it.
+*/
+
+void QListBox::doLayout() const
+{
+ if ( !d->layoutDirty || d->resizeTimer->isActive() )
+ return;
+ constPolish();
+ int c = count();
+ switch( rowMode() ) {
+ case FixedNumber:
+ // columnMode() is known to be Variable
+ tryGeometry( d->numRows, (c+d->numRows-1)/d->numRows );
+ break;
+ case FitToHeight:
+ // columnMode() is known to be Variable
+ if ( d->head ) {
+ // this is basically the FitToWidth code, but edited to use rows.
+ int maxh = 0;
+ QListBoxItem * i = d->head;
+ while ( i ) {
+ int h = i->height(this);
+ if ( maxh < h )
+ maxh = h;
+ i = i->n;
+ }
+ int vh = viewportSize( 1, 1 ).height();
+ do {
+ int rows = vh / maxh;
+ if ( rows > c )
+ rows = c;
+ if ( rows < 1 )
+ rows = 1;
+ if ( variableHeight() && rows < c ) {
+ do {
+ ++rows;
+ tryGeometry( rows, (c+rows-1)/rows );
+ } while ( rows <= c &&
+ d->rowPos[(int)d->rowPos.size()-1] <= vh );
+ --rows;
+ }
+ tryGeometry( rows, (c+rows-1)/rows );
+ int nvh = viewportSize( d->columnPos[(int)d->columnPos.size()-1],
+ d->rowPos[(int)d->rowPos.size()-1] ).height();
+ if ( nvh < vh )
+ vh = nvh;
+ } while ( d->rowPos.size() > 2 &&
+ vh < d->rowPos[(int)d->rowPos.size()-1] );
+ } else {
+ tryGeometry( 1, 1 );
+ }
+ break;
+ case Variable:
+ if ( columnMode() == FixedNumber ) {
+ tryGeometry( (count()+d->numColumns-1)/d->numColumns,
+ d->numColumns );
+ } else if ( d->head ) { // FitToWidth, at least one item
+ int maxw = 0;
+ QListBoxItem * i = d->head;
+ while ( i ) {
+ int w = i->width(this);
+ if ( maxw < w )
+ maxw = w;
+ i = i->n;
+ }
+ int vw = viewportSize( 1, 1 ).width();
+ do {
+ int cols = vw / maxw;
+ if ( cols > c )
+ cols = c;
+ if ( cols < 1 )
+ cols = 1;
+ if ( variableWidth() && cols < c ) {
+ do {
+ ++cols;
+ tryGeometry( (c+cols-1)/cols, cols );
+ } while ( cols <= c &&
+ d->columnPos[(int)d->columnPos.size()-1] <= vw );
+ --cols;
+ }
+ tryGeometry( (c+cols-1)/cols, cols );
+ int nvw = viewportSize( d->columnPos[(int)d->columnPos.size()-1],
+ d->rowPos[(int)d->rowPos.size()-1] ).width();
+ if ( nvw < vw )
+ vw = nvw;
+ } while ( d->columnPos.size() > 2 &&
+ vw < d->columnPos[(int)d->columnPos.size()-1] );
+ } else {
+ tryGeometry( 1, 1 );
+ }
+ break;
+ }
+
+ d->layoutDirty = FALSE;
+ int w = d->columnPos[(int)d->columnPos.size()-1];
+ int h = d->rowPos[(int)d->rowPos.size()-1];
+ QSize s( viewportSize( w, h ) );
+ w = QMAX( w, s.width() );
+
+ d->columnPosOne = d->columnPos[1];
+ // extend the column for simple single-column listboxes
+ if ( columnMode() == FixedNumber && d->numColumns == 1 &&
+ d->columnPos[1] < w )
+ d->columnPos[1] = w;
+ ((QListBox *)this)->resizeContents( w, h );
+}
+
+
+/*!
+ Lay the items out in a \a columns by \a rows array. The array may
+ be too big: doLayout() is expected to call this with the right
+ values.
+*/
+
+void QListBox::tryGeometry( int rows, int columns ) const
+{
+ if ( columns < 1 )
+ columns = 1;
+ d->columnPos.resize( columns+1 );
+
+ if ( rows < 1 )
+ rows = 1;
+ d->rowPos.resize( rows+1 );
+
+ // funky hack I: dump the height/width of each column/row in
+ // {column,row}Pos for later conversion to positions.
+ int c;
+ for( c=0; c<=columns; c++ )
+ d->columnPos[c] = 0;
+ int r;
+ for( r=0; r<=rows; r++ )
+ d->rowPos[r] = 0;
+ r = c = 0;
+ QListBoxItem * i = d->head;
+ while ( i && c < columns ) {
+ if ( i == d->current ) {
+ d->currentRow = r;
+ d->currentColumn = c;
+ }
+
+ int w = i->width(this);
+ if ( d->columnPos[c] < w )
+ d->columnPos[c] = w;
+ int h = i->height(this);
+ if ( d->rowPos[r] < h )
+ d->rowPos[r] = h;
+ i = i->n;
+ r++;
+ if ( r == rows ) {
+ r = 0;
+ c++;
+ }
+ }
+ // funky hack II: if not variable {width,height}, unvariablify it.
+ if ( !variableWidth() ) {
+ int w = 0;
+ for( c=0; c<columns; c++ )
+ if ( w < d->columnPos[c] )
+ w = d->columnPos[c];
+ for( c=0; c<columns; c++ )
+ d->columnPos[c] = w;
+ }
+ if ( !variableHeight() ) {
+ int h = 0;
+ for( r=0; r<rows; r++ )
+ if ( h < d->rowPos[r] )
+ h = d->rowPos[r];
+ for( r=0; r<rows; r++ )
+ d->rowPos[r] = h;
+ }
+ // repair the hacking.
+ int x = 0;
+ for( c=0; c<=columns; c++ ) {
+ int w = d->columnPos[c];
+ d->columnPos[c] = x;
+ x += w;
+ }
+ int y = 0;
+ for( r=0; r<=rows; r++ ) {
+ int h = d->rowPos[r];
+ d->rowPos[r] = y;
+ y += h;
+ }
+}
+
+
+/*!
+ Returns the row index of the current item, or -1 if no item is the
+ current item.
+*/
+
+int QListBox::currentRow() const
+{
+ if ( !d->current )
+ return -1;
+ if ( d->currentRow < 0 )
+ d->layoutDirty = TRUE;
+ if ( d->layoutDirty )
+ doLayout();
+ return d->currentRow;
+}
+
+
+/*!
+ Returns the column index of the current item, or -1 if no item is
+ the current item.
+*/
+
+int QListBox::currentColumn() const
+{
+ if ( !d->current )
+ return -1;
+ if ( d->currentColumn < 0 )
+ d->layoutDirty = TRUE;
+ if ( d->layoutDirty )
+ doLayout();
+ return d->currentColumn;
+}
+
+
+void QListBox::setTopItem( int index )
+{
+ if ( index >= (int)count() || count() == 0 )
+ return;
+ int col = index / numRows();
+ int y = d->rowPos[index-col*numRows()];
+ if ( d->columnPos[col] >= contentsX() &&
+ d->columnPos[col+1] <= contentsX() + visibleWidth() )
+ setContentsPos( contentsX(), y );
+ else
+ setContentsPos( d->columnPos[col], y );
+}
+
+/*!
+ Scrolls the list box so the item at position \a index in the list
+ is displayed in the bottom row of the list box.
+
+ \sa setTopItem()
+*/
+
+void QListBox::setBottomItem( int index )
+{
+ if ( index >= (int)count() || count() == 0 )
+ return;
+ int col = index / numRows();
+ int y = d->rowPos[1+index-col*numRows()] - visibleHeight();
+ if ( y < 0 )
+ y = 0;
+ if ( d->columnPos[col] >= contentsX() &&
+ d->columnPos[col+1] <= contentsX() + visibleWidth() )
+ setContentsPos( contentsX(), y );
+ else
+ setContentsPos( d->columnPos[col], y );
+}
+
+
+/*!
+ Returns the item at point \a p, specified in viewport coordinates,
+ or a 0 if there is no item at \a p.
+
+ Use contentsToViewport() to convert between widget coordinates and
+ viewport coordinates.
+*/
+
+QListBoxItem * QListBox::itemAt( const QPoint& p ) const
+{
+ if ( d->layoutDirty )
+ doLayout();
+ QPoint np = p;
+
+ // take into acount frame margin to get to viewport
+ np -= viewport()->pos();
+ if (!viewport()->rect().contains(np))
+ return 0;
+
+ // take into account contents position
+ np = viewportToContents( np );
+
+ int x = np.x();
+ int y = np.y();
+
+ // return 0 when y is below the last row
+ if ( y > d->rowPos[ numRows() ] )
+ return 0;
+
+ int col = columnAt( x );
+ int row = rowAt( y );
+
+ QListBoxItem *i = item( col * numRows() + row );
+ if ( i && numColumns() > 1 ) {
+ if ( d->columnPos[ col ] + i->width( this ) >= x )
+ return i;
+ } else {
+ if ( d->columnPos[ col + 1 ] >= x )
+ return i;
+ }
+ return 0;
+}
+
+
+/*!
+ Ensures that the current item is visible.
+*/
+
+void QListBox::ensureCurrentVisible()
+{
+ if ( !d->current )
+ return;
+
+ doLayout();
+
+ int row = currentRow();
+ int column = currentColumn();
+ int w = ( d->columnPos[column+1] - d->columnPos[column] ) / 2;
+ int h = ( d->rowPos[row+1] - d->rowPos[row] ) / 2;
+ // next four lines are Bad. they mean that for pure left-to-right
+ // languages, textual list box items are displayed better than
+ // before when there is little space. for non-textual items, or
+ // other languages, it means... that you really should have enough
+ // space in the first place :)
+ if ( numColumns() == 1 )
+ w = 0;
+ if ( w*2 > viewport()->width() )
+ w = viewport()->width()/2;
+
+ ensureVisible( d->columnPos[column] + w, d->rowPos[row] + h, w, h);
+}
+
+
+/*! \internal */
+
+void QListBox::doAutoScroll()
+{
+ if ( d->scrollPos.x() < 0 ) {
+ // scroll left
+ int x = contentsX() - horizontalScrollBar()->lineStep();
+ if ( x < 0 )
+ x = 0;
+ if ( x != contentsX() ) {
+ d->mouseMoveColumn = columnAt( x );
+ updateSelection();
+ if ( x < contentsX() )
+ setContentsPos( x, contentsY() );
+ }
+ } else if ( d->scrollPos.x() > 0 ) {
+ // scroll right
+ int x = contentsX() + horizontalScrollBar()->lineStep();
+ if ( x + visibleWidth() > contentsWidth() )
+ x = contentsWidth() - visibleWidth();
+ if ( x != contentsX() ) {
+ d->mouseMoveColumn = columnAt( x + visibleWidth() - 1 );
+ updateSelection();
+ if ( x > contentsX() )
+ setContentsPos( x, contentsY() );
+ }
+ }
+
+ if ( d->scrollPos.y() < 0 ) {
+ // scroll up
+ int y = contentsY() - verticalScrollBar()->lineStep();
+ if ( y < 0 )
+ y = 0;
+ if ( y != contentsY() ) {
+ y = contentsY() - verticalScrollBar()->lineStep();
+ d->mouseMoveRow = rowAt( y );
+ updateSelection();
+ }
+ } else if ( d->scrollPos.y() > 0 ) {
+ // scroll down
+ int y = contentsY() + verticalScrollBar()->lineStep();
+ if ( y + visibleHeight() > contentsHeight() )
+ y = contentsHeight() - visibleHeight();
+ if ( y != contentsY() ) {
+ y = contentsY() + verticalScrollBar()->lineStep();
+ d->mouseMoveRow = rowAt(y + visibleHeight() - 1 );
+ updateSelection();
+ }
+ }
+
+ if ( d->scrollPos == QPoint( 0, 0 ) ) {
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+}
+
+
+/*!
+ \property QListBox::topItem
+ \brief the index of an item at the top of the screen.
+
+ When getting this property and the listbox has multiple columns,
+ an arbitrary item is selected and returned.
+
+ When setting this property, the list box is scrolled so the item
+ at position \e index in the list is displayed in the top row of
+ the list box.
+*/
+
+int QListBox::topItem() const
+{
+ doLayout();
+
+ // move rightwards to the best column
+ int col = columnAt( contentsX() );
+ int row = rowAt( contentsY() );
+ return col * numRows() + row;
+}
+
+
+/*!
+ \property QListBox::variableHeight
+ \brief whether this list box has variable-height rows
+
+ When the list box has variable-height rows (the default), each row
+ is as high as the highest item in that row. When it has same-sized
+ rows, all rows are as high as the highest item in the list box.
+
+ \sa variableWidth
+*/
+
+bool QListBox::variableHeight() const
+{
+ return d->variableHeight;
+}
+
+
+void QListBox::setVariableHeight( bool enable )
+{
+ if ( (bool)d->variableHeight == enable )
+ return;
+
+ d->variableHeight = enable;
+ triggerUpdate( TRUE );
+}
+
+
+/*!
+ \property QListBox::variableWidth
+ \brief whether this list box has variable-width columns
+
+ When the list box has variable-width columns, each column is as
+ wide as the widest item in that column. When it has same-sized
+ columns (the default), all columns are as wide as the widest item
+ in the list box.
+
+ \sa variableHeight
+*/
+
+bool QListBox::variableWidth() const
+{
+ return d->variableWidth;
+}
+
+
+void QListBox::setVariableWidth( bool enable )
+{
+ if ( (bool)d->variableWidth == enable )
+ return;
+
+ d->variableWidth = enable;
+ triggerUpdate( TRUE );
+}
+
+
+/*!
+ Repaints only what really needs to be repainted.
+*/
+void QListBox::refreshSlot()
+{
+ if ( d->mustPaintAll ||
+ d->layoutDirty ) {
+ d->mustPaintAll = FALSE;
+ bool currentItemVisible = itemVisible( currentItem() );
+ doLayout();
+ if ( hasFocus() &&
+ currentItemVisible &&
+ d->currentColumn >= 0 &&
+ d->currentRow >= 0 &&
+ ( d->columnPos[d->currentColumn] < contentsX() ||
+ d->columnPos[d->currentColumn+1]>contentsX()+visibleWidth() ||
+ d->rowPos[d->currentRow] < contentsY() ||
+ d->rowPos[d->currentRow+1] > contentsY()+visibleHeight() ) )
+ ensureCurrentVisible();
+ viewport()->repaint( FALSE );
+ return;
+ }
+
+ QRegion r;
+ int x = contentsX();
+ int y = contentsY();
+ int col = columnAt( x );
+ int row = rowAt( y );
+ int top = row;
+ while( col < (int)d->columnPos.size()-1 && d->columnPos[col+1] < x )
+ col++;
+ while( top < (int)d->rowPos.size()-1 && d->rowPos[top+1] < y )
+ top++;
+ QListBoxItem * i = item( col * numRows() + row );
+
+ while ( i && (int)col < numColumns() &&
+ d->columnPos[col] < x + visibleWidth() ) {
+ int cw = d->columnPos[col+1] - d->columnPos[col];
+ while ( i && row < numRows() && d->rowPos[row] <
+ y + visibleHeight() ) {
+ if ( i->dirty )
+ r = r.unite( QRect( d->columnPos[col] - x, d->rowPos[row] - y,
+ cw, d->rowPos[row+1] - d->rowPos[row] ) );
+ row++;
+ i = i->n;
+ }
+ col++;
+ if ( numColumns() > 1 ) {
+ row = top;
+ i = item( col * numRows() + row );
+ }
+ }
+
+ if ( r.isEmpty() )
+ viewport()->repaint( FALSE );
+ else
+ viewport()->repaint( r, FALSE );
+}
+
+
+/*! \reimp */
+
+void QListBox::viewportPaintEvent( QPaintEvent * e )
+{
+ doLayout();
+ QWidget* vp = viewport();
+ QPainter p( vp );
+ QRegion r = e->region();
+
+#if 0
+ {
+ // this stuff has been useful enough times that from now I'm
+ // leaving it in the source.
+ uint i = 0;
+ qDebug( "%s/%s: %i rects", className(), name(), r.rects().size() );
+ while( i < r.rects().size() ) {
+ qDebug( "rect %d: %d, %d, %d, %d", i,
+ r.rects()[i].left(), r.rects()[i].top(),
+ r.rects()[i].width(), r.rects()[i].height() );
+ i++;
+ }
+ qDebug( "" );
+ }
+#endif
+
+ int x = contentsX();
+ int y = contentsY();
+ int w = vp->width();
+ int h = vp->height();
+
+ int col = columnAt( x );
+ int top = rowAt( y );
+ int row = top;
+
+ QListBoxItem * i = item( col*numRows() + row );
+
+ const QColorGroup & g = colorGroup();
+ p.setPen( g.text() );
+ p.setBackgroundColor( backgroundBrush().color() );
+ while ( i && (int)col < numColumns() && d->columnPos[col] < x + w ) {
+ int cw = d->columnPos[col+1] - d->columnPos[col];
+ while ( i && (int)row < numRows() && d->rowPos[row] < y + h ) {
+ int ch = d->rowPos[row+1] - d->rowPos[row];
+ QRect itemRect( d->columnPos[col]-x, d->rowPos[row]-y, cw, ch );
+ QRegion tempRegion( itemRect );
+ QRegion itemPaintRegion( tempRegion.intersect( r ) );
+ if ( !itemPaintRegion.isEmpty() ) {
+ p.save();
+ p.setClipRegion( itemPaintRegion );
+ p.translate( d->columnPos[col]-x, d->rowPos[row]-y );
+ paintCell( &p, row, col );
+ p.restore();
+ r = r.subtract( itemPaintRegion );
+ }
+ row++;
+ if ( i->dirty ) {
+ // reset dirty flag only if the entire item was painted
+ if ( itemPaintRegion == QRegion( itemRect ) )
+ i->dirty = FALSE;
+ }
+ i = i->n;
+ }
+ col++;
+ if ( numColumns() > 1 ) {
+ row = top;
+ i = item( col * numRows() + row );
+ }
+ }
+
+ if ( r.isEmpty() )
+ return;
+ p.setClipRegion( r );
+ p.fillRect( 0, 0, w, h, viewport()->backgroundBrush() );
+}
+
+
+/*!
+ Returns the height in pixels of the item with index \a index. \a
+ index defaults to 0.
+
+ If \a index is too large, this function returns 0.
+*/
+
+int QListBox::itemHeight( int index ) const
+{
+ if ( index >= (int)count() || index < 0 )
+ return 0;
+ int r = index % numRows();
+ return d->rowPos[r+1] - d->rowPos[r];
+}
+
+
+/*!
+ Returns the index of the column at \a x, which is in the listbox's
+ coordinates, not in on-screen coordinates.
+
+ If there is no column that spans \a x, columnAt() returns -1.
+*/
+
+int QListBox::columnAt( int x ) const
+{
+ if ( x < 0 )
+ return -1;
+ if ( !d->columnPos.size() )
+ return -1;
+ if ( x >= d->columnPos[(int)d->columnPos.size()-1 ] )
+ return numColumns() - 1;
+
+ int col = 0;
+ while( col < (int)d->columnPos.size()-1 && d->columnPos[col+1] < x )
+ col++;
+ return col;
+}
+
+
+/*!
+ Returns the index of the row at \a y, which is in the listbox's
+ coordinates, not in on-screen coordinates.
+
+ If there is no row that spans \a y, rowAt() returns -1.
+*/
+
+int QListBox::rowAt( int y ) const
+{
+ if ( y < 0 )
+ return -1;
+
+ // find the top item, use bsearch for speed
+ int l = 0;
+ int r = d->rowPos.size() - 2;
+ if ( r < 0 )
+ return -1;
+ if ( l <= d->rowPosCache && d->rowPosCache <= r ) {
+ if ( d->rowPos[ QMAX( l, d->rowPosCache - 10 ) ] <= y
+ && y <= d->rowPos[ QMIN( r, d->rowPosCache + 10 ) ] ) {
+ l = QMAX( l, d->rowPosCache - 10 );
+ r = QMIN( r, d->rowPosCache + 10 );
+ }
+ }
+ int i = ( (l+r+1) / 2 );
+ while ( r - l ) {
+ if ( d->rowPos[i] > y )
+ r = i -1;
+ else
+ l = i;
+ i = ( (l+r+1) / 2 );
+ }
+ d->rowPosCache = i;
+ if ( d->rowPos[i] <= y && y <= d->rowPos[i+1] )
+ return i;
+
+ return d->count - 1;
+}
+
+
+/*!
+ Returns the rectangle on the screen that \a item occupies in
+ viewport()'s coordinates, or an invalid rectangle if \a item is 0
+ or is not currently visible.
+*/
+
+QRect QListBox::itemRect( QListBoxItem *item ) const
+{
+ if ( d->resizeTimer->isActive() )
+ return QRect( 0, 0, -1, -1 );
+ if ( !item )
+ return QRect( 0, 0, -1, -1 );
+
+ int i = index( item );
+ int col = i / numRows();
+ int row = i % numRows();
+
+ int x = d->columnPos[ col ] - contentsX();
+ int y = d->rowPos[ row ] - contentsY();
+
+ QRect r( x, y, d->columnPos[ col + 1 ] - d->columnPos[ col ],
+ d->rowPos[ row + 1 ] - d->rowPos[ row ] );
+ if ( r.intersects( QRect( 0, 0, visibleWidth(), visibleHeight() ) ) )
+ return r;
+ return QRect( 0, 0, -1, -1 );
+}
+
+
+#ifndef QT_NO_COMPAT
+
+/*!
+ \obsolete
+
+ Using this method is quite inefficient. We suggest to use insertItem()
+ for inserting and sort() afterwards.
+
+ Inserts \a lbi at its sorted position in the list box and returns the
+ position.
+
+ All items must be inserted with inSort() to maintain the sorting
+ order. inSort() treats any pixmap (or user-defined type) as
+ lexicographically less than any string.
+
+ \sa insertItem(), sort()
+*/
+int QListBox::inSort( const QListBoxItem * lbi )
+{
+ qObsolete( "QListBox", "inSort", "insertItem" );
+ if ( !lbi )
+ return -1;
+
+ QListBoxItem * i = d->head;
+ int c = 0;
+
+ while( i && i->text() < lbi->text() ) {
+ i = i->n;
+ c++;
+ }
+ insertItem( lbi, c );
+ return c;
+}
+
+/*!
+ \obsolete
+ \overload
+ Using this method is quite inefficient. We suggest to use insertItem()
+ for inserting and sort() afterwards.
+
+ Inserts a new item of \a text at its sorted position in the list box and
+ returns the position.
+
+ All items must be inserted with inSort() to maintain the sorting
+ order. inSort() treats any pixmap (or user-defined type) as
+ lexicographically less than any string.
+
+ \sa insertItem(), sort()
+*/
+int QListBox::inSort( const QString& text )
+{
+ qObsolete( "QListBox", "inSort", "insertItem" );
+ return inSort( new QListBoxText(text) );
+}
+
+#endif
+
+
+/*! \reimp */
+
+void QListBox::resizeEvent( QResizeEvent *e )
+{
+ d->layoutDirty = ( d->layoutDirty ||
+ rowMode() == FitToHeight ||
+ columnMode() == FitToWidth );
+
+ if ( !d->layoutDirty && columnMode() == FixedNumber &&
+ d->numColumns == 1) {
+ int w = d->columnPosOne;
+ QSize s( viewportSize( w, contentsHeight() ) );
+ w = QMAX( w, s.width() );
+ d->columnPos[1] = QMAX( w, d->columnPosOne );
+ resizeContents( d->columnPos[1], contentsHeight() );
+ }
+
+ if ( d->resizeTimer->isActive() )
+ d->resizeTimer->stop();
+ if ( d->rowMode == FixedNumber && d->columnMode == FixedNumber ) {
+ bool currentItemVisible = itemVisible( currentItem() );
+ doLayout();
+ QScrollView::resizeEvent( e );
+ if ( currentItemVisible )
+ ensureCurrentVisible();
+ if ( d->current )
+ viewport()->repaint( itemRect( d->current ), FALSE );
+ } else if ( ( d->columnMode == FitToWidth || d->rowMode == FitToHeight ) && !(isVisible()) ) {
+ QScrollView::resizeEvent( e );
+ } else if ( d->layoutDirty ) {
+ d->resizeTimer->start( 100, TRUE );
+ resizeContents( contentsWidth() - ( e->oldSize().width() - e->size().width() ),
+ contentsHeight() - ( e->oldSize().height() - e->size().height() ) );
+ QScrollView::resizeEvent( e );
+ } else {
+ QScrollView::resizeEvent( e );
+ }
+}
+
+/*!
+ \internal
+*/
+
+void QListBox::adjustItems()
+{
+ triggerUpdate( TRUE );
+ ensureCurrentVisible();
+}
+
+
+/*!
+ Provided for compatibility with the old QListBox. We recommend
+ using QListBoxItem::paint() instead.
+
+ Repaints the cell at \a row, \a col using painter \a p.
+*/
+
+void QListBox::paintCell( QPainter * p, int row, int col )
+{
+ bool drawActiveSelection = hasFocus() || d->inMenuMode ||
+ !style().styleHint( QStyle::SH_ItemView_ChangeHighlightOnFocus, this );
+ const QColorGroup &g = ( drawActiveSelection ? colorGroup() : palette().inactive() );
+
+ int cw = d->columnPos[col+1] - d->columnPos[col];
+ int ch = d->rowPos[row+1] - d->rowPos[row];
+ QListBoxItem * i = item( col*numRows()+row );
+ p->save();
+ if ( i->s ) {
+ if ( i->custom_highlight ) {
+ p->fillRect( 0, 0, cw, ch,
+ g.brush( QPalette::backgroundRoleFromMode( viewport()->backgroundMode() ) ) );
+ p->setPen( g.highlightedText() );
+ p->setBackgroundColor( g.highlight() );
+ }
+ else if ( numColumns() == 1 ) {
+ p->fillRect( 0, 0, cw, ch, g.brush( QColorGroup::Highlight ) );
+ p->setPen( g.highlightedText() );
+ p->setBackgroundColor( g.highlight() );
+ } else {
+ int iw = i->width( this );
+ p->fillRect( 0, 0, iw, ch, g.brush( QColorGroup::Highlight ) );
+ p->fillRect( iw, 0, cw - iw + 1, ch,
+ g.brush( QPalette::backgroundRoleFromMode( viewport()->backgroundMode() ) ) );
+ p->setPen( g.highlightedText() );
+ p->setBackgroundColor( g.highlight() );
+ }
+ } else {
+ p->fillRect( 0, 0, cw, ch,
+ g.brush( QPalette::backgroundRoleFromMode( viewport()->backgroundMode() ) ) );
+ }
+
+ i->paint( p );
+
+ if ( d->current == i && hasFocus() && !i->custom_highlight ) {
+ if ( numColumns() > 1 )
+ cw = i->width( this );
+
+ style().drawPrimitive( QStyle::PE_FocusRect, p, QRect( 0, 0, cw, ch ), g,
+ QStyle::Style_FocusAtBorder,
+ QStyleOption(i->isSelected() ? g.highlight() : g.base() ) );
+ }
+
+ p->restore();
+}
+
+/*!
+ Returns the width of the widest item in the list box.
+*/
+
+long QListBox::maxItemWidth() const
+{
+ if ( d->layoutDirty )
+ doLayout();
+ long m = 0;
+ int i = d->columnPos.size();
+ while( i-- )
+ if ( m < d->columnPos[i] )
+ m = d->columnPos[i];
+ return m;
+}
+
+
+/*! \reimp */
+
+void QListBox::showEvent( QShowEvent * )
+{
+ d->ignoreMoves = FALSE;
+ d->mousePressRow = -1;
+ d->mousePressColumn = -1;
+ d->mustPaintAll = FALSE;
+ ensureCurrentVisible();
+}
+
+#ifndef QT_NO_COMPAT
+
+/*!
+ \obsolete
+
+ Returns the vertical pixel-coordinate in \a *yPos, of the list box
+ item at position \a index in the list. Returns FALSE if the item is
+ outside the visible area.
+*/
+bool QListBox::itemYPos( int index, int *yPos ) const
+{
+ qObsolete( "QListBox", "itemYPos" );
+ QListBoxItem* i = item(index);
+ if ( !i )
+ return FALSE;
+ if ( yPos )
+ *yPos = i->y;
+ return TRUE;
+}
+
+#endif
+
+/*!
+ \fn bool QListBoxItem::isSelected() const
+
+ Returns TRUE if the item is selected; otherwise returns FALSE.
+
+ \sa QListBox::isSelected(), isCurrent()
+*/
+
+/*!
+ \fn bool QListBoxItem::selected() const
+ \obsolete
+*/
+
+/*!
+ Returns TRUE if the item is the current item; otherwise returns
+ FALSE.
+
+ \sa QListBox::currentItem(), QListBox::item(), isSelected()
+*/
+bool QListBoxItem::isCurrent() const
+{
+ return listBox() && listBox()->hasFocus() &&
+ listBox()->item( listBox()->currentItem() ) == this;
+}
+/*!
+ \fn bool QListBoxItem::current() const
+ \obsolete
+*/
+
+/*!
+ \fn void QListBox::centerCurrentItem()
+ \obsolete
+
+ This function does exactly the same as ensureCurrentVisible()
+
+ \sa QListBox::ensureCurrentVisible()
+*/
+
+/*!
+ Returns a pointer to the list box containing this item.
+*/
+
+QListBox * QListBoxItem::listBox() const
+{
+ return lbox;
+}
+
+
+/*!
+ Removes \a item from the list box and causes an update of the
+ screen display. The item is not deleted. You should normally not
+ need to call this function because QListBoxItem::~QListBoxItem()
+ calls it. The normal way to delete an item is with \c delete.
+
+ \sa QListBox::insertItem()
+*/
+void QListBox::takeItem( const QListBoxItem * item )
+{
+ if ( !item || d->clearing )
+ return;
+ d->cache = 0;
+ d->count--;
+ if ( item == d->last )
+ d->last = d->last->p;
+ if ( item->p && item->p->n == item )
+ item->p->n = item->n;
+ if ( item->n && item->n->p == item )
+ item->n->p = item->p;
+ if ( d->head == item ) {
+ d->head = item->n;
+ d->currentColumn = d->currentRow = -1;
+ }
+
+ if ( d->current == item ) {
+ d->current = item->n ? item->n : item->p;
+ QListBoxItem *i = d->current;
+ QString tmp;
+ if ( i )
+ tmp = i->text();
+ int tmp2 = index( i );
+ emit highlighted( i );
+ if ( !tmp.isNull() )
+ emit highlighted( tmp );
+ emit highlighted( tmp2 );
+ emit currentChanged( i );
+ }
+ if ( d->tmpCurrent == item )
+ d->tmpCurrent = d->current;
+ if ( d->selectAnchor == item )
+ d->selectAnchor = d->current;
+
+ if ( item->s )
+ emit selectionChanged();
+ ((QListBoxItem *)item)->lbox = 0;
+ triggerUpdate( TRUE );
+}
+
+/*!
+ \internal
+ Finds the next item after start beginning with \a text.
+*/
+
+int QListBoxPrivate::findItemByName( int start, const QString &text )
+{
+ if ( start < 0 || (uint)start >= listBox->count() )
+ start = 0;
+ QString match = text.lower();
+ if ( match.length() < 1 )
+ return start;
+ QString curText;
+ int item = start;
+ do {
+ curText = listBox->text( item ).lower();
+ if ( curText.startsWith( match ) )
+ return item;
+ item++;
+ if ( (uint)item == listBox->count() )
+ item = 0;
+ } while ( item != start );
+ return -1;
+}
+
+/*!
+ \internal --- obsolete!
+*/
+
+void QListBox::clearInputString()
+{
+ d->currInputString = QString::null;
+}
+
+/*!
+ Finds the first list box item that has the text \a text and
+ returns it, or returns 0 of no such item could be found.
+ The search starts from the current item if the current item exists,
+ otherwise it starts from the first list box item.
+ If \c ComparisonFlags are specified in \a compare then these flags
+ are used, otherwise the default is a case-insensitive, "begins
+ with" search.
+
+ \sa Qt::StringComparisonMode
+*/
+
+QListBoxItem *QListBox::findItem( const QString &text, ComparisonFlags compare ) const
+{
+ if ( text.isEmpty() )
+ return 0;
+
+ if ( compare == CaseSensitive || compare == 0 )
+ compare |= ExactMatch;
+
+ QString itmtxt;
+ QString comtxt = text;
+ if ( ! (compare & CaseSensitive ) )
+ comtxt = text.lower();
+
+ QListBoxItem *item;
+ if ( d->current )
+ item = d->current;
+ else
+ item = d->head;
+
+ QListBoxItem *beginsWithItem = 0;
+ QListBoxItem *endsWithItem = 0;
+ QListBoxItem *containsItem = 0;
+
+ if ( item ) {
+ for ( ; item; item = item->n ) {
+ if ( ! (compare & CaseSensitive) )
+ itmtxt = item->text().lower();
+ else
+ itmtxt = item->text();
+
+ if ( compare & ExactMatch && itmtxt == comtxt )
+ return item;
+ if ( compare & BeginsWith && !beginsWithItem && itmtxt.startsWith( comtxt ) )
+ beginsWithItem = containsItem = item;
+ if ( compare & EndsWith && !endsWithItem && itmtxt.endsWith( comtxt ) )
+ endsWithItem = containsItem = item;
+ if ( compare & Contains && !containsItem && itmtxt.contains( comtxt ) )
+ containsItem = item;
+ }
+
+ if ( d->current && d->head ) {
+ item = d->head;
+ for ( ; item && item != d->current; item = item->n ) {
+ if ( ! (compare & CaseSensitive) )
+ itmtxt = item->text().lower();
+ else
+ itmtxt = item->text();
+
+ if ( compare & ExactMatch && itmtxt == comtxt )
+ return item;
+ if ( compare & BeginsWith && !beginsWithItem && itmtxt.startsWith( comtxt ) )
+ beginsWithItem = containsItem = item;
+ if ( compare & EndsWith && !endsWithItem && itmtxt.endsWith( comtxt ) )
+ endsWithItem = containsItem = item;
+ if ( compare & Contains && !containsItem && itmtxt.contains( comtxt ) )
+ containsItem = item;
+ }
+ }
+ }
+
+ // Obey the priorities
+ if ( beginsWithItem )
+ return beginsWithItem;
+ else if ( endsWithItem )
+ return endsWithItem;
+ else if ( containsItem )
+ return containsItem;
+ return 0;
+}
+
+/*!
+ \internal
+*/
+
+void QListBox::drawRubber()
+{
+ if ( !d->rubber )
+ return;
+ if ( !d->rubber->width() && !d->rubber->height() )
+ return;
+ QPainter p( viewport() );
+ p.setRasterOp( NotROP );
+ style().drawPrimitive( QStyle::PE_RubberBand, &p, d->rubber->normalize(),
+ colorGroup() );
+ p.end();
+}
+
+/*!
+ \internal
+*/
+
+void QListBox::doRubberSelection( const QRect &old, const QRect &rubber )
+{
+ QListBoxItem *i = d->head;
+ QRect ir, pr;
+ bool changed = FALSE;
+ for ( ; i; i = i->n ) {
+ ir = itemRect( i );
+ if ( ir == QRect( 0, 0, -1, -1 ) )
+ continue;
+ if ( i->isSelected() && !ir.intersects( rubber ) && ir.intersects( old ) ) {
+ i->s = FALSE;
+ pr = pr.unite( ir );
+ changed = TRUE;
+ } else if ( !i->isSelected() && ir.intersects( rubber ) ) {
+ if ( i->isSelectable() ) {
+ i->s = TRUE;
+ pr = pr.unite( ir );
+ changed = TRUE;
+ }
+ }
+ }
+ if ( changed ) {
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+#endif
+ }
+ viewport()->repaint( pr, TRUE );
+}
+
+
+/*!
+ Returns TRUE if the user is selecting items using a rubber band
+ rectangle; otherwise returns FALSE.
+*/
+
+bool QListBox::isRubberSelecting() const
+{
+ return d->rubber != 0;
+}
+
+
+/*!
+ Returns the item that comes after this in the list box. If this is
+ the last item, 0 is returned.
+
+ \sa prev()
+*/
+
+QListBoxItem *QListBoxItem::next() const
+{
+ return n;
+}
+
+/*!
+ Returns the item which comes before this in the list box. If this
+ is the first item, 0 is returned.
+
+ \sa next()
+*/
+
+QListBoxItem *QListBoxItem::prev() const
+{
+ return p;
+}
+
+/*!
+ Returns the first item in this list box. If the list box is empty,
+ returns 0.
+*/
+
+QListBoxItem *QListBox::firstItem() const
+{
+ return d->head;
+}
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+#ifdef Q_OS_TEMP
+static int _cdecl cmpListBoxItems( const void *n1, const void *n2 )
+#else
+static int cmpListBoxItems( const void *n1, const void *n2 )
+#endif
+{
+ if ( !n1 || !n2 )
+ return 0;
+
+ QListBoxPrivate::SortableItem *i1 = (QListBoxPrivate::SortableItem *)n1;
+ QListBoxPrivate::SortableItem *i2 = (QListBoxPrivate::SortableItem *)n2;
+
+ return i1->item->text().localeAwareCompare( i2->item->text() );
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+/*!
+ If \a ascending is TRUE sorts the items in ascending order;
+ otherwise sorts in descending order.
+
+ To compare the items, the text (QListBoxItem::text()) of the items
+ is used.
+*/
+
+void QListBox::sort( bool ascending )
+{
+ if ( count() == 0 )
+ return;
+
+ d->cache = 0;
+
+ QListBoxPrivate::SortableItem *items = new QListBoxPrivate::SortableItem[ count() ];
+
+ QListBoxItem *item = d->head;
+ int i = 0;
+ for ( ; item; item = item->n )
+ items[ i++ ].item = item;
+
+ qsort( items, count(), sizeof( QListBoxPrivate::SortableItem ), cmpListBoxItems );
+
+ QListBoxItem *prev = 0;
+ item = 0;
+ if ( ascending ) {
+ for ( i = 0; i < (int)count(); ++i ) {
+ item = items[ i ].item;
+ if ( item ) {
+ item->p = prev;
+ item->dirty = TRUE;
+ if ( item->p )
+ item->p->n = item;
+ item->n = 0;
+ }
+ if ( i == 0 )
+ d->head = item;
+ prev = item;
+ }
+ } else {
+ for ( i = (int)count() - 1; i >= 0 ; --i ) {
+ item = items[ i ].item;
+ if ( item ) {
+ item->p = prev;
+ item->dirty = TRUE;
+ if ( item->p )
+ item->p->n = item;
+ item->n = 0;
+ }
+ if ( i == (int)count() - 1 )
+ d->head = item;
+ prev = item;
+ }
+ }
+ d->last = item;
+
+ delete [] items;
+
+ // We have to update explicitly in case the current "vieport" overlaps the
+ // new viewport we set (starting at (0,0)).
+ bool haveToUpdate = contentsX() < visibleWidth() || contentsY() < visibleHeight();
+ setContentsPos( 0, 0 );
+ if ( haveToUpdate )
+ updateContents( 0, 0, visibleWidth(), visibleHeight() );
+}
+
+void QListBox::handleItemChange( QListBoxItem *old, bool shift, bool control )
+{
+ if ( d->selectionMode == Single ) {
+ // nothing
+ } else if ( d->selectionMode == Extended ) {
+ if ( shift ) {
+ selectRange( d->selectAnchor ? d->selectAnchor : old,
+ d->current, FALSE, TRUE, (d->selectAnchor && !control) ? TRUE : FALSE );
+ } else if ( !control ) {
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ selectAll( FALSE );
+ blockSignals( block );
+ setSelected( d->current, TRUE );
+ }
+ } else if ( d->selectionMode == Multi ) {
+ if ( shift )
+ selectRange( old, d->current, TRUE, FALSE );
+ }
+}
+
+void QListBox::selectRange( QListBoxItem *from, QListBoxItem *to, bool invert, bool includeFirst, bool clearSel )
+{
+ if ( !from || !to )
+ return;
+ if ( from == to && !includeFirst )
+ return;
+ QListBoxItem *i = 0;
+ int index =0;
+ int f_idx = -1, t_idx = -1;
+ for ( i = d->head; i; i = i->n, index++ ) {
+ if ( i == from )
+ f_idx = index;
+ if ( i == to )
+ t_idx = index;
+ if ( f_idx != -1 && t_idx != -1 )
+ break;
+ }
+ if ( f_idx > t_idx ) {
+ i = from;
+ from = to;
+ to = i;
+ if ( !includeFirst )
+ to = to->prev();
+ } else {
+ if ( !includeFirst )
+ from = from->next();
+ }
+
+ bool changed = FALSE;
+ if ( clearSel ) {
+ for ( i = d->head; i && i != from; i = i->n ) {
+ if ( i->s ) {
+ i->s = FALSE;
+ changed = TRUE;
+ updateItem( i );
+ }
+ }
+ for ( i = to->n; i; i = i->n ) {
+ if ( i->s ) {
+ i->s = FALSE;
+ changed = TRUE;
+ updateItem( i );
+ }
+ }
+ }
+
+ for ( i = from; i; i = i->next() ) {
+ if ( !invert ) {
+ if ( !i->s && i->isSelectable() ) {
+ i->s = TRUE;
+ changed = TRUE;
+ updateItem( i );
+ }
+ } else {
+ bool sel = !i->s;
+ if ( (bool)i->s != sel && sel && i->isSelectable() || !sel ) {
+ i->s = sel;
+ changed = TRUE;
+ updateItem( i );
+ }
+ }
+ if ( i == to )
+ break;
+ }
+ if ( changed ) {
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+#endif
+ }
+}
+
+/*! \reimp */
+void QListBox::windowActivationChange( bool oldActive )
+{
+ if ( oldActive && d->scrollTimer )
+ d->scrollTimer->stop();
+ if ( palette().active() != palette().inactive() )
+ viewport()->update();
+ QScrollView::windowActivationChange( oldActive );
+}
+
+int QListBoxItem::RTTI = 0;
+
+/*!
+ Returns 0.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between listbox items. You should use values
+ greater than 1000 preferably a large random number, to allow for
+ extensions to this class.
+*/
+
+int QListBoxItem::rtti() const
+{
+ return RTTI;
+}
+
+#endif // QT_NO_LISTBOX
diff --git a/src/widgets/qlistbox.h b/src/widgets/qlistbox.h
new file mode 100644
index 0000000..2dd2109
--- /dev/null
+++ b/src/widgets/qlistbox.h
@@ -0,0 +1,435 @@
+/**********************************************************************
+**
+** Definition of QListBox widget class
+**
+** Created : 941121
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QLISTBOX_H
+#define QLISTBOX_H
+
+#ifndef QT_H
+#include "qscrollview.h"
+#include "qpixmap.h"
+#endif // QT_H
+
+#ifndef QT_NO_LISTBOX
+
+
+class QListBoxPrivate;
+class QListBoxItem;
+class QString;
+class QStrList;
+class QStringList;
+
+
+class Q_EXPORT QListBox : public QScrollView
+{
+ friend class QListBoxItem;
+ friend class QListBoxPrivate;
+
+ Q_OBJECT
+ Q_ENUMS( SelectionMode LayoutMode )
+ Q_PROPERTY( uint count READ count )
+ Q_PROPERTY( int numItemsVisible READ numItemsVisible )
+ Q_PROPERTY( int currentItem READ currentItem WRITE setCurrentItem )
+ Q_PROPERTY( QString currentText READ currentText )
+ Q_PROPERTY( int topItem READ topItem WRITE setTopItem DESIGNABLE false )
+ Q_PROPERTY( SelectionMode selectionMode READ selectionMode WRITE setSelectionMode )
+ Q_PROPERTY( bool multiSelection READ isMultiSelection WRITE setMultiSelection DESIGNABLE false )
+ Q_PROPERTY( LayoutMode columnMode READ columnMode WRITE setColumnMode )
+ Q_PROPERTY( LayoutMode rowMode READ rowMode WRITE setRowMode )
+ Q_PROPERTY( int numColumns READ numColumns )
+ Q_PROPERTY( int numRows READ numRows )
+ Q_PROPERTY( bool variableWidth READ variableWidth WRITE setVariableWidth )
+ Q_PROPERTY( bool variableHeight READ variableHeight WRITE setVariableHeight )
+
+public:
+ QListBox( QWidget* parent=0, const char* name=0, WFlags f=0 );
+ ~QListBox();
+
+ virtual void setFont( const QFont & );
+
+ uint count() const;
+
+ void insertStringList( const QStringList&, int index=-1 );
+ void insertStrList( const QStrList *, int index=-1 );
+ void insertStrList( const QStrList &, int index=-1 );
+ void insertStrList( const char **,
+ int numStrings=-1, int index=-1 );
+
+ void insertItem( const QListBoxItem *, int index=-1 );
+ void insertItem( const QListBoxItem *, const QListBoxItem *after );
+ void insertItem( const QString &text, int index=-1 );
+ void insertItem( const QPixmap &pixmap, int index=-1 );
+ void insertItem( const QPixmap &pixmap, const QString &text, int index=-1 );
+
+ void removeItem( int index );
+
+ QString text( int index ) const;
+ const QPixmap *pixmap( int index ) const;
+
+ void changeItem( const QListBoxItem *, int index );
+ void changeItem( const QString &text, int index );
+ void changeItem( const QPixmap &pixmap, int index );
+ void changeItem( const QPixmap &pixmap, const QString &text, int index );
+
+ void takeItem( const QListBoxItem * );
+
+ int numItemsVisible() const;
+
+ int currentItem() const;
+ QString currentText() const { return text(currentItem()); }
+ virtual void setCurrentItem( int index );
+ virtual void setCurrentItem( QListBoxItem * );
+ void centerCurrentItem() { ensureCurrentVisible(); }
+ int topItem() const;
+ virtual void setTopItem( int index );
+ virtual void setBottomItem( int index );
+
+ long maxItemWidth() const;
+
+ enum SelectionMode { Single, Multi, Extended, NoSelection };
+ virtual void setSelectionMode( SelectionMode );
+ SelectionMode selectionMode() const;
+
+ void setMultiSelection( bool multi );
+ bool isMultiSelection() const;
+
+ virtual void setSelected( QListBoxItem *, bool );
+ void setSelected( int, bool );
+ bool isSelected( int ) const;
+ bool isSelected( const QListBoxItem * ) const;
+ QListBoxItem* selectedItem() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ QListBoxItem *item( int index ) const;
+ int index( const QListBoxItem * ) const;
+ QListBoxItem *findItem( const QString &text, ComparisonFlags compare = BeginsWith ) const;
+
+ void triggerUpdate( bool doLayout );
+
+ bool itemVisible( int index );
+ bool itemVisible( const QListBoxItem * );
+
+ enum LayoutMode { FixedNumber,
+ FitToWidth, FitToHeight = FitToWidth,
+ Variable };
+ virtual void setColumnMode( LayoutMode );
+ virtual void setColumnMode( int );
+ virtual void setRowMode( LayoutMode );
+ virtual void setRowMode( int );
+
+ LayoutMode columnMode() const;
+ LayoutMode rowMode() const;
+
+ int numColumns() const;
+ int numRows() const;
+
+ bool variableWidth() const;
+ virtual void setVariableWidth( bool );
+
+ bool variableHeight() const;
+ virtual void setVariableHeight( bool );
+
+ void viewportPaintEvent( QPaintEvent * );
+
+#ifndef QT_NO_COMPAT
+ bool dragSelect() const { return TRUE; }
+ void setDragSelect( bool ) {}
+ bool autoScroll() const { return TRUE; }
+ void setAutoScroll( bool ) {}
+ bool autoScrollBar() const { return vScrollBarMode() == Auto; }
+ void setAutoScrollBar( bool enable ) { setVScrollBarMode( enable ? Auto : AlwaysOff ); }
+ bool scrollBar() const { return vScrollBarMode() != AlwaysOff; }
+ void setScrollBar( bool enable ) { setVScrollBarMode( enable ? AlwaysOn : AlwaysOff ); }
+ bool autoBottomScrollBar() const { return hScrollBarMode() == Auto; }
+ void setAutoBottomScrollBar( bool enable ) { setHScrollBarMode( enable ? Auto : AlwaysOff ); }
+ bool bottomScrollBar() const { return hScrollBarMode() != AlwaysOff; }
+ void setBottomScrollBar( bool enable ) { setHScrollBarMode( enable ? AlwaysOn : AlwaysOff ); }
+ bool smoothScrolling() const { return FALSE; }
+ void setSmoothScrolling( bool ) {}
+ bool autoUpdate() const { return TRUE; }
+ void setAutoUpdate( bool ) {}
+ void setFixedVisibleLines( int lines ) { setRowMode( lines ); }
+ int inSort( const QListBoxItem * );
+ int inSort( const QString& text );
+ int cellHeight( int i ) const { return itemHeight(i); }
+ int cellHeight() const { return itemHeight(); }
+ int cellWidth() const { return maxItemWidth(); }
+ int cellWidth(int i) const { Q_ASSERT(i==0); Q_UNUSED(i) return maxItemWidth(); }
+ int numCols() const { return numColumns(); }
+#endif
+
+ int itemHeight( int index = 0 ) const;
+ QListBoxItem * itemAt( const QPoint & ) const;
+
+ QRect itemRect( QListBoxItem *item ) const;
+
+ QListBoxItem *firstItem() const;
+
+ void sort( bool ascending = TRUE );
+
+public slots:
+ void clear();
+ virtual void ensureCurrentVisible();
+ virtual void clearSelection();
+ virtual void selectAll( bool select );
+ virtual void invertSelection();
+
+signals:
+ void highlighted( int index );
+ void selected( int index );
+ void highlighted( const QString &);
+ void selected( const QString &);
+ void highlighted( QListBoxItem * );
+ void selected( QListBoxItem * );
+
+ void selectionChanged();
+ void selectionChanged( QListBoxItem * );
+ void currentChanged( QListBoxItem * );
+ void clicked( QListBoxItem * );
+ void clicked( QListBoxItem *, const QPoint & );
+ void pressed( QListBoxItem * );
+ void pressed( QListBoxItem *, const QPoint & );
+
+ void doubleClicked( QListBoxItem * );
+ void returnPressed( QListBoxItem * );
+ void rightButtonClicked( QListBoxItem *, const QPoint & );
+ void rightButtonPressed( QListBoxItem *, const QPoint & );
+ void mouseButtonPressed( int, QListBoxItem*, const QPoint& );
+ void mouseButtonClicked( int, QListBoxItem*, const QPoint& );
+
+ void contextMenuRequested( QListBoxItem *, const QPoint & );
+
+ void onItem( QListBoxItem *item );
+ void onViewport();
+
+protected:
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void contentsContextMenuEvent( QContextMenuEvent * );
+
+ void keyPressEvent( QKeyEvent *e );
+ void focusInEvent( QFocusEvent *e );
+ void focusOutEvent( QFocusEvent *e );
+ void resizeEvent( QResizeEvent * );
+ void showEvent( QShowEvent * );
+
+ bool eventFilter( QObject *o, QEvent *e );
+
+ void updateItem( int index );
+ void updateItem( QListBoxItem * );
+
+#ifndef QT_NO_COMPAT
+ void updateCellWidth() { }
+ int totalWidth() const { return contentsWidth(); }
+ int totalHeight() const { return contentsHeight(); }
+#endif
+
+ virtual void paintCell( QPainter *, int row, int col );
+
+ void toggleCurrentItem();
+ bool isRubberSelecting() const;
+
+ void doLayout() const;
+
+ void windowActivationChange( bool );
+
+#ifndef QT_NO_COMPAT
+ bool itemYPos( int index, int *yPos ) const;
+ int findItem( int yPos ) const { return index(itemAt(QPoint(0,yPos)) ); }
+#endif
+
+protected slots:
+ void clearInputString();
+
+private slots:
+ void refreshSlot();
+ void doAutoScroll();
+ void adjustItems();
+
+private:
+ void mousePressEventEx( QMouseEvent * );
+ void tryGeometry( int, int ) const;
+ int currentRow() const;
+ int currentColumn() const;
+ void updateSelection();
+ void repaintSelection();
+ void drawRubber();
+ void doRubberSelection( const QRect &old, const QRect &rubber );
+ void handleItemChange( QListBoxItem *old, bool shift, bool control );
+ void selectRange( QListBoxItem *from, QListBoxItem *to, bool invert, bool includeFirst, bool clearSel = FALSE );
+
+ void emitChangedSignal( bool );
+
+ int columnAt( int ) const;
+ int rowAt( int ) const;
+
+ QListBoxPrivate * d;
+
+ static QListBox * changedListBox;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QListBox( const QListBox & );
+ QListBox &operator=( const QListBox & );
+#endif
+};
+
+
+class Q_EXPORT QListBoxItem
+{
+public:
+ QListBoxItem( QListBox* listbox = 0 );
+ QListBoxItem( QListBox* listbox, QListBoxItem *after );
+ virtual ~QListBoxItem();
+
+ virtual QString text() const;
+ virtual const QPixmap *pixmap() const;
+
+ virtual int height( const QListBox * ) const;
+ virtual int width( const QListBox * ) const;
+
+ bool isSelected() const { return s; }
+ bool isCurrent() const;
+
+#ifndef QT_NO_COMPAT
+ bool selected() const { return isSelected(); }
+ bool current() const { return isCurrent(); }
+#endif
+
+ QListBox *listBox() const;
+
+ void setSelectable( bool b );
+ bool isSelectable() const;
+
+ QListBoxItem *next() const;
+ QListBoxItem *prev() const;
+
+ virtual int rtti() const;
+ static int RTTI;
+
+protected:
+ virtual void paint( QPainter * ) = 0;
+ virtual void setText( const QString &text ) { txt = text; }
+ void setCustomHighlighting( bool );
+
+private:
+ QString txt;
+ uint s:1;
+ uint dirty:1;
+ uint custom_highlight : 1;
+ int x, y;
+ QListBoxItem * p, * n;
+ QListBox* lbox;
+ friend class QListBox;
+ friend class QListBoxPrivate;
+ friend class QComboBox;
+ friend class QComboBoxPopupItem;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QListBoxItem( const QListBoxItem & );
+ QListBoxItem &operator=( const QListBoxItem & );
+#endif
+};
+
+
+class Q_EXPORT QListBoxText : public QListBoxItem
+{
+public:
+ QListBoxText( QListBox* listbox, const QString & text=QString::null );
+ QListBoxText( const QString & text=QString::null );
+ QListBoxText( QListBox* listbox, const QString & text, QListBoxItem *after );
+ ~QListBoxText();
+
+ int height( const QListBox * ) const;
+ int width( const QListBox * ) const;
+
+ int rtti() const;
+ static int RTTI;
+
+protected:
+ void paint( QPainter * );
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QListBoxText( const QListBoxText & );
+ QListBoxText &operator=( const QListBoxText & );
+#endif
+};
+
+
+class Q_EXPORT QListBoxPixmap : public QListBoxItem
+{
+public:
+ QListBoxPixmap( QListBox* listbox, const QPixmap & );
+ QListBoxPixmap( const QPixmap & );
+ QListBoxPixmap( QListBox* listbox, const QPixmap & pix, QListBoxItem *after );
+ QListBoxPixmap( QListBox* listbox, const QPixmap &, const QString& );
+ QListBoxPixmap( const QPixmap &, const QString& );
+ QListBoxPixmap( QListBox* listbox, const QPixmap & pix, const QString&, QListBoxItem *after );
+ ~QListBoxPixmap();
+
+ const QPixmap *pixmap() const { return &pm; }
+
+ int height( const QListBox * ) const;
+ int width( const QListBox * ) const;
+
+ int rtti() const;
+ static int RTTI;
+
+protected:
+ void paint( QPainter * );
+
+private:
+ QPixmap pm;
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QListBoxPixmap( const QListBoxPixmap & );
+ QListBoxPixmap &operator=( const QListBoxPixmap & );
+#endif
+};
+
+
+#endif // QT_NO_LISTBOX
+
+#endif // QLISTBOX_H
diff --git a/src/widgets/qlistview.cpp b/src/widgets/qlistview.cpp
new file mode 100644
index 0000000..d441a59
--- /dev/null
+++ b/src/widgets/qlistview.cpp
@@ -0,0 +1,8174 @@
+/****************************************************************************
+**
+** Implementation of QListView widget class
+**
+** Created : 970809
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qlistview.h"
+#ifndef QT_NO_LISTVIEW
+#include "qtimer.h"
+#include "qheader.h"
+#include "qpainter.h"
+#include "qcursor.h"
+#include "qptrstack.h"
+#include "qptrlist.h"
+#include "qstrlist.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdatetime.h"
+#include "qptrdict.h"
+#include "qptrvector.h"
+#include "qiconset.h"
+#include "qcleanuphandler.h"
+#include "qpixmapcache.h"
+#include "qpopupmenu.h"
+#include "qtl.h"
+#include "qdragobject.h"
+#include "qlineedit.h"
+#include "qvbox.h"
+#include "qtooltip.h"
+#include "qstyle.h"
+#include "qstylesheet.h"
+#include "../kernel/qinternal_p.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+const int Unsorted = 16383;
+
+static QCleanupHandler<QBitmap> qlv_cleanup_bitmap;
+
+struct QListViewItemIteratorPrivate
+{
+ QListViewItemIteratorPrivate( uint f ) : flags( f )
+ {
+ // nothing yet
+ }
+
+ uint flags;
+};
+
+static QPtrDict<QListViewItemIteratorPrivate> *qt_iteratorprivate_dict = 0;
+
+struct QListViewPrivate
+{
+ // classes that are here to avoid polluting the global name space
+
+ // the magical hidden mother of all items
+ class Root: public QListViewItem {
+ public:
+ Root( QListView * parent );
+
+ void setHeight( int );
+ void invalidateHeight();
+ void setup();
+ QListView * theListView() const;
+
+ QListView * lv;
+ };
+
+ // for the stack used in drawContentsOffset()
+ class Pending {
+ public:
+ Pending( int level, int ypos, QListViewItem * item)
+ : l(level), y(ypos), i(item) {};
+
+ int l; // level of this item; root is -1 or 0
+ int y; // level of this item in the tree
+ QListViewItem * i; // the item itself
+ };
+
+ // to remember what's on screen
+ class DrawableItem {
+ public:
+ DrawableItem( Pending * pi ) { y = pi->y; l = pi->l; i = pi->i; };
+ int y;
+ int l;
+ QListViewItem * i;
+ };
+
+ // for sorting
+ class SortableItem {
+ public:
+ /*
+ We could be smarter and keep a pointer to the QListView
+ item instead of numCols, col and asc. This would then allow
+ us to use the physical ordering of columns rather than the
+ logical. Microsoft uses the logical ordering, so there is
+ some virtue in doing so, although it prevents the user from
+ chosing the secondary key.
+ */
+ QListViewItem * item;
+ int numCols;
+ int col;
+ bool asc;
+
+ int cmp( const SortableItem& i ) const {
+ int diff = item->compare( i.item, col, asc );
+ if ( diff == 0 && numCols != 1 ) {
+ for ( int j = 0; j < numCols; j++ ) {
+ if ( j != col ) {
+ diff = item->compare( i.item, j, asc );
+ if ( diff != 0 )
+ break;
+ }
+ }
+ }
+ return diff;
+ }
+ bool operator<( const SortableItem& i ) const { return cmp( i ) < 0; }
+ bool operator<=( const SortableItem& i ) const { return cmp( i ) <= 0; }
+ bool operator>( const SortableItem& i ) const { return cmp( i ) > 0; }
+ };
+
+ class ItemColumnInfo {
+ public:
+ ItemColumnInfo(): pm( 0 ), next( 0 ), truncated( FALSE ), dirty( FALSE ), allow_rename( FALSE ), width( 0 ) {}
+ ~ItemColumnInfo() { delete pm; delete next; }
+ QString text, tmpText;
+ QPixmap * pm;
+ ItemColumnInfo * next;
+ uint truncated : 1;
+ uint dirty : 1;
+ uint allow_rename : 1;
+ int width;
+ };
+
+ class ViewColumnInfo {
+ public:
+ ViewColumnInfo(): align(Qt::AlignAuto), sortable(TRUE), next( 0 ) {}
+ ~ViewColumnInfo() { delete next; }
+ int align;
+ bool sortable;
+ ViewColumnInfo * next;
+ };
+
+ // private variables used in QListView
+ ViewColumnInfo * vci;
+ QHeader * h;
+ Root * r;
+ uint rootIsExpandable : 1;
+ int margin;
+
+ QListViewItem * focusItem, *highlighted, *oldFocusItem;
+
+ QTimer * timer;
+ QTimer * dirtyItemTimer;
+ QTimer * visibleTimer;
+ int levelWidth;
+
+ // the list of drawables, and the range drawables covers entirely
+ // (it may also include a few items above topPixel)
+ QPtrList<DrawableItem> * drawables;
+ int topPixel;
+ int bottomPixel;
+
+ QPtrDict<void> * dirtyItems;
+
+ QListView::SelectionMode selectionMode;
+
+ // Per-column structure for information not in the QHeader
+ struct Column {
+ QListView::WidthMode wmode;
+ };
+ QPtrVector<Column> column;
+
+ // suggested height for the items
+ int fontMetricsHeight;
+ int minLeftBearing, minRightBearing;
+ int ellipsisWidth;
+
+ // currently typed prefix for the keyboard interface, and the time
+ // of the last key-press
+ QString currentPrefix;
+ QTime currentPrefixTime;
+
+ // holds a list of iterators
+ QPtrList<QListViewItemIterator> *iterators;
+ QListViewItem *pressedItem, *selectAnchor;
+
+ QTimer *scrollTimer;
+ QTimer *renameTimer;
+ QTimer *autoopenTimer;
+
+ // sort column and order #### may need to move to QHeader [subclass]
+ int sortcolumn;
+ bool ascending :1;
+ bool sortIndicator :1;
+ // whether to select or deselect during this mouse press.
+ bool allColumnsShowFocus :1;
+ bool select :1;
+
+ // TRUE if the widget should take notice of mouseReleaseEvent
+ bool buttonDown :1;
+ // TRUE if the widget should ignore a double-click
+ bool ignoreDoubleClick :1;
+
+ bool clearing :1;
+ bool pressedSelected :1;
+ bool pressedEmptyArea :1;
+
+ bool useDoubleBuffer :1;
+ bool toolTips :1;
+ bool fullRepaintOnComlumnChange:1;
+ bool updateHeader :1;
+
+ bool startEdit : 1;
+ bool ignoreEditAfterFocus : 1;
+ bool inMenuMode :1;
+
+ QListView::RenameAction defRenameAction;
+
+ QListViewItem *startDragItem;
+ QPoint dragStartPos;
+ QListViewToolTip *toolTip;
+ int pressedColumn;
+ QListView::ResizeMode resizeMode;
+};
+
+#ifndef QT_NO_TOOLTIP
+class QListViewToolTip : public QToolTip
+{
+public:
+ QListViewToolTip( QWidget *parent, QListView *lv );
+
+ void maybeTip( const QPoint &pos );
+
+private:
+ QListView *view;
+
+};
+
+QListViewToolTip::QListViewToolTip( QWidget *parent, QListView *lv )
+ : QToolTip( parent ), view( lv )
+{
+}
+
+void QListViewToolTip::maybeTip( const QPoint &pos )
+{
+ if ( !parentWidget() || !view || !view->showToolTips() )
+ return;
+
+ QListViewItem *item = view->itemAt( pos );
+ QPoint contentsPos = view->viewportToContents( pos );
+ if ( !item || !item->columns )
+ return;
+ int col = view->header()->sectionAt( contentsPos.x() );
+ QListViewPrivate::ItemColumnInfo *ci = (QListViewPrivate::ItemColumnInfo*)item->columns;
+ for ( int i = 0; ci && ( i < col ); ++i )
+ ci = ci->next;
+
+ if ( !ci || !ci->truncated )
+ return;
+
+ QRect r = view->itemRect( item );
+ int headerPos = view->header()->sectionPos( col );
+ r.setLeft( headerPos );
+ r.setRight( headerPos + view->header()->sectionSize( col ) );
+ tip( r, QStyleSheet::escape(item->text( col ) ) );
+}
+#endif
+
+// these should probably be in QListViewPrivate, for future thread safety
+static bool activatedByClick;
+
+// Holds the position of activation. The position is relative to the top left corner in the row minus the root decoration and its branches/depth.
+// Used to track the point clicked for CheckBoxes and RadioButtons.
+static QPoint activatedP;
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+static int indexOfItem( QListViewItem *item )
+{
+ if ( !QAccessible::isActive() )
+ return 0;
+
+ static QListViewItem *lastItem = 0;
+ static int lastIndex = 0;
+
+ if ( !item || !item->listView() )
+ return 0;
+
+ if ( item == lastItem )
+ return lastIndex;
+
+ lastItem = item;
+ int index = 1;
+
+ QListViewItemIterator it( item->listView() );
+ while ( it.current() ) {
+ if ( it.current() == item ) {
+ lastIndex = index;
+ return index;
+ }
+ ++it;
+ ++index;
+ }
+ lastIndex = 0;
+ return 0;
+}
+#endif
+
+/*!
+ \internal
+ Creates a string with ... like "Trollte..." or "...olltech" depending on the alignment
+*/
+
+static QString qEllipsisText( const QString &org, const QFontMetrics &fm, int width, int align )
+{
+ int ellWidth = fm.width( "..." );
+ QString text = QString::fromLatin1("");
+ int i = 0;
+ int len = org.length();
+ int offset = (align & Qt::AlignRight) ? (len-1) - i : i;
+ while ( i < len && fm.width( text + org[ offset ] ) + ellWidth < width ) {
+ if ( align & Qt::AlignRight )
+ text.prepend( org[ offset ] );
+ else
+ text += org[ offset ];
+ offset = (align & Qt::AlignRight) ? (len-1) - ++i : ++i;
+ }
+ if ( text.isEmpty() )
+ text = ( align & Qt::AlignRight ) ? org.right( 1 ) : text = org.left( 1 );
+ if ( align & Qt::AlignRight )
+ text.prepend( "..." );
+ else
+ text += "...";
+ return text;
+}
+
+/*!
+ \class QListViewItem
+ \brief The QListViewItem class implements a list view item.
+
+ \ingroup advanced
+
+ A list view item is a multi-column object capable of displaying
+ itself in a QListView.
+
+ The easiest way to use QListViewItem is to construct one with a
+ few constant strings, and either a QListView or another
+ QListViewItem as parent.
+ \code
+ (void) new QListViewItem( listView, "Column 1", "Column 2" );
+ (void) new QListViewItem( listView->firstChild(), "A", "B", "C" );
+ \endcode
+ We've discarded the pointers to the items since we can still access
+ them via their parent \e listView. By default, QListView sorts its
+ items; this can be switched off with QListView::setSorting(-1).
+
+ The parent must be another QListViewItem or a QListView. If the
+ parent is a QListView, the item becomes a top-level item within
+ that QListView. If the parent is another QListViewItem, the item
+ becomes a child of that list view item.
+
+ If you keep the pointer, you can set or change the texts using
+ setText(), add pixmaps using setPixmap(), change its mode using
+ setSelectable(), setSelected(), setOpen() and setExpandable().
+ You'll also be able to change its height using setHeight(), and
+ traverse its sub-items. You don't have to keep the pointer since
+ you can get a pointer to any QListViewItem in a QListView using
+ QListView::selectedItem(), QListView::currentItem(),
+ QListView::firstChild(), QListView::lastItem() and
+ QListView::findItem().
+
+ If you call \c delete on a list view item, it will be deleted as
+ expected, and as usual for \l{QObject}s, if it has any child items
+ (to any depth), all these will be deleted too.
+
+ \l{QCheckListItem}s are list view items that have a checkbox or
+ radio button and can be used in place of plain QListViewItems.
+
+ You can traverse the tree as if it were a doubly-linked list using
+ itemAbove() and itemBelow(); they return pointers to the items
+ directly above and below this item on the screen (even if none of
+ them are actually visible at the moment).
+
+ Here's how to traverse all of an item's children (but not its
+ children's children, etc.):
+ Example:
+ \code
+ QListViewItem * myChild = myItem->firstChild();
+ while( myChild ) {
+ doSomething( myChild );
+ myChild = myChild->nextSibling();
+ }
+ \endcode
+
+ If you want to iterate over every item, to any level of depth use
+ an iterator. To iterate over the entire tree, initialize the
+ iterator with the list view itself; to iterate starting from a
+ particular item, initialize the iterator with the item:
+
+ \code
+ QListViewItemIterator it( listview );
+ while ( it.current() ) {
+ QListViewItem *item = it.current();
+ doSomething( item );
+ ++it;
+ }
+ \endcode
+
+ Note that the order of the children will change when the sorting
+ order changes and is undefined if the items are not visible. You
+ can, however, call enforceSortOrder() at any time; QListView will
+ always call it before it needs to show an item.
+
+ Many programs will need to reimplement QListViewItem. The most
+ commonly reimplemented functions are:
+ \table
+ \header \i Function \i Description
+ \row \i \l text()
+ \i Returns the text in a column. Many subclasses will compute
+ this on the fly.
+ \row \i \l key()
+ \i Used for sorting. The default key() simply calls
+ text(), but judicious use of key() can give you fine
+ control over sorting; for example, QFileDialog
+ reimplements key() to sort by date.
+ \row \i \l setup()
+ \i Called before showing the item and whenever the list
+ view's font changes, for example.
+ \row \i \l activate()
+ \i Called whenever the user clicks on the item or presses
+ Space when the item is the current item.
+ \endtable
+
+ Some subclasses call setExpandable(TRUE) even when they have no
+ children, and populate themselves when setup() or setOpen(TRUE) is
+ called. The \c dirview/dirview.cpp example program uses this
+ technique to start up quickly: The files and subdirectories in a
+ directory aren't inserted into the tree until they're actually
+ needed.
+
+ \img qlistviewitems.png List View Items
+
+ \sa QCheckListItem QListView
+*/
+
+/*!
+ \fn int QCheckListItem::rtti() const
+
+ Returns 1.
+
+ Make your derived classes return their own values for rtti(), and
+ you can distinguish between list view items. You should use values
+ greater than 1000, to allow for extensions to this class.
+*/
+
+/*!
+ Constructs a new top-level list view item in the QListView \a
+ parent.
+*/
+
+QListViewItem::QListViewItem( QListView * parent )
+{
+ init();
+ parent->insertItem( this );
+}
+
+
+/*!
+ Constructs a new list view item that is a child of \a parent and
+ first in the parent's list of children.
+*/
+
+QListViewItem::QListViewItem( QListViewItem * parent )
+{
+ init();
+ parent->insertItem( this );
+}
+
+
+
+
+/*!
+ Constructs an empty list view item that is a child of \a parent
+ and is after item \a after in the parent's list of children. Since
+ \a parent is a QListView the item will be a top-level item.
+*/
+
+QListViewItem::QListViewItem( QListView * parent, QListViewItem * after )
+{
+ init();
+ parent->insertItem( this );
+ moveToJustAfter( after );
+}
+
+
+/*!
+ Constructs an empty list view item that is a child of \a parent
+ and is after item \a after in the parent's list of children.
+*/
+
+QListViewItem::QListViewItem( QListViewItem * parent, QListViewItem * after )
+{
+ init();
+ parent->insertItem( this );
+ moveToJustAfter( after );
+}
+
+
+
+/*!
+ Constructs a new top-level list view item in the QListView \a
+ parent, with up to eight constant strings, \a label1, \a label2, \a
+ label3, \a label4, \a label5, \a label6, \a label7 and \a label8
+ defining its columns' contents.
+
+ \sa setText()
+*/
+
+QListViewItem::QListViewItem( QListView * parent,
+ QString label1,
+ QString label2,
+ QString label3,
+ QString label4,
+ QString label5,
+ QString label6,
+ QString label7,
+ QString label8 )
+{
+ init();
+ parent->insertItem( this );
+
+ setText( 0, label1 );
+ setText( 1, label2 );
+ setText( 2, label3 );
+ setText( 3, label4 );
+ setText( 4, label5 );
+ setText( 5, label6 );
+ setText( 6, label7 );
+ setText( 7, label8 );
+}
+
+
+/*!
+ Constructs a new list view item as a child of the QListViewItem \a
+ parent with up to eight constant strings, \a label1, \a label2, \a
+ label3, \a label4, \a label5, \a label6, \a label7 and \a label8
+ as columns' contents.
+
+ \sa setText()
+*/
+
+QListViewItem::QListViewItem( QListViewItem * parent,
+ QString label1,
+ QString label2,
+ QString label3,
+ QString label4,
+ QString label5,
+ QString label6,
+ QString label7,
+ QString label8 )
+{
+ init();
+ parent->insertItem( this );
+
+ setText( 0, label1 );
+ setText( 1, label2 );
+ setText( 2, label3 );
+ setText( 3, label4 );
+ setText( 4, label5 );
+ setText( 5, label6 );
+ setText( 6, label7 );
+ setText( 7, label8 );
+}
+
+/*!
+ Constructs a new list view item in the QListView \a parent that is
+ included after item \a after and that has up to eight column
+ texts, \a label1, \a label2, \a label3, \a label4, \a label5, \a
+ label6, \a label7 and\a label8.
+
+ Note that the order is changed according to QListViewItem::key()
+ unless the list view's sorting is disabled using
+ QListView::setSorting(-1).
+
+ \sa setText()
+*/
+
+QListViewItem::QListViewItem( QListView * parent, QListViewItem * after,
+ QString label1,
+ QString label2,
+ QString label3,
+ QString label4,
+ QString label5,
+ QString label6,
+ QString label7,
+ QString label8 )
+{
+ init();
+ parent->insertItem( this );
+ moveToJustAfter( after );
+
+ setText( 0, label1 );
+ setText( 1, label2 );
+ setText( 2, label3 );
+ setText( 3, label4 );
+ setText( 4, label5 );
+ setText( 5, label6 );
+ setText( 6, label7 );
+ setText( 7, label8 );
+}
+
+
+/*!
+ Constructs a new list view item as a child of the QListViewItem \a
+ parent. It is inserted after item \a after and may contain up to
+ eight strings, \a label1, \a label2, \a label3, \a label4, \a
+ label5, \a label6, \a label7 and \a label8 as column entries.
+
+ Note that the order is changed according to QListViewItem::key()
+ unless the list view's sorting is disabled using
+ QListView::setSorting(-1).
+
+ \sa setText()
+*/
+
+QListViewItem::QListViewItem( QListViewItem * parent, QListViewItem * after,
+ QString label1,
+ QString label2,
+ QString label3,
+ QString label4,
+ QString label5,
+ QString label6,
+ QString label7,
+ QString label8 )
+{
+ init();
+ parent->insertItem( this );
+ moveToJustAfter( after );
+
+ setText( 0, label1 );
+ setText( 1, label2 );
+ setText( 2, label3 );
+ setText( 3, label4 );
+ setText( 4, label5 );
+ setText( 5, label6 );
+ setText( 6, label7 );
+ setText( 7, label8 );
+}
+
+/*!
+ Sorts all this item's child items using the current sorting
+ configuration (sort column and direction).
+
+ \sa enforceSortOrder()
+*/
+
+void QListViewItem::sort()
+{
+ if ( !listView() )
+ return;
+ lsc = Unsorted;
+ enforceSortOrder();
+ listView()->triggerUpdate();
+}
+
+int QListViewItem::RTTI = 0;
+
+/*!
+ Returns 0.
+
+ Make your derived classes return their own values for rtti(), so
+ that you can distinguish between different kinds of list view
+ items. You should use values greater than 1000 to allow for
+ extensions to this class.
+*/
+
+int QListViewItem::rtti() const
+{
+ return RTTI;
+}
+
+/*
+ Performs the initializations that's common to the constructors.
+*/
+
+void QListViewItem::init()
+{
+ ownHeight = 0;
+ maybeTotalHeight = -1;
+ open = FALSE;
+
+ nChildren = 0;
+ parentItem = 0;
+ siblingItem = childItem = 0;
+
+ columns = 0;
+
+ selected = 0;
+
+ lsc = Unsorted;
+ lso = TRUE; // unsorted in ascending order :)
+ configured = FALSE;
+ expandable = FALSE;
+ selectable = TRUE;
+ is_root = FALSE;
+ allow_drag = FALSE;
+ allow_drop = FALSE;
+ visible = TRUE;
+ renameBox = 0;
+ enabled = TRUE;
+ mlenabled = FALSE;
+}
+
+/*!
+ If \a b is TRUE, the item is made visible; otherwise it is hidden.
+
+ If the item is not visible, itemAbove() and itemBelow() will never
+ return this item, although you still can reach it by using e.g.
+ QListViewItemIterator.
+*/
+
+void QListViewItem::setVisible( bool b )
+{
+ if ( b == (bool)visible )
+ return;
+ QListView *lv = listView();
+ if ( !lv )
+ return;
+ if ( b && parent() && !parent()->isVisible() )
+ return;
+ visible = b;
+ configured = FALSE;
+ setHeight( 0 );
+ invalidateHeight();
+ if ( parent() )
+ parent()->invalidateHeight();
+ else
+ lv->d->r->invalidateHeight();
+ for ( QListViewItem *i = childItem; i; i = i->siblingItem )
+ i->setVisible( b );
+ if ( lv )
+ lv->triggerUpdate();
+}
+
+/*!
+ Returns TRUE if the item is visible; otherwise returns FALSE.
+
+ \sa setVisible()
+*/
+
+bool QListViewItem::isVisible() const
+{
+ return (bool)visible;
+}
+
+/*!
+ If \a b is TRUE, this item can be in-place renamed in the column
+ \a col by the user; otherwise it cannot be renamed in-place.
+*/
+
+void QListViewItem::setRenameEnabled( int col, bool b )
+{
+ QListViewPrivate::ItemColumnInfo * l = (QListViewPrivate::ItemColumnInfo*)columns;
+ if ( !l ) {
+ l = new QListViewPrivate::ItemColumnInfo;
+ columns = (void*)l;
+ }
+ for( int c = 0; c < col; c++ ) {
+ if ( !l->next )
+ l->next = new QListViewPrivate::ItemColumnInfo;
+ l = l->next;
+ }
+
+ if ( !l )
+ return;
+ l->allow_rename = b;
+}
+
+/*!
+ Returns TRUE if this item can be in-place renamed in column \a
+ col; otherwise returns FALSE.
+*/
+
+bool QListViewItem::renameEnabled( int col ) const
+{
+ QListViewPrivate::ItemColumnInfo * l = (QListViewPrivate::ItemColumnInfo*)columns;
+ if ( !l )
+ return FALSE;
+
+ while( col && l ) {
+ l = l->next;
+ col--;
+ }
+
+ if ( !l )
+ return FALSE;
+ return (bool)l->allow_rename;
+}
+
+/*!
+ If \a b is TRUE the item is enabled; otherwise it is disabled.
+ Disabled items are drawn differently (e.g. grayed-out) and are not
+ accessible by the user.
+*/
+
+void QListViewItem::setEnabled( bool b )
+{
+ if ( (bool)enabled == b )
+ return;
+ enabled = b;
+ if ( !enabled )
+ selected = FALSE;
+ QListView *lv = listView();
+ if ( lv ) {
+ lv->triggerUpdate();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( lv->viewport(), indexOfItem( this ), QAccessible::StateChanged );
+#endif
+ }
+}
+
+/*!
+ Returns TRUE if this item is enabled; otherwise returns FALSE.
+
+ \sa setEnabled()
+*/
+
+bool QListViewItem::isEnabled() const
+{
+ return (bool)enabled;
+}
+
+/*!
+ If in-place renaming of this item is enabled (see
+ renameEnabled()), this function starts renaming the item in column
+ \a col, by creating and initializing an edit box.
+*/
+
+void QListViewItem::startRename( int col )
+{
+ if ( !renameEnabled( col ) )
+ return;
+ if ( renameBox )
+ cancelRename( col );
+ QListView *lv = listView();
+ if ( !lv )
+ return;
+
+ if ( lv->d->renameTimer )
+ lv->d->renameTimer->stop();
+
+ lv->ensureItemVisible( this );
+
+ if ( lv->d->timer->isActive() ) {
+ // make sure that pending calculations get finished
+ lv->d->timer->stop();
+ lv->updateContents();
+ }
+
+ if ( lv->currentItem() && lv->currentItem()->renameBox ) {
+ if ( lv->d->defRenameAction == QListView::Reject )
+ lv->currentItem()->cancelRename( lv->currentItem()->renameCol );
+ else
+ lv->currentItem()->okRename( lv->currentItem()->renameCol );
+ }
+
+ if ( this != lv->currentItem() )
+ lv->setCurrentItem( this );
+
+ QRect r = lv->itemRect( this );
+ r = QRect( lv->viewportToContents( r.topLeft() ), r.size() );
+ r.setLeft( lv->header()->sectionPos( col ) );
+ r.setWidth(QMIN(lv->header()->sectionSize(col) - 1,
+ lv->contentsX() + lv->visibleWidth() - r.left()));
+ if ( col == 0 )
+ r.setLeft( r.left() + lv->itemMargin() + ( depth() + ( lv->rootIsDecorated() ? 1 : 0 ) ) * lv->treeStepSize() - 1 );
+ if ( pixmap( col ) )
+ r.setLeft( r.left() + pixmap( col )->width() );
+ if ( r.x() - lv->contentsX() < 0 ) {
+ lv->scrollBy( r.x() - lv->contentsX(), 0 );
+ r.setX( lv->contentsX() );
+ } else if ( ( lv->contentsX() + lv->visibleWidth() ) < ( r.x() + r.width() ) ) {
+ lv->scrollBy( ( r.x() + r.width() ) - ( lv->contentsX() + lv->visibleWidth() ), 0 );
+ }
+ if ( r.width() > lv->visibleWidth() )
+ r.setWidth( lv->visibleWidth() );
+ renameBox = new QLineEdit( lv->viewport(), "qt_renamebox" );
+ renameBox->setFrameStyle( QFrame::Box | QFrame::Plain );
+ renameBox->setLineWidth( 1 );
+ renameBox->setText( text( col ) );
+ renameBox->selectAll();
+ renameBox->installEventFilter( lv );
+ lv->addChild( renameBox, r.x(), r.y() );
+ renameBox->resize( r.size() );
+ lv->viewport()->setFocusProxy( renameBox );
+ renameBox->setFocus();
+ renameBox->show();
+ renameCol = col;
+}
+
+/*!
+ This function removes the rename box.
+*/
+
+void QListViewItem::removeRenameBox()
+{
+ // Sanity, it should be checked by the functions calling this first anyway
+ QListView *lv = listView();
+ if ( !lv || !renameBox )
+ return;
+ const bool resetFocus = lv->viewport()->focusProxy() == renameBox;
+ const bool renameBoxHadFocus = renameBox->hasFocus();
+ delete renameBox;
+ renameBox = 0;
+ if ( resetFocus )
+ lv->viewport()->setFocusProxy( lv );
+ if (renameBoxHadFocus)
+ lv->setFocus();
+}
+
+/*!
+ This function is called if the user presses Enter during in-place
+ renaming of the item in column \a col.
+
+ \sa cancelRename()
+*/
+
+void QListViewItem::okRename( int col )
+{
+ QListView *lv = listView();
+ if ( !lv || !renameBox )
+ return;
+ setText( col, renameBox->text() );
+ removeRenameBox();
+
+ // we set the parent lsc to Unsorted if that column is the sorted one
+ if ( parent() && (int)parent()->lsc == col )
+ parent()->lsc = Unsorted;
+
+ emit lv->itemRenamed( this, col );
+ emit lv->itemRenamed( this, col, text( col ) );
+}
+
+/*!
+ This function is called if the user cancels in-place renaming of
+ this item in column \a col (e.g. by pressing Esc).
+
+ \sa okRename()
+*/
+
+void QListViewItem::cancelRename( int )
+{
+ QListView *lv = listView();
+ if ( !lv || !renameBox )
+ return;
+ removeRenameBox();
+}
+
+/*!
+ Destroys the item, deleting all its children and freeing up all
+ allocated resources.
+*/
+
+QListViewItem::~QListViewItem()
+{
+ if ( renameBox ) {
+ delete renameBox;
+ renameBox = 0;
+ }
+
+ QListView *lv = listView();
+
+ if ( lv ) {
+ if ( lv->d->oldFocusItem == this )
+ lv->d->oldFocusItem = 0;
+ if ( lv->d->iterators ) {
+ QListViewItemIterator *i = lv->d->iterators->first();
+ while ( i ) {
+ if ( i->current() == this )
+ i->currentRemoved();
+ i = lv->d->iterators->next();
+ }
+ }
+ }
+
+ if ( parentItem )
+ parentItem->takeItem( this );
+ QListViewItem * i = childItem;
+ childItem = 0;
+ while ( i ) {
+ i->parentItem = 0;
+ QListViewItem * n = i->siblingItem;
+ delete i;
+ i = n;
+ }
+ delete (QListViewPrivate::ItemColumnInfo *)columns;
+}
+
+
+/*!
+ If \a b is TRUE each of the item's columns may contain multiple
+ lines of text; otherwise each of them may only contain a single
+ line.
+*/
+
+void QListViewItem::setMultiLinesEnabled( bool b )
+{
+ mlenabled = b;
+}
+
+/*!
+ Returns TRUE if the item can display multiple lines of text in its
+ columns; otherwise returns FALSE.
+*/
+
+bool QListViewItem::multiLinesEnabled() const
+{
+ return mlenabled;
+}
+
+/*!
+ If \a allow is TRUE, the list view starts a drag (see
+ QListView::dragObject()) when the user presses and moves the mouse
+ on this item.
+*/
+
+
+void QListViewItem::setDragEnabled( bool allow )
+{
+ allow_drag = (uint)allow;
+}
+
+/*!
+ If \a allow is TRUE, the list view accepts drops onto the item;
+ otherwise drops are not allowed.
+*/
+
+void QListViewItem::setDropEnabled( bool allow )
+{
+ allow_drop = (uint)allow;
+}
+
+/*!
+ Returns TRUE if this item can be dragged; otherwise returns FALSE.
+
+ \sa setDragEnabled()
+*/
+
+bool QListViewItem::dragEnabled() const
+{
+ return (bool)allow_drag;
+}
+
+/*!
+ Returns TRUE if this item accepts drops; otherwise returns FALSE.
+
+ \sa setDropEnabled(), acceptDrop()
+*/
+
+bool QListViewItem::dropEnabled() const
+{
+ return (bool)allow_drop;
+}
+
+/*!
+ Returns TRUE if the item can accept drops of type QMimeSource \a
+ mime; otherwise returns FALSE.
+
+ The default implementation does nothing and returns FALSE. A
+ subclass must reimplement this to accept drops.
+*/
+
+bool QListViewItem::acceptDrop( const QMimeSource * ) const
+{
+ return FALSE;
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ This function is called when something was dropped on the item. \a e
+ contains all the information about the drop.
+
+ The default implementation does nothing, subclasses may need to
+ reimplement this function.
+*/
+
+void QListViewItem::dropped( QDropEvent *e )
+{
+ Q_UNUSED( e );
+}
+
+#endif
+
+/*!
+ This function is called when a drag enters the item's bounding
+ rectangle.
+
+ The default implementation does nothing, subclasses may need to
+ reimplement this function.
+*/
+
+void QListViewItem::dragEntered()
+{
+}
+
+/*!
+ This function is called when a drag leaves the item's bounding
+ rectangle.
+
+ The default implementation does nothing, subclasses may need to
+ reimplement this function.
+*/
+
+void QListViewItem::dragLeft()
+{
+}
+
+/*!
+ Inserts \a newChild into this list view item's list of children.
+ You should not need to call this function; it is called
+ automatically by the constructor of \a newChild.
+
+ \warning If you are using \c Single selection mode, then you
+ should only insert unselected items.
+*/
+
+void QListViewItem::insertItem( QListViewItem * newChild )
+{
+ QListView *lv = listView();
+ if ( lv && lv->currentItem() && lv->currentItem()->renameBox ) {
+ if ( lv->d->defRenameAction == QListView::Reject )
+ lv->currentItem()->cancelRename( lv->currentItem()->renameCol );
+ else
+ lv->currentItem()->okRename( lv->currentItem()->renameCol );
+ }
+
+ if ( !newChild || newChild->parentItem == this )
+ return;
+ if ( newChild->parentItem )
+ newChild->parentItem->takeItem( newChild );
+ if ( open )
+ invalidateHeight();
+ newChild->siblingItem = childItem;
+ childItem = newChild;
+ nChildren++;
+ newChild->parentItem = this;
+ lsc = Unsorted;
+ newChild->ownHeight = 0;
+ newChild->configured = FALSE;
+
+ if ( lv && !lv->d->focusItem ) {
+ lv->d->focusItem = lv->firstChild();
+ lv->d->selectAnchor = lv->d->focusItem;
+ lv->repaintItem( lv->d->focusItem );
+ }
+}
+
+
+/*!
+ \fn void QListViewItem::removeItem( QListViewItem * )
+ \obsolete
+
+ This function has been renamed takeItem().
+*/
+
+
+/*!
+ Removes \a item from this object's list of children and causes an
+ update of the screen display. The item is not deleted. You should
+ not normally need to call this function because
+ QListViewItem::~QListViewItem() calls it.
+
+ The normal way to delete an item is to use \c delete.
+
+ If you need to move an item from one place in the hierarchy to
+ another you can use takeItem() to remove the item from the list
+ view and then insertItem() to put the item back in its new
+ position.
+
+ If a taken item is part of a selection in \c Single selection
+ mode, it is unselected and selectionChanged() is emitted. If a
+ taken item is part of a selection in \c Multi or \c Extended
+ selection mode, it remains selected.
+
+ \warning This function leaves \a item and its children in a state
+ where most member functions are unsafe. Only a few functions work
+ correctly on an item in this state, most notably insertItem(). The
+ functions that work on taken items are explicitly documented as
+ such.
+
+ \sa QListViewItem::insertItem()
+*/
+
+void QListViewItem::takeItem( QListViewItem * item )
+{
+ if ( !item )
+ return;
+
+ QListView *lv = listView();
+ if ( lv && lv->currentItem() && lv->currentItem()->renameBox ) {
+ if ( lv->d->defRenameAction == QListView::Reject )
+ lv->currentItem()->cancelRename( lv->currentItem()->renameCol );
+ else
+ lv->currentItem()->okRename( lv->currentItem()->renameCol );
+ }
+ bool emit_changed = FALSE;
+ if ( lv && !lv->d->clearing ) {
+ if ( lv->d->oldFocusItem == this )
+ lv->d->oldFocusItem = 0;
+
+ if ( lv->d->iterators ) {
+ QListViewItemIterator *i = lv->d->iterators->first();
+ while ( i ) {
+ if ( i->current() == item )
+ i->currentRemoved();
+ i = lv->d->iterators->next();
+ }
+ }
+
+ invalidateHeight();
+
+ if ( lv->d && lv->d->drawables ) {
+ delete lv->d->drawables;
+ lv->d->drawables = 0;
+ }
+
+ if ( lv->d->dirtyItems ) {
+ if ( item->childItem ) {
+ delete lv->d->dirtyItems;
+ lv->d->dirtyItems = 0;
+ lv->d->dirtyItemTimer->stop();
+ lv->triggerUpdate();
+ } else {
+ lv->d->dirtyItems->take( (void *)item );
+ }
+ }
+
+ if ( lv->d->focusItem ) {
+ const QListViewItem * c = lv->d->focusItem;
+ while( c && c != item )
+ c = c->parentItem;
+ if ( c == item ) {
+ if ( lv->selectedItem() ) {
+ // for Single, setSelected( FALSE ) when selectedItem() is taken
+ lv->selectedItem()->setSelected( FALSE );
+ // we don't emit selectionChanged( 0 )
+ emit lv->selectionChanged();
+ }
+ if ( item->nextSibling() )
+ lv->d->focusItem = item->nextSibling();
+ else if ( item->itemAbove() )
+ lv->d->focusItem = item->itemAbove();
+ else
+ lv->d->focusItem = 0;
+ emit_changed = TRUE;
+ }
+ }
+
+ // reset anchors etc. if they are set to this or any child
+ // items
+ const QListViewItem *ptr = lv->d->selectAnchor;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->selectAnchor = lv->d->focusItem;
+
+ ptr = lv->d->startDragItem;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->startDragItem = 0;
+
+ ptr = lv->d->pressedItem;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->pressedItem = 0;
+
+ ptr = lv->d->highlighted;
+ while (ptr && ptr != item)
+ ptr = ptr->parentItem;
+ if (ptr == item)
+ lv->d->highlighted = 0;
+ }
+
+ nChildren--;
+
+ QListViewItem ** nextChild = &childItem;
+ while( nextChild && *nextChild && item != *nextChild )
+ nextChild = &((*nextChild)->siblingItem);
+
+ if ( nextChild && item == *nextChild )
+ *nextChild = (*nextChild)->siblingItem;
+ item->parentItem = 0;
+ item->siblingItem = 0;
+ item->ownHeight = 0;
+ item->maybeTotalHeight = -1;
+ item->configured = FALSE;
+
+ if ( emit_changed ) {
+ emit lv->currentChanged( lv->d->focusItem );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( lv->viewport(), 0, QAccessible::Focus );
+#endif
+ }
+}
+
+
+/*!
+ \fn QString QListViewItem::key( int column, bool ascending ) const
+
+ Returns a key that can be used for sorting by column \a column.
+ The default implementation returns text(). Derived classes may
+ also incorporate the order indicated by \a ascending into this
+ key, although this is not recommended.
+
+ If you want to sort on non-alphabetical data, e.g. dates, numbers,
+ etc., it is more efficient to reimplement compare().
+
+ \sa compare(), sortChildItems()
+*/
+
+QString QListViewItem::key( int column, bool ) const
+{
+ return text( column );
+}
+
+
+/*!
+ Compares this list view item to \a i using the column \a col in \a
+ ascending order. Returns \< 0 if this item is less than \a i, 0 if
+ they are equal and \> 0 if this item is greater than \a i.
+
+ This function is used for sorting.
+
+ The default implementation compares the item keys (key()) using
+ QString::localeAwareCompare(). A reimplementation can use
+ different values and a different comparison function. Here is a
+ reimplementation that uses plain Unicode comparison:
+
+ \code
+ int MyListViewItem::compare( QListViewItem *i, int col,
+ bool ascending ) const
+ {
+ return key( col, ascending ).compare( i->key( col, ascending) );
+ }
+ \endcode
+ We don't recommend using \a ascending so your code can safely
+ ignore it.
+
+ \sa key() QString::localeAwareCompare() QString::compare()
+*/
+
+int QListViewItem::compare( QListViewItem *i, int col, bool ascending ) const
+{
+ return key( col, ascending ).localeAwareCompare( i->key( col, ascending ) );
+}
+
+/*!
+ Sorts this item's children using column \a column. This is done in
+ ascending order if \a ascending is TRUE and in descending order if
+ \a ascending is FALSE.
+
+ Asks some of the children to sort their children. (QListView and
+ QListViewItem ensure that all on-screen objects are properly
+ sorted but may avoid or defer sorting other objects in order to be
+ more responsive.)
+
+ \sa key() compare()
+*/
+
+void QListViewItem::sortChildItems( int column, bool ascending )
+{
+ // we try HARD not to sort. if we're already sorted, don't.
+ if ( column == (int)lsc && ascending == (bool)lso )
+ return;
+
+ if ( column < 0 )
+ return;
+
+ lsc = column;
+ lso = ascending;
+
+ const int nColumns = ( listView() ? listView()->columns() : 0 );
+
+ // only sort if the item have more than one child.
+ if ( column > nColumns || childItem == 0 || (childItem->siblingItem == 0 && childItem->childItem == 0))
+ return;
+
+ // make an array for qHeapSort()
+ QListViewPrivate::SortableItem * siblings
+ = new QListViewPrivate::SortableItem[nChildren];
+ QListViewItem * s = childItem;
+ int i = 0;
+ while ( s && i < nChildren ) {
+ siblings[i].numCols = nColumns;
+ siblings[i].col = column;
+ siblings[i].asc = ascending;
+ siblings[i].item = s;
+ s = s->siblingItem;
+ i++;
+ }
+
+ // and sort it.
+ qHeapSort( siblings, siblings + nChildren );
+
+ // build the linked list of siblings, in the appropriate
+ // direction, and finally set this->childItem to the new top
+ // child.
+ if ( ascending ) {
+ for( i = 0; i < nChildren - 1; i++ )
+ siblings[i].item->siblingItem = siblings[i+1].item;
+ siblings[nChildren-1].item->siblingItem = 0;
+ childItem = siblings[0].item;
+ } else {
+ for( i = nChildren - 1; i > 0; i-- )
+ siblings[i].item->siblingItem = siblings[i-1].item;
+ siblings[0].item->siblingItem = 0;
+ childItem = siblings[nChildren-1].item;
+ }
+ for ( i = 0; i < nChildren; i++ ) {
+ if ( siblings[i].item->isOpen() )
+ siblings[i].item->sort();
+ }
+ delete[] siblings;
+}
+
+
+/*!
+ Sets this item's height to \a height pixels. This implicitly
+ changes totalHeight(), too.
+
+ Note that a font change causes this height to be overwritten
+ unless you reimplement setup().
+
+ For best results in Windows style we suggest using an even number
+ of pixels.
+
+ \sa height() totalHeight() isOpen();
+*/
+
+void QListViewItem::setHeight( int height )
+{
+ if ( ownHeight != height ) {
+ if ( visible )
+ ownHeight = height;
+ else
+ ownHeight = 0;
+ invalidateHeight();
+ }
+}
+
+
+/*!
+ Invalidates the cached total height of this item, including all
+ open children.
+
+ \sa setHeight() height() totalHeight()
+*/
+
+void QListViewItem::invalidateHeight()
+{
+ if ( maybeTotalHeight < 0 )
+ return;
+ maybeTotalHeight = -1;
+ if ( parentItem && parentItem->isOpen() )
+ parentItem->invalidateHeight();
+}
+
+
+/*!
+ Opens or closes an item, i.e. shows or hides an item's children.
+
+ If \a o is TRUE all child items are shown initially. The user can
+ hide them by clicking the <b>-</b> icon to the left of the item.
+ If \a o is FALSE, the children of this item are initially hidden.
+ The user can show them by clicking the <b>+</b> icon to the left
+ of the item.
+
+ \sa height() totalHeight() isOpen()
+*/
+
+void QListViewItem::setOpen( bool o )
+{
+ if ( o == (bool)open || !enabled )
+ return;
+ open = o;
+
+ // If no children to show simply emit signals and return
+ if ( !nChildren ) {
+ QListView *lv = listView();
+ if ( lv && this != lv->d->r ) {
+ if ( o )
+ emit lv->expanded( this );
+ else
+ emit lv->collapsed( this );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( lv->viewport(), indexOfItem( this ), QAccessible::StateChanged );
+#endif
+ }
+ return;
+ }
+ invalidateHeight();
+
+ if ( !configured ) {
+ QListViewItem * l = this;
+ QPtrStack<QListViewItem> s;
+ while( l ) {
+ if ( l->open && l->childItem ) {
+ s.push( l->childItem );
+ } else if ( l->childItem ) {
+ // first invisible child is unconfigured
+ QListViewItem * c = l->childItem;
+ while( c ) {
+ c->configured = FALSE;
+ c = c->siblingItem;
+ }
+ }
+ l->configured = TRUE;
+ l->setup();
+ l = (l == this) ? 0 : l->siblingItem;
+ if ( !l && !s.isEmpty() )
+ l = s.pop();
+ }
+ }
+
+ QListView *lv = listView();
+
+ if ( open && lv)
+ enforceSortOrder();
+
+ if ( isVisible() && lv && lv->d && lv->d->drawables ) {
+ lv->d->drawables->clear();
+ lv->buildDrawableList();
+ }
+
+ if ( lv && this != lv->d->r ) {
+ if ( o )
+ emit lv->expanded( this );
+ else
+ emit lv->collapsed( this );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( lv->viewport(), indexOfItem( this ), QAccessible::StateChanged );
+#endif
+ }
+}
+
+
+/*!
+ This virtual function is called before the first time QListView
+ needs to know the height or any other graphical attribute of this
+ object, and whenever the font, GUI style, or colors of the list
+ view change.
+
+ The default calls widthChanged() and sets the item's height to the
+ height of a single line of text in the list view's font. (If you
+ use icons, multi-line text, etc., you will probably need to call
+ setHeight() yourself or reimplement it.)
+*/
+
+void QListViewItem::setup()
+{
+ widthChanged();
+ QListView *lv = listView();
+
+ int ph = 0;
+ int h = 0;
+ if ( lv ) {
+ for ( uint i = 0; i < lv->d->column.size(); ++i ) {
+ if ( pixmap( i ) )
+ ph = QMAX( ph, pixmap( i )->height() );
+ }
+
+ if ( mlenabled ) {
+ h = ph;
+ for ( int c = 0; c < lv->columns(); ++c ) {
+ int lines = text( c ).contains( QChar('\n') ) + 1;
+ int tmph = lv->d->fontMetricsHeight
+ + lv->fontMetrics().lineSpacing() * ( lines - 1 );
+ h = QMAX( h, tmph );
+ }
+ h += 2*lv->itemMargin();
+ } else {
+ h = QMAX( lv->d->fontMetricsHeight, ph ) + 2*lv->itemMargin();
+ }
+ }
+
+ h = QMAX( h, QApplication::globalStrut().height());
+
+ if ( h % 2 > 0 )
+ h++;
+ setHeight( h );
+}
+
+
+
+
+/*!
+ This virtual function is called whenever the user presses the mouse
+ on this item or presses Space on it.
+
+ \sa activatedPos()
+*/
+
+void QListViewItem::activate()
+{
+}
+
+
+/*!
+ When called from a reimplementation of activate(), this function
+ gives information on how the item was activated. Otherwise the
+ behavior is undefined.
+
+ If activate() was caused by a mouse press, the function sets \a
+ pos to where the user clicked and returns TRUE; otherwise it
+ returns FALSE and does not change \a pos.
+
+ \a pos is relative to the top-left corner of this item.
+
+ \warning We recommend that you ignore this function; it is
+ scheduled to become obsolete.
+
+ \sa activate()
+*/
+
+bool QListViewItem::activatedPos( QPoint &pos )
+{
+ if ( activatedByClick )
+ pos = activatedP;
+ return activatedByClick;
+}
+
+
+/*!
+ \fn bool QListViewItem::isSelectable() const
+
+ Returns TRUE if the item is selectable (as it is by default);
+ otherwise returns FALSE
+
+ \sa setSelectable()
+*/
+
+
+/*!
+ Sets this item to be selectable if \a enable is TRUE (the
+ default) or not to be selectable if \a enable is FALSE.
+
+ The user is not able to select a non-selectable item using either
+ the keyboard or the mouse. This also applies for the application
+ programmer (e.g. setSelected() respects this value).
+
+ \sa isSelectable()
+*/
+
+void QListViewItem::setSelectable( bool enable )
+{
+ selectable = enable;
+}
+
+
+/*!
+ \fn bool QListViewItem::isExpandable() const
+
+ Returns TRUE if this item is expandable even when it has no
+ children; otherwise returns FALSE.
+*/
+
+/*!
+ Sets this item to be expandable even if it has no children if \a
+ enable is TRUE, and to be expandable only if it has children if \a
+ enable is FALSE (the default).
+
+ The dirview example uses this in the canonical fashion. It checks
+ whether the directory is empty in setup() and calls
+ setExpandable(TRUE) if not; in setOpen() it reads the contents of
+ the directory and inserts items accordingly. This strategy means
+ that dirview can display the entire file system without reading
+ very much at startup.
+
+ Note that root items are not expandable by the user unless
+ QListView::setRootIsDecorated() is set to TRUE.
+
+ \sa setSelectable()
+*/
+
+void QListViewItem::setExpandable( bool enable )
+{
+ expandable = enable;
+}
+
+
+/*!
+ Makes sure that this object's children are sorted appropriately.
+
+ This only works if every item from the root item down to this item
+ is already sorted.
+
+ \sa sortChildItems()
+*/
+
+void QListViewItem::enforceSortOrder() const
+{
+ QListView *lv = listView();
+ if ( !lv || lv && (lv->d->clearing || lv->d->sortcolumn == Unsorted) )
+ return;
+ if ( parentItem &&
+ (parentItem->lsc != lsc || parentItem->lso != lso) )
+ ((QListViewItem *)this)->sortChildItems( (int)parentItem->lsc,
+ (bool)parentItem->lso );
+ else if ( !parentItem &&
+ ( (int)lsc != lv->d->sortcolumn || (bool)lso != lv->d->ascending ) )
+ ((QListViewItem *)this)->sortChildItems( lv->d->sortcolumn, lv->d->ascending );
+}
+
+
+/*!
+ \fn bool QListViewItem::isSelected() const
+
+ Returns TRUE if this item is selected; otherwise returns FALSE.
+
+ \sa setSelected() QListView::setSelected() QListView::selectionChanged()
+*/
+
+
+/*!
+ If \a s is TRUE this item is selected; otherwise it is deselected.
+
+ This function does not maintain any invariants or repaint anything
+ -- QListView::setSelected() does that.
+
+ \sa height() totalHeight()
+*/
+
+void QListViewItem::setSelected( bool s )
+{
+ bool old = selected;
+
+ QListView *lv = listView();
+ if ( lv && lv->selectionMode() != QListView::NoSelection) {
+ if ( s && isSelectable() )
+ selected = TRUE;
+ else
+ selected = FALSE;
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( old != (bool)selected ) {
+ int ind = indexOfItem( this );
+ QAccessible::updateAccessibility( lv->viewport(), ind, QAccessible::StateChanged );
+ QAccessible::updateAccessibility( lv->viewport(), ind, selected ? QAccessible::SelectionAdd : QAccessible::SelectionRemove );
+ }
+#else
+ Q_UNUSED( old );
+#endif
+ }
+}
+
+/*!
+ Returns the total height of this object, including any visible
+ children. This height is recomputed lazily and cached for as long
+ as possible.
+
+ Functions which can affect the total height are, setHeight() which
+ is used to set an item's height, setOpen() to show or hide an
+ item's children, and invalidateHeight() to invalidate the cached
+ height.
+
+ \sa height()
+*/
+
+int QListViewItem::totalHeight() const
+{
+ if ( !visible )
+ return 0;
+ if ( maybeTotalHeight >= 0 )
+ return maybeTotalHeight;
+ QListViewItem * that = (QListViewItem *)this;
+ if ( !that->configured ) {
+ that->configured = TRUE;
+ that->setup(); // ### virtual non-const function called in const
+ }
+ that->maybeTotalHeight = that->ownHeight;
+
+ if ( !that->isOpen() || !that->childCount() )
+ return that->ownHeight;
+
+ QListViewItem * child = that->childItem;
+ while ( child != 0 ) {
+ that->maybeTotalHeight += child->totalHeight();
+ child = child->siblingItem;
+ }
+ return that->maybeTotalHeight;
+}
+
+
+/*!
+ Returns the text in column \a column, or QString::null if there is
+ no text in that column.
+
+ \sa key() paintCell()
+*/
+
+QString QListViewItem::text( int column ) const
+{
+ QListViewPrivate::ItemColumnInfo * l
+ = (QListViewPrivate::ItemColumnInfo*) columns;
+
+ while( column && l ) {
+ l = l->next;
+ column--;
+ }
+
+ return l ? l->text : QString::null;
+}
+
+
+/*!
+ Sets the text in column \a column to \a text, if \a column is a
+ valid column number and \a text is different from the existing
+ text.
+
+ If \a text() has been reimplemented, this function may be a no-op.
+
+ \sa text() key()
+*/
+
+void QListViewItem::setText( int column, const QString &text )
+{
+ if ( column < 0 )
+ return;
+
+ QListViewPrivate::ItemColumnInfo * l
+ = (QListViewPrivate::ItemColumnInfo*) columns;
+ if ( !l ) {
+ l = new QListViewPrivate::ItemColumnInfo;
+ columns = (void*)l;
+ }
+ for( int c = 0; c < column; c++ ) {
+ if ( !l->next )
+ l->next = new QListViewPrivate::ItemColumnInfo;
+ l = l->next;
+ }
+ if ( l->text == text )
+ return;
+
+ int oldLc = 0;
+ int newLc = 0;
+ if ( mlenabled ) {
+ if ( !l->text.isEmpty() )
+ oldLc = l->text.contains( QChar( '\n' ) ) + 1;
+ if ( !text.isEmpty() )
+ newLc = text.contains( QChar( '\n' ) ) + 1;
+ }
+
+ l->dirty = TRUE;
+ l->text = text;
+ if ( column == (int)lsc )
+ lsc = Unsorted;
+
+ if ( mlenabled && oldLc != newLc )
+ setup();
+ else
+ widthChanged( column );
+
+ QListView * lv = listView();
+ if ( lv ) {
+ lv->d->useDoubleBuffer = TRUE;
+ lv->triggerUpdate();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( lv->isVisible() )
+ QAccessible::updateAccessibility( lv->viewport(), indexOfItem(this), QAccessible::NameChanged );
+#endif
+ }
+}
+
+
+/*!
+ Sets the pixmap in column \a column to \a pm, if \a pm is non-null
+ and different from the current pixmap, and if \a column is
+ non-negative.
+
+ \sa pixmap() setText()
+*/
+
+void QListViewItem::setPixmap( int column, const QPixmap & pm )
+{
+ if ( column < 0 )
+ return;
+
+ int oldW = 0;
+ int oldH = 0;
+ if ( pixmap( column ) ) {
+ oldW = pixmap( column )->width();
+ oldH = pixmap( column )->height();
+ }
+
+ QListViewPrivate::ItemColumnInfo * l
+ = (QListViewPrivate::ItemColumnInfo*) columns;
+ if ( !l ) {
+ l = new QListViewPrivate::ItemColumnInfo;
+ columns = (void*)l;
+ }
+
+ for( int c = 0; c < column; c++ ) {
+ if ( !l->next )
+ l->next = new QListViewPrivate::ItemColumnInfo;
+ l = l->next;
+ }
+
+ if ( ( pm.isNull() && ( !l->pm || l->pm->isNull() ) ) ||
+ ( l->pm && pm.serialNumber() == l->pm->serialNumber() ) )
+ return;
+
+ if ( pm.isNull() ) {
+ delete l->pm;
+ l->pm = 0;
+ } else {
+ if ( l->pm )
+ *(l->pm) = pm;
+ else
+ l->pm = new QPixmap( pm );
+ }
+
+ int newW = 0;
+ int newH = 0;
+ if ( pixmap( column ) ) {
+ newW = pixmap( column )->width();
+ newH = pixmap( column )->height();
+ }
+
+ if ( oldW != newW || oldH != newH ) {
+ setup();
+ widthChanged( column );
+ invalidateHeight();
+ }
+ QListView *lv = listView();
+ if ( lv ) {
+ lv->d->useDoubleBuffer = TRUE;
+ lv->triggerUpdate();
+ }
+}
+
+
+/*!
+ Returns the pixmap for \a column, or 0 if there is no pixmap for
+ \a column.
+
+ \sa setText() setPixmap()
+*/
+
+const QPixmap * QListViewItem::pixmap( int column ) const
+{
+ QListViewPrivate::ItemColumnInfo * l
+ = (QListViewPrivate::ItemColumnInfo*) columns;
+
+ while( column && l ) {
+ l = l->next;
+ column--;
+ }
+
+ return (l && l->pm) ? l->pm : 0;
+}
+
+
+/*!
+ This virtual function paints the contents of one column of an item
+ and aligns it as described by \a align.
+
+ \a p is a QPainter open on the relevant paint device. \a p is
+ translated so (0, 0) is the top-left pixel in the cell and \a
+ width-1, height()-1 is the bottom-right pixel \e in the cell. The
+ other properties of \a p (pen, brush, etc) are undefined. \a cg is
+ the color group to use. \a column is the logical column number
+ within the item that is to be painted; 0 is the column which may
+ contain a tree.
+
+ This function may use QListView::itemMargin() for readability
+ spacing on the left and right sides of data such as text, and
+ should honor isSelected() and QListView::allColumnsShowFocus().
+
+ If you reimplement this function, you should also reimplement
+ width().
+
+ The rectangle to be painted is in an undefined state when this
+ function is called, so you \e must draw on all the pixels. The
+ painter \a p has the right font on entry.
+
+ \sa paintBranches(), QListView::drawContentsOffset()
+*/
+
+void QListViewItem::paintCell( QPainter * p, const QColorGroup & cg,
+ int column, int width, int align )
+{
+ // Change width() if you change this.
+
+ if ( !p )
+ return;
+
+ QListView *lv = listView();
+ if ( !lv )
+ return;
+ QFontMetrics fm( p->fontMetrics() );
+
+ // had, but we _need_ the column info for the ellipsis thingy!!!
+ if ( !columns ) {
+ for ( uint i = 0; i < lv->d->column.size(); ++i ) {
+ setText( i, text( i ) );
+ }
+ }
+
+ QString t = text( column );
+
+ if ( columns ) {
+ QListViewPrivate::ItemColumnInfo *ci = 0;
+ // try until we have a column info....
+ while ( !ci ) {
+ ci = (QListViewPrivate::ItemColumnInfo*)columns;
+ for ( int i = 0; ci && (i < column); ++i )
+ ci = ci->next;
+
+ if ( !ci ) {
+ setText( column, t );
+ ci = 0;
+ }
+ }
+
+ // if the column width changed and this item was not painted since this change
+ if ( ci && ( ci->width != width || ci->text != t || ci->dirty ) ) {
+ ci->text = t;
+ ci->dirty = FALSE;
+ ci->width = width;
+ ci->truncated = FALSE;
+ // if we have to do the ellipsis thingy calc the truncated text
+ int pw = lv->itemMargin()*2 - lv->d->minLeftBearing - lv->d->minRightBearing;
+ pw += pixmap( column ) ? pixmap( column )->width() + lv->itemMargin() : 0;
+ if ( !mlenabled && fm.width( t ) + pw > width ) {
+ // take care of arabic shaping in width calculation (lars)
+ ci->truncated = TRUE;
+ ci->tmpText = qEllipsisText( t, fm, width - pw, align );
+ } else if ( mlenabled && fm.width( t ) + pw > width ) {
+#ifndef QT_NO_STRINGLIST
+ QStringList list = QStringList::split( QChar('\n'), t, TRUE );
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ QString z = *it;
+ if ( fm.width( z ) + pw > width ) {
+ ci->truncated = TRUE;
+ *it = qEllipsisText( z, fm, width - pw, align );
+ }
+ }
+
+ if ( ci->truncated )
+ ci->tmpText = list.join( QString("\n") );
+#endif
+ }
+ }
+
+ // if we have to draw the ellipsis thingy, use the truncated text
+ if ( ci && ci->truncated )
+ t = ci->tmpText;
+ }
+
+ int marg = lv->itemMargin();
+ int r = marg;
+ const QPixmap * icon = pixmap( column );
+
+ const BackgroundMode bgmode = lv->viewport()->backgroundMode();
+ const QColorGroup::ColorRole crole = QPalette::backgroundRoleFromMode( bgmode );
+ if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) )
+ p->fillRect( 0, 0, width, height(), cg.brush( crole ) );
+ else
+ lv->paintEmptyArea( p, QRect( 0, 0, width, height() ) );
+
+
+ // (lars) what does this do???
+#if 0 // RS: ####
+ if ( align != AlignLeft )
+ marg -= lv->d->minRightBearing;
+#endif
+ if ( isSelected() &&
+ (column == 0 || lv->allColumnsShowFocus()) ) {
+ p->fillRect( r - marg, 0, width - r + marg, height(),
+ cg.brush( QColorGroup::Highlight ) );
+ if ( enabled || !lv )
+ p->setPen( cg.highlightedText() );
+ else if ( !enabled && lv)
+ p->setPen( lv->palette().disabled().highlightedText() );
+ } else {
+ if ( enabled || !lv )
+ p->setPen( cg.text() );
+ else if ( !enabled && lv)
+ p->setPen( lv->palette().disabled().text() );
+ }
+
+
+#if 0
+ bool reverse = QApplication::reverseLayout();
+#else
+ bool reverse = FALSE;
+#endif
+ int iconWidth = 0;
+
+ if ( icon ) {
+ iconWidth = icon->width() + lv->itemMargin();
+ int xo = r;
+ // we default to AlignVCenter.
+ int yo = ( height() - icon->height() ) / 2;
+
+ // I guess we may as well always respect vertical alignment.
+ if ( align & AlignBottom )
+ yo = height() - icon->height();
+ else if ( align & AlignTop )
+ yo = 0;
+
+ // respect horizontal alignment when there is no text for an item.
+ if ( text(column).isEmpty() ) {
+ if ( align & AlignRight )
+ xo = width - 2 * marg - iconWidth;
+ else if ( align & AlignHCenter )
+ xo = ( width - iconWidth ) / 2;
+ }
+ if ( reverse )
+ xo = width - 2 * marg - iconWidth;
+ p->drawPixmap( xo, yo, *icon );
+ }
+
+ if ( !t.isEmpty() ) {
+ if ( !mlenabled ) {
+ if ( !(align & AlignTop || align & AlignBottom) )
+ align |= AlignVCenter;
+ } else {
+ if ( !(align & AlignVCenter || align & AlignBottom) )
+ align |= AlignTop;
+ }
+ if ( !reverse )
+ r += iconWidth;
+
+ if ( !mlenabled ) {
+ p->drawText( r, 0, width-marg-r, height(), align, t );
+ } else {
+ p->drawText( r, marg, width-marg-r, height(), align, t );
+ }
+ }
+
+ if ( mlenabled && column == 0 && isOpen() && childCount() ) {
+ int textheight = fm.size( align, t ).height() + 2 * lv->itemMargin();
+ textheight = QMAX( textheight, QApplication::globalStrut().height() );
+ if ( textheight % 2 > 0 )
+ textheight++;
+ if ( textheight < height() ) {
+ int w = lv->treeStepSize() / 2;
+ lv->style().drawComplexControl( QStyle::CC_ListView, p, lv,
+ QRect( 0, textheight, w + 1, height() - textheight + 1 ), cg,
+ lv->isEnabled() ? QStyle::Style_Enabled : QStyle::Style_Default,
+ QStyle::SC_ListViewExpand,
+ (uint)QStyle::SC_All, QStyleOption( this ) );
+ }
+ }
+}
+
+/*!
+ Returns the number of pixels of width required to draw column \a c
+ of list view \a lv, using the metrics \a fm without cropping. The
+ list view containing this item may use this information depending
+ on the QListView::WidthMode settings for the column.
+
+ The default implementation returns the width of the bounding
+ rectangle of the text of column \a c.
+
+ \sa listView() widthChanged() QListView::setColumnWidthMode()
+ QListView::itemMargin()
+*/
+int QListViewItem::width( const QFontMetrics& fm,
+ const QListView* lv, int c ) const
+{
+ int w;
+ if ( mlenabled )
+ w = fm.size( AlignVCenter, text( c ) ).width() + lv->itemMargin() * 2
+ - lv->d->minLeftBearing - lv->d->minRightBearing;
+ else
+ w = fm.width( text( c ) ) + lv->itemMargin() * 2
+ - lv->d->minLeftBearing - lv->d->minRightBearing;
+ const QPixmap * pm = pixmap( c );
+ if ( pm )
+ w += pm->width() + lv->itemMargin(); // ### correct margin stuff?
+ return QMAX( w, QApplication::globalStrut().width() );
+}
+
+
+/*!
+ Paints a focus indicator on the rectangle \a r using painter \a p
+ and colors \a cg.
+
+ \a p is already clipped.
+
+ \sa paintCell() paintBranches() QListView::setAllColumnsShowFocus()
+*/
+
+void QListViewItem::paintFocus( QPainter *p, const QColorGroup &cg,
+ const QRect & r )
+{
+ QListView *lv = listView();
+ if ( lv )
+ lv->style().drawPrimitive( QStyle::PE_FocusRect, p, r, cg,
+ (isSelected() ?
+ QStyle::Style_FocusAtBorder :
+ QStyle::Style_Default),
+ QStyleOption(isSelected() ? cg.highlight() : cg.base() ));
+}
+
+
+/*!
+ Paints a set of branches from this item to (some of) its children.
+
+ Painter \a p is set up with clipping and translation so that you
+ can only draw in the rectangle that needs redrawing; \a cg is the
+ color group to use; the update rectangle is at (0, 0) and has size
+ width \a w by height \a h. The top of the rectangle you own is at
+ \a y (which is never greater than 0 but can be outside the window
+ system's allowed coordinate range).
+
+ The update rectangle is in an undefined state when this function
+ is called; this function must draw on \e all of the pixels.
+
+ \sa paintCell(), QListView::drawContentsOffset()
+*/
+
+void QListViewItem::paintBranches( QPainter * p, const QColorGroup & cg,
+ int w, int y, int h )
+{
+ QListView *lv = listView();
+ if ( lv )
+ lv->paintEmptyArea( p, QRect( 0, 0, w, h ) );
+ if ( !visible || !lv )
+ return;
+ lv->style().drawComplexControl( QStyle::CC_ListView, p, lv,
+ QRect( 0, y, w, h ),
+ cg,
+ lv->isEnabled() ? QStyle::Style_Enabled :
+ QStyle::Style_Default,
+ (QStyle::SC_ListViewBranch |
+ QStyle::SC_ListViewExpand),
+ QStyle::SC_None, QStyleOption(this) );
+}
+
+
+QListViewPrivate::Root::Root( QListView * parent )
+ : QListViewItem( parent )
+{
+ lv = parent;
+ setHeight( 0 );
+ setOpen( TRUE );
+}
+
+
+void QListViewPrivate::Root::setHeight( int )
+{
+ QListViewItem::setHeight( 0 );
+}
+
+
+void QListViewPrivate::Root::invalidateHeight()
+{
+ QListViewItem::invalidateHeight();
+ lv->triggerUpdate();
+}
+
+
+QListView * QListViewPrivate::Root::theListView() const
+{
+ return lv;
+}
+
+
+void QListViewPrivate::Root::setup()
+{
+ // explicitly nothing
+}
+
+
+
+/*!
+\internal
+If called after a mouse click, tells the list view to ignore a
+following double click. This state is reset after the next mouse click.
+*/
+
+void QListViewItem::ignoreDoubleClick()
+{
+ QListView *lv = listView();
+ if ( lv )
+ lv->d->ignoreDoubleClick = TRUE;
+}
+
+
+
+/*!
+ \fn void QListView::onItem( QListViewItem *i )
+
+ This signal is emitted when the user moves the mouse cursor onto
+ item \a i, similar to the QWidget::enterEvent() function.
+*/
+
+// ### bug here too? see qiconview.cppp onItem/onViewport
+
+/*!
+ \fn void QListView::onViewport()
+
+ This signal is emitted when the user moves the mouse cursor from
+ an item to an empty part of the list view.
+*/
+
+/*!
+ \enum QListView::SelectionMode
+
+ This enumerated type is used by QListView to indicate how it
+ reacts to selection by the user.
+
+ \value Single When the user selects an item, any already-selected
+ item becomes unselected. The user can unselect the selected
+ item by clicking on some empty space within the view.
+
+ \value Multi When the user selects an item in the usual way, the
+ selection status of that item is toggled and the other items are
+ left alone. Also, multiple items can be selected by dragging the
+ mouse while the left mouse button stays pressed.
+
+ \value Extended When the user selects an item in the usual way,
+ the selection is cleared and the new item selected. However, if
+ the user presses the Ctrl key when clicking on an item, the
+ clicked item gets toggled and all other items are left untouched.
+ And if the user presses the Shift key while clicking on an item,
+ all items between the current item and the clicked item get
+ selected or unselected, depending on the state of the clicked
+ item. Also, multiple items can be selected by dragging the mouse
+ over them.
+
+ \value NoSelection Items cannot be selected.
+
+ In other words, \c Single is a real single-selection list view, \c
+ Multi a real multi-selection list view, \c Extended is a list view
+ where users can select multiple items but usually want to select
+ either just one or a range of contiguous items, and \c NoSelection
+ is a list view where the user can look but not touch.
+*/
+
+/*!
+ \enum QListView::ResizeMode
+
+ This enum describes how the list view's header adjusts to resize
+ events which affect the width of the list view.
+
+ \value NoColumn The columns do not get resized in resize events.
+
+ \value AllColumns All columns are resized equally to fit the width
+ of the list view.
+
+ \value LastColumn The last column is resized to fit the width of
+ the list view.
+*/
+
+/*!
+ \enum QListView::RenameAction
+
+ This enum describes whether a rename operation is accepted if the
+ rename editor loses focus without the user pressing Enter.
+
+ \value Accept Rename if Enter is pressed or focus is lost.
+
+ \value Reject Discard the rename operation if focus is lost (and
+ Enter has not been pressed).
+*/
+
+/*!
+ \class QListView
+ \brief The QListView class implements a list/tree view.
+
+ \ingroup advanced
+ \mainclass
+
+ It can display and control a hierarchy of multi-column items, and
+ provides the ability to add new items at any time. The user may
+ select one or many items (depending on the \c SelectionMode) and
+ sort the list in increasing or decreasing order by any column.
+
+ The simplest pattern of use is to create a QListView, add some
+ column headers using addColumn() and create one or more
+ QListViewItem or QCheckListItem objects with the QListView as
+ parent:
+
+ \quotefile xml/tagreader-with-features/structureparser.h
+ \skipto QListView * table
+ \printline
+ \quotefile xml/tagreader-with-features/structureparser.cpp
+ \skipto addColumn
+ \printline addColumn
+ \printline
+ \skipto new QListViewItem( table
+ \printline
+
+ Further nodes can be added to the list view object (the root of the
+ tree) or as child nodes to QListViewItems:
+
+ \skipto for ( int i = 0 ; i < attributes.length();
+ \printuntil }
+
+ (From \link xml/tagreader-with-features/structureparser.cpp
+ xml/tagreader-with-features/structureparser.cpp\endlink)
+
+ The main setup functions are:
+ \table
+ \header \i Function \i Action
+ \row \i \l addColumn()
+ \i Adds a column with a text label and perhaps width. Columns
+ are counted from the left starting with column 0.
+ \row \i \l setColumnWidthMode()
+ \i Sets the column to be resized automatically or not.
+ \row \i \l setAllColumnsShowFocus()
+ \i Sets whether items should show keyboard focus using all
+ columns or just column 0. The default is to show focus
+ just using column 0.
+ \row \i \l setRootIsDecorated()
+ \i Sets whether root items should show open/close decoration to their left.
+ The default is FALSE.
+ \row \i \l setTreeStepSize()
+ \i Sets how many pixels an item's children are indented
+ relative to their parent. The default is 20. This is
+ mostly a matter of taste.
+ \row \i \l setSorting()
+ \i Sets whether the items should be sorted, whether it should
+ be in ascending or descending order, and by what column
+ they should be sorted. By default the list view is sorted
+ by the first column; to switch this off call setSorting(-1).
+ \endtable
+
+ To handle events such as mouse presses on the list view, derived
+ classes can reimplement the QScrollView functions:
+ \link QScrollView::contentsMousePressEvent() contentsMousePressEvent\endlink,
+ \link QScrollView::contentsMouseReleaseEvent() contentsMouseReleaseEvent\endlink,
+ \link QScrollView::contentsMouseDoubleClickEvent() contentsMouseDoubleClickEvent\endlink,
+ \link QScrollView::contentsMouseMoveEvent() contentsMouseMoveEvent\endlink,
+ \link QScrollView::contentsDragEnterEvent() contentsDragEnterEvent\endlink,
+ \link QScrollView::contentsDragMoveEvent() contentsDragMoveEvent\endlink,
+ \link QScrollView::contentsDragLeaveEvent() contentsDragLeaveEvent\endlink,
+ \link QScrollView::contentsDropEvent() contentsDropEvent\endlink, and
+ \link QScrollView::contentsWheelEvent() contentsWheelEvent\endlink.
+
+ There are also several functions for mapping between items and
+ coordinates. itemAt() returns the item at a position on-screen,
+ itemRect() returns the rectangle an item occupies on the screen,
+ and itemPos() returns the position of any item (whether it is
+ on-screen or not). firstChild() returns the list view's first item
+ (not necessarily visible on-screen).
+
+ You can iterate over visible items using
+ QListViewItem::itemBelow(); over a list view's top-level items
+ using QListViewItem::firstChild() and
+ QListViewItem::nextSibling(); or every item using a
+ QListViewItemIterator. See
+ the QListViewItem documentation for examples of traversal.
+
+ An item can be moved amongst its siblings using
+ QListViewItem::moveItem(). To move an item in the hierarchy use
+ takeItem() and insertItem(). Item's (and all their child items)
+ are deleted with \c delete; to delete all the list view's items
+ use clear().
+
+ There are a variety of selection modes described in the
+ QListView::SelectionMode documentation. The default is \c Single
+ selection, which you can change using setSelectionMode().
+
+ Because QListView offers multiple selection it must display
+ keyboard focus and selection state separately. Therefore there are
+ functions both to set the selection state of an item
+ (setSelected()) and to set which item displays keyboard focus
+ (setCurrentItem()).
+
+ QListView emits two groups of signals; one group signals changes
+ in selection/focus state and one indicates selection. The first
+ group consists of selectionChanged() (applicable to all list
+ views), selectionChanged(QListViewItem*) (applicable only to a
+ \c Single selection list view), and currentChanged(QListViewItem*).
+ The second group consists of doubleClicked(QListViewItem*),
+ returnPressed(QListViewItem*),
+ rightButtonClicked(QListViewItem*, const QPoint&, int), etc.
+
+ Note that changing the state of the list view in a slot connected
+ to a list view signal may cause unexpected side effects. If you
+ need to change the list view's state in response to a signal, use
+ a \link QTimer::singleShot() single shot timer\endlink with a
+ time out of 0, and connect this timer to a slot that modifies the
+ list view's state.
+
+ In Motif style, QListView deviates fairly strongly from the look
+ and feel of the Motif hierarchical tree view. This is done mostly
+ to provide a usable keyboard interface and to make the list view
+ look better with a white background.
+
+ If selectionMode() is \c Single (the default) the user can select
+ one item at a time, e.g. by clicking an item with the mouse, see
+ \l QListView::SelectionMode for details.
+
+ The list view can be navigated either using the mouse or the
+ keyboard. Clicking a <b>-</b> icon closes an item (hides its
+ children) and clicking a <b>+</b> icon opens an item (shows its
+ children). The keyboard controls are these:
+ \table
+ \header \i Keypress \i Action
+ \row \i Home
+ \i Make the first item current and visible.
+ \row \i End
+ \i Make the last item current and visible.
+ \row \i Page Up
+ \i Make the item above the top visible item current and visible.
+ \row \i Page Down
+ \i Make the item below the bottom visible item current and visible.
+ \row \i Up Arrow
+ \i Make the item above the current item current and visible.
+ \row \i Down Arrow
+ \i Make the item below the current item current and visible.
+ \row \i Left Arrow
+ \i If the current item is closed (<b>+</b> icon) or has no
+ children, make its parent item current and visible. If the
+ current item is open (<b>-</b> icon) close it, i.e. hide its
+ children. Exception: if the current item is the first item
+ and is closed and the horizontal scrollbar is offset to
+ the right the list view will be scrolled left.
+ \row \i Right Arrow
+ \i If the current item is closed (<b>+</b> icon) and has
+ children, the item is opened. If the current item is
+ opened (<b>-</b> icon) and has children the item's first
+ child is made current and visible. If the current item has
+ no children the list view is scrolled right.
+ \endtable
+
+ If the user starts typing letters with the focus in the list view
+ an incremental search will occur. For example if the user types
+ 'd' the current item will change to the first item that begins
+ with the letter 'd'; if they then type 'a', the current item will
+ change to the first item that begins with 'da', and so on. If no
+ item begins with the letters they type the current item doesn't
+ change.
+
+ \warning The list view assumes ownership of all list view items
+ and will delete them when it does not need them any more.
+
+ <img src=qlistview-m.png> <img src=qlistview-w.png>
+
+ \sa QListViewItem QCheckListItem
+*/
+
+/*!
+ \fn void QListView::itemRenamed( QListViewItem * item, int col )
+
+ \overload
+
+ This signal is emitted when \a item has been renamed, e.g. by
+ in-place renaming, in column \a col.
+
+ \sa QListViewItem::setRenameEnabled()
+*/
+
+/*!
+ \fn void QListView::itemRenamed( QListViewItem * item, int col, const QString &text)
+
+ This signal is emitted when \a item has been renamed to \a text,
+ e.g. by in in-place renaming, in column \a col.
+
+ \sa QListViewItem::setRenameEnabled()
+*/
+
+/*!
+ Constructs a new empty list view called \a name with parent \a
+ parent.
+
+ Performance is boosted by modifying the widget flags \a f so that
+ only part of the QListViewItem children is redrawn. This may be
+ unsuitable for custom QListViewItem classes, in which case \c
+ WStaticContents and \c WNoAutoErase should be cleared.
+
+ \sa QWidget::clearWFlags() Qt::WidgetFlags
+*/
+QListView::QListView( QWidget * parent, const char *name, WFlags f )
+ : QScrollView( parent, name, f | WStaticContents | WNoAutoErase )
+{
+ init();
+}
+
+void QListView::init()
+{
+ d = new QListViewPrivate;
+ d->vci = 0;
+ d->timer = new QTimer( this );
+ d->levelWidth = 20;
+ d->r = 0;
+ d->rootIsExpandable = 0;
+ d->h = new QHeader( this, "list view header" );
+ d->h->installEventFilter( this );
+ d->focusItem = 0;
+ d->oldFocusItem = 0;
+ d->drawables = 0;
+ d->dirtyItems = 0;
+ d->dirtyItemTimer = new QTimer( this );
+ d->visibleTimer = new QTimer( this );
+ d->renameTimer = new QTimer( this );
+ d->autoopenTimer = new QTimer( this );
+ d->margin = 1;
+ d->selectionMode = QListView::Single;
+ d->sortcolumn = 0;
+ d->ascending = TRUE;
+ d->allColumnsShowFocus = FALSE;
+ d->fontMetricsHeight = fontMetrics().height();
+ d->h->setTracking(TRUE);
+ d->buttonDown = FALSE;
+ d->ignoreDoubleClick = FALSE;
+ d->column.setAutoDelete( TRUE );
+ d->iterators = 0;
+ d->scrollTimer = 0;
+ d->sortIndicator = FALSE;
+ d->clearing = FALSE;
+ d->minLeftBearing = fontMetrics().minLeftBearing();
+ d->minRightBearing = fontMetrics().minRightBearing();
+ d->ellipsisWidth = fontMetrics().width( "..." ) * 2;
+ d->highlighted = 0;
+ d->pressedItem = 0;
+ d->selectAnchor = 0;
+ d->select = TRUE;
+ d->useDoubleBuffer = FALSE;
+ d->startDragItem = 0;
+ d->toolTips = TRUE;
+#ifndef QT_NO_TOOLTIP
+ d->toolTip = new QListViewToolTip( viewport(), this );
+#endif
+ d->updateHeader = FALSE;
+ d->fullRepaintOnComlumnChange = FALSE;
+ d->resizeMode = NoColumn;
+ d->defRenameAction = Reject;
+ d->pressedEmptyArea = FALSE;
+ d->startEdit = TRUE;
+ d->ignoreEditAfterFocus = FALSE;
+ d->inMenuMode = FALSE;
+ d->pressedSelected = FALSE;
+
+ setMouseTracking( TRUE );
+ viewport()->setMouseTracking( TRUE );
+
+ connect( d->timer, SIGNAL(timeout()),
+ this, SLOT(updateContents()) );
+ connect( d->dirtyItemTimer, SIGNAL(timeout()),
+ this, SLOT(updateDirtyItems()) );
+ connect( d->visibleTimer, SIGNAL(timeout()),
+ this, SLOT(makeVisible()) );
+ connect( d->renameTimer, SIGNAL(timeout()),
+ this, SLOT(startRename()) );
+ connect( d->autoopenTimer, SIGNAL(timeout()),
+ this, SLOT(openFocusItem()) );
+
+ connect( d->h, SIGNAL(sizeChange(int,int,int)),
+ this, SLOT(handleSizeChange(int,int,int)) );
+ connect( d->h, SIGNAL(indexChange(int,int,int)),
+ this, SLOT(handleIndexChange()) );
+ connect( d->h, SIGNAL(sectionClicked(int)),
+ this, SLOT(changeSortColumn(int)) );
+ connect( d->h, SIGNAL(sectionHandleDoubleClicked(int)),
+ this, SLOT(adjustColumn(int)) );
+ connect( horizontalScrollBar(), SIGNAL(sliderMoved(int)),
+ d->h, SLOT(setOffset(int)) );
+ connect( horizontalScrollBar(), SIGNAL(valueChanged(int)),
+ d->h, SLOT(setOffset(int)) );
+
+ // will access d->r
+ QListViewPrivate::Root * r = new QListViewPrivate::Root( this );
+ r->is_root = TRUE;
+ d->r = r;
+ d->r->setSelectable( FALSE );
+
+ viewport()->setFocusProxy( this );
+ viewport()->setFocusPolicy( WheelFocus );
+ viewport()->setBackgroundMode( PaletteBase );
+ setBackgroundMode( PaletteBackground, PaletteBase );
+}
+
+/*!
+ \property QListView::showSortIndicator
+ \brief whether the list view header should display a sort indicator.
+
+ If this property is TRUE, an arrow is drawn in the header of the
+ list view to indicate the sort order of the list view contents.
+ The arrow will be drawn in the correct column and will point up or
+ down, depending on the current sort direction. The default is
+ FALSE (don't show an indicator).
+
+ \sa QHeader::setSortIndicator()
+*/
+
+void QListView::setShowSortIndicator( bool show )
+{
+ if ( show == d->sortIndicator )
+ return;
+
+ d->sortIndicator = show;
+ if ( d->sortcolumn != Unsorted && d->sortIndicator )
+ d->h->setSortIndicator( d->sortcolumn, d->ascending );
+ else
+ d->h->setSortIndicator( -1 );
+}
+
+bool QListView::showSortIndicator() const
+{
+ return d->sortIndicator;
+}
+
+/*!
+ \property QListView::showToolTips
+ \brief whether this list view should show tooltips for truncated column texts
+
+ The default is TRUE.
+*/
+
+void QListView::setShowToolTips( bool b )
+{
+ d->toolTips = b;
+}
+
+bool QListView::showToolTips() const
+{
+ return d->toolTips;
+}
+
+/*!
+ \property QListView::resizeMode
+ \brief whether all, none or the only the last column should be resized
+
+ Specifies whether all, none or only the last column should be
+ resized to fit the full width of the list view. The values for this
+ property can be one of: \c NoColumn (the default), \c AllColumns
+ or \c LastColumn.
+
+ \warning Setting the resize mode should be done after all necessary
+ columns have been added to the list view, otherwise the behavior is
+ undefined.
+
+ \sa QHeader, header()
+*/
+
+void QListView::setResizeMode( ResizeMode m )
+{
+ d->resizeMode = m;
+ if ( m == NoColumn )
+ header()->setStretchEnabled( FALSE );
+ else if ( m == AllColumns )
+ header()->setStretchEnabled( TRUE );
+ else
+ header()->setStretchEnabled( TRUE, header()->count() - 1 );
+}
+
+QListView::ResizeMode QListView::resizeMode() const
+{
+ return d->resizeMode;
+}
+
+/*!
+ Destroys the list view, deleting all its items, and frees up all
+ allocated resources.
+*/
+
+QListView::~QListView()
+{
+ if ( d->iterators ) {
+ QListViewItemIterator *i = d->iterators->first();
+ while ( i ) {
+ i->listView = 0;
+ i = d->iterators->next();
+ }
+ delete d->iterators;
+ d->iterators = 0;
+ }
+
+ d->focusItem = 0;
+ delete d->r;
+ d->r = 0;
+ delete d->dirtyItems;
+ d->dirtyItems = 0;
+ delete d->drawables;
+ d->drawables = 0;
+ delete d->vci;
+ d->vci = 0;
+#ifndef QT_NO_TOOLTIP
+ delete d->toolTip;
+ d->toolTip = 0;
+#endif
+ delete d;
+ d = 0;
+}
+
+
+/*!
+ Calls QListViewItem::paintCell() and
+ QListViewItem::paintBranches() as necessary for all list view
+ items that require repainting in the \a cw pixels wide and \a ch
+ pixels high bounding rectangle starting at position \a cx, \a cy
+ with offset \a ox, \a oy. Uses the painter \a p.
+*/
+
+void QListView::drawContentsOffset( QPainter * p, int ox, int oy,
+ int cx, int cy, int cw, int ch )
+{
+ if ( columns() == 0 ) {
+ paintEmptyArea( p, QRect( cx, cy, cw, ch ) );
+ return;
+ }
+
+ if ( !d->drawables ||
+ d->drawables->isEmpty() ||
+ d->topPixel > cy ||
+ d->bottomPixel < cy + ch - 1 ||
+ d->r->maybeTotalHeight < 0 )
+ buildDrawableList();
+
+ if ( d->dirtyItems ) {
+ QRect br( cx - ox, cy - oy, cw, ch );
+ QPtrDictIterator<void> it( *(d->dirtyItems) );
+ QListViewItem * i;
+ while( (i = (QListViewItem *)(it.currentKey())) != 0 ) {
+ ++it;
+ QRect ir = itemRect( i ).intersect( viewport()->rect() );
+ if ( ir.isEmpty() || br.contains( ir ) )
+ // we're painting this one, or it needs no painting: forget it
+ d->dirtyItems->remove( (void *)i );
+ }
+ if ( d->dirtyItems->count() ) {
+ // there are still items left that need repainting
+ d->dirtyItemTimer->start( 0, TRUE );
+ } else {
+ // we're painting all items that need to be painted
+ delete d->dirtyItems;
+ d->dirtyItems = 0;
+ d->dirtyItemTimer->stop();
+ }
+ }
+
+ p->setFont( font() );
+
+ QPtrListIterator<QListViewPrivate::DrawableItem> it( *(d->drawables) );
+
+ QRect r;
+ int fx = -1, x, fc = 0, lc = 0;
+ int tx = -1;
+ QListViewPrivate::DrawableItem * current;
+
+ while ( (current = it.current()) != 0 ) {
+ ++it;
+ if ( !current->i->isVisible() )
+ continue;
+ int ih = current->i->height();
+ int ith = current->i->totalHeight();
+ int c;
+ int cs;
+
+ // need to paint current?
+ if ( ih > 0 && current->y < cy+ch && current->y+ih > cy ) {
+ if ( fx < 0 ) {
+ // find first interesting column, once
+ x = 0;
+ c = 0;
+ cs = d->h->cellSize( 0 );
+ while ( x + cs <= cx && c < d->h->count() ) {
+ x += cs;
+ c++;
+ if ( c < d->h->count() )
+ cs = d->h->cellSize( c );
+ }
+ fx = x;
+ fc = c;
+ while( x < cx + cw && c < d->h->count() ) {
+ x += cs;
+ c++;
+ if ( c < d->h->count() )
+ cs = d->h->cellSize( c );
+ }
+ lc = c;
+ }
+
+ x = fx;
+ c = fc;
+ // draw to last interesting column
+
+ bool drawActiveSelection = hasFocus() || d->inMenuMode ||
+ !style().styleHint( QStyle::SH_ItemView_ChangeHighlightOnFocus, this ) ||
+ ( currentItem() && currentItem()->renameBox && currentItem()->renameBox->hasFocus() );
+ const QColorGroup &cg = ( drawActiveSelection ? colorGroup() : palette().inactive() );
+
+ while ( c < lc && d->drawables ) {
+ int i = d->h->mapToLogical( c );
+ cs = d->h->cellSize( c );
+ r.setRect( x - ox, current->y - oy, cs, ih );
+ if ( i == 0 && current->i->parentItem )
+ r.setLeft( r.left() + current->l * treeStepSize() );
+
+ p->save();
+ // No need to paint if the cell isn't technically visible
+ if ( !( r.width() == 0 || r.height() == 0 ) ) {
+ p->translate( r.left(), r.top() );
+ int ac = d->h->mapToLogical( c );
+ // map to Left currently. This should change once we
+ // can really reverse the listview.
+ int align = columnAlignment( ac );
+ if ( align == AlignAuto ) align = AlignLeft;
+ if ( d->useDoubleBuffer ) {
+ QRect a( 0, 0, r.width(), current->i->height() );
+ QSharedDoubleBuffer buffer( p, a, QSharedDoubleBuffer::Force );
+ if ( buffer.isBuffered() )
+ paintEmptyArea( buffer.painter(), a );
+ buffer.painter()->setFont( p->font() );
+ buffer.painter()->setPen( p->pen() );
+ buffer.painter()->setBrush( p->brush() );
+ buffer.painter()->setBrushOrigin( -r.left(), -r.top() );
+ current->i->paintCell( buffer.painter(), cg, ac, r.width(),
+ align );
+ } else {
+ current->i->paintCell( p, cg, ac, r.width(),
+ align );
+ }
+ }
+ p->restore();
+ x += cs;
+ c++;
+ }
+
+ if ( current->i == d->focusItem && hasFocus() &&
+ !d->allColumnsShowFocus ) {
+ p->save();
+ int cell = d->h->mapToActual( 0 );
+ QRect r( d->h->cellPos( cell ) - ox, current->y - oy, d->h->cellSize( cell ), ih );
+ if ( current->i->parentItem )
+ r.setLeft( r.left() + current->l * treeStepSize() );
+ if ( r.left() < r.right() )
+ current->i->paintFocus( p, colorGroup(), r );
+ p->restore();
+ }
+ }
+
+ const int cell = d->h->mapToActual( 0 );
+
+ // does current need focus indication?
+ if ( current->i == d->focusItem && hasFocus() &&
+ d->allColumnsShowFocus ) {
+ p->save();
+ int x = -contentsX();
+ int w = header()->cellPos( header()->count() - 1 ) +
+ header()->cellSize( header()->count() - 1 );
+
+ r.setRect( x, current->y - oy, w, ih );
+ if ( d->h->mapToActual( 0 ) == 0 || ( current->l == 0 && !rootIsDecorated() ) ) {
+ int offsetx = QMIN( current->l * treeStepSize(), d->h->cellSize( cell ) );
+ r.setLeft( r.left() + offsetx );
+ current->i->paintFocus( p, colorGroup(), r );
+ } else {
+ int xdepth = QMIN( treeStepSize() * ( current->i->depth() + ( rootIsDecorated() ? 1 : 0) )
+ + itemMargin(), d->h->cellSize( cell ) );
+ xdepth += d->h->cellPos( cell );
+ QRect r1( r );
+ r1.setRight( d->h->cellPos( cell ) - 1 );
+ QRect r2( r );
+ r2.setLeft( xdepth - 1 );
+ current->i->paintFocus( p, colorGroup(), r1 );
+ current->i->paintFocus( p, colorGroup(), r2 );
+ }
+ p->restore();
+ }
+
+ if ( tx < 0 )
+ tx = d->h->cellPos( cell );
+
+ // do any children of current need to be painted?
+ if ( ih != ith &&
+ (current->i != d->r || d->rootIsExpandable) &&
+ current->y + ith > cy &&
+ current->y + ih < cy + ch &&
+ tx + current->l * treeStepSize() < cx + cw &&
+ tx + (current->l+1) * treeStepSize() > cx ) {
+ // compute the clip rectangle the safe way
+
+ int rtop = current->y + ih;
+ int rbottom = current->y + ith;
+ int rleft = tx + current->l*treeStepSize();
+ int rright = rleft + treeStepSize();
+
+ int crtop = QMAX( rtop, cy );
+ int crbottom = QMIN( rbottom, cy+ch );
+ int crleft = QMAX( rleft, cx );
+ int crright = QMIN( rright, cx+cw );
+
+ r.setRect( crleft-ox, crtop-oy,
+ crright-crleft, crbottom-crtop );
+
+ if ( r.isValid() ) {
+ p->save();
+ p->translate( rleft-ox, crtop-oy );
+ current->i->paintBranches( p, colorGroup(), treeStepSize(),
+ rtop - crtop, r.height() );
+ p->restore();
+ }
+ }
+ }
+
+ if ( d->r->totalHeight() < cy + ch )
+ paintEmptyArea( p, QRect( cx - ox, d->r->totalHeight() - oy,
+ cw, cy + ch - d->r->totalHeight() ) );
+
+ int c = d->h->count()-1;
+ if ( c >= 0 &&
+ d->h->cellPos( c ) + d->h->cellSize( c ) < cx + cw ) {
+ c = d->h->cellPos( c ) + d->h->cellSize( c );
+ paintEmptyArea( p, QRect( c - ox, cy - oy, cx + cw - c, ch ) );
+ }
+}
+
+
+
+/*!
+ Paints \a rect so that it looks like empty background using
+ painter \a p. \a rect is in widget coordinates, ready to be fed to
+ \a p.
+
+ The default function fills \a rect with the
+ viewport()->backgroundBrush().
+*/
+
+void QListView::paintEmptyArea( QPainter * p, const QRect & rect )
+{
+ QStyleOption opt( d->sortcolumn, 0 ); // ### hack; in 3.1, add a property in QListView and QHeader
+ QStyle::SFlags how = QStyle::Style_Default;
+ if ( isEnabled() )
+ how |= QStyle::Style_Enabled;
+
+ style().drawComplexControl( QStyle::CC_ListView,
+ p, this, rect, colorGroup(),
+ how, QStyle::SC_ListView, QStyle::SC_None,
+ opt );
+}
+
+
+/*
+ Rebuilds the list of drawable QListViewItems. This function is
+ const so that const functions can call it without requiring
+ d->drawables to be mutable.
+*/
+
+void QListView::buildDrawableList() const
+{
+ d->r->enforceSortOrder();
+
+ QPtrStack<QListViewPrivate::Pending> stack;
+ stack.push( new QListViewPrivate::Pending( ((int)d->rootIsExpandable)-1,
+ 0, d->r ) );
+
+ // could mess with cy and ch in order to speed up vertical
+ // scrolling
+ int cy = contentsY();
+ int ch = ((QListView *)this)->visibleHeight();
+ d->topPixel = cy + ch; // one below bottom
+ d->bottomPixel = cy - 1; // one above top
+
+ QListViewPrivate::Pending * cur;
+
+ // used to work around lack of support for mutable
+ QPtrList<QListViewPrivate::DrawableItem> * dl;
+
+ dl = new QPtrList<QListViewPrivate::DrawableItem>;
+ dl->setAutoDelete( TRUE );
+ if ( d->drawables )
+ delete ((QListView *)this)->d->drawables;
+ ((QListView *)this)->d->drawables = dl;
+
+ while ( !stack.isEmpty() ) {
+ cur = stack.pop();
+
+ int ih = cur->i->height();
+ int ith = cur->i->totalHeight();
+
+ // if this is not true, buildDrawableList has been called recursivly
+ Q_ASSERT( dl == d->drawables );
+
+ // is this item, or its branch symbol, inside the viewport?
+ if ( cur->y + ith >= cy && cur->y < cy + ch ) {
+ dl->append( new QListViewPrivate::DrawableItem(cur));
+ // perhaps adjust topPixel up to this item? may be adjusted
+ // down again if any children are not to be painted
+ if ( cur->y < d->topPixel )
+ d->topPixel = cur->y;
+ // bottompixel is easy: the bottom item drawn contains it
+ d->bottomPixel = cur->y + ih - 1;
+ }
+
+ // push younger sibling of cur on the stack?
+ if ( cur->y + ith < cy+ch && cur->i->siblingItem )
+ stack.push( new QListViewPrivate::Pending(cur->l,
+ cur->y + ith,
+ cur->i->siblingItem));
+
+ // do any children of cur need to be painted?
+ if ( cur->i->isOpen() && cur->i->childCount() &&
+ cur->y + ith > cy &&
+ cur->y + ih < cy + ch ) {
+ cur->i->enforceSortOrder();
+
+ QListViewItem * c = cur->i->childItem;
+ int y = cur->y + ih;
+
+ // if any of the children are not to be painted, skip them
+ // and invalidate topPixel
+ while ( c && y + c->totalHeight() <= cy ) {
+ y += c->totalHeight();
+ c = c->siblingItem;
+ d->topPixel = cy + ch;
+ }
+
+ // push one child on the stack, if there is at least one
+ // needing to be painted
+ if ( c && y < cy+ch )
+ stack.push( new QListViewPrivate::Pending( cur->l + 1,
+ y, c ) );
+ }
+
+ delete cur;
+ }
+}
+
+/*!
+ \property QListView::treeStepSize
+ \brief the number of pixels a child is offset from its parent
+
+ The default is 20 pixels.
+
+ Of course, this property is only meaningful for hierarchical list
+ views.
+*/
+
+int QListView::treeStepSize() const
+{
+ return d->levelWidth;
+}
+
+void QListView::setTreeStepSize( int size )
+{
+ if ( size != d->levelWidth ) {
+ d->levelWidth = size;
+ viewport()->repaint( FALSE );
+ }
+}
+
+/*!
+ Inserts item \a i into the list view as a top-level item. You do
+ not need to call this unless you've called takeItem(\a i) or
+ QListViewItem::takeItem(\a i) and need to reinsert \a i elsewhere.
+
+ \sa QListViewItem::takeItem() takeItem()
+*/
+
+void QListView::insertItem( QListViewItem * i )
+{
+ if ( d->r ) // not for d->r itself
+ d->r->insertItem( i );
+}
+
+
+/*!
+ Removes and deletes all the items in this list view and triggers
+ an update.
+
+ Note that the currentChanged() signal is not emitted when this slot is invoked.
+ \sa triggerUpdate()
+*/
+
+void QListView::clear()
+{
+ bool wasUpdatesEnabled = viewport()->isUpdatesEnabled();
+ viewport()->setUpdatesEnabled( FALSE );
+ setContentsPos( 0, 0 );
+ viewport()->setUpdatesEnabled( wasUpdatesEnabled );
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ d->clearing = TRUE;
+ clearSelection();
+ if ( d->iterators ) {
+ QListViewItemIterator *i = d->iterators->first();
+ while ( i ) {
+ i->curr = 0;
+ i = d->iterators->next();
+ }
+ }
+
+ if ( d->drawables )
+ d->drawables->clear();
+ delete d->dirtyItems;
+ d->dirtyItems = 0;
+ d->dirtyItemTimer->stop();
+
+ d->focusItem = 0;
+ d->selectAnchor = 0;
+ d->pressedItem = 0;
+ d->highlighted = 0;
+ d->startDragItem = 0;
+
+ // if it's down its downness makes no sense, so undown it
+ d->buttonDown = FALSE;
+
+ QListViewItem *c = (QListViewItem *)d->r->firstChild();
+ QListViewItem *n;
+ while( c ) {
+ n = (QListViewItem *)c->nextSibling();
+ delete c;
+ c = n;
+ }
+ resizeContents( d->h->sizeHint().width(), contentsHeight() );
+ delete d->r;
+ d->r = 0;
+ QListViewPrivate::Root * r = new QListViewPrivate::Root( this );
+ r->is_root = TRUE;
+ d->r = r;
+ d->r->setSelectable( FALSE );
+ blockSignals( block );
+ triggerUpdate();
+ d->clearing = FALSE;
+}
+
+/*!
+ \reimp
+*/
+
+void QListView::setContentsPos( int x, int y )
+{
+ updateGeometries();
+ QScrollView::setContentsPos( x, y );
+}
+
+/*!
+ Adds a \a width pixels wide column with the column header \a label
+ to the list view, and returns the index of the new column.
+
+ All columns apart from the first one are inserted to the right of
+ the existing ones.
+
+ If \a width is negative, the new column's \l WidthMode is set to
+ \c Maximum instead of \c Manual.
+
+ \sa setColumnText() setColumnWidth() setColumnWidthMode()
+*/
+int QListView::addColumn( const QString &label, int width )
+{
+ int c = d->h->addLabel( label, width );
+ d->column.resize( c+1 );
+ d->column.insert( c, new QListViewPrivate::Column );
+ d->column[c]->wmode = width >=0 ? Manual : Maximum;
+ updateGeometries();
+ updateGeometry();
+ return c;
+}
+
+/*!
+ \overload
+
+ Adds a \a width pixels wide new column with the header \a label
+ and the \a iconset to the list view, and returns the index of the
+ column.
+
+ If \a width is negative, the new column's \l WidthMode is set to
+ \c Maximum, and to \c Manual otherwise.
+
+ \sa setColumnText() setColumnWidth() setColumnWidthMode()
+*/
+int QListView::addColumn( const QIconSet& iconset, const QString &label, int width )
+{
+ int c = d->h->addLabel( iconset, label, width );
+ d->column.resize( c+1 );
+ d->column.insert( c, new QListViewPrivate::Column );
+ d->column[c]->wmode = width >=0 ? Manual : Maximum;
+ updateGeometries();
+ updateGeometry();
+ return c;
+}
+
+/*!
+ \property QListView::columns
+ \brief the number of columns in this list view
+
+ \sa addColumn(), removeColumn()
+*/
+
+int QListView::columns() const
+{
+ return d->column.count();
+}
+
+/*!
+ Removes the column at position \a index.
+
+ If no columns remain after the column is removed, the
+ list view will be cleared.
+
+ \sa clear()
+*/
+
+void QListView::removeColumn( int index )
+{
+ if ( index < 0 || index > (int)d->column.count() - 1 )
+ return;
+
+ if ( d->vci ) {
+ QListViewPrivate::ViewColumnInfo *vi = d->vci, *prev = 0, *next = 0;
+ for ( int i = 0; i < index; ++i ) {
+ if ( vi ) {
+ prev = vi;
+ vi = vi->next;
+ }
+ }
+ if ( vi ) {
+ next = vi->next;
+ if ( prev )
+ prev->next = next;
+ vi->next = 0;
+ delete vi;
+ if ( index == 0 )
+ d->vci = next;
+ }
+ }
+
+ QListViewItemIterator it( this );
+ for ( ; it.current(); ++it ) {
+ QListViewPrivate::ItemColumnInfo *ci = (QListViewPrivate::ItemColumnInfo*)it.current()->columns;
+ if ( ci ) {
+ QListViewPrivate::ItemColumnInfo *prev = 0, *next = 0;
+ for ( int i = 0; i < index; ++i ) {
+ if ( ci ) {
+ prev = ci;
+ ci = ci->next;
+ }
+ }
+ if ( ci ) {
+ next = ci->next;
+ if ( prev )
+ prev->next = next;
+ ci->next = 0;
+ delete ci;
+ if ( index == 0 )
+ it.current()->columns = next;
+ }
+ }
+ }
+
+ for ( int i = index; i < (int)d->column.size(); ++i ) {
+ QListViewPrivate::Column *c = d->column.take( i );
+ if ( i == index )
+ delete c;
+ if ( i < (int)d->column.size()-1 )
+ d->column.insert( i, d->column[ i + 1 ] );
+ }
+ d->column.resize( d->column.size() - 1 );
+
+ d->h->removeLabel( index );
+ if (d->resizeMode == LastColumn)
+ d->h->setStretchEnabled( TRUE, d->h->count() - 1 );
+
+ updateGeometries();
+ if ( d->column.count() == 0 )
+ clear();
+ updateGeometry();
+ viewport()->update();
+}
+
+/*!
+ Sets the heading of column \a column to \a label.
+
+ \sa columnText()
+*/
+void QListView::setColumnText( int column, const QString &label )
+{
+ if ( column < d->h->count() ) {
+ d->h->setLabel( column, label );
+ updateGeometries();
+ updateGeometry();
+ }
+}
+
+/*!
+ \overload
+
+ Sets the heading of column \a column to \a iconset and \a label.
+
+ \sa columnText()
+*/
+void QListView::setColumnText( int column, const QIconSet& iconset, const QString &label )
+{
+ if ( column < d->h->count() ) {
+ d->h->setLabel( column, iconset, label );
+ updateGeometries();
+ }
+}
+
+/*!
+ Sets the width of column \a column to \a w pixels. Note that if
+ the column has a \c WidthMode other than \c Manual, this width
+ setting may be subsequently overridden.
+
+ \sa columnWidth()
+*/
+void QListView::setColumnWidth( int column, int w )
+{
+ int oldw = d->h->sectionSize( column );
+ if ( column < d->h->count() && oldw != w ) {
+ d->h->resizeSection( column, w );
+ disconnect( d->h, SIGNAL(sizeChange(int,int,int)),
+ this, SLOT(handleSizeChange(int,int,int)) );
+ emit d->h->sizeChange( column, oldw, w);
+ connect( d->h, SIGNAL(sizeChange(int,int,int)),
+ this, SLOT(handleSizeChange(int,int,int)) );
+ updateGeometries();
+ viewport()->update();
+ }
+}
+
+
+/*!
+ Returns the text of column \a c.
+
+ \sa setColumnText()
+*/
+
+QString QListView::columnText( int c ) const
+{
+ return d->h->label(c);
+}
+
+/*!
+ Returns the width of column \a c.
+
+ \sa setColumnWidth()
+*/
+
+int QListView::columnWidth( int c ) const
+{
+ int actual = d->h->mapToActual( c );
+ return d->h->cellSize( actual );
+}
+
+
+/*!
+ \enum QListView::WidthMode
+
+ This enum type describes how the width of a column in the view
+ changes.
+
+ \value Manual the column width does not change automatically.
+
+ \value Maximum the column is automatically sized according to the
+ widths of all items in the column. (Note: The column never shrinks
+ in this case.) This means that the column is always resized to the
+ width of the item with the largest width in the column.
+
+ \sa setColumnWidth() setColumnWidthMode() columnWidth()
+*/
+
+
+/*!
+ Sets column \a{c}'s width mode to \a mode. The default depends on
+ the original width argument to addColumn().
+
+ \sa QListViewItem::width()
+*/
+
+void QListView::setColumnWidthMode( int c, WidthMode mode )
+{
+ if ( c < d->h->count() )
+ d->column[c]->wmode = mode;
+}
+
+
+/*!
+ Returns the \c WidthMode for column \a c.
+
+ \sa setColumnWidthMode()
+*/
+
+QListView::WidthMode QListView::columnWidthMode( int c ) const
+{
+ if ( c < d->h->count() )
+ return d->column[c]->wmode;
+ else
+ return Manual;
+}
+
+
+/*!
+ Sets column \a{column}'s alignment to \a align. The alignment is
+ ultimately passed to QListViewItem::paintCell() for each item in
+ the list view. For horizontally aligned text with Qt::AlignLeft or
+ Qt::AlignHCenter the ellipsis (...) will be to the right, for
+ Qt::AlignRight the ellipsis will be to the left.
+
+ \sa Qt::AlignmentFlags
+*/
+
+void QListView::setColumnAlignment( int column, int align )
+{
+ if ( column < 0 )
+ return;
+ if ( !d->vci )
+ d->vci = new QListViewPrivate::ViewColumnInfo;
+ QListViewPrivate::ViewColumnInfo * l = d->vci;
+ while( column ) {
+ if ( !l->next )
+ l->next = new QListViewPrivate::ViewColumnInfo;
+ l = l->next;
+ column--;
+ }
+ if ( l->align == align )
+ return;
+ l->align = align;
+ triggerUpdate();
+}
+
+
+/*!
+ Returns the alignment of column \a column. The default is \c
+ AlignAuto.
+
+ \sa Qt::AlignmentFlags
+*/
+
+int QListView::columnAlignment( int column ) const
+{
+ if ( column < 0 || !d->vci )
+ return AlignAuto;
+ QListViewPrivate::ViewColumnInfo * l = d->vci;
+ while( column ) {
+ if ( !l->next )
+ l->next = new QListViewPrivate::ViewColumnInfo;
+ l = l->next;
+ column--;
+ }
+ return l ? l->align : AlignAuto;
+}
+
+
+
+/*!
+ \reimp
+ */
+void QListView::show()
+{
+ // Reimplemented to setx the correct background mode and viewed
+ // area size.
+ if ( !isVisible() ) {
+ reconfigureItems();
+ updateGeometries();
+ }
+ QScrollView::show();
+}
+
+
+/*!
+ Updates the sizes of the viewport, header, scroll bars and so on.
+
+ \warning Don't call this directly; call triggerUpdate() instead.
+*/
+
+void QListView::updateContents()
+{
+ if ( d->updateHeader )
+ header()->adjustHeaderSize();
+ d->updateHeader = FALSE;
+ if ( !isVisible() ) {
+ // Not in response to a setText/setPixmap any more.
+ d->useDoubleBuffer = FALSE;
+
+ return;
+ }
+ if ( d->drawables ) {
+ delete d->drawables;
+ d->drawables = 0;
+ }
+ viewport()->setUpdatesEnabled( FALSE );
+ updateGeometries();
+ viewport()->setUpdatesEnabled( TRUE );
+ viewport()->repaint( FALSE );
+ d->useDoubleBuffer = FALSE;
+}
+
+
+void QListView::updateGeometries()
+{
+ int th = d->r->totalHeight();
+ int tw = d->h->headerWidth();
+ if ( d->h->offset() &&
+ tw < d->h->offset() + d->h->width() )
+ horizontalScrollBar()->setValue( tw - QListView::d->h->width() );
+#if 0
+ if ( QApplication::reverseLayout() && d->h->offset() != horizontalScrollBar()->value() )
+ horizontalScrollBar()->setValue( d->h->offset() );
+#endif
+ verticalScrollBar()->raise();
+ resizeContents( tw, th );
+ if ( d->h->isHidden() ) {
+ setMargins( 0, 0, 0, 0 );
+ } else {
+ QSize hs( d->h->sizeHint() );
+ setMargins( 0, hs.height(), 0, 0 );
+ d->h->setGeometry( viewport()->x(), viewport()->y()-hs.height(),
+ visibleWidth(), hs.height() );
+ }
+}
+
+
+/*!
+ Updates the display when the section \a section has changed size
+ from the old size, \a os, to the new size, \a ns.
+*/
+
+void QListView::handleSizeChange( int section, int os, int ns )
+{
+ bool upe = viewport()->isUpdatesEnabled();
+ viewport()->setUpdatesEnabled( FALSE );
+ int sx = horizontalScrollBar()->value();
+ bool sv = horizontalScrollBar()->isVisible();
+ updateGeometries();
+ bool fullRepaint = d->fullRepaintOnComlumnChange || sx != horizontalScrollBar()->value()
+ || sv != horizontalScrollBar()->isVisible();
+ d->fullRepaintOnComlumnChange = FALSE;
+ viewport()->setUpdatesEnabled( upe );
+
+ if ( fullRepaint ) {
+ viewport()->repaint( FALSE );
+ return;
+ }
+
+ int actual = d->h->mapToActual( section );
+ int dx = ns - os;
+ int left = d->h->cellPos( actual ) - contentsX() + d->h->cellSize( actual );
+ if ( dx > 0 )
+ left -= dx;
+ if ( left < visibleWidth() )
+ viewport()->scroll( dx, 0, QRect( left, 0, visibleWidth() - left, visibleHeight() ) );
+ viewport()->repaint( left - 4 - d->ellipsisWidth, 0, 4 + d->ellipsisWidth,
+ visibleHeight(), FALSE ); // border between the items and ellipses width
+
+ // map auto to left for now. Need to fix this once we support
+ // reverse layout on the listview.
+ int align = columnAlignment( section );
+ if ( align == AlignAuto ) align = AlignLeft;
+ if ( align != AlignAuto && align != AlignLeft )
+ viewport()->repaint( d->h->cellPos( actual ) - contentsX(), 0,
+ d->h->cellSize( actual ), visibleHeight() );
+
+ if ( currentItem() && currentItem()->renameBox ) {
+ QRect r = itemRect( currentItem() );
+ r = QRect( viewportToContents( r.topLeft() ), r.size() );
+ r.setLeft( header()->sectionPos( currentItem()->renameCol ) );
+ r.setWidth( header()->sectionSize( currentItem()->renameCol ) - 1 );
+ if ( currentItem()->renameCol == 0 )
+ r.setLeft( r.left() + itemMargin() + ( currentItem()->depth() +
+ ( rootIsDecorated() ? 1 : 0 ) ) * treeStepSize() - 1 );
+ if ( currentItem()->pixmap( currentItem()->renameCol ) )
+ r.setLeft( r.left() + currentItem()->pixmap( currentItem()->renameCol )->width() );
+ if ( r.x() - contentsX() < 0 )
+ r.setX( contentsX() );
+ if ( r.width() > visibleWidth() )
+ r.setWidth( visibleWidth() );
+ addChild( currentItem()->renameBox, r.x(), r.y() );
+ currentItem()->renameBox->resize( r.size() );
+ }
+}
+
+
+/*
+ Very smart internal slot that repaints \e only the items that need
+ to be repainted. Don't use this directly; call repaintItem()
+ instead.
+*/
+
+void QListView::updateDirtyItems()
+{
+ if ( d->timer->isActive() || !d->dirtyItems )
+ return;
+ QRect ir;
+ QPtrDictIterator<void> it( *(d->dirtyItems) );
+ QListViewItem * i;
+ while( (i = (QListViewItem *)(it.currentKey())) != 0 ) {
+ ++it;
+ ir = ir.unite( itemRect(i) );
+ }
+ if ( !ir.isEmpty() ) { // rectangle to be repainted
+ if ( ir.x() < 0 )
+ ir.moveBy( -ir.x(), 0 );
+ viewport()->repaint( ir, FALSE );
+ }
+}
+
+
+void QListView::makeVisible()
+{
+ if ( d->focusItem )
+ ensureItemVisible( d->focusItem );
+}
+
+
+/*!
+ Ensures that the header is correctly sized and positioned when the
+ resize event \a e occurs.
+*/
+
+void QListView::resizeEvent( QResizeEvent *e )
+{
+ QScrollView::resizeEvent( e );
+ d->fullRepaintOnComlumnChange = TRUE;
+ d->h->resize( visibleWidth(), d->h->height() );
+}
+
+/*! \reimp */
+
+void QListView::viewportResizeEvent( QResizeEvent *e )
+{
+ QScrollView::viewportResizeEvent( e );
+ d->h->resize( visibleWidth(), d->h->height() );
+ if ( resizeMode() != NoColumn && currentItem() && currentItem()->renameBox ) {
+ QRect r = itemRect( currentItem() );
+ r = QRect( viewportToContents( r.topLeft() ), r.size() );
+ r.setLeft( header()->sectionPos( currentItem()->renameCol ) );
+ r.setWidth( header()->sectionSize( currentItem()->renameCol ) - 1 );
+ if ( currentItem()->renameCol == 0 )
+ r.setLeft( r.left() + itemMargin() + ( currentItem()->depth() +
+ ( rootIsDecorated() ? 1 : 0 ) ) * treeStepSize() - 1 );
+ if ( currentItem()->pixmap( currentItem()->renameCol ) )
+ r.setLeft( r.left() + currentItem()->pixmap( currentItem()->renameCol )->width() );
+ if ( r.x() - contentsX() < 0 )
+ r.setX( contentsX() );
+ if ( r.width() > visibleWidth() )
+ r.setWidth( visibleWidth() );
+ addChild( currentItem()->renameBox, r.x(), r.y() );
+ currentItem()->renameBox->resize( r.size() );
+ }
+}
+
+/*!
+ Triggers a size, geometry and content update during the next
+ iteration of the event loop. Ensures that there'll be just one
+ update to avoid flicker.
+*/
+
+void QListView::triggerUpdate()
+{
+ if ( !isVisible() || !isUpdatesEnabled() ) {
+ // Not in response to a setText/setPixmap any more.
+ d->useDoubleBuffer = FALSE;
+
+ return; // it will update when shown, or something.
+ }
+
+ d->timer->start( 0, TRUE );
+}
+
+
+/*!
+ Redirects the event \a e relating to object \a o, for the viewport
+ to mousePressEvent(), keyPressEvent() and friends.
+*/
+
+bool QListView::eventFilter( QObject * o, QEvent * e )
+{
+ if ( o == d->h &&
+ e->type() >= QEvent::MouseButtonPress &&
+ e->type() <= QEvent::MouseMove ) {
+ QMouseEvent * me = (QMouseEvent *)e;
+ QMouseEvent me2( me->type(),
+ QPoint( me->pos().x(),
+ me->pos().y() - d->h->height() ),
+ me->button(), me->state() );
+ switch( me2.type() ) {
+ case QEvent::MouseButtonDblClick:
+ if ( me2.button() == RightButton )
+ return TRUE;
+ break;
+ case QEvent::MouseMove:
+ if ( me2.state() & RightButton ) {
+ viewportMouseMoveEvent( &me2 );
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if ( o == viewport() ) {
+ QFocusEvent * fe = (QFocusEvent *)e;
+
+ switch( e->type() ) {
+ case QEvent::FocusIn:
+ focusInEvent( fe );
+ return TRUE;
+ case QEvent::FocusOut:
+ focusOutEvent( fe );
+ return TRUE;
+ default:
+ // nothing
+ break;
+ }
+ } else if ( ::qt_cast<QLineEdit*>(o) ) {
+ if ( currentItem() && currentItem()->renameBox ) {
+ if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ if ( ke->key() == Key_Return ||
+ ke->key() == Key_Enter ) {
+ currentItem()->okRename( currentItem()->renameCol );
+ return TRUE;
+ } else if ( ke->key() == Key_Escape ) {
+ currentItem()->cancelRename( currentItem()->renameCol );
+ return TRUE;
+ }
+ } else if ( e->type() == QEvent::FocusOut ) {
+ if ( ( (QFocusEvent*)e )->reason() != QFocusEvent::Popup ) {
+ QCustomEvent *e = new QCustomEvent( 9999 );
+ QApplication::postEvent( o, e );
+ return TRUE;
+ }
+ } else if ( e->type() == 9999 ) {
+ if ( d->defRenameAction == Reject )
+ currentItem()->cancelRename( currentItem()->renameCol );
+ else
+ currentItem()->okRename( currentItem()->renameCol );
+ return TRUE;
+ }
+ }
+ }
+
+ return QScrollView::eventFilter( o, e );
+}
+
+
+/*!
+ Returns a pointer to the list view containing this item.
+
+ Note that this function traverses the items to the root to find the
+ listview. This function will return 0 for taken items - see
+ QListViewItem::takeItem()
+*/
+
+QListView * QListViewItem::listView() const
+{
+ const QListViewItem* c = this;
+ while ( c && !c->is_root )
+ c = c->parentItem;
+ if ( !c )
+ return 0;
+ return ((QListViewPrivate::Root*)c)->theListView();
+}
+
+
+/*!
+ Returns the depth of this item.
+*/
+int QListViewItem::depth() const
+{
+ return parentItem ? parentItem->depth()+1 : -1; // -1 == the hidden root
+}
+
+
+/*!
+ Returns a pointer to the item immediately above this item on the
+ screen. This is usually the item's closest older sibling, but it
+ may also be its parent or its next older sibling's youngest child,
+ or something else if anyoftheabove->height() returns 0. Returns 0
+ if there is no item immediately above this item.
+
+ This function assumes that all parents of this item are open (i.e.
+ that this item is visible, or can be made visible by scrolling).
+
+ This function might be relatively slow because of the tree
+ traversions needed to find the correct item.
+
+ \sa itemBelow() QListView::itemRect()
+*/
+
+QListViewItem * QListViewItem::itemAbove()
+{
+ if ( !parentItem )
+ return 0;
+
+ QListViewItem * c = parentItem;
+ if ( c->childItem != this ) {
+ c = c->childItem;
+ while( c && c->siblingItem != this )
+ c = c->siblingItem;
+ if ( !c )
+ return 0;
+ while( c->isOpen() && c->childItem ) {
+ c = c->childItem;
+ while( c->siblingItem )
+ c = c->siblingItem; // assign c's sibling to c
+ }
+ }
+ if ( c && ( !c->height() || !c->isEnabled() ) )
+ return c->itemAbove();
+ return c;
+}
+
+
+/*!
+ Returns a pointer to the item immediately below this item on the
+ screen. This is usually the item's eldest child, but it may also
+ be its next younger sibling, its parent's next younger sibling,
+ grandparent's, etc., or something else if anyoftheabove->height()
+ returns 0. Returns 0 if there is no item immediately below this
+ item.
+
+ This function assumes that all parents of this item are open (i.e.
+ that this item is visible or can be made visible by scrolling).
+
+ \sa itemAbove() QListView::itemRect()
+*/
+
+QListViewItem * QListViewItem::itemBelow()
+{
+ QListViewItem * c = 0;
+ if ( isOpen() && childItem ) {
+ c = childItem;
+ } else if ( siblingItem ) {
+ c = siblingItem;
+ } else if ( parentItem ) {
+ c = this;
+ do {
+ c = c->parentItem;
+ } while( c->parentItem && !c->siblingItem );
+ if ( c )
+ c = c->siblingItem;
+ }
+ if ( c && ( !c->height() || !c->isEnabled() ) )
+ return c->itemBelow();
+ return c;
+}
+
+
+/*!
+ \fn bool QListViewItem::isOpen () const
+
+ Returns TRUE if this list view item has children \e and they are
+ not explicitly hidden; otherwise returns FALSE.
+
+ \sa setOpen()
+*/
+
+/*!
+ Returns the first (top) child of this item, or 0 if this item has
+ no children.
+
+ Note that the children are not guaranteed to be sorted properly.
+ QListView and QListViewItem try to postpone or avoid sorting to
+ the greatest degree possible, in order to keep the user interface
+ snappy.
+
+ \sa nextSibling() sortChildItems()
+*/
+
+QListViewItem* QListViewItem::firstChild() const
+{
+ enforceSortOrder();
+ return childItem;
+}
+
+
+/*!
+ Returns the parent of this item, or 0 if this item has no parent.
+
+ \sa firstChild(), nextSibling()
+*/
+
+QListViewItem* QListViewItem::parent() const
+{
+ if ( !parentItem || parentItem->is_root ) return 0;
+ return parentItem;
+}
+
+
+/*!
+ \fn QListViewItem* QListViewItem::nextSibling() const
+
+ Returns the sibling item below this item, or 0 if there is no
+ sibling item after this item.
+
+ Note that the siblings are not guaranteed to be sorted properly.
+ QListView and QListViewItem try to postpone or avoid sorting to
+ the greatest degree possible, in order to keep the user interface
+ snappy.
+
+ \sa firstChild() sortChildItems()
+*/
+
+/*!
+ \fn int QListViewItem::childCount () const
+
+ Returns how many children this item has. The count only includes
+ the item's immediate children.
+*/
+
+
+/*!
+ Returns the height of this item in pixels. This does not include
+ the height of any children; totalHeight() returns that.
+*/
+int QListViewItem::height() const
+{
+ QListViewItem * that = (QListViewItem *)this;
+ if ( !that->configured ) {
+ that->configured = TRUE;
+ that->setup(); // ### virtual non-const function called in const
+ }
+
+ return visible ? ownHeight : 0;
+}
+
+/*!
+ Call this function when the value of width() may have changed for
+ column \a c. Normally, you should call this if text(c) changes.
+ Passing -1 for \a c indicates that all columns may have changed.
+ It is more efficient to pass -1 if two or more columns have
+ changed than to call widthChanged() separately for each one.
+
+ \sa width()
+*/
+void QListViewItem::widthChanged( int c ) const
+{
+ QListView *lv = listView();
+ if ( lv )
+ lv->widthChanged( this, c );
+}
+
+/*!
+ \fn void QListView::dropped ( QDropEvent * e )
+
+ This signal is emitted, when a drop event occurred on the
+ viewport (not onto an item).
+
+ \a e provides all the information about the drop.
+*/
+
+/*!
+ \fn void QListView::selectionChanged()
+
+ This signal is emitted whenever the set of selected items has
+ changed (normally before the screen update). It is available in
+ \c Single, \c Multi, and \c Extended selection modes, but is most
+ useful in \c Multi selection mode.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+
+ \sa setSelected() QListViewItem::setSelected()
+*/
+
+
+/*!
+ \fn void QListView::pressed( QListViewItem *item )
+
+ This signal is emitted whenever the user presses the mouse button
+ in a list view. \a item is the list view item on which the user
+ pressed the mouse button, or 0 if the user didn't press the mouse
+ on an item.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListView::pressed( QListViewItem *item, const QPoint &pnt, int c )
+
+ \overload
+
+ This signal is emitted whenever the user presses the mouse button
+ in a list view. \a item is the list view item on which the user
+ pressed the mouse button, or 0 if the user didn't press the mouse
+ on an item. \a pnt is the position of the mouse cursor in global
+ coordinates, and \a c is the column where the mouse cursor was
+ when the user pressed the mouse button.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListView::clicked( QListViewItem *item )
+
+ This signal is emitted whenever the user clicks (mouse pressed \e
+ and mouse released) in the list view. \a item is the clicked list
+ view item, or 0 if the user didn't click on an item.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListView::mouseButtonClicked(int button, QListViewItem * item, const QPoint & pos, int c)
+
+ This signal is emitted whenever the user clicks (mouse pressed \e
+ and mouse released) in the list view at position \a pos. \a button
+ is the mouse button that the user pressed, \a item is the clicked
+ list view item or 0 if the user didn't click on an item. If \a
+ item is not 0, \a c is the list view column into which the user
+ pressed; if \a item is 0 \a{c}'s value is undefined.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListView::mouseButtonPressed(int button, QListViewItem * item, const QPoint & pos, int c)
+
+ This signal is emitted whenever the user pressed the mouse button
+ in the list view at position \a pos. \a button is the mouse button
+ which the user pressed, \a item is the pressed list view item or 0
+ if the user didn't press on an item. If \a item is not 0, \a c is
+ the list view column into which the user pressed; if \a item is 0
+ \a{c}'s value is undefined.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListView::clicked( QListViewItem *item, const QPoint &pnt, int c )
+
+ \overload
+
+ This signal is emitted whenever the user clicks (mouse pressed \e
+ and mouse released) in the list view. \a item is the clicked list
+ view item, or 0 if the user didn't click on an item. \a pnt is the
+ position where the user has clicked in global coordinates. If \a
+ item is not 0, \a c is the list view column into which the user
+ pressed; if \a item is 0 \a{c}'s value is undefined.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+/*!
+ \fn void QListView::selectionChanged( QListViewItem * )
+
+ \overload
+
+ This signal is emitted whenever the selected item has changed in
+ \c Single selection mode (normally after the screen update). The
+ argument is the newly selected item. If the selection is cleared
+ (when, for example, the user clicks in the unused area of the list
+ view) then this signal will not be emitted.
+
+ In \c Multi selection mode, use the no argument overload of this
+ signal.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+
+ \sa setSelected() QListViewItem::setSelected() currentChanged()
+*/
+
+
+/*!
+ \fn void QListView::currentChanged( QListViewItem * )
+
+ This signal is emitted whenever the current item has changed
+ (normally after the screen update). The current item is the item
+ responsible for indicating keyboard focus.
+
+ The argument is the newly current item, or 0 if the change made no
+ item current. This can happen, for example, if all items in the
+ list view are deleted.
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+
+ \sa setCurrentItem() currentItem()
+*/
+
+
+/*!
+ \fn void QListView::expanded( QListViewItem *item )
+
+ This signal is emitted when \a item has been expanded, i.e. when
+ the children of \a item are shown.
+
+ \sa setOpen() collapsed()
+*/
+
+/*!
+ \fn void QListView::collapsed( QListViewItem *item )
+
+ This signal is emitted when the \a item has been collapsed, i.e.
+ when the children of \a item are hidden.
+
+ \sa setOpen() expanded()
+*/
+
+/*!
+ Processes the mouse press event \a e on behalf of the viewed widget.
+*/
+void QListView::contentsMousePressEvent( QMouseEvent * e )
+{
+ contentsMousePressEventEx( e );
+}
+
+void QListView::contentsMousePressEventEx( QMouseEvent * e )
+{
+ if ( !e )
+ return;
+
+ if ( !d->ignoreEditAfterFocus )
+ d->startEdit = TRUE;
+ d->ignoreEditAfterFocus = FALSE;
+
+ if ( currentItem() && currentItem()->renameBox &&
+ !itemRect( currentItem() ).contains( e->pos() ) ) {
+ d->startEdit = FALSE;
+ if ( d->defRenameAction == Reject )
+ currentItem()->cancelRename( currentItem()->renameCol );
+ else
+ currentItem()->okRename( currentItem()->renameCol );
+ }
+
+ d->startDragItem = 0;
+ d->dragStartPos = e->pos();
+ QPoint vp = contentsToViewport( e->pos() );
+
+ d->ignoreDoubleClick = FALSE;
+ d->buttonDown = TRUE;
+
+ QListViewItem * i = itemAt( vp );
+ d->pressedEmptyArea = e->y() > contentsHeight();
+ if ( i && !i->isEnabled() )
+ return;
+ if ( d->startEdit && ( i != currentItem() || (i && !i->isSelected()) ) )
+ d->startEdit = FALSE;
+ QListViewItem *oldCurrent = currentItem();
+
+ if ( e->button() == RightButton && (e->state() & ControlButton ) )
+ goto emit_signals;
+
+ if ( !i ) {
+ if ( !( e->state() & ControlButton ) )
+ clearSelection();
+ goto emit_signals;
+ } else {
+ // No new anchor when using shift
+ if ( !(e->state() & ShiftButton) )
+ d->selectAnchor = i;
+ }
+
+ if ( (i->isExpandable() || i->childCount()) &&
+ d->h->mapToLogical( d->h->cellAt( vp.x() ) ) == 0 ) {
+ int x1 = vp.x() +
+ d->h->offset() -
+ d->h->cellPos( d->h->mapToActual( 0 ) );
+ QPtrListIterator<QListViewPrivate::DrawableItem> it( *(d->drawables) );
+ while( it.current() && it.current()->i != i )
+ ++it;
+
+ if ( it.current() ) {
+ x1 -= treeStepSize() * (it.current()->l - 1);
+ QStyle::SubControl ctrl =
+ style().querySubControl( QStyle::CC_ListView,
+ this, QPoint(x1, e->pos().y()),
+ QStyleOption(i) );
+ if( ctrl == QStyle::SC_ListViewExpand &&
+ e->type() == style().styleHint(QStyle::SH_ListViewExpand_SelectMouseType, this)) {
+ d->buttonDown = FALSE;
+ if ( e->button() == LeftButton ) {
+ bool close = i->isOpen();
+ setOpen( i, !close );
+ // ### Looks dangerous, removed because of reentrance problems
+ // qApp->processEvents();
+ if ( !d->focusItem ) {
+ d->focusItem = i;
+ repaintItem( d->focusItem );
+ emit currentChanged( d->focusItem );
+ }
+ if ( close ) {
+ bool newCurrent = FALSE;
+ QListViewItem *ci = d->focusItem;
+ while ( ci ) {
+ if ( ci->parent() && ci->parent() == i ) {
+ newCurrent = TRUE;
+ break;
+ }
+ ci = ci->parent();
+ }
+ if ( newCurrent ) {
+ setCurrentItem( i );
+ }
+ }
+ }
+ d->ignoreDoubleClick = TRUE;
+ d->buttonDown = FALSE;
+ goto emit_signals;
+ }
+ }
+ }
+
+ d->select = d->selectionMode == Multi ? !i->isSelected() : TRUE;
+
+ {// calculate activatedP
+ activatedByClick = TRUE;
+ QPoint topLeft = itemRect( i ).topLeft(); //### inefficient?
+ activatedP = vp - topLeft;
+ int xdepth = treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0))
+ + itemMargin();
+
+ // This returns the position of the first visual section?!? Shouldn't that always be 0? Keep it just in case we have missed something.
+ xdepth += d->h->sectionPos( d->h->mapToSection( 0 ) );
+ activatedP.rx() -= xdepth;
+ }
+ i->activate();
+ activatedByClick = FALSE;
+
+ if ( i != d->focusItem )
+ setCurrentItem( i );
+ else
+ repaintItem( i );
+
+ d->pressedSelected = i && i->isSelected();
+
+ if ( i->isSelectable() && selectionMode() != NoSelection ) {
+ if ( selectionMode() == Single )
+ setSelected( i, TRUE );
+ else if ( selectionMode() == Multi )
+ setSelected( i, d->select );
+ else if ( selectionMode() == Extended ) {
+ bool changed = FALSE;
+ if ( !(e->state() & (ControlButton | ShiftButton)) ) {
+ if ( !i->isSelected() ) {
+ bool blocked = signalsBlocked();
+ blockSignals( TRUE );
+ clearSelection();
+ blockSignals( blocked );
+ i->setSelected( TRUE );
+ changed = TRUE;
+ }
+ } else {
+ if ( e->state() & ShiftButton )
+ d->pressedSelected = FALSE;
+ if ( (e->state() & ControlButton) && !(e->state() & ShiftButton) && i ) {
+ i->setSelected( !i->isSelected() );
+ changed = TRUE;
+ d->pressedSelected = FALSE;
+ } else if ( !oldCurrent || !i || oldCurrent == i ) {
+ if ( (bool)i->selected != d->select ) {
+ changed = TRUE;
+ i->setSelected( d->select );
+ }
+ // Shift pressed in Extended mode ---
+ } else {
+ changed = selectRange( i, oldCurrent, d->selectAnchor );
+ }
+ }
+ if ( changed ) {
+ d->useDoubleBuffer = TRUE;
+ triggerUpdate();
+ emit selectionChanged();
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+#endif
+ }
+ }
+ }
+
+ emit_signals:
+
+ if ( i && !d->buttonDown &&
+ vp.x() + contentsX() < itemMargin() + ( i->depth() + ( rootIsDecorated() ? 1 : 0 ) ) * treeStepSize() )
+ i = 0;
+ d->pressedItem = i;
+
+ int c = i ? d->h->mapToLogical( d->h->cellAt( vp.x() ) ) : -1;
+ if ( !i || ( i && i->isEnabled() ) ) {
+ emit pressed( i );
+ emit pressed( i, viewport()->mapToGlobal( vp ), c );
+ }
+ emit mouseButtonPressed( e->button(), i, viewport()->mapToGlobal( vp ), c );
+
+ if ( e->button() == RightButton && i == d->pressedItem ) {
+ if ( !i && !(e->state() & ControlButton) )
+ clearSelection();
+
+ emit rightButtonPressed( i, viewport()->mapToGlobal( vp ), c );
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QListView::contentsContextMenuEvent( QContextMenuEvent *e )
+{
+ if ( !receivers( SIGNAL(contextMenuRequested(QListViewItem*,const QPoint&,int)) ) ) {
+ e->ignore();
+ return;
+ }
+ if ( e->reason() == QContextMenuEvent::Keyboard ) {
+ QListViewItem *item = currentItem();
+ if ( item ) {
+ QRect r = itemRect( item );
+ QPoint p = r.topLeft();
+ if ( allColumnsShowFocus() )
+ p += QPoint( width() / 2, ( r.height() / 2 ) );
+ else
+ p += QPoint( columnWidth( 0 ) / 2, ( r.height() / 2 ) );
+ p.rx() = QMAX( 0, p.x() );
+ p.rx() = QMIN( visibleWidth(), p.x() );
+ emit contextMenuRequested( item, viewport()->mapToGlobal( p ), -1 );
+ }
+ } else {
+ QPoint vp = contentsToViewport( e->pos() );
+ QListViewItem * i = itemAt( vp );
+ int c = i ? d->h->mapToLogical( d->h->cellAt( vp.x() ) ) : -1;
+ emit contextMenuRequested( i, viewport()->mapToGlobal( vp ), c );
+ }
+}
+
+/*!
+ Processes the mouse release event \a e on behalf of the viewed widget.
+*/
+void QListView::contentsMouseReleaseEvent( QMouseEvent * e )
+{
+ contentsMouseReleaseEventEx( e );
+}
+
+void QListView::contentsMouseReleaseEventEx( QMouseEvent * e )
+{
+ d->startDragItem = 0;
+ bool emitClicked = !d->pressedItem || d->buttonDown;
+ d->buttonDown = FALSE;
+ // delete and disconnect autoscroll timer, if we have one
+ if ( d->scrollTimer ) {
+ disconnect( d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()) );
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+
+ if ( !e )
+ return;
+
+ if ( d->selectionMode == Extended &&
+ d->focusItem == d->pressedItem &&
+ d->pressedSelected && d->focusItem &&
+ e->button() == LeftButton) {
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ clearSelection();
+ blockSignals( block );
+ d->focusItem->setSelected( TRUE );
+ emit selectionChanged();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::Selection );
+#endif
+ }
+
+ QPoint vp = contentsToViewport(e->pos());
+ QListViewItem *i = itemAt( vp );
+ if ( i && !i->isEnabled() )
+ return;
+
+ if ( i && i == d->pressedItem && (i->isExpandable() || i->childCount()) &&
+ !d->h->mapToLogical( d->h->cellAt( vp.x() ) ) && e->button() == LeftButton &&
+ e->type() == style().styleHint(QStyle::SH_ListViewExpand_SelectMouseType, this)) {
+ QPtrListIterator<QListViewPrivate::DrawableItem> it( *(d->drawables) );
+ while( it.current() && it.current()->i != i )
+ ++it;
+ if ( it.current() ) {
+ int x1 = vp.x() + d->h->offset() - d->h->cellPos( d->h->mapToActual( 0 ) ) -
+ (treeStepSize() * (it.current()->l - 1));
+ QStyle::SubControl ctrl = style().querySubControl( QStyle::CC_ListView,
+ this, QPoint(x1, e->pos().y()),
+ QStyleOption(i) );
+ if( ctrl == QStyle::SC_ListViewExpand ) {
+ bool close = i->isOpen();
+ setOpen( i, !close );
+ // ### Looks dangerous, removed because of reentrance problems
+ // qApp->processEvents();
+ if ( !d->focusItem ) {
+ d->focusItem = i;
+ repaintItem( d->focusItem );
+ emit currentChanged( d->focusItem );
+ }
+ if ( close ) {
+ bool newCurrent = FALSE;
+ QListViewItem *ci = d->focusItem;
+ while ( ci ) {
+ if ( ci->parent() && ci->parent() == i ) {
+ newCurrent = TRUE;
+ break;
+ }
+ ci = ci->parent();
+ }
+ if ( newCurrent )
+ setCurrentItem( i );
+ d->ignoreDoubleClick = TRUE;
+ }
+ }
+ }
+ }
+
+ if ( i == d->pressedItem && i && i->isSelected() && e->button() == LeftButton && d->startEdit ) {
+ QRect r = itemRect( currentItem() );
+ r = QRect( viewportToContents( r.topLeft() ), r.size() );
+ d->pressedColumn = header()->sectionAt( e->pos().x() );
+ r.setLeft( header()->sectionPos( d->pressedColumn ) );
+ r.setWidth( header()->sectionSize( d->pressedColumn ) - 1 );
+ if ( d->pressedColumn == 0 )
+ r.setLeft( r.left() + itemMargin() + ( currentItem()->depth() +
+ ( rootIsDecorated() ? 1 : 0 ) ) * treeStepSize() - 1 );
+ if ( r.contains( e->pos() ) &&
+ !( e->state() & ( ShiftButton | ControlButton ) ) )
+ d->renameTimer->start( QApplication::doubleClickInterval(), TRUE );
+ }
+ // Check if we are clicking at the root decoration.
+ int rootColumnPos = d->h->sectionPos( 0 );
+ if ( i && vp.x() + contentsX() < rootColumnPos + itemMargin() + ( i->depth() + ( rootIsDecorated() ? 1 : 0 ) ) * treeStepSize()
+ && vp.x() + contentsX() > rootColumnPos ) {
+ i = 0;
+ }
+ emitClicked = emitClicked && d->pressedItem == i;
+ d->pressedItem = 0;
+ d->highlighted = 0;
+
+ if ( emitClicked ) {
+ if ( !i || ( i && i->isEnabled() ) ) {
+ emit clicked( i );
+ emit clicked( i, viewport()->mapToGlobal( vp ), d->h->mapToLogical( d->h->cellAt( vp.x() ) ) );
+ }
+ emit mouseButtonClicked( e->button(), i, viewport()->mapToGlobal( vp ),
+ i ? d->h->mapToLogical( d->h->cellAt( vp.x() ) ) : -1 );
+
+ if ( e->button() == RightButton ) {
+ if ( !i ) {
+ if ( !(e->state() & ControlButton) )
+ clearSelection();
+ emit rightButtonClicked( 0, viewport()->mapToGlobal( vp ), -1 );
+ return;
+ }
+
+ int c = d->h->mapToLogical( d->h->cellAt( vp.x() ) );
+ emit rightButtonClicked( i, viewport()->mapToGlobal( vp ), c );
+ }
+ }
+}
+
+
+/*!
+ Processes the mouse double-click event \a e on behalf of the viewed widget.
+*/
+void QListView::contentsMouseDoubleClickEvent( QMouseEvent * e )
+{
+ d->renameTimer->stop();
+ d->startEdit = FALSE;
+ if ( !e || e->button() != LeftButton )
+ return;
+
+ // ensure that the following mouse moves and eventual release is
+ // ignored.
+ d->buttonDown = FALSE;
+
+ if ( d->ignoreDoubleClick ) {
+ d->ignoreDoubleClick = FALSE;
+ return;
+ }
+
+ QPoint vp = contentsToViewport(e->pos());
+
+ QListViewItem * i = itemAt( vp );
+
+ // we emit doubleClicked when the item is null (or enabled) to be consistent with
+ // rightButtonClicked etc.
+ if ( !i || i->isEnabled() ) {
+ int c = d->h->mapToLogical( d->h->cellAt( vp.x() ) );
+ emit doubleClicked( i, viewport()->mapToGlobal( vp ), c );
+ }
+
+ if ( !i || !i->isEnabled() )
+ return;
+
+ if ( !i->isOpen() ) {
+ if ( i->isExpandable() || i->childCount() )
+ setOpen( i, TRUE );
+ } else {
+ setOpen( i, FALSE );
+ }
+
+ // we emit the 'old' obsolete doubleClicked only if the item is not null and enabled
+ emit doubleClicked( i );
+}
+
+
+/*!
+ Processes the mouse move event \a e on behalf of the viewed widget.
+*/
+void QListView::contentsMouseMoveEvent( QMouseEvent * e )
+{
+ if ( !e )
+ return;
+
+ bool needAutoScroll = FALSE;
+
+ QPoint vp = contentsToViewport(e->pos());
+
+ QListViewItem * i = itemAt( vp );
+ if ( i && !i->isEnabled() )
+ return;
+ if ( i != d->highlighted &&
+ !(d->pressedItem &&
+ ( d->pressedItem->isSelected() || d->selectionMode == NoSelection ) &&
+ d->pressedItem->dragEnabled() )) {
+
+ if ( i ) {
+ emit onItem( i );
+ } else {
+ emit onViewport();
+ }
+ d->highlighted = i;
+ }
+
+ if ( d->startDragItem )
+ i = d->startDragItem;
+
+ if ( !d->buttonDown ||
+ ( ( e->state() & LeftButton ) != LeftButton &&
+ ( e->state() & MidButton ) != MidButton &&
+ ( e->state() & RightButton ) != RightButton ) )
+ return;
+
+ if ( d->pressedItem &&
+ ( d->pressedItem->isSelected() || d->selectionMode == NoSelection ) &&
+ d->pressedItem->dragEnabled() ) {
+
+ if ( !d->startDragItem ) {
+ setSelected( d->pressedItem, TRUE );
+ d->startDragItem = d->pressedItem;
+ }
+ if ( ( d->dragStartPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) {
+ d->buttonDown = FALSE;
+#ifndef QT_NO_DRAGANDDROP
+ startDrag();
+#endif
+ }
+ return;
+ }
+
+ // check, if we need to scroll
+ if ( vp.y() > visibleHeight() || vp.y() < 0 )
+ needAutoScroll = TRUE;
+
+ // if we need to scroll and no autoscroll timer is started,
+ // connect the timer
+ if ( needAutoScroll && !d->scrollTimer ) {
+ d->scrollTimer = new QTimer( this );
+ connect( d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()) );
+ d->scrollTimer->start( 100, FALSE );
+ // call it once manually
+ doAutoScroll( vp );
+ }
+
+ // if we don't need to autoscroll
+ if ( !needAutoScroll ) {
+ // if there is a autoscroll timer, delete it
+ if ( d->scrollTimer ) {
+ disconnect( d->scrollTimer, SIGNAL(timeout()),
+ this, SLOT(doAutoScroll()) );
+ d->scrollTimer->stop();
+ delete d->scrollTimer;
+ d->scrollTimer = 0;
+ }
+ // call this to select an item ( using the pos from the event )
+ doAutoScroll( vp );
+ }
+}
+
+
+/*!
+ This slot handles auto-scrolling when the mouse button is pressed
+ and the mouse is outside the widget.
+*/
+void QListView::doAutoScroll()
+{
+ doAutoScroll( QPoint() );
+}
+
+/*
+ Handles auto-scrolling when the mouse button is pressed
+ and the mouse is outside the widget.
+
+ If cursorPos is (0,0) (isNull == TRUE) it uses the current QCursor::pos, otherwise it uses cursorPos
+*/
+void QListView::doAutoScroll( const QPoint &cursorPos )
+{
+ QPoint pos = cursorPos.isNull() ? viewport()->mapFromGlobal( QCursor::pos() ) : cursorPos;
+ if ( !d->focusItem || ( d->pressedEmptyArea && pos.y() > contentsHeight() ) )
+ return;
+
+ bool down = pos.y() > itemRect( d->focusItem ).y();
+
+ int g = pos.y() + contentsY();
+
+ if ( down && pos.y() > height() )
+ g = height() + contentsY();
+ else if ( pos.y() < 0 )
+ g = contentsY();
+
+ QListViewItem *c = d->focusItem, *old = 0;
+ QListViewItem *oldCurrent = c;
+ if ( down ) {
+ int y = itemRect( d->focusItem ).y() + contentsY();
+ while( c && y + c->height() <= g ) {
+ y += c->height();
+ old = c;
+ c = c->itemBelow();
+ }
+ if ( !c && old )
+ c = old;
+ } else {
+ int y = itemRect( d->focusItem ).y() + contentsY();
+ while( c && y >= g ) {
+ old = c;
+ c = c->itemAbove();
+ if ( c )
+ y -= c->height();
+ }
+ if ( !c && old )
+ c = old;
+ }
+
+ if ( !c || c == d->focusItem )
+ return;
+
+ if ( d->focusItem ) {
+ if ( d->selectionMode == Multi ) {
+ // also (de)select the ones in between
+ QListViewItem * b = d->focusItem;
+ bool down = ( itemPos( c ) > itemPos( b ) );
+ while( b && b != c ) {
+ if ( b->isSelectable() )
+ setSelected( b, d->select );
+ b = down ? b->itemBelow() : b->itemAbove();
+ }
+ if ( c->isSelectable() )
+ setSelected( c, d->select );
+ } else if ( d->selectionMode == Extended ) {
+ if ( selectRange( c, oldCurrent, d->selectAnchor ) ) {
+ d->useDoubleBuffer = TRUE;
+ triggerUpdate();
+ emit selectionChanged();
+ }
+ }
+ }
+
+ setCurrentItem( c );
+ d->visibleTimer->start( 1, TRUE );
+}
+
+/*!
+ \reimp
+*/
+
+void QListView::focusInEvent( QFocusEvent* )
+{
+ d->inMenuMode = FALSE;
+ if ( d->focusItem ) {
+ repaintItem( d->focusItem );
+ } else if ( firstChild() && QFocusEvent::reason() != QFocusEvent::Mouse ) {
+ d->focusItem = firstChild();
+ emit currentChanged( d->focusItem );
+ repaintItem( d->focusItem );
+ }
+ if ( QFocusEvent::reason() == QFocusEvent::Mouse ) {
+ d->ignoreEditAfterFocus = TRUE;
+ d->startEdit = FALSE;
+ }
+ if ( style().styleHint( QStyle::SH_ItemView_ChangeHighlightOnFocus, this ) ) {
+ bool db = d->useDoubleBuffer;
+ d->useDoubleBuffer = TRUE;
+ viewport()->repaint( FALSE );
+ d->useDoubleBuffer = db;
+ }
+
+ QRect mfrect = itemRect( d->focusItem );
+ if ( mfrect.isValid() ) {
+ if ( header() && header()->isVisible() )
+ setMicroFocusHint( mfrect.x(), mfrect.y()+header()->height(), mfrect.width(), mfrect.height(), FALSE );
+ else
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+
+void QListView::focusOutEvent( QFocusEvent* )
+{
+ if ( QFocusEvent::reason() == QFocusEvent::Popup && d->buttonDown )
+ d->buttonDown = FALSE;
+ if ( style().styleHint( QStyle::SH_ItemView_ChangeHighlightOnFocus, this ) ) {
+ d->inMenuMode =
+ QFocusEvent::reason() == QFocusEvent::Popup
+ || (qApp->focusWidget() && qApp->focusWidget()->inherits("QMenuBar"));
+ if ( !d->inMenuMode ) {
+ bool db = d->useDoubleBuffer;
+ d->useDoubleBuffer = TRUE;
+ viewport()->repaint( FALSE );
+ d->useDoubleBuffer = db;
+ }
+ }
+
+ if ( d->focusItem )
+ repaintItem( d->focusItem );
+}
+
+
+/*!
+ \reimp
+*/
+
+void QListView::keyPressEvent( QKeyEvent * e )
+{
+ if (currentItem() && currentItem()->renameBox)
+ return;
+ if (!firstChild()) {
+ e->ignore();
+ return; // subclass bug
+ }
+
+ QListViewItem* oldCurrent = currentItem();
+ if ( !oldCurrent ) {
+ setCurrentItem( firstChild() );
+ if ( d->selectionMode == Single )
+ setSelected( firstChild(), TRUE );
+ return;
+ }
+
+ QListViewItem * i = currentItem();
+ QListViewItem *old = i;
+
+ QRect r( itemRect( i ) );
+ QListViewItem * i2;
+
+ bool singleStep = FALSE;
+ bool selectCurrent = TRUE;
+ bool wasNavigation = TRUE;
+
+ switch( e->key() ) {
+ case Key_Backspace:
+ case Key_Delete:
+ d->currentPrefix.truncate( 0 );
+ break;
+ case Key_Enter:
+ case Key_Return:
+ d->currentPrefix.truncate( 0 );
+ if ( i && !i->isSelectable() && i->isEnabled() &&
+ ( i->childCount() || i->isExpandable() || i->isOpen() ) ) {
+ i->setOpen( !i->isOpen() );
+ return;
+ }
+ e->ignore();
+ if ( currentItem() && !currentItem()->isEnabled() )
+ break;
+ emit returnPressed( currentItem() );
+ // do NOT accept. QDialog.
+ return;
+ case Key_Down:
+ selectCurrent = FALSE;
+ i = i->itemBelow();
+ d->currentPrefix.truncate( 0 );
+ singleStep = TRUE;
+ break;
+ case Key_Up:
+ selectCurrent = FALSE;
+ i = i->itemAbove();
+ d->currentPrefix.truncate( 0 );
+ singleStep = TRUE;
+ break;
+ case Key_Home:
+ selectCurrent = FALSE;
+ i = firstChild();
+ if (!i->height() || !i->isEnabled())
+ i = i->itemBelow();
+ d->currentPrefix.truncate( 0 );
+ break;
+ case Key_End:
+ selectCurrent = FALSE;
+ i = firstChild();
+ while (i->nextSibling() && i->nextSibling()->height() && i->nextSibling()->isEnabled())
+ i = i->nextSibling();
+ while ( i->itemBelow() )
+ i = i->itemBelow();
+ d->currentPrefix.truncate( 0 );
+ break;
+ case Key_Next:
+ selectCurrent = FALSE;
+ i2 = itemAt( QPoint( 0, visibleHeight()-1 ) );
+ if ( i2 == i || !r.isValid() ||
+ visibleHeight() <= itemRect( i ).bottom() ) {
+ if ( i2 )
+ i = i2;
+ int left = visibleHeight();
+ while( (i2 = i->itemBelow()) != 0 && left > i2->height() ) {
+ left -= i2->height();
+ i = i2;
+ }
+ } else {
+ if ( !i2 ) {
+ // list is shorter than the view, goto last item
+ while( (i2 = i->itemBelow()) != 0 )
+ i = i2;
+ } else {
+ i = i2;
+ }
+ }
+ d->currentPrefix.truncate( 0 );
+ break;
+ case Key_Prior:
+ selectCurrent = FALSE;
+ i2 = itemAt( QPoint( 0, 0 ) );
+ if ( i == i2 || !r.isValid() || r.top() <= 0 ) {
+ if ( i2 )
+ i = i2;
+ int left = visibleHeight();
+ while( (i2 = i->itemAbove()) != 0 && left > i2->height() ) {
+ left -= i2->height();
+ i = i2;
+ }
+ } else {
+ i = i2;
+ }
+ d->currentPrefix.truncate( 0 );
+ break;
+ case Key_Plus:
+ d->currentPrefix.truncate( 0 );
+ if ( !i->isOpen() && (i->isExpandable() || i->childCount()) )
+ setOpen( i, TRUE );
+ else
+ return;
+ break;
+ case Key_Right:
+ d->currentPrefix.truncate( 0 );
+ if ( i->isOpen() && i->childItem) {
+ QListViewItem *childItem = i->childItem;
+ while (childItem && !childItem->isVisible())
+ childItem = childItem->nextSibling();
+ if (childItem)
+ i = childItem;
+ } else if ( !i->isOpen() && (i->isExpandable() || i->childCount()) ) {
+ setOpen( i, TRUE );
+ } else if ( contentsX() + visibleWidth() < contentsWidth() ) {
+ horizontalScrollBar()->addLine();
+ return;
+ } else {
+ return;
+ }
+ break;
+ case Key_Minus:
+ d->currentPrefix.truncate( 0 );
+ if ( i->isOpen() )
+ setOpen( i, FALSE );
+ else
+ return;
+ break;
+ case Key_Left:
+ d->currentPrefix.truncate( 0 );
+ if ( i->isOpen() ) {
+ setOpen( i, FALSE );
+ } else if ( i->parentItem && i->parentItem != d->r ) {
+ i = i->parentItem;
+ } else if ( contentsX() ) {
+ horizontalScrollBar()->subtractLine();
+ return;
+ } else {
+ return;
+ }
+ break;
+ case Key_Space:
+ activatedByClick = FALSE;
+ d->currentPrefix.truncate( 0 );
+ if ( currentItem() && !currentItem()->isEnabled() )
+ break;
+ i->activate();
+ if ( i->isSelectable() && ( d->selectionMode == Multi || d->selectionMode == Extended ) ) {
+ setSelected( i, !i->isSelected() );
+ d->currentPrefix.truncate( 0 );
+ }
+ emit spacePressed( currentItem() );
+ break;
+ case Key_Escape:
+ e->ignore(); // For QDialog
+ return;
+ case Key_F2:
+ if ( currentItem() && currentItem()->renameEnabled( 0 ) )
+ currentItem()->startRename( 0 );
+ default:
+ if ( e->text().length() > 0 && e->text()[ 0 ].isPrint() ) {
+ selectCurrent = FALSE;
+ wasNavigation = FALSE;
+ QString input( d->currentPrefix );
+ QListViewItem * keyItem = i;
+ QTime now( QTime::currentTime() );
+ bool tryFirst = TRUE;
+ while( keyItem ) {
+ // try twice, first with the previous string and this char
+ if ( d->currentPrefixTime.msecsTo( now ) <= 400 )
+ input = input + e->text().lower();
+ else
+ input = e->text().lower();
+ if ( input.length() == e->text().length() ) {
+ if ( keyItem->itemBelow() ) {
+ keyItem = keyItem->itemBelow();
+ tryFirst = TRUE;
+ } else {
+ keyItem = firstChild();
+ tryFirst = FALSE;
+ }
+ }
+ QString keyItemKey;
+ QString prefix;
+ while( keyItem ) {
+ keyItemKey = QString::null;
+ // Look first in the sort column, then left to right
+ if (d->sortcolumn != Unsorted)
+ keyItemKey = keyItem->text(d->sortcolumn);
+ for ( int col = 0; col < d->h->count() && keyItemKey.isNull(); ++col )
+ keyItemKey = keyItem->text( d->h->mapToSection(col) );
+ if ( !keyItemKey.isEmpty() ) {
+ prefix = keyItemKey;
+ prefix.truncate( input.length() );
+ prefix = prefix.lower();
+ if ( prefix == input ) {
+ d->currentPrefix = input;
+ d->currentPrefixTime = now;
+ i = keyItem;
+ // nonoptimal double-break...
+ keyItem = 0;
+ input.truncate( 0 );
+ tryFirst = FALSE;
+ }
+ }
+ if ( keyItem )
+ keyItem = keyItem->itemBelow();
+ if ( !keyItem && tryFirst ) {
+ keyItem = firstChild();
+ tryFirst = FALSE;
+ }
+ }
+ // then, if appropriate, with just this character
+ if ( input.length() > e->text().length() ) {
+ input.truncate(0);
+ keyItem = i;
+ }
+ }
+ } else {
+ d->currentPrefix.truncate( 0 );
+ if ( e->state() & ControlButton ) {
+ d->currentPrefix = QString::null;
+ switch ( e->key() ) {
+ case Key_A:
+ selectAll( TRUE );
+ break;
+ }
+ }
+ e->ignore();
+ return;
+ }
+ }
+
+ if ( !i )
+ return;
+
+ if ( !( e->state() & ShiftButton ) || !d->selectAnchor )
+ d->selectAnchor = i;
+
+ setCurrentItem( i );
+ if ( i->isSelectable() )
+ handleItemChange( old, wasNavigation && (e->state() & ShiftButton),
+ wasNavigation && (e->state() & ControlButton) );
+
+ if ( d->focusItem && !d->focusItem->isSelected() && d->selectionMode == Single && selectCurrent )
+ setSelected( d->focusItem, TRUE );
+
+ if ( singleStep )
+ d->visibleTimer->start( 1, TRUE );
+ else
+ ensureItemVisible( i );
+}
+
+
+/*!
+ Returns the list view item at \a viewPos. Note that \a viewPos is
+ in the viewport()'s coordinate system, not in the list view's own,
+ much larger, coordinate system.
+
+ itemAt() returns 0 if there is no such item.
+
+ Note that you also get the pointer to the item if \a viewPos
+ points to the root decoration (see setRootIsDecorated()) of the
+ item. To check whether or not \a viewPos is on the root decoration
+ of the item, you can do something like this:
+
+ \code
+ QListViewItem *i = itemAt( p );
+ if ( i ) {
+ if ( p.x() > header()->sectionPos( header()->mapToIndex( 0 ) ) +
+ treeStepSize() * ( i->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() ||
+ p.x() < header()->sectionPos( header()->mapToIndex( 0 ) ) ) {
+ ; // p is not on root decoration
+ else
+ ; // p is on the root decoration
+ }
+ \endcode
+
+ This might be interesting if you use this function to find out
+ where the user clicked and if you want to start a drag (which you
+ do not want to do if the user clicked onto the root decoration of
+ an item).
+
+ \sa itemPos() itemRect() viewportToContents()
+*/
+
+QListViewItem * QListView::itemAt( const QPoint & viewPos ) const
+{
+ if ( viewPos.x() > contentsWidth() - contentsX() )
+ return 0;
+
+ if ( !d->drawables || d->drawables->isEmpty() )
+ buildDrawableList();
+
+ QListViewPrivate::DrawableItem * c = d->drawables->first();
+ int g = viewPos.y() + contentsY();
+
+ while( c && c->i && ( c->y + c->i->height() <= g ||
+ !c->i->isVisible() ||
+ c->i->parent() && !c->i->parent()->isVisible() ) )
+ c = d->drawables->next();
+
+ QListViewItem *i = (c && c->y <= g) ? c->i : 0;
+ return i;
+}
+
+
+/*!
+ Returns the y-coordinate of \a item in the list view's coordinate
+ system. This function is normally much slower than itemAt() but it
+ works for all items, whereas itemAt() normally works only for
+ items on the screen.
+
+ This is a thin wrapper around QListViewItem::itemPos().
+
+ \sa itemAt() itemRect()
+*/
+
+int QListView::itemPos( const QListViewItem * item )
+{
+ return item ? item->itemPos() : 0;
+}
+
+
+/*! \obsolete
+ \property QListView::multiSelection
+ \brief whether the list view is in multi-selection or extended-selection mode
+
+ If you enable multi-selection, \c Multi, mode, it is possible to
+ specify whether or not this mode should be extended. \c Extended
+ means that the user can select multiple items only when pressing
+ the Shift or Ctrl key at the same time.
+
+ The default selection mode is \c Single.
+
+ \sa selectionMode()
+*/
+
+void QListView::setMultiSelection( bool enable )
+{
+ if ( !enable )
+ d->selectionMode = QListView::Single;
+ else if ( d->selectionMode != Multi && d->selectionMode != Extended )
+ d->selectionMode = QListView::Multi;
+}
+
+bool QListView::isMultiSelection() const
+{
+ return d->selectionMode == QListView::Extended || d->selectionMode == QListView::Multi;
+}
+
+/*!
+ \property QListView::selectionMode
+ \brief the list view's selection mode
+
+ The mode can be \c Single (the default), \c Extended, \c Multi or
+ \c NoSelection.
+
+ \sa multiSelection
+*/
+
+void QListView::setSelectionMode( SelectionMode mode )
+{
+ if ( d->selectionMode == mode )
+ return;
+
+ if ( ( d->selectionMode == Multi || d->selectionMode == Extended ) &&
+ ( mode == QListView::Single || mode == QListView::NoSelection ) ){
+ clearSelection();
+ if ( ( mode == QListView::Single ) && currentItem() )
+ currentItem()->selected = TRUE;
+ }
+
+ d->selectionMode = mode;
+}
+
+QListView::SelectionMode QListView::selectionMode() const
+{
+ return d->selectionMode;
+}
+
+
+/*!
+ If \a selected is TRUE the \a item is selected; otherwise it is
+ unselected.
+
+ If the list view is in \c Single selection mode and \a selected is
+ TRUE, the currently selected item is unselected and \a item is
+ made current. Unlike QListViewItem::setSelected(), this function
+ updates the list view as necessary and emits the
+ selectionChanged() signals.
+
+ \sa isSelected() setMultiSelection() isMultiSelection()
+ setCurrentItem(), setSelectionAnchor()
+*/
+
+void QListView::setSelected( QListViewItem * item, bool selected )
+{
+ if ( !item || item->isSelected() == selected ||
+ !item->isSelectable() || selectionMode() == NoSelection )
+ return;
+
+ bool emitHighlighted = FALSE;
+ if ( selectionMode() == Single && d->focusItem != item ) {
+ QListViewItem *o = d->focusItem;
+ if ( d->focusItem && d->focusItem->selected )
+ d->focusItem->setSelected( FALSE );
+ d->focusItem = item;
+ if ( o )
+ repaintItem( o );
+ emitHighlighted = TRUE;
+ }
+
+ item->setSelected( selected );
+
+ repaintItem( item );
+
+ if ( d->selectionMode == Single && selected )
+ emit selectionChanged( item );
+ emit selectionChanged();
+
+ if ( emitHighlighted )
+ emit currentChanged( d->focusItem );
+}
+
+/*!
+ Sets the selection anchor to \a item, if \a item is selectable.
+
+ The selection anchor is the item that remains selected when
+ Shift-selecting with either mouse or keyboard in \c Extended
+ selection mode.
+
+ \sa setSelected()
+*/
+
+void QListView::setSelectionAnchor( QListViewItem *item )
+{
+ if ( item && item->isSelectable() )
+ d->selectAnchor = item;
+}
+
+/*!
+ Sets all the items to be not selected, updates the list view as
+ necessary, and emits the selectionChanged() signals. Note that for
+ \c Multi selection list views this function needs to iterate over
+ \e all items.
+
+ \sa setSelected(), setMultiSelection()
+*/
+
+void QListView::clearSelection()
+{
+ selectAll( FALSE );
+}
+
+/*!
+ If \a select is TRUE, all the items get selected; otherwise all
+ the items get unselected. This only works in the selection modes \c
+ Multi and \c Extended. In \c Single and \c NoSelection mode the
+ selection of the current item is just set to \a select.
+*/
+
+void QListView::selectAll( bool select )
+{
+ if ( d->selectionMode == Multi || d->selectionMode == Extended ) {
+ bool b = signalsBlocked();
+ blockSignals( TRUE );
+ bool anything = FALSE;
+ QListViewItemIterator it( this );
+ while ( it.current() ) {
+ QListViewItem *i = it.current();
+ if ( (bool)i->selected != select ) {
+ i->setSelected( select );
+ anything = TRUE;
+ }
+ ++it;
+ }
+ blockSignals( b );
+ if ( anything ) {
+ emit selectionChanged();
+ d->useDoubleBuffer = TRUE;
+ triggerUpdate();
+ }
+ } else if ( d->focusItem ) {
+ QListViewItem * i = d->focusItem;
+ setSelected( i, select );
+ }
+}
+
+/*!
+ Inverts the selection. Only works in \c Multi and \c Extended
+ selection modes.
+*/
+
+void QListView::invertSelection()
+{
+ if ( d->selectionMode == Single ||
+ d->selectionMode == NoSelection )
+ return;
+
+ bool b = signalsBlocked();
+ blockSignals( TRUE );
+ QListViewItemIterator it( this );
+ for ( ; it.current(); ++it )
+ it.current()->setSelected( !it.current()->isSelected() );
+ blockSignals( b );
+ emit selectionChanged();
+ triggerUpdate();
+}
+
+
+/*!
+ Returns TRUE if the list view item \a i is selected; otherwise
+ returns FALSE.
+
+ \sa QListViewItem::isSelected()
+*/
+
+bool QListView::isSelected( const QListViewItem * i ) const
+{
+ return i ? i->isSelected() : FALSE;
+}
+
+
+/*!
+ Returns the selected item if the list view is in \c Single
+ selection mode and an item is selected.
+
+ If no items are selected or the list view is not in \c Single
+ selection mode this function returns 0.
+
+ \sa setSelected() setMultiSelection()
+*/
+
+QListViewItem * QListView::selectedItem() const
+{
+ if ( d->selectionMode != Single )
+ return 0;
+ if ( d->focusItem && d->focusItem->isSelected() )
+ return d->focusItem;
+ return 0;
+}
+
+
+/*!
+ Sets item \a i to be the current item and repaints appropriately
+ (i.e. highlights the item). The current item is used for keyboard
+ navigation and focus indication; it is independent of any selected
+ items, although a selected item can also be the current item.
+
+ This function does not set the selection anchor. Use
+ setSelectionAnchor() instead.
+
+ \sa currentItem() setSelected()
+*/
+
+void QListView::setCurrentItem( QListViewItem * i )
+{
+ if ( !i || d->focusItem == i || !i->isEnabled() )
+ return;
+
+ if ( currentItem() && currentItem()->renameBox ) {
+ if ( d->defRenameAction == Reject )
+ currentItem()->cancelRename( currentItem()->renameCol );
+ else
+ currentItem()->okRename( currentItem()->renameCol );
+ }
+
+ QListViewItem * prev = d->focusItem;
+ d->focusItem = i;
+
+ QRect mfrect = itemRect( i );
+ if ( mfrect.isValid() ) {
+ if ( header() && header()->isVisible() )
+ setMicroFocusHint( mfrect.x(), mfrect.y()+header()->height(), mfrect.width(), mfrect.height(), FALSE );
+ else
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+ }
+
+ if ( i != prev ) {
+ if ( i && d->selectionMode == Single ) {
+ bool changed = FALSE;
+ if ( prev && prev->selected ) {
+ changed = TRUE;
+ prev->setSelected( FALSE );
+ }
+ if ( i && !i->selected && d->selectionMode != NoSelection && i->isSelectable() ) {
+ i->setSelected( TRUE );
+ changed = TRUE;
+ emit selectionChanged( i );
+ }
+ if ( changed )
+ emit selectionChanged();
+ }
+
+ if ( i )
+ repaintItem( i );
+ if ( prev )
+ repaintItem( prev );
+ emit currentChanged( i );
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), indexOfItem( i ), QAccessible::Focus );
+#endif
+ }
+}
+
+
+/*!
+ Returns the current item, or 0 if there isn't one.
+
+ \sa setCurrentItem()
+*/
+
+QListViewItem * QListView::currentItem() const
+{
+ return d->focusItem;
+}
+
+
+/*!
+ Returns the rectangle on the screen that item \a i occupies in
+ viewport()'s coordinates, or an invalid rectangle if \a i is 0 or
+ is not currently visible.
+
+ The rectangle returned does not include any children of the
+ rectangle (i.e. it uses QListViewItem::height(), rather than
+ QListViewItem::totalHeight()). If you want the rectangle to
+ include children you can use something like this:
+
+ \code
+ QRect r( listView->itemRect( item ) );
+ r.setHeight( (QCOORD)(QMIN( item->totalHeight(),
+ listView->viewport->height() - r.y() ) ) )
+ \endcode
+
+ Note the way it avoids too-high rectangles. totalHeight() can be
+ much larger than the window system's coordinate system allows.
+
+ itemRect() is comparatively slow. It's best to call it only for
+ items that are probably on-screen.
+*/
+
+QRect QListView::itemRect( const QListViewItem * i ) const
+{
+ if ( !d->drawables || d->drawables->isEmpty() )
+ buildDrawableList();
+
+ QListViewPrivate::DrawableItem * c = d->drawables->first();
+
+ while( c && c->i && c->i != i )
+ c = d->drawables->next();
+
+ if ( c && c->i == i ) {
+ int y = c->y - contentsY();
+ if ( y + c->i->height() >= 0 &&
+ y < ((QListView *)this)->visibleHeight() ) {
+ QRect r( -contentsX(), y, d->h->width(), i->height() );
+ return r;
+ }
+ }
+
+ return QRect( 0, 0, -1, -1 );
+}
+
+
+/*!
+ \fn void QListView::doubleClicked( QListViewItem *item )
+
+ \obsolete (use doubleClicked( QListViewItem *, const QPoint&, int ))
+
+ This signal is emitted whenever an item is double-clicked. It's
+ emitted on the second button press, not the second button release.
+ \a item is the list view item on which the user did the
+ double-click.
+*/
+
+/*!
+ \fn void QListView::doubleClicked( QListViewItem *, const QPoint&, int )
+
+ This signal is emitted whenever an item is double-clicked. It's
+ emitted on the second button press, not the second button release.
+ The arguments are the relevant QListViewItem (may be 0), the point
+ in global coordinates and the relevant column (or -1 if the click
+ was outside the list).
+
+ \warning Do not delete any QListViewItem objects in slots
+ connected to this signal.
+*/
+
+
+/*!
+ \fn void QListView::returnPressed( QListViewItem * )
+
+ This signal is emitted when Enter or Return is pressed. The
+ argument is the currentItem().
+*/
+
+/*!
+ \fn void QListView::spacePressed( QListViewItem * )
+
+ This signal is emitted when Space is pressed. The argument is
+ the currentItem().
+*/
+
+
+/*!
+ Sets the list view to be sorted by column \a column in ascending
+ order if \a ascending is TRUE or descending order if it is FALSE.
+
+ If \a column is -1, sorting is disabled and the user cannot sort
+ columns by clicking on the column headers. If \a column is larger
+ than the number of columns the user must click on a column
+ header to sort the list view.
+*/
+
+void QListView::setSorting( int column, bool ascending )
+{
+ if ( column == -1 )
+ column = Unsorted;
+
+ if ( d->sortcolumn == column && d->ascending == ascending )
+ return;
+
+ d->ascending = ascending;
+ d->sortcolumn = column;
+ if ( d->sortcolumn != Unsorted && d->sortIndicator )
+ d->h->setSortIndicator( d->sortcolumn, d->ascending );
+ else
+ d->h->setSortIndicator( -1 );
+
+ triggerUpdate();
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( viewport(), 0, QAccessible::ObjectReorder );
+#endif
+}
+
+/*!
+ \enum Qt::SortOrder
+
+ This enum describes how the items in a widget are sorted.
+
+ \value Ascending The items are sorted ascending e.g. starts with
+ 'AAA' ends with 'ZZZ' in Latin-1 locales
+
+ \value Descending The items are sorted descending e.g. starts with
+ 'ZZZ' ends with 'AAA' in Latin-1 locales
+*/
+
+/*!
+ Sets the \a column the list view is sorted by.
+
+ Sorting is triggered by choosing a header section.
+*/
+
+void QListView::changeSortColumn( int column )
+{
+ if ( isRenaming() ) {
+ if ( d->defRenameAction == QListView::Reject ) {
+ currentItem()->cancelRename( currentItem()->renameCol );
+ } else {
+ currentItem()->okRename( currentItem()->renameCol );
+ }
+ }
+ if ( d->sortcolumn != Unsorted ) {
+ int lcol = d->h->mapToLogical( column );
+ setSorting( lcol, d->sortcolumn == lcol ? !d->ascending : TRUE);
+ }
+}
+
+/*!
+ \internal
+ Handles renaming when sections are being swapped by the user.
+*/
+
+void QListView::handleIndexChange()
+{
+ if ( isRenaming() ) {
+ if ( d->defRenameAction == QListView::Reject ) {
+ currentItem()->cancelRename( currentItem()->renameCol );
+ } else {
+ currentItem()->okRename( currentItem()->renameCol );
+ }
+ }
+ triggerUpdate();
+}
+
+/*!
+ Returns the column by which the list view is sorted, or -1 if
+ sorting is disabled.
+
+ \sa sortOrder()
+*/
+
+int QListView::sortColumn() const
+{
+ return d->sortcolumn == Unsorted ? -1 : d->sortcolumn;
+}
+
+/*!
+ Sets the sorting column for the list view.
+
+ If \a column is -1, sorting is disabled and the user cannot sort
+ columns by clicking on the column headers. If \a column is larger
+ than the number of columns the user must click on a column header
+ to sort the list view.
+
+ \sa setSorting()
+*/
+void QListView::setSortColumn( int column )
+{
+ setSorting( column, d->ascending );
+}
+
+/*!
+ Returns the sorting order of the list view items.
+
+ \sa sortColumn()
+*/
+Qt::SortOrder QListView::sortOrder() const
+{
+ if ( d->ascending )
+ return Ascending;
+ return Descending;
+}
+
+/*!
+ Sets the sort order for the items in the list view to \a order.
+
+ \sa setSorting()
+*/
+void QListView::setSortOrder( SortOrder order )
+{
+ setSorting( d->sortcolumn, order == Ascending ? TRUE : FALSE );
+}
+
+/*!
+ Sorts the list view using the last sorting configuration (sort
+ column and ascending/descending).
+*/
+
+void QListView::sort()
+{
+ if ( d->r )
+ d->r->sort();
+}
+
+/*!
+ \property QListView::itemMargin
+ \brief the advisory item margin that list items may use
+
+ The item margin defaults to one pixel and is the margin between
+ the item's edges and the area where it draws its contents.
+ QListViewItem::paintFocus() draws in the margin.
+
+ \sa QListViewItem::paintCell()
+*/
+
+void QListView::setItemMargin( int m )
+{
+ if ( d->margin == m )
+ return;
+ d->margin = m;
+ if ( isVisible() ) {
+ if ( d->drawables )
+ d->drawables->clear();
+ triggerUpdate();
+ }
+}
+
+int QListView::itemMargin() const
+{
+ return d->margin;
+}
+
+
+/*!
+ \fn void QListView::rightButtonClicked( QListViewItem *, const QPoint&, int )
+
+ This signal is emitted when the right button is clicked (i.e. when
+ it's released). The arguments are the relevant QListViewItem (may
+ be 0), the point in global coordinates and the relevant column (or
+ -1 if the click was outside the list).
+*/
+
+
+/*!
+ \fn void QListView::rightButtonPressed (QListViewItem *, const QPoint &, int)
+
+ This signal is emitted when the right button is pressed. The
+ arguments are the relevant QListViewItem (may be 0), the point in
+ global coordinates and the relevant column (or -1 if the click was
+ outside the list).
+*/
+
+/*!
+ \fn void QListView::contextMenuRequested( QListViewItem *item, const QPoint & pos, int col )
+
+ This signal is emitted when the user invokes a context menu with
+ the right mouse button or with special system keys. If the
+ keyboard was used \a item is the current item; if the mouse was
+ used, \a item is the item under the mouse pointer or 0 if there is
+ no item under the mouse pointer. If no item is clicked, the column
+ index emitted is -1.
+
+ \a pos is the position for the context menu in the global
+ coordinate system.
+
+ \a col is the column on which the user pressed, or -1 if the
+ signal was triggered by a key event.
+*/
+
+/*!
+ \reimp
+*/
+void QListView::styleChange( QStyle& old )
+{
+ QScrollView::styleChange( old );
+ reconfigureItems();
+}
+
+
+/*!
+ \reimp
+*/
+void QListView::setFont( const QFont & f )
+{
+ QScrollView::setFont( f );
+ reconfigureItems();
+}
+
+
+/*!
+ \reimp
+*/
+void QListView::setPalette( const QPalette & p )
+{
+ QScrollView::setPalette( p );
+ reconfigureItems();
+}
+
+
+/*!
+ Ensures that setup() is called for all currently visible items,
+ and that it will be called for currently invisible items as soon
+ as their parents are opened.
+
+ (A visible item, here, is an item whose parents are all open. The
+ item may happen to be off-screen.)
+
+ \sa QListViewItem::setup()
+*/
+
+void QListView::reconfigureItems()
+{
+ d->fontMetricsHeight = fontMetrics().height();
+ d->minLeftBearing = fontMetrics().minLeftBearing();
+ d->minRightBearing = fontMetrics().minRightBearing();
+ d->ellipsisWidth = fontMetrics().width( "..." ) * 2;
+ d->r->setOpen( FALSE );
+ d->r->configured = FALSE;
+ d->r->setOpen( TRUE );
+}
+
+/*!
+ Ensures that the width mode of column \a c is updated according to
+ the width of \a item.
+*/
+
+void QListView::widthChanged( const QListViewItem* item, int c )
+{
+ if ( c >= d->h->count() )
+ return;
+
+
+ QFontMetrics fm = fontMetrics();
+ int col = c < 0 ? 0 : c;
+ while ( col == c || ( c < 0 && col < d->h->count() ) ) {
+ if ( d->column[col]->wmode == Maximum ) {
+ int w = item->width( fm, this, col );
+ if ( showSortIndicator() ) {
+ int tw = d->h->sectionSizeHint( col, fm ).width();
+ tw += 40; //add space for the sort indicator
+ w = QMAX( w, tw );
+ }
+ if ( col == 0 ) {
+ int indent = treeStepSize() * item->depth();
+ if ( rootIsDecorated() )
+ indent += treeStepSize();
+ w += indent;
+ }
+ if ( w > columnWidth( col ) && !d->h->isStretchEnabled() && !d->h->isStretchEnabled( col ) ) {
+ d->updateHeader = TRUE;
+ setColumnWidth( col, w );
+ }
+ }
+ col++;
+ }
+}
+
+/*!
+ \property QListView::allColumnsShowFocus
+ \brief whether items should show keyboard focus using all columns
+
+ If this property is TRUE all columns will show focus and selection
+ states, otherwise only column 0 will show focus.
+
+ The default is FALSE.
+
+ Setting this to TRUE if it's not necessary may cause noticeable
+ flicker.
+*/
+
+void QListView::setAllColumnsShowFocus( bool enable )
+{
+ d->allColumnsShowFocus = enable;
+}
+
+bool QListView::allColumnsShowFocus() const
+{
+ return d->allColumnsShowFocus;
+}
+
+
+/*!
+ Returns the first item in this QListView. Returns 0 if there is no
+ first item.
+
+ A list view's items can be traversed using firstChild()
+ and nextSibling() or using a QListViewItemIterator.
+
+ \sa itemAt() QListViewItem::itemBelow() QListViewItem::itemAbove()
+*/
+
+QListViewItem * QListView::firstChild() const
+{
+ if ( !d->r )
+ return 0;
+
+ d->r->enforceSortOrder();
+ return d->r->childItem;
+}
+
+/*!
+ Returns the last item in the list view tree. Returns 0 if there
+ are no items in the QListView.
+
+ This function is slow because it traverses the entire tree to find
+ the last item.
+*/
+
+QListViewItem* QListView::lastItem() const
+{
+ QListViewItem* item = firstChild();
+ if ( item ) {
+ while ( item->nextSibling() || item->firstChild() ) {
+ if ( item->nextSibling() )
+ item = item->nextSibling();
+ else
+ item = item->firstChild();
+ }
+ }
+ return item;
+}
+
+/*!
+ Repaints this item on the screen if it is currently visible.
+*/
+
+void QListViewItem::repaint() const
+{
+ QListView *lv = listView();
+ if ( lv )
+ lv->repaintItem( this );
+}
+
+
+/*!
+ Repaints \a item on the screen if \a item is currently visible.
+ Takes care to avoid multiple repaints.
+*/
+
+void QListView::repaintItem( const QListViewItem * item ) const
+{
+ if ( !item )
+ return;
+ d->dirtyItemTimer->start( 0, TRUE );
+ if ( !d->dirtyItems )
+ d->dirtyItems = new QPtrDict<void>();
+ d->dirtyItems->replace( (void *)item, (void *)item );
+}
+
+
+struct QCheckListItemPrivate
+{
+ QCheckListItemPrivate():
+ exclusive( 0 ),
+ currentState( QCheckListItem::Off ),
+ statesDict( 0 ),
+ tristate( FALSE ) {}
+
+ QCheckListItem *exclusive;
+ QCheckListItem::ToggleState currentState;
+ QPtrDict<QCheckListItem::ToggleState> *statesDict;
+ bool tristate;
+};
+
+
+/*!
+ \class QCheckListItem
+ \brief The QCheckListItem class provides checkable list view items.
+
+ \ingroup advanced
+
+ QCheckListItems are used in \l{QListView}s to provide
+ \l{QListViewItem}s that are checkboxes, radio buttons or
+ controllers.
+
+ Checkbox and controller check list items may be inserted at any
+ level in a list view. Radio button check list items must be
+ children of a controller check list item.
+
+ The item can be checked or unchecked with setOn(). Its type can be
+ retrieved with type() and its text retrieved with text().
+
+ \img qlistviewitems.png List View Items
+
+ \sa QListViewItem QListView
+*/
+
+// ### obscenity is warranted.
+
+/*!
+ \enum QCheckListItem::Type
+
+ This enum type specifies a QCheckListItem's type:
+
+ \value RadioButton
+ \value CheckBox
+ \value Controller \e obsolete (use \c RadioButtonController instead)
+ \value RadioButtonController
+ \value CheckBoxController
+*/
+
+/*!
+ \enum QCheckListItem::ToggleState
+
+ This enum specifies a QCheckListItem's toggle state.
+
+ \value Off
+ \value NoChange
+ \value On
+*/
+
+
+/*!
+ Constructs a checkable item with parent \a parent, text \a text
+ and of type \a tt. Note that a \c RadioButton must be the child of a
+ \c RadioButtonController, otherwise it will not toggle.
+*/
+QCheckListItem::QCheckListItem( QCheckListItem *parent, const QString &text,
+ Type tt )
+ : QListViewItem( parent, text, QString::null )
+{
+ myType = tt;
+ init();
+ if ( myType == RadioButton ) {
+ if ( parent->type() != RadioButtonController )
+ qWarning( "QCheckListItem::QCheckListItem(), radio button must be "
+ "child of a controller" );
+ else
+ d->exclusive = parent;
+ }
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, which is after
+ \a after in the parent's list of children, and with text \a text
+ and of type \a tt. Note that a \c RadioButton must be the child of
+ a \c RadioButtonController, otherwise it will not toggle.
+*/
+QCheckListItem::QCheckListItem( QCheckListItem *parent, QListViewItem *after,
+ const QString &text, Type tt )
+ : QListViewItem( parent, after, text )
+{
+ myType = tt;
+ init();
+ if ( myType == RadioButton ) {
+ if ( parent->type() != RadioButtonController )
+ qWarning( "QCheckListItem::QCheckListItem(), radio button must be "
+ "child of a controller" );
+ else
+ d->exclusive = parent;
+ }
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, text \a text
+ and of type \a tt. Note that this item must \e not be a \c
+ RadioButton. Radio buttons must be children of a \c
+ RadioButtonController.
+*/
+QCheckListItem::QCheckListItem( QListViewItem *parent, const QString &text,
+ Type tt )
+ : QListViewItem( parent, text, QString::null )
+{
+ myType = tt;
+ if ( myType == RadioButton ) {
+ qWarning( "QCheckListItem::QCheckListItem(), radio button must be "
+ "child of a QCheckListItem" );
+ }
+ init();
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, which is after
+ \a after in the parent's list of children, with text \a text and
+ of type \a tt. Note that this item must \e not be a \c
+ RadioButton. Radio buttons must be children of a \c
+ RadioButtonController.
+*/
+QCheckListItem::QCheckListItem( QListViewItem *parent, QListViewItem *after,
+ const QString &text, Type tt )
+ : QListViewItem( parent, after, text )
+{
+ myType = tt;
+ if ( myType == RadioButton ) {
+ qWarning( "QCheckListItem::QCheckListItem(), radio button must be "
+ "child of a QCheckListItem" );
+ }
+ init();
+}
+
+
+/*!
+ Constructs a checkable item with parent \a parent, text \a text
+ and of type \a tt. Note that \a tt must \e not be \c RadioButton.
+ Radio buttons must be children of a \c RadioButtonController.
+*/
+QCheckListItem::QCheckListItem( QListView *parent, const QString &text,
+ Type tt )
+ : QListViewItem( parent, text )
+{
+ myType = tt;
+ if ( tt == RadioButton )
+ qWarning( "QCheckListItem::QCheckListItem(), radio button must be "
+ "child of a QCheckListItem" );
+ init();
+}
+
+/*!
+ Constructs a checkable item with parent \a parent, which is after
+ \a after in the parent's list of children, with text \a text and
+ of type \a tt. Note that \a tt must \e not be \c RadioButton.
+ Radio buttons must be children of a \c RadioButtonController.
+*/
+QCheckListItem::QCheckListItem( QListView *parent, QListViewItem *after,
+ const QString &text, Type tt )
+ : QListViewItem( parent, after, text )
+{
+ myType = tt;
+ if ( tt == RadioButton )
+ qWarning( "QCheckListItem::QCheckListItem(), radio button must be "
+ "child of a QCheckListItem" );
+ init();
+}
+
+
+int QCheckListItem::RTTI = 1;
+
+/* \reimp */
+
+int QCheckListItem::rtti() const
+{
+ return RTTI;
+}
+
+/*!
+ Constructs a \c RadioButtonController item with parent \a parent,
+ text \a text and pixmap \a p.
+*/
+QCheckListItem::QCheckListItem( QListView *parent, const QString &text,
+ const QPixmap & p )
+ : QListViewItem( parent, text )
+{
+ myType = RadioButtonController;
+ setPixmap( 0, p );
+ init();
+}
+
+/*!
+ Constructs a \c RadioButtonController item with parent \a parent,
+ text \a text and pixmap \a p.
+*/
+QCheckListItem::QCheckListItem( QListViewItem *parent, const QString &text,
+ const QPixmap & p )
+ : QListViewItem( parent, text )
+{
+ myType = RadioButtonController;
+ setPixmap( 0, p );
+ init();
+}
+
+void QCheckListItem::init()
+{
+ d = new QCheckListItemPrivate();
+ on = FALSE; // ### remove on ver 4
+ if ( myType == CheckBoxController || myType == CheckBox ) {
+ d->statesDict = new QPtrDict<ToggleState>(101);
+ d->statesDict->setAutoDelete( TRUE );
+ }
+ // CheckBoxControllers by default have tristate set to TRUE
+ if ( myType == CheckBoxController )
+ setTristate( TRUE );
+}
+
+/*!
+ Destroys the item, and all its children to any depth, freeing up
+ all allocated resources.
+*/
+QCheckListItem::~QCheckListItem()
+{
+ if ( myType == RadioButton
+ && d->exclusive && d->exclusive->d
+ && d->exclusive->d->exclusive == this )
+ d->exclusive->turnOffChild();
+ d->exclusive = 0; // so the children won't try to access us.
+ if ( d->statesDict )
+ delete d->statesDict;
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn QCheckListItem::Type QCheckListItem::type() const
+
+ Returns the type of this item.
+*/
+
+/*!
+ \fn bool QCheckListItem::isOn() const
+
+ Returns TRUE if the item is toggled on; otherwise returns FALSE.
+*/
+
+/*!
+ Sets tristate to \a b if the \c Type is either a \c CheckBoxController or
+ a \c CheckBox.
+
+ \c CheckBoxControllers are tristate by default.
+
+ \sa state() isTristate()
+*/
+void QCheckListItem::setTristate( bool b )
+{
+ if ( ( myType != CheckBoxController ) && ( myType != CheckBox ) ) {
+ qWarning( "QCheckListItem::setTristate(), has no effect on RadioButton "
+ "or RadioButtonController." );
+ return;
+ }
+ d->tristate = b;
+}
+
+/*!
+ Returns TRUE if the item is tristate; otherwise returns FALSE.
+
+ \sa setTristate()
+*/
+bool QCheckListItem::isTristate() const
+{
+ return d->tristate;
+}
+
+/*!
+ Returns the state of the item.
+
+ \sa QCheckListItem::ToggleState
+*/
+QCheckListItem::ToggleState QCheckListItem::state() const
+{
+ if ( !isTristate() && internalState() == NoChange )
+ return Off;
+ else
+ return d->currentState;
+}
+
+/*
+ Same as the public state() except this one does not mask NoChange into Off
+ when tristate is disabled.
+*/
+QCheckListItem::ToggleState QCheckListItem::internalState() const
+{
+ return d->currentState;
+}
+
+
+
+
+/*!
+ Sets the toggle state of the checklistitem to \a s. \a s can be
+ \c Off, \c NoChange or \c On.
+
+ Tristate can only be enabled for \c CheckBox or \c CheckBoxController,
+ therefore the \c NoChange only applies to them.
+
+ Setting the state to \c On or \c Off on a \c CheckBoxController
+ will recursivly set the states of its children to the same state.
+
+ Setting the state to \c NoChange on a \c CheckBoxController will
+ make it recursivly recall the previous stored state of its
+ children. If there was no previous stored state the children are
+ all set to \c On.
+*/
+void QCheckListItem::setState( ToggleState s )
+{
+ if ( myType == CheckBoxController && state() == NoChange )
+ updateStoredState( (void*) this );
+ setState( s, TRUE, TRUE );
+}
+
+/*
+ Sets the toggle state of the checklistitems. \a update tells if the
+ controller / parent controller should be aware of these changes, \a store
+ tells if the parent should store its children if certain conditions arise
+*/
+void QCheckListItem::setState( ToggleState s, bool update, bool store)
+{
+
+ if ( s == internalState() )
+ return;
+
+ if ( myType == CheckBox ) {
+ setCurrentState( s );
+ stateChange( state() );
+ if ( update && parent() && parent()->rtti() == 1
+ && ((QCheckListItem*)parent())->type() == CheckBoxController )
+ ((QCheckListItem*)parent())->updateController( update, store );
+ } else if ( myType == CheckBoxController ) {
+ if ( s == NoChange && childCount()) {
+ restoreState( (void*) this );
+ } else {
+ QListViewItem *item = firstChild();
+ int childCount = 0;
+ while( item ) {
+ if ( item->rtti() == 1 &&
+ ( ((QCheckListItem*)item)->type() == CheckBox ||
+ ((QCheckListItem*)item)->type() == CheckBoxController ) ) {
+ QCheckListItem *checkItem = (QCheckListItem*)item;
+ checkItem->setState( s, FALSE, FALSE );
+ childCount++;
+ }
+ item = item->nextSibling();
+ }
+ if ( update ) {
+ if ( childCount > 0 ) {
+ ToggleState oldState = internalState();
+ updateController( FALSE, FALSE );
+ if ( oldState != internalState() &&
+ parent() && parent()->rtti() == 1 &&
+ ((QCheckListItem*)parent())->type() == CheckBoxController )
+ ((QCheckListItem*)parent())->updateController( update, store );
+
+ updateController( update, store );
+ } else {
+ // if there are no children we simply set the CheckBoxController and update its parent
+ setCurrentState( s );
+ stateChange( state() );
+ if ( parent() && parent()->rtti() == 1
+ && ((QCheckListItem*)parent())->type() == CheckBoxController )
+ ((QCheckListItem*)parent())->updateController( update, store );
+ }
+ } else {
+ setCurrentState( s );
+ stateChange( state() );
+ }
+
+ }
+ } else if ( myType == RadioButton ) {
+ if ( s == On ) {
+ if ( d->exclusive && d->exclusive->d->exclusive != this )
+ d->exclusive->turnOffChild();
+ setCurrentState( s );
+ if ( d->exclusive )
+ d->exclusive->d->exclusive = this;
+ } else {
+ if ( d->exclusive && d->exclusive->d->exclusive == this )
+ d->exclusive->d->exclusive = 0;
+ setCurrentState( Off );
+ }
+ stateChange( state() );
+ }
+ repaint();
+}
+
+/*
+ this function is needed becase we need to update "on" everytime
+ we update d->currentState. In order to retain binary compatibility
+ the inline function isOn() needs the "on" bool
+ ### should be changed in ver 4
+*/
+void QCheckListItem::setCurrentState( ToggleState s )
+{
+ ToggleState old = d->currentState;
+ d->currentState = s;
+ if (d->currentState == On)
+ on = TRUE;
+ else
+ on = FALSE;
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( old != d->currentState && listView() )
+ QAccessible::updateAccessibility( listView()->viewport(), indexOfItem( this ), QAccessible::StateChanged );
+#else
+ Q_UNUSED( old );
+#endif
+}
+
+
+
+/*
+ updates the internally stored state of this item for the parent (key)
+*/
+void QCheckListItem::setStoredState( ToggleState newState, void *key )
+{
+ if ( myType == CheckBox || myType == CheckBoxController )
+ d->statesDict->replace( key, new ToggleState(newState) );
+}
+
+/*
+ Returns the stored state for this item for the given key.
+ If the key is not found it returns Off.
+*/
+QCheckListItem::ToggleState QCheckListItem::storedState( void *key ) const
+{
+ if ( !d->statesDict )
+ return Off;
+
+ ToggleState *foundState = d->statesDict->find( key );
+ if ( foundState )
+ return ToggleState( *foundState );
+ else
+ return Off;
+}
+
+
+/*!
+ \fn QString QCheckListItem::text() const
+
+ Returns the item's text.
+*/
+
+
+/*!
+ If this is a \c RadioButtonController that has \c RadioButton
+ children, turn off the child that is on.
+*/
+void QCheckListItem::turnOffChild()
+{
+ if ( myType == RadioButtonController && d->exclusive )
+ d->exclusive->setOn( FALSE );
+}
+
+/*!
+ Toggle check box or set radio button to on.
+*/
+void QCheckListItem::activate()
+{
+ QListView * lv = listView();
+
+ if ( lv && !lv->isEnabled() || !isEnabled() )
+ return;
+
+ QPoint pos;
+ int boxsize = lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv);
+ if ( activatedPos( pos ) ) {
+ bool parentControl = FALSE;
+ if ( parent() && parent()->rtti() == 1 &&
+ ((QCheckListItem*) parent())->type() == RadioButtonController )
+ parentControl = TRUE;
+
+ int x = parentControl ? 0 : 3;
+ int align = lv->columnAlignment( 0 );
+ int marg = lv->itemMargin();
+ int y = 0;
+
+ if ( align & AlignVCenter )
+ y = ( ( height() - boxsize ) / 2 ) + marg;
+ else
+ y = (lv->fontMetrics().height() + 2 + marg - boxsize) / 2;
+
+ QRect r( x, y, boxsize-3, boxsize-3 );
+ // columns might have been swapped
+ r.moveBy( lv->header()->sectionPos( 0 ), 0 );
+ if ( !r.contains( pos ) )
+ return;
+ }
+ if ( ( myType == CheckBox ) || ( myType == CheckBoxController) ) {
+ switch ( internalState() ) {
+ case On:
+ setState( Off );
+ break;
+ case Off:
+ if ( (!isTristate() && myType == CheckBox) ||
+ (myType == CheckBoxController && !childCount()) ) {
+ setState( On );
+ } else {
+ setState( NoChange );
+ if ( myType == CheckBoxController && internalState() != NoChange )
+ setState( On );
+ }
+ break;
+ case NoChange:
+ setState( On );
+ break;
+ }
+ ignoreDoubleClick();
+ } else if ( myType == RadioButton ) {
+ setOn( TRUE );
+ ignoreDoubleClick();
+ }
+}
+
+/*!
+ Sets the button on if \a b is TRUE, otherwise sets it off.
+ Maintains radio button exclusivity.
+*/
+void QCheckListItem::setOn( bool b )
+{
+ if ( b )
+ setState( On , TRUE, TRUE );
+ else
+ setState( Off , TRUE, TRUE );
+}
+
+
+/*!
+ This virtual function is called when the item changes its state.
+ \c NoChange (if tristate is enabled and the type is either \c
+ CheckBox or \c CheckBoxController) reports the same as \c Off, so
+ use state() to determine if the state is actually \c Off or \c
+ NoChange.
+*/
+void QCheckListItem::stateChange( bool )
+{
+}
+
+/*
+ Calls the public virtual function if the state is changed to either On, NoChange or Off.
+ NoChange reports the same as Off - ### should be fixed in ver4
+*/
+void QCheckListItem::stateChange( ToggleState s )
+{
+ stateChange( s == On );
+}
+
+/*
+ sets the state of the CheckBox and CheckBoxController back to
+ previous stored state
+*/
+void QCheckListItem::restoreState( void *key, int depth )
+{
+ switch ( type() ) {
+ case CheckBox:
+ setCurrentState( storedState( key ) );
+ stateChange( state() );
+ repaint();
+ break;
+ case CheckBoxController: {
+ QListViewItem *item = firstChild();
+ int childCount = 0;
+ while ( item ) {
+ // recursively calling restoreState for children of type CheckBox and CheckBoxController
+ if ( item->rtti() == 1 &&
+ ( ((QCheckListItem*)item)->type() == CheckBox ||
+ ((QCheckListItem*)item)->type() == CheckBoxController ) ) {
+ ((QCheckListItem*)item)->restoreState( key , depth+1 );
+ childCount++;
+ }
+ item = item->nextSibling();
+ }
+ if ( childCount > 0 ) {
+ if ( depth == 0 )
+ updateController( TRUE );
+ else
+ updateController( FALSE );
+ } else {
+ // if there are no children we retrieve the CheckBoxController state directly.
+ setState( storedState( key ), TRUE, FALSE );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*
+ Checks the childrens state and updates the controllers state
+ if necessary. If the controllers state change, then his parent again is
+ called to update itself.
+*/
+void QCheckListItem::updateController( bool update , bool store )
+{
+ if ( myType != CheckBoxController )
+ return;
+
+ QCheckListItem *controller = 0;
+ // checks if this CheckBoxController has another CheckBoxController as parent
+ if ( parent() && parent()->rtti() == 1
+ && ((QCheckListItem*)parent())->type() == CheckBoxController )
+ controller = (QCheckListItem*)parent();
+
+ ToggleState theState = Off;
+ bool first = TRUE;
+ QListViewItem *item = firstChild();
+ while( item && theState != NoChange ) {
+ if ( item->rtti() == 1 &&
+ ( ((QCheckListItem*)item)->type() == CheckBox ||
+ ((QCheckListItem*)item)->type() == CheckBoxController ) ) {
+ QCheckListItem *checkItem = (QCheckListItem*)item;
+ if ( first ) {
+ theState = checkItem->internalState();
+ first = FALSE;
+ } else {
+ if ( checkItem->internalState() == NoChange ||
+ theState != checkItem->internalState() )
+ theState = NoChange;
+ else
+ theState = checkItem->internalState();
+ }
+ }
+ item = item->nextSibling();
+ }
+ if ( internalState() != theState ) {
+ setCurrentState( theState );
+ if ( store && ( internalState() == On || internalState() == Off ) )
+ updateStoredState( (void*) this );
+ stateChange( state() );
+ if ( update && controller ) {
+ controller->updateController( update, store );
+ }
+ repaint();
+ }
+}
+
+
+/*
+ Makes all the children CheckBoxes update their storedState
+*/
+void QCheckListItem::updateStoredState( void *key )
+{
+ if ( myType != CheckBoxController )
+ return;
+
+ QListViewItem *item = firstChild();
+ while( item ) {
+ if ( item->rtti() == 1 ) {
+ QCheckListItem *checkItem = (QCheckListItem*)item;
+ if ( checkItem->type() == CheckBox )
+ checkItem->setStoredState( checkItem->internalState(), key );
+ else if (checkItem->type() == CheckBoxController )
+ checkItem->updateStoredState( key );
+ }
+ item = item->nextSibling();
+ }
+ // this state is only needed if the CheckBoxController has no CheckBox / CheckBoxController children.
+ setStoredState( internalState() , key );
+}
+
+
+/*!
+ \reimp
+*/
+void QCheckListItem::setup()
+{
+ QListViewItem::setup();
+ int h = height();
+ QListView *lv = listView();
+ if ( lv )
+ h = QMAX( lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv),
+ h );
+ h = QMAX( h, QApplication::globalStrut().height() );
+ setHeight( h );
+}
+
+/*!
+ \reimp
+*/
+
+int QCheckListItem::width( const QFontMetrics& fm, const QListView* lv, int column) const
+{
+ int r = QListViewItem::width( fm, lv, column );
+ if ( column == 0 ) {
+ r += lv->itemMargin();
+ if ( myType == RadioButtonController && pixmap( 0 ) ) {
+ // r += 0;
+ } else {
+ r += lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv) + 4;
+ }
+ }
+ return QMAX( r, QApplication::globalStrut().width() );
+}
+
+/*!
+ Paints the item using the painter \a p and the color group \a cg.
+ The item is in column \a column, has width \a width and has
+ alignment \a align. (See Qt::AlignmentFlags for valid alignments.)
+*/
+void QCheckListItem::paintCell( QPainter * p, const QColorGroup & cg,
+ int column, int width, int align )
+{
+ if ( !p )
+ return;
+
+ QListView *lv = listView();
+ if ( !lv )
+ return;
+
+ const BackgroundMode bgmode = lv->viewport()->backgroundMode();
+ const QColorGroup::ColorRole crole = QPalette::backgroundRoleFromMode( bgmode );
+ if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) )
+ p->fillRect( 0, 0, width, height(), cg.brush( crole ) );
+ else
+ lv->paintEmptyArea( p, QRect( 0, 0, width, height() ) );
+
+ if ( column != 0 ) {
+ // The rest is text, or for subclasses to change.
+ QListViewItem::paintCell( p, cg, column, width, align );
+ return;
+ }
+
+ bool parentControl = FALSE;
+ if ( parent() && parent()->rtti() == 1 &&
+ ((QCheckListItem*) parent())->type() == RadioButtonController )
+ parentControl = TRUE;
+
+ QFontMetrics fm( lv->fontMetrics() );
+ int boxsize = lv->style().pixelMetric( myType == RadioButtonController ? QStyle::PM_CheckListControllerSize :
+ QStyle::PM_CheckListButtonSize, lv);
+ int marg = lv->itemMargin();
+ int r = marg;
+
+ // Draw controller / checkbox / radiobutton ---------------------
+ int styleflags = QStyle::Style_Default;
+ if ( internalState() == On ) {
+ styleflags |= QStyle::Style_On;
+ } else if ( internalState() == NoChange ) {
+ if ( myType == CheckBoxController && !isTristate() )
+ styleflags |= QStyle::Style_Off;
+ else
+ styleflags |= QStyle::Style_NoChange;
+ } else {
+ styleflags |= QStyle::Style_Off;
+ }
+ if ( isSelected() )
+ styleflags |= QStyle::Style_Selected;
+ if ( isEnabled() && lv->isEnabled() )
+ styleflags |= QStyle::Style_Enabled;
+
+ if ( myType == RadioButtonController ) {
+ int x = 0;
+ if(!parentControl)
+ x += 3;
+ if ( !pixmap( 0 ) ) {
+ lv->style().drawPrimitive(QStyle::PE_CheckListController, p,
+ QRect(x, 0, boxsize,
+ fm.height() + 2 + marg),
+ cg, styleflags, QStyleOption(this));
+ r += boxsize + 4;
+ }
+ } else {
+ Q_ASSERT( lv ); //###
+ int x = 0;
+ int y = 0;
+ if ( !parentControl )
+ x += 3;
+ if ( align & AlignVCenter )
+ y = ( ( height() - boxsize ) / 2 ) + marg;
+ else
+ y = (fm.height() + 2 + marg - boxsize) / 2;
+
+ if ( ( myType == CheckBox ) || ( myType == CheckBoxController ) ) {
+ lv->style().drawPrimitive(QStyle::PE_CheckListIndicator, p,
+ QRect(x, y, boxsize,
+ fm.height() + 2 + marg),
+ cg, styleflags, QStyleOption(this));
+ } else { //radio button look
+ lv->style().drawPrimitive(QStyle::PE_CheckListExclusiveIndicator,
+ p, QRect(x, y, boxsize,
+ fm.height() + 2 + marg),
+ cg, styleflags, QStyleOption(this));
+ }
+ r += boxsize + 4;
+ }
+
+ // Draw text ----------------------------------------------------
+ p->translate( r, 0 );
+ p->setPen( QPen( cg.text() ) );
+ QListViewItem::paintCell( p, cg, column, width - r, align );
+}
+
+/*!
+ Draws the focus rectangle \a r using the color group \a cg on the
+ painter \a p.
+*/
+void QCheckListItem::paintFocus( QPainter *p, const QColorGroup & cg,
+ const QRect & r )
+{
+ bool intersect = TRUE;
+ QListView *lv = listView();
+ if ( lv && lv->header()->mapToActual( 0 ) != 0 ) {
+ int xdepth = lv->treeStepSize() * ( depth() + ( lv->rootIsDecorated() ? 1 : 0) ) + lv->itemMargin();
+ int p = lv->header()->cellPos( lv->header()->mapToActual( 0 ) );
+ xdepth += p;
+ intersect = r.intersects( QRect( p, r.y(), xdepth - p + 1, r.height() ) );
+ }
+ bool parentControl = FALSE;
+ if ( parent() && parent()->rtti() == 1 &&
+ ((QCheckListItem*) parent())->type() == RadioButtonController )
+ parentControl = TRUE;
+ if ( myType != RadioButtonController && intersect &&
+ (lv->rootIsDecorated() || myType == RadioButton ||
+ (myType == CheckBox && parentControl) ) ) {
+ QRect rect;
+ int boxsize = lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv);
+ if ( lv->columnAlignment(0) == AlignCenter ) {
+ QFontMetrics fm( lv->font() );
+ int bx = (lv->columnWidth(0) - (boxsize + fm.width(text())))/2 + boxsize;
+ if ( bx < 0 ) bx = 0;
+ rect.setRect( r.x() + bx + 5, r.y(), r.width() - bx - 5,
+ r.height() );
+ } else
+ rect.setRect( r.x() + boxsize + 5, r.y(), r.width() - boxsize - 5,
+ r.height() );
+ QListViewItem::paintFocus(p, cg, rect);
+ } else {
+ QListViewItem::paintFocus(p, cg, r);
+ }
+}
+
+/*!
+ \reimp
+*/
+QSize QListView::sizeHint() const
+{
+ if ( cachedSizeHint().isValid() )
+ return cachedSizeHint();
+
+ constPolish();
+
+ if ( !isVisible() && (!d->drawables || d->drawables->isEmpty()) )
+ // force the column widths to sanity, if possible
+ buildDrawableList();
+
+ QSize s( d->h->sizeHint() );
+ if ( verticalScrollBar()->isVisible() )
+ s.setWidth( s.width() + style().pixelMetric(QStyle::PM_ScrollBarExtent) );
+ s += QSize(frameWidth()*2,frameWidth()*2);
+ QListViewItem * l = d->r;
+ while( l && !l->height() )
+ l = l->childItem ? l->childItem : l->siblingItem;
+
+ if ( l && l->height() )
+ s.setHeight( s.height() + 10 * l->height() );
+ else
+ s.setHeight( s.height() + 140 );
+
+ if ( s.width() > s.height() * 3 )
+ s.setHeight( s.width() / 3 );
+ else if ( s.width() *3 < s.height() )
+ s.setHeight( s.width() * 3 );
+
+ setCachedSizeHint( s );
+
+ return s;
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize QListView::minimumSizeHint() const
+{
+ return QScrollView::minimumSizeHint();
+}
+
+
+/*!
+ Sets \a item to be open if \a open is TRUE and \a item is
+ expandable, and to be closed if \a open is FALSE. Repaints
+ accordingly.
+
+ \sa QListViewItem::setOpen() QListViewItem::setExpandable()
+*/
+
+void QListView::setOpen( QListViewItem * item, bool open )
+{
+ if ( !item ||
+ item->isOpen() == open ||
+ (open && !item->childCount() && !item->isExpandable()) )
+ return;
+
+ QListViewItem* nextParent = 0;
+ if ( open )
+ nextParent = item->itemBelow();
+
+ item->setOpen( open );
+
+ if ( open ) {
+ QListViewItem* lastChild = item;
+ QListViewItem* tmp;
+ while ( TRUE ) {
+ tmp = lastChild->itemBelow();
+ if ( !tmp || tmp == nextParent )
+ break;
+ lastChild = tmp;
+ }
+ ensureItemVisible( lastChild );
+ ensureItemVisible( item );
+ }
+ if ( d->drawables )
+ d->drawables->clear();
+ buildDrawableList();
+
+ QListViewPrivate::DrawableItem * c = d->drawables->first();
+
+ while( c && c->i && c->i != item )
+ c = d->drawables->next();
+
+ if ( c && c->i == item ) {
+ d->dirtyItemTimer->start( 0, TRUE );
+ if ( !d->dirtyItems )
+ d->dirtyItems = new QPtrDict<void>();
+ while( c && c->i ) {
+ d->dirtyItems->insert( (void *)(c->i), (void *)(c->i) );
+ c = d->drawables->next();
+ }
+ }
+}
+
+
+/*!
+ Identical to \a{item}->isOpen(). Provided for completeness.
+
+ \sa setOpen()
+*/
+
+bool QListView::isOpen( const QListViewItem * item ) const
+{
+ return item->isOpen();
+}
+
+
+/*!
+ \property QListView::rootIsDecorated
+ \brief whether the list view shows open/close signs on root items
+
+ Open/close signs are small <b>+</b> or <b>-</b> symbols in windows
+ style, or arrows in Motif style. The default is FALSE.
+*/
+
+void QListView::setRootIsDecorated( bool enable )
+{
+ if ( enable != (bool)d->rootIsExpandable ) {
+ d->rootIsExpandable = enable;
+ if ( isVisible() )
+ triggerUpdate();
+ }
+}
+
+bool QListView::rootIsDecorated() const
+{
+ return d->rootIsExpandable;
+}
+
+
+/*!
+ Ensures that item \a i is visible, scrolling the list view
+ vertically if necessary and opening (expanding) any parent items
+ if this is required to show the item.
+
+ \sa itemRect() QScrollView::ensureVisible()
+*/
+
+void QListView::ensureItemVisible( const QListViewItem * i )
+{
+ if ( !i || !i->isVisible() )
+ return;
+
+ QListViewItem *parent = i->parent();
+ while ( parent ) {
+ if ( !parent->isOpen() )
+ parent->setOpen( TRUE );
+ parent = parent->parent();
+ }
+
+ if ( d->r->maybeTotalHeight < 0 )
+ updateGeometries();
+ int y = itemPos( i );
+ int h = i->height();
+ if ( isVisible() && y + h > contentsY() + visibleHeight() )
+ setContentsPos( contentsX(), y - visibleHeight() + h );
+ else if ( !isVisible() || y < contentsY() )
+ setContentsPos( contentsX(), y );
+}
+
+
+/*!
+ \fn QString QCheckListItem::text( int n ) const
+
+ \reimp
+*/
+
+/*!
+ Returns the QHeader object that manages this list view's columns.
+ Please don't modify the header behind the list view's back.
+
+ You may safely call QHeader::setClickEnabled(),
+ QHeader::setResizeEnabled(), QHeader::setMovingEnabled(),
+ QHeader::hide() and all the const QHeader functions.
+*/
+
+QHeader * QListView::header() const
+{
+ return d->h;
+}
+
+
+/*!
+ \property QListView::childCount
+ \brief the number of parentless (top-level) QListViewItem objects in this QListView
+
+ Holds the current number of parentless (top-level) QListViewItem
+ objects in this QListView.
+
+ \sa QListViewItem::childCount()
+*/
+
+int QListView::childCount() const
+{
+ if ( d->r )
+ return d->r->childCount();
+ return 0;
+}
+
+
+/*
+ Moves this item to just after \a olderSibling. \a olderSibling and
+ this object must have the same parent.
+
+ If you need to move an item in the hierarchy use takeItem() and
+ insertItem().
+*/
+
+void QListViewItem::moveToJustAfter( QListViewItem * olderSibling )
+{
+ if ( parentItem && olderSibling &&
+ olderSibling->parentItem == parentItem && olderSibling != this ) {
+ if ( parentItem->childItem == this ) {
+ parentItem->childItem = siblingItem;
+ } else {
+ QListViewItem * i = parentItem->childItem;
+ while( i && i->siblingItem != this )
+ i = i->siblingItem;
+ if ( i )
+ i->siblingItem = siblingItem;
+ }
+ siblingItem = olderSibling->siblingItem;
+ olderSibling->siblingItem = this;
+ parentItem->lsc = Unsorted;
+ }
+}
+
+/*!
+ Move the item to be after item \a after, which must be one of the
+ item's siblings. To move an item in the hierarchy, use takeItem()
+ and insertItem().
+
+ Note that this function will have no effect if sorting is enabled
+ in the list view.
+*/
+
+void QListViewItem::moveItem( QListViewItem *after )
+{
+ if ( !after || after == this )
+ return;
+ if ( parent() != after->parent() ) {
+ if ( parentItem )
+ parentItem->takeItem( this );
+ if ( after->parentItem ) {
+ int tmpLsc = after->parentItem->lsc;
+ after->parentItem->insertItem( this );
+ after->parentItem->lsc = tmpLsc;
+ }
+ }
+ moveToJustAfter( after );
+ QListView *lv = listView();
+ if ( lv )
+ lv->triggerUpdate();
+}
+
+/*
+ Recursively sorts items, from the root to this item.
+ (enforceSortOrder() won't work the other way around, as
+ documented.)
+*/
+void QListViewItem::enforceSortOrderBackToRoot()
+{
+ if ( parentItem ) {
+ parentItem->enforceSortOrderBackToRoot();
+ parentItem->enforceSortOrder();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QListView::showEvent( QShowEvent * )
+{
+ if ( d->drawables )
+ d->drawables->clear();
+ delete d->dirtyItems;
+ d->dirtyItems = 0;
+ d->dirtyItemTimer->stop();
+ d->fullRepaintOnComlumnChange = TRUE;
+
+ updateGeometries();
+}
+
+
+/*!
+ Returns the y coordinate of this item in the list view's
+ coordinate system. This function is normally much slower than
+ QListView::itemAt(), but it works for all items whereas
+ QListView::itemAt() normally only works for items on the screen.
+
+ \sa QListView::itemAt() QListView::itemRect() QListView::itemPos()
+*/
+
+int QListViewItem::itemPos() const
+{
+ QPtrStack<QListViewItem> s;
+ QListViewItem * i = (QListViewItem *)this;
+ while( i ) {
+ s.push( i );
+ i = i->parentItem;
+ }
+
+ int a = 0;
+ QListViewItem * p = 0;
+ while( s.count() ) {
+ i = s.pop();
+ if ( p ) {
+ if ( !p->configured ) {
+ p->configured = TRUE;
+ p->setup(); // ### virtual non-const function called in const
+ }
+ a += p->height();
+ QListViewItem * s = p->firstChild();
+ while( s && s != i ) {
+ a += s->totalHeight();
+ s = s->nextSibling();
+ }
+ }
+ p = i;
+ }
+ return a;
+}
+
+
+/*!
+ \fn void QListView::removeItem( QListViewItem * )
+ \obsolete
+
+ This function has been renamed takeItem().
+*/
+
+/*!
+ Removes item \a i from the list view; \a i must be a top-level
+ item. The warnings regarding QListViewItem::takeItem() apply to
+ this function, too.
+
+ \sa insertItem()
+*/
+void QListView::takeItem( QListViewItem * i )
+{
+ if ( d->r )
+ d->r->takeItem( i );
+}
+
+
+void QListView::openFocusItem()
+{
+ d->autoopenTimer->stop();
+ if ( d->focusItem && !d->focusItem->isOpen() ) {
+ d->focusItem->setOpen( TRUE );
+ d->focusItem->repaint();
+ }
+}
+
+static const int autoopenTime = 750;
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*! \reimp */
+
+void QListView::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ d->oldFocusItem = d->focusItem;
+ QListViewItem *i = d->focusItem;
+ d->focusItem = itemAt( contentsToViewport( e->pos() ) );
+ if ( i )
+ i->repaint();
+ if ( d->focusItem ) {
+ d->autoopenTimer->start( autoopenTime );
+ d->focusItem->dragEntered();
+ d->focusItem->repaint();
+ }
+ if ( i && i->dropEnabled() && i->acceptDrop( e ) || acceptDrops() )
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*! \reimp */
+
+void QListView::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ QListViewItem *i = d->focusItem;
+ d->focusItem = itemAt( contentsToViewport( e->pos() ) );
+ if ( i ) {
+ if ( i != d->focusItem )
+ i->dragLeft();
+ i->repaint();
+ }
+ if ( d->focusItem ) {
+ if ( i != d->focusItem ) {
+ d->focusItem->dragEntered();
+ d->autoopenTimer->stop();
+ d->autoopenTimer->start( autoopenTime );
+ }
+ d->focusItem->repaint();
+ } else {
+ d->autoopenTimer->stop();
+ }
+ if ( i && i->dropEnabled() && i->acceptDrop( e ) || acceptDrops() )
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*! \reimp */
+
+void QListView::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+ d->autoopenTimer->stop();
+
+ if ( d->focusItem )
+ d->focusItem->dragLeft();
+
+ setCurrentItem( d->oldFocusItem );
+ d->oldFocusItem = 0;
+}
+
+/*! \reimp */
+
+void QListView::contentsDropEvent( QDropEvent *e )
+{
+ d->autoopenTimer->stop();
+
+ setCurrentItem( d->oldFocusItem );
+ QListViewItem *i = itemAt( contentsToViewport( e->pos() ) );
+ if ( i && i->dropEnabled() && i->acceptDrop( e ) ) {
+ i->dropped( e );
+ e->accept();
+ } else if ( acceptDrops() ) {
+ emit dropped( e );
+ e->accept();
+ }
+}
+
+/*!
+ If the user presses the mouse on an item and starts moving the
+ mouse, and the item allow dragging (see
+ QListViewItem::setDragEnabled()), this function is called to get a
+ drag object and a drag is started unless dragObject() returns 0.
+
+ By default this function returns 0. You should reimplement it and
+ create a QDragObject depending on the selected items.
+*/
+
+QDragObject *QListView::dragObject()
+{
+ return 0;
+}
+
+/*!
+ Starts a drag.
+*/
+
+void QListView::startDrag()
+{
+ if ( !d->startDragItem )
+ return;
+
+ d->startDragItem = 0;
+ d->buttonDown = FALSE;
+
+ QDragObject *drag = dragObject();
+ if ( !drag )
+ return;
+
+ drag->drag();
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+ \property QListView::defaultRenameAction
+ \brief What action to perform when the editor loses focus during renaming
+
+ If this property is \c Accept, and the user renames an item and
+ the editor loses focus (without the user pressing Enter), the
+ item will still be renamed. If the property's value is \c Reject,
+ the item will not be renamed unless the user presses Enter. The
+ default is \c Reject.
+*/
+
+void QListView::setDefaultRenameAction( RenameAction a )
+{
+ d->defRenameAction = a;
+}
+
+QListView::RenameAction QListView::defaultRenameAction() const
+{
+ return d->defRenameAction;
+}
+
+/*!
+ Returns TRUE if an item is being renamed; otherwise returns FALSE.
+*/
+
+bool QListView::isRenaming() const
+{
+ return currentItem() && currentItem()->renameBox;
+}
+
+/**********************************************************************
+ *
+ * Class QListViewItemIterator
+ *
+ **********************************************************************/
+
+
+/*!
+ \class QListViewItemIterator
+ \brief The QListViewItemIterator class provides an iterator for collections of QListViewItems.
+
+ \ingroup advanced
+
+ Construct an instance of a QListViewItemIterator, with either a
+ QListView* or a QListViewItem* as argument, to operate on the tree
+ of QListViewItems, starting from the argument.
+
+ A QListViewItemIterator iterates over all the items from its
+ starting point. This means that it always makes the first child of
+ the current item the new current item. If there is no child, the
+ next sibling becomes the new current item; and if there is no next
+ sibling, the next sibling of the parent becomes current.
+
+ The following example creates a list of all the items that have
+ been selected by the user, storing pointers to the items in a
+ QPtrList:
+ \code
+ QPtrList<QListViewItem> lst;
+ QListViewItemIterator it( myListView );
+ while ( it.current() ) {
+ if ( it.current()->isSelected() )
+ lst.append( it.current() );
+ ++it;
+ }
+ \endcode
+
+ An alternative approach is to use an \c IteratorFlag:
+ \code
+ QPtrList<QListViewItem> lst;
+ QListViewItemIterator it( myListView, QListViewItemIterator::Selected );
+ while ( it.current() ) {
+ lst.append( it.current() );
+ ++it;
+ }
+ \endcode
+
+ A QListViewItemIterator provides a convenient and easy way to
+ traverse a hierarchical QListView.
+
+ Multiple QListViewItemIterators can operate on the tree of
+ QListViewItems. A QListView knows about all iterators operating on
+ its QListViewItems. So when a QListViewItem gets removed all
+ iterators that point to this item are updated and point to the
+ following item if possible, otherwise to a valid item before the
+ current one or to 0. Note however that deleting the parent item of
+ an item that an iterator points to is not safe.
+
+ \sa QListView, QListViewItem
+*/
+
+/*!
+ \enum QListViewItemIterator::IteratorFlag
+
+ These flags can be passed to a QListViewItemIterator constructor
+ (OR-ed together if more than one is used), so that the iterator
+ will only iterate over items that match the given flags.
+
+ \value Visible
+ \value Invisible
+ \value Selected
+ \value Unselected
+ \value Selectable
+ \value NotSelectable
+ \value DragEnabled
+ \value DragDisabled
+ \value DropEnabled
+ \value DropDisabled
+ \value Expandable
+ \value NotExpandable
+ \value Checked
+ \value NotChecked
+*/
+
+/*!
+ Constructs an empty iterator.
+*/
+
+QListViewItemIterator::QListViewItemIterator()
+ : curr( 0 ), listView( 0 )
+{
+ init( 0 );
+}
+
+/*!
+ Constructs an iterator for the QListView that contains the \a
+ item. The current iterator item is set to point to the \a item.
+*/
+
+QListViewItemIterator::QListViewItemIterator( QListViewItem *item )
+ : curr( item ), listView( 0 )
+{
+ init( 0 );
+
+ if ( item ) {
+ item->enforceSortOrderBackToRoot();
+ listView = item->listView();
+ }
+ addToListView();
+}
+
+/*!
+ Constructs an iterator for the QListView that contains the \a item
+ using the flags \a iteratorFlags. The current iterator item is set
+ to point to \a item or the next matching item if \a item doesn't
+ match the flags.
+
+ \sa QListViewItemIterator::IteratorFlag
+*/
+
+QListViewItemIterator::QListViewItemIterator( QListViewItem *item, int iteratorFlags )
+ : curr( item ), listView( 0 )
+{
+ init( iteratorFlags );
+
+ // go to next matching item if the current don't match
+ if ( curr && !matchesFlags( curr ) )
+ ++( *this );
+
+ if ( curr ) {
+ curr->enforceSortOrderBackToRoot();
+ listView = curr->listView();
+ }
+ addToListView();
+}
+
+
+/*!
+ Constructs an iterator for the same QListView as \a it. The
+ current iterator item is set to point on the current item of \a
+ it.
+*/
+
+QListViewItemIterator::QListViewItemIterator( const QListViewItemIterator& it )
+ : curr( it.curr ), listView( it.listView )
+{
+ init(it.d() ? it.d()->flags : 0);
+
+ addToListView();
+}
+
+/*!
+ Constructs an iterator for the QListView \a lv. The current
+ iterator item is set to point on the first child (QListViewItem)
+ of \a lv.
+*/
+
+QListViewItemIterator::QListViewItemIterator( QListView *lv )
+ : curr( lv->firstChild() ), listView( lv )
+{
+ init( 0 );
+
+ addToListView();
+}
+
+/*!
+ Constructs an iterator for the QListView \a lv with the flags \a
+ iteratorFlags. The current iterator item is set to point on the
+ first child (QListViewItem) of \a lv that matches the flags.
+
+ \sa QListViewItemIterator::IteratorFlag
+*/
+
+QListViewItemIterator::QListViewItemIterator( QListView *lv, int iteratorFlags )
+ : curr ( lv->firstChild() ), listView( lv )
+{
+ init( iteratorFlags );
+
+ addToListView();
+ if ( !matchesFlags( curr ) )
+ ++( *this );
+}
+
+
+
+/*!
+ Assignment. Makes a copy of \a it and returns a reference to its
+ iterator.
+*/
+
+QListViewItemIterator &QListViewItemIterator::operator=( const QListViewItemIterator &it )
+{
+ if ( listView ) {
+ if ( listView->d->iterators->removeRef( this ) ) {
+ if ( listView->d->iterators->count() == 0 ) {
+ delete listView->d->iterators;
+ listView->d->iterators = 0;
+ }
+ }
+ }
+
+ listView = it.listView;
+ addToListView();
+ curr = it.curr;
+
+ // sets flags to be the same as the input iterators flags
+ if ( d() && it.d() )
+ d()->flags = it.d()->flags;
+
+ // go to next matching item if the current don't match
+ if ( curr && !matchesFlags( curr ) )
+ ++( *this );
+
+ return *this;
+}
+
+/*!
+ Destroys the iterator.
+*/
+
+QListViewItemIterator::~QListViewItemIterator()
+{
+ if ( listView ) {
+ if ( listView->d->iterators->removeRef( this ) ) {
+ if ( listView->d->iterators->count() == 0 ) {
+ delete listView->d->iterators;
+ listView->d->iterators = 0;
+ }
+ }
+ }
+ // removs the d-ptr from the dict ( autodelete on), and deletes the
+ // ptrdict if it becomes empty
+ if ( qt_iteratorprivate_dict ) {
+ qt_iteratorprivate_dict->remove( this );
+ if ( qt_iteratorprivate_dict->isEmpty() ) {
+ delete qt_iteratorprivate_dict;
+ qt_iteratorprivate_dict = 0;
+ }
+ }
+}
+
+/*!
+ Prefix ++. Makes the next item the new current item and returns
+ it. Returns 0 if the current item is the last item or the
+ QListView is 0.
+*/
+
+QListViewItemIterator &QListViewItemIterator::operator++()
+{
+ do {
+ if ( !curr )
+ return *this;
+
+ QListViewItem *item = curr->firstChild();
+ if ( !item ) {
+ while ( (item = curr->nextSibling()) == 0 ) {
+ curr = curr->parent();
+ if ( curr == 0 )
+ break;
+ }
+ }
+ curr = item;
+ // if the next one doesn't match the flags we try one more ahead
+ } while ( curr && !matchesFlags( curr ) );
+ return *this;
+}
+
+/*!
+ \overload
+
+ Postfix ++. Makes the next item the new current item and returns
+ the item that \e was the current item.
+*/
+
+const QListViewItemIterator QListViewItemIterator::operator++( int )
+{
+ QListViewItemIterator oldValue = *this;
+ ++( *this );
+ return oldValue;
+}
+
+/*!
+ Sets the current item to the item \a j positions after the current
+ item. If that item is beyond the last item, the current item is
+ set to 0. Returns the current item.
+*/
+
+QListViewItemIterator &QListViewItemIterator::operator+=( int j )
+{
+ while ( curr && j-- )
+ ++( *this );
+
+ return *this;
+}
+
+/*!
+ Prefix --. Makes the previous item the new current item and
+ returns it. Returns 0 if the current item is the first item or the
+ QListView is 0.
+*/
+
+QListViewItemIterator &QListViewItemIterator::operator--()
+{
+ if ( !curr )
+ return *this;
+
+ if ( !curr->parent() ) {
+ // we are in the first depth
+ if ( curr->listView() ) {
+ if ( curr->listView()->firstChild() != curr ) {
+ // go the previous sibling
+ QListViewItem *i = curr->listView()->firstChild();
+ while ( i && i->siblingItem != curr )
+ i = i->siblingItem;
+
+ curr = i;
+
+ if ( i && i->firstChild() ) {
+ // go to the last child of this item
+ QListViewItemIterator it( curr->firstChild() );
+ for ( ; it.current() && it.current()->parent(); ++it )
+ curr = it.current();
+ }
+
+ if ( curr && !matchesFlags( curr ) )
+ --( *this );
+
+ return *this;
+ } else {
+ //we are already the first child of the list view, so it's over
+ curr = 0;
+ return *this;
+ }
+ } else
+ return *this;
+ } else {
+ QListViewItem *parent = curr->parent();
+
+ if ( curr != parent->firstChild() ) {
+ // go to the previous sibling
+ QListViewItem *i = parent->firstChild();
+ while ( i && i->siblingItem != curr )
+ i = i->siblingItem;
+
+ curr = i;
+
+ if ( i && i->firstChild() ) {
+ // go to the last child of this item
+ QListViewItemIterator it( curr->firstChild() );
+ for ( ; it.current() && it.current()->parent() != parent; ++it )
+ curr = it.current();
+ }
+
+ if ( curr && !matchesFlags( curr ) )
+ --( *this );
+
+ return *this;
+ } else {
+ // make our parent the current item
+ curr = parent;
+
+ if ( curr && !matchesFlags( curr ) )
+ --( *this );
+
+ return *this;
+ }
+ }
+}
+
+/*!
+ \overload
+
+ Postfix --. Makes the previous item the new current item and
+ returns the item that \e was the current item.
+*/
+
+const QListViewItemIterator QListViewItemIterator::operator--( int )
+{
+ QListViewItemIterator oldValue = *this;
+ --( *this );
+ return oldValue;
+}
+
+/*!
+ Sets the current item to the item \a j positions before the
+ current item. If that item is before the first item, the current
+ item is set to 0. Returns the current item.
+*/
+
+QListViewItemIterator &QListViewItemIterator::operator-=( int j )
+{
+ while ( curr && j-- )
+ --( *this );
+
+ return *this;
+}
+
+/*!
+ Dereference operator. Returns a reference to the current item. The
+ same as current().
+*/
+
+QListViewItem* QListViewItemIterator::operator*()
+{
+ if ( curr != 0 && !matchesFlags( curr ) )
+ qWarning( "QListViewItemIterator::operator*() curr out of sync" );
+ return curr;
+}
+
+/*!
+ Returns iterator's current item.
+*/
+
+QListViewItem *QListViewItemIterator::current() const
+{
+ if ( curr != 0 && !matchesFlags( curr ) )
+ qWarning( "QListViewItemIterator::current() curr out of sync" );
+ return curr;
+}
+
+QListViewItemIteratorPrivate* QListViewItemIterator::d() const
+{
+ return qt_iteratorprivate_dict ?
+ qt_iteratorprivate_dict->find( (void *)this ) : 0;
+}
+
+void QListViewItemIterator::init( int iteratorFlags )
+{
+ // makes new global ptrdict if it doesn't exist
+ if ( !qt_iteratorprivate_dict ) {
+ qt_iteratorprivate_dict = new QPtrDict<QListViewItemIteratorPrivate>;
+ qt_iteratorprivate_dict->setAutoDelete( TRUE );
+ }
+
+ // sets flag, or inserts new QListViewItemIteratorPrivate with flag
+ if ( d() )
+ d()->flags = iteratorFlags;
+ else
+ qt_iteratorprivate_dict->insert( this, new QListViewItemIteratorPrivate( iteratorFlags ) );
+}
+
+
+/*
+ Adds this iterator to its QListView's list of iterators.
+*/
+
+void QListViewItemIterator::addToListView()
+{
+ if ( listView ) {
+ if ( !listView->d->iterators ) {
+ listView->d->iterators = new QPtrList<QListViewItemIterator>;
+ Q_CHECK_PTR( listView->d->iterators );
+ }
+ listView->d->iterators->append( this );
+ }
+}
+
+/*
+ This function is called to notify the iterator that the current
+ item has been deleted, and sets the current item point to another
+ (valid) item or 0.
+*/
+
+void QListViewItemIterator::currentRemoved()
+{
+ if ( !curr ) return;
+
+ if ( curr->parent() )
+ curr = curr->parent();
+ else if ( curr->nextSibling() )
+ curr = curr->nextSibling();
+ else if ( listView && listView->firstChild() &&
+ listView->firstChild() != curr )
+ curr = listView->firstChild();
+ else
+ curr = 0;
+}
+
+/*
+ returns TRUE if the item \a item matches all of the flags set for the iterator
+*/
+bool QListViewItemIterator::matchesFlags( const QListViewItem *item ) const
+{
+ if ( !item )
+ return FALSE;
+
+ int flags = d() ? d()->flags : 0;
+
+ if ( flags == 0 )
+ return TRUE;
+
+ if ( flags & Visible && !item->isVisible() )
+ return FALSE;
+ if ( flags & Invisible && item->isVisible() )
+ return FALSE;
+ if ( flags & Selected && !item->isSelected() )
+ return FALSE;
+ if ( flags & Unselected && item->isSelected() )
+ return FALSE;
+ if ( flags & Selectable && !item->isSelectable() )
+ return FALSE;
+ if ( flags & NotSelectable && item->isSelectable() )
+ return FALSE;
+ if ( flags & DragEnabled && !item->dragEnabled() )
+ return FALSE;
+ if ( flags & DragDisabled && item->dragEnabled() )
+ return FALSE;
+ if ( flags & DropEnabled && !item->dropEnabled() )
+ return FALSE;
+ if ( flags & DropDisabled && item->dropEnabled() )
+ return FALSE;
+ if ( flags & Expandable && !item->isExpandable() )
+ return FALSE;
+ if ( flags & NotExpandable && item->isExpandable() )
+ return FALSE;
+ if ( flags & Checked && !isChecked( item ) )
+ return FALSE;
+ if ( flags & NotChecked && isChecked( item ) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ we want the iterator to check QCheckListItems as well, so we provide this convenience function
+ that checks if the rtti() is 1 which means QCheckListItem and if isOn is TRUE, returns FALSE otherwise.
+*/
+bool QListViewItemIterator::isChecked( const QListViewItem *item ) const
+{
+ if ( item->rtti() == 1 )
+ return ((const QCheckListItem*)item)->isOn();
+ else return FALSE;
+}
+
+void QListView::handleItemChange( QListViewItem *old, bool shift, bool control )
+{
+ if ( d->selectionMode == Single ) {
+ // nothing
+ } else if ( d->selectionMode == Extended ) {
+ if ( shift ) {
+ selectRange( d->selectAnchor ? d->selectAnchor : old,
+ d->focusItem, FALSE, TRUE, (d->selectAnchor && !control) ? TRUE : FALSE );
+ } else if ( !control ) {
+ bool block = signalsBlocked();
+ blockSignals( TRUE );
+ selectAll( FALSE );
+ blockSignals( block );
+ setSelected( d->focusItem, TRUE );
+ }
+ } else if ( d->selectionMode == Multi ) {
+ if ( shift )
+ selectRange( old, d->focusItem, TRUE, FALSE );
+ }
+}
+
+void QListView::startRename()
+{
+ if ( !currentItem() )
+ return;
+ currentItem()->startRename( d->pressedColumn );
+ d->buttonDown = FALSE;
+}
+
+/* unselects items from to, including children, returns TRUE if any items were unselected */
+bool QListView::clearRange( QListViewItem *from, QListViewItem *to, bool includeFirst )
+{
+ if ( !from || !to )
+ return FALSE;
+
+ // Swap
+ if ( from->itemPos() > to->itemPos() ) {
+ QListViewItem *temp = from;
+ from = to;
+ to = temp;
+ }
+
+ // Start on second?
+ if ( !includeFirst ) {
+ QListViewItem *below = (from == to) ? from : from->itemBelow();
+ if ( below )
+ from = below;
+ }
+
+ // Clear items <from, to>
+ bool changed = FALSE;
+
+ QListViewItemIterator it( from );
+ while ( it.current() ) {
+ if ( it.current()->isSelected() ) {
+ it.current()->setSelected( FALSE );
+ changed = TRUE;
+ }
+ if ( it.current() == to )
+ break;
+ ++it;
+ }
+
+ // NOTE! This function does _not_ emit
+ // any signals about selection changed
+ return changed;
+}
+
+void QListView::selectRange( QListViewItem *from, QListViewItem *to, bool invert, bool includeFirst, bool clearSel )
+{
+ if ( !from || !to )
+ return;
+ if ( from == to && !includeFirst )
+ return;
+ bool swap = FALSE;
+ if ( to == from->itemAbove() )
+ swap = TRUE;
+ if ( !swap && from != to && from != to->itemAbove() ) {
+ QListViewItemIterator it( from );
+ bool found = FALSE;
+ for ( ; it.current(); ++it ) {
+ if ( it.current() == to ) {
+ found = TRUE;
+ break;
+ }
+ }
+ if ( !found )
+ swap = TRUE;
+ }
+ if ( swap ) {
+ QListViewItem *i = from;
+ from = to;
+ to = i;
+ if ( !includeFirst )
+ to = to->itemAbove();
+ } else {
+ if ( !includeFirst )
+ from = from->itemBelow();
+ }
+
+ bool changed = FALSE;
+ if ( clearSel ) {
+ QListViewItemIterator it( firstChild() );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->selected ) {
+ it.current()->setSelected( FALSE );
+ changed = TRUE;
+ }
+ }
+ it = QListViewItemIterator( to );
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->selected ) {
+ it.current()->setSelected( FALSE );
+ changed = TRUE;
+ }
+ }
+ }
+
+ for ( QListViewItem *i = from; i; i = i->itemBelow() ) {
+ if ( !invert ) {
+ if ( !i->selected && i->isSelectable() ) {
+ i->setSelected( TRUE );
+ changed = TRUE;
+ }
+ } else {
+ bool sel = !i->selected;
+ if ( (bool)i->selected != sel && sel && i->isSelectable() || !sel ) {
+ i->setSelected( sel );
+ changed = TRUE;
+ }
+ }
+ if ( i == to )
+ break;
+ }
+ if ( changed ) {
+ d->useDoubleBuffer = TRUE;
+ triggerUpdate();
+ emit selectionChanged();
+ }
+}
+
+/* clears selection from anchor to old, selects from anchor to new, does not emit selectionChanged on change */
+bool QListView::selectRange( QListViewItem *newItem, QListViewItem *oldItem, QListViewItem *anchorItem )
+{
+ if ( !newItem || !oldItem || !anchorItem )
+ return FALSE;
+
+ int anchorPos = anchorItem ? anchorItem->itemPos() : 0,
+ oldPos = oldItem ? oldItem->itemPos() : 0,
+ newPos = newItem->itemPos();
+ QListViewItem *top=0, *bottom=0;
+ if ( anchorPos > newPos ) {
+ top = newItem;
+ bottom = anchorItem;
+ } else {
+ top = anchorItem;
+ bottom = newItem;
+ }
+
+ // removes the parts of the old selection that will no longer be selected
+ bool changed = FALSE;
+ int topPos = top ? top->itemPos() : 0,
+ bottomPos = bottom ? bottom->itemPos() : 0;
+ if ( !(oldPos > topPos && oldPos < bottomPos) ) {
+ if ( oldPos < topPos )
+ changed = clearRange( oldItem, top );
+ else
+ changed = clearRange( bottom, oldItem );
+ }
+
+ // selects the new (not already selected) items
+ QListViewItemIterator lit( top );
+ for ( ; lit.current(); ++lit ) {
+ if ( (bool)lit.current()->selected != d->select ) {
+ lit.current()->setSelected( d->select );
+ changed = TRUE;
+ }
+ // Include bottom, then break
+ if ( lit.current() == bottom )
+ break;
+ }
+
+ return changed;
+}
+
+
+/*!
+ Finds the first list view item in column \a column, that matches
+ \a text and returns the item, or returns 0 of no such item could
+ be found.
+ The search starts from the current item if the current item exists,
+ otherwise it starts from the first list view item. After reaching
+ the last item the search continues from the first item.
+ Pass OR-ed together \l Qt::StringComparisonMode values
+ in the \a compare flag, to control how the matching is performed.
+ The default comparison mode is case-sensitive, exact match.
+*/
+
+QListViewItem *QListView::findItem( const QString& text, int column,
+ ComparisonFlags compare ) const
+{
+ if (text.isEmpty() && !(compare & ExactMatch))
+ return 0;
+
+ if ( compare == CaseSensitive || compare == 0 )
+ compare |= ExactMatch;
+
+ QString itmtxt;
+ QString comtxt = text;
+ if ( !(compare & CaseSensitive) )
+ comtxt = comtxt.lower();
+
+ QListViewItemIterator it( d->focusItem ? d->focusItem : firstChild() );
+ QListViewItem *sentinel = 0;
+ QListViewItem *item;
+ QListViewItem *beginsWithItem = 0;
+ QListViewItem *endsWithItem = 0;
+ QListViewItem *containsItem = 0;
+
+ for ( int pass = 0; pass < 2; pass++ ) {
+ while ( (item = it.current()) != sentinel ) {
+ itmtxt = item->text( column );
+ if ( !(compare & CaseSensitive) )
+ itmtxt = itmtxt.lower();
+
+ if ( compare & ExactMatch && itmtxt == comtxt )
+ return item;
+ if ( compare & BeginsWith && !beginsWithItem && itmtxt.startsWith( comtxt ) )
+ beginsWithItem = containsItem = item;
+ if ( compare & EndsWith && !endsWithItem && itmtxt.endsWith( comtxt ) )
+ endsWithItem = containsItem = item;
+ if ( compare & Contains && !containsItem && itmtxt.contains( comtxt ) )
+ containsItem = item;
+ ++it;
+ }
+
+ it = QListViewItemIterator( firstChild() );
+ sentinel = d->focusItem ? d->focusItem : firstChild();
+ }
+
+ // Obey the priorities
+ if ( beginsWithItem )
+ return beginsWithItem;
+ else if ( endsWithItem )
+ return endsWithItem;
+ else if ( containsItem )
+ return containsItem;
+ return 0;
+}
+
+/*! \reimp */
+void QListView::windowActivationChange( bool oldActive )
+{
+ if ( oldActive && d->scrollTimer )
+ d->scrollTimer->stop();
+ if ( palette().active() != palette().inactive() )
+ viewport()->update();
+ QScrollView::windowActivationChange( oldActive );
+}
+
+/*!
+ Hides the column specified at \a column. This is a convenience
+ function that calls setColumnWidth( \a column, 0 ).
+
+ Note: The user may still be able to resize the hidden column using
+ the header handles. To prevent this, call setResizeEnabled(FALSE,
+ \a column) on the list views header.
+
+ \sa setColumnWidth()
+*/
+
+void QListView::hideColumn( int column )
+{
+ setColumnWidth( column, 0 );
+}
+
+/*! Adjusts the column \a col to its preferred width */
+
+void QListView::adjustColumn( int col )
+{
+ if ( col < 0 || col > (int)d->column.count() - 1 || d->h->isStretchEnabled( col ) )
+ return;
+
+ int oldw = d->h->sectionSize( col );
+
+ int w = d->h->sectionSizeHint( col, fontMetrics() ).width();
+ if ( d->h->iconSet( col ) )
+ w += d->h->iconSet( col )->pixmap().width();
+ w = QMAX( w, 20 );
+ QFontMetrics fm( fontMetrics() );
+ QListViewItem* item = firstChild();
+ int rootDepth = rootIsDecorated() ? treeStepSize() : 0;
+ while ( item ) {
+ int iw = item->width( fm, this, col );
+ if ( 0 == col )
+ iw += itemMargin() + rootDepth + item->depth()*treeStepSize() - 1;
+ w = QMAX( w, iw );
+ item = item->itemBelow();
+ }
+ w = QMAX( w, QApplication::globalStrut().width() );
+
+ d->h->adjustHeaderSize( oldw - w );
+ if (oldw != w) {
+ d->fullRepaintOnComlumnChange = TRUE;
+ d->h->resizeSection( col, w );
+ emit d->h->sizeChange( col, oldw, w);
+ }
+}
+
+#endif // QT_NO_LISTVIEW
diff --git a/src/widgets/qlistview.h b/src/widgets/qlistview.h
new file mode 100644
index 0000000..e5dc0e4
--- /dev/null
+++ b/src/widgets/qlistview.h
@@ -0,0 +1,605 @@
+/****************************************************************************
+**
+** Definition of QListView widget class
+**
+** Created : 970809
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QLISTVIEW_H
+#define QLISTVIEW_H
+
+#ifndef QT_H
+#include "qscrollview.h"
+#endif // QT_H
+
+#ifndef QT_NO_LISTVIEW
+
+
+class QPixmap;
+class QFont;
+class QHeader;
+class QIconSet;
+
+class QListView;
+struct QListViewPrivate;
+struct QCheckListItemPrivate;
+class QListViewItemIterator;
+struct QListViewItemIteratorPrivate;
+class QDragObject;
+class QMimeSource;
+class QLineEdit;
+class QListViewToolTip;
+
+class Q_EXPORT QListViewItem : public Qt
+{
+ friend class QListViewItemIterator;
+ friend class QListViewToolTip;
+
+public:
+ QListViewItem( QListView * parent );
+ QListViewItem( QListViewItem * parent );
+ QListViewItem( QListView * parent, QListViewItem * after );
+ QListViewItem( QListViewItem * parent, QListViewItem * after );
+
+ QListViewItem( QListView * parent,
+ QString, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null );
+ QListViewItem( QListViewItem * parent,
+ QString, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null );
+
+ QListViewItem( QListView * parent, QListViewItem * after,
+ QString, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null );
+ QListViewItem( QListViewItem * parent, QListViewItem * after,
+ QString, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null,
+ QString = QString::null, QString = QString::null );
+ virtual ~QListViewItem();
+
+ virtual void insertItem( QListViewItem * );
+ virtual void takeItem( QListViewItem * );
+ virtual void removeItem( QListViewItem *item ) { takeItem( item ); } //obsolete, use takeItem instead
+
+ int height() const;
+ virtual void invalidateHeight();
+ int totalHeight() const;
+ virtual int width( const QFontMetrics&,
+ const QListView*, int column) const;
+ void widthChanged(int column=-1) const;
+ int depth() const;
+
+ virtual void setText( int, const QString &);
+ virtual QString text( int ) const;
+
+ virtual void setPixmap( int, const QPixmap & );
+ virtual const QPixmap * pixmap( int ) const;
+
+ virtual QString key( int, bool ) const;
+ virtual int compare( QListViewItem *i, int col, bool ) const;
+ virtual void sortChildItems( int, bool );
+
+ int childCount() const { return nChildren; }
+
+ bool isOpen() const { return open; }
+ virtual void setOpen( bool );
+ virtual void setup();
+
+ virtual void setSelected( bool );
+ bool isSelected() const { return selected; }
+
+ virtual void paintCell( QPainter *, const QColorGroup & cg,
+ int column, int width, int alignment );
+ virtual void paintBranches( QPainter * p, const QColorGroup & cg,
+ int w, int y, int h );
+ virtual void paintFocus( QPainter *, const QColorGroup & cg,
+ const QRect & r );
+
+ QListViewItem * firstChild() const;
+ QListViewItem * nextSibling() const { return siblingItem; }
+ QListViewItem * parent() const;
+
+ QListViewItem * itemAbove();
+ QListViewItem * itemBelow();
+
+ int itemPos() const;
+
+ QListView *listView() const;
+
+ virtual void setSelectable( bool enable );
+ bool isSelectable() const { return selectable && enabled; }
+
+ virtual void setExpandable( bool );
+ bool isExpandable() const { return expandable; }
+
+ void repaint() const;
+
+ virtual void sort();
+ void moveItem( QListViewItem *after );
+
+ virtual void setDragEnabled( bool allow );
+ virtual void setDropEnabled( bool allow );
+ bool dragEnabled() const;
+ bool dropEnabled() const;
+ virtual bool acceptDrop( const QMimeSource *mime ) const;
+
+ void setVisible( bool b );
+ bool isVisible() const;
+
+ virtual void setRenameEnabled( int col, bool b );
+ bool renameEnabled( int col ) const;
+ virtual void startRename( int col );
+
+ virtual void setEnabled( bool b );
+ bool isEnabled() const;
+
+ virtual int rtti() const;
+ // ### Qt 4: make const or better use an enum
+ static int RTTI;
+
+ virtual void setMultiLinesEnabled( bool b );
+ bool multiLinesEnabled() const;
+
+protected:
+ virtual void enforceSortOrder() const;
+ virtual void setHeight( int );
+ virtual void activate();
+
+ bool activatedPos( QPoint & );
+#ifndef QT_NO_DRAGANDDROP
+ virtual void dropped( QDropEvent *e );
+#endif
+ virtual void dragEntered();
+ virtual void dragLeft();
+ virtual void okRename( int col );
+ virtual void cancelRename( int col );
+
+ void ignoreDoubleClick();
+
+private:
+ void init();
+ void moveToJustAfter( QListViewItem * );
+ void enforceSortOrderBackToRoot();
+ void removeRenameBox();
+
+ int ownHeight;
+ int maybeTotalHeight;
+ int nChildren;
+
+ uint lsc: 14;
+ uint lso: 1;
+ uint open : 1;
+ uint selected : 1;
+ uint selectable: 1;
+ uint configured: 1;
+ uint expandable: 1;
+ uint is_root: 1;
+ uint allow_drag : 1;
+ uint allow_drop : 1;
+ uint visible : 1;
+ uint enabled : 1;
+ uint mlenabled : 1;
+
+ QListViewItem * parentItem;
+ QListViewItem * siblingItem;
+ QListViewItem * childItem;
+ QLineEdit *renameBox;
+ int renameCol;
+
+ void * columns;
+
+ friend class QListView;
+};
+
+class QCheckListItem;
+
+class Q_EXPORT QListView: public QScrollView
+{
+ friend class QListViewItemIterator;
+ friend class QListViewItem;
+ friend class QCheckListItem;
+ friend class QListViewToolTip;
+
+ Q_OBJECT
+ Q_ENUMS( SelectionMode ResizeMode RenameAction )
+ Q_PROPERTY( int columns READ columns )
+ Q_PROPERTY( bool multiSelection READ isMultiSelection WRITE setMultiSelection DESIGNABLE false )
+ Q_PROPERTY( SelectionMode selectionMode READ selectionMode WRITE setSelectionMode )
+ Q_PROPERTY( int childCount READ childCount )
+ Q_PROPERTY( bool allColumnsShowFocus READ allColumnsShowFocus WRITE setAllColumnsShowFocus )
+ Q_PROPERTY( bool showSortIndicator READ showSortIndicator WRITE setShowSortIndicator )
+ Q_PROPERTY( int itemMargin READ itemMargin WRITE setItemMargin )
+ Q_PROPERTY( bool rootIsDecorated READ rootIsDecorated WRITE setRootIsDecorated )
+ Q_PROPERTY( bool showToolTips READ showToolTips WRITE setShowToolTips )
+ Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode )
+ Q_PROPERTY( int treeStepSize READ treeStepSize WRITE setTreeStepSize )
+ Q_PROPERTY( RenameAction defaultRenameAction READ defaultRenameAction WRITE setDefaultRenameAction )
+
+public:
+ QListView( QWidget* parent=0, const char* name=0, WFlags f = 0 );
+ ~QListView();
+
+ int treeStepSize() const;
+ virtual void setTreeStepSize( int );
+
+ virtual void insertItem( QListViewItem * );
+ virtual void takeItem( QListViewItem * );
+ virtual void removeItem( QListViewItem *item ) { takeItem( item ); } // obsolete, use takeItem instead
+
+ QHeader * header() const;
+
+ virtual int addColumn( const QString &label, int size = -1);
+ virtual int addColumn( const QIconSet& iconset, const QString &label, int size = -1);
+ virtual void removeColumn( int index );
+ virtual void setColumnText( int column, const QString &label );
+ virtual void setColumnText( int column, const QIconSet& iconset, const QString &label );
+ QString columnText( int column ) const;
+ virtual void setColumnWidth( int column, int width );
+ int columnWidth( int column ) const;
+ enum WidthMode { Manual, Maximum };
+ virtual void setColumnWidthMode( int column, WidthMode );
+ WidthMode columnWidthMode( int column ) const;
+ int columns() const;
+
+ virtual void setColumnAlignment( int, int );
+ int columnAlignment( int ) const;
+
+ void show();
+
+ QListViewItem * itemAt( const QPoint & screenPos ) const;
+ QRect itemRect( const QListViewItem * ) const;
+ int itemPos( const QListViewItem * );
+
+ void ensureItemVisible( const QListViewItem * );
+
+ void repaintItem( const QListViewItem * ) const;
+
+ virtual void setMultiSelection( bool enable );
+ bool isMultiSelection() const;
+
+ enum SelectionMode { Single, Multi, Extended, NoSelection };
+ void setSelectionMode( SelectionMode mode );
+ SelectionMode selectionMode() const;
+
+ virtual void clearSelection();
+ virtual void setSelected( QListViewItem *, bool );
+ void setSelectionAnchor( QListViewItem * );
+ bool isSelected( const QListViewItem * ) const;
+ QListViewItem * selectedItem() const;
+ virtual void setOpen( QListViewItem *, bool );
+ bool isOpen( const QListViewItem * ) const;
+
+ virtual void setCurrentItem( QListViewItem * );
+ QListViewItem * currentItem() const;
+
+ QListViewItem * firstChild() const;
+ QListViewItem * lastItem() const;
+
+ int childCount() const;
+
+ virtual void setAllColumnsShowFocus( bool );
+ bool allColumnsShowFocus() const;
+
+ virtual void setItemMargin( int );
+ int itemMargin() const;
+
+ virtual void setRootIsDecorated( bool );
+ bool rootIsDecorated() const;
+
+ virtual void setSorting( int column, bool ascending = TRUE );
+ int sortColumn() const;
+ void setSortColumn( int column );
+ SortOrder sortOrder() const;
+ void setSortOrder( SortOrder order );
+ virtual void sort();
+
+ virtual void setFont( const QFont & );
+ virtual void setPalette( const QPalette & );
+
+ bool eventFilter( QObject * o, QEvent * );
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ virtual void setShowSortIndicator( bool show );
+ bool showSortIndicator() const;
+ virtual void setShowToolTips( bool b );
+ bool showToolTips() const;
+
+ enum ResizeMode { NoColumn, AllColumns, LastColumn };
+ virtual void setResizeMode( ResizeMode m );
+ ResizeMode resizeMode() const;
+
+ QListViewItem * findItem( const QString& text, int column, ComparisonFlags compare = ExactMatch | CaseSensitive ) const;
+
+ enum RenameAction { Accept, Reject };
+ virtual void setDefaultRenameAction( RenameAction a );
+ RenameAction defaultRenameAction() const;
+ bool isRenaming() const;
+
+ void hideColumn( int column );
+
+public slots:
+ virtual void clear();
+ virtual void invertSelection();
+ virtual void selectAll( bool select );
+ void triggerUpdate();
+ void setContentsPos( int x, int y );
+ void adjustColumn( int col );
+
+signals:
+ void selectionChanged();
+ void selectionChanged( QListViewItem * );
+ void currentChanged( QListViewItem * );
+ void clicked( QListViewItem * );
+ void clicked( QListViewItem *, const QPoint &, int );
+ void pressed( QListViewItem * );
+ void pressed( QListViewItem *, const QPoint &, int );
+
+ void doubleClicked( QListViewItem * );
+ void doubleClicked( QListViewItem *, const QPoint&, int );
+ void returnPressed( QListViewItem * );
+ void spacePressed( QListViewItem * );
+ void rightButtonClicked( QListViewItem *, const QPoint&, int );
+ void rightButtonPressed( QListViewItem *, const QPoint&, int );
+ void mouseButtonPressed( int, QListViewItem *, const QPoint& , int );
+ void mouseButtonClicked( int, QListViewItem *, const QPoint&, int );
+
+ void contextMenuRequested( QListViewItem *, const QPoint &, int );
+
+ void onItem( QListViewItem *item );
+ void onViewport();
+
+ void expanded( QListViewItem *item );
+ void collapsed( QListViewItem *item );
+#ifndef QT_NO_DRAGANDDROP
+ void dropped( QDropEvent *e );
+#endif
+ void itemRenamed( QListViewItem *item, int col, const QString & );
+ void itemRenamed( QListViewItem *item, int col );
+
+protected:
+ void contentsMousePressEvent( QMouseEvent * e );
+ void contentsMouseReleaseEvent( QMouseEvent * e );
+ void contentsMouseMoveEvent( QMouseEvent * e );
+ void contentsMouseDoubleClickEvent( QMouseEvent * e );
+ void contentsContextMenuEvent( QContextMenuEvent * e );
+#ifndef QT_NO_DRAGANDDROP
+ void contentsDragEnterEvent( QDragEnterEvent *e );
+ void contentsDragMoveEvent( QDragMoveEvent *e );
+ void contentsDragLeaveEvent( QDragLeaveEvent *e );
+ void contentsDropEvent( QDropEvent *e );
+ virtual QDragObject *dragObject();
+ virtual void startDrag();
+#endif
+
+ void focusInEvent( QFocusEvent * e );
+ void focusOutEvent( QFocusEvent * e );
+
+ void keyPressEvent( QKeyEvent *e );
+
+ void resizeEvent( QResizeEvent *e );
+ void viewportResizeEvent( QResizeEvent *e );
+
+ void showEvent( QShowEvent * );
+
+ void drawContentsOffset( QPainter *, int ox, int oy,
+ int cx, int cy, int cw, int ch );
+
+ virtual void paintEmptyArea( QPainter *, const QRect & );
+ void styleChange( QStyle& );
+ void windowActivationChange( bool );
+
+protected slots:
+ void updateContents();
+ void doAutoScroll();
+
+private slots:
+ void changeSortColumn( int );
+ void handleIndexChange();
+ void updateDirtyItems();
+ void makeVisible();
+ void handleSizeChange( int, int, int );
+ void startRename();
+ void openFocusItem();
+
+private:
+ void contentsMousePressEventEx( QMouseEvent * e );
+ void contentsMouseReleaseEventEx( QMouseEvent * e );
+ void init();
+ void updateGeometries();
+ void buildDrawableList() const;
+ void reconfigureItems();
+ void widthChanged(const QListViewItem*, int c);
+ void handleItemChange( QListViewItem *old, bool shift, bool control );
+ void selectRange( QListViewItem *from, QListViewItem *to, bool invert, bool includeFirst, bool clearSel = FALSE );
+ bool selectRange( QListViewItem *newItem, QListViewItem *oldItem, QListViewItem *anchorItem );
+ bool clearRange( QListViewItem *from, QListViewItem *to, bool includeFirst = TRUE );
+ void doAutoScroll( const QPoint &cursorPos );
+
+ QListViewPrivate * d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QListView( const QListView & );
+ QListView &operator=( const QListView & );
+#endif
+};
+
+
+class Q_EXPORT QCheckListItem : public QListViewItem
+{
+public:
+ enum Type { RadioButton,
+ CheckBox,
+ Controller,
+ RadioButtonController=Controller,
+ CheckBoxController };
+ // ### should be integrated with qbutton in ver4 perhaps
+ enum ToggleState { Off, NoChange, On };
+
+ QCheckListItem( QCheckListItem *parent, const QString &text,
+ Type = RadioButtonController );
+ QCheckListItem( QCheckListItem *parent, QListViewItem *after,
+ const QString &text, Type = RadioButtonController );
+ QCheckListItem( QListViewItem *parent, const QString &text,
+ Type = RadioButtonController );
+ QCheckListItem( QListViewItem *parent, QListViewItem *after,
+ const QString &text, Type = RadioButtonController );
+ QCheckListItem( QListView *parent, const QString &text,
+ Type = RadioButtonController );
+ QCheckListItem( QListView *parent, QListViewItem *after,
+ const QString &text, Type = RadioButtonController );
+ QCheckListItem( QListViewItem *parent, const QString &text,
+ const QPixmap & );
+ QCheckListItem( QListView *parent, const QString &text,
+ const QPixmap & );
+ ~QCheckListItem();
+
+ void paintCell( QPainter *, const QColorGroup & cg,
+ int column, int width, int alignment );
+ virtual void paintFocus( QPainter *, const QColorGroup & cg,
+ const QRect & r );
+ int width( const QFontMetrics&, const QListView*, int column) const;
+ void setup();
+
+ virtual void setOn( bool ); // ### should be replaced by setChecked in ver4
+ bool isOn() const { return on; }
+ Type type() const { return myType; }
+ QString text() const { return QListViewItem::text( 0 ); }
+ QString text( int n ) const { return QListViewItem::text( n ); }
+
+ void setTristate( bool );
+ bool isTristate() const;
+ ToggleState state() const;
+ void setState( ToggleState s);
+
+ int rtti() const;
+ static int RTTI;
+
+protected:
+ void activate();
+ void turnOffChild();
+ virtual void stateChange( bool );
+
+private:
+ void init();
+ ToggleState internalState() const;
+ void setStoredState( ToggleState newState, void *key );
+ ToggleState storedState( void *key ) const;
+ void stateChange( ToggleState s );
+ void restoreState( void *key, int depth = 0 );
+ void updateController( bool update = TRUE , bool store = FALSE );
+ void updateStoredState( void *key );
+ void setState( ToggleState s, bool update, bool store );
+ void setCurrentState( ToggleState s );
+
+ Type myType;
+ bool on; // ### remove in ver4
+ QCheckListItemPrivate *d;
+};
+
+class Q_EXPORT QListViewItemIterator
+{
+ friend struct QListViewPrivate;
+ friend class QListView;
+ friend class QListViewItem;
+
+public:
+ enum IteratorFlag {
+ Visible = 0x00000001,
+ Invisible = 0x00000002,
+ Selected = 0x00000004,
+ Unselected = 0x00000008,
+ Selectable = 0x00000010,
+ NotSelectable = 0x00000020,
+ DragEnabled = 0x00000040,
+ DragDisabled = 0x00000080,
+ DropEnabled = 0x00000100,
+ DropDisabled = 0x00000200,
+ Expandable = 0x00000400,
+ NotExpandable = 0x00000800,
+ Checked = 0x00001000,
+ NotChecked = 0x00002000
+ };
+
+ QListViewItemIterator();
+ QListViewItemIterator( QListViewItem *item );
+ QListViewItemIterator( QListViewItem *item, int iteratorFlags );
+
+ QListViewItemIterator( const QListViewItemIterator &it );
+ QListViewItemIterator( QListView *lv );
+ QListViewItemIterator( QListView *lv, int iteratorFlags );
+
+ QListViewItemIterator &operator=( const QListViewItemIterator &it );
+
+ ~QListViewItemIterator();
+
+ QListViewItemIterator &operator++();
+ const QListViewItemIterator operator++( int );
+ QListViewItemIterator &operator+=( int j );
+
+ QListViewItemIterator &operator--();
+ const QListViewItemIterator operator--( int );
+ QListViewItemIterator &operator-=( int j );
+
+ QListViewItem* operator*();
+ QListViewItem *current() const;
+
+protected:
+ QListViewItem *curr;
+ QListView *listView;
+
+private:
+ QListViewItemIteratorPrivate* d() const;
+ void init( int flags );
+ void addToListView();
+ void currentRemoved();
+ bool matchesFlags( const QListViewItem* ) const;
+ bool testPair( QListViewItemIterator::IteratorFlag, QListViewItemIterator::IteratorFlag, bool ) const;
+ bool isChecked( const QListViewItem* ) const;
+};
+
+#endif // QT_NO_LISTVIEW
+
+#endif // QLISTVIEW_H
diff --git a/src/widgets/qmainwindow.cpp b/src/widgets/qmainwindow.cpp
new file mode 100644
index 0000000..7ad2781
--- /dev/null
+++ b/src/widgets/qmainwindow.cpp
@@ -0,0 +1,2609 @@
+/****************************************************************************
+**
+** Implementation of QMainWindow class
+**
+** Created : 980312
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qmainwindow.h"
+#ifndef QT_NO_MAINWINDOW
+
+#include "qtimer.h"
+#include "qlayout.h"
+#include "qobjectlist.h"
+#include "qintdict.h"
+#include "qapplication.h"
+#include "qptrlist.h"
+#include "qmap.h"
+#include "qcursor.h"
+#include "qpainter.h"
+#include "qmenubar.h"
+#include "qpopupmenu.h"
+#include "qtoolbar.h"
+#include "qstatusbar.h"
+#include "qscrollview.h"
+#include "qtooltip.h"
+#include "qdatetime.h"
+#include "qwhatsthis.h"
+#include "qbitmap.h"
+#include "qdockarea.h"
+#include "qstringlist.h"
+#include "qstyle.h"
+#ifdef Q_WS_MACX
+# include "qt_mac.h"
+#endif
+
+class QHideDock;
+class QMainWindowLayout;
+
+class QMainWindowPrivate
+{
+public:
+ QMainWindowPrivate()
+ : mb(0), sb(0), ttg(0), mc(0), tll(0), mwl(0), ubp( FALSE ), utl( FALSE ),
+ justify( FALSE ), movable( TRUE ), opaque( FALSE ), dockMenu( TRUE )
+ {
+ docks.insert( Qt::DockTop, TRUE );
+ docks.insert( Qt::DockBottom, TRUE );
+ docks.insert( Qt::DockLeft, TRUE );
+ docks.insert( Qt::DockRight, TRUE );
+ docks.insert( Qt::DockMinimized, FALSE );
+ docks.insert( Qt::DockTornOff, TRUE );
+ }
+
+ ~QMainWindowPrivate()
+ {
+ }
+
+#ifndef QT_NO_MENUBAR
+ QMenuBar * mb;
+#else
+ QWidget * mb;
+#endif
+ QStatusBar * sb;
+ QToolTipGroup * ttg;
+
+ QWidget * mc;
+
+ QBoxLayout * tll;
+ QMainWindowLayout * mwl;
+
+ uint ubp :1;
+ uint utl :1;
+ uint justify :1;
+ uint movable :1;
+ uint opaque :1;
+ uint dockMenu :1;
+
+ QDockArea *topDock, *bottomDock, *leftDock, *rightDock;
+
+ QPtrList<QDockWindow> dockWindows;
+ QMap<Qt::Dock, bool> docks;
+ QStringList disabledDocks;
+ QHideDock *hideDock;
+
+ QGuardedPtr<QPopupMenu> rmbMenu, tbMenu, dwMenu;
+ QMap<QDockWindow*, bool> appropriate;
+ QMap<QPopupMenu*, QMainWindow::DockWindows> dockWindowModes;
+
+};
+
+
+/* QMainWindowLayout, respects widthForHeight layouts (like the left
+ and right docks are)
+*/
+
+class QMainWindowLayout : public QLayout
+{
+ Q_OBJECT
+
+public:
+ QMainWindowLayout( QMainWindow *mw, QLayout* parent = 0 );
+ ~QMainWindowLayout() {}
+
+ void addItem( QLayoutItem * );
+ void setLeftDock( QDockArea *l );
+ void setRightDock( QDockArea *r );
+ void setCentralWidget( QWidget *w );
+ bool hasHeightForWidth() const { return FALSE; }
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ QLayoutIterator iterator();
+ QSizePolicy::ExpandData expanding() const { return QSizePolicy::BothDirections; }
+ void invalidate() {}
+
+protected:
+ void setGeometry( const QRect &r ) {
+ QLayout::setGeometry( r );
+ layoutItems( r );
+ }
+
+private:
+ int layoutItems( const QRect&, bool testonly = FALSE );
+ int extraPixels() const;
+
+ QDockArea *left, *right;
+ QWidget *central;
+ QMainWindow *mainWindow;
+
+};
+
+QSize QMainWindowLayout::sizeHint() const
+{
+ int w = 0;
+ int h = 0;
+
+ if ( left ) {
+ w += left->sizeHint().width();
+ h = QMAX( h, left->sizeHint().height() );
+ }
+ if ( right ) {
+ w += right->sizeHint().width();
+ h = QMAX( h, right->sizeHint().height() );
+ }
+ if ( central ) {
+ w += central->sizeHint().width();
+ int diff = extraPixels();
+ h = QMAX( h, central->sizeHint().height() + diff );
+ }
+ return QSize( w, h );
+}
+
+QSize QMainWindowLayout::minimumSize() const
+{
+ int w = 0;
+ int h = 0;
+
+ if ( left ) {
+ QSize ms = left->minimumSizeHint().expandedTo( left->minimumSize() );
+ w += ms.width();
+ h = QMAX( h, ms.height() );
+ }
+ if ( right ) {
+ QSize ms = right->minimumSizeHint().expandedTo( right->minimumSize() );
+ w += ms.width();
+ h = QMAX( h, ms.height() );
+ }
+ if ( central ) {
+ QSize min = central->minimumSize().isNull() ?
+ central->minimumSizeHint() : central->minimumSize();
+ w += min.width();
+ int diff = extraPixels();
+ h = QMAX( h, min.height() + diff );
+ }
+ return QSize( w, h );
+}
+
+QMainWindowLayout::QMainWindowLayout( QMainWindow *mw, QLayout* parent )
+ : QLayout( parent ), left( 0 ), right( 0 ), central( 0 )
+{
+ mainWindow = mw;
+}
+
+void QMainWindowLayout::setLeftDock( QDockArea *l )
+{
+ left = l;
+}
+
+void QMainWindowLayout::setRightDock( QDockArea *r )
+{
+ right = r;
+}
+
+void QMainWindowLayout::setCentralWidget( QWidget *w )
+{
+ central = w;
+}
+
+int QMainWindowLayout::layoutItems( const QRect &r, bool testonly )
+{
+ if ( !left && !central && !right )
+ return 0;
+
+ int wl = 0, wr = 0;
+ if ( left )
+ wl = ( (QDockAreaLayout*)left->QWidget::layout() )->widthForHeight( r.height() );
+ if ( right )
+ wr = ( (QDockAreaLayout*)right->QWidget::layout() )->widthForHeight( r.height() );
+ int w = r.width() - wr - wl;
+ if ( w < 0 )
+ w = 0;
+
+ int diff = extraPixels();
+ if ( !testonly ) {
+ QRect g( geometry() );
+ if ( left )
+ left->setGeometry( QRect( g.x(), g.y() + diff, wl, r.height() - diff ) );
+ if ( right )
+ right->setGeometry( QRect( g.x() + g.width() - wr, g.y() + diff, wr, r.height() - diff ) );
+ if ( central )
+ central->setGeometry( g.x() + wl, g.y() + diff, w, r.height() - diff );
+ }
+
+ w = wl + wr;
+ if ( central )
+ w += central->minimumSize().width();
+ return w;
+}
+
+int QMainWindowLayout::extraPixels() const
+{
+ if ( mainWindow->d->topDock->isEmpty() &&
+ !(mainWindow->d->leftDock->isEmpty() &&
+ mainWindow->d->rightDock->isEmpty()) ) {
+ return 2;
+ } else {
+ return 0;
+ }
+}
+
+void QMainWindowLayout::addItem( QLayoutItem * /* item */ )
+{
+}
+
+
+QLayoutIterator QMainWindowLayout::iterator()
+{
+ return 0;
+}
+
+
+/*
+ QHideToolTip and QHideDock - minimized dock
+*/
+
+#ifndef QT_NO_TOOLTIP
+class QHideToolTip : public QToolTip
+{
+public:
+ QHideToolTip( QWidget *parent ) : QToolTip( parent ) {}
+ ~QHideToolTip() {}
+
+ virtual void maybeTip( const QPoint &pos );
+};
+#endif
+
+
+class QHideDock : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QHideDock( QMainWindow *parent ) : QWidget( parent, "qt_hide_dock" ) {
+ hide();
+ setFixedHeight( style().pixelMetric( QStyle::PM_DockWindowHandleExtent,
+ this ) + 3 );
+ pressedHandle = -1;
+ pressed = FALSE;
+ setMouseTracking( TRUE );
+ win = parent;
+#ifndef QT_NO_TOOLTIP
+ tip = new QHideToolTip( this );
+#endif
+ }
+ ~QHideDock()
+ {
+#ifndef QT_NO_TOOLTIP
+ delete tip;
+#endif
+ }
+
+protected:
+ void paintEvent( QPaintEvent *e ) {
+ if ( !children() || children()->isEmpty() )
+ return;
+ QPainter p( this );
+ p.setClipRegion( e->rect() );
+ p.fillRect( e->rect(), colorGroup().brush( QColorGroup::Background ) );
+ int x = 0;
+ int i = -1;
+ QObjectListIt it( *children() );
+ QObject *o;
+ while ( ( o = it.current() ) ) {
+ ++it;
+ ++i;
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(o);
+ if ( !dw || !dw->isVisible() )
+ continue;
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( i == pressedHandle )
+ flags |= QStyle::Style_On;
+
+ style().drawPrimitive( QStyle::PE_DockWindowHandle, &p,
+ QRect( x, 0, 30, 10 ), colorGroup(),
+ flags );
+ x += 30;
+ }
+ }
+
+ void mousePressEvent( QMouseEvent *e ) {
+ pressed = TRUE;
+ if ( !children() || children()->isEmpty() )
+ return;
+ mouseMoveEvent( e );
+ pressedHandle = -1;
+
+ if ( e->button() == RightButton && win->isDockMenuEnabled() ) {
+ // ### TODO: HideDock menu
+ } else {
+ mouseMoveEvent( e );
+ }
+ }
+
+ void mouseMoveEvent( QMouseEvent *e ) {
+ if ( !children() || children()->isEmpty() )
+ return;
+ if ( !pressed )
+ return;
+ int x = 0;
+ int i = -1;
+ if ( e->y() >= 0 && e->y() <= height() ) {
+ QObjectListIt it( *children() );
+ QObject *o;
+ while ( ( o = it.current() ) ) {
+ ++it;
+ ++i;
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(o);
+ if ( !dw || !dw->isVisible() )
+ continue;
+
+ if ( e->x() >= x && e->x() <= x + 30 ) {
+ int old = pressedHandle;
+ pressedHandle = i;
+ if ( pressedHandle != old )
+ repaint( TRUE );
+ return;
+ }
+ x += 30;
+ }
+ }
+ int old = pressedHandle;
+ pressedHandle = -1;
+ if ( old != -1 )
+ repaint( TRUE );
+ }
+
+ void mouseReleaseEvent( QMouseEvent *e ) {
+ pressed = FALSE;
+ if ( pressedHandle == -1 )
+ return;
+ if ( !children() || children()->isEmpty() )
+ return;
+ if ( e->button() == LeftButton ) {
+ if ( e->y() >= 0 && e->y() <= height() ) {
+ QObject *o = ( (QObjectList*)children() )->at( pressedHandle );
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(o);
+ if ( dw ) {
+ dw->show();
+ dw->dock();
+ }
+ }
+ }
+ pressedHandle = -1;
+ repaint( FALSE );
+ }
+
+ bool eventFilter( QObject *o, QEvent *e ) {
+ if ( o == this || !o->isWidgetType() )
+ return QWidget::eventFilter( o, e );
+ if ( e->type() == QEvent::Hide ||
+ e->type() == QEvent::Show ||
+ e->type() == QEvent::ShowToParent )
+ updateState();
+ return QWidget::eventFilter( o, e );
+ }
+
+ void updateState() {
+ bool visible = TRUE;
+ if ( !children() || children()->isEmpty() ) {
+ visible = FALSE;
+ } else {
+ QObjectListIt it( *children() );
+ QObject *o;
+ while ( ( o = it.current() ) ) {
+ ++it;
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(o);
+ if ( !dw )
+ continue;
+ if ( dw->isHidden() ) {
+ visible = FALSE;
+ continue;
+ }
+ if ( !dw->isVisible() )
+ continue;
+ visible = TRUE;
+ break;
+ }
+ }
+
+ if ( visible )
+ show();
+ else
+ hide();
+ win->triggerLayout( FALSE );
+ update();
+ }
+
+ void childEvent( QChildEvent *e ) {
+ QWidget::childEvent( e );
+ if ( e->type() == QEvent::ChildInserted )
+ e->child()->installEventFilter( this );
+ else
+ e->child()->removeEventFilter( this );
+ updateState();
+ }
+
+private:
+ QMainWindow *win;
+ int pressedHandle;
+ bool pressed;
+#ifndef QT_NO_TOOLTIP
+ QHideToolTip *tip;
+ friend class QHideToolTip;
+#endif
+};
+
+#ifndef QT_NO_TOOLTIP
+void QHideToolTip::maybeTip( const QPoint &pos )
+{
+ if ( !parentWidget() )
+ return;
+ QHideDock *dock = (QHideDock*)parentWidget();
+
+ if ( !dock->children() || dock->children()->isEmpty() )
+ return;
+ QObjectListIt it( *dock->children() );
+ QObject *o;
+ int x = 0;
+ while ( ( o = it.current() ) ) {
+ ++it;
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(o);
+ if ( !dw || !dw->isVisible() )
+ continue;
+
+ if ( pos.x() >= x && pos.x() <= x + 30 ) {
+ QDockWindow *dw = (QDockWindow*)o;
+ if ( !dw->caption().isEmpty() )
+ tip( QRect( x, 0, 30, dock->height() ), dw->caption() );
+ return;
+ }
+ x += 30;
+ }
+}
+#endif
+
+/*!
+ \class QMainWindow qmainwindow.h
+ \brief The QMainWindow class provides a main application window,
+ with a menu bar, dock windows (e.g. for toolbars), and a status
+ bar.
+
+ \ingroup application
+ \mainclass
+
+ Main windows are most often used to provide menus, toolbars and a
+ status bar around a large central widget, such as a text edit,
+ drawing canvas or QWorkspace (for MDI applications). QMainWindow
+ is usually subclassed since this makes it easier to encapsulate
+ the central widget, menus and toolbars as well as the window's
+ state. Subclassing makes it possible to create the slots that are
+ called when the user clicks menu items or toolbar buttons. You can
+ also create main windows using \link designer-manual.book Qt
+ Designer\endlink. We'll briefly review adding menu items and
+ toolbar buttons then describe the facilities of QMainWindow
+ itself.
+
+ \code
+ QMainWindow *mw = new QMainWindow;
+ QTextEdit *edit = new QTextEdit( mw, "editor" );
+ edit->setFocus();
+ mw->setCaption( "Main Window" );
+ mw->setCentralWidget( edit );
+ mw->show();
+ \endcode
+
+ QMainWindows may be created in their own right as shown above.
+ The central widget is set with setCentralWidget(). Popup menus can
+ be added to the default menu bar, widgets can be added to the
+ status bar, toolbars and dock windows can be added to any of the
+ dock areas.
+
+ \quotefile application/main.cpp
+ \skipto ApplicationWindow
+ \printuntil show
+
+ In the extract above ApplicationWindow is a subclass of
+ QMainWindow that we must write for ourselves; this is the usual
+ approach to using QMainWindow. (The source for the extracts in
+ this description are taken from \l application/main.cpp, \l
+ application/application.cpp, \l action/main.cpp, and \l
+ action/application.cpp )
+
+ When subclassing we add the menu items and toolbars in the
+ subclass's constructor. If we've created a QMainWindow instance
+ directly we can add menu items and toolbars just as easily by
+ passing the QMainWindow instance as the parent instead of the \e
+ this pointer.
+
+ \quotefile application/application.cpp
+ \skipto help = new
+ \printuntil about
+
+ Here we've added a new menu with one menu item. The menu has been
+ inserted into the menu bar that QMainWindow provides by default
+ and which is accessible through the menuBar() function. The slot
+ will be called when the menu item is clicked.
+
+ \quotefile application/application.cpp
+ \skipto fileTools
+ \printuntil setLabel
+ \skipto QToolButton
+ \printuntil open file
+
+ This extract shows the creation of a toolbar with one toolbar
+ button. QMainWindow supplies four dock areas for toolbars. When a
+ toolbar is created as a child of a QMainWindow (or derived class)
+ instance it will be placed in a dock area (the \c Top dock area by
+ default). The slot will be called when the toolbar button is
+ clicked. Any dock window can be added to a dock area either using
+ addDockWindow(), or by creating a dock window with the QMainWindow
+ as the parent.
+
+ \quotefile application/application.cpp
+ \skipto editor
+ \printuntil statusBar
+
+ Having created the menus and toolbar we create an instance of the
+ large central widget, give it the focus and set it as the main
+ window's central widget. In the example we've also set the status
+ bar, accessed via the statusBar() function, to an initial message
+ which will be displayed for two seconds. Note that you can add
+ additional widgets to the status bar, for example labels, to show
+ further status information. See the QStatusBar documentation for
+ details, particularly the addWidget() function.
+
+ Often we want to synchronize a toolbar button with a menu item.
+ For example, if the user clicks a 'bold' toolbar button we want
+ the 'bold' menu item to be checked. This synchronization can be
+ achieved automatically by creating actions and adding the actions
+ to the toolbar and menu.
+
+ \quotefile action/application.cpp
+ \skipto QAction * fileOpen
+ \printline
+ \skipto fileOpenAction
+ \printuntil choose
+
+ Here we create an action with an icon which will be used in any
+ menu and toolbar that the action is added to. We've also given the
+ action a menu name, '\&Open', and a keyboard shortcut. The
+ connection that we have made will be used when the user clicks
+ either the menu item \e or the toolbar button.
+
+ \quotefile action/application.cpp
+ \skipto QPopupMenu * file
+ \printuntil menuBar
+ \skipto fileOpen
+ \printline
+
+ The extract above shows the creation of a popup menu. We add the
+ menu to the QMainWindow's menu bar and add our action.
+
+ \quotefile action/application.cpp
+ \skipto QToolBar * fileTool
+ \printuntil OpenAction
+
+ Here we create a new toolbar as a child of the QMainWindow and add
+ our action to the toolbar.
+
+ We'll now explore the functionality offered by QMainWindow.
+
+ The main window will take care of the dock areas, and the geometry
+ of the central widget, but all other aspects of the central widget
+ are left to you. QMainWindow automatically detects the creation of
+ a menu bar or status bar if you specify the QMainWindow as parent,
+ or you can use the provided menuBar() and statusBar() functions.
+ The functions menuBar() and statusBar() create a suitable widget
+ if one doesn't exist, and update the window's layout to make
+ space.
+
+ QMainWindow provides a QToolTipGroup connected to the status bar.
+ The function toolTipGroup() provides access to the default
+ QToolTipGroup. It isn't possible to set a different tool tip
+ group.
+
+ New dock windows and toolbars can be added to a QMainWindow using
+ addDockWindow(). Dock windows can be moved using moveDockWindow()
+ and removed with removeDockWindow(). QMainWindow allows default
+ dock window (toolbar) docking in all its dock areas (\c Top, \c
+ Left, \c Right, \c Bottom). You can use setDockEnabled() to
+ enable and disable docking areas for dock windows. When adding or
+ moving dock windows you can specify their 'edge' (dock area). The
+ currently available edges are: \c Top, \c Left, \c Right, \c
+ Bottom, \c Minimized (effectively a 'hidden' dock area) and \c
+ TornOff (floating). See \l Qt::Dock for an explanation of these
+ areas. Note that the *ToolBar functions are included for backward
+ compatibility; all new code should use the *DockWindow functions.
+ QToolbar is a subclass of QDockWindow so all functions that work
+ with dock windows work on toolbars in the same way.
+
+ \target dwm
+ If the user clicks the close button, then the dock window is
+ hidden. A dock window can be hidden or unhidden by the user by
+ right clicking a dock area and clicking the name of the relevant
+ dock window on the pop up dock window menu. This menu lists the
+ names of every dock window; visible dock windows have a tick
+ beside their names. The dock window menu is created automatically
+ as required by createDockWindowMenu(). Since it may not always be
+ appropriate for a dock window to appear on this menu the
+ setAppropriate() function is used to inform the main window
+ whether or not the dock window menu should include a particular
+ dock window. Double clicking a dock window handle (usually on the
+ left-hand side of the dock window) undocks (floats) the dock
+ window. Double clicking a floating dock window's titlebar will
+ dock the floating dock window. (See also
+ \l{QMainWindow::DockWindows}.)
+
+ Some functions change the appearance of a QMainWindow globally:
+ \list
+ \i QDockWindow::setHorizontalStretchable() and
+ QDockWindow::setVerticalStretchable() are used to make specific dock
+ windows or toolbars stretchable.
+ \i setUsesBigPixmaps() is used to set whether tool buttons should
+ draw small or large pixmaps (see QIconSet for more information).
+ \i setUsesTextLabel() is used to set whether tool buttons
+ should display a textual label in addition to pixmaps
+ (see QToolButton for more information).
+ \endlist
+
+ The user can drag dock windows into any enabled docking area. Dock
+ windows can also be dragged \e within a docking area, for example
+ to rearrange the order of some toolbars. Dock windows can also be
+ dragged outside any docking area (undocked or 'floated'). Being
+ able to drag dock windows can be enabled (the default) and
+ disabled using setDockWindowsMovable().
+
+ The \c Minimized edge is a hidden dock area. If this dock area is
+ enabled the user can hide (minimize) a dock window or show (restore)
+ a minimized dock window by clicking the dock window handle. If the
+ user hovers the mouse cursor over one of the handles, the caption of
+ the dock window is displayed in a tool tip (see
+ QDockWindow::caption() or QToolBar::label()), so if you enable the
+ \c Minimized dock area, it is best to specify a meaningful caption
+ or label for each dock window. To minimize a dock window
+ programmatically use moveDockWindow() with an edge of \c Minimized.
+
+ Dock windows are moved transparently by default, i.e. during the
+ drag an outline rectangle is drawn on the screen representing the
+ position of the dock window as it moves. If you want the dock
+ window to be shown normally whilst it is moved use
+ setOpaqueMoving().
+
+ The location of a dock window, i.e. its dock area and position
+ within the dock area, can be determined by calling getLocation().
+ Movable dock windows can be lined up to minimize wasted space with
+ lineUpDockWindows(). Pointers to the dock areas are available from
+ topDock(), leftDock(), rightDock() and bottomDock(). A customize
+ menu item is added to the pop up dock window menu if
+ isCustomizable() returns TRUE; it returns FALSE by default.
+ Reimplement isCustomizable() and customize() if you want to offer
+ this extra menu item, for example, to allow the user to change
+ settings relating to the main window and its toolbars and dock
+ windows.
+
+ The main window's menu bar is fixed (at the top) by default. If
+ you want a movable menu bar, create a QMenuBar as a stretchable
+ widget inside its own movable dock window and restrict this dock
+ window to only live within the \c Top or \c Bottom dock:
+
+ \code
+ QToolBar *tb = new QToolBar( this );
+ addDockWindow( tb, tr( "Menubar" ), Top, FALSE );
+ QMenuBar *mb = new QMenuBar( tb );
+ mb->setFrameStyle( QFrame::NoFrame );
+ tb->setStretchableWidget( mb );
+ setDockEnabled( tb, Left, FALSE );
+ setDockEnabled( tb, Right, FALSE );
+ \endcode
+
+ An application with multiple dock windows can choose to save the
+ current dock window layout in order to restore it later, e.g. in
+ the next session. You can do this by using the streaming operators
+ for QMainWindow.
+
+ To save the layout and positions of all the dock windows do this:
+
+ \code
+ QFile file( filename );
+ if ( file.open( IO_WriteOnly ) ) {
+ QTextStream stream( &file );
+ stream << *mainWindow;
+ file.close();
+ }
+ \endcode
+
+ To restore the dock window positions and sizes (normally when the
+ application is next started), do following:
+
+ \code
+ QFile file( filename );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ stream >> *mainWindow;
+ file.close();
+ }
+ \endcode
+
+ The QSettings class can be used in conjunction with the streaming
+ operators to store the application's settings.
+
+ QMainWindow's management of dock windows and toolbars is done
+ transparently behind-the-scenes by QDockArea.
+
+ For multi-document interfaces (MDI), use a QWorkspace as the
+ central widget.
+
+ Adding dock windows, e.g. toolbars, to QMainWindow's dock areas is
+ straightforward. If the supplied dock areas are not sufficient for
+ your application we suggest that you create a QWidget subclass and
+ add your own dock areas (see \l QDockArea) to the subclass since
+ QMainWindow provides functionality specific to the standard dock
+ areas it provides.
+
+ <img src=qmainwindow-m.png> <img src=qmainwindow-w.png>
+
+ \sa QToolBar QDockWindow QStatusBar QAction QMenuBar QPopupMenu QToolTipGroup QDialog
+*/
+
+/*! \enum Qt::ToolBarDock
+ \internal
+*/
+
+/*!
+ \enum Qt::Dock
+
+ Each dock window can be in one of the following positions:
+
+ \value DockTop above the central widget, below the menu bar.
+
+ \value DockBottom below the central widget, above the status bar.
+
+ \value DockLeft to the left of the central widget.
+
+ \value DockRight to the right of the central widget.
+
+ \value DockMinimized the dock window is not shown (this is
+ effectively a 'hidden' dock area); the handles of all minimized
+ dock windows are drawn in one row below the menu bar.
+
+ \value DockTornOff the dock window floats as its own top level
+ window which always stays on top of the main window.
+
+ \value DockUnmanaged not managed by a QMainWindow.
+*/
+
+/*!
+ \enum QMainWindow::DockWindows
+
+ Right-clicking a dock area will pop-up the dock window menu
+ (createDockWindowMenu() is called automatically). When called in
+ code you can specify what items should appear on the menu with
+ this enum.
+
+ \value OnlyToolBars The menu will list all the toolbars, but not
+ any other dock windows.
+
+ \value NoToolBars The menu will list dock windows but not
+ toolbars.
+
+ \value AllDockWindows The menu will list all toolbars and other
+ dock windows. (This is the default.)
+*/
+
+/*!
+ \obsolete
+ \fn void QMainWindow::addToolBar( QDockWindow *, Dock = Top, bool newLine = FALSE );
+*/
+
+/*!
+ \obsolete
+ \overload void QMainWindow::addToolBar( QDockWindow *, const QString &label, Dock = Top, bool newLine = FALSE );
+*/
+
+/*!
+ \obsolete
+ \fn void QMainWindow::moveToolBar( QDockWindow *, Dock = Top );
+*/
+
+/*!
+ \obsolete
+ \overload void QMainWindow::moveToolBar( QDockWindow *, Dock, bool nl, int index, int extraOffset = -1 );
+*/
+
+/*!
+ \obsolete
+ \fn void QMainWindow::removeToolBar( QDockWindow * );
+*/
+
+/*!
+ \obsolete
+ \fn void QMainWindow::lineUpToolBars( bool keepNewLines = FALSE );
+*/
+
+/*!
+ \obsolete
+ \fn void QMainWindow::toolBarPositionChanged( QToolBar * );
+*/
+
+/*!
+ \obsolete
+ \fn bool QMainWindow::toolBarsMovable() const
+*/
+
+/*!
+ \obsolete
+ \fn void QMainWindow::setToolBarsMovable( bool )
+*/
+
+/*!
+ Constructs an empty main window. The \a parent, \a name and widget
+ flags \a f, are passed on to the QWidget constructor.
+
+ By default, the widget flags are set to \c WType_TopLevel rather
+ than 0 as they are with QWidget. If you don't want your
+ QMainWindow to be a top level widget then you will need to set \a
+ f to 0.
+*/
+
+QMainWindow::QMainWindow( QWidget * parent, const char * name, WFlags f )
+ : QWidget( parent, name, f )
+{
+ d = new QMainWindowPrivate;
+#ifdef Q_WS_MACX
+ d->opaque = TRUE;
+#else
+ d->opaque = FALSE;
+#endif
+ installEventFilter( this );
+ d->topDock = new QDockArea( Horizontal, QDockArea::Normal, this, "qt_top_dock" );
+ d->topDock->installEventFilter( this );
+ d->bottomDock = new QDockArea( Horizontal, QDockArea::Reverse, this, "qt_bottom_dock" );
+ d->bottomDock->installEventFilter( this );
+ d->leftDock = new QDockArea( Vertical, QDockArea::Normal, this, "qt_left_dock" );
+ d->leftDock->installEventFilter( this );
+ d->rightDock = new QDockArea( Vertical, QDockArea::Reverse, this, "qt_right_dock" );
+ d->rightDock->installEventFilter( this );
+ d->hideDock = new QHideDock( this );
+}
+
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QMainWindow::~QMainWindow()
+{
+ delete layout();
+ delete d;
+}
+
+#ifndef QT_NO_MENUBAR
+/*!
+ Sets this main window to use the menu bar \a newMenuBar.
+
+ The existing menu bar (if any) is deleted along with its contents.
+
+ \sa menuBar()
+*/
+
+void QMainWindow::setMenuBar( QMenuBar * newMenuBar )
+{
+ if ( !newMenuBar )
+ return;
+ if ( d->mb )
+ delete d->mb;
+ d->mb = newMenuBar;
+ d->mb->installEventFilter( this );
+ triggerLayout();
+}
+
+
+/*!
+ Returns the menu bar for this window.
+
+ If there isn't one, then menuBar() creates an empty menu bar.
+
+ \sa statusBar()
+*/
+
+QMenuBar * QMainWindow::menuBar() const
+{
+ if ( d->mb )
+ return d->mb;
+
+ QObjectList * l
+ = ((QObject*)this)->queryList( "QMenuBar", 0, FALSE, FALSE );
+ QMenuBar * b;
+ if ( l && l->count() ) {
+ b = (QMenuBar *)l->first();
+ } else {
+ b = new QMenuBar( (QMainWindow *)this, "automatic menu bar" );
+ b->show();
+ }
+ delete l;
+ d->mb = b;
+ d->mb->installEventFilter( this );
+ ((QMainWindow *)this)->triggerLayout();
+ return b;
+}
+#endif // QT_NO_MENUBAR
+
+/*!
+ Sets this main window to use the status bar \a newStatusBar.
+
+ The existing status bar (if any) is deleted along with its
+ contents.
+
+ Note that \a newStatusBar \e must be a child of this main window,
+ and that it is not automatically displayed. If you call this
+ function after show(), you will probably also need to call
+ newStatusBar->show().
+
+ \sa setMenuBar() statusBar()
+*/
+
+void QMainWindow::setStatusBar( QStatusBar * newStatusBar )
+{
+ if ( !newStatusBar || newStatusBar == d->sb )
+ return;
+ if ( d->sb )
+ delete d->sb;
+ d->sb = newStatusBar;
+#ifndef QT_NO_TOOLTIP
+ // ### this code can cause unnecessary creation of a tool tip group
+ connect( toolTipGroup(), SIGNAL(showTip(const QString&)),
+ d->sb, SLOT(message(const QString&)) );
+ connect( toolTipGroup(), SIGNAL(removeTip()),
+ d->sb, SLOT(clear()) );
+#endif
+ d->sb->installEventFilter( this );
+ triggerLayout();
+}
+
+
+/*!
+ Returns this main window's status bar. If there isn't one,
+ statusBar() creates an empty status bar, and if necessary a tool
+ tip group too.
+
+ \sa menuBar() toolTipGroup()
+*/
+
+QStatusBar * QMainWindow::statusBar() const
+{
+ if ( d->sb )
+ return d->sb;
+
+ QObjectList * l
+ = ((QObject*)this)->queryList( "QStatusBar", 0, FALSE, FALSE );
+ QStatusBar * s;
+ if ( l && l->count() ) {
+ s = (QStatusBar *)l->first();
+ } else {
+ s = new QStatusBar( (QMainWindow *)this, "automatic status bar" );
+ s->show();
+ }
+ delete l;
+ ((QMainWindow *)this)->setStatusBar( s );
+ ((QMainWindow *)this)->triggerLayout( TRUE );
+ return s;
+}
+
+
+#ifndef QT_NO_TOOLTIP
+/*!
+ Sets this main window to use the tool tip group \a
+ newToolTipGroup.
+
+ The existing tool tip group (if any) is deleted along with its
+ contents. All the tool tips connected to it lose the ability to
+ display the group texts.
+
+ \sa menuBar() toolTipGroup()
+*/
+
+void QMainWindow::setToolTipGroup( QToolTipGroup * newToolTipGroup )
+{
+ if ( !newToolTipGroup || newToolTipGroup == d->ttg )
+ return;
+ if ( d->ttg )
+ delete d->ttg;
+ d->ttg = newToolTipGroup;
+
+ connect( toolTipGroup(), SIGNAL(showTip(const QString&)),
+ statusBar(), SLOT(message(const QString&)) );
+ connect( toolTipGroup(), SIGNAL(removeTip()),
+ statusBar(), SLOT(clear()) );
+}
+
+
+/*!
+ Returns this main window's tool tip group. If there isn't one,
+ toolTipGroup() creates an empty tool tip group.
+
+ \sa menuBar() statusBar()
+*/
+
+QToolTipGroup * QMainWindow::toolTipGroup() const
+{
+ if ( d->ttg )
+ return d->ttg;
+
+ QToolTipGroup * t = new QToolTipGroup( (QMainWindow*)this,
+ "automatic tool tip group" );
+ ((QMainWindowPrivate*)d)->ttg = t;
+ return t;
+}
+#endif
+
+
+/*!
+ If \a enable is TRUE then users can dock windows in the \a dock
+ area. If \a enable is FALSE users cannot dock windows in the \a
+ dock dock area.
+
+ Users can dock (drag) dock windows into any enabled dock area.
+*/
+
+void QMainWindow::setDockEnabled( Dock dock, bool enable )
+{
+ d->docks.replace( dock, enable );
+}
+
+
+/*!
+ Returns TRUE if the \a dock dock area is enabled, i.e. it can
+ accept user dragged dock windows; otherwise returns FALSE.
+
+ \sa setDockEnabled()
+*/
+
+bool QMainWindow::isDockEnabled( Dock dock ) const
+{
+ return d->docks[ dock ];
+}
+
+/*!
+ \overload
+
+ Returns TRUE if dock area \a area is enabled, i.e. it can accept
+ user dragged dock windows; otherwise returns FALSE.
+
+ \sa setDockEnabled()
+*/
+
+bool QMainWindow::isDockEnabled( QDockArea *area ) const
+{
+
+ if ( area == d->leftDock )
+ return d->docks[ DockLeft ];
+ if ( area == d->rightDock )
+ return d->docks[ DockRight ];
+ if ( area == d->topDock )
+ return d->docks[ DockTop ];
+ if ( area == d->bottomDock )
+ return d->docks[ DockBottom ];
+ return FALSE;
+}
+
+/*!
+ \overload
+
+ If \a enable is TRUE then users can dock the \a dw dock window in
+ the \a dock area. If \a enable is FALSE users cannot dock the \a
+ dw dock window in the \a dock area.
+
+ In general users can dock (drag) dock windows into any enabled
+ dock area. Using this function particular dock areas can be
+ enabled (or disabled) as docking points for particular dock
+ windows.
+*/
+
+
+void QMainWindow::setDockEnabled( QDockWindow *dw, Dock dock, bool enable )
+{
+ if ( d->dockWindows.find( dw ) == -1 ) {
+ d->dockWindows.append( dw );
+ connect( dw, SIGNAL( placeChanged(QDockWindow::Place) ),
+ this, SLOT( slotPlaceChanged() ) );
+ }
+ QString s;
+ s.sprintf( "%p_%d", (void*)dw, (int)dock );
+ if ( enable )
+ d->disabledDocks.remove( s );
+ else if ( d->disabledDocks.find( s ) == d->disabledDocks.end() )
+ d->disabledDocks << s;
+ switch ( dock ) {
+ case DockTop:
+ topDock()->setAcceptDockWindow( dw, enable );
+ break;
+ case DockLeft:
+ leftDock()->setAcceptDockWindow( dw, enable );
+ break;
+ case DockRight:
+ rightDock()->setAcceptDockWindow( dw, enable );
+ break;
+ case DockBottom:
+ bottomDock()->setAcceptDockWindow( dw, enable );
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \overload
+
+ Returns TRUE if dock area \a area is enabled for the dock window
+ \a dw; otherwise returns FALSE.
+
+ \sa setDockEnabled()
+*/
+
+bool QMainWindow::isDockEnabled( QDockWindow *dw, QDockArea *area ) const
+{
+ if ( !isDockEnabled( area ) )
+ return FALSE;
+ Dock dock;
+ if ( area == d->leftDock )
+ dock = DockLeft;
+ else if ( area == d->rightDock )
+ dock = DockRight;
+ else if ( area == d->topDock )
+ dock = DockTop;
+ else if ( area == d->bottomDock )
+ dock = DockBottom;
+ else
+ return FALSE;
+ return isDockEnabled( dw, dock );
+}
+
+/*!
+ \overload
+
+ Returns TRUE if dock area \a dock is enabled for the dock window
+ \a tb; otherwise returns FALSE.
+
+ \sa setDockEnabled()
+*/
+
+bool QMainWindow::isDockEnabled( QDockWindow *tb, Dock dock ) const
+{
+ if ( !isDockEnabled( dock ) )
+ return FALSE;
+ QString s;
+ s.sprintf( "%p_%d", (void*)tb, (int)dock );
+ return d->disabledDocks.find( s ) == d->disabledDocks.end();
+}
+
+
+
+/*!
+ Adds \a dockWindow to the \a edge dock area.
+
+ If \a newLine is FALSE (the default) then the \a dockWindow is
+ added at the end of the \a edge. For vertical edges the end is at
+ the bottom, for horizontal edges (including \c Minimized) the end
+ is at the right. If \a newLine is TRUE a new line of dock windows
+ is started with \a dockWindow as the first (left-most and
+ top-most) dock window.
+
+ If \a dockWindow is managed by another main window, it is first
+ removed from that window.
+*/
+
+void QMainWindow::addDockWindow( QDockWindow *dockWindow,
+ Dock edge, bool newLine )
+{
+#ifdef Q_WS_MAC
+ if(isTopLevel() && edge == DockTop)
+ ChangeWindowAttributes((WindowPtr)handle(), kWindowToolbarButtonAttribute, 0);
+#endif
+ moveDockWindow( dockWindow, edge );
+ dockWindow->setNewLine( newLine );
+ if ( d->dockWindows.find( dockWindow ) == -1 ) {
+ d->dockWindows.append( dockWindow );
+ connect( dockWindow, SIGNAL( placeChanged(QDockWindow::Place) ),
+ this, SLOT( slotPlaceChanged() ) );
+ dockWindow->installEventFilter( this );
+ }
+ dockWindow->setOpaqueMoving( d->opaque );
+}
+
+
+/*!
+ \overload
+
+ Adds \a dockWindow to the dock area with label \a label.
+
+ If \a newLine is FALSE (the default) the \a dockWindow is added at
+ the end of the \a edge. For vertical edges the end is at the
+ bottom, for horizontal edges (including \c Minimized) the end is
+ at the right. If \a newLine is TRUE a new line of dock windows is
+ started with \a dockWindow as the first (left-most and top-most)
+ dock window.
+
+ If \a dockWindow is managed by another main window, it is first
+ removed from that window.
+*/
+
+void QMainWindow::addDockWindow( QDockWindow * dockWindow, const QString &label,
+ Dock edge, bool newLine )
+{
+ addDockWindow( dockWindow, edge, newLine );
+#ifndef QT_NO_TOOLBAR
+ QToolBar *tb = ::qt_cast<QToolBar*>(dockWindow);
+ if ( tb )
+ tb->setLabel( label );
+#endif
+}
+
+/*!
+ Moves \a dockWindow to the end of the \a edge.
+
+ For vertical edges the end is at the bottom, for horizontal edges
+ (including \c Minimized) the end is at the right.
+
+ If \a dockWindow is managed by another main window, it is first
+ removed from that window.
+*/
+
+void QMainWindow::moveDockWindow( QDockWindow * dockWindow, Dock edge )
+{
+ Orientation oo = dockWindow->orientation();
+ switch ( edge ) {
+ case DockTop:
+ if ( dockWindow->area() != d->topDock )
+ dockWindow->removeFromDock( FALSE );
+ d->topDock->moveDockWindow( dockWindow );
+ emit dockWindowPositionChanged( dockWindow );
+ break;
+ case DockBottom:
+ if ( dockWindow->area() != d->bottomDock )
+ dockWindow->removeFromDock( FALSE );
+ d->bottomDock->moveDockWindow( dockWindow );
+ emit dockWindowPositionChanged( dockWindow );
+ break;
+ case DockRight:
+ if ( dockWindow->area() != d->rightDock )
+ dockWindow->removeFromDock( FALSE );
+ d->rightDock->moveDockWindow( dockWindow );
+ emit dockWindowPositionChanged( dockWindow );
+ break;
+ case DockLeft:
+ if ( dockWindow->area() != d->leftDock )
+ dockWindow->removeFromDock( FALSE );
+ d->leftDock->moveDockWindow( dockWindow );
+ emit dockWindowPositionChanged( dockWindow );
+ break;
+ case DockTornOff:
+ dockWindow->undock();
+ break;
+ case DockMinimized:
+ dockWindow->undock( d->hideDock );
+ break;
+ case DockUnmanaged:
+ break;
+ }
+
+ if ( oo != dockWindow->orientation() )
+ dockWindow->setOrientation( dockWindow->orientation() );
+}
+
+/*!
+ \overload
+
+ Moves \a dockWindow to position \a index within the \a edge dock
+ area.
+
+ Any dock windows with positions \a index or higher have their
+ position number incremented and any of these on the same line are
+ moved right (down for vertical dock areas) to make room.
+
+ If \a nl is TRUE, a new dock window line is created below the line
+ in which the moved dock window appears and the moved dock window,
+ with any others with higher positions on the same line, is moved
+ to this new line.
+
+ The \a extraOffset is the space to put between the left side of
+ the dock area (top side for vertical dock areas) and the dock
+ window. (This is mostly used for restoring dock windows to the
+ positions the user has dragged them to.)
+
+ If \a dockWindow is managed by another main window, it is first
+ removed from that window.
+*/
+
+void QMainWindow::moveDockWindow( QDockWindow * dockWindow, Dock edge, bool nl, int index, int extraOffset )
+{
+ Orientation oo = dockWindow->orientation();
+
+ dockWindow->setNewLine( nl );
+ dockWindow->setOffset( extraOffset );
+ switch ( edge ) {
+ case DockTop:
+ if ( dockWindow->area() != d->topDock )
+ dockWindow->removeFromDock( FALSE );
+ d->topDock->moveDockWindow( dockWindow, index );
+ break;
+ case DockBottom:
+ if ( dockWindow->area() != d->bottomDock )
+ dockWindow->removeFromDock( FALSE );
+ d->bottomDock->moveDockWindow( dockWindow, index );
+ break;
+ case DockRight:
+ if ( dockWindow->area() != d->rightDock )
+ dockWindow->removeFromDock( FALSE );
+ d->rightDock->moveDockWindow( dockWindow, index );
+ break;
+ case DockLeft:
+ if ( dockWindow->area() != d->leftDock )
+ dockWindow->removeFromDock( FALSE );
+ d->leftDock->moveDockWindow( dockWindow, index );
+ break;
+ case DockTornOff:
+ dockWindow->undock();
+ break;
+ case DockMinimized:
+ dockWindow->undock( d->hideDock );
+ break;
+ case DockUnmanaged:
+ break;
+ }
+
+ if ( oo != dockWindow->orientation() )
+ dockWindow->setOrientation( dockWindow->orientation() );
+}
+
+/*!
+ Removes \a dockWindow from the main window's docking area,
+ provided \a dockWindow is non-null and managed by this main
+ window.
+*/
+
+void QMainWindow::removeDockWindow( QDockWindow * dockWindow )
+{
+#ifdef Q_WS_MAC
+ if(isTopLevel() && dockWindow->area() == topDock() && !dockWindows( DockTop ).count())
+ ChangeWindowAttributes((WindowPtr)handle(), 0, kWindowToolbarButtonAttribute);
+#endif
+
+ dockWindow->hide();
+ d->dockWindows.removeRef( dockWindow );
+ disconnect( dockWindow, SIGNAL( placeChanged(QDockWindow::Place) ),
+ this, SLOT( slotPlaceChanged() ) );
+ dockWindow->removeEventFilter( this );
+}
+
+/*!
+ Sets up the geometry management of the window. It is called
+ automatically when needed, so you shouldn't need to call it.
+*/
+
+void QMainWindow::setUpLayout()
+{
+#ifndef QT_NO_MENUBAR
+ if ( !d->mb ) {
+ // slightly evil hack here. reconsider this
+ QObjectList * l
+ = ((QObject*)this)->queryList( "QMenuBar", 0, FALSE, FALSE );
+ if ( l && l->count() )
+ d->mb = menuBar();
+ delete l;
+ }
+#endif
+ if ( !d->sb ) {
+ // as above.
+ QObjectList * l
+ = ((QObject*)this)->queryList( "QStatusBar", 0, FALSE, FALSE );
+ if ( l && l->count() )
+ d->sb = statusBar();
+ delete l;
+ }
+
+ if (!d->tll) {
+ d->tll = new QBoxLayout( this, QBoxLayout::Down );
+ d->tll->setResizeMode( minimumSize().isNull() ? QLayout::Minimum : QLayout::FreeResize );
+ } else {
+ d->tll->setMenuBar( 0 );
+ QLayoutIterator it = d->tll->iterator();
+ QLayoutItem *item;
+ while ( (item = it.takeCurrent()) )
+ delete item;
+ }
+
+#ifndef QT_NO_MENUBAR
+ if ( d->mb && d->mb->isVisibleTo( this ) ) {
+ d->tll->setMenuBar( d->mb );
+ if (style().styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, this))
+ d->tll->addSpacing( d->movable ? 1 : 2 );
+ }
+#endif
+
+ d->tll->addWidget( d->hideDock );
+ if(d->topDock->parentWidget() == this)
+ d->tll->addWidget( d->topDock );
+
+ QMainWindowLayout *mwl = new QMainWindowLayout( this, d->tll );
+ d->tll->setStretchFactor( mwl, 1 );
+
+ if(d->leftDock->parentWidget() == this)
+ mwl->setLeftDock( d->leftDock );
+ if ( centralWidget() )
+ mwl->setCentralWidget( centralWidget() );
+ if(d->rightDock->parentWidget() == this)
+ mwl->setRightDock( d->rightDock );
+ d->mwl = mwl;
+
+ if(d->bottomDock->parentWidget() == this)
+ d->tll->addWidget( d->bottomDock );
+
+ if ( d->sb && d->sb->parentWidget() == this) {
+ d->tll->addWidget( d->sb, 0 );
+ // make the sb stay on top of tool bars if there isn't enough space
+ d->sb->raise();
+ }
+}
+
+/*! \reimp */
+void QMainWindow::show()
+{
+ if ( !d->tll )
+ setUpLayout();
+
+ // show all floating dock windows not explicitly hidden
+ if (!isVisible()) {
+ QPtrListIterator<QDockWindow> it(d->dockWindows);
+ while ( it.current() ) {
+ QDockWindow *dw = it.current();
+ ++it;
+ if ( dw->isTopLevel() && !dw->isVisible() && !dw->testWState(WState_ForceHide) )
+ dw->show();
+ }
+ }
+
+ // show us last so we get focus
+ QWidget::show();
+}
+
+
+/*! \reimp
+*/
+void QMainWindow::hide()
+{
+ if ( isVisible() ) {
+ QPtrListIterator<QDockWindow> it(d->dockWindows);
+ while ( it.current() ) {
+ QDockWindow *dw = it.current();
+ ++it;
+ if ( dw->isTopLevel() && dw->isVisible() ) {
+ dw->hide(); // implicit hide, so clear forcehide
+ ((QMainWindow*)dw)->clearWState(WState_ForceHide);
+ }
+ }
+ }
+
+ QWidget::hide();
+}
+
+
+/*! \reimp */
+QSize QMainWindow::sizeHint() const
+{
+ QMainWindow* that = (QMainWindow*) this;
+ // Workaround: because d->tll get's deleted in
+ // totalSizeHint->polish->sendPostedEvents->childEvent->triggerLayout
+ // [eg. canvas example on Qt/Embedded]
+ QApplication::sendPostedEvents( that, QEvent::ChildInserted );
+ if ( !that->d->tll )
+ that->setUpLayout();
+ return that->d->tll->totalSizeHint();
+}
+
+/*! \reimp */
+QSize QMainWindow::minimumSizeHint() const
+{
+ if ( !d->tll ) {
+ QMainWindow* that = (QMainWindow*) this;
+ that->setUpLayout();
+ }
+ return d->tll->totalMinimumSize();
+}
+
+/*!
+ Sets the central widget for this main window to \a w.
+
+ The central widget is surrounded by the left, top, right and
+ bottom dock areas. The menu bar is above the top dock area.
+
+ \sa centralWidget()
+*/
+
+void QMainWindow::setCentralWidget( QWidget * w )
+{
+ if ( d->mc )
+ d->mc->removeEventFilter( this );
+ d->mc = w;
+ if ( d->mc )
+ d->mc->installEventFilter( this );
+ triggerLayout();
+}
+
+
+/*!
+ Returns a pointer to the main window's central widget.
+
+ The central widget is surrounded by the left, top, right and
+ bottom dock areas. The menu bar is above the top dock area.
+
+ \sa setCentralWidget()
+*/
+
+QWidget * QMainWindow::centralWidget() const
+{
+ return d->mc;
+}
+
+
+/*! \reimp */
+
+void QMainWindow::paintEvent( QPaintEvent * )
+{
+ if (d->mb &&
+ style().styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, this)) {
+ QPainter p( this );
+ int y = d->mb->height() + 1;
+ style().drawPrimitive(QStyle::PE_Separator, &p, QRect(0, y, width(), 1),
+ colorGroup(), QStyle::Style_Sunken);
+ }
+}
+
+
+bool QMainWindow::dockMainWindow( QObject *dock )
+{
+ while ( dock ) {
+ if ( dock->parent() && dock->parent() == this )
+ return TRUE;
+ if ( ::qt_cast<QMainWindow*>(dock->parent()) )
+ return FALSE;
+ dock = dock->parent();
+ }
+ return FALSE;
+}
+
+/*!
+ \reimp
+*/
+
+bool QMainWindow::eventFilter( QObject* o, QEvent *e )
+{
+ if ( e->type() == QEvent::Show && o == this ) {
+ if ( !d->tll )
+ setUpLayout();
+ d->tll->activate();
+ } else if ( e->type() == QEvent::ContextMenu && d->dockMenu &&
+ ( ::qt_cast<QDockArea*>(o) && dockMainWindow( o ) || o == d->hideDock || o == d->mb ) ) {
+ if ( showDockMenu( ( (QMouseEvent*)e )->globalPos() ) ) {
+ ( (QContextMenuEvent*)e )->accept();
+ return TRUE;
+ }
+ }
+
+ return QWidget::eventFilter( o, e );
+}
+
+
+/*!
+ Monitors events, recieved in \a e, to ensure the layout is updated.
+*/
+void QMainWindow::childEvent( QChildEvent* e)
+{
+ if ( e->type() == QEvent::ChildRemoved ) {
+ if ( e->child() == 0 ||
+ !e->child()->isWidgetType() ||
+ ((QWidget*)e->child())->testWFlags( WType_TopLevel ) ) {
+ // nothing
+ } else if ( e->child() == d->sb ) {
+ d->sb = 0;
+ triggerLayout();
+ } else if ( e->child() == d->mb ) {
+ d->mb = 0;
+ triggerLayout();
+ } else if ( e->child() == d->mc ) {
+ d->mc = 0;
+ d->mwl->setCentralWidget( 0 );
+ triggerLayout();
+ } else if ( ::qt_cast<QDockWindow*>(e->child()) ) {
+ removeDockWindow( (QDockWindow *)(e->child()) );
+ d->appropriate.remove( (QDockWindow*)e->child() );
+ triggerLayout();
+ }
+ } else if ( e->type() == QEvent::ChildInserted && !d->sb ) {
+ d->sb = ::qt_cast<QStatusBar*>(e->child());
+ if ( d->sb ) {
+ if ( d->tll ) {
+ if ( !d->tll->findWidget( d->sb ) )
+ d->tll->addWidget( d->sb );
+ } else {
+ triggerLayout();
+ }
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+
+bool QMainWindow::event( QEvent * e )
+{
+ if ( e->type() == QEvent::ChildRemoved && ( (QChildEvent*)e )->child() == d->mc ) {
+ d->mc->removeEventFilter( this );
+ d->mc = 0;
+ d->mwl->setCentralWidget( 0 );
+ }
+
+ return QWidget::event( e );
+}
+
+
+/*!
+ \property QMainWindow::usesBigPixmaps
+ \brief whether big pixmaps are enabled
+
+ If FALSE (the default), the tool buttons will use small pixmaps;
+ otherwise big pixmaps will be used.
+
+ Tool buttons and other widgets that wish to respond to this
+ setting are responsible for reading the correct state on startup,
+ and for connecting to the main window's widget's
+ pixmapSizeChanged() signal.
+*/
+
+bool QMainWindow::usesBigPixmaps() const
+{
+ return d->ubp;
+}
+
+void QMainWindow::setUsesBigPixmaps( bool enable )
+{
+ if ( enable == (bool)d->ubp )
+ return;
+
+ d->ubp = enable;
+ emit pixmapSizeChanged( enable );
+
+ QObjectList *l = queryList( "QLayout" );
+ if ( !l || !l->first() ) {
+ delete l;
+ return;
+ }
+ for ( QLayout *lay = (QLayout*)l->first(); lay; lay = (QLayout*)l->next() )
+ lay->activate();
+ delete l;
+}
+
+/*!
+ \property QMainWindow::usesTextLabel
+ \brief whether text labels for toolbar buttons are enabled
+
+ If disabled (the default), the tool buttons will not use text
+ labels. If enabled, text labels will be used.
+
+ Tool buttons and other widgets that wish to respond to this
+ setting are responsible for reading the correct state on startup,
+ and for connecting to the main window's widget's
+ usesTextLabelChanged() signal.
+
+ \sa QToolButton::setUsesTextLabel()
+*/
+
+bool QMainWindow::usesTextLabel() const
+{
+ return d->utl;
+}
+
+
+void QMainWindow::setUsesTextLabel( bool enable )
+{
+ if ( enable == (bool)d->utl )
+ return;
+
+ d->utl = enable;
+ emit usesTextLabelChanged( enable );
+
+ QObjectList *l = queryList( "QLayout" );
+ if ( !l || !l->first() ) {
+ delete l;
+ return;
+ }
+ for ( QLayout *lay = (QLayout*)l->first(); lay; lay = (QLayout*)l->next() )
+ lay->activate();
+ delete l;
+}
+
+
+/*!
+ \fn void QMainWindow::pixmapSizeChanged( bool )
+
+ This signal is emitted whenever the setUsesBigPixmaps() is called
+ with a value different to the current setting. All widgets that
+ should respond to such changes, e.g. toolbar buttons, must connect
+ to this signal.
+*/
+
+/*!
+ \fn void QMainWindow::usesTextLabelChanged( bool )
+
+ This signal is emitted whenever the setUsesTextLabel() is called
+ with a value different to the current setting. All widgets that
+ should respond to such changes, e.g. toolbar buttons, must connect
+ to this signal.
+*/
+
+/*!
+ \fn void QMainWindow::dockWindowPositionChanged( QDockWindow *dockWindow )
+
+ This signal is emitted when the \a dockWindow has changed its
+ position. A change in position occurs when a dock window is moved
+ within its dock area or moved to another dock area (including the
+ \c Minimized and \c TearOff dock areas).
+
+ \sa getLocation()
+*/
+
+void QMainWindow::setRightJustification( bool enable )
+{
+ if ( enable == (bool)d->justify )
+ return;
+ d->justify = enable;
+ triggerLayout( TRUE );
+}
+
+
+/*!
+ \obsolete
+ \property QMainWindow::rightJustification
+ \brief whether the main window right-justifies its dock windows
+
+ If disabled (the default), stretchable dock windows are expanded,
+ and non-stretchable dock windows are given the minimum space they
+ need. Since most dock windows are not stretchable, this usually
+ results in an unjustified right edge (or unjustified bottom edge
+ for a vertical dock area). If enabled, the main window will
+ right-justify its dock windows.
+
+ \sa QDockWindow::setVerticalStretchable(), QDockWindow::setHorizontalStretchable()
+*/
+
+bool QMainWindow::rightJustification() const
+{
+ return d->justify;
+}
+
+/*! \internal
+ */
+
+void QMainWindow::triggerLayout( bool deleteLayout )
+{
+ if ( deleteLayout || !d->tll )
+ setUpLayout();
+ QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
+}
+
+/*!
+ Enters 'What's This?' mode and returns immediately.
+
+ This is the same as QWhatsThis::enterWhatsThisMode(), but
+ implemented as a main window object's slot. This way it can easily
+ be used for popup menus, for example:
+
+ \code
+ QPopupMenu * help = new QPopupMenu( this );
+ help->insertItem( "What's &This", this , SLOT(whatsThis()), SHIFT+Key_F1);
+ \endcode
+
+ \sa QWhatsThis::enterWhatsThisMode()
+*/
+void QMainWindow::whatsThis()
+{
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::enterWhatsThisMode();
+#endif
+}
+
+
+/*!
+ \reimp
+*/
+
+void QMainWindow::styleChange( QStyle& old )
+{
+ QWidget::styleChange( old );
+}
+
+/*!
+ Finds the location of the dock window \a dw.
+
+ If the \a dw dock window is found in the main window the function
+ returns TRUE and populates the \a dock variable with the dw's dock
+ area and the \a index with the dw's position within the dock area.
+ It also sets \a nl to TRUE if the \a dw begins a new line
+ (otherwise FALSE), and \a extraOffset with the dock window's offset.
+
+ If the \a dw dock window is not found then the function returns
+ FALSE and the state of \a dock, \a index, \a nl and \a extraOffset
+ is undefined.
+
+ If you want to save and restore dock window positions then use
+ operator>>() and operator<<().
+
+ \sa operator>>() operator<<()
+*/
+
+bool QMainWindow::getLocation( QDockWindow *dw, Dock &dock, int &index, bool &nl, int &extraOffset ) const
+{
+ dock = DockTornOff;
+ if ( d->topDock->hasDockWindow( dw, &index ) )
+ dock = DockTop;
+ else if ( d->bottomDock->hasDockWindow( dw, &index ) )
+ dock = DockBottom;
+ else if ( d->leftDock->hasDockWindow( dw, &index ) )
+ dock = DockLeft;
+ else if ( d->rightDock->hasDockWindow( dw, &index ) )
+ dock = DockRight;
+ else if ( dw->parentWidget() == d->hideDock ) {
+ index = 0;
+ dock = DockMinimized;
+ } else {
+ index = 0;
+ }
+ nl = dw->newLine();
+ extraOffset = dw->offset();
+ return TRUE;
+}
+
+#ifndef QT_NO_TOOLBAR
+/*!
+ Returns a list of all the toolbars which are in the \a dock dock
+ area, regardless of their state.
+
+ For example, the \c TornOff dock area may contain closed toolbars
+ but these are returned along with the visible toolbars.
+
+ \sa dockWindows()
+*/
+
+QPtrList<QToolBar> QMainWindow::toolBars( Dock dock ) const
+{
+ QPtrList<QDockWindow> lst = dockWindows( dock );
+ QPtrList<QToolBar> tbl;
+ for ( QDockWindow *w = lst.first(); w; w = lst.next() ) {
+ QToolBar *tb = ::qt_cast<QToolBar*>(w);
+ if ( tb )
+ tbl.append( tb );
+ }
+ return tbl;
+}
+#endif
+
+/*!
+ Returns a list of all the dock windows which are in the \a dock
+ dock area, regardless of their state.
+
+ For example, the \c DockTornOff dock area may contain closed dock
+ windows but these are returned along with the visible dock
+ windows.
+*/
+
+QPtrList<QDockWindow> QMainWindow::dockWindows( Dock dock ) const
+{
+ QPtrList<QDockWindow> lst;
+ switch ( dock ) {
+ case DockTop:
+ return d->topDock->dockWindowList();
+ case DockBottom:
+ return d->bottomDock->dockWindowList();
+ case DockLeft:
+ return d->leftDock->dockWindowList();
+ case DockRight:
+ return d->rightDock->dockWindowList();
+ case DockTornOff: {
+ for ( QDockWindow *w = d->dockWindows.first(); w; w = d->dockWindows.next() ) {
+ if ( !w->area() && w->place() == QDockWindow::OutsideDock )
+ lst.append( w );
+ }
+ }
+ return lst;
+ case DockMinimized: {
+ if ( d->hideDock->children() ) {
+ QObjectListIt it( *d->hideDock->children() );
+ QObject *o;
+ while ( ( o = it.current() ) ) {
+ ++it;
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(o);
+ if ( !dw )
+ continue;
+ lst.append( dw );
+ }
+ }
+ }
+ return lst;
+ default:
+ break;
+ }
+ return lst;
+}
+
+/*!
+ \overload
+
+ Returns the list of dock windows which belong to this main window,
+ regardless of which dock area they are in or what their state is,
+ (e.g. irrespective of whether they are visible or not).
+*/
+
+QPtrList<QDockWindow> QMainWindow::dockWindows() const
+{
+ return d->dockWindows;
+}
+
+void QMainWindow::setDockWindowsMovable( bool enable )
+{
+ d->movable = enable;
+ QObjectList *l = queryList( "QDockWindow" );
+ if ( l ) {
+ for ( QObject *o = l->first(); o; o = l->next() )
+ ( (QDockWindow*)o )->setMovingEnabled( enable );
+ }
+ delete l;
+}
+
+/*!
+ \property QMainWindow::dockWindowsMovable
+ \brief whether the dock windows are movable
+
+ If TRUE (the default), the user will be able to move movable dock
+ windows from one QMainWindow dock area to another, including the
+ \c TearOff area (i.e. where the dock window floats freely as a
+ window in its own right), and the \c Minimized area (where only
+ the dock window's handle is shown below the menu bar). Moveable
+ dock windows can also be moved within QMainWindow dock areas, i.e.
+ to rearrange them within a dock area.
+
+ If FALSE the user will not be able to move any dock windows.
+
+ By default dock windows are moved transparently (i.e. only an
+ outline rectangle is shown during the drag), but this setting can
+ be changed with setOpaqueMoving().
+
+ \sa setDockEnabled(), setOpaqueMoving()
+*/
+
+bool QMainWindow::dockWindowsMovable() const
+{
+ return d->movable;
+}
+
+void QMainWindow::setOpaqueMoving( bool b )
+{
+ d->opaque = b;
+ QObjectList *l = queryList( "QDockWindow" );
+ if ( l ) {
+ for ( QObject *o = l->first(); o; o = l->next() )
+ ( (QDockWindow*)o )->setOpaqueMoving( b );
+ }
+ delete l;
+}
+
+/*!
+ \property QMainWindow::opaqueMoving
+ \brief whether dock windows are moved opaquely
+
+ If TRUE the dock windows of the main window are shown opaquely
+ (i.e. it shows the toolbar as it looks when docked) whilst it is
+ being moved. If FALSE (the default) they are shown transparently,
+ (i.e. as an outline rectangle).
+
+ \warning Opaque moving of toolbars and dockwindows is known to
+ have several problems. We recommend avoiding the use of this
+ feature for the time being. We intend fixing the problems in a
+ future release.
+*/
+
+bool QMainWindow::opaqueMoving() const
+{
+ return d->opaque;
+}
+
+/*!
+ This function will line up dock windows within the visible dock
+ areas (\c Top, \c Left, \c Right and \c Bottom) as compactly as
+ possible.
+
+ If \a keepNewLines is TRUE, all dock windows stay on their
+ original lines. If \a keepNewLines is FALSE then newlines may be
+ removed to achieve the most compact layout possible.
+
+ The method only works if dockWindowsMovable() returns TRUE.
+*/
+
+void QMainWindow::lineUpDockWindows( bool keepNewLines )
+{
+ if ( !dockWindowsMovable() )
+ return;
+ d->topDock->lineUp( keepNewLines );
+ d->leftDock->lineUp( keepNewLines );
+ d->rightDock->lineUp( keepNewLines );
+ d->bottomDock->lineUp( keepNewLines );
+}
+
+/*!
+ Returns TRUE, if the dock window menu is enabled; otherwise
+ returns FALSE.
+
+ The menu lists the (appropriate()) dock windows (which may be
+ shown or hidden), and has a "Line Up Dock Windows" menu item. It
+ will also have a "Customize" menu item if isCustomizable() returns
+ TRUE.
+
+ \sa setDockEnabled(), lineUpDockWindows() appropriate()
+ setAppropriate()
+*/
+
+bool QMainWindow::isDockMenuEnabled() const
+{
+ return d->dockMenu;
+}
+
+/*!
+ If \a b is TRUE, then right clicking on a dock window or dock area
+ will pop up the dock window menu. If \a b is FALSE, right clicking
+ a dock window or dock area will not pop up the menu.
+
+ The menu lists the (appropriate()) dock windows (which may be
+ shown or hidden), and has a "Line Up Dock Windows" item. It will
+ also have a "Customize" menu item if isCustomizable() returns
+ TRUE.
+
+ \sa lineUpDockWindows(), isDockMenuEnabled()
+*/
+
+void QMainWindow::setDockMenuEnabled( bool b )
+{
+ d->dockMenu = b;
+}
+
+/*!
+ Creates the dock window menu which contains all toolbars (if \a
+ dockWindows is \c OnlyToolBars ), all dock windows (if \a
+ dockWindows is \c NoToolBars) or all toolbars and dock windows (if
+ \a dockWindows is \c AllDockWindows - the default).
+
+ This function is called internally when necessary, e.g. when the
+ user right clicks a dock area (providing isDockMenuEnabled()
+ returns TRUE).
+\omit
+### Qt 4.0
+ You can reimplement this function if you wish to customize the
+ behaviour.
+\endomit
+
+ The menu items representing the toolbars and dock windows are
+ checkable. The visible dock windows are checked and the hidden
+ dock windows are unchecked. The user can click a menu item to
+ change its state (show or hide the dock window).
+
+ The list and the state are always kept up-to-date.
+
+ Toolbars and dock windows which are not appropriate in the current
+ context (see setAppropriate()) are not listed in the menu.
+
+ The menu also has a menu item for lining up the dock windows.
+
+ If isCustomizable() returns TRUE, a Customize menu item is added
+ to the menu, which if clicked will call customize(). The
+ isCustomizable() function we provide returns FALSE and customize()
+ does nothing, so they must be reimplemented in a subclass to be
+ useful.
+*/
+
+QPopupMenu *QMainWindow::createDockWindowMenu( DockWindows dockWindows ) const
+{
+ QObjectList *l = queryList( "QDockWindow" );
+
+ if ( !l || l->isEmpty() )
+ return 0;
+
+ delete l;
+
+ QPopupMenu *menu = new QPopupMenu( (QMainWindow*)this, "qt_customize_menu" );
+ menu->setCheckable( TRUE );
+ d->dockWindowModes.replace( menu, dockWindows );
+ connect( menu, SIGNAL( aboutToShow() ), this, SLOT( menuAboutToShow() ) );
+ return menu;
+}
+
+/*!
+ This slot is called from the aboutToShow() signal of the default
+ dock menu of the mainwindow. The default implementation
+ initializes the menu with all dock windows and toolbars in this
+ slot.
+\omit
+### Qt 4.0
+ If you want to do small adjustments to the menu, you can do it in
+ this slot; or you can reimplement createDockWindowMenu().
+\endomit
+*/
+
+void QMainWindow::menuAboutToShow()
+{
+ QPopupMenu *menu = (QPopupMenu*)sender();
+ QMap<QPopupMenu*, DockWindows>::Iterator it = d->dockWindowModes.find( menu );
+ if ( it == d->dockWindowModes.end() )
+ return;
+ menu->clear();
+
+ DockWindows dockWindows = *it;
+
+ QObjectList *l = queryList( "QDockWindow" );
+
+ bool empty = TRUE;
+ if ( l && !l->isEmpty() ) {
+
+ QObject *o = 0;
+ if ( dockWindows == AllDockWindows || dockWindows == NoToolBars ) {
+ for ( o = l->first(); o; o = l->next() ) {
+ QDockWindow *dw = (QDockWindow*)o;
+ if ( !appropriate( dw ) || ::qt_cast<QToolBar*>(dw) || !dockMainWindow( dw ) )
+ continue;
+ QString label = dw->caption();
+ if ( !label.isEmpty() ) {
+ int id = menu->insertItem( label, dw, SLOT( toggleVisible() ) );
+ menu->setItemChecked( id, dw->isVisible() );
+ empty = FALSE;
+ }
+ }
+ if ( !empty )
+ menu->insertSeparator();
+ }
+
+ empty = TRUE;
+
+#ifndef QT_NO_TOOLBAR
+ if ( dockWindows == AllDockWindows || dockWindows == OnlyToolBars ) {
+ for ( o = l->first(); o; o = l->next() ) {
+ QToolBar *tb = ::qt_cast<QToolBar*>(o);
+ if ( !tb || !appropriate(tb) || !dockMainWindow(tb) )
+ continue;
+ QString label = tb->label();
+ if ( !label.isEmpty() ) {
+ int id = menu->insertItem( label, tb, SLOT( toggleVisible() ) );
+ menu->setItemChecked( id, tb->isVisible() );
+ empty = FALSE;
+ }
+ }
+ }
+#endif
+
+ }
+
+ delete l;
+
+ if ( !empty )
+ menu->insertSeparator();
+
+ if ( dockWindowsMovable() )
+ menu->insertItem( tr( "Line up" ), this, SLOT( doLineUp() ) );
+ if ( isCustomizable() )
+ menu->insertItem( tr( "Customize..." ), this, SLOT( customize() ) );
+}
+
+/*!
+ Shows the dock menu at the position \a globalPos. The menu lists
+ the dock windows so that they can be shown (or hidden), lined up,
+ and possibly customized. Returns TRUE if the menu is shown;
+ otherwise returns FALSE.
+
+ If you want a custom menu, reimplement this function. You can
+ create the menu from scratch or call createDockWindowMenu() and
+ modify the result.
+\omit
+### Qt 4.0
+ The default implementation uses the dock window menu which gets
+ created by createDockWindowMenu(). You can reimplement
+ createDockWindowMenu() if you want to use your own specialized
+ popup menu.
+\endomit
+*/
+
+bool QMainWindow::showDockMenu( const QPoint &globalPos )
+{
+ if ( !d->dockMenu )
+ return FALSE;
+ if ( !d->rmbMenu )
+ d->rmbMenu = createDockWindowMenu();
+ if ( !d->rmbMenu )
+ return FALSE;
+
+ d->rmbMenu->exec( globalPos );
+ return TRUE;
+}
+
+void QMainWindow::slotPlaceChanged()
+{
+ QObject* obj = (QObject*)sender();
+ QDockWindow *dw = ::qt_cast<QDockWindow*>(obj);
+ if ( dw )
+ emit dockWindowPositionChanged( dw );
+#ifndef QT_NO_TOOLBAR
+ QToolBar *tb = ::qt_cast<QToolBar*>(obj);
+ if ( tb )
+ emit toolBarPositionChanged( tb );
+#endif
+}
+
+/*!
+ \internal
+ For internal use of QDockWindow only.
+ */
+
+QDockArea *QMainWindow::dockingArea( const QPoint &p )
+{
+ int mh = d->mb ? d->mb->height() : 0;
+ int sh = d->sb ? d->sb->height() : 0;
+ if ( p.x() >= -5 && p.x() <= 100 && p.y() > mh && p.y() - height() - sh )
+ return d->leftDock;
+ if ( p.x() >= width() - 100 && p.x() <= width() + 5 && p.y() > mh && p.y() - height() - sh )
+ return d->rightDock;
+ if ( p.y() >= -5 && p.y() < mh + 100 && p.x() >= 0 && p.x() <= width() )
+ return d->topDock;
+ if ( p.y() >= height() - sh - 100 && p.y() <= height() + 5 && p.x() >= 0 && p.x() <= width() )
+ return d->bottomDock;
+ return 0;
+}
+
+/*!
+ Returns TRUE if \a dw is a dock window known to the main window;
+ otherwise returns FALSE.
+*/
+
+bool QMainWindow::hasDockWindow( QDockWindow *dw )
+{
+ return d->dockWindows.findRef( dw ) != -1;
+}
+
+/*!
+ Returns the \c Left dock area
+
+ \sa rightDock() topDock() bottomDock()
+*/
+
+QDockArea *QMainWindow::leftDock() const
+{
+ return d->leftDock;
+}
+
+/*!
+ Returns the \c Right dock area
+
+ \sa leftDock() topDock() bottomDock()
+*/
+
+QDockArea *QMainWindow::rightDock() const
+{
+ return d->rightDock;
+}
+
+/*!
+ Returns the \c Top dock area
+
+ \sa bottomDock() leftDock() rightDock()
+*/
+
+QDockArea *QMainWindow::topDock() const
+{
+ return d->topDock;
+}
+
+/*!
+ Returns a pointer the \c Bottom dock area
+
+ \sa topDock() leftDock() rightDock()
+*/
+
+QDockArea *QMainWindow::bottomDock() const
+{
+ return d->bottomDock;
+}
+
+/*!
+ This function is called when the user clicks the Customize menu
+ item on the dock window menu.
+
+ The customize menu item will only appear if isCustomizable()
+ returns TRUE (it returns FALSE by default).
+
+ The function is intended, for example, to provide the user with a
+ means of telling the application that they wish to customize the
+ main window, dock windows or dock areas.
+
+ The default implementation does nothing and the Customize menu
+ item is not shown on the right-click menu by default. If you want
+ the item to appear then reimplement isCustomizable() to return
+ TRUE, and reimplement this function to do whatever you want.
+
+ \sa isCustomizable()
+*/
+
+void QMainWindow::customize()
+{
+}
+
+/*!
+ Returns TRUE if the dock area dock window menu includes the
+ Customize menu item (which calls customize() when clicked).
+ Returns FALSE by default, i.e. the popup menu will not contain a
+ Customize menu item. You will need to reimplement this function
+ and set it to return TRUE if you wish the user to be able to see
+ the dock window menu.
+
+ \sa customize()
+*/
+
+bool QMainWindow::isCustomizable() const
+{
+ return FALSE;
+}
+
+/*!
+ Returns TRUE if it is appropriate to include a menu item for the
+ \a dw dock window in the dock window menu; otherwise returns
+ FALSE.
+
+ The user is able to change the state (show or hide) a dock window
+ that has a menu item by clicking the item.
+
+ Call setAppropriate() to indicate whether or not a particular dock
+ window should appear on the popup menu.
+
+ \sa setAppropriate()
+*/
+
+bool QMainWindow::appropriate( QDockWindow *dw ) const
+{
+ QMap<QDockWindow*, bool>::ConstIterator it = d->appropriate.find( dw );
+ if ( it == d->appropriate.end() )
+ return TRUE;
+ return *it;
+}
+
+/*!
+ Use this function to control whether or not the \a dw dock
+ window's caption should appear as a menu item on the dock window
+ menu that lists the dock windows.
+
+ If \a a is TRUE then the \a dw will appear as a menu item on the
+ dock window menu. The user is able to change the state (show or
+ hide) a dock window that has a menu item by clicking the item;
+ depending on the state of your application, this may or may not be
+ appropriate. If \a a is FALSE the \a dw will not appear on the
+ popup menu.
+
+ \sa showDockMenu() isCustomizable() customize()
+*/
+
+void QMainWindow::setAppropriate( QDockWindow *dw, bool a )
+{
+ d->appropriate.replace( dw, a );
+}
+
+#ifndef QT_NO_TEXTSTREAM
+static void saveDockArea( QTextStream &ts, QDockArea *a )
+{
+ QPtrList<QDockWindow> l = a->dockWindowList();
+ for ( QDockWindow *dw = l.first(); dw; dw = l.next() ) {
+ ts << QString( dw->caption() );
+ ts << ",";
+ }
+ ts << endl;
+ ts << *a;
+}
+
+/*!
+ \relates QMainWindow
+
+ Writes the layout (sizes and positions) of the dock windows in the
+ dock areas of the QMainWindow \a mainWindow, including \c
+ Minimized and \c TornOff dock windows, to the text stream \a ts.
+
+ This can be used, for example, in conjunction with QSettings to
+ save the user's layout when the \mainWindow receives a closeEvent.
+
+ \sa operator>>() closeEvent()
+*/
+
+QTextStream &operator<<( QTextStream &ts, const QMainWindow &mainWindow )
+{
+ QPtrList<QDockWindow> l = mainWindow.dockWindows( Qt::DockMinimized );
+ QDockWindow *dw = 0;
+ for ( dw = l.first(); dw; dw = l.next() ) {
+ ts << dw->caption();
+ ts << ",";
+ }
+ ts << endl;
+
+ l = mainWindow.dockWindows( Qt::DockTornOff );
+ for ( dw = l.first(); dw; dw = l.next() ) {
+ ts << dw->caption();
+ ts << ",";
+ }
+ ts << endl;
+ for ( dw = l.first(); dw; dw = l.next() ) {
+ ts << "[" << dw->caption() << ","
+ << (int)dw->geometry().x() << ","
+ << (int)dw->geometry().y() << ","
+ << (int)dw->geometry().width() << ","
+ << (int)dw->geometry().height() << ","
+ << (int)dw->isVisible() << "]";
+ }
+ ts << endl;
+
+ saveDockArea( ts, mainWindow.topDock() );
+ saveDockArea( ts, mainWindow.bottomDock() );
+ saveDockArea( ts, mainWindow.rightDock() );
+ saveDockArea( ts, mainWindow.leftDock() );
+ return ts;
+}
+
+static void loadDockArea( const QStringList &names, QDockArea *a, Qt::Dock d, QPtrList<QDockWindow> &l, QMainWindow *mw, QTextStream &ts )
+{
+ for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it ) {
+ for ( QDockWindow *dw = l.first(); dw; dw = l.next() ) {
+ if ( dw->caption() == *it ) {
+ mw->addDockWindow( dw, d );
+ break;
+ }
+ }
+ }
+ if ( a ) {
+ ts >> *a;
+ } else if ( d == Qt::DockTornOff ) {
+ QString s = ts.readLine();
+ enum State { Pre, Name, X, Y, Width, Height, Visible, Post };
+ int state = Pre;
+ QString name, x, y, w, h, visible;
+ QChar c;
+ for ( int i = 0; i < (int)s.length(); ++i ) {
+ c = s[ i ];
+ if ( state == Pre && c == '[' ) {
+ state++;
+ continue;
+ }
+ if ( c == ',' &&
+ ( state == Name || state == X || state == Y || state == Width || state == Height ) ) {
+ state++;
+ continue;
+ }
+ if ( state == Visible && c == ']' ) {
+ for ( QDockWindow *dw = l.first(); dw; dw = l.next() ) {
+ if ( QString( dw->caption() ) == name ) {
+ if ( !::qt_cast<QToolBar*>(dw) )
+ dw->setGeometry( x.toInt(), y.toInt(), w.toInt(), h.toInt() );
+ else
+ dw->setGeometry( x.toInt(), y.toInt(), dw->width(), dw->height() );
+ if ( !(bool)visible.toInt() )
+ dw->hide();
+ else
+ dw->show();
+ break;
+ }
+ }
+
+ name = x = y = w = h = visible = "";
+
+ state = Pre;
+ continue;
+ }
+ if ( state == Name )
+ name += c;
+ else if ( state == X )
+ x += c;
+ else if ( state == Y )
+ y += c;
+ else if ( state == Width )
+ w += c;
+ else if ( state == Height )
+ h += c;
+ else if ( state == Visible )
+ visible += c;
+ }
+ }
+}
+
+/*!
+ \relates QMainWindow
+
+ Reads the layout (sizes and positions) of the dock windows in the
+ dock areas of the QMainWindow \a mainWindow from the text stream,
+ \a ts, including \c Minimized and \c TornOff dock windows.
+ Restores the dock windows and dock areas to these sizes and
+ positions. The layout information must be in the format produced
+ by operator<<().
+
+ This can be used, for example, in conjunction with QSettings to
+ restore the user's layout.
+
+ \sa operator<<()
+*/
+
+QTextStream &operator>>( QTextStream &ts, QMainWindow &mainWindow )
+{
+ QPtrList<QDockWindow> l = mainWindow.dockWindows();
+
+ QString s = ts.readLine();
+ QStringList names = QStringList::split( ',', s );
+ loadDockArea( names, 0, Qt::DockMinimized, l, &mainWindow, ts );
+
+ s = ts.readLine();
+ names = QStringList::split( ',', s );
+ loadDockArea( names, 0, Qt::DockTornOff, l, &mainWindow, ts );
+
+ int i = 0;
+ QDockArea *areas[] = { mainWindow.topDock(), mainWindow.bottomDock(), mainWindow.rightDock(), mainWindow.leftDock() };
+ for ( int d = (int)Qt::DockTop; d != (int)Qt::DockMinimized; ++d, ++i ) {
+ s = ts.readLine();
+ names = QStringList::split( ',', s );
+ loadDockArea( names, areas[ i ], (Qt::Dock)d, l, &mainWindow, ts );
+ }
+ return ts;
+}
+#endif
+
+#include "qmainwindow.moc"
+
+#endif
diff --git a/src/widgets/qmainwindow.h b/src/widgets/qmainwindow.h
new file mode 100644
index 0000000..1d18c7e
--- /dev/null
+++ b/src/widgets/qmainwindow.h
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Definition of QMainWindow class
+**
+** Created : 980316
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QMAINWINDOW_H
+#define QMAINWINDOW_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qtoolbar.h"
+#include "qptrlist.h"
+#include "qtextstream.h"
+#endif // QT_H
+
+#ifndef QT_NO_MAINWINDOW
+
+class QMenuBar;
+class QStatusBar;
+class QToolTipGroup;
+class QMainWindowPrivate;
+class QMainWindowLayout;
+class QPopupMenu;
+
+class Q_EXPORT QMainWindow: public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY( bool rightJustification READ rightJustification WRITE setRightJustification DESIGNABLE false )
+ Q_PROPERTY( bool usesBigPixmaps READ usesBigPixmaps WRITE setUsesBigPixmaps )
+ Q_PROPERTY( bool usesTextLabel READ usesTextLabel WRITE setUsesTextLabel )
+ Q_PROPERTY( bool dockWindowsMovable READ dockWindowsMovable WRITE setDockWindowsMovable )
+ Q_PROPERTY( bool opaqueMoving READ opaqueMoving WRITE setOpaqueMoving )
+
+public:
+ QMainWindow( QWidget* parent=0, const char* name=0, WFlags f = WType_TopLevel );
+ ~QMainWindow();
+
+#ifndef QT_NO_MENUBAR
+ QMenuBar * menuBar() const;
+#endif
+ QStatusBar * statusBar() const;
+#ifndef QT_NO_TOOLTIP
+ QToolTipGroup * toolTipGroup() const;
+#endif
+
+ virtual void setCentralWidget( QWidget * );
+ QWidget * centralWidget() const;
+
+ virtual void setDockEnabled( Dock dock, bool enable );
+ bool isDockEnabled( Dock dock ) const;
+ bool isDockEnabled( QDockArea *area ) const;
+ virtual void setDockEnabled( QDockWindow *tb, Dock dock, bool enable );
+ bool isDockEnabled( QDockWindow *tb, Dock dock ) const;
+ bool isDockEnabled( QDockWindow *tb, QDockArea *area ) const;
+
+ virtual void addDockWindow( QDockWindow *, Dock = DockTop, bool newLine = FALSE );
+ virtual void addDockWindow( QDockWindow *, const QString &label,
+ Dock = DockTop, bool newLine = FALSE );
+ virtual void moveDockWindow( QDockWindow *, Dock = DockTop );
+ virtual void moveDockWindow( QDockWindow *, Dock, bool nl, int index, int extraOffset = -1 );
+ virtual void removeDockWindow( QDockWindow * );
+
+ void show();
+ void hide();
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ bool rightJustification() const;
+ bool usesBigPixmaps() const;
+ bool usesTextLabel() const;
+ bool dockWindowsMovable() const;
+ bool opaqueMoving() const;
+
+ bool eventFilter( QObject*, QEvent* );
+
+ bool getLocation( QDockWindow *tb, Dock &dock, int &index, bool &nl, int &extraOffset ) const;
+
+ QPtrList<QDockWindow> dockWindows( Dock dock ) const;
+ QPtrList<QDockWindow> dockWindows() const;
+ void lineUpDockWindows( bool keepNewLines = FALSE );
+
+ bool isDockMenuEnabled() const;
+
+ // compatibility stuff
+ bool hasDockWindow( QDockWindow *dw );
+#ifndef QT_NO_TOOLBAR
+ void addToolBar( QDockWindow *, Dock = DockTop, bool newLine = FALSE );
+ void addToolBar( QDockWindow *, const QString &label,
+ Dock = DockTop, bool newLine = FALSE );
+ void moveToolBar( QDockWindow *, Dock = DockTop );
+ void moveToolBar( QDockWindow *, Dock, bool nl, int index, int extraOffset = -1 );
+ void removeToolBar( QDockWindow * );
+
+ bool toolBarsMovable() const;
+ QPtrList<QToolBar> toolBars( Dock dock ) const;
+ void lineUpToolBars( bool keepNewLines = FALSE );
+#endif
+
+ virtual QDockArea *dockingArea( const QPoint &p );
+ QDockArea *leftDock() const;
+ QDockArea *rightDock() const;
+ QDockArea *topDock() const;
+ QDockArea *bottomDock() const;
+
+ virtual bool isCustomizable() const;
+
+ bool appropriate( QDockWindow *dw ) const;
+
+ enum DockWindows { OnlyToolBars, NoToolBars, AllDockWindows };
+ QPopupMenu *createDockWindowMenu( DockWindows dockWindows = AllDockWindows ) const;
+
+public slots:
+ virtual void setRightJustification( bool );
+ virtual void setUsesBigPixmaps( bool );
+ virtual void setUsesTextLabel( bool );
+ virtual void setDockWindowsMovable( bool );
+ virtual void setOpaqueMoving( bool );
+ virtual void setDockMenuEnabled( bool );
+ virtual void whatsThis();
+ virtual void setAppropriate( QDockWindow *dw, bool a );
+ virtual void customize();
+
+ // compatibility stuff
+ void setToolBarsMovable( bool );
+
+signals:
+ void pixmapSizeChanged( bool );
+ void usesTextLabelChanged( bool );
+ void dockWindowPositionChanged( QDockWindow * );
+
+#ifndef QT_NO_TOOLBAR
+ // compatibility stuff
+ void toolBarPositionChanged( QToolBar * );
+#endif
+
+protected slots:
+ virtual void setUpLayout();
+ virtual bool showDockMenu( const QPoint &globalPos );
+ void menuAboutToShow();
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void childEvent( QChildEvent * );
+ bool event( QEvent * );
+ void styleChange( QStyle& );
+
+private slots:
+ void slotPlaceChanged();
+ void doLineUp() { lineUpDockWindows( TRUE ); }
+
+private:
+ QMainWindowPrivate * d;
+ void triggerLayout( bool deleteLayout = TRUE);
+ bool dockMainWindow( QObject *dock );
+
+#ifndef QT_NO_MENUBAR
+ virtual void setMenuBar( QMenuBar * );
+#endif
+ virtual void setStatusBar( QStatusBar * );
+#ifndef QT_NO_TOOLTIP
+ virtual void setToolTipGroup( QToolTipGroup * );
+#endif
+
+ friend class QDockWindow;
+ friend class QMenuBar;
+ friend class QHideDock;
+ friend class QToolBar;
+ friend class QMainWindowLayout;
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QMainWindow( const QMainWindow & );
+ QMainWindow& operator=( const QMainWindow & );
+#endif
+};
+
+#ifndef QT_NO_TOOLBAR
+inline void QMainWindow::addToolBar( QDockWindow *w, ToolBarDock dock, bool newLine )
+{
+ addDockWindow( w, dock, newLine );
+}
+
+inline void QMainWindow::addToolBar( QDockWindow *w, const QString &label,
+ ToolBarDock dock, bool newLine )
+{
+ addDockWindow( w, label, dock, newLine );
+}
+
+inline void QMainWindow::moveToolBar( QDockWindow *w, ToolBarDock dock )
+{
+ moveDockWindow( w, dock );
+}
+
+inline void QMainWindow::moveToolBar( QDockWindow *w, ToolBarDock dock, bool nl, int index, int extraOffset )
+{
+ moveDockWindow( w, dock, nl, index, extraOffset );
+}
+
+inline void QMainWindow::removeToolBar( QDockWindow *w )
+{
+ removeDockWindow( w );
+}
+
+inline bool QMainWindow::toolBarsMovable() const
+{
+ return dockWindowsMovable();
+}
+
+inline void QMainWindow::lineUpToolBars( bool keepNewLines )
+{
+ lineUpDockWindows( keepNewLines );
+}
+
+inline void QMainWindow::setToolBarsMovable( bool b )
+{
+ setDockWindowsMovable( b );
+}
+#endif
+
+#ifndef QT_NO_TEXTSTREAM
+Q_EXPORT QTextStream &operator<<( QTextStream &, const QMainWindow & );
+Q_EXPORT QTextStream &operator>>( QTextStream &, QMainWindow & );
+#endif
+
+#endif // QT_NO_MAINWINDOW
+
+#endif // QMAINWINDOW_H
diff --git a/src/widgets/qmenubar.cpp b/src/widgets/qmenubar.cpp
new file mode 100644
index 0000000..45e0ffb
--- /dev/null
+++ b/src/widgets/qmenubar.cpp
@@ -0,0 +1,1683 @@
+/****************************************************************************
+**
+** Implementation of QMenuBar class
+**
+** Created : 941209
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+// qmainwindow.h before qmenubar.h because of GCC-2.7.* compatibility
+// ### could be reorganised by discarding INCLUDE_MENUITEM_DEF and put
+// the relevant declarations in a private header?
+#include "qmainwindow.h"
+#ifndef QT_NO_MENUBAR
+#include "qmenubar.h"
+#include "qpopupmenu.h"
+#include "qaccel.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qapplication.h"
+#include "qguardedptr.h"
+#include "qlayout.h"
+#include "qcleanuphandler.h"
+#include "../kernel/qinternal_p.h"
+#include "qstyle.h"
+#include "qtimer.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+class QMenuDataData {
+ // attention: also defined in qmenudata.cpp
+public:
+ QMenuDataData();
+ QGuardedPtr<QWidget> aWidget;
+ int aInt;
+};
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+static bool inMenu = FALSE;
+#endif
+
+#if defined(Q_WS_X11)
+extern int qt_xfocusout_grab_counter; // defined in qapplication_x11.cpp
+#endif
+
+/*!
+ \class QMenuBar qmenubar.h
+ \brief The QMenuBar class provides a horizontal menu bar.
+
+ \ingroup application
+ \mainclass
+
+ A menu bar consists of a list of pull-down menu items. You add
+ menu items with \link QMenuData::insertItem()
+ insertItem()\endlink. For example, asuming that \c menubar is a
+ pointer to a QMenuBar and \c filemenu is a pointer to a
+ QPopupMenu, the following statement inserts the menu into the menu
+ bar:
+ \code
+ menubar->insertItem( "&File", filemenu );
+ \endcode
+ 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.)
+
+ Items are either enabled or disabled. You toggle their state with
+ setItemEnabled().
+
+ 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.
+
+ \important insertItem removeItem clear insertSeparator setItemEnabled isItemEnabled setItemVisible isItemVisible
+
+ Example of creating a menu bar with menu items (from \l menu/menu.cpp):
+ \quotefile menu/menu.cpp
+ \skipto file = new QPopupMenu
+ \printline
+ \skipto Key_O
+ \printline
+ \printline
+ \skipto new QMenuBar
+ \printline
+ \skipto insertItem
+ \printline
+
+ In most main window style applications you would use the menuBar()
+ provided in QMainWindow, adding \l{QPopupMenu}s to the menu bar
+ and adding \l{QAction}s to the popup menus.
+
+ Example (from \l action/application.cpp):
+ \quotefile action/application.cpp
+ \skipto file = new QPopupMenu
+ \printuntil fileNewAction
+
+ Menu items can have text and pixmaps (or iconsets), see the
+ various \link QMenuData::insertItem() insertItem()\endlink
+ overloads, as well as separators, see \link
+ QMenuData::insertSeparator() insertSeparator()\endlink. You can
+ also add custom menu items that are derived from
+ \l{QCustomMenuItem}.
+
+ Menu items may be removed with removeItem() and enabled or
+ disabled with \link QMenuData::setItemEnabled()
+ setItemEnabled()\endlink.
+
+ <img src=qmenubar-m.png> <img src=qmenubar-w.png>
+
+ \section1 QMenuBar on Qt/Mac
+
+ QMenuBar on Qt/Mac is a wrapper for using the system-wide menubar.
+ If you have multiple menubars in one dialog the outermost menubar
+ (normally inside a widget with widget flag \c WType_TopLevel) will
+ be used for the system-wide menubar.
+
+ Note that arbitrary Qt widgets \e cannot be inserted into a
+ QMenuBar on the Mac because Qt uses Mac's native menus which don't
+ support this functionality. This limitation does not apply to
+ stand-alone QPopupMenus.
+
+ Qt/Mac also provides a menubar merging feature to make QMenuBar
+ conform more closely to accepted Mac OS X menubar layout. The
+ merging functionality is based on string matching the title of a
+ QPopupMenu 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 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
+
+ \link menu-example.html menu/menu.cpp\endlink is an example of
+ QMenuBar and QPopupMenu use.
+
+ \sa QPopupMenu QAccel QAction \link http://developer.apple.com/techpubs/macosx/Carbon/HumanInterfaceToolbox/Aqua/aqua.html Aqua Style Guidelines \endlink \link guibooks.html#fowler GUI Design Handbook: Menu Bar \endlink
+*/
+
+
+/*!
+ \enum QMenuBar::Separator
+
+ This enum type is used to decide whether QMenuBar should draw a
+ separator line at its bottom.
+
+ \value Never In many applications there is already a separator,
+ and having two looks wrong.
+
+ \value InWindowsStyle In some other applications a separator looks
+ good in Windows style, but nowhere else.
+*/
+
+/*!
+ \fn void QMenuBar::activated( int id )
+
+ This signal is emitted when a menu item is selected; \a id is the
+ id of the selected item.
+
+ Normally you will connect each menu item to a single slot using
+ QMenuData::insertItem(), 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 highlighted(), QMenuData::insertItem()
+*/
+
+/*!
+ \fn void QMenuBar::highlighted( int id )
+
+ This signal is emitted when a menu item is highlighted; \a id is
+ the id of the highlighted item.
+
+ Normally, you will connect each menu item to a single slot using
+ QMenuData::insertItem(), 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 activated(), QMenuData::insertItem()
+*/
+
+
+// Motif style parameters
+
+static const int motifBarHMargin = 2; // menu bar hor margin to item
+static const int motifBarVMargin = 1; // menu bar ver margin to item
+static const int motifItemFrame = 2; // menu item frame width
+static const int motifItemHMargin = 5; // menu item hor text margin
+static const int motifItemVMargin = 4; // menu item ver text margin
+
+// The others are 0
+static const int gtkItemHMargin = 8;
+static const int gtkItemVMargin = 8;
+
+/*
+
++-----------------------------
+| BarFrame
+| +-------------------------
+| | V BarMargin
+| | +---------------------
+| | H | ItemFrame
+| | | +-----------------
+| | | | \
+| | | | ^ T E X T ^ | ItemVMargin
+| | | | | | /
+| | | ItemHMargin
+| |
+|
+
+*/
+
+
+/*****************************************************************************
+ QMenuBar member functions
+ *****************************************************************************/
+
+
+/*!
+ Constructs a menu bar called \a name with parent \a parent.
+*/
+QMenuBar::QMenuBar( QWidget *parent, const char *name )
+ : QFrame( parent, name, WNoAutoErase )
+{
+#if defined( Q_WS_MAC ) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ mac_eaten_menubar = FALSE;
+ mac_d = 0;
+ macCreateNativeMenubar();
+#endif
+ isMenuBar = TRUE;
+#ifndef QT_NO_ACCEL
+ autoaccel = 0;
+#endif
+ irects = 0;
+ rightSide = 0; // Right of here is rigth-aligned content
+ mseparator = 0;
+ waitforalt = 0;
+ popupvisible = 0;
+ hasmouse = 0;
+ defaultup = 0;
+ toggleclose = 0;
+ pendingDelayedContentsChanges = 0;
+ pendingDelayedStateChanges = 0;
+ if ( parent ) {
+ // filter parent events for resizing
+ parent->installEventFilter( this );
+
+ // filter top-level-widget events for accelerators
+ QWidget *tlw = topLevelWidget();
+ if ( tlw != parent )
+ tlw->installEventFilter( this );
+ }
+ installEventFilter( this );
+
+ setBackgroundMode( PaletteButton );
+ setFrameStyle( QFrame::MenuBarPanel | QFrame::Raised );
+
+ QFontMetrics fm = fontMetrics();
+
+ int h;
+ int gs = style().styleHint(QStyle::SH_GUIStyle);
+ if (gs == GtkStyle) {
+ h = fm.height() + gtkItemVMargin;
+ } else {
+ h = 2*motifBarVMargin + fm.height() + motifItemVMargin + 2*frameWidth() + 2*motifItemFrame;
+ }
+
+ setGeometry( 0, 0, width(), h );
+
+ setMouseTracking( style().styleHint(QStyle::SH_MenuBar_MouseTracking) );
+}
+
+
+
+/*! \reimp */
+
+void QMenuBar::styleChange( QStyle& old )
+{
+ setMouseTracking( style().styleHint(QStyle::SH_MenuBar_MouseTracking) );
+ QFrame::styleChange( old );
+}
+
+
+
+/*!
+ Destroys the menu bar.
+*/
+
+QMenuBar::~QMenuBar()
+{
+#ifndef QT_NO_ACCEL
+ delete autoaccel;
+#endif
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ macRemoveNativeMenubar();
+#endif
+ if ( irects ) // Avoid purify complaint.
+ delete [] irects;
+}
+
+/*!
+ \internal
+
+ Repaints the menu item with id \a id; does nothing if there is no
+ such menu item.
+*/
+void QMenuBar::updateItem( int id )
+{
+ int i = indexOf( id );
+ if ( i >= 0 && irects )
+ repaint( irects[i], FALSE );
+}
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+static bool fromFrameChange = FALSE;
+#endif
+
+/*!
+ Recomputes the menu bar's display data according to the new
+ contents.
+
+ You should never need to call this; it is called automatically by
+ QMenuData whenever it needs to be called.
+*/
+
+void QMenuBar::menuContentsChanged()
+{
+ // here the part that can't be delayed
+ QMenuData::menuContentsChanged();
+ badSize = TRUE; // might change the size
+ if( pendingDelayedContentsChanges )
+ return;
+ pendingDelayedContentsChanges = 1;
+ if( !pendingDelayedStateChanges )// if the timer hasn't been started yet
+ QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
+}
+
+void QMenuBar::performDelayedContentsChanged()
+{
+ pendingDelayedContentsChanges = 0;
+ // here the part the can be delayed
+#ifndef QT_NO_ACCEL
+ // if performDelayedStateChanged() will be called too,
+ // it will call setupAccelerators() too, no need to do it twice
+ if( !pendingDelayedStateChanges )
+ setupAccelerators();
+#endif
+ calculateRects();
+ if ( isVisible() ) {
+ update();
+#ifndef QT_NO_MAINWINDOW
+ QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
+ if ( mw ) {
+ mw->triggerLayout();
+ mw->update();
+ }
+#endif
+#ifndef QT_NO_LAYOUT
+ if ( parentWidget() && parentWidget()->layout() )
+ parentWidget()->layout()->activate();
+#endif
+ }
+}
+
+/*!
+ Recomputes the menu bar's display data according to the new state.
+
+ You should never need to call this; it is called automatically by
+ QMenuData whenever it needs to be called.
+*/
+
+void QMenuBar::menuStateChanged()
+{
+ if( pendingDelayedStateChanges )
+ return;
+ pendingDelayedStateChanges = 1;
+ if( !pendingDelayedContentsChanges ) // if the timer hasn't been started yet
+ QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
+}
+
+void QMenuBar::performDelayedStateChanged()
+{
+ pendingDelayedStateChanges = 0;
+ // here the part that can be delayed
+#ifndef QT_NO_ACCEL
+ setupAccelerators(); // ### when we have a good solution for the accel vs. focus
+ // widget problem, remove that. That is only a workaround
+ // if you remove this, see performDelayedContentsChanged()
+#endif
+ update();
+}
+
+
+void QMenuBar::performDelayedChanges()
+{
+#if defined(Q_WS_MAC) && !defined(QMAC_MENUBAR_NO_NATIVE)
+ // I must do this here as the values change in the function below.
+ bool needMacUpdate = (pendingDelayedContentsChanges || pendingDelayedStateChanges);
+#endif
+ if( pendingDelayedContentsChanges )
+ performDelayedContentsChanged();
+ if( pendingDelayedStateChanges )
+ performDelayedStateChanged();
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if(mac_eaten_menubar && needMacUpdate) {
+ macDirtyNativeMenubar();
+
+ bool all_hidden = TRUE;
+ if(irects) {
+ for(int i = 0; all_hidden && i < (int)mitems->count(); i++)
+ all_hidden = irects[i].isEmpty();
+ }
+ if( all_hidden ) {
+ if( !isHidden())
+ hide();
+ } else {
+ if( !isShown() && !fromFrameChange )
+ show();
+ }
+ }
+#endif
+}
+
+
+void QMenuBar::menuInsPopup( QPopupMenu *popup )
+{
+ connect( popup, SIGNAL(activatedRedirect(int)),
+ SLOT(subActivated(int)) );
+ connect( popup, SIGNAL(highlightedRedirect(int)),
+ SLOT(subHighlighted(int)) );
+ connect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+}
+
+void QMenuBar::menuDelPopup( QPopupMenu *popup )
+{
+ popup->disconnect( SIGNAL(activatedRedirect(int)) );
+ popup->disconnect( SIGNAL(highlightedRedirect(int)) );
+ disconnect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+}
+
+void QMenuBar::frameChanged()
+{
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ fromFrameChange = TRUE;
+#endif
+ menuContentsChanged();
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ fromFrameChange = FALSE;
+#endif
+}
+
+void QMenuBar::languageChange()
+{
+ menuContentsChanged();
+}
+
+/*!
+ \internal
+
+ This function is used to adjust the menu bar's geometry to the
+ parent widget's geometry. Note that this is \e not part of the
+ public interface - the function is \c public only because
+ QObject::eventFilter() is.
+
+ Resizes the menu bar to fit in the parent widget when the parent
+ receives a resize event.
+*/
+
+bool QMenuBar::eventFilter( QObject *object, QEvent *event )
+{
+ if ( object == parent() && object
+#ifndef QT_NO_TOOLBAR
+ && !::qt_cast<QToolBar*>(object)
+#endif
+ && event->type() == QEvent::Resize ) {
+ QResizeEvent *e = (QResizeEvent *)event;
+ int w = e->size().width();
+ setGeometry( 0, y(), w, heightForWidth(w) );
+ return FALSE;
+ }
+
+ if ( !isVisible() || !object->isWidgetType() )
+ return FALSE;
+
+ if ( object == this && event->type() == QEvent::LanguageChange ) {
+ badSize = TRUE;
+ calculateRects();
+ return FALSE;
+ } else if ( event->type() == QEvent::MouseButtonPress ||
+ event->type() == QEvent::MouseButtonRelease ) {
+ waitforalt = 0;
+ return FALSE;
+ } else if ( waitforalt && event->type() == QEvent::FocusOut ) {
+ // some window systems/managers use alt/meta as accelerator keys
+ // for switching between windows/desktops/etc. If the focus
+ // widget gets unfocused, then we need to stop waiting for alt
+ // NOTE: this event came from the real focus widget, so we don't
+ // need to touch the event filters
+ waitforalt = 0;
+ // although the comment above said not to remove the event filter, it is
+ // incorrect. We need to remove our self fom the focused widget as normally
+ // this happens in the key release but it does not happen in this case
+ QWidget * f = ((QWidget *)object)->focusWidget();
+ if (f)
+ f->removeEventFilter( this );
+ return FALSE;
+ } else if ( !( event->type() == QEvent::Accel ||
+ event->type() == QEvent::AccelOverride ||
+ event->type() == QEvent::KeyPress ||
+ event->type() == QEvent::KeyRelease ) ||
+ !style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) ) {
+ return FALSE;
+ }
+
+ QKeyEvent * ke = (QKeyEvent *) event;
+#ifndef QT_NO_ACCEL
+ // look for Alt press and Alt-anything press
+ if ( event->type() == QEvent::Accel ) {
+ QWidget * f = ((QWidget *)object)->focusWidget();
+ // ### this thinks alt and meta are the same
+ if ( ke->key() == Key_Alt || ke->key() == Key_Meta ) {
+ // A new Alt press and we wait for release, eat
+ // this key and don't wait for Alt on this widget
+ if ( waitforalt ) {
+ waitforalt = 0;
+ if ( object->parent() )
+ object->removeEventFilter( this );
+ ke->accept();
+ return TRUE;
+ // Menu has focus, send focus back
+ } else if ( hasFocus() ) {
+ setAltMode( FALSE );
+ ke->accept();
+ return TRUE;
+ // Start waiting for Alt release on focus widget
+ } else if ( ke->stateAfter() == AltButton ) {
+ waitforalt = 1;
+#if defined(Q_WS_X11)
+ QMenuData::d->aInt = qt_xfocusout_grab_counter;
+#endif
+ if ( f && f != object )
+ f->installEventFilter( this );
+ }
+ // Other modifiers kills focus on menubar
+ } else if ( ke->key() == Key_Control || ke->key() == Key_Shift) {
+ setAltMode( FALSE );
+ // Got other key, no need to wait for Alt release
+ } else {
+ waitforalt = 0;
+ }
+ // ### ! block all accelerator events when the menu bar is active
+ if ( qApp && qApp->focusWidget() == this ) {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+#endif
+ // look for Alt release
+ if ( ((QWidget*)object)->focusWidget() == object ||
+ (object->parent() == 0 && ((QWidget*)object)->focusWidget() == 0) ) {
+ if ( waitforalt && event->type() == QEvent::KeyRelease &&
+ ( ke->key() == Key_Alt || ke->key() == Key_Meta )
+#if defined(Q_WS_X11)
+ && QMenuData::d->aInt == qt_xfocusout_grab_counter
+#endif
+ ) {
+ setAltMode( TRUE );
+ if ( object->parent() )
+ object->removeEventFilter( this );
+ QWidget * tlw = ((QWidget *)object)->topLevelWidget();
+ if ( tlw ) {
+ // ### !
+ // make sure to be the first event filter, so we can kill
+ // accelerator events before the accelerators get to them.
+ tlw->removeEventFilter( this );
+ tlw->installEventFilter( this );
+ }
+ return TRUE;
+ // Cancel if next keypress is NOT Alt/Meta,
+ } else if ( !hasFocus() && (event->type() == QEvent::AccelOverride ) &&
+ !(((QKeyEvent *)event)->key() == Key_Alt ||
+ ((QKeyEvent *)event)->key() == Key_Meta) ) {
+ if ( object->parent() )
+ object->removeEventFilter( this );
+ setAltMode( FALSE );
+ }
+ }
+
+ return FALSE; // don't stop event
+}
+
+
+
+/*!
+ \internal
+ Receives signals from menu items.
+*/
+
+void QMenuBar::subActivated( int id )
+{
+ emit activated( id );
+}
+
+/*!
+ \internal
+ Receives signals from menu items.
+*/
+
+void QMenuBar::subHighlighted( int id )
+{
+ emit highlighted( id );
+}
+
+/*!
+ \internal
+ Receives signals from menu accelerator.
+*/
+#ifndef QT_NO_ACCEL
+void QMenuBar::accelActivated( int id )
+{
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if(mac_eaten_menubar)
+ return;
+#endif
+ if ( !isEnabled() ) // the menu bar is disabled
+ return;
+ setAltMode( TRUE );
+ setActiveItem( indexOf( id ) );
+}
+#endif
+
+/*!
+ \internal
+ This slot receives signals from menu accelerator when it is about to be
+ destroyed.
+*/
+#ifndef QT_NO_ACCEL
+void QMenuBar::accelDestroyed()
+{
+ autoaccel = 0; // don't delete it twice!
+}
+#endif
+
+void QMenuBar::popupDestroyed( QObject *o )
+{
+ removePopup( (QPopupMenu*)o );
+}
+
+bool QMenuBar::tryMouseEvent( QPopupMenu *, QMouseEvent *e )
+{
+ QPoint pos = mapFromGlobal( e->globalPos() );
+ if ( !rect().contains( pos ) ) // outside
+ return FALSE;
+ int item = itemAtPos( pos );
+ if ( item == -1 && (e->type() == QEvent::MouseButtonPress ||
+ e->type() == QEvent::MouseButtonRelease) ) {
+ hidePopups();
+ goodbye();
+ return FALSE;
+ }
+ QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
+ event( &ee );
+ return TRUE;
+}
+
+
+void QMenuBar::tryKeyEvent( QPopupMenu *, QKeyEvent *e )
+{
+ event( e );
+}
+
+
+void QMenuBar::goodbye( bool cancelled )
+{
+ mouseBtDn = FALSE;
+ popupvisible = 0;
+ setAltMode( cancelled && style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) );
+}
+
+
+void QMenuBar::openActPopup()
+{
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( !inMenu ) {
+ QAccessible::updateAccessibility( this, 0, QAccessible::MenuStart );
+ inMenu = TRUE;
+ }
+#endif
+
+ if ( actItem < 0 )
+ return;
+ QPopupMenu *popup = mitems->at(actItem)->popup();
+ if ( !popup || !popup->isEnabled() )
+ return;
+
+ QRect r = itemRect( actItem );
+ bool reverse = QApplication::reverseLayout();
+ const int yoffset = 1; //(style().styleHint( QStyle::SH_GUIStyle ) == QStyle::WindowsStyle) ? 4 : 1; ### this breaks designer mainwindow editing
+ QPoint pos = r.bottomLeft() + QPoint(0,yoffset);
+ if( reverse ) {
+ pos = r.bottomRight() + QPoint(0,yoffset);
+ pos.rx() -= popup->sizeHint().width();
+ }
+
+ int ph = popup->sizeHint().height();
+ pos = mapToGlobal(pos);
+ int sh = QApplication::desktop()->height();
+ if ( defaultup || (pos.y() + ph > sh) ) {
+ QPoint t = mapToGlobal( r.topLeft() );
+ if( reverse ) {
+ t = mapToGlobal( r.topRight() );
+ t.rx() -= popup->sizeHint().width();
+ }
+ t.ry() -= (QCOORD)ph;
+ if ( !defaultup || t.y() >= 0 )
+ pos = t;
+ }
+
+ //avoid circularity
+ if ( popup->isVisible() )
+ return;
+
+ Q_ASSERT( popup->parentMenu == 0 );
+ popup->parentMenu = this; // set parent menu
+
+ popup->snapToMouse = FALSE;
+ popup->popup( pos );
+ popup->snapToMouse = TRUE;
+}
+
+/*!
+ \internal
+ Hides all popup menu items.
+*/
+
+void QMenuBar::hidePopups()
+{
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ bool anyVisible = FALSE;
+#endif
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( mi->popup() && mi->popup()->isVisible() ) {
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ anyVisible = TRUE;
+#endif
+ mi->popup()->hide();
+ }
+ }
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( !popupvisible && anyVisible && inMenu ) {
+ QAccessible::updateAccessibility( this, 0, QAccessible::MenuEnd );
+ inMenu = FALSE;
+ }
+#endif
+}
+
+
+/*!
+ Reimplements QWidget::show() in order to set up the correct
+ keyboard accelerators and to raise itself to the top of the widget
+ stack.
+*/
+
+void QMenuBar::show()
+{
+#ifndef QT_NO_ACCEL
+ setupAccelerators();
+#endif
+
+ if ( parentWidget() )
+ resize( parentWidget()->width(), height() );
+
+ QApplication::sendPostedEvents( this, QEvent::Resize );
+ performDelayedChanges();
+ calculateRects();
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if(mac_eaten_menubar) {
+ //If all elements are invisible no reason for me to be visible either
+ bool all_hidden = TRUE;
+ if(irects) {
+ for(int i = 0; all_hidden && i < (int)mitems->count(); i++)
+ all_hidden = irects[i].isEmpty();
+ }
+ if(all_hidden)
+ QWidget::hide();
+ else
+ QWidget::show();
+ } else {
+ QWidget::show();
+ }
+#else
+ QWidget::show();
+#endif
+
+#ifndef QT_NO_MAINWINDOW
+ QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
+ if ( mw ) //### ugly workaround
+ mw->triggerLayout();
+#endif
+ raise();
+}
+
+/*!
+ Reimplements QWidget::hide() in order to deselect any selected
+ item, and calls setUpLayout() for the main window.
+*/
+
+void QMenuBar::hide()
+{
+ QWidget::hide();
+ setAltMode( FALSE );
+ hidePopups();
+#ifndef QT_NO_MAINWINDOW
+ QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
+ if ( mw ) //### ugly workaround
+ mw->triggerLayout();
+#endif
+}
+
+/*!
+ \internal
+ Needs to change the size of the menu bar when a new font is set.
+*/
+
+void QMenuBar::fontChange( const QFont & f )
+{
+ badSize = TRUE;
+ updateGeometry();
+ if ( isVisible() )
+ calculateRects();
+ QWidget::fontChange( f );
+}
+
+
+/*****************************************************************************
+ Item geometry functions
+ *****************************************************************************/
+
+/*
+ This function serves two different purposes. If the parameter is
+ negative, it updates the irects member for the current width and
+ resizes. Otherwise, it does the same calculations for the GIVEN
+ width and returns the height to which it WOULD have resized. A bit
+ tricky, but both operations require almost identical steps.
+*/
+int QMenuBar::calculateRects( int max_width )
+{
+ polish();
+ bool update = ( max_width < 0 );
+
+ if ( update ) {
+ rightSide = 0;
+ if ( !badSize ) // size was not changed
+ return 0;
+ delete [] irects;
+ int i = mitems->count();
+ if ( i == 0 ) {
+ irects = 0;
+ } else {
+ irects = new QRect[ i ];
+ Q_CHECK_PTR( irects );
+ }
+ max_width = width();
+ }
+ QFontMetrics fm = fontMetrics();
+ int max_height = 0;
+ int max_item_height = 0;
+ int nlitems = 0; // number on items on cur line
+ int gs = style().styleHint(QStyle::SH_GUIStyle);
+ bool reverse = QApplication::reverseLayout();
+ int x = frameWidth();
+ int y = frameWidth();
+ if ( gs == MotifStyle ) {
+ x += motifBarHMargin;
+ y += motifBarVMargin;
+ } else if ( style().inherits("QWindowsXPStyle") && style().styleHint(QStyle::SH_TitleBar_NoBorder) ) {
+ ;
+ } else if ( gs == WindowsStyle ) {
+ x += 2;
+ y += 2;
+ }
+ if ( reverse )
+ x = max_width - x;
+
+ int i = 0;
+ int separator = -1;
+ const int itemSpacing = style().pixelMetric(QStyle::PM_MenuBarItemSpacing);
+ const int lastItem = reverse ? 0 : mitems->count() - 1;
+
+ while ( i < (int)mitems->count() ) { // for each menu item...
+ QMenuItem *mi = mitems->at(i);
+
+ int w=0, h=0;
+ if ( !mi->isVisible()
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ || (mac_eaten_menubar && !mi->custom() && !mi->widget() )
+#endif
+ ) {
+ ; // empty rectangle
+ } else if ( mi->widget() ) {
+ if ( mi->widget()->parentWidget() != this ) {
+ mi->widget()->reparent( this, QPoint(0,0) );
+ }
+ w = mi->widget()->sizeHint().expandedTo( QApplication::globalStrut() ).width()+2;
+ h = mi->widget()->sizeHint().expandedTo( QApplication::globalStrut() ).height()+2;
+ if ( i && separator < 0 )
+ separator = i;
+ } else if ( mi->pixmap() ) { // pixmap item
+ w = QMAX( mi->pixmap()->width() + 4, QApplication::globalStrut().width() );
+ h = QMAX( mi->pixmap()->height() + 4, QApplication::globalStrut().height() );
+ } else if ( !mi->text().isNull() ) { // text item
+ QString s = mi->text();
+ if ( gs == GtkStyle ) {
+ w = fm.boundingRect( s ).width() + 2*gtkItemHMargin;
+ } else {
+ w = fm.boundingRect( s ).width() + 2*motifItemHMargin;
+ }
+ w -= s.contains('&')*fm.width('&');
+ w += s.contains("&&")*fm.width('&');
+ w = QMAX( w, QApplication::globalStrut().width() );
+ if (gs == GtkStyle ) {
+ h = QMAX( fm.height() + gtkItemVMargin, QApplication::globalStrut().height() );
+ } else {
+ h = QMAX( fm.height() + motifItemVMargin, QApplication::globalStrut().height() );
+ }
+ } else if ( mi->isSeparator() ) { // separator item
+ if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle )
+ separator = i; //### only motif?
+ }
+ if ( !mi->isSeparator() || mi->widget() ) {
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if ( !mac_eaten_menubar ) {
+#endif
+ if ( gs == MotifStyle && mi->isVisible() ) {
+ w += 2*motifItemFrame;
+ h += 2*motifItemFrame;
+ }
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ }
+#endif
+
+ if ( ( ( !reverse && x + w + frameWidth() - max_width > 0 ) ||
+ ( reverse && x - w - itemSpacing - frameWidth() < 0 ) )
+ && nlitems > 0 ) {
+ nlitems = 0;
+ x = frameWidth();
+ y += h;
+ if ( gs == MotifStyle ) {
+ x += motifBarHMargin;
+ y += motifBarVMargin;
+ }
+ if ( reverse )
+ x = max_width - x + itemSpacing;
+ if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle )
+ separator = -1;
+ }
+ if ( y + h + 2*frameWidth() > max_height )
+ max_height = y + h + 2*frameWidth();
+ if ( h > max_item_height )
+ max_item_height = h;
+ }
+
+ const bool isLast = (i == lastItem);
+
+ if( reverse ) {
+ x -= w;
+ if (!isLast && !mi->isSeparator())
+ x -= itemSpacing;
+ }
+ if ( update ) {
+ irects[i].setRect( x, y, w, h );
+ }
+ if ( !reverse ) {
+ x += w;
+ if (!isLast && !mi->isSeparator())
+ x += itemSpacing;
+ }
+ nlitems++;
+ i++;
+ }
+ if ( gs == WindowsStyle ) {
+ max_height += 2;
+ max_width += 2;
+ }
+
+ if ( update ) {
+ if ( separator >= 0 ) {
+ int moveBy = reverse ? - x - frameWidth() : max_width - x - frameWidth();
+ rightSide = x;
+ while( --i >= separator ) {
+ irects[i].moveBy( moveBy, 0 );
+ }
+ } else {
+ rightSide = width()-frameWidth();
+ }
+ if ( max_height != height() )
+ resize( width(), max_height );
+ for ( i = 0; i < (int)mitems->count(); i++ ) {
+ irects[i].setHeight( max_item_height );
+ QMenuItem *mi = mitems->at(i);
+ if ( mi->widget() ) {
+ QRect r ( QPoint(0,0), mi->widget()->sizeHint() );
+ r.moveCenter( irects[i].center() );
+ mi->widget()->setGeometry( r );
+ if( mi->widget()->isHidden() )
+ mi->widget()->show();
+ }
+ }
+ badSize = FALSE;
+ }
+
+ return max_height;
+}
+
+/*!
+ Returns the height that the menu would resize itself to if its
+ parent (and hence itself) resized to the given \a max_width. This
+ can be useful for simple layout tasks in which the height of the
+ menu bar is needed after items have been inserted. See \l
+ showimg/showimg.cpp for an example of the usage.
+*/
+int QMenuBar::heightForWidth(int max_width) const
+{
+ // Okay to cast away const, as we are not updating.
+ if ( max_width < 0 ) max_width = 0;
+ return ((QMenuBar*)this)->calculateRects( max_width );
+}
+
+/*!
+ \internal
+ Return the bounding rectangle for the menu item at position \a index.
+*/
+
+QRect QMenuBar::itemRect( int index )
+{
+ calculateRects();
+ return irects ? irects[index] : QRect(0,0,0,0);
+}
+
+/*!
+ \internal
+ Return the item at \a pos, or -1 if there is no item there or if
+ it is a separator item.
+*/
+
+int QMenuBar::itemAtPos( const QPoint &pos_ )
+{
+ calculateRects();
+ if ( !irects )
+ return -1;
+ int i = 0;
+ QPoint pos = pos_;
+ // Fitts' Law for edges - compensate for the extra margin
+ // added in calculateRects()
+ const int margin = 2;
+ pos.setX( QMAX( margin, QMIN( width() - margin, pos.x())));
+ pos.setY( QMAX( margin, QMIN( height() - margin, pos.y())));
+ while ( i < (int)mitems->count() ) {
+ if ( !irects[i].isEmpty() && irects[i].contains( pos ) ) {
+ QMenuItem *mi = mitems->at(i);
+ return mi->isSeparator() ? -1 : i;
+ }
+ ++i;
+ }
+ return -1; // no match
+}
+
+
+/*!
+ \property QMenuBar::separator
+ \brief in which cases a menubar sparator is drawn
+
+ \obsolete
+*/
+void QMenuBar::setSeparator( Separator when )
+{
+ mseparator = when;
+}
+
+QMenuBar::Separator QMenuBar::separator() const
+{
+ return mseparator ? InWindowsStyle : Never;
+}
+
+/*****************************************************************************
+ Event handlers
+ *****************************************************************************/
+
+/*!
+ Called from QFrame::paintEvent(). Draws the menu bar contents
+ using painter \a p.
+*/
+
+void QMenuBar::drawContents( QPainter *p )
+{
+ performDelayedChanges();
+ QRegion reg( contentsRect() );
+ QColorGroup g = colorGroup();
+ bool e;
+
+ // this shouldn't happen
+ if ( !irects )
+ return;
+
+ for ( int i=0; i<(int)mitems->count(); i++ ) {
+ QMenuItem *mi = mitems->at( i );
+ if ( !mi->text().isNull() || mi->pixmap() ) {
+ QRect r = irects[i];
+ if(r.isEmpty() || !mi->isVisible())
+ continue;
+ e = mi->isEnabledAndVisible();
+ if ( e )
+ g = isEnabled() ? ( isActiveWindow() ? palette().active() :
+ palette().inactive() ) : palette().disabled();
+ else
+ g = palette().disabled();
+ reg = reg.subtract( r );
+ QSharedDoubleBuffer buffer( p, r );
+ buffer.painter()->setFont( p->font() );
+ buffer.painter()->setPen( p->pen() );
+ buffer.painter()->setBrush( p->brush() );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled() && e)
+ flags |= QStyle::Style_Enabled;
+ if ( i == actItem )
+ flags |= QStyle::Style_Active;
+ if ( actItemDown )
+ flags |= QStyle::Style_Down;
+ if (hasFocus() || hasmouse || popupvisible)
+ flags |= QStyle::Style_HasFocus;
+ style().drawControl(QStyle::CE_MenuBarItem, buffer.painter(), this,
+ r, g, flags, QStyleOption(mi));
+ }
+ }
+
+ p->save();
+ p->setClipRegion(reg);
+ style().drawControl(QStyle::CE_MenuBarEmptyArea, p, this, contentsRect(), g);
+ p->restore();
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if ( !mac_eaten_menubar )
+#endif
+ {
+ Qt::GUIStyle gs = (Qt::GUIStyle) style().styleHint(QStyle::SH_GUIStyle);
+ if ( mseparator == InWindowsStyle && gs == WindowsStyle ) {
+ p->setPen( g.light() );
+ p->drawLine( 0, height()-1, width()-1, height()-1 );
+ p->setPen( g.dark() );
+ p->drawLine( 0, height()-2, width()-1, height()-2 );
+ }
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QMenuBar::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+ mouseBtDn = TRUE; // mouse button down
+ int item = itemAtPos( e->pos() );
+ if ( item == actItem && popupvisible )
+ toggleclose = 1;
+ if ( item >= 0 ) {
+ QFocusEvent::Reason oldReason = QFocusEvent::reason();
+ QMenuItem *mi = findItem( idAt( item ) );
+ // we know that a popup will open, so set the reason to avoid
+ // itemviews to redraw their selections
+ if ( mi && mi->popup() )
+ QFocusEvent::setReason( QFocusEvent::Popup );
+ setAltMode( TRUE );
+ QFocusEvent::setReason( oldReason );
+ }
+ setActiveItem( item, TRUE, FALSE );
+}
+
+
+/*!
+ \reimp
+*/
+void QMenuBar::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+ if ( !mouseBtDn )
+ return;
+ mouseBtDn = FALSE; // mouse button up
+ int item = itemAtPos( e->pos() );
+ if ( item >= 0 && !mitems->at(item)->isEnabledAndVisible() ||
+ actItem >= 0 && !mitems->at(actItem)->isEnabledAndVisible() ) {
+ hidePopups();
+ setActiveItem( -1 );
+ return;
+ }
+ bool showMenu = TRUE;
+ if ( toggleclose &&
+ // pressing an item twice closes in windows, but not in motif :/
+ style().styleHint(QStyle::SH_GUIStyle) == WindowsStyle &&
+ actItem == item ) {
+ showMenu = FALSE;
+ setAltMode( FALSE );
+ }
+ setActiveItem( item, showMenu, !hasMouseTracking() );
+ toggleclose = 0;
+}
+
+
+/*!
+ \reimp
+*/
+void QMenuBar::mouseMoveEvent( QMouseEvent *e )
+{
+ int item = itemAtPos( e->pos() );
+ if ( !mouseBtDn && !popupvisible) {
+ if ( item >= 0 ) {
+ if ( !hasmouse ) {
+ hasmouse = 1;
+ if ( actItem == item )
+ actItem = -1; // trigger update
+ }
+ }
+ setActiveItem( item, FALSE, FALSE );
+ return;
+ }
+ if ( item != actItem && item >= 0 && ( popupvisible || mouseBtDn ) )
+ setActiveItem( item, TRUE, FALSE );
+}
+
+
+/*!
+ \reimp
+*/
+void QMenuBar::leaveEvent( QEvent * e )
+{
+ hasmouse = 0;
+ int actId = idAt( actItem );
+ if ( !hasFocus() && !popupvisible )
+ actItem = -1;
+ updateItem( actId );
+ QFrame::leaveEvent( e );
+}
+
+
+/*!
+ \reimp
+*/
+void QMenuBar::keyPressEvent( QKeyEvent *e )
+{
+ if ( actItem < 0 )
+ return;
+
+ QMenuItem *mi = 0;
+ int dx = 0;
+
+ if ( e->state() & Qt::ControlButton &&
+ ( e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab ) )
+ {
+ e->ignore();
+ return;
+ }
+
+ switch ( e->key() ) {
+ case Key_Left:
+ dx = QApplication::reverseLayout() ? 1 : -1;
+ break;
+
+ case Key_Right:
+ case Key_Tab:
+ dx = QApplication::reverseLayout() ? -1 : 1;
+ break;
+
+ case Key_Up:
+ case Key_Down:
+ case Key_Enter:
+ case Key_Return:
+ if ( style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation) )
+ setActiveItem( actItem );
+ break;
+
+ case Key_Escape:
+ setAltMode( FALSE );
+ break;
+ }
+
+ if ( dx ) { // highlight next/prev
+ register int i = actItem;
+ int c = mitems->count();
+ int n = c;
+ while ( n-- ) {
+ i = i + dx;
+ if ( i == c )
+ i = 0;
+ else if ( i < 0 )
+ i = c - 1;
+ mi = mitems->at( i );
+ // ### fix windows-style traversal - currently broken due to
+ // QMenuBar's reliance on QPopupMenu
+ if ( /* (style() == WindowsStyle || */ mi->isEnabledAndVisible() /* ) */
+ && !mi->isSeparator() )
+ break;
+ }
+ setActiveItem( i, popupvisible );
+ } else if ( ( !e->state() || (e->state()&(MetaButton|AltButton)) ) && e->text().length()==1 && !popupvisible ) {
+ QChar c = e->text()[0].upper();
+
+ QMenuItemListIt it(*mitems);
+ QMenuItem* first = 0;
+ QMenuItem* currentSelected = 0;
+ QMenuItem* firstAfterCurrent = 0;
+
+ register QMenuItem *m;
+ int indx = 0;
+ int clashCount = 0;
+ while ( (m=it.current()) ) {
+ ++it;
+ QString s = m->text();
+ if ( !s.isEmpty() ) {
+ int i = s.find( '&' );
+ if ( i >= 0 )
+ {
+ if ( s[i+1].upper() == c ) {
+ clashCount++;
+ if ( !first )
+ first = m;
+ if ( indx == actItem )
+ currentSelected = m;
+ else if ( !firstAfterCurrent && currentSelected )
+ firstAfterCurrent = m;
+ }
+ }
+ }
+ indx++;
+ }
+ if ( 0 == clashCount ) {
+ return;
+ } else if ( 1 == clashCount ) {
+ indx = indexOf( first->id() );
+ } else {
+ // If there's clashes and no one is selected, use first one
+ // or if there is no clashes _after_ current, use first one
+ if ( !currentSelected || (currentSelected && !firstAfterCurrent))
+ indx = indexOf( first->id() );
+ else
+ indx = indexOf( firstAfterCurrent->id() );
+ }
+
+ setActiveItem( indx );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QMenuBar::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+ if ( badSize )
+ return;
+ badSize = TRUE;
+ calculateRects();
+}
+
+/*
+ Sets actItem to \a i and calls repaint for the changed things.
+
+ Takes care to optimize the repainting. Assumes that
+ calculateRects() has been called as appropriate.
+*/
+
+void QMenuBar::setActiveItem( int i, bool show, bool activate_first_item )
+{
+ if ( i == actItem && (uint)show == popupvisible )
+ return;
+
+ QMenuItem* mi = 0;
+ if ( i >= 0 )
+ mi = mitems->at( i );
+ if ( mi && !mi->isEnabledAndVisible() )
+ return;
+
+ popupvisible = i >= 0 ? (show) : 0;
+ actItemDown = popupvisible;
+
+ if ( i < 0 || actItem < 0 ) {
+ // just one item needs repainting
+ int n = QMAX( actItem, i );
+ actItem = i;
+ if ( irects && n >= 0 )
+ repaint( irects[n], FALSE );
+ } else if ( QABS(i-actItem) == 1 ) {
+ // two neighbouring items need repainting
+ int o = actItem;
+ actItem = i;
+ if ( irects )
+ repaint( irects[i].unite( irects[o] ), FALSE );
+ } else {
+ // two non-neighbouring items need repainting
+ int o = actItem;
+ actItem = i;
+ if ( irects ) {
+ repaint( irects[o], FALSE );
+ repaint( irects[i], FALSE );
+ }
+ }
+
+ hidePopups();
+
+ if ( !popupvisible && actItem >= 0 && irects ) {
+ QRect mfrect = irects[actItem];
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+ }
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( mi )
+ QAccessible::updateAccessibility( this, indexOf( mi->id() )+1, QAccessible::Focus );
+#endif
+
+ if ( actItem < 0 || !popupvisible || !mi )
+ return;
+
+ QPopupMenu *popup = mi->popup();
+ if ( popup ) {
+ emit highlighted( mi->id() );
+ openActPopup();
+ if ( activate_first_item )
+ popup->setFirstItemActive();
+ } else { // not a popup
+ goodbye( FALSE );
+ if ( mi->signal() ) // activate signal
+ mi->signal()->activate();
+ emit activated( mi->id() );
+ }
+}
+
+
+void QMenuBar::setAltMode( bool enable )
+{
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( inMenu && !enable ) {
+ QAccessible::updateAccessibility( this, 0, QAccessible::MenuEnd );
+ inMenu = FALSE;
+ } else if ( !inMenu && enable ) {
+ QAccessible::updateAccessibility( this, 0, QAccessible::MenuStart );
+ inMenu = TRUE;
+ }
+#endif
+
+ waitforalt = 0;
+ actItemDown = FALSE;
+ if ( enable ) {
+ if ( !QMenuData::d->aWidget )
+ QMenuData::d->aWidget = qApp->focusWidget();
+ setFocus();
+ updateItem( idAt( actItem ) );
+ } else {
+ // set the focus back to the previous widget if
+ // we still have the focus.
+ if ( qApp->focusWidget() == this ) {
+ if ( QMenuData::d->aWidget )
+ QMenuData::d->aWidget->setFocus();
+ else
+ clearFocus();
+ }
+ int actId = idAt( actItem );
+ actItem = -1;
+ updateItem( actId );
+ QMenuData::d->aWidget = 0;
+ }
+}
+
+/*!
+ Sets up keyboard accelerators for the menu bar.
+*/
+#ifndef QT_NO_ACCEL
+
+void QMenuBar::setupAccelerators()
+{
+ delete autoaccel;
+ autoaccel = 0;
+
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( !mi->isEnabledAndVisible() ) // ### when we have a good solution for the accel vs. focus widget problem, remove that. That is only a workaround
+ continue;
+ QString s = mi->text();
+ if ( !s.isEmpty() ) {
+ int i = QAccel::shortcutKey( s );
+ if ( i ) {
+ if ( !autoaccel ) {
+ autoaccel = new QAccel( this );
+ Q_CHECK_PTR( autoaccel );
+ autoaccel->setIgnoreWhatsThis( TRUE );
+ connect( autoaccel, SIGNAL(activated(int)),
+ SLOT(accelActivated(int)) );
+ connect( autoaccel, SIGNAL(activatedAmbiguously(int)),
+ SLOT(accelActivated(int)) );
+ connect( autoaccel, SIGNAL(destroyed()),
+ SLOT(accelDestroyed()) );
+ }
+ autoaccel->insertItem( i, mi->id() );
+ }
+ }
+ if ( mi->popup() ) {
+ QPopupMenu* popup = mi->popup();
+ popup->updateAccel( this );
+ if ( !popup->isEnabled() )
+ popup->enableAccel( FALSE );
+ }
+ }
+}
+#endif
+
+/*!
+ \reimp
+ */
+bool QMenuBar::customWhatsThis() const
+{
+ return TRUE;
+}
+
+
+
+/*!
+ \reimp
+ */
+void QMenuBar::focusInEvent( QFocusEvent * )
+{
+ if ( actItem < 0 ) {
+ int i = -1;
+ while ( actItem < 0 && ++i < (int) mitems->count() ) {
+ QMenuItem* mi = mitems->at( i );
+ if ( mi && mi->isEnabledAndVisible() && !mi->isSeparator() )
+ setActiveItem( i, FALSE );
+ }
+ } else if ( !popupvisible ) {
+ updateItem( idAt( actItem ) );
+ }
+}
+
+/*!
+ \reimp
+ */
+void QMenuBar::focusOutEvent( QFocusEvent * )
+{
+ updateItem( idAt( actItem ) );
+ if ( !popupvisible )
+ setAltMode( FALSE );
+}
+
+/*!
+ \reimp
+*/
+
+QSize QMenuBar::sizeHint() const
+{
+ int h = height();
+ if ( badSize )
+ h = ( (QMenuBar*)this )->calculateRects();
+ QSize s( 2*frameWidth(),0);
+ if ( irects ) {
+ for ( int i = 0; i < (int)mitems->count(); ++i )
+ s.setWidth( s.width() + irects[ i ].width() + 2 );
+ }
+ s.setHeight( h );
+ return (style().sizeFromContents(QStyle::CT_MenuBar, this, s.
+ expandedTo(QApplication::globalStrut())));
+}
+
+/*!
+ \reimp
+*/
+
+QSize QMenuBar::minimumSize() const
+{
+#ifndef QT_NO_TOOLBAR
+ QToolBar *tb = ::qt_cast<QToolBar*>(parent());
+ if ( tb )
+ return sizeHint();
+#endif
+ return QFrame::minimumSize();
+}
+
+/*!
+ \reimp
+*/
+
+QSize QMenuBar::minimumSizeHint() const
+{
+ return minimumSize();
+}
+
+/*!
+ \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 on )
+{
+ defaultup = on;
+}
+
+bool QMenuBar::isDefaultUp() const
+{
+ return defaultup;
+}
+
+
+/*!
+ \reimp
+ */
+void QMenuBar::activateItemAt( int index )
+{
+ if ( index >= 0 && index < (int) mitems->count() )
+ setActiveItem( index );
+ else
+ goodbye( FALSE );
+}
+
+#endif // QT_NO_MENUBAR
diff --git a/src/widgets/qmenubar.h b/src/widgets/qmenubar.h
new file mode 100644
index 0000000..74778d3
--- /dev/null
+++ b/src/widgets/qmenubar.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Definition of QMenuBar class
+**
+** Created : 941209
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QMENUBAR_H
+#define QMENUBAR_H
+
+#ifndef QT_H
+#include "qpopupmenu.h" // ### remove or keep for users' convenience?
+#include "qframe.h"
+#include "qmenudata.h"
+#endif // QT_H
+
+#ifndef QT_NO_MENUBAR
+
+class QPopupMenu;
+
+class Q_EXPORT QMenuBar : public QFrame, public QMenuData
+{
+ Q_OBJECT
+ Q_ENUMS( Separator )
+ Q_PROPERTY( Separator separator READ separator WRITE setSeparator DESIGNABLE false )
+ Q_PROPERTY( bool defaultUp READ isDefaultUp WRITE setDefaultUp )
+
+public:
+ QMenuBar( QWidget* parent=0, const char* name=0 );
+ ~QMenuBar();
+
+ void updateItem( int id );
+
+ void show(); // reimplemented show
+ void hide(); // reimplemented hide
+
+ bool eventFilter( QObject *, QEvent * );
+
+ int heightForWidth(int) const;
+
+ enum Separator { Never=0, InWindowsStyle=1 };
+ Separator separator() const;
+ virtual void setSeparator( Separator when );
+
+ void setDefaultUp( bool );
+ bool isDefaultUp() const;
+
+ bool customWhatsThis() const;
+
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ QSize minimumSizeHint() const;
+
+ void activateItemAt( int index );
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ static void initialize();
+ static void cleanup();
+#endif
+
+signals:
+ void activated( int itemId );
+ void highlighted( int itemId );
+
+protected:
+ void drawContents( QPainter * );
+ void fontChange( const QFont & );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent * );
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+ void resizeEvent( QResizeEvent * );
+ void leaveEvent( QEvent * );
+ void menuContentsChanged();
+ void menuStateChanged();
+ void styleChange( QStyle& );
+ int itemAtPos( const QPoint & );
+ void hidePopups();
+ QRect itemRect( int item );
+
+private slots:
+ void subActivated( int itemId );
+ void subHighlighted( int itemId );
+#ifndef QT_NO_ACCEL
+ void accelActivated( int itemId );
+ void accelDestroyed();
+#endif
+ void popupDestroyed( QObject* );
+ void performDelayedChanges();
+
+ void languageChange();
+
+private:
+ void performDelayedContentsChanged();
+ void performDelayedStateChanged();
+ void menuInsPopup( QPopupMenu * );
+ void menuDelPopup( QPopupMenu * );
+ void frameChanged();
+
+ bool tryMouseEvent( QPopupMenu *, QMouseEvent * );
+ void tryKeyEvent( QPopupMenu *, QKeyEvent * );
+ void goodbye( bool cancelled = FALSE );
+ void openActPopup();
+
+ void setActiveItem( int index, bool show = TRUE, bool activate_first_item = TRUE );
+ void setAltMode( bool );
+
+ int calculateRects( int max_width = -1 );
+
+#ifndef QT_NO_ACCEL
+ void setupAccelerators();
+ QAccel *autoaccel;
+#endif
+ QRect *irects;
+ int rightSide;
+
+ uint mseparator : 1;
+ uint waitforalt : 1;
+ uint popupvisible : 1;
+ uint hasmouse : 1;
+ uint defaultup : 1;
+ uint toggleclose : 1;
+ uint pendingDelayedContentsChanges : 1;
+ uint pendingDelayedStateChanges : 1;
+
+ friend class QPopupMenu;
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ friend class QWidget;
+ friend class QApplication;
+ friend void qt_mac_set_modal_state(bool, QMenuBar *);
+
+ void macCreateNativeMenubar();
+ void macRemoveNativeMenubar();
+ void macDirtyNativeMenubar();
+
+#if !defined(QMAC_QMENUBAR_NO_EVENT)
+ static void qt_mac_install_menubar_event(MenuRef);
+ static OSStatus qt_mac_menubar_event(EventHandlerCallRef, EventRef, void *);
+#endif
+ virtual void macWidgetChangedWindow();
+ bool syncPopups(MenuRef ret, QPopupMenu *d);
+ MenuRef createMacPopup(QPopupMenu *d, int id, bool =FALSE);
+ bool updateMenuBar();
+#if !defined(QMAC_QMENUBAR_NO_MERGE)
+ uint isCommand(QMenuItem *, bool just_check=FALSE);
+#endif
+
+ uint mac_eaten_menubar : 1;
+ class MacPrivate;
+ MacPrivate *mac_d;
+ static bool activate(MenuRef, short, bool highlight=FALSE, bool by_accel=FALSE);
+ static bool activateCommand(uint cmd);
+ static bool macUpdateMenuBar();
+ static bool macUpdatePopupVisible(MenuRef, bool);
+ static bool macUpdatePopup(MenuRef);
+#endif
+
+private: // Disabled copy constructor and operator=
+
+#if defined(Q_DISABLE_COPY)
+ QMenuBar( const QMenuBar & );
+ QMenuBar &operator=( const QMenuBar & );
+#endif
+};
+
+
+#endif // QT_NO_MENUBAR
+
+#endif // QMENUBAR_H
diff --git a/src/widgets/qmenudata.cpp b/src/widgets/qmenudata.cpp
new file mode 100644
index 0000000..518ea6b
--- /dev/null
+++ b/src/widgets/qmenudata.cpp
@@ -0,0 +1,1603 @@
+/****************************************************************************
+**
+** Implementation of QMenuData class
+**
+** Created : 941128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qmenudata.h"
+#ifndef QT_NO_MENUDATA
+#include "qpopupmenu.h"
+#include "qmenubar.h"
+#include "qapplication.h"
+#include "qguardedptr.h"
+
+class QMenuItemData {
+public:
+ QCustomMenuItem *custom_item; // custom menu item
+};
+
+class QMenuDataData {
+ // attention: also defined in qmenubar.cpp and qpopupmenu.cpp
+public:
+ QMenuDataData();
+ QGuardedPtr<QWidget> aWidget;
+ int aInt;
+};
+QMenuDataData::QMenuDataData()
+ : aInt(-1)
+{}
+
+/*!
+ \class QMenuData qmenudata.h
+ \brief The QMenuData class is a base class for QMenuBar and QPopupMenu.
+
+ \ingroup misc
+
+ QMenuData has an internal list of menu items. A menu item can have
+ a text(), an \link accel() accelerator\endlink, a pixmap(), an
+ iconSet(), a whatsThis() text and a popup menu (unless it is a
+ separator). Menu items may optionally be \link setItemChecked()
+ checked\endlink (except for separators).
+
+ The menu item sends out an \link QMenuBar::activated()
+ activated()\endlink signal when it is chosen and a \link
+ QMenuBar::highlighted() highlighted()\endlink signal when it
+ receives the user input focus.
+
+ \keyword menu identifier
+
+ Menu items are assigned the menu identifier \e id that is passed
+ in insertItem() or an automatically generated identifier if \e id
+ is < 0 (the default). The generated identifiers (negative
+ integers) are guaranteed to be unique within the entire
+ application. The identifier is used to access the menu item in
+ other functions.
+
+ Menu items can be removed with removeItem() and removeItemAt(), or
+ changed with changeItem(). All menu items can be removed with
+ clear(). Accelerators can be changed or set with setAccel().
+ Checkable items can be checked or unchecked with setItemChecked().
+ Items can be enabled or disabled using setItemEnabled() and
+ connected and disconnected with connectItem() and disconnectItem()
+ respectively. By default, newly created menu items are visible.
+ They can be hidden (and shown again) with setItemVisible().
+
+ Menu items are stored in a list. Use findItem() to find an item by
+ its list position or by its menu identifier. (See also indexOf()
+ and idAt().)
+
+ \sa QAccel QPopupMenu QAction
+*/
+
+
+/*****************************************************************************
+ QMenuItem member functions
+ *****************************************************************************/
+
+QMenuItem::QMenuItem()
+ :ident( -1 ), iconset_data( 0 ), pixmap_data( 0 ), popup_menu( 0 ),
+ widget_item( 0 ), signal_data( 0 ), is_separator( FALSE ), is_enabled( TRUE ),
+ is_checked( FALSE ), is_dirty( TRUE ), is_visible( TRUE ), d( 0)
+{}
+
+QMenuItem::~QMenuItem()
+{
+ delete iconset_data;
+ delete pixmap_data;
+ delete signal_data;
+ delete widget_item;
+ if ( d )
+ delete d->custom_item;
+ delete d;
+}
+
+
+/*****************************************************************************
+ QMenuData member functions
+ *****************************************************************************/
+
+QMenuItemData* QMenuItem::extra()
+{
+ if ( !d ) d = new QMenuItemData;
+ return d;
+}
+
+QCustomMenuItem *QMenuItem::custom() const
+{
+ if ( !d ) return 0;
+ return d->custom_item;
+}
+
+
+static int get_seq_id()
+{
+ static int seq_no = -2;
+ return seq_no--;
+}
+
+
+/*!
+ Constructs an empty menu data list.
+*/
+
+QMenuData::QMenuData()
+{
+ actItem = -1; // no active menu item
+ mitems = new QMenuItemList; // create list of menu items
+ Q_CHECK_PTR( mitems );
+ mitems->setAutoDelete( TRUE );
+ parentMenu = 0; // assume top level
+ isPopupMenu = FALSE;
+ isMenuBar = FALSE;
+ mouseBtDn = FALSE;
+ badSize = TRUE;
+ avoid_circularity = 0;
+ actItemDown = FALSE;
+ d = new QMenuDataData;
+}
+
+/*!
+ Removes all menu items and disconnects any signals that have been
+ connected.
+*/
+
+QMenuData::~QMenuData()
+{
+ delete mitems; // delete menu item list
+ delete d;
+}
+
+
+/*!
+ Virtual function; notifies subclasses about an item with \a id
+ that has been changed.
+*/
+
+void QMenuData::updateItem( int /* id */ ) // reimplemented in subclass
+{
+}
+
+/*!
+ Virtual function; notifies subclasses that one or more items have
+ been inserted or removed.
+*/
+
+void QMenuData::menuContentsChanged() // reimplemented in subclass
+{
+}
+
+/*!
+ Virtual function; notifies subclasses that one or more items have
+ changed state (enabled/disabled or checked/unchecked).
+*/
+
+void QMenuData::menuStateChanged() // reimplemented in subclass
+{
+}
+
+/*!
+ Virtual function; notifies subclasses that a popup menu item has
+ been inserted.
+*/
+
+void QMenuData::menuInsPopup( QPopupMenu * ) // reimplemented in subclass
+{
+}
+
+/*!
+ Virtual function; notifies subclasses that a popup menu item has
+ been removed.
+*/
+
+void QMenuData::menuDelPopup( QPopupMenu * ) // reimplemented in subclass
+{
+}
+
+
+/*!
+ Returns the number of items in the menu.
+*/
+
+uint QMenuData::count() const
+{
+ return mitems->count();
+}
+
+
+
+/*!
+ \internal
+
+ Internal function that insert a menu item. Called by all insert()
+ functions.
+*/
+
+int QMenuData::insertAny( const QString *text, const QPixmap *pixmap,
+ QPopupMenu *popup, const QIconSet* iconset, int id, int index,
+ QWidget* widget, QCustomMenuItem* custom )
+{
+ if ( index < 0 ) { // append, but not if the rightmost item is an mdi separator in the menubar
+ index = mitems->count();
+ if ( isMenuBar && mitems->last() && mitems->last()->widget() && mitems->last()->isSeparator() )
+ index--;
+ } else if ( index > (int) mitems->count() ) { // append
+ index = mitems->count();
+ }
+ if ( id < 0 ) // -2, -3 etc.
+ id = get_seq_id();
+
+ register QMenuItem *mi = new QMenuItem;
+ Q_CHECK_PTR( mi );
+ mi->ident = id;
+ if ( widget != 0 ) {
+ mi->widget_item = widget;
+ mi->is_separator = !widget->isFocusEnabled();
+ } else if ( custom != 0 ) {
+ mi->extra()->custom_item = custom;
+ mi->is_separator = custom->isSeparator();
+ if ( iconset && !iconset->isNull() )
+ mi->iconset_data = new QIconSet( *iconset );
+ } else if ( text == 0 && pixmap == 0 && popup == 0 ) {
+ mi->is_separator = TRUE; // separator
+ } else {
+#ifndef Q_OS_TEMP
+ mi->text_data = text?*text:QString();
+#else
+ QString newText( *text );
+ newText.truncate( newText.findRev( '\t' ) );
+ mi->text_data = newText.isEmpty()?QString():newText;
+#endif
+#ifndef QT_NO_ACCEL
+ mi->accel_key = Qt::Key_unknown;
+#endif
+ if ( pixmap && !pixmap->isNull() )
+ mi->pixmap_data = new QPixmap( *pixmap );
+ if ( (mi->popup_menu = popup) )
+ menuInsPopup( popup );
+ if ( iconset && !iconset->isNull() )
+ mi->iconset_data = new QIconSet( *iconset );
+ }
+
+ mitems->insert( index, mi );
+ QPopupMenu* p = ::qt_cast<QPopupMenu*>(QMenuData::d->aWidget);
+ if (p && p->isVisible() && p->mitems) {
+ p->mitems->clear();
+ for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
+ if ( it.current()->id() != QMenuData::d->aInt && !it.current()->widget() )
+ p->mitems->append( it.current() );
+ }
+ }
+ menuContentsChanged(); // menu data changed
+ return mi->ident;
+}
+
+/*!
+ \internal
+
+ Internal function that finds the menu item where \a popup is located,
+ storing its index at \a index if \a index is not NULL.
+*/
+QMenuItem *QMenuData::findPopup( QPopupMenu *popup, int *index )
+{
+ int i = 0;
+ QMenuItem *mi = mitems->first();
+ while ( mi ) {
+ if ( mi->popup_menu == popup ) // found popup
+ break;
+ i++;
+ mi = mitems->next();
+ }
+ if ( index && mi )
+ *index = i;
+ return mi;
+}
+
+void QMenuData::removePopup( QPopupMenu *popup )
+{
+ int index = 0;
+ QMenuItem *mi = findPopup( popup, &index );
+ if ( mi ) {
+ mi->popup_menu = 0;
+ removeItemAt( index );
+ }
+}
+
+
+/*!
+ The family of insertItem() functions inserts menu items into a
+ popup menu or a menu bar.
+
+ A menu item is usually either a text string or a pixmap, both with
+ an optional icon or keyboard accelerator. For special cases it is
+ also possible to insert custom items (see \l{QCustomMenuItem}) or
+ even widgets into popup menus.
+
+ Some insertItem() members take a popup menu as an additional
+ argument. Use this to insert submenus into existing menus or
+ pulldown menus into a menu bar.
+
+ The number of insert functions may look confusing, but they are
+ actually quite simple to use.
+
+ This default version inserts a menu item with the text \a text,
+ the accelerator key \a accel, an id and an optional index and
+ connects it to the slot \a member in the object \a receiver.
+
+ Example:
+ \code
+ QMenuBar *mainMenu = new QMenuBar;
+ QPopupMenu *fileMenu = new QPopupMenu;
+ fileMenu->insertItem( "New", myView, SLOT(newFile()), CTRL+Key_N );
+ fileMenu->insertItem( "Open", myView, SLOT(open()), CTRL+Key_O );
+ mainMenu->insertItem( "File", fileMenu );
+ \endcode
+
+ Not all insert functions take an object/slot parameter or an
+ accelerator key. Use connectItem() and setAccel() on those items.
+
+ If you need to translate accelerators, use tr() with the text and
+ accelerator. (For translations use a string \link QKeySequence key
+ sequence\endlink.):
+ \code
+ fileMenu->insertItem( tr("Open"), myView, SLOT(open()),
+ tr("Ctrl+O") );
+ \endcode
+
+ In the example above, pressing Ctrl+O or selecting "Open" from the
+ menu activates the myView->open() function.
+
+ Some insert functions take a QIconSet parameter to specify the
+ little menu item icon. Note that you can always pass a QPixmap
+ object instead.
+
+ The \a id specifies the identification number associated with the
+ menu item. Note that only positive values are valid, as a negative
+ value will make Qt select a unique id for the item.
+
+ The \a index specifies the position in the menu. The menu item is
+ appended at the end of the list if \a index is negative.
+
+ Note that keyboard accelerators in Qt are not application-global,
+ instead they are bound to a certain top-level window. For example,
+ accelerators in QPopupMenu items only work for menus that are
+ associated with a certain window. This is true for popup menus
+ that live in a menu bar since their accelerators will then be
+ installed in the menu bar itself. This also applies to stand-alone
+ popup menus that have a top-level widget in their parentWidget()
+ chain. The menu will then install its accelerator object on that
+ top-level widget. For all other cases use an independent QAccel
+ object.
+
+ \warning Be careful when passing a literal 0 to insertItem()
+ because some C++ compilers choose the wrong overloaded function.
+ Cast the 0 to what you mean, e.g. \c{(QObject*)0}.
+
+ \warning On Mac OS X, items that connect to a slot that are inserted into a
+ menubar will not function as we use the native menubar that knows nothing
+ about signals or slots. Instead insert the items into a popup menu and
+ insert the popup menu into the menubar. This may be fixed in a future Qt
+ version.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem(), QAccel,
+ qnamespace.h
+*/
+
+int QMenuData::insertItem( const QString &text,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel, int id, int index )
+{
+ int actualID = insertAny( &text, 0, 0, 0, id, index );
+ connectItem( actualID, receiver, member );
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ setAccel( accel, actualID );
+#endif
+ return actualID;
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with icon \a icon, text \a text, accelerator
+ \a accel, optional id \a id, and optional \a index position. The
+ menu item is connected it to the \a receiver's \a member slot. The
+ icon will be displayed to the left of the text in the item.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem(), QAccel,
+ qnamespace.h
+*/
+
+int QMenuData::insertItem( const QIconSet& icon,
+ const QString &text,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel, int id, int index )
+{
+ int actualID = insertAny( &text, 0, 0, &icon, id, index );
+ connectItem( actualID, receiver, member );
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ setAccel( accel, actualID );
+#endif
+ return actualID;
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with pixmap \a pixmap, accelerator \a accel,
+ optional id \a id, and optional \a index position. The menu item
+ is connected it to the \a receiver's \a member slot. The icon will
+ be displayed to the left of the text in the item.
+
+ To look best when being highlighted as a menu item, the pixmap
+ should provide a mask (see QPixmap::mask()).
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QPixmap &pixmap,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel, int id, int index )
+{
+ int actualID = insertAny( 0, &pixmap, 0, 0, id, index );
+ connectItem( actualID, receiver, member );
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ setAccel( accel, actualID );
+#endif
+ return actualID;
+}
+
+
+/*!
+ \overload
+
+ Inserts a menu item with icon \a icon, pixmap \a pixmap,
+ accelerator \a accel, optional id \a id, and optional \a index
+ position. The icon will be displayed to the left of the pixmap in
+ the item. The item is connected to the \a member slot in the \a
+ receiver object.
+
+ To look best when being highlighted as a menu item, the pixmap
+ should provide a mask (see QPixmap::mask()).
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem(), QAccel,
+ qnamespace.h
+*/
+
+int QMenuData::insertItem( const QIconSet& icon,
+ const QPixmap &pixmap,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel, int id, int index )
+{
+ int actualID = insertAny( 0, &pixmap, 0, &icon, id, index );
+ connectItem( actualID, receiver, member );
+#ifndef QT_NO_ACCEL
+ if ( accel )
+ setAccel( accel, actualID );
+#endif
+ return actualID;
+}
+
+
+
+/*!
+ \overload
+
+ Inserts a menu item with text \a text, optional id \a id, and
+ optional \a index position.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QString &text, int id, int index )
+{
+ return insertAny( &text, 0, 0, 0, id, index );
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with icon \a icon, text \a text, optional id
+ \a id, and optional \a index position. The icon will be displayed
+ to the left of the text in the item.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QIconSet& icon,
+ const QString &text, int id, int index )
+{
+ return insertAny( &text, 0, 0, &icon, id, index );
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with text \a text, submenu \a popup, optional
+ id \a id, and optional \a index position.
+
+ The \a popup must be deleted by the programmer or by its parent
+ widget. It is not deleted when this menu item is removed or when
+ the menu is deleted.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QString &text, QPopupMenu *popup,
+ int id, int index )
+{
+ return insertAny( &text, 0, popup, 0, id, index );
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with icon \a icon, text \a text, submenu \a
+ popup, optional id \a id, and optional \a index position. The icon
+ will be displayed to the left of the text in the item.
+
+ The \a popup must be deleted by the programmer or by its parent
+ widget. It is not deleted when this menu item is removed or when
+ the menu is deleted.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QIconSet& icon,
+ const QString &text, QPopupMenu *popup,
+ int id, int index )
+{
+ return insertAny( &text, 0, popup, &icon, id, index );
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with pixmap \a pixmap, optional id \a id, and
+ optional \a index position.
+
+ To look best when being highlighted as a menu item, the pixmap
+ should provide a mask (see QPixmap::mask()).
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QPixmap &pixmap, int id, int index )
+{
+ return insertAny( 0, &pixmap, 0, 0, id, index );
+}
+
+/*!
+ \overload
+
+ Inserts a menu item with icon \a icon, pixmap \a pixmap, optional
+ id \a id, and optional \a index position. The icon will be
+ displayed to the left of the pixmap in the item.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QIconSet& icon,
+ const QPixmap &pixmap, int id, int index )
+{
+ return insertAny( 0, &pixmap, 0, &icon, id, index );
+}
+
+
+/*!
+ \overload
+
+ Inserts a menu item with pixmap \a pixmap, submenu \a popup,
+ optional id \a id, and optional \a index position.
+
+ The \a popup must be deleted by the programmer or by its parent
+ widget. It is not deleted when this menu item is removed or when
+ the menu is deleted.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QPixmap &pixmap, QPopupMenu *popup,
+ int id, int index )
+{
+ return insertAny( 0, &pixmap, popup, 0, id, index );
+}
+
+
+/*!
+ \overload
+
+ Inserts a menu item with icon \a icon, pixmap \a pixmap submenu \a
+ popup, optional id \a id, and optional \a index position. The icon
+ will be displayed to the left of the pixmap in the item.
+
+ The \a popup must be deleted by the programmer or by its parent
+ widget. It is not deleted when this menu item is removed or when
+ the menu is deleted.
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem(), changeItem(), setAccel(), connectItem()
+*/
+
+int QMenuData::insertItem( const QIconSet& icon,
+ const QPixmap &pixmap, QPopupMenu *popup,
+ int id, int index )
+{
+ return insertAny( 0, &pixmap, popup, &icon, id, index );
+}
+
+
+
+/*!
+ \overload
+
+ Inserts a menu item that consists of the widget \a widget with
+ optional id \a id, and optional \a index position.
+
+ Ownership of \a widget is transferred to the popup menu or to the
+ menu bar.
+
+ Theoretically, any widget can be inserted into a popup menu. In
+ practice, this only makes sense with certain widgets.
+
+ If a widget is not focus-enabled (see
+ \l{QWidget::isFocusEnabled()}), the menu treats it as a separator;
+ this means that the item is not selectable and will never get
+ focus. In this way you can, for example, simply insert a QLabel if
+ you need a popup menu with a title.
+
+ If the widget is focus-enabled it will get focus when the user
+ traverses the popup menu with the arrow keys. If the widget does
+ not accept \c ArrowUp and \c ArrowDown in its key event handler,
+ the focus will move back to the menu when the respective arrow key
+ is hit one more time. This works with a QLineEdit, for example. If
+ the widget accepts the arrow key itself, it must also provide the
+ possibility to put the focus back on the menu again by calling
+ QWidget::focusNextPrevChild(). Futhermore, if the embedded widget
+ closes the menu when the user made a selection, this can be done
+ safely by calling:
+ \code
+ if ( isVisible() &&
+ parentWidget() &&
+ parentWidget()->inherits("QPopupMenu") )
+ parentWidget()->close();
+ \endcode
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa removeItem()
+*/
+int QMenuData::insertItem( QWidget* widget, int id, int index )
+{
+ return insertAny( 0, 0, 0, 0, id, index, widget );
+}
+
+
+/*!
+ \overload
+
+ Inserts a custom menu item \a custom with optional id \a id, and
+ optional \a index position.
+
+ This only works with popup menus. It is not supported for menu
+ bars. Ownership of \a custom is transferred to the popup menu.
+
+ If you want to connect a custom item to a slot, use connectItem().
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa connectItem(), removeItem(), QCustomMenuItem
+*/
+int QMenuData::insertItem( QCustomMenuItem* custom, int id, int index )
+{
+ return insertAny( 0, 0, 0, 0, id, index, 0, custom );
+}
+
+/*!
+ \overload
+
+ Inserts a custom menu item \a custom with an \a icon and with
+ optional id \a id, and optional \a index position.
+
+ This only works with popup menus. It is not supported for menu
+ bars. Ownership of \a custom is transferred to the popup menu.
+
+ If you want to connect a custom item to a slot, use connectItem().
+
+ Returns the allocated menu identifier number (\a id if \a id >= 0).
+
+ \sa connectItem(), removeItem(), QCustomMenuItem
+*/
+int QMenuData::insertItem( const QIconSet& icon, QCustomMenuItem* custom, int id, int index )
+{
+ return insertAny( 0, 0, 0, &icon, id, index, 0, custom );
+}
+
+
+/*!
+ Inserts a separator at position \a index, and returns the menu identifier
+ number allocated to it. The separator becomes the last menu item if
+ \a index is negative.
+
+ In a popup menu a separator is rendered as a horizontal line. In a
+ Motif menu bar a separator is spacing, so the rest of the items
+ (normally just "Help") are drawn right-justified. In a Windows
+ menu bar separators are ignored (to comply with the Windows style
+ guidelines).
+*/
+int QMenuData::insertSeparator( int index )
+{
+ return insertAny( 0, 0, 0, 0, -1, index );
+}
+
+/*!
+ \fn void QMenuData::removeItem( int id )
+
+ Removes the menu item that has the identifier \a id.
+
+ \sa removeItemAt(), clear()
+*/
+
+void QMenuData::removeItem( int id )
+{
+ QMenuData *parent;
+ if ( findItem( id, &parent ) )
+ parent->removeItemAt(parent->indexOf(id));
+}
+
+/*!
+ Removes the menu item at position \a index.
+
+ \sa removeItem(), clear()
+*/
+
+void QMenuData::removeItemAt( int index )
+{
+ if ( index < 0 || index >= (int)mitems->count() ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QMenuData::removeItem: Index %d out of range", index );
+#endif
+ return;
+ }
+ QMenuItem *mi = mitems->at( index );
+ if ( mi->popup_menu )
+ menuDelPopup( mi->popup_menu );
+ mitems->remove();
+ QPopupMenu* p = ::qt_cast<QPopupMenu*>(QMenuData::d->aWidget);
+ if (p && p->isVisible() && p->mitems) {
+ p->mitems->clear();
+ for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
+ if ( it.current()->id() != QMenuData::d->aInt && !it.current()->widget() )
+ p->mitems->append( it.current() );
+ }
+ }
+ if ( !QApplication::closingDown() ) // avoid trouble
+ menuContentsChanged();
+}
+
+
+/*!
+ Removes all menu items.
+
+ \sa removeItem(), removeItemAt()
+*/
+
+void QMenuData::clear()
+{
+ register QMenuItem *mi = mitems->first();
+ while ( mi ) {
+ if ( mi->popup_menu )
+ menuDelPopup( mi->popup_menu );
+ mitems->remove();
+ mi = mitems->current();
+ }
+ QPopupMenu* p = ::qt_cast<QPopupMenu*>(QMenuData::d->aWidget);
+ if (p && p->isVisible() && p->mitems) {
+ p->mitems->clear();
+ }
+ if ( !QApplication::closingDown() ) // avoid trouble
+ menuContentsChanged();
+}
+
+#ifndef QT_NO_ACCEL
+
+/*!
+ Returns the accelerator key that has been defined for the menu
+ item \a id, or 0 if it has no accelerator key or if there is no
+ such menu item.
+
+ \sa setAccel(), QAccel, qnamespace.h
+*/
+
+QKeySequence QMenuData::accel( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ if ( mi )
+ return mi->key();
+ return QKeySequence();
+}
+
+/*!
+ Sets the accelerator key for the menu item \a id to \a key.
+
+ An accelerator key consists of a key code and a combination of the
+ modifiers \c SHIFT, \c CTRL, \c ALT or \c UNICODE_ACCEL (OR'ed or
+ added). The header file \c qnamespace.h contains a list of key
+ codes.
+
+ Defining an accelerator key produces a text that is added to the
+ menu item; for instance, \c CTRL + \c Key_O produces "Ctrl+O". The
+ text is formatted differently for different platforms.
+
+ Note that keyboard accelerators in Qt are not application-global,
+ instead they are bound to a certain top-level window. For example,
+ accelerators in QPopupMenu items only work for menus that are
+ associated with a certain window. This is true for popup menus
+ that live in a menu bar since their accelerators will then be
+ installed in the menu bar itself. This also applies to stand-alone
+ popup menus that have a top-level widget in their parentWidget()
+ chain. The menu will then install its accelerator object on that
+ top-level widget. For all other cases use an independent QAccel
+ object.
+
+ Example:
+ \code
+ QMenuBar *mainMenu = new QMenuBar;
+ QPopupMenu *fileMenu = new QPopupMenu; // file sub menu
+ fileMenu->insertItem( "Open Document", 67 ); // add "Open" item
+ fileMenu->setAccel( CTRL + Key_O, 67 ); // Ctrl+O to open
+ fileMenu->insertItem( "Quit", 69 ); // add "Quit" item
+ fileMenu->setAccel( CTRL + ALT + Key_Delete, 69 ); // add Alt+Del to quit
+ mainMenu->insertItem( "File", fileMenu ); // add the file menu
+ \endcode
+
+ If you need to translate accelerators, use tr() with a string:
+ \code
+ fileMenu->setAccel( tr("Ctrl+O"), 67 );
+ \endcode
+
+ You can also specify the accelerator in the insertItem() function.
+ You may prefer to use QAction to associate accelerators with menu
+ items.
+
+ \sa accel() insertItem() QAccel QAction
+*/
+
+void QMenuData::setAccel( const QKeySequence& key, int id )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi ) {
+ mi->accel_key = key;
+ parent->menuContentsChanged();
+ }
+}
+
+#endif // QT_NO_ACCEL
+
+/*!
+ Returns the icon set that has been set for menu item \a id, or 0
+ if no icon set has been set.
+
+ \sa changeItem(), text(), pixmap()
+*/
+
+QIconSet* QMenuData::iconSet( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ return mi ? mi->iconSet() : 0;
+}
+
+/*!
+ Returns the text that has been set for menu item \a id, or
+ QString::null if no text has been set.
+
+ \sa changeItem(), pixmap(), iconSet()
+*/
+
+QString QMenuData::text( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ return mi ? mi->text() : QString::null;
+}
+
+/*!
+ Returns the pixmap that has been set for menu item \a id, or 0 if
+ no pixmap has been set.
+
+ \sa changeItem(), text(), iconSet()
+*/
+
+QPixmap *QMenuData::pixmap( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ return mi ? mi->pixmap() : 0;
+}
+
+/*!
+ \fn void QMenuData::changeItem( const QString &, int )
+ \obsolete
+
+ Changes the text of the menu item \a id. If the item has an icon,
+ the icon remains unchanged.
+
+ \sa text()
+*/
+/*!
+ \fn void QMenuData::changeItem( const QPixmap &, int )
+ \obsolete
+
+ Changes the pixmap of the menu item \a id. If the item has an icon,
+ the icon remains unchanged.
+
+ \sa pixmap()
+*/
+
+/*!
+ \fn void QMenuData::changeItem( const QIconSet &, const QString &, int )
+ \obsolete
+
+ Changes the icon and text of the menu item \a id.
+
+ \sa pixmap()
+*/
+
+/*!
+ Changes the text of the menu item \a id to \a text. If the item
+ has an icon, the icon remains unchanged.
+
+ \sa text()
+*/
+
+void QMenuData::changeItem( int id, const QString &text )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi ) { // item found
+ if ( mi->text_data == text ) // same string
+ return;
+ if ( mi->pixmap_data ) { // delete pixmap
+ delete mi->pixmap_data;
+ mi->pixmap_data = 0;
+ }
+ mi->text_data = text;
+#ifndef QT_NO_ACCEL
+ if ( !mi->accel_key && text.find( '\t' ) != -1 )
+ mi->accel_key = Qt::Key_unknown;
+#endif
+ parent->menuContentsChanged();
+ }
+}
+
+/*!
+ \overload
+
+ Changes the pixmap of the menu item \a id to the pixmap \a pixmap.
+ If the item has an icon, the icon is unchanged.
+
+ \sa pixmap()
+*/
+
+void QMenuData::changeItem( int id, const QPixmap &pixmap )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi ) { // item found
+ register QPixmap *i = mi->pixmap_data;
+ bool fast_refresh = i != 0 &&
+ i->width() == pixmap.width() &&
+ i->height() == pixmap.height() &&
+ !mi->text();
+ if ( !mi->text_data.isNull() ) // delete text
+ mi->text_data = QString::null;
+ if ( !pixmap.isNull() )
+ mi->pixmap_data = new QPixmap( pixmap );
+ else
+ mi->pixmap_data = 0;
+ delete i; // old mi->pixmap_data, could be &pixmap
+ if ( fast_refresh )
+ parent->updateItem( id );
+ else
+ parent->menuContentsChanged();
+ }
+}
+
+/*!
+ \overload
+
+ Changes the iconset and text of the menu item \a id to the \a icon
+ and \a text respectively.
+
+ \sa pixmap()
+*/
+
+void QMenuData::changeItem( int id, const QIconSet &icon, const QString &text )
+{
+ changeItem( id, text );
+ changeItemIconSet( id, icon );
+}
+
+/*!
+ \overload
+
+ Changes the iconset and pixmap of the menu item \a id to \a icon
+ and \a pixmap respectively.
+
+ \sa pixmap()
+*/
+
+void QMenuData::changeItem( int id, const QIconSet &icon, const QPixmap &pixmap )
+{
+ changeItem( id, pixmap );
+ changeItemIconSet( id, icon );
+}
+
+
+
+/*!
+ Changes the icon of the menu item \a id to \a icon.
+
+ \sa pixmap()
+*/
+
+void QMenuData::changeItemIconSet( int id, const QIconSet &icon )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi ) { // item found
+ register QIconSet *i = mi->iconset_data;
+ bool fast_refresh = i != 0;
+ if ( !icon.isNull() )
+ mi->iconset_data = new QIconSet( icon );
+ else
+ mi->iconset_data = 0;
+ delete i; // old mi->iconset_data, could be &icon
+ if ( fast_refresh )
+ parent->updateItem( id );
+ else
+ parent->menuContentsChanged();
+ }
+}
+
+
+/*!
+ Returns TRUE if the item with identifier \a id is enabled;
+ otherwise returns FALSE
+
+ \sa setItemEnabled(), isItemVisible()
+*/
+
+bool QMenuData::isItemEnabled( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ return mi ? mi->isEnabled() : FALSE;
+}
+
+/*!
+ If \a enable is TRUE, enables the menu item with identifier \a id;
+ otherwise disables the menu item with identifier \a id.
+
+ \sa isItemEnabled()
+*/
+
+void QMenuData::setItemEnabled( int id, bool enable )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi && (bool)mi->is_enabled != enable ) {
+ mi->is_enabled = enable;
+#if !defined(QT_NO_ACCEL) && !defined(QT_NO_POPUPMENU)
+ if ( mi->popup() )
+ mi->popup()->enableAccel( enable );
+#endif
+ parent->menuStateChanged();
+ }
+}
+
+
+/*!
+ Returns TRUE if the menu item with the id \a id is currently
+ active; otherwise returns FALSE.
+*/
+bool QMenuData::isItemActive( int id ) const
+{
+ if ( actItem == -1 )
+ return FALSE;
+ return indexOf( id ) == actItem;
+}
+
+/*!
+ Returns TRUE if the menu item with the id \a id has been checked;
+ otherwise returns FALSE.
+
+ \sa setItemChecked()
+*/
+
+bool QMenuData::isItemChecked( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ return mi ? mi->isChecked() : FALSE;
+}
+
+/*!
+ If \a check is TRUE, checks the menu item with id \a id; otherwise
+ unchecks the menu item with id \a id. Calls
+ QPopupMenu::setCheckable( TRUE ) if necessary.
+
+ \sa isItemChecked()
+*/
+
+void QMenuData::setItemChecked( int id, bool check )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi && (bool)mi->is_checked != check ) {
+ mi->is_checked = check;
+#ifndef QT_NO_POPUPMENU
+ if ( parent->isPopupMenu && !((QPopupMenu *)parent)->isCheckable() )
+ ((QPopupMenu *)parent)->setCheckable( TRUE );
+#endif
+ parent->menuStateChanged();
+ }
+}
+
+/*!
+ Returns TRUE if the menu item with the id \a id is visible;
+ otherwise returns FALSE.
+
+ \sa setItemVisible()
+*/
+
+bool QMenuData::isItemVisible( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ return mi ? mi->isVisible() : FALSE;
+}
+
+/*!
+ If \a visible is TRUE, shows the menu item with id \a id; otherwise
+ hides the menu item with id \a id.
+
+ \sa isItemVisible(), isItemEnabled()
+*/
+
+void QMenuData::setItemVisible( int id, bool visible )
+{
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi && (bool)mi->is_visible != visible ) {
+ mi->is_visible = visible;
+ parent->menuContentsChanged();
+ }
+}
+
+
+/*!
+ Returns the menu item with identifier \a id, or 0 if there is no
+ item with this identifier.
+
+ Note that QMenuItem is an internal class, and that you should not
+ need to call this function. Use the higher level functions like
+ text(), pixmap() and changeItem() to get and modify menu item
+ attributes instead.
+
+ \sa indexOf()
+*/
+
+QMenuItem *QMenuData::findItem( int id ) const
+{
+ return findItem( id, 0 );
+}
+
+
+/*!
+ \overload
+
+ Returns the menu item with identifier \a id, or 0 if there is no
+ item with this identifier. Changes \a *parent to point to the
+ parent of the return value.
+
+ Note that QMenuItem is an internal class, and that you should not
+ need to call this function. Use the higher level functions like
+ text(), pixmap() and changeItem() to get and modify menu item
+ attributes instead.
+
+ \sa indexOf()
+*/
+
+QMenuItem * QMenuData::findItem( int id, QMenuData ** parent ) const
+{
+ if ( parent )
+ *parent = (QMenuData *)this; // ###
+
+ if ( id == -1 ) // bad identifier
+ return 0;
+ QMenuItemListIt it( *mitems );
+ QMenuItem *mi;
+ while ( (mi=it.current()) ) { // search this menu
+ ++it;
+ if ( mi->ident == id ) // found item
+ return mi;
+ }
+ it.toFirst();
+ while ( (mi=it.current()) ) { // search submenus
+ ++it;
+#ifndef QT_NO_POPUPMENU
+ if ( mi->popup_menu ) {
+ QPopupMenu *p = mi->popup_menu;
+ if (!p->avoid_circularity) {
+ p->avoid_circularity = 1;
+ mi = mi->popup_menu->findItem( id, parent );
+ p->avoid_circularity = 0;
+ if ( mi ) // found item
+ return mi;
+ }
+ }
+#endif
+ }
+ return 0; // not found
+}
+
+/*!
+ Returns the index of the menu item with identifier \a id, or -1 if
+ there is no item with this identifier.
+
+ \sa idAt(), findItem()
+*/
+
+int QMenuData::indexOf( int id ) const
+{
+ if ( id == -1 ) // bad identifier
+ return -1;
+ QMenuItemListIt it( *mitems );
+ QMenuItem *mi;
+ int index = 0;
+ while ( (mi=it.current()) ) {
+ if ( mi->ident == id ) // this one?
+ return index;
+ ++index;
+ ++it;
+ }
+ return -1; // not found
+}
+
+/*!
+ Returns the identifier of the menu item at position \a index in
+ the internal list, or -1 if \a index is out of range.
+
+ \sa setId(), indexOf()
+*/
+
+int QMenuData::idAt( int index ) const
+{
+ return index < (int)mitems->count() && index >= 0 ?
+ mitems->at(index)->id() : -1;
+}
+
+/*!
+ Sets the menu identifier of the item at \a index to \a id.
+
+ If \a index is out of range, the operation is ignored.
+
+ \sa idAt()
+*/
+
+void QMenuData::setId( int index, int id )
+{
+ if ( index < (int)mitems->count() )
+ mitems->at(index)->ident = id;
+}
+
+
+/*!
+ Sets the parameter of the activation signal of item \a id to \a
+ param.
+
+ If any receiver takes an integer parameter, this value is passed.
+
+ \sa connectItem(), disconnectItem(), itemParameter()
+*/
+bool QMenuData::setItemParameter( int id, int param ) {
+ QMenuItem *mi = findItem( id );
+ if ( !mi ) // no such identifier
+ return FALSE;
+ if ( !mi->signal_data ) { // create new signal
+ mi->signal_data = new QSignal;
+ Q_CHECK_PTR( mi->signal_data );
+ }
+ mi->signal_data->setValue( param );
+ return TRUE;
+}
+
+
+/*!
+ Returns the parameter of the activation signal of item \a id.
+
+ If no parameter has been specified for this item with
+ setItemParameter(), the value defaults to \a id.
+
+ \sa connectItem(), disconnectItem(), setItemParameter()
+*/
+int QMenuData::itemParameter( int id ) const
+{
+ QMenuItem *mi = findItem( id );
+ if ( !mi || !mi->signal_data )
+ return id;
+ return mi->signal_data->value().toInt();
+}
+
+
+/*!
+ Connects the menu item with identifier \a id to \a{receiver}'s \a
+ member slot or signal.
+
+ The receiver's slot (or signal) is activated when the menu item is
+ activated.
+
+ \sa disconnectItem(), setItemParameter()
+*/
+
+bool QMenuData::connectItem( int id, const QObject *receiver,
+ const char* member )
+{
+ QMenuItem *mi = findItem( id );
+ if ( !mi ) // no such identifier
+ return FALSE;
+ if ( !mi->signal_data ) { // create new signal
+ mi->signal_data = new QSignal;
+ Q_CHECK_PTR( mi->signal_data );
+ mi->signal_data->setValue( id );
+ }
+ return mi->signal_data->connect( receiver, member );
+}
+
+
+/*!
+ Disconnects the \a{receiver}'s \a member from the menu item with
+ identifier \a id.
+
+ All connections are removed when the menu data object is
+ destroyed.
+
+ \sa connectItem(), setItemParameter()
+*/
+
+bool QMenuData::disconnectItem( int id, const QObject *receiver,
+ const char* member )
+{
+ QMenuItem *mi = findItem( id );
+ if ( !mi || !mi->signal_data ) // no identifier or no signal
+ return FALSE;
+ return mi->signal_data->disconnect( receiver, member );
+}
+
+/*!
+ Sets \a text as What's This help for the menu item with identifier
+ \a id.
+
+ \sa whatsThis()
+*/
+void QMenuData::setWhatsThis( int id, const QString& text )
+{
+
+ QMenuData *parent;
+ QMenuItem *mi = findItem( id, &parent );
+ if ( mi ) {
+ mi->setWhatsThis( text );
+ parent->menuContentsChanged();
+ }
+}
+
+/*!
+ Returns the What's This help text for the item with identifier \a
+ id or QString::null if no text has yet been defined.
+
+ \sa setWhatsThis()
+*/
+QString QMenuData::whatsThis( int id ) const
+{
+
+ QMenuItem *mi = findItem( id );
+ return mi? mi->whatsThis() : QString::null;
+}
+
+
+
+/*!
+ \class QCustomMenuItem qmenudata.h
+ \brief The QCustomMenuItem class is an abstract base class for custom menu items in popup menus.
+
+ \ingroup misc
+
+ A custom menu item is a menu item that is defined by two pure
+ virtual functions, paint() and sizeHint(). The size hint tells the
+ menu how much space it needs to reserve for this item, and paint
+ is called whenever the item needs painting.
+
+ This simple mechanism allows you to create all kinds of
+ application specific menu items. Examples are items showing
+ different fonts in a word processor or menus that allow the
+ selection of drawing utilities in a vector drawing program.
+
+ A custom item is inserted into a popup menu with
+ QPopupMenu::insertItem().
+
+ By default, a custom item can also have an icon and a keyboard
+ accelerator. You can reimplement fullSpan() to return TRUE if you
+ want the item to span the entire popup menu width. This is
+ particularly useful for labels.
+
+ If you want the custom item to be treated just as a separator,
+ reimplement isSeparator() to return TRUE.
+
+ Note that you can insert pixmaps or bitmaps as items into a popup
+ menu without needing to create a QCustomMenuItem. However, custom
+ menu items offer more flexibility, and -- especially important
+ with Windows style -- provide the possibility of drawing the item
+ with a different color when it is highlighted.
+
+ \link menu-example.html menu/menu.cpp\endlink shows a simple
+ example how custom menu items can be used.
+
+ Note: the current implementation of QCustomMenuItem will not
+ recognize shortcut keys that are from text with ampersands. Normal
+ accelerators work though.
+
+ <img src=qpopmenu-fancy.png>
+
+ \sa QMenuData, QPopupMenu
+*/
+
+
+
+/*!
+ Constructs a QCustomMenuItem
+*/
+QCustomMenuItem::QCustomMenuItem()
+{
+}
+
+/*!
+ Destroys a QCustomMenuItem
+*/
+QCustomMenuItem::~QCustomMenuItem()
+{
+}
+
+
+/*!
+ Sets the font of the custom menu item to \a font.
+
+ This function is called whenever the font in the popup menu
+ changes. For menu items that show their own individual font entry,
+ you want to ignore this.
+*/
+void QCustomMenuItem::setFont( const QFont& /* font */ )
+{
+}
+
+
+
+/*!
+ Returns TRUE if this item wants to span the entire popup menu
+ width; otherwise returns FALSE. The default is FALSE, meaning that
+ the menu may show an icon and an accelerator key for this item as
+ well.
+*/
+bool QCustomMenuItem::fullSpan() const
+{
+ return FALSE;
+}
+
+/*!
+ Returns TRUE if this item is just a separator; otherwise returns
+ FALSE.
+*/
+bool QCustomMenuItem::isSeparator() const
+{
+ return FALSE;
+}
+
+
+/*!
+ \fn void QCustomMenuItem::paint( QPainter* p, const QColorGroup& cg, bool act, bool enabled, int x, int y, int w, int h );
+
+ Paints this item. When this function is invoked, the painter \a p
+ is set to a font and foreground color suitable for a menu item
+ text using color group \a cg. The item is active if \a act is TRUE
+ and enabled if \a enabled is TRUE. The geometry values \a x, \a y,
+ \a w and \a h specify where to draw the item.
+
+ Do not draw any background, this has already been done by the
+ popup menu according to the current GUI style.
+*/
+
+
+/*!
+ \fn QSize QCustomMenuItem::sizeHint();
+
+ Returns the item's size hint.
+*/
+
+
+
+/*!
+ Activates the menu item at position \a index.
+
+ If the index is invalid (for example, -1), the object itself is
+ deactivated.
+*/
+void QMenuData::activateItemAt( int index )
+{
+#ifndef QT_NO_MENUBAR
+ if ( isMenuBar )
+ ( (QMenuBar*)this )->activateItemAt( index );
+ else
+#endif
+ {
+#ifndef QT_NO_POPUPMENU
+ if ( isPopupMenu )
+ ( (QPopupMenu*)this )->activateItemAt( index );
+#endif
+ }
+}
+
+#endif
diff --git a/src/widgets/qmenudata.h b/src/widgets/qmenudata.h
new file mode 100644
index 0000000..13f26c3
--- /dev/null
+++ b/src/widgets/qmenudata.h
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Definition of QMenuData class
+**
+** Created : 941128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QMENUDATA_H
+#define QMENUDATA_H
+
+#ifndef QT_H
+#include "qglobal.h"
+#include "qiconset.h" // conversion QPixmap->QIconset
+#include "qkeysequence.h"
+#include "qstring.h"
+#include "qsignal.h"
+#include "qfont.h"
+#endif // QT_H
+
+#ifndef QT_NO_MENUDATA
+
+class QPopupMenu;
+class QMenuDataData;
+class QObject;
+
+class QCustomMenuItem;
+class QMenuItemData;
+
+class Q_EXPORT QMenuItem // internal menu item class
+{
+friend class QMenuData;
+public:
+ QMenuItem();
+ ~QMenuItem();
+
+ int id() const { return ident; }
+ QIconSet *iconSet() const { return iconset_data; }
+ QString text() const { return text_data; }
+ QString whatsThis() const { return whatsthis_data; }
+ QPixmap *pixmap() const { return pixmap_data; }
+ QPopupMenu *popup() const { return popup_menu; }
+ QWidget *widget() const { return widget_item; }
+ QCustomMenuItem *custom() const;
+#ifndef QT_NO_ACCEL
+ QKeySequence key() const { return accel_key; }
+#endif
+ QSignal *signal() const { return signal_data; }
+ bool isSeparator() const { return is_separator; }
+ bool isEnabled() const { return is_enabled; }
+ bool isChecked() const { return is_checked; }
+ bool isDirty() const { return is_dirty; }
+ bool isVisible() const { return is_visible; }
+ bool isEnabledAndVisible() const { return is_enabled && is_visible; }
+
+ void setText( const QString &text ) { text_data = text; }
+ void setDirty( bool dirty ) { is_dirty = dirty; }
+ void setVisible( bool visible ) { is_visible = visible; }
+ void setWhatsThis( const QString &text ) { whatsthis_data = text; }
+
+private:
+ int ident; // item identifier
+ QIconSet *iconset_data; // icons
+ QString text_data; // item text
+ QString whatsthis_data; // item Whats This help text
+ QPixmap *pixmap_data; // item pixmap
+ QPopupMenu *popup_menu; // item popup menu
+ QWidget *widget_item; // widget menu item
+#ifndef QT_NO_ACCEL
+ QKeySequence accel_key; // accelerator key (state|ascii)
+#endif
+ QSignal *signal_data; // connection
+ uint is_separator : 1; // separator flag
+ uint is_enabled : 1; // disabled flag
+ uint is_checked : 1; // checked flag
+ uint is_dirty : 1; // dirty (update) flag
+ uint is_visible : 1; // visibility flag
+ QMenuItemData* d;
+
+ QMenuItemData* extra();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QMenuItem( const QMenuItem & );
+ QMenuItem &operator=( const QMenuItem & );
+#endif
+};
+
+#include "qptrlist.h"
+typedef QPtrList<QMenuItem> QMenuItemList;
+typedef QPtrListIterator<QMenuItem> QMenuItemListIt;
+
+
+class Q_EXPORT QCustomMenuItem : public Qt
+{
+public:
+ QCustomMenuItem();
+ virtual ~QCustomMenuItem();
+ virtual bool fullSpan() const;
+ virtual bool isSeparator() const;
+ virtual void setFont( const QFont& font );
+ virtual void paint( QPainter* p, const QColorGroup& cg, bool act,
+ bool enabled, int x, int y, int w, int h ) = 0;
+ virtual QSize sizeHint() = 0;
+};
+
+
+class Q_EXPORT QMenuData // menu data class
+{
+friend class QMenuBar;
+friend class QPopupMenu;
+public:
+ QMenuData();
+ virtual ~QMenuData();
+
+ uint count() const;
+
+
+ int insertItem( const QString &text,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel = 0, int id = -1, int index = -1 );
+ int insertItem( const QIconSet& icon,
+ const QString &text,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel = 0, int id = -1, int index = -1 );
+ int insertItem( const QPixmap &pixmap,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel = 0, int id = -1, int index = -1 );
+ int insertItem( const QIconSet& icon,
+ const QPixmap &pixmap,
+ const QObject *receiver, const char* member,
+ const QKeySequence& accel = 0, int id = -1, int index = -1 );
+
+ int insertItem( const QString &text, int id=-1, int index=-1 );
+ int insertItem( const QIconSet& icon,
+ const QString &text, int id=-1, int index=-1 );
+
+ int insertItem( const QString &text, QPopupMenu *popup,
+ int id=-1, int index=-1 );
+ int insertItem( const QIconSet& icon,
+ const QString &text, QPopupMenu *popup,
+ int id=-1, int index=-1 );
+
+
+ int insertItem( const QPixmap &pixmap, int id=-1, int index=-1 );
+ int insertItem( const QIconSet& icon,
+ const QPixmap &pixmap, int id=-1, int index=-1 );
+ int insertItem( const QPixmap &pixmap, QPopupMenu *popup,
+ int id=-1, int index=-1 );
+ int insertItem( const QIconSet& icon,
+ const QPixmap &pixmap, QPopupMenu *popup,
+ int id=-1, int index=-1 );
+
+ int insertItem( QWidget* widget, int id=-1, int index=-1 );
+
+ int insertItem( const QIconSet& icon, QCustomMenuItem* custom, int id=-1, int index=-1 );
+ int insertItem( QCustomMenuItem* custom, int id=-1, int index=-1 );
+
+
+ int insertSeparator( int index=-1 );
+
+ void removeItem( int id );
+ void removeItemAt( int index );
+ void clear();
+
+#ifndef QT_NO_ACCEL
+ QKeySequence accel( int id ) const;
+ void setAccel( const QKeySequence& key, int id );
+#endif
+
+ QIconSet *iconSet( int id ) const;
+ QString text( int id ) const;
+ QPixmap *pixmap( int id ) const;
+
+ void setWhatsThis( int id, const QString& );
+ QString whatsThis( int id ) const;
+
+
+ void changeItem( int id, const QString &text );
+ void changeItem( int id, const QPixmap &pixmap );
+ void changeItem( int id, const QIconSet &icon, const QString &text );
+ void changeItem( int id, const QIconSet &icon, const QPixmap &pixmap );
+
+ void changeItem( const QString &text, int id ) { changeItem( id, text); } // obsolete
+ void changeItem( const QPixmap &pixmap, int id ) { changeItem( id, pixmap ); } // obsolete
+ void changeItem( const QIconSet &icon, const QString &text, int id ) { // obsolete
+ changeItem( id, icon, text );
+ }
+
+ bool isItemActive( int id ) const;
+
+ bool isItemEnabled( int id ) const;
+ void setItemEnabled( int id, bool enable );
+
+ bool isItemChecked( int id ) const;
+ void setItemChecked( int id, bool check );
+
+ bool isItemVisible( int id ) const;
+ void setItemVisible( int id, bool visible );
+
+ virtual void updateItem( int id );
+
+ int indexOf( int id ) const;
+ int idAt( int index ) const;
+ virtual void setId( int index, int id );
+
+ bool connectItem( int id,
+ const QObject *receiver, const char* member );
+ bool disconnectItem( int id,
+ const QObject *receiver, const char* member );
+
+ bool setItemParameter( int id, int param );
+ int itemParameter( int id ) const;
+
+ QMenuItem *findItem( int id ) const;
+ QMenuItem *findItem( int id, QMenuData ** parent ) const;
+ QMenuItem * findPopup( QPopupMenu *, int *index = 0 );
+
+ virtual void activateItemAt( int index );
+
+protected:
+ int actItem;
+ QMenuItemList *mitems;
+ QMenuData *parentMenu;
+ uint isPopupMenu : 1;
+ uint isMenuBar : 1;
+ uint badSize : 1;
+ uint mouseBtDn : 1;
+ uint avoid_circularity : 1;
+ uint actItemDown : 1;
+ virtual void menuContentsChanged();
+ virtual void menuStateChanged();
+ virtual void menuInsPopup( QPopupMenu * );
+ virtual void menuDelPopup( QPopupMenu * );
+
+private:
+ int insertAny( const QString *, const QPixmap *, QPopupMenu *,
+ const QIconSet*, int, int, QWidget* = 0, QCustomMenuItem* = 0);
+ void removePopup( QPopupMenu * );
+ void changeItemIconSet( int id, const QIconSet &icon );
+
+ QMenuDataData *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QMenuData( const QMenuData & );
+ QMenuData &operator=( const QMenuData & );
+#endif
+};
+
+
+#endif // QT_NO_MENUDATA
+
+#endif // QMENUDATA_H
diff --git a/src/widgets/qmultilineedit.cpp b/src/widgets/qmultilineedit.cpp
new file mode 100644
index 0000000..2cead2c
--- /dev/null
+++ b/src/widgets/qmultilineedit.cpp
@@ -0,0 +1,541 @@
+/**********************************************************************
+**
+** Implementation of QMultiLineEdit widget class
+**
+** Created : 961005
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qmultilineedit.h"
+#ifndef QT_NO_MULTILINEEDIT
+#include "qpainter.h"
+#include "qscrollbar.h"
+#include "qcursor.h"
+#include "qclipboard.h"
+#include "qpixmap.h"
+#include "qregexp.h"
+#include "qapplication.h"
+#include "qdragobject.h"
+#include "qpopupmenu.h"
+#include "qtimer.h"
+#include "qdict.h"
+#include "../kernel/qrichtext_p.h"
+
+
+/*!
+ \class QMultiLineEdit qmultilineedit.h
+ \obsolete
+
+ \brief The QMultiLineEdit widget is a simple editor for inputting text.
+
+ \ingroup advanced
+
+ The QMultiLineEdit was a simple editor widget in former Qt versions. Qt
+ 3.0 includes a new richtext engine which obsoletes QMultiLineEdit. It is
+ still included for compatibility reasons. It is now a subclass of
+ \l QTextEdit, and provides enough of the old QMultiLineEdit API to keep old
+ applications working.
+
+ If you implement something new with QMultiLineEdit, we suggest using
+ \l QTextEdit instead and call QTextEdit::setTextFormat(Qt::PlainText).
+
+ Although most of the old QMultiLineEdit API is still available, there is
+ a few difference. The old QMultiLineEdit operated on lines, not on
+ paragraphs. As lines change all the time during wordwrap, the new
+ richtext engine uses paragraphs as basic elements in the data structure.
+ All functions (numLines(), textLine(), etc.) that operated on lines, now
+ operate on paragraphs. Further, getString() has been removed completely.
+ It revealed too much of the internal data structure.
+
+ Applications which made normal and reasonable use of QMultiLineEdit
+ should still work without problems. Some odd usage will require some
+ porting. In these cases, it may be better to use \l QTextEdit now.
+
+ <img src=qmlined-m.png> <img src=qmlined-w.png>
+
+ \sa QTextEdit
+*/
+
+/*!
+ \fn bool QMultiLineEdit::autoUpdate() const
+ \obsolete
+*/
+
+/*!
+ \fn virtual void QMultiLineEdit::setAutoUpdate( bool )
+ \obsolete
+*/
+
+/*!
+ \fn int QMultiLineEdit::totalWidth() const
+ \obsolete
+*/
+
+/*!
+ \fn int QMultiLineEdit::totalHeight() const
+ \obsolete
+*/
+
+/*!
+ \fn int QMultiLineEdit::maxLines() const
+ \obsolete
+*/
+
+/*!
+ \fn void QMultiLineEdit::setMaxLines( int )
+ \obsolete
+*/
+
+/*!
+ \fn void QMultiLineEdit::deselect()
+ \obsolete
+*/
+
+
+class QMultiLineEditData
+{
+};
+
+
+/*!
+ Constructs a new, empty, QMultiLineEdit with parent \a parent called
+ \a name.
+*/
+
+QMultiLineEdit::QMultiLineEdit( QWidget *parent , const char *name )
+ : QTextEdit( parent, name )
+{
+ d = new QMultiLineEditData;
+ setTextFormat( Qt::PlainText );
+}
+
+/*! \property QMultiLineEdit::numLines
+ \brief the number of paragraphs in the editor
+
+ The count includes any empty paragraph at top and bottom, so for an
+ empty editor this method returns 1.
+*/
+
+int QMultiLineEdit::numLines() const
+{
+ return document()->lastParagraph()->paragId() + 1;
+}
+
+/*! \property QMultiLineEdit::atEnd
+ \brief whether the cursor is placed at the end of the text
+
+ \sa atBeginning
+*/
+
+bool QMultiLineEdit::atEnd() const
+{
+ return textCursor()->paragraph() == document()->lastParagraph() && textCursor()->atParagEnd();
+}
+
+
+/*! \property QMultiLineEdit::atBeginning
+ \brief whether the cursor is placed at the beginning of the text
+
+ \sa atEnd
+*/
+
+bool QMultiLineEdit::atBeginning() const
+{
+ return textCursor()->paragraph() == document()->firstParagraph() && textCursor()->atParagStart();
+}
+
+/*! Returns the number of characters at paragraph number \a row. If
+ \a row is out of range, -1 is returned.
+*/
+
+int QMultiLineEdit::lineLength( int row ) const
+{
+ if ( row < 0 || row > numLines() )
+ return -1;
+ return document()->paragAt( row )->length() - 1;
+}
+
+
+/*! \reimp */
+
+QMultiLineEdit::~QMultiLineEdit()
+{
+ delete d;
+}
+
+/*!
+ If there is selected text, sets \a line1, \a col1, \a line2 and \a col2
+ to the start and end of the selected region and returns TRUE. Returns
+ FALSE if there is no selected text.
+ */
+bool QMultiLineEdit::getMarkedRegion( int *line1, int *col1,
+ int *line2, int *col2 ) const
+{
+ int p1,c1, p2, c2;
+ getSelection( &p1, &c1, &p2, &c2 );
+ if ( p1 == -1 && c1 == -1 && p2 == -1 && c2 == -1 )
+ return FALSE;
+ if ( line1 )
+ *line1 = p1;
+ if ( col1 )
+ *col1 = c1;
+ if ( line2 )
+ *line2 = p2;
+ if ( col2 )
+ *col2 = c2;
+ return TRUE;
+}
+
+
+/*!
+ Returns TRUE if there is selected text.
+*/
+
+bool QMultiLineEdit::hasMarkedText() const
+{
+ return hasSelectedText();
+}
+
+
+/*!
+ Returns a copy of the selected text.
+*/
+
+QString QMultiLineEdit::markedText() const
+{
+ return selectedText();
+}
+
+/*!
+ Moves the cursor one page down. If \a mark is TRUE, the text
+ is selected.
+*/
+
+void QMultiLineEdit::pageDown( bool mark )
+{
+ moveCursor( MoveDown, mark );
+}
+
+
+/*!
+ Moves the cursor one page up. If \a mark is TRUE, the text
+ is selected.
+*/
+
+void QMultiLineEdit::pageUp( bool mark )
+{
+ moveCursor( MovePgUp, mark );
+}
+
+
+/*! Inserts \a txt at paragraph number \a line. If \a line is less
+ than zero, or larger than the number of paragraphs, the new text is
+ put at the end. If \a txt contains newline characters, several
+ paragraphs are inserted.
+
+ The cursor position is not changed.
+*/
+
+void QMultiLineEdit::insertLine( const QString &txt, int line )
+{
+ insertParagraph( txt, line );
+}
+
+/*! Deletes the paragraph at paragraph number \a paragraph. If \a
+ paragraph is less than zero or larger than the number of paragraphs,
+ nothing is deleted.
+*/
+
+void QMultiLineEdit::removeLine( int paragraph )
+{
+ removeParagraph( paragraph );
+}
+
+/*! Inserts \a str at the current cursor position and selects the
+ text if \a mark is TRUE.
+*/
+
+void QMultiLineEdit::insertAndMark( const QString& str, bool mark )
+{
+ insert( str );
+ if ( mark )
+ document()->setSelectionEnd( QTextDocument::Standard, *textCursor() );
+}
+
+/*! Splits the paragraph at the current cursor position.
+*/
+
+void QMultiLineEdit::newLine()
+{
+ insert( "\n" );
+}
+
+
+/*! Deletes the character on the left side of the text cursor and
+ moves the cursor one position to the left. If a text has been selected
+ by the user (e.g. by clicking and dragging) the cursor is put at the
+ beginning of the selected text and the selected text is removed. \sa
+ del()
+*/
+
+void QMultiLineEdit::backspace()
+{
+ if ( document()->hasSelection( QTextDocument::Standard ) ) {
+ removeSelectedText();
+ return;
+ }
+
+ if ( !textCursor()->paragraph()->prev() &&
+ textCursor()->atParagStart() )
+ return;
+
+ doKeyboardAction( ActionBackspace );
+}
+
+
+/*! Moves the text cursor to the left end of the line. If \a mark is
+ TRUE, text is selected toward the first position. If it is FALSE and the
+ cursor is moved, all selected text is unselected.
+
+ \sa end()
+*/
+
+void QMultiLineEdit::home( bool mark )
+{
+ moveCursor( MoveLineStart, mark );
+}
+
+/*! Moves the text cursor to the right end of the line. If \a mark is
+ TRUE, text is selected toward the last position. If it is FALSE and the
+ cursor is moved, all selected text is unselected.
+
+ \sa home()
+*/
+
+void QMultiLineEdit::end( bool mark )
+{
+ moveCursor( MoveLineEnd, mark );
+}
+
+
+/*!
+ \fn void QMultiLineEdit::setCursorPosition( int line, int col )
+ \reimp
+*/
+
+/*! Sets the cursor position to character number \a col in paragraph
+ number \a line. The parameters are adjusted to lie within the legal
+ range.
+
+ If \a mark is FALSE, the selection is cleared. otherwise it is extended.
+
+*/
+
+void QMultiLineEdit::setCursorPosition( int line, int col, bool mark )
+{
+ if ( !mark )
+ selectAll( FALSE );
+ QTextEdit::setCursorPosition( line, col );
+ if ( mark )
+ document()->setSelectionEnd( QTextDocument::Standard, *textCursor() );
+}
+
+/*! Returns the top center point where the cursor is drawn.
+*/
+
+QPoint QMultiLineEdit::cursorPoint() const
+{
+ return QPoint( textCursor()->x(), textCursor()->y() + textCursor()->paragraph()->rect().y() );
+}
+
+/*! \property QMultiLineEdit::alignment
+ \brief The editor's paragraph alignment
+
+ Sets the alignment to flag, which must be \c AlignLeft, \c
+ AlignHCenter or \c AlignRight.
+
+ If flag is an illegal flag nothing happens.
+
+ \sa Qt::AlignmentFlags
+*/
+void QMultiLineEdit::setAlignment( int flag )
+{
+ if ( flag == AlignCenter )
+ flag = AlignHCenter;
+ if ( flag != AlignLeft && flag != AlignRight && flag != AlignHCenter )
+ return;
+ QTextParagraph *p = document()->firstParagraph();
+ while ( p ) {
+ p->setAlignment( flag );
+ p = p->next();
+ }
+}
+
+int QMultiLineEdit::alignment() const
+{
+ return document()->firstParagraph()->alignment();
+}
+
+
+void QMultiLineEdit::setEdited( bool e )
+{
+ setModified( e );
+}
+
+/*! \property QMultiLineEdit::edited
+ \brief whether the document has been edited by the user
+
+ This is the same as QTextEdit's "modifed" property.
+
+ \sa QTextEdit::modified
+*/
+bool QMultiLineEdit::edited() const
+{
+ return isModified();
+}
+
+/*! Moves the cursor one word to the right. If \a mark is TRUE, the text
+ is selected.
+
+ \sa cursorWordBackward()
+*/
+void QMultiLineEdit::cursorWordForward( bool mark )
+{
+ moveCursor( MoveWordForward, mark );
+}
+
+/*! Moves the cursor one word to the left. If \a mark is TRUE, the
+ text is selected.
+
+ \sa cursorWordForward()
+*/
+void QMultiLineEdit::cursorWordBackward( bool mark )
+{
+ moveCursor( MoveWordBackward, mark );
+}
+
+/*!
+ \fn QMultiLineEdit::insertAt( const QString &s, int line, int col )
+ \reimp
+*/
+
+/*! Inserts string \a s at paragraph number \a line, after character
+ number \a col in the paragraph. If \a s contains newline
+ characters, new lines are inserted.
+ If \a mark is TRUE the inserted string will be selected.
+
+ The cursor position is adjusted.
+ */
+
+void QMultiLineEdit::insertAt( const QString &s, int line, int col, bool mark )
+{
+ QTextEdit::insertAt( s, line, col );
+ if ( mark )
+ setSelection( line, col, line, col + s.length() );
+}
+
+// ### reggie - is this documentation correct?
+
+/*! Deletes text from the current cursor position to the end of the
+ line. (Note that this function still operates on lines, not paragraphs.)
+*/
+
+void QMultiLineEdit::killLine()
+{
+ doKeyboardAction( ActionKill );
+}
+
+/*! Moves the cursor one character to the left. If \a mark is TRUE,
+ the text is selected.
+ The \a wrap parameter is currently ignored.
+
+ \sa cursorRight() cursorUp() cursorDown()
+*/
+
+void QMultiLineEdit::cursorLeft( bool mark, bool )
+{
+ moveCursor( MoveBackward, mark );
+}
+
+/*! Moves the cursor one character to the right. If \a mark is TRUE,
+ the text is selected.
+ The \a wrap parameter is currently ignored.
+
+ \sa cursorLeft() cursorUp() cursorDown()
+*/
+
+void QMultiLineEdit::cursorRight( bool mark, bool )
+{
+ moveCursor( MoveForward, mark );
+}
+
+/*! Moves the cursor up one line. If \a mark is TRUE, the text is
+ selected.
+
+ \sa cursorDown() cursorLeft() cursorRight()
+*/
+
+void QMultiLineEdit::cursorUp( bool mark )
+{
+ moveCursor( MoveUp, mark );
+}
+
+/*!
+ Moves the cursor one line down. If \a mark is TRUE, the text
+ is selected.
+ \sa cursorUp() cursorLeft() cursorRight()
+*/
+
+void QMultiLineEdit::cursorDown( bool mark )
+{
+ moveCursor( MoveDown, mark );
+}
+
+
+/*! Returns the text at line number \a line (possibly the empty
+ string), or a \link QString::operator!() null string\endlink if \a
+ line is invalid.
+*/
+
+QString QMultiLineEdit::textLine( int line ) const
+{
+ if ( line < 0 || line >= numLines() )
+ return QString::null;
+ QString str = document()->paragAt( line )->string()->toString();
+ str.truncate( str.length() - 1 );
+ return str;
+}
+
+#endif
diff --git a/src/widgets/qmultilineedit.h b/src/widgets/qmultilineedit.h
new file mode 100644
index 0000000..48e2742
--- /dev/null
+++ b/src/widgets/qmultilineedit.h
@@ -0,0 +1,141 @@
+/**********************************************************************
+**
+** Definition of QMultiLineEdit widget class
+**
+** Created : 961005
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QMULTILINEEDIT_H
+#define QMULTILINEEDIT_H
+
+#ifndef QT_H
+#include "qtextedit.h"
+#endif // QT_H
+
+#ifndef QT_NO_MULTILINEEDIT
+
+class QMultiLineEditCommand;
+class QValidator;
+class QMultiLineEditData;
+
+class Q_EXPORT QMultiLineEdit : public QTextEdit
+{
+ Q_OBJECT
+ Q_PROPERTY( int numLines READ numLines )
+ Q_PROPERTY( bool atBeginning READ atBeginning )
+ Q_PROPERTY( bool atEnd READ atEnd )
+ Q_PROPERTY( Alignment alignment READ alignment WRITE setAlignment )
+ Q_PROPERTY( bool edited READ edited WRITE setEdited DESIGNABLE false )
+
+public:
+ QMultiLineEdit( QWidget* parent=0, const char* name=0 );
+ ~QMultiLineEdit();
+
+ QString textLine( int line ) const;
+ int numLines() const;
+
+ virtual void insertLine( const QString &s, int line = -1 );
+ virtual void insertAt( const QString &s, int line, int col ) {
+ insertAt( s, line, col, FALSE );
+ }
+ virtual void insertAt( const QString &s, int line, int col, bool mark );
+ virtual void removeLine( int line );
+ virtual void setCursorPosition( int line, int col ) {
+ setCursorPosition( line, col, FALSE );
+ }
+ virtual void setCursorPosition( int line, int col, bool mark );
+ bool atBeginning() const;
+ bool atEnd() const;
+
+ void setAlignment( int flags );
+ int alignment() const;
+
+ void setEdited( bool );
+ bool edited() const;
+
+ bool hasMarkedText() const;
+ QString markedText() const;
+
+ void cursorWordForward( bool mark );
+ void cursorWordBackward( bool mark );
+
+ // noops
+ bool autoUpdate() const { return TRUE; }
+ virtual void setAutoUpdate( bool ) {}
+
+ int totalWidth() const { return contentsWidth(); }
+ int totalHeight() const { return contentsHeight(); }
+
+ int maxLines() const { return QWIDGETSIZE_MAX; }
+ void setMaxLines( int ) {}
+
+public slots:
+ void deselect() { selectAll( FALSE ); }
+
+protected:
+ QPoint cursorPoint() const;
+
+protected:
+ virtual void insertAndMark( const QString&, bool mark );
+ virtual void newLine();
+ virtual void killLine();
+ virtual void pageUp( bool mark=FALSE );
+ virtual void pageDown( bool mark=FALSE );
+ virtual void cursorLeft( bool mark=FALSE, bool wrap = TRUE );
+ virtual void cursorRight( bool mark=FALSE, bool wrap = TRUE );
+ virtual void cursorUp( bool mark=FALSE );
+ virtual void cursorDown( bool mark=FALSE );
+ virtual void backspace();
+ virtual void home( bool mark=FALSE );
+ virtual void end( bool mark=FALSE );
+
+ bool getMarkedRegion( int *line1, int *col1,
+ int *line2, int *col2 ) const;
+ int lineLength( int row ) const;
+
+private:
+ QMultiLineEditData *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QMultiLineEdit( const QMultiLineEdit & );
+ QMultiLineEdit &operator=( const QMultiLineEdit & );
+#endif
+};
+
+#endif // QT_NO_MULTILINEEDIT
+
+#endif // QMULTILINED_H
diff --git a/src/widgets/qpopupmenu.cpp b/src/widgets/qpopupmenu.cpp
new file mode 100644
index 0000000..9e1e01c
--- /dev/null
+++ b/src/widgets/qpopupmenu.cpp
@@ -0,0 +1,2886 @@
+/****************************************************************************
+**
+** Implementation of QPopupMenu class
+**
+** Created : 941128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qpopupmenu.h"
+#ifndef QT_NO_POPUPMENU
+#include "qmenubar.h"
+#include "qaccel.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qapplication.h"
+#include "qpixmap.h"
+#include "qpixmapcache.h"
+#include "qtimer.h"
+#include "qwhatsthis.h"
+#include "qobjectlist.h"
+#include "qguardedptr.h"
+#include "qeffects_p.h"
+#include "qcursor.h"
+#include "qstyle.h"
+#include "qtimer.h"
+#include "qdatetime.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+//#define ANIMATED_POPUP
+//#define BLEND_POPUP
+
+// Motif style parameters
+
+static const int motifArrowHMargin = 6; // arrow horizontal margin
+static const int motifArrowVMargin = 2; // arrow vertical margin
+
+static const int gtkArrowHMargin = 0; // arrow horizontal margin
+static const int gtkArrowVMargin = 0; // arrow vertical margin
+
+/*
+
++-----------------------------
+| PopupFrame
+| +-------------------------
+| | ItemFrame
+| | +---------------------
+| | |
+| | | \
+| | | ^ T E X T ^ | ItemVMargin
+| | | | | /
+| | ItemHMargin
+|
+
+*/
+
+#if 0
+# define DEBUG_SLOPPY_SUBMENU
+#endif
+
+// used for internal communication
+static QPopupMenu * syncMenu = 0;
+static int syncMenuId = 0;
+
+// Used to detect motion prior to mouse-release
+static int motion;
+
+// used to provide ONE single-shot timer
+static QTimer * singleSingleShot = 0;
+
+static bool supressAboutToShow = FALSE;
+
+static void cleanup()
+{
+ delete singleSingleShot;
+ singleSingleShot = 0;
+}
+
+static void popupSubMenuLater( int msec, QPopupMenu * receiver ) {
+ if ( !singleSingleShot ) {
+ singleSingleShot = new QTimer( qApp, "popup submenu timer" );
+ qAddPostRoutine( cleanup );
+ }
+
+ singleSingleShot->disconnect( SIGNAL(timeout()) );
+ QObject::connect( singleSingleShot, SIGNAL(timeout()),
+ receiver, SLOT(subMenuTimer()) );
+ singleSingleShot->start( msec, TRUE );
+}
+
+static bool preventAnimation = FALSE;
+
+#ifndef QT_NO_WHATSTHIS
+extern void qWhatsThisBDH();
+static QMenuItem* whatsThisItem = 0;
+#endif
+
+/*!
+ \class QPopupMenu qpopupmenu.h
+ \brief The QPopupMenu class provides a popup menu widget.
+
+ \ingroup application
+ \ingroup basic
+ \mainclass
+
+ A popup menu widget is a selection menu. It can be either a
+ pull-down menu in a menu bar or a standalone context (popup) 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::insertItem() to insert a popup menu into a menu bar.
+ Show a context menu either asynchronously with popup() or
+ synchronously with exec().
+
+ Technically, a popup menu consists of a list of menu items. You
+ add items with insertItem(). An item is either a string, a pixmap
+ or a custom item that provides its own drawing function (see
+ QCustomMenuItem). In addition, items can have an optional icon
+ drawn on the very left side and an accelerator key such as
+ "Ctrl+X".
+
+ There are three kinds of menu items: separators, menu items that
+ perform an action and menu items that show a submenu. Separators
+ are inserted with insertSeparator(). For submenus, you pass a
+ pointer to a QPopupMenu in your call to insertItem(). 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 selected.
+ In addition, QPopupMenu provides two signals, activated() and
+ highlighted(), which signal the identifier of the respective menu
+ item. It is sometimes practical to connect several items to one
+ slot. To distinguish between them, specify a slot that takes an
+ integer argument and use setItemParameter() to associate a unique
+ value with each item.
+
+ You clear a popup menu with clear() and remove single items with
+ removeItem() or removeItemAt().
+
+ A popup menu can display check marks for certain items when
+ enabled with setCheckable(TRUE). You check or uncheck items with
+ setItemChecked().
+
+ Items are either enabled or disabled. You toggle their state with
+ setItemEnabled(). Just before a popup menu becomes visible, it
+ emits the aboutToShow() signal. You can use this signal to set the
+ correct enabled/disabled states of all menu items before the user
+ sees it. The corresponding aboutToHide() signal is emitted when
+ the menu hides again.
+
+ You can provide What's This? help for single menu items with
+ setWhatsThis(). See QWhatsThis for general information about this
+ kind of lightweight online help.
+
+ For ultimate flexibility, you can also add entire widgets as items
+ into a popup menu (for example, a color selector).
+
+ A QPopupMenu 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
+ that functionality for a certain menu, insert a tear-off handle
+ with insertTearOffHandle(). When using tear-off menus, bear in
+ mind that the concept isn't typically used on Microsoft Windows so
+ users may not be familiar with it. Consider using a QToolBar
+ instead. Tear-off menus cannot contain custom widgets; if the
+ original menu contains a custom widget item, this item is omitted.
+
+ \link menu-example.html menu/menu.cpp\endlink is an example of
+ QMenuBar and QPopupMenu use.
+
+ \important insertItem removeItem removeItemAt clear text pixmap iconSet insertSeparator changeItem whatsThis setWhatsThis accel setAccel setItemEnabled isItemEnabled setItemVisible isItemVisible setItemChecked isItemChecked connectItem disconnectItem setItemParameter itemParameter
+
+ <img src=qpopmenu-m.png> <img src=qpopmenu-w.png>
+
+ \sa QMenuBar
+ \link guibooks.html#fowler GUI Design Handbook: Menu, Drop-Down and
+ Pop-Up\endlink
+*/
+
+
+/*!
+ \fn void QPopupMenu::aboutToShow()
+
+ This signal is emitted just before the popup menu is displayed.
+ You can connect it to any slot that sets up the menu contents
+ (e.g. to ensure that the right items are enabled).
+
+ \sa aboutToHide(), setItemEnabled(), setItemChecked(), insertItem(), removeItem()
+*/
+
+/*!
+ \fn void QPopupMenu::aboutToHide()
+
+ This signal is emitted just before the popup menu is hidden after
+ it has been displayed.
+
+ \warning Do not open a widget in a slot connected to this signal.
+
+ \sa aboutToShow(), setItemEnabled(), setItemChecked(), insertItem(), removeItem()
+*/
+
+
+
+/*****************************************************************************
+ QPopupMenu member functions
+ *****************************************************************************/
+
+class QMenuDataData {
+ // attention: also defined in qmenudata.cpp
+public:
+ QMenuDataData();
+ QGuardedPtr<QWidget> aWidget;
+ int aInt;
+};
+
+class QPopupMenuPrivate {
+public:
+ struct Scroll {
+ enum { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
+ uint scrollable : 2;
+ uint direction : 1;
+ int topScrollableIndex, scrollableSize;
+ QTime lastScroll;
+ QTimer *scrolltimer;
+ } scroll;
+ QSize calcSize;
+ QRegion mouseMoveBuffer;
+ uint hasmouse : 1;
+ QPoint ignoremousepos;
+};
+
+static QPopupMenu* active_popup_menu = 0;
+
+/*!
+ Constructs a popup menu called \a name 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).
+*/
+
+QPopupMenu::QPopupMenu( QWidget *parent, const char *name )
+ : QFrame( parent, name, WType_Popup | WNoAutoErase )
+{
+ d = new QPopupMenuPrivate;
+ d->scroll.scrollableSize = d->scroll.topScrollableIndex = 0;
+ d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ d->scroll.scrolltimer = 0;
+ d->hasmouse = 0;
+ isPopupMenu = TRUE;
+#ifndef QT_NO_ACCEL
+ autoaccel = 0;
+ accelDisabled = FALSE;
+#endif
+ popupActive = -1;
+ snapToMouse = TRUE;
+ tab = 0;
+ checkable = 0;
+ tornOff = 0;
+ pendingDelayedContentsChanges = 0;
+ pendingDelayedStateChanges = 0;
+ maxPMWidth = 0;
+
+ tab = 0;
+ ncols = 1;
+ setFrameStyle( QFrame::PopupPanel | QFrame::Raised );
+ setMouseTracking(style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this));
+ style().polishPopupMenu( this );
+ setBackgroundMode( PaletteButton );
+ connectModalRecursionSafety = 0;
+
+ setFocusPolicy( StrongFocus );
+#ifdef Q_WS_X11
+ x11SetWindowType( X11WindowTypePopup );
+#endif
+}
+
+/*!
+ Destroys the popup menu.
+*/
+
+QPopupMenu::~QPopupMenu()
+{
+ if ( syncMenu == this && qApp ) {
+ qApp->exit_loop();
+ syncMenu = 0;
+ }
+
+ if(d->scroll.scrolltimer)
+ delete d->scroll.scrolltimer;
+
+ if ( isVisible() ) {
+ parentMenu = 0;
+ hidePopups();
+ }
+
+ delete (QWidget*) QMenuData::d->aWidget; // tear-off menu
+
+ preventAnimation = FALSE;
+ delete d;
+}
+
+
+/*!
+ Updates the item with identity \a id.
+*/
+void QPopupMenu::updateItem( int id ) // update popup menu item
+{
+ updateRow( indexOf(id) );
+}
+
+
+void QPopupMenu::setCheckable( bool enable )
+{
+ if ( isCheckable() != enable ) {
+ checkable = enable;
+ badSize = TRUE;
+ if ( QMenuData::d->aWidget )
+ ( (QPopupMenu*)(QWidget*)QMenuData::d->aWidget)->setCheckable( enable );
+ }
+}
+
+/*!
+ \property QPopupMenu::checkable
+ \brief whether the display of check marks on menu items is enabled
+
+ When TRUE, the display of check marks on menu items is enabled.
+ Checking is always enabled when in Windows-style.
+
+ \sa QMenuData::setItemChecked()
+*/
+
+bool QPopupMenu::isCheckable() const
+{
+ return checkable;
+}
+
+void QPopupMenu::menuContentsChanged()
+{
+ // here the part that can't be delayed
+ QMenuData::menuContentsChanged();
+ badSize = TRUE; // might change the size
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ mac_dirty_popup = 1;
+#endif
+ if( pendingDelayedContentsChanges )
+ return;
+ pendingDelayedContentsChanges = 1;
+ if( !pendingDelayedStateChanges ) // if the timer hasn't been started yet
+ QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
+}
+
+void QPopupMenu::performDelayedContentsChanged()
+{
+ pendingDelayedContentsChanges = 0;
+ // here the part the can be delayed
+#ifndef QT_NO_ACCEL
+ // if performDelayedStateChanged() will be called too,
+ // it will call updateAccel() too, no need to do it twice
+ if( !pendingDelayedStateChanges )
+ updateAccel( 0 );
+#endif
+ if ( isVisible() ) {
+ if ( tornOff )
+ return;
+ updateSize(TRUE);
+ update();
+ }
+ QPopupMenu* p = (QPopupMenu*)(QWidget*)QMenuData::d->aWidget;
+ if ( p && p->isVisible() ) {
+ p->updateSize(TRUE);
+ p->update();
+ }
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ mac_dirty_popup = 1;
+#endif
+}
+
+
+void QPopupMenu::menuStateChanged()
+{
+ // here the part that can't be delayed
+ if( pendingDelayedStateChanges )
+ return;
+ pendingDelayedStateChanges = 1;
+ if( !pendingDelayedContentsChanges ) // if the timer hasn't been started yet
+ QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
+}
+
+void QPopupMenu::performDelayedStateChanged()
+{
+ pendingDelayedStateChanges = 0;
+ // here the part that can be delayed
+#ifndef QT_NO_ACCEL
+ updateAccel( 0 ); // ### when we have a good solution for the accel vs. focus widget problem, remove that. That is only a workaround
+ // if you remove this, see performDelayedContentsChanged()
+#endif
+ update();
+ if ( QMenuData::d->aWidget )
+ QMenuData::d->aWidget->update();
+}
+
+void QPopupMenu::performDelayedChanges()
+{
+ if( pendingDelayedContentsChanges )
+ performDelayedContentsChanged();
+ if( pendingDelayedStateChanges )
+ performDelayedStateChanged();
+}
+
+void QPopupMenu::menuInsPopup( QPopupMenu *popup )
+{
+ connect( popup, SIGNAL(activatedRedirect(int)),
+ SLOT(subActivated(int)) );
+ connect( popup, SIGNAL(highlightedRedirect(int)),
+ SLOT(subHighlighted(int)) );
+ connect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+}
+
+void QPopupMenu::menuDelPopup( QPopupMenu *popup )
+{
+ popup->disconnect( SIGNAL(activatedRedirect(int)) );
+ popup->disconnect( SIGNAL(highlightedRedirect(int)) );
+ disconnect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+}
+
+
+void QPopupMenu::frameChanged()
+{
+ menuContentsChanged();
+}
+
+QRect QPopupMenu::screenRect( const QPoint& pos )
+{
+ int screen_num = QApplication::desktop()->screenNumber( pos );
+#ifdef Q_WS_MAC
+ return QApplication::desktop()->availableGeometry( screen_num );
+#else
+ return QApplication::desktop()->screenGeometry( screen_num );
+#endif
+}
+/*!
+ Displays the popup menu so that the item number \a indexAtPoint
+ will be at the specified \e global position \a pos. To translate a
+ widget's local coordinates into global coordinates, use
+ QWidget::mapToGlobal().
+
+ When positioning a popup with exec() or popup(), bear in mind that
+ you cannot rely on the popup menu's current size(). For
+ performance reasons, the popup adapts its size only when
+ necessary, so in many cases, the size before and after the show is
+ different. Instead, use sizeHint(). It calculates the proper size
+ depending on the menu's current contents.
+*/
+
+void QPopupMenu::popup( const QPoint &pos, int indexAtPoint )
+{
+ if ( !isPopup() && isVisible() )
+ hide();
+
+ //avoid circularity
+ if ( isVisible() || !isEnabled() )
+ return;
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if( macPopupMenu(pos, indexAtPoint ))
+ return;
+#endif
+
+#if (QT_VERSION-0 >= 0x040000)
+#error "Fix this now"
+ // #### should move to QWidget - anything might need this functionality,
+ // #### since anything can have WType_Popup window flag.
+ // #### This includes stuff in QPushButton and some stuff for setting
+ // #### the geometry of QDialog.
+ // QPopupMenu
+ // ::exec()
+ // ::popup()
+ // QPushButton (shouldn't require QMenuPopup)
+ // ::popupPressed
+ // Some stuff in qwidget.cpp for dialogs... can't remember exactly.
+ // Also the code here indicatets the parameter should be a rect, not a
+ // point.
+#endif
+
+ QRect screen = screenRect( geometry().center());
+ QRect screen2 = screenRect( QApplication::reverseLayout()
+ ? pos+QPoint(width(),0) : pos );
+ // if the widget is not in the screen given by the position, move it
+ // there, so that updateSize() uses the right size of the screen
+ if( screen != screen2 ) {
+ screen = screen2;
+ move( screen.x(), screen.y());
+ }
+ if(d->scroll.scrollable) {
+ d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ d->scroll.topScrollableIndex = d->scroll.scrollableSize = 0;
+ badSize = TRUE;
+ }
+ updateSize();
+
+ QPoint mouse = QCursor::pos();
+ snapToMouse = pos == mouse;
+
+ // have to emit here as a menu might be setup in a slot connected
+ // to aboutToShow which will change the size of the menu
+ bool s = supressAboutToShow;
+ supressAboutToShow = TRUE;
+ if ( !s) {
+ emit aboutToShow();
+ updateSize(TRUE);
+ }
+
+ int sw = screen.width(); // screen width
+ int sh = screen.height(); // screen height
+ int sx = screen.x(); // screen pos
+ int sy = screen.y();
+ int x = pos.x();
+ int y = pos.y();
+ if ( indexAtPoint >= 0 ) // don't subtract when < 0
+ y -= itemGeometry( indexAtPoint ).y(); // (would subtract 2 pixels!)
+ int w = width();
+ int h = height();
+
+ if ( snapToMouse ) {
+ if ( qApp->reverseLayout() )
+ x -= w;
+ if ( x+w > sx+sw )
+ x = mouse.x()-w;
+ if ( y+h > sy+sh )
+ y = mouse.y()-h;
+ if ( x < sx )
+ x = mouse.x();
+ if ( y < sy )
+ y = sy;
+ }
+#ifdef Q_WS_X11
+#ifndef QT_NO_MENUBAR
+ QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+ if( top->isMenuBar )
+ x11SetWindowType( X11WindowTypeDropdown );
+ if( parentMenu && parentMenu->isMenuBar )
+ x11SetWindowTransient( static_cast< QMenuBar* >( parentMenu )->topLevelWidget());
+#endif
+ if( parentMenu && !parentMenu->isMenuBar )
+ x11SetWindowTransient( static_cast< QPopupMenu* >( parentMenu ));
+ if( !parentMenu ) {
+ // hackish ... try to find the main window related to this popup
+ QWidget* parent = parentWidget() ? parentWidget()->topLevelWidget() : NULL;
+ if( parent == NULL )
+ parent = QApplication::widgetAt( pos );
+ if( parent == NULL )
+ parent = qApp->activeWindow();
+ if( parent != NULL )
+ x11SetWindowTransient( parent );
+ }
+#endif
+
+ if ( x+w > sx+sw ) // the complete widget must
+ x = sx+sw - w; // be visible
+ if ( y+h > sy+sh )
+ y = sy+sh - h;
+ if ( x < sx )
+ x = sx;
+ if ( y < sy )
+ y = sy;
+
+ if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
+ int off_top = 0, off_bottom = 0;
+ if(y+h > sy+sh)
+ off_bottom = (y+h) - (sy+sh);
+ if(y < sy)
+ off_top = sy - y;
+ if(off_bottom || off_top) {
+ int ch = updateSize().height(); //store the old height, before setting scrollable --Sam
+ const int vextra = style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this);
+ d->scroll.scrollableSize = h - off_top - off_bottom - 2*vextra;
+ if(off_top) {
+ move( x, y = sy );
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollUp;
+ }
+ if( off_bottom )
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollDown;
+ if( off_top != off_bottom && indexAtPoint >= 0 ) {
+ ch -= (vextra * 2);
+ if(ch > sh) //no bigger than the screen!
+ ch = sh;
+ if( ch > d->scroll.scrollableSize )
+ d->scroll.scrollableSize = ch;
+ }
+
+ updateSize(TRUE); //now set the size using the scrollable/scrollableSize as above
+ w = width();
+ h = height();
+ if(indexAtPoint >= 0) {
+ if(off_top) { //scroll to it
+ register QMenuItem *mi = NULL;
+ QMenuItemListIt it(*mitems);
+ for(int tmp_y = 0; tmp_y < off_top && (mi=it.current()); ) {
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemHeight( mi )),
+ QStyleOption(mi,maxPMWidth,0));
+ tmp_y += sz.height();
+ d->scroll.topScrollableIndex++;
+ }
+ }
+ }
+ }
+ }
+ move( x, y );
+ motion=0;
+ actItem = -1;
+
+#ifndef QT_NO_EFFECTS
+ int hGuess = qApp->reverseLayout() ? QEffects::LeftScroll : QEffects::RightScroll;
+ int vGuess = QEffects::DownScroll;
+ if ( qApp->reverseLayout() ) {
+ if ( snapToMouse && ( x + w/2 > mouse.x() ) ||
+ ( parentMenu && parentMenu->isPopupMenu &&
+ ( x + w/2 > ((QPopupMenu*)parentMenu)->x() ) ) )
+ hGuess = QEffects::RightScroll;
+ } else {
+ if ( snapToMouse && ( x + w/2 < mouse.x() ) ||
+ ( parentMenu && parentMenu->isPopupMenu &&
+ ( x + w/2 < ((QPopupMenu*)parentMenu)->x() ) ) )
+ hGuess = QEffects::LeftScroll;
+ }
+
+#ifndef QT_NO_MENUBAR
+ if ( snapToMouse && ( y + h/2 < mouse.y() ) ||
+ ( parentMenu && parentMenu->isMenuBar &&
+ ( y + h/2 < ((QMenuBar*)parentMenu)->mapToGlobal( ((QMenuBar*)parentMenu)->pos() ).y() ) ) )
+ vGuess = QEffects::UpScroll;
+#endif
+
+ if ( QApplication::isEffectEnabled( UI_AnimateMenu ) &&
+ preventAnimation == FALSE ) {
+ if ( QApplication::isEffectEnabled( UI_FadeMenu ) )
+ qFadeEffect( this );
+ else if ( parentMenu )
+ qScrollEffect( this, parentMenu->isPopupMenu ? hGuess : vGuess );
+ else
+ qScrollEffect( this, hGuess | vGuess );
+ } else
+#endif
+ {
+ show();
+ }
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::PopupMenuStart );
+#endif
+}
+
+/*!
+ \fn void QPopupMenu::activated( int id )
+
+ This signal is emitted when a menu item is selected; \a id is the
+ id of the selected item.
+
+ Normally, you connect each menu item to a single slot using
+ QMenuData::insertItem(), 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 highlighted(), QMenuData::insertItem()
+*/
+
+/*!
+ \fn void QPopupMenu::highlighted( int id )
+
+ This signal is emitted when a menu item is highlighted; \a id is
+ the id of the highlighted item.
+
+ \sa activated(), QMenuData::insertItem()
+*/
+
+/*! \fn void QPopupMenu::highlightedRedirect( int id )
+ \internal
+ Used internally to connect submenus to their parents.
+*/
+
+/*! \fn void QPopupMenu::activatedRedirect( int id )
+ \internal
+ Used internally to connect submenus to their parents.
+*/
+
+void QPopupMenu::subActivated( int id )
+{
+ emit activatedRedirect( id );
+}
+
+void QPopupMenu::subHighlighted( int id )
+{
+ emit highlightedRedirect( id );
+}
+
+static bool fromAccel = FALSE;
+
+#ifndef QT_NO_ACCEL
+void QPopupMenu::accelActivated( int id )
+{
+ QMenuItem *mi = findItem( id );
+ if ( mi && mi->isEnabledAndVisible() ) {
+ QGuardedPtr<QSignal> signal = mi->signal();
+ fromAccel = TRUE;
+ actSig( mi->id() );
+ fromAccel = FALSE;
+ if ( signal )
+ signal->activate();
+ }
+}
+
+void QPopupMenu::accelDestroyed() // accel about to be deleted
+{
+ autoaccel = 0; // don't delete it twice!
+}
+#endif //QT_NO_ACCEL
+
+void QPopupMenu::popupDestroyed( QObject *o )
+{
+ removePopup( (QPopupMenu*)o );
+}
+
+void QPopupMenu::actSig( int id, bool inwhatsthis )
+{
+ if ( !inwhatsthis ) {
+ emit activated( id );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( !fromAccel )
+ QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::MenuCommand );
+#endif
+ } else {
+#ifndef QT_NO_WHATSTHIS
+ QRect r( itemGeometry( indexOf( id ) ) );
+ QPoint p( r.center().x(), r.bottom() );
+ QString whatsThis = findItem( id )->whatsThis();
+ if ( whatsThis.isNull() )
+ whatsThis = QWhatsThis::textFor( this, p );
+ QWhatsThis::leaveWhatsThisMode( whatsThis, mapToGlobal( p ), this );
+#endif
+ }
+
+ emit activatedRedirect( id );
+}
+
+void QPopupMenu::hilitSig( int id )
+{
+ emit highlighted( id );
+ emit highlightedRedirect( id );
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::Focus );
+ QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::Selection );
+#endif
+}
+
+void QPopupMenu::setFirstItemActive()
+{
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ int ai = 0;
+ if(d->scroll.scrollable)
+ ai = d->scroll.topScrollableIndex;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( !mi->isSeparator() && mi->id() != QMenuData::d->aInt &&
+ ( style().styleHint( QStyle::SH_PopupMenu_AllowActiveAndDisabled, this ) || mi->isEnabledAndVisible() )) {
+ setActiveItem( ai );
+ return;
+ }
+ ai++;
+ }
+ actItem = -1;
+}
+
+/*!
+ \internal
+ Hides all popup menus (in this menu tree) that are currently open.
+*/
+
+void QPopupMenu::hideAllPopups()
+{
+ register QMenuData *top = this; // find top level popup
+ if ( !preventAnimation )
+ QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ if ( !isPopup() )
+ return; // nothing to do
+
+ while ( top->parentMenu && top->parentMenu->isPopupMenu
+ && ((QPopupMenu*)top->parentMenu)->isPopup() )
+ top = top->parentMenu;
+ ((QPopupMenu*)top)->hide(); // cascade from top level
+
+#ifndef QT_NO_WHATSTHIS
+ if (whatsThisItem) {
+ qWhatsThisBDH();
+ whatsThisItem = 0;
+ }
+#endif
+
+}
+
+/*!
+ \internal
+ Hides all popup sub-menus.
+*/
+
+void QPopupMenu::hidePopups()
+{
+ if ( !preventAnimation )
+ QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( mi->popup() && mi->popup()->parentMenu == this ) //avoid circularity
+ mi->popup()->hide();
+ }
+ popupActive = -1; // no active sub menu
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+
+ QRect mfrect = itemGeometry( actItem );
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+}
+
+
+/*!
+ \internal
+ Sends the event to the menu bar.
+*/
+
+bool QPopupMenu::tryMenuBar( QMouseEvent *e )
+{
+ register QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+#ifndef QT_NO_MENUBAR
+ return top->isMenuBar ?
+ ((QMenuBar *)top)->tryMouseEvent( this, e ) :
+ ((QPopupMenu*)top)->tryMouseEvent(this, e );
+#else
+ return ((QPopupMenu*)top)->tryMouseEvent(this, e );
+#endif
+}
+
+
+/*!
+ \internal
+*/
+bool QPopupMenu::tryMouseEvent( QPopupMenu *p, QMouseEvent * e)
+{
+ if ( p == this )
+ return FALSE;
+ QPoint pos = mapFromGlobal( e->globalPos() );
+ if ( !rect().contains( pos ) ) // outside
+ return FALSE;
+ QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
+ event( &ee );
+ return TRUE;
+}
+
+/*!
+ \internal
+ Tells the menu bar to go back to idle state.
+*/
+
+void QPopupMenu::byeMenuBar()
+{
+#ifndef QT_NO_MENUBAR
+ register QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+#endif
+ hideAllPopups();
+#ifndef QT_NO_MENUBAR
+ if ( top->isMenuBar )
+ ((QMenuBar *)top)->goodbye();
+#endif
+}
+
+
+/*!
+ \internal
+ Return the item at \a pos, or -1 if there is no item there or if
+ it is a separator item.
+*/
+
+int QPopupMenu::itemAtPos( const QPoint &pos, bool ignoreSeparator ) const
+{
+ if ( !contentsRect().contains(pos) )
+ return -1;
+
+ int row = 0;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ QMenuItem *mi;
+ QMenuItemListIt it( *mitems );
+ if(d->scroll.scrollable) {
+ if(d->scroll.topScrollableIndex) {
+ for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi) {
+ row = 0;
+ it.toFirst();
+ }
+ y += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ }
+ }
+ int itemw = contentsRect().width() / ncols;
+ QSize sz;
+ while ( (mi=it.current()) ) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ y >= contentsRect().height() - style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this))
+ return -1;
+ ++it;
+ if ( !mi->isVisible() ) {
+ ++row;
+ continue;
+ }
+ int itemh = itemHeight( mi );
+
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(mi,maxPMWidth));
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if ( QRect( x, y, itemw, itemh ).contains( pos ) )
+ break;
+ y += itemh;
+ ++row;
+ }
+
+ if ( mi && ( !ignoreSeparator || !mi->isSeparator() ) )
+ return row;
+ return -1;
+}
+
+/*!
+ \internal
+ Returns the geometry of item number \a index.
+*/
+
+QRect QPopupMenu::itemGeometry( int index )
+{
+ QMenuItem *mi;
+ QSize sz;
+ int row = 0, scrollh = 0;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ QMenuItemListIt it( *mitems );
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) {
+ scrollh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ y += scrollh;
+ if(d->scroll.topScrollableIndex) {
+ for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi) {
+ row = 0;
+ it.toFirst();
+ }
+ }
+ }
+ int itemw = contentsRect().width() / ncols;
+ while ( (mi=it.current()) ) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ y >= contentsRect().height() - scrollh)
+ break;
+ ++it;
+ if ( !mi->isVisible() ) {
+ ++row;
+ continue;
+ }
+ int itemh = itemHeight( mi );
+
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(mi,maxPMWidth));
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ (y + itemh > contentsRect().height() - scrollh))
+ itemh -= (y + itemh) - (contentsRect().height() - scrollh);
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if ( row == index )
+ return QRect( x,y,itemw,itemh );
+ y += itemh;
+ ++row;
+ }
+
+ return QRect(0,0,0,0);
+}
+
+
+/*!
+ \internal
+ Calculates and sets the size of the popup menu, based on the size
+ of the items.
+*/
+
+QSize QPopupMenu::updateSize(bool force_update, bool do_resize)
+{
+ polish();
+ if ( count() == 0 ) {
+ QSize ret = QSize( 50, 8 );
+ if(do_resize)
+ setFixedSize( ret );
+ badSize = TRUE;
+ return ret;
+ }
+
+ int scrheight = 0;
+ if(d->scroll.scrollableSize) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp)
+ scrheight += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown)
+ scrheight += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ }
+
+ if(badSize || force_update) {
+#ifndef QT_NO_ACCEL
+ updateAccel( 0 );
+#endif
+ int height = 0;
+ int max_width = 0, max_height = 0;
+ QFontMetrics fm = fontMetrics();
+ register QMenuItem *mi;
+ maxPMWidth = 0;
+ int maxWidgetWidth = 0;
+ tab = 0;
+
+ for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
+ mi = it.current();
+ QWidget *miw = mi->widget();
+ if (miw) {
+ if ( miw->parentWidget() != this )
+ miw->reparent( this, QPoint(0,0), TRUE );
+ // widget items musn't propgate mouse events
+ ((QPopupMenu*)miw)->setWFlags(WNoMousePropagation);
+ }
+ if ( mi->custom() )
+ mi->custom()->setFont( font() );
+ if ( mi->iconSet() != 0)
+ maxPMWidth = QMAX( maxPMWidth,
+ mi->iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4 );
+ }
+
+ int dh = screenRect( geometry().center()).height();
+ ncols = 1;
+
+ for ( QMenuItemListIt it2( *mitems ); it2.current(); ++it2 ) {
+ mi = it2.current();
+ if ( !mi->isVisible() )
+ continue;
+ int w = 0;
+ int itemHeight = QPopupMenu::itemHeight( mi );
+
+ if ( mi->widget() ) {
+ QSize s( mi->widget()->sizeHint() );
+ s = s.expandedTo( mi->widget()->minimumSize() );
+ mi->widget()->resize( s );
+ if ( s.width() > maxWidgetWidth )
+ maxWidgetWidth = s.width();
+ itemHeight = s.height();
+ } else {
+ if( ! mi->isSeparator() ) {
+ if ( mi->custom() ) {
+ if ( mi->custom()->fullSpan() ) {
+ maxWidgetWidth = QMAX( maxWidgetWidth,
+ mi->custom()->sizeHint().width() );
+ } else {
+ QSize s ( mi->custom()->sizeHint() );
+ w += s.width();
+ }
+ }
+
+ w += maxPMWidth;
+
+ if (! mi->text().isNull()) {
+ QString s = mi->text();
+ int t;
+ if ( (t = s.find('\t')) >= 0 ) { // string contains tab
+ w += fm.width( s, t );
+ w -= s.contains('&') * fm.width('&');
+ w += s.contains("&&") * fm.width('&');
+ int tw = fm.width( s.mid(t + 1) );
+ if ( tw > tab)
+ tab = tw;
+ } else {
+ w += fm.width( s );
+ w -= s.contains('&') * fm.width('&');
+ w += s.contains("&&") * fm.width('&');
+ }
+ } else if (mi->pixmap())
+ w += mi->pixmap()->width();
+ } else {
+ if ( mi->custom() ) {
+ QSize s ( mi->custom()->sizeHint() );
+ w += s.width();
+ } else {
+ w = itemHeight = 2;
+ }
+ }
+
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(w, itemHeight),
+ QStyleOption(mi,maxPMWidth));
+
+ w = sz.width();
+ itemHeight = sz.height();
+
+#if defined(QT_CHECK_NULL)
+ if ( mi->text().isNull() && !mi->pixmap() && !mi->iconSet() &&
+ !mi->isSeparator() && !mi->widget() && !mi->custom() )
+ qWarning( "QPopupMenu: (%s) Popup has invalid menu item",
+ name( "unnamed" ) );
+#endif
+ }
+ height += itemHeight;
+ if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
+ if(scrheight && height >= d->scroll.scrollableSize - scrheight) {
+ height = d->scroll.scrollableSize - scrheight;
+ break;
+ }
+ } else if( height + 2*frameWidth() >= dh ) {
+ ncols++;
+ max_height = QMAX(max_height, height - itemHeight);
+ height = itemHeight;
+ }
+ if ( w > max_width )
+ max_width = w;
+ }
+ if( ncols == 1 && !max_height )
+ max_height = height;
+
+ if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
+ height += scrheight;
+ setMouseTracking(TRUE);
+ }
+
+ if ( tab )
+ tab -= fontMetrics().minRightBearing();
+ else
+ max_width -= fontMetrics().minRightBearing();
+
+ if ( max_width + tab < maxWidgetWidth )
+ max_width = maxWidgetWidth - tab;
+
+ const int fw = frameWidth();
+ int extra_width = (fw+style().pixelMetric(QStyle::PM_PopupMenuFrameHorizontalExtra, this)) * 2,
+ extra_height = (fw+style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this)) * 2;
+ if ( ncols == 1 )
+ d->calcSize = QSize( QMAX( minimumWidth(), max_width + tab + extra_width ),
+ QMAX( minimumHeight() , height + extra_height ) );
+ else
+ d->calcSize = QSize( QMAX( minimumWidth(), (ncols*(max_width + tab)) + extra_width ),
+ QMAX( minimumHeight(), QMIN( max_height + extra_height + 1, dh ) ) );
+ badSize = FALSE;
+ }
+
+ {
+ // Position the widget items. It could be done in drawContents
+ // but this way we get less flicker.
+ QSize sz;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ int itemw = contentsRect().width() / ncols;
+ for(QMenuItemListIt it(*mitems); it.current(); ++it) {
+ QMenuItem *mi = it.current();
+ if ( !mi->isVisible() )
+ continue;
+
+ int itemh = itemHeight( mi );
+
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh), QStyleOption(mi,maxPMWidth));
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if ( mi->widget() )
+ mi->widget()->setGeometry( x, y, itemw, mi->widget()->height() );
+ y += itemh;
+ }
+ }
+
+ if( do_resize && size() != d->calcSize ) {
+ setMaximumSize( d->calcSize );
+ d->calcSize = maximumSize(); //let the max size adjust it (virtual)
+ resize( d->calcSize );
+ }
+ return d->calcSize;
+}
+
+
+#ifndef QT_NO_ACCEL
+/*!
+ \internal
+ The \a parent is 0 when it is updated when a menu item has
+ changed a state, or it is something else if called from the menu bar.
+*/
+
+void QPopupMenu::updateAccel( QWidget *parent )
+{
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+
+ if ( parent ) {
+ delete autoaccel;
+ autoaccel = 0;
+ } else if ( !autoaccel ) {
+ // we have no parent. Rather than ignoring any accelerators we try to find this popup's main window
+ if ( tornOff ) {
+ parent = this;
+ } else {
+ QWidget *w = (QWidget *) this;
+ parent = w->parentWidget();
+ while ( (!w->testWFlags(WType_TopLevel) || !w->testWFlags(WType_Popup)) && parent ) {
+ w = parent;
+ parent = parent->parentWidget();
+ }
+ }
+ }
+
+ if ( parent == 0 && autoaccel == 0 )
+ return;
+
+ if ( autoaccel ) // build it from scratch
+ autoaccel->clear();
+ else {
+ // create an autoaccel in any case, even if we might not use
+ // it immediately. Maybe the user needs it later.
+ autoaccel = new QAccel( parent, this );
+ connect( autoaccel, SIGNAL(activated(int)),
+ SLOT(accelActivated(int)) );
+ connect( autoaccel, SIGNAL(activatedAmbiguously(int)),
+ SLOT(accelActivated(int)) );
+ connect( autoaccel, SIGNAL(destroyed()),
+ SLOT(accelDestroyed()) );
+ if ( accelDisabled )
+ autoaccel->setEnabled( FALSE );
+ }
+ while ( (mi=it.current()) ) {
+ ++it;
+ QKeySequence k = mi->key();
+ if ( (int)k ) {
+ int id = autoaccel->insertItem( k, mi->id() );
+#ifndef QT_NO_WHATSTHIS
+ autoaccel->setWhatsThis( id, mi->whatsThis() );
+#endif
+ }
+ if ( !mi->text().isNull() || mi->custom() ) {
+ QString s = mi->text();
+ int i = s.find('\t');
+
+ // Note: Only looking at the first key in the sequence!
+ if ( (int)k && (int)k != Key_unknown ) {
+ QString t = (QString)mi->key();
+ if ( i >= 0 )
+ s.replace( i+1, s.length()-i, t );
+ else {
+ s += '\t';
+ s += t;
+ }
+ } else if ( !k ) {
+ if ( i >= 0 )
+ s.truncate( i );
+ }
+ if ( s != mi->text() ) {
+ mi->setText( s );
+ badSize = TRUE;
+ }
+ }
+ if ( mi->popup() && parent ) { // call recursively
+ // reuse
+ QPopupMenu* popup = mi->popup();
+ if (!popup->avoid_circularity) {
+ popup->avoid_circularity = 1;
+ popup->updateAccel( parent );
+ popup->avoid_circularity = 0;
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+ It would be better to check in the slot.
+*/
+
+void QPopupMenu::enableAccel( bool enable )
+{
+ if ( autoaccel )
+ autoaccel->setEnabled( enable );
+ accelDisabled = !enable; // rememeber when updateAccel
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) { // do the same for sub popups
+ ++it;
+ if ( mi->popup() ) // call recursively
+ mi->popup()->enableAccel( enable );
+ }
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QPopupMenu::setFont( const QFont &font )
+{
+ QWidget::setFont( font );
+ badSize = TRUE;
+ if ( isVisible() ) {
+ updateSize();
+ update();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QPopupMenu::show()
+{
+ if ( !isPopup() && isVisible() )
+ hide();
+
+ if ( isVisible() ) {
+ supressAboutToShow = FALSE;
+ QWidget::show();
+ return;
+ }
+ if (!supressAboutToShow)
+ emit aboutToShow();
+ else
+ supressAboutToShow = FALSE;
+ performDelayedChanges();
+ updateSize(TRUE);
+ QWidget::show();
+ popupActive = -1;
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+ d->ignoremousepos = QCursor::pos();
+}
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::hide()
+{
+ if ( syncMenu == this && qApp ) {
+ qApp->exit_loop();
+ syncMenu = 0;
+ }
+
+ if ( !isVisible() ) {
+ QWidget::hide();
+ return;
+ }
+ emit aboutToHide();
+
+ actItem = popupActive = -1;
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+ mouseBtDn = FALSE; // mouse button up
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::PopupMenuEnd );
+#endif
+#ifndef QT_NO_MENUBAR
+ QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+ if( top->isMenuBar )
+ x11SetWindowType( X11WindowTypePopup ); // reset
+#endif
+ parentMenu = 0;
+ hidePopups();
+ QWidget::hide();
+}
+
+
+/*!
+ Calculates the height in pixels of the item in row \a row.
+*/
+int QPopupMenu::itemHeight( int row ) const
+{
+ return itemHeight( mitems->at( row ) );
+}
+
+/*!
+ \overload
+
+ Calculates the height in pixels of the menu item \a mi.
+*/
+int QPopupMenu::itemHeight( QMenuItem *mi ) const
+{
+ if ( mi->widget() )
+ return mi->widget()->height();
+ if ( mi->custom() && mi->custom()->fullSpan() )
+ return mi->custom()->sizeHint().height();
+
+ QFontMetrics fm(fontMetrics());
+ int h = 0;
+ if ( mi->isSeparator() ) // separator height
+ h = 2;
+ else if ( mi->pixmap() ) // pixmap height
+ h = mi->pixmap()->height();
+ else // text height
+ h = fm.height();
+
+ if ( !mi->isSeparator() && mi->iconSet() != 0 )
+ h = QMAX(h, mi->iconSet()->pixmap( QIconSet::Small,
+ QIconSet::Normal ).height());
+ if ( mi->custom() )
+ h = QMAX(h, mi->custom()->sizeHint().height());
+
+ return h;
+}
+
+
+/*!
+ Draws menu item \a mi in the area \a x, \a y, \a w, \a h, using
+ painter \a p. The item is drawn active if \a act is TRUE or drawn
+ inactive if \a act is FALSE. The rightmost \a tab_ pixels are used
+ for accelerator text.
+
+ \sa QStyle::drawControl()
+*/
+void QPopupMenu::drawItem( QPainter* p, int tab_, QMenuItem* mi,
+ bool act, int x, int y, int w, int h)
+{
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled() && mi->isEnabledAndVisible() && (!mi->popup() || mi->popup()->isEnabled()) )
+ flags |= QStyle::Style_Enabled;
+ if (act)
+ flags |= QStyle::Style_Active;
+ if (mouseBtDn)
+ flags |= QStyle::Style_Down;
+
+ const QColorGroup &cg = ((flags&QStyle::Style_Enabled) ? colorGroup() : palette().disabled() );
+
+ if ( mi->custom() && mi->custom()->fullSpan() ) {
+ QMenuItem dummy;
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, QRect(x, y, w, h), cg,
+ flags, QStyleOption(&dummy,maxPMWidth,tab_));
+ mi->custom()->paint( p, cg, act, flags&QStyle::Style_Enabled, x, y, w, h );
+ } else
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, QRect(x, y, w, h), cg,
+ flags, QStyleOption(mi,maxPMWidth,tab_));
+}
+
+
+/*!
+ Draws all menu items using painter \a p.
+*/
+void QPopupMenu::drawContents( QPainter* p )
+{
+ QMenuItemListIt it(*mitems);
+ QMenuItem *mi = 0;
+ int row = 0;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ if(d->scroll.scrollable) {
+ if(d->scroll.topScrollableIndex) {
+ for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi)
+ it.toFirst();
+ }
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) {
+ QRect rect(x, y, contentsRect().width(),
+ style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this));
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ QStyle::SFlags flags = QStyle::Style_Up;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuScroller, p, this, rect,
+ colorGroup(), flags, QStyleOption(maxPMWidth));
+ }
+ y += rect.height();
+ }
+ }
+
+ int itemw = contentsRect().width() / ncols;
+ QSize sz;
+ QStyle::SFlags flags;
+ while ( (mi=it.current()) ) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ y >= contentsRect().height() - style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this))
+ break;
+ ++it;
+ if ( !mi->isVisible() ) {
+ ++row;
+ continue;
+ }
+ int itemh = itemHeight( mi );
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(mi,maxPMWidth,0)
+ );
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ if ( y < contentsRect().bottom() ) {
+ QRect rect(x, y, itemw, contentsRect().bottom() - y);
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ flags = QStyle::Style_Default;
+ if (isEnabled() && mi->isEnabledAndVisible())
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, rect,
+ colorGroup(), flags, QStyleOption((QMenuItem*)0,maxPMWidth));
+ }
+ }
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if (!mi->widget() && (!p->hasClipping() || p->clipRegion().contains(QRect(x, y, itemw, itemh))))
+ drawItem( p, tab, mi, row == actItem, x, y, itemw, itemh );
+ y += itemh;
+ ++row;
+ }
+ if ( y < contentsRect().bottom() ) {
+ QRect rect(x, y, itemw, contentsRect().bottom() - y);
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ flags = QStyle::Style_Default;
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, rect,
+ colorGroup(), flags, QStyleOption((QMenuItem*)0,maxPMWidth));
+ }
+ }
+ if( d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown ) {
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ QRect rect(x, contentsRect().height() - sh, contentsRect().width(), sh);
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ QStyle::SFlags flags = QStyle::Style_Down;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuScroller, p, this, rect,
+ colorGroup(), flags, QStyleOption(maxPMWidth));
+ }
+ }
+#if defined( DEBUG_SLOPPY_SUBMENU )
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
+ p->setClipRegion( d->mouseMoveBuffer );
+ p->fillRect( d->mouseMoveBuffer.boundingRect(), colorGroup().brush( QColorGroup::Highlight ) );
+ }
+#endif
+}
+
+
+/*****************************************************************************
+ Event handlers
+ *****************************************************************************/
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::paintEvent( QPaintEvent *e )
+{
+ QFrame::paintEvent( e );
+}
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::closeEvent( QCloseEvent * e) {
+ e->accept();
+ byeMenuBar();
+}
+
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::mousePressEvent( QMouseEvent *e )
+{
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if (rect().contains(e->pos()) &&
+ ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
+ (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ e->pos().y() >= contentsRect().height() - sh))) //down
+ return;
+
+ mouseBtDn = TRUE; // mouse button down
+ int item = itemAtPos( e->pos() );
+ if ( item == -1 ) {
+ if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) {
+ byeMenuBar();
+ }
+ return;
+ }
+ register QMenuItem *mi = mitems->at(item);
+ if ( item != actItem ) // new item activated
+ setActiveItem( item );
+
+ QPopupMenu *popup = mi->popup();
+ if ( popup ) {
+ if ( popup->isVisible() ) { // sub menu already open
+ int pactItem = popup->actItem;
+ popup->actItem = -1;
+ popup->hidePopups();
+ popup->updateRow( pactItem );
+ } else { // open sub menu
+ hidePopups();
+ popupSubMenuLater( 20, this );
+ }
+ } else {
+ hidePopups();
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::mouseReleaseEvent( QMouseEvent *e )
+{
+ // do not hide a standalone context menu on press-release, unless
+ // the user moved the mouse significantly
+ if ( !parentMenu && !mouseBtDn && actItem < 0 && motion < 6 )
+ return;
+
+ mouseBtDn = FALSE;
+
+ // if the user released the mouse outside the menu, pass control
+ // to the menubar or our parent menu
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if ( !rect().contains( e->pos() ) && tryMenuBar(e) )
+ return;
+ else if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
+ (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ e->pos().y() >= contentsRect().height() - sh)) //down
+ return;
+
+ if ( actItem < 0 ) { // we do not have an active item
+ // if the release is inside without motion (happens with
+ // oversized popup menus on small screens), ignore it
+ if ( rect().contains( e->pos() ) && motion < 6 )
+ return;
+ else
+ byeMenuBar();
+ } else { // selected menu item!
+ register QMenuItem *mi = mitems->at(actItem);
+ if ( mi ->widget() ) {
+ QWidget* widgetAt = QApplication::widgetAt( e->globalPos(), TRUE );
+ if ( widgetAt && widgetAt != this ) {
+ QMouseEvent me( e->type(), widgetAt->mapFromGlobal( e->globalPos() ),
+ e->globalPos(), e->button(), e->state() );
+ QApplication::sendEvent( widgetAt, &me );
+ }
+ }
+ QPopupMenu *popup = mi->popup();
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if ( !mi->isEnabledAndVisible() ) {
+#ifndef QT_NO_WHATSTHIS
+ if ( b ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ byeMenuBar();
+ actSig( mi->id(), b);
+ }
+#endif
+ } else if ( popup ) {
+ popup->setFirstItemActive();
+ } else { // normal menu item
+ byeMenuBar(); // deactivate menu bar
+ if ( mi->isEnabledAndVisible() ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::mouseMoveEvent( QMouseEvent *e )
+{
+ if( e->globalPos() == d->ignoremousepos ) {
+ return;
+ }
+ d->ignoremousepos = QPoint();
+
+ motion++;
+
+ if ( parentMenu && parentMenu->isPopupMenu ) {
+ QPopupMenu* p = (QPopupMenu*)parentMenu;
+ int myIndex;
+
+ p->findPopup( this, &myIndex );
+ QPoint pPos = p->mapFromParent( e->globalPos() );
+ if ( p->actItem != myIndex && !p->rect().contains( pPos ) )
+ p->setActiveItem( myIndex );
+
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
+ p->d->mouseMoveBuffer = QRegion();
+#ifdef DEBUG_SLOPPY_SUBMENU
+ p->repaint();
+#endif
+ }
+ }
+
+ if ( (e->state() & Qt::MouseButtonMask) == 0 &&
+ !hasMouseTracking() )
+ return;
+
+ if(d->scroll.scrollable && e->pos().x() >= rect().x() && e->pos().x() <= rect().width()) {
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) ||
+ (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown && e->pos().y() >= height()-sh)) {
+ if(!d->scroll.scrolltimer) {
+ d->scroll.scrolltimer = new QTimer(this, "popup scroll timer");
+ QObject::connect( d->scroll.scrolltimer, SIGNAL(timeout()),
+ this, SLOT(subScrollTimer()) );
+ }
+ if(!d->scroll.scrolltimer->isActive())
+ d->scroll.scrolltimer->start(40);
+ return;
+ }
+ }
+
+ int item = itemAtPos( e->pos() );
+ if ( item == -1 ) { // no valid item
+ if( !d->hasmouse ) {
+ tryMenuBar( e );
+ return;
+ }
+ d->hasmouse = 0;
+ int lastActItem = actItem;
+ actItem = -1;
+ if ( lastActItem >= 0 )
+ updateRow( lastActItem );
+ if ( lastActItem > 0 ||
+ ( !rect().contains( e->pos() ) && !tryMenuBar( e ) ) ) {
+ popupSubMenuLater(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay,
+ this), this);
+ }
+ } else { // mouse on valid item
+ // but did not register mouse press
+ d->hasmouse = 1;
+ if ( (e->state() & Qt::MouseButtonMask) && !mouseBtDn )
+ mouseBtDn = TRUE; // so mouseReleaseEvent will pop down
+
+ register QMenuItem *mi = mitems->at( item );
+
+ if ( mi->widget() ) {
+ QWidget* widgetAt = QApplication::widgetAt( e->globalPos(), TRUE );
+ if ( widgetAt && widgetAt != this ) {
+ QMouseEvent me( e->type(), widgetAt->mapFromGlobal( e->globalPos() ),
+ e->globalPos(), e->button(), e->state() );
+ QApplication::sendEvent( widgetAt, &me );
+ }
+ }
+
+ if ( actItem == item )
+ return;
+
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this) &&
+ d->mouseMoveBuffer.contains( e->pos() ) ) {
+ actItem = item;
+ popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this) * 6,
+ this );
+ return;
+ }
+
+ if ( mi->popup() || ( popupActive >= 0 && popupActive != item ))
+ popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this),
+ this );
+ else if ( singleSingleShot )
+ singleSingleShot->stop();
+
+ if ( item != actItem )
+ setActiveItem( item );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::keyPressEvent( QKeyEvent *e )
+{
+ /*
+ I get nothing but complaints about this. -Brad
+
+ - if (mouseBtDn && actItem >= 0) {
+ - if (e->key() == Key_Shift ||
+ - e->key() == Key_Control ||
+ - e->key() == Key_Alt)
+ - return;
+ -
+ - QMenuItem *mi = mitems->at(actItem);
+ - int modifier = (((e->state() & ShiftButton) ? SHIFT : 0) |
+ - ((e->state() & ControlButton) ? CTRL : 0) |
+ - ((e->state() & AltButton) ? ALT : 0));
+ -
+ - #ifndef QT_NO_ACCEL
+ - if (mi)
+ - setAccel(modifier + e->key(), mi->id());
+ - #endif
+ - return;
+ - }
+ */
+
+ QMenuItem *mi = 0;
+ QPopupMenu *popup;
+ int dy = 0;
+ bool ok_key = TRUE;
+
+ int key = e->key();
+ if ( QApplication::reverseLayout() ) {
+ // in reverse mode opening and closing keys for submenues are reversed
+ if ( key == Key_Left )
+ key = Key_Right;
+ else if ( key == Key_Right )
+ key = Key_Left;
+ }
+
+ switch ( key ) {
+ case Key_Tab:
+ // ignore tab, otherwise it will be passed to the menubar
+ break;
+
+ case Key_Up:
+ dy = -1;
+ break;
+
+ case Key_Down:
+ dy = 1;
+ break;
+
+ case Key_Alt:
+ if ( style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) )
+ byeMenuBar();
+ break;
+
+ case Key_Escape:
+ if ( tornOff ) {
+ close();
+ return;
+ }
+ // just hide one
+ {
+ QMenuData* p = parentMenu;
+ hide();
+#ifndef QT_NO_MENUBAR
+ if ( p && p->isMenuBar )
+ ((QMenuBar*) p)->goodbye( TRUE );
+#endif
+ }
+ break;
+
+ case Key_Left:
+ if ( ncols > 1 && actItem >= 0 ) {
+ QRect r( itemGeometry( actItem ) );
+ int newActItem = itemAtPos( QPoint( r.left() - 1, r.center().y() ) );
+ if ( newActItem >= 0 ) {
+ setActiveItem( newActItem );
+ break;
+ }
+ }
+ if ( parentMenu && parentMenu->isPopupMenu ) {
+ ((QPopupMenu *)parentMenu)->hidePopups();
+ if ( singleSingleShot )
+ singleSingleShot->stop();
+ break;
+ }
+
+ ok_key = FALSE;
+ break;
+
+ case Key_Right:
+ if ( actItem >= 0 && ( mi=mitems->at(actItem) )->isEnabledAndVisible() && (popup=mi->popup()) ) {
+ hidePopups();
+ if ( singleSingleShot )
+ singleSingleShot->stop();
+ // ### The next two lines were switched to fix the problem with the first item of the
+ // submenu not being highlighted...any reason why they should have been the other way??
+ subMenuTimer();
+ popup->setFirstItemActive();
+ break;
+ } else if ( actItem == -1 && ( parentMenu && !parentMenu->isMenuBar )) {
+ dy = 1;
+ break;
+ }
+ if ( ncols > 1 && actItem >= 0 ) {
+ QRect r( itemGeometry( actItem ) );
+ int newActItem = itemAtPos( QPoint( r.right() + 1, r.center().y() ) );
+ if ( newActItem >= 0 ) {
+ setActiveItem( newActItem );
+ break;
+ }
+ }
+ ok_key = FALSE;
+ break;
+
+ case Key_Space:
+ if (! style().styleHint(QStyle::SH_PopupMenu_SpaceActivatesItem, this))
+ break;
+ // for motif, fall through
+
+ case Key_Return:
+ case Key_Enter:
+ {
+ if ( actItem < 0 )
+ break;
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ mi = mitems->at( actItem );
+ if ( !mi->isEnabled() && !b )
+ break;
+ popup = mi->popup();
+ if ( popup ) {
+ hidePopups();
+ popupSubMenuLater( 20, this );
+ popup->setFirstItemActive();
+ } else {
+ actItem = -1;
+ updateItem( mi->id() );
+ byeMenuBar();
+ if ( mi->isEnabledAndVisible() || b ) {
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+ break;
+#ifndef QT_NO_WHATSTHIS
+ case Key_F1:
+ if ( actItem < 0 || e->state() != ShiftButton)
+ break;
+ mi = mitems->at( actItem );
+ if ( !mi->whatsThis().isNull() ){
+ if ( !QWhatsThis::inWhatsThisMode() )
+ QWhatsThis::enterWhatsThisMode();
+ QRect r( itemGeometry( actItem) );
+ QWhatsThis::leaveWhatsThisMode( mi->whatsThis(), mapToGlobal( r.bottomLeft()) );
+ }
+ //fall-through!
+#endif
+ default:
+ ok_key = FALSE;
+
+ }
+ if ( !ok_key &&
+ ( !e->state() || e->state() == AltButton || e->state() == ShiftButton ) &&
+ e->text().length()==1 ) {
+ QChar c = e->text()[0].upper();
+
+ QMenuItemListIt it(*mitems);
+ QMenuItem* first = 0;
+ QMenuItem* currentSelected = 0;
+ QMenuItem* firstAfterCurrent = 0;
+
+ register QMenuItem *m;
+ mi = 0;
+ int indx = 0;
+ int clashCount = 0;
+ while ( (m=it.current()) ) {
+ ++it;
+ QString s = m->text();
+ if ( !s.isEmpty() ) {
+ int i = s.find( '&' );
+ while ( i >= 0 && i < (int)s.length() - 1 ) {
+ if ( s[i+1].upper() == c ) {
+ ok_key = TRUE;
+ clashCount++;
+ if ( !first )
+ first = m;
+ if ( indx == actItem )
+ currentSelected = m;
+ else if ( !firstAfterCurrent && currentSelected )
+ firstAfterCurrent = m;
+ break;
+ } else if ( s[i+1] == '&' ) {
+ i = s.find( '&', i+2 );
+ } else {
+ break;
+ }
+ }
+ }
+ if ( mi )
+ break;
+ indx++;
+ }
+
+ if ( 1 == clashCount ) { // No clashes, continue with selection
+ mi = first;
+ popup = mi->popup();
+ if ( popup ) {
+ setActiveItem( indexOf(mi->id()) );
+ hidePopups();
+ popupSubMenuLater( 20, this );
+ popup->setFirstItemActive();
+ } else {
+ byeMenuBar();
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if ( mi->isEnabledAndVisible() || b ) {
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ } else if ( clashCount > 1 ) { // Clashes, highlight next...
+ // If there's clashes and no one is selected, use first one
+ // or if there is no clashes _after_ current, use first one
+ if ( !currentSelected || (currentSelected && !firstAfterCurrent))
+ dy = indexOf( first->id() ) - actItem;
+ else
+ dy = indexOf( firstAfterCurrent->id() ) - actItem;
+ }
+ }
+#ifndef QT_NO_MENUBAR
+ if ( !ok_key ) { // send to menu bar
+ register QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+ if ( top->isMenuBar ) {
+ int beforeId = top->actItem;
+ ((QMenuBar*)top)->tryKeyEvent( this, e );
+ if ( beforeId != top->actItem )
+ ok_key = TRUE;
+ }
+ }
+#endif
+ if ( actItem < 0 ) {
+ if ( dy > 0 ) {
+ setFirstItemActive();
+ } else if ( dy < 0 ) {
+ QMenuItemListIt it(*mitems);
+ it.toLast();
+ register QMenuItem *mi;
+ int ai = count() - 1;
+ while ( (mi=it.current()) ) {
+ --it;
+ if ( !mi->isSeparator() && mi->id() != QMenuData::d->aInt ) {
+ setActiveItem( ai );
+ return;
+ }
+ ai--;
+ }
+ actItem = -1;
+ }
+ return;
+ }
+
+ if ( dy ) { // highlight next/prev
+ register int i = actItem;
+ int c = mitems->count();
+ for(int n = c; n; n--) {
+ i = i + dy;
+ if(d->scroll.scrollable) {
+ if(d->scroll.scrolltimer)
+ d->scroll.scrolltimer->stop();
+ if(i < 0)
+ i = 0;
+ else if(i >= c)
+ i = c - 1;
+ } else {
+ if ( i == c )
+ i = 0;
+ else if ( i < 0 )
+ i = c - 1;
+ }
+ mi = mitems->at( i );
+ if ( !mi || !mi->isVisible() )
+ continue;
+
+ if ( !mi->isSeparator() &&
+ ( style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this)
+ || mi->isEnabledAndVisible() ) )
+ break;
+ }
+ if ( i != actItem )
+ setActiveItem( i );
+ if(d->scroll.scrollable) { //need to scroll to make it visible?
+ QRect r = itemGeometry(actItem);
+ if(r.isNull() || r.height() < itemHeight(mitems->at(actItem))) {
+ bool refresh = FALSE;
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && dy == -1) { //up
+ if(d->scroll.topScrollableIndex >= 0) {
+ d->scroll.topScrollableIndex--;
+ refresh = TRUE;
+ }
+ } else if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown) { //down
+ QMenuItemListIt it(*mitems);
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ for(int i = 0, y = ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) ? sh : 0); it.current(); i++, ++it) {
+ if(i >= d->scroll.topScrollableIndex) {
+ int itemh = itemHeight(it.current());
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(it.current(),maxPMWidth,0));
+ y += sz.height();
+ if(y > (contentsRect().height()-sh)) {
+ if(sz.height() > sh || !it.atLast())
+ d->scroll.topScrollableIndex++;
+ refresh = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if(refresh) {
+ updateScrollerState();
+ update();
+ }
+ }
+ }
+ }
+
+#ifdef Q_OS_WIN32
+ if ( !ok_key &&
+ !( e->key() == Key_Control || e->key() == Key_Shift || e->key() == Key_Meta ) )
+ qApp->beep();
+#endif // Q_OS_WIN32
+}
+
+
+/*!
+ \reimp
+*/
+
+void QPopupMenu::timerEvent( QTimerEvent *e )
+{
+ QFrame::timerEvent( e );
+}
+
+/*!
+ \reimp
+*/
+void QPopupMenu::leaveEvent( QEvent * )
+{
+ d->hasmouse = 0;
+ if ( testWFlags( WStyle_Tool ) && style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this) ) {
+ int lastActItem = actItem;
+ actItem = -1;
+ if ( lastActItem >= 0 )
+ updateRow( lastActItem );
+ }
+}
+
+/*!
+ \reimp
+*/
+void QPopupMenu::styleChange( QStyle& old )
+{
+ QFrame::styleChange( old );
+ setMouseTracking(style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this));
+ style().polishPopupMenu( this );
+ updateSize(TRUE);
+}
+
+/*!\reimp
+ */
+void QPopupMenu::enabledChange( bool )
+{
+ if ( QMenuData::d->aWidget ) // torn-off menu
+ QMenuData::d->aWidget->setEnabled( isEnabled() );
+}
+
+
+/*!
+ If a popup 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.
+
+ \sa sizeHint()
+*/
+int QPopupMenu::columns() const
+{
+ return ncols;
+}
+
+/* This private slot handles the scrolling popupmenu */
+void QPopupMenu::subScrollTimer() {
+ QPoint pos = QCursor::pos();
+ if(!d->scroll.scrollable || !isVisible()) {
+ if(d->scroll.scrolltimer)
+ d->scroll.scrolltimer->stop();
+ return;
+ } else if(pos.x() > x() + width() || pos.x() < x()) {
+ return;
+ }
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(!d->scroll.lastScroll.isValid()) {
+ d->scroll.lastScroll = QTime::currentTime();
+ } else {
+ int factor=0;
+ if(pos.y() < y())
+ factor = y() - pos.y();
+ else if(pos.y() > y() + height())
+ factor = pos.y() - (y() + height());
+ int msecs = 250 - ((factor / 10) * 40);
+ if(d->scroll.lastScroll.msecsTo(QTime::currentTime()) < QMAX(0, msecs))
+ return;
+ d->scroll.lastScroll = QTime::currentTime();
+ }
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && pos.y() <= y() + sh) { //up
+ if(d->scroll.topScrollableIndex > 0) {
+ d->scroll.topScrollableIndex--;
+ updateScrollerState();
+ update(contentsRect());
+ }
+ } else if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ pos.y() >= (y() + contentsRect().height()) - sh) { //down
+ QMenuItemListIt it(*mitems);
+ for(int i = 0, y = contentsRect().y() + sh; it.current(); i++, ++it) {
+ if(i >= d->scroll.topScrollableIndex) {
+ int itemh = itemHeight(it.current());
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this, QSize(0, itemh),
+ QStyleOption(it.current(),maxPMWidth,0));
+ y += sz.height();
+ if(y > contentsRect().height() - sh) {
+ d->scroll.topScrollableIndex++;
+ updateScrollerState();
+ update(contentsRect());
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* This private slot handles the delayed submenu effects */
+
+void QPopupMenu::subMenuTimer() {
+
+ if ( !isVisible() || (actItem < 0 && popupActive < 0) || actItem == popupActive )
+ return;
+
+ if ( popupActive >= 0 ) {
+ hidePopups();
+ popupActive = -1;
+ }
+
+ // hidePopups() may change actItem etc.
+ if ( !isVisible() || actItem < 0 || actItem == popupActive )
+ return;
+
+ QMenuItem *mi = mitems->at(actItem);
+ if ( !mi || !mi->isEnabledAndVisible() )
+ return;
+
+ QPopupMenu *popup = mi->popup();
+ if ( !popup || !popup->isEnabled() )
+ return;
+
+ //avoid circularity
+ if ( popup->isVisible() )
+ return;
+
+ Q_ASSERT( popup->parentMenu == 0 );
+ popup->parentMenu = this; // set parent menu
+
+ emit popup->aboutToShow();
+ supressAboutToShow = TRUE;
+
+
+ QRect r( itemGeometry( actItem ) );
+ QPoint p;
+ QSize ps = popup->sizeHint();
+ // GUI Style
+ int gs = style().styleHint(QStyle::SH_GUIStyle);
+ int arrowHMargin, arrowVMargin;
+ if (gs == GtkStyle) {
+ arrowHMargin = gtkArrowHMargin;
+ arrowVMargin = gtkArrowVMargin;
+ } else {
+ arrowHMargin = motifArrowHMargin;
+ arrowVMargin = motifArrowVMargin;
+ }
+ if( QApplication::reverseLayout() ) {
+ p = QPoint( r.left() + arrowHMargin - ps.width(), r.top() + arrowVMargin );
+ p = mapToGlobal( p );
+
+ bool right = FALSE;
+ if ( ( parentMenu && parentMenu->isPopupMenu &&
+ ((QPopupMenu*)parentMenu)->geometry().x() < geometry().x() ) ||
+ p.x() < screenRect( p ).left())
+ right = TRUE;
+ if ( right && (ps.width() > screenRect( p ).right() - mapToGlobal( r.topRight() ).x() ) )
+ right = FALSE;
+ if ( right )
+ p.setX( mapToGlobal( r.topRight() ).x() );
+ } else {
+ p = QPoint( r.right() - arrowHMargin, r.top() + arrowVMargin );
+ p = mapToGlobal( p );
+
+ bool left = FALSE;
+ if ( ( parentMenu && parentMenu->isPopupMenu &&
+ ((QPopupMenu*)parentMenu)->geometry().x() > geometry().x() ) ||
+ p.x() + ps.width() > screenRect( p ).right() )
+ left = TRUE;
+ if ( left && (ps.width() > mapToGlobal( r.topLeft() ).x() ) )
+ left = FALSE;
+ if ( left )
+ p.setX( mapToGlobal( r.topLeft() ).x() - ps.width() );
+ }
+ QRect pr = popup->itemGeometry(popup->count() - 1);
+ if (p.y() + ps.height() > screenRect( p ).bottom() &&
+ p.y() - ps.height() + (QCOORD) pr.height() >= screenRect( p ).top())
+ p.setY( p.y() - ps.height() + (QCOORD) pr.height());
+
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
+ QPoint cur = QCursor::pos();
+ if ( r.contains( mapFromGlobal( cur ) ) ) {
+ QPoint pts[4];
+ pts[0] = QPoint( cur.x(), cur.y() - 2 );
+ pts[3] = QPoint( cur.x(), cur.y() + 2 );
+ if ( p.x() >= cur.x() ) {
+ pts[1] = QPoint( geometry().right(), p.y() );
+ pts[2] = QPoint( geometry().right(), p.y() + ps.height() );
+ } else {
+ pts[1] = QPoint( p.x() + ps.width(), p.y() );
+ pts[2] = QPoint( p.x() + ps.width(), p.y() + ps.height() );
+ }
+ QPointArray points( 4 );
+ for( int i = 0; i < 4; i++ )
+ points.setPoint( i, mapFromGlobal( pts[i] ) );
+ d->mouseMoveBuffer = QRegion( points );
+ repaint();
+ }
+ }
+
+ popupActive = actItem;
+ popup->popup( p );
+}
+
+void QPopupMenu::allowAnimation()
+{
+ preventAnimation = FALSE;
+}
+
+void QPopupMenu::updateRow( int row )
+{
+ if ( !isVisible() )
+ return;
+
+ if ( badSize ) {
+ updateSize();
+ update();
+ return;
+ }
+ updateSize();
+ QRect r = itemGeometry( row );
+ if ( !r.isNull() ) // can happen via the scroller
+ repaint( r );
+}
+
+
+/*!
+ \overload
+
+ Executes this popup synchronously.
+
+ Opens the popup menu so that the item number \a indexAtPoint will
+ be at the specified \e global position \a pos. To translate a
+ widget's local coordinates into global coordinates, use
+ QWidget::mapToGlobal().
+
+ The return code is the id of the selected item in either the popup
+ menu or one of its submenus, or -1 if no item is selected
+ (normally because the user pressed Esc).
+
+ Note that all signals are emitted as usual. If you connect a menu
+ item 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 popup at the current mouse
+ position:
+ \code
+ exec( QCursor::pos() );
+ \endcode
+ or aligned to a widget:
+ \code
+ exec( somewidget.mapToGlobal(QPoint(0, 0)) );
+ \endcode
+
+ When positioning a popup with exec() or popup(), bear in mind that
+ you cannot rely on the popup menu's current size(). For
+ performance reasons, the popup adapts its size only when
+ necessary. So in many cases, the size before and after the show is
+ different. Instead, use sizeHint(). It calculates the proper size
+ depending on the menu's current contents.
+
+ \sa popup(), sizeHint()
+*/
+
+int QPopupMenu::exec( const QPoint & pos, int indexAtPoint )
+{
+ snapToMouse = TRUE;
+ if ( !qApp )
+ return -1;
+
+ QPopupMenu* priorSyncMenu = syncMenu;
+
+ syncMenu = this;
+ syncMenuId = -1;
+
+ QGuardedPtr<QPopupMenu> that = this;
+ connectModal( that, TRUE );
+ popup( pos, indexAtPoint );
+ qApp->enter_loop();
+ connectModal( that, FALSE );
+
+ syncMenu = priorSyncMenu;
+ return syncMenuId;
+}
+
+
+
+/*
+ Connect the popup and all its submenus to modalActivation() if
+ \a doConnect is true, otherwise disconnect.
+ */
+void QPopupMenu::connectModal( QPopupMenu* receiver, bool doConnect )
+{
+ if ( !receiver )
+ return;
+
+ connectModalRecursionSafety = doConnect;
+
+ if ( doConnect )
+ connect( this, SIGNAL(activated(int)),
+ receiver, SLOT(modalActivation(int)) );
+ else
+ disconnect( this, SIGNAL(activated(int)),
+ receiver, SLOT(modalActivation(int)) );
+
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( mi->popup() && mi->popup() != receiver
+ && (bool)(mi->popup()->connectModalRecursionSafety) != doConnect )
+ mi->popup()->connectModal( receiver, doConnect ); //avoid circular
+ }
+}
+
+
+/*!
+ Executes this popup synchronously.
+
+ This is equivalent to \c{exec(mapToGlobal(QPoint(0,0)))}. In most
+ situations you'll want to specify the position yourself, for
+ example at the current mouse position:
+ \code
+ exec(QCursor::pos());
+ \endcode
+ or aligned to a widget:
+ \code
+ exec(somewidget.mapToGlobal(QPoint(0,0)));
+ \endcode
+*/
+
+int QPopupMenu::exec()
+{
+ return exec(mapToGlobal(QPoint(0,0)));
+}
+
+
+/* Internal slot used for exec(). */
+
+void QPopupMenu::modalActivation( int id )
+{
+ syncMenuId = id;
+}
+
+
+/*!
+ Sets the currently active item to index \a i and repaints as necessary.
+*/
+
+void QPopupMenu::setActiveItem( int i )
+{
+ int lastActItem = actItem;
+ actItem = i;
+ if ( lastActItem >= 0 )
+ updateRow( lastActItem );
+ if ( i >= 0 && i != lastActItem )
+ updateRow( i );
+ QMenuItem *mi = mitems->at( actItem );
+ if ( !mi )
+ return;
+
+ if ( mi->widget() && mi->widget()->isFocusEnabled() ) {
+ mi->widget()->setFocus();
+ } else {
+ setFocus();
+ QRect mfrect = itemGeometry( actItem );
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+ }
+ if ( mi->id() != -1 )
+ hilitSig( mi->id() );
+#ifndef QT_NO_WHATSTHIS
+ if (whatsThisItem && whatsThisItem != mi) {
+ qWhatsThisBDH();
+ }
+ whatsThisItem = mi;
+#endif
+}
+
+
+/*!
+ \reimp
+*/
+QSize QPopupMenu::sizeHint() const
+{
+ constPolish();
+ QPopupMenu* that = (QPopupMenu*) this;
+ //We do not need a resize here, just the sizeHint..
+ return that->updateSize(FALSE).expandedTo( QApplication::globalStrut() );
+}
+
+
+/*!
+ \overload
+
+ Returns the id of the item at \a pos, or -1 if there is no item
+ there or if it is a separator.
+*/
+int QPopupMenu::idAt( const QPoint& pos ) const
+{
+ return idAt( itemAtPos( pos ) );
+}
+
+
+/*!
+ \fn int QPopupMenu::idAt( int index ) const
+
+ Returns the identifier of the menu item at position \a index in
+ the internal list, or -1 if \a index is out of range.
+
+ \sa QMenuData::setId(), QMenuData::indexOf()
+*/
+
+
+/*!
+ \reimp
+ */
+bool QPopupMenu::customWhatsThis() const
+{
+ return TRUE;
+}
+
+
+/*!
+ \reimp
+ */
+bool QPopupMenu::focusNextPrevChild( bool next )
+{
+ register QMenuItem *mi;
+ int dy = next? 1 : -1;
+ if ( dy && actItem < 0 ) {
+ setFirstItemActive();
+ } else if ( dy ) { // highlight next/prev
+ register int i = actItem;
+ int c = mitems->count();
+ int n = c;
+ while ( n-- ) {
+ i = i + dy;
+ if ( i == c )
+ i = 0;
+ else if ( i < 0 )
+ i = c - 1;
+ mi = mitems->at( i );
+ if ( mi && !mi->isSeparator() &&
+ ( ( style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this)
+ && mi->isVisible() )
+ || mi->isEnabledAndVisible() ) )
+ break;
+ }
+ if ( i != actItem )
+ setActiveItem( i );
+ }
+ return TRUE;
+}
+
+
+/*!
+ \reimp
+ */
+void QPopupMenu::focusInEvent( QFocusEvent * )
+{
+}
+
+/*!
+ \reimp
+ */
+void QPopupMenu::focusOutEvent( QFocusEvent * )
+{
+}
+
+
+class QTearOffMenuItem : public QCustomMenuItem
+{
+public:
+ QTearOffMenuItem()
+ {
+ }
+ ~QTearOffMenuItem()
+ {
+ }
+ void paint( QPainter* p, const QColorGroup& cg, bool /* act*/,
+ bool /*enabled*/, int x, int y, int w, int h )
+ {
+ p->setPen( QPen( cg.dark(), 1, DashLine ) );
+ p->drawLine( x+2, y+h/2-1, x+w-4, y+h/2-1 );
+ p->setPen( QPen( cg.light(), 1, DashLine ) );
+ p->drawLine( x+2, y+h/2, x+w-4, y+h/2 );
+ }
+ bool fullSpan() const
+ {
+ return TRUE;
+ }
+
+ QSize sizeHint()
+ {
+ return QSize( 20, 6 );
+ }
+};
+
+
+
+/*!
+ Inserts a tear-off handle into the menu. A tear-off handle is a
+ special menu item that creates a copy of the menu when the menu is
+ selected. 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.
+
+ The handle item is assigned the identifier \a id or an
+ automatically generated identifier if \a id is < 0. The generated
+ identifiers (negative integers) are guaranteed to be unique within
+ the entire application.
+
+ The \a index specifies the position in the menu. The tear-off
+ handle is appended at the end of the list if \a index is negative.
+*/
+int QPopupMenu::insertTearOffHandle( int id, int index )
+{
+ int myid = insertItem( new QTearOffMenuItem, id, index );
+ connectItem( myid, this, SLOT( toggleTearOff() ) );
+ QMenuData::d->aInt = myid;
+ return myid;
+}
+
+
+/*!\internal
+
+ implements tear-off menus
+ */
+void QPopupMenu::toggleTearOff()
+{
+ if ( active_popup_menu && active_popup_menu->tornOff ) {
+ active_popup_menu->close();
+ } else if (QMenuData::d->aWidget ) {
+ delete (QWidget*) QMenuData::d->aWidget; // delete the old one
+ } else {
+ // create a tear off menu
+ QPopupMenu* p = new QPopupMenu( parentWidget(), "tear off menu" );
+ connect( p, SIGNAL( activated(int) ), this, SIGNAL( activated(int) ) );
+ connect( p, SIGNAL( highlighted(int) ), this, SIGNAL( highlighted(int) ) );
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ p->setCaption( caption() );
+#endif
+ p->setCheckable( isCheckable() );
+ p->reparent( parentWidget(), WType_TopLevel | WStyle_Tool |
+ WNoAutoErase | WDestructiveClose,
+ geometry().topLeft(), FALSE );
+ p->mitems->setAutoDelete( FALSE );
+ p->tornOff = TRUE;
+#ifdef Q_WS_X11
+ p->x11SetWindowType( X11WindowTypeMenu );
+#endif
+ for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
+ if ( it.current()->id() != QMenuData::d->aInt && !it.current()->widget() )
+ p->mitems->append( it.current() );
+ }
+ p->show();
+ QMenuData::d->aWidget = p;
+ }
+}
+
+/*!
+ \reimp
+ */
+void QPopupMenu::activateItemAt( int index )
+{
+ if ( index >= 0 && index < (int) mitems->count() ) {
+ QMenuItem *mi = mitems->at( index );
+ if ( index != actItem ) // new item activated
+ setActiveItem( index );
+ QPopupMenu *popup = mi->popup();
+ if ( popup ) {
+ if ( popup->isVisible() ) { // sub menu already open
+ int pactItem = popup->actItem;
+ popup->actItem = -1;
+ popup->hidePopups();
+ popup->updateRow( pactItem );
+ } else { // open sub menu
+ hidePopups();
+ actItem = index;
+ subMenuTimer();
+ popup->setFirstItemActive();
+ }
+ } else {
+ byeMenuBar(); // deactivate menu bar
+
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if ( !mi->isEnabledAndVisible() ) {
+#ifndef QT_NO_WHATSTHIS
+ if ( b ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ byeMenuBar();
+ actSig( mi->id(), b);
+ }
+#endif
+ } else {
+ byeMenuBar(); // deactivate menu bar
+ if ( mi->isEnabledAndVisible() ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+ } else {
+ if ( tornOff ) {
+ close();
+ } else {
+ QMenuData* p = parentMenu;
+ hide();
+#ifndef QT_NO_MENUBAR
+ if ( p && p->isMenuBar )
+ ((QMenuBar*) p)->goodbye( TRUE );
+#endif
+ }
+ }
+
+}
+
+/*! \internal
+ This private function is to update the scroll states in styles that support scrolling. */
+void
+QPopupMenu::updateScrollerState()
+{
+ uint old_scrollable = d->scroll.scrollable;
+ d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ if(!style().styleHint(QStyle::SH_PopupMenu_Scrollable, this))
+ return;
+
+ QMenuItem *mi;
+ QMenuItemListIt it( *mitems );
+ if(d->scroll.topScrollableIndex) {
+ for(int row = 0; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi)
+ it.toFirst();
+ }
+ int y = 0, sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(!it.atFirst()) {
+ // can't use |= because of a bug/feature in IBM xlC 5.0.2
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollUp;
+ y += sh;
+ }
+ while ( (mi=it.current()) ) {
+ ++it;
+ int myheight = contentsRect().height();
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemHeight( mi )),
+ QStyleOption(mi,maxPMWidth));
+ if(y + sz.height() >= myheight) {
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollDown;
+ break;
+ }
+ y += sz.height();
+ }
+ if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) &&
+ !(old_scrollable & QPopupMenuPrivate::Scroll::ScrollUp))
+ d->scroll.topScrollableIndex++;
+}
+
+#endif // QT_NO_POPUPMENU
+
diff --git a/src/widgets/qpopupmenu.h b/src/widgets/qpopupmenu.h
new file mode 100644
index 0000000..0609731
--- /dev/null
+++ b/src/widgets/qpopupmenu.h
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Definition of QPopupMenu class
+**
+** Created : 941128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QPOPUPMENU_H
+#define QPOPUPMENU_H
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qmenudata.h"
+#endif // QT_H
+
+#ifndef QT_NO_POPUPMENU
+class QPopupMenuPrivate;
+
+class Q_EXPORT QPopupMenu : public QFrame, public QMenuData
+{
+ Q_OBJECT
+ Q_PROPERTY( bool checkable READ isCheckable WRITE setCheckable )
+public:
+ QPopupMenu( QWidget* parent=0, const char* name=0 );
+ ~QPopupMenu();
+
+ void popup( const QPoint & pos, int indexAtPoint = -1 ); // open
+ void updateItem( int id );
+
+ virtual void setCheckable( bool );
+ bool isCheckable() const;
+
+ void setFont( const QFont & );
+ void show();
+ void hide();
+
+ int exec();
+ int exec( const QPoint & pos, int indexAtPoint = 0 ); // modal
+
+ virtual void setActiveItem( int );
+ QSize sizeHint() const;
+
+ int idAt( int index ) const { return QMenuData::idAt( index ); }
+ int idAt( const QPoint& pos ) const;
+
+ bool customWhatsThis() const;
+
+ int insertTearOffHandle( int id=-1, int index=-1 );
+
+ void activateItemAt( int index );
+ QRect itemGeometry( int index );
+
+
+signals:
+ void activated( int itemId );
+ void highlighted( int itemId );
+ void activatedRedirect( int itemId ); // to parent menu
+ void highlightedRedirect( int itemId );
+ void aboutToShow();
+ void aboutToHide();
+
+protected:
+ int itemHeight( int ) const;
+ int itemHeight( QMenuItem* mi ) const;
+ void drawItem( QPainter* p, int tab, QMenuItem* mi,
+ bool act, int x, int y, int w, int h);
+
+ void drawContents( QPainter * );
+
+ void closeEvent( QCloseEvent *e );
+ void paintEvent( QPaintEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent * );
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+ void timerEvent( QTimerEvent * );
+ void leaveEvent( QEvent * );
+ void styleChange( QStyle& );
+ void enabledChange( bool );
+ int columns() const;
+
+ bool focusNextPrevChild( bool next );
+
+ int itemAtPos( const QPoint &, bool ignoreSeparator = TRUE ) const;
+
+private slots:
+ void subActivated( int itemId );
+ void subHighlighted( int itemId );
+#ifndef QT_NO_ACCEL
+ void accelActivated( int itemId );
+ void accelDestroyed();
+#endif
+ void popupDestroyed( QObject* );
+ void modalActivation( int );
+
+ void subMenuTimer();
+ void subScrollTimer();
+ void allowAnimation();
+ void toggleTearOff();
+
+ void performDelayedChanges();
+
+private:
+ void updateScrollerState();
+ void menuContentsChanged();
+ void menuStateChanged();
+ void performDelayedContentsChanged();
+ void performDelayedStateChanged();
+ void menuInsPopup( QPopupMenu * );
+ void menuDelPopup( QPopupMenu * );
+ void frameChanged();
+
+ void actSig( int, bool = FALSE );
+ void hilitSig( int );
+ virtual void setFirstItemActive();
+ void hideAllPopups();
+ void hidePopups();
+ bool tryMenuBar( QMouseEvent * );
+ void byeMenuBar();
+
+ QSize updateSize(bool force_recalc=FALSE, bool do_resize=TRUE);
+ void updateRow( int row );
+ QRect screenRect(const QPoint& pos);
+#ifndef QT_NO_ACCEL
+ void updateAccel( QWidget * );
+ void enableAccel( bool );
+#endif
+ QPopupMenuPrivate *d;
+#ifndef QT_NO_ACCEL
+ QAccel *autoaccel;
+#endif
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ bool macPopupMenu(const QPoint &, int);
+ uint mac_dirty_popup : 1;
+#endif
+
+ int popupActive;
+ int tab;
+ uint accelDisabled : 1;
+ uint checkable : 1;
+ uint connectModalRecursionSafety : 1;
+ uint tornOff : 1;
+ uint pendingDelayedContentsChanges : 1;
+ uint pendingDelayedStateChanges : 1;
+ int maxPMWidth;
+ int ncols;
+ bool snapToMouse;
+ bool tryMouseEvent( QPopupMenu *, QMouseEvent * );
+
+ friend class QMenuData;
+ friend class QMenuBar;
+
+ void connectModal(QPopupMenu* receiver, bool doConnect);
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QPopupMenu( const QPopupMenu & );
+ QPopupMenu &operator=( const QPopupMenu & );
+#endif
+};
+
+
+#endif // QT_NO_POPUPMENU
+
+#endif // QPOPUPMENU_H
diff --git a/src/widgets/qprogressbar.cpp b/src/widgets/qprogressbar.cpp
new file mode 100644
index 0000000..a64ea8c
--- /dev/null
+++ b/src/widgets/qprogressbar.cpp
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** Implementation of QProgressBar class
+**
+** Created : 970521
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qprogressbar.h"
+#ifndef QT_NO_PROGRESSBAR
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qpixmap.h"
+#include "qstyle.h"
+#include "../kernel/qinternal_p.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+#include <limits.h>
+
+/*!
+ \class QProgressBar qprogressbar.h
+ \brief The QProgressBar widget provides a horizontal progress bar.
+
+ \ingroup advanced
+ \mainclass
+
+ 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 give it the
+ total number of steps and the number of steps completed so far and
+ it will display the percentage of steps that have been completed.
+ You can specify the total number of steps in the constructor or
+ later with setTotalSteps(). The current number of steps is set
+ with setProgress(). The progress bar can be rewound to the
+ beginning with reset().
+
+ If the total is given as 0 the progress bar shows a busy indicator
+ instead of a percentage of steps. This is useful, for example,
+ when using QFtp or QHttp to download items when they are unable to
+ determine the size of the item being downloaded.
+
+ \sa QProgressDialog
+
+ <img src=qprogbar-m.png> <img src=qprogbar-w.png>
+
+ \sa QProgressDialog
+ \link guibooks.html#fowler GUI Design Handbook: Progress Indicator\endlink
+*/
+
+
+/*!
+ Constructs a progress bar.
+
+ The total number of steps is set to 100 by default.
+
+ The \a parent, \a name and widget flags, \a f, are passed on to
+ the QFrame::QFrame() constructor.
+
+ \sa setTotalSteps()
+*/
+
+QProgressBar::QProgressBar( QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f | WNoAutoErase ),
+ total_steps( 100 ),
+ progress_val( -1 ),
+ percentage( -1 ),
+ center_indicator( TRUE ),
+ auto_indicator( TRUE ),
+ percentage_visible( TRUE ),
+ d( 0 )
+{
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
+ initFrame();
+}
+
+
+/*!
+ Constructs a progress bar.
+
+ The \a totalSteps is the total number of steps that need to be
+ completed for the operation which this progress bar represents.
+ For example, if the operation is to examine 50 files, this value
+ would be 50. Before examining the first file, call setProgress(0);
+ call setProgress(50) after examining the last file.
+
+ The \a parent, \a name and widget flags, \a f, are passed to the
+ QFrame::QFrame() constructor.
+
+ \sa setTotalSteps(), setProgress()
+*/
+
+QProgressBar::QProgressBar( int totalSteps,
+ QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f | WNoAutoErase ),
+ total_steps( totalSteps ),
+ progress_val( -1 ),
+ percentage( -1 ),
+ center_indicator( TRUE ),
+ auto_indicator( TRUE ),
+ percentage_visible( TRUE ),
+ d( 0 )
+{
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
+ initFrame();
+}
+
+
+/*!
+ Reset the progress bar. The progress bar "rewinds" and shows no
+ progress.
+*/
+
+void QProgressBar::reset()
+{
+ progress_val = -1;
+ percentage = -1;
+ setIndicator(progress_str, progress_val, total_steps);
+ repaint( FALSE );
+}
+
+
+/*!
+ \property QProgressBar::totalSteps
+ \brief The total number of steps.
+
+ If totalSteps is 0, the progress bar will display a busy
+ indicator.
+
+ \sa totalSteps()
+*/
+
+void QProgressBar::setTotalSteps( int totalSteps )
+{
+ total_steps = totalSteps;
+
+ // Current progress is invalid if larger than total
+ if ( total_steps < progress_val )
+ progress_val = -1;
+
+ if ( isVisible() &&
+ ( setIndicator(progress_str, progress_val, total_steps) || !total_steps ) )
+ repaint( FALSE );
+}
+
+
+/*!
+ \property QProgressBar::progress
+ \brief The current amount of progress
+
+ This property is -1 if progress counting has not started.
+*/
+
+void QProgressBar::setProgress( int progress )
+{
+ if ( progress == progress_val ||
+ progress < 0 || ( ( progress > total_steps ) && total_steps ) )
+ return;
+
+ progress_val = progress;
+
+ setIndicator( progress_str, progress_val, total_steps );
+
+ repaint( FALSE );
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+/*!
+ \overload
+
+ Sets the amount of progress to \a progress and the total number of
+ steps to \a totalSteps.
+
+ \sa setTotalSteps()
+*/
+
+void QProgressBar::setProgress( int progress, int totalSteps )
+{
+ if ( total_steps != totalSteps )
+ setTotalSteps( totalSteps );
+ setProgress( progress );
+}
+
+/*!
+ \property QProgressBar::progressString
+ \brief the amount of progress as a string
+
+ This property is QString::null if progress counting has not started.
+*/
+
+
+/*!
+ \reimp
+*/
+QSize QProgressBar::sizeHint() const
+{
+ constPolish();
+ QFontMetrics fm = fontMetrics();
+ int cw = style().pixelMetric(QStyle::PM_ProgressBarChunkWidth, this);
+ return style().sizeFromContents(QStyle::CT_ProgressBar, this,
+ QSize( cw * 7 + fm.width( '0' ) * 4,
+ fm.height() + 8));
+}
+
+
+/*!
+ \reimp
+*/
+QSize QProgressBar::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+/*!
+ \property QProgressBar::centerIndicator
+ \brief whether the indicator string should be centered
+
+ Changing this property sets \l QProgressBar::indicatorFollowsStyle
+ to FALSE. The default is TRUE.
+*/
+
+void QProgressBar::setCenterIndicator( bool on )
+{
+ if ( !auto_indicator && on == center_indicator )
+ return;
+ auto_indicator = FALSE;
+ center_indicator = on;
+ repaint( FALSE );
+}
+
+/*!
+ \property QProgressBar::indicatorFollowsStyle
+ \brief whether the display of the indicator string should follow the GUI style
+
+ The default is TRUE.
+
+ \sa centerIndicator
+*/
+
+void QProgressBar::setIndicatorFollowsStyle( bool on )
+{
+ if ( on == auto_indicator )
+ return;
+ auto_indicator = on;
+ repaint( FALSE );
+}
+
+/*!
+ \property QProgressBar::percentageVisible
+ \brief whether the current progress value is displayed
+
+ The default is TRUE.
+
+ \sa centerIndicator, indicatorFollowsStyle
+*/
+void QProgressBar::setPercentageVisible( bool on )
+{
+ if ( on == percentage_visible )
+ return;
+ percentage_visible = on;
+ repaint( FALSE );
+}
+
+/*!
+ \reimp
+*/
+void QProgressBar::show()
+{
+ setIndicator( progress_str, progress_val, total_steps );
+ QFrame::show();
+}
+
+void QProgressBar::initFrame()
+{
+ setFrameStyle(QFrame::NoFrame);
+}
+
+/*!
+ \reimp
+*/
+void QProgressBar::styleChange( QStyle& old )
+{
+ initFrame();
+ QFrame::styleChange( old );
+}
+
+
+/*!
+ This method is called to generate the text displayed in the center
+ (or in some styles, to the left) of the progress bar.
+
+ The \a progress may be negative, indicating that the progress bar
+ is in the "reset" state before any progress is set.
+
+ The default implementation is the percentage of completion or
+ blank in the reset state. The percentage is calculated based on
+ the \a progress and \a totalSteps. You can set the \a indicator
+ text if you wish.
+
+ To allow efficient repainting of the progress bar, this method
+ should return FALSE if the string is unchanged from the last call
+ to this function.
+*/
+
+bool QProgressBar::setIndicator( QString & indicator, int progress,
+ int totalSteps )
+{
+ if ( !totalSteps )
+ return FALSE;
+ if ( progress < 0 ) {
+ indicator = QString::fromLatin1("");
+ return TRUE;
+ } else {
+ // Get the values down to something usable.
+ if ( totalSteps > INT_MAX/1000 ) {
+ progress /= 1000;
+ totalSteps /= 1000;
+ }
+
+ int np = progress * 100 / totalSteps;
+ if ( np != percentage ) {
+ percentage = np;
+ indicator.sprintf( "%d%%", np );
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QProgressBar::drawContents( QPainter *p )
+{
+ const QRect bar = contentsRect();
+
+ QSharedDoubleBuffer buffer( p, bar.x(), bar.y(), bar.width(), bar.height() );
+
+ QPoint pn = backgroundOffset();
+ buffer.painter()->setBrushOrigin( -pn.x(), -pn.y() );
+
+ const QPixmap *bpm = paletteBackgroundPixmap();
+ if ( bpm )
+ buffer.painter()->fillRect( bar, QBrush( paletteBackgroundColor(), *bpm ) );
+ else
+ buffer.painter()->fillRect( bar, paletteBackgroundColor() );
+ buffer.painter()->setFont( p->font() );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+
+ style().drawControl(QStyle::CE_ProgressBarGroove, buffer.painter(), this,
+ QStyle::visualRect(style().subRect(QStyle::SR_ProgressBarGroove, this), this ),
+ colorGroup(), flags);
+
+ style().drawControl(QStyle::CE_ProgressBarContents, buffer.painter(), this,
+ QStyle::visualRect(style().subRect(QStyle::SR_ProgressBarContents, this), this ),
+ colorGroup(), flags);
+
+ if (percentageVisible())
+ style().drawControl(QStyle::CE_ProgressBarLabel, buffer.painter(), this,
+ QStyle::visualRect(style().subRect(QStyle::SR_ProgressBarLabel, this), this ),
+ colorGroup(), flags);
+}
+
+#endif
diff --git a/src/widgets/qprogressbar.h b/src/widgets/qprogressbar.h
new file mode 100644
index 0000000..2c4f039
--- /dev/null
+++ b/src/widgets/qprogressbar.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Definition of QProgressBar class
+**
+** Created : 970520
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QPROGRESSBAR_H
+#define QPROGRESSBAR_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_PROGRESSBAR
+
+
+class QProgressBarPrivate;
+
+
+class Q_EXPORT QProgressBar : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( int totalSteps READ totalSteps WRITE setTotalSteps )
+ Q_PROPERTY( int progress READ progress WRITE setProgress )
+ Q_PROPERTY( QString progressString READ progressString )
+ Q_PROPERTY( bool centerIndicator READ centerIndicator WRITE setCenterIndicator )
+ Q_PROPERTY( bool indicatorFollowsStyle READ indicatorFollowsStyle WRITE setIndicatorFollowsStyle )
+ Q_PROPERTY( bool percentageVisible READ percentageVisible WRITE setPercentageVisible )
+
+public:
+ QProgressBar( QWidget* parent=0, const char* name=0, WFlags f=0 );
+ QProgressBar( int totalSteps, QWidget* parent=0, const char* name=0, WFlags f=0 );
+
+ int totalSteps() const;
+ int progress() const;
+ const QString &progressString() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void setCenterIndicator( bool on );
+ bool centerIndicator() const;
+
+ void setIndicatorFollowsStyle( bool );
+ bool indicatorFollowsStyle() const;
+
+ bool percentageVisible() const;
+ void setPercentageVisible( bool );
+
+ void show();
+
+public slots:
+ void reset();
+ virtual void setTotalSteps( int totalSteps );
+ virtual void setProgress( int progress );
+ void setProgress( int progress, int totalSteps );
+
+protected:
+ void drawContents( QPainter * );
+ virtual bool setIndicator( QString & progress_str, int progress,
+ int totalSteps );
+ void styleChange( QStyle& );
+
+private:
+ int total_steps;
+ int progress_val;
+ int percentage;
+ QString progress_str;
+ bool center_indicator : 1;
+ bool auto_indicator : 1;
+ bool percentage_visible : 1;
+ QProgressBarPrivate * d;
+ void initFrame();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QProgressBar( const QProgressBar & );
+ QProgressBar &operator=( const QProgressBar & );
+#endif
+};
+
+
+inline int QProgressBar::totalSteps() const
+{
+ return total_steps;
+}
+
+inline int QProgressBar::progress() const
+{
+ return progress_val;
+}
+
+inline const QString &QProgressBar::progressString() const
+{
+ return progress_str;
+}
+
+inline bool QProgressBar::centerIndicator() const
+{
+ return center_indicator;
+}
+
+inline bool QProgressBar::indicatorFollowsStyle() const
+{
+ return auto_indicator;
+}
+
+inline bool QProgressBar::percentageVisible() const
+{
+ return percentage_visible;
+}
+
+#endif // QT_NO_PROGRESSBAR
+
+#endif // QPROGRESSBAR_H
diff --git a/src/widgets/qpushbutton.cpp b/src/widgets/qpushbutton.cpp
new file mode 100644
index 0000000..e3db3f7
--- /dev/null
+++ b/src/widgets/qpushbutton.cpp
@@ -0,0 +1,760 @@
+/****************************************************************************
+**
+** Implementation of QPushButton class
+**
+** Created : 940221
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qpushbutton.h"
+#ifndef QT_NO_PUSHBUTTON
+#include "qdialog.h"
+#include "qfontmetrics.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qpixmap.h"
+#include "qbitmap.h"
+#include "qpopupmenu.h"
+#include "qguardedptr.h"
+#include "qapplication.h"
+#include "qtoolbar.h"
+#include "qstyle.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+/*!
+ \class QPushButton qpushbutton.h
+ \brief The QPushButton widget provides a command button.
+
+ \ingroup basic
+ \mainclass
+
+ 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. An underlined character in the label
+ (signified by preceding it with an ampersand in the text)
+ indicates an accelerator key, e.g.
+ \code
+ QPushButton *pb = new QPushButton( "&Download", this );
+ \endcode
+ In this example the accelerator is \e{Alt+D}, and the label text
+ will be displayed as <b><u>D</u>ownload</b>.
+
+ Push buttons can display a textual label or a pixmap, and
+ optionally a small icon. These can be set using the constructors
+ and changed later using setText(), setPixmap() and setIconSet().
+ If the button is disabled the appearance of the text or pixmap and
+ iconset 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 accelerator. 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 setToggleButton()) 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 setPopup() to
+ associate a popup menu with a push button.
+
+ Other classes of buttons are option buttons (see QRadioButton) and
+ check boxes (see QCheckBox).
+
+ <img src="qpushbt-m.png"> <img src="qpushbt-w.png">
+
+ In Qt, the QButton abstract base class provides most of the modes
+ and other API, and QPushButton provides GUI logic. See QButton for
+ more information about the API.
+
+ \important text, setText, text, pixmap, setPixmap, accel, setAccel,
+ isToggleButton, setDown, isDown, isOn, state, autoRepeat,
+ isExclusiveToggle, group, setAutoRepeat, toggle, pressed, released,
+ clicked, toggled, state stateChanged
+
+ \sa QToolButton, QRadioButton QCheckBox
+ \link guibooks.html#fowler GUI Design Handbook: Push Button\endlink
+*/
+
+/*!
+ \property QPushButton::autoDefault
+ \brief whether the push button is the auto default button
+
+ If this property is set to TRUE then the push button is the auto
+ default button in a dialog.
+
+ 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::autoMask
+ \brief whether the button is automatically masked
+
+ \sa QWidget::setAutoMask()
+*/
+
+/*!
+ \property QPushButton::default
+ \brief whether the push button is the default button
+
+ If this property is set to TRUE then the push button will be
+ pressed if the user presses the Enter (or Return) key in a dialog.
+
+ Regardless of focus, if the user presses Enter: If there is a
+ default button the default button is pressed; otherwise, if
+ there are one or more \l autoDefault buttons the first \l autoDefault
+ button that is next in the tab order is pressed. If there are no
+ default or \l autoDefault buttons only pressing Space on a button
+ with focus, mouse clicking, or using an accelerator will press a
+ button.
+
+ 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 Enter (or
+ Return) or the Spacebar when the button has focus.
+
+ This property's default is FALSE.
+*/
+
+/*!
+ \property QPushButton::flat
+ \brief whether the border is disabled
+
+ This property's default is FALSE.
+*/
+
+/*!
+ \property QPushButton::iconSet
+ \brief the icon set on the push button
+
+ This property will return 0 if the push button has no iconset.
+*/
+
+/*!
+ \property QPushButton::on
+ \brief whether the push button is toggled
+
+ This property should only be set for toggle push buttons. The
+ default value is FALSE.
+
+ \sa isOn(), toggle(), toggled(), isToggleButton()
+*/
+
+/*!
+ \property QPushButton::toggleButton
+ \brief whether the button is a toggle button
+
+ Toggle buttons have an on/off state similar to \link QCheckBox
+ check boxes. \endlink A push button is initially not a toggle
+ button.
+
+ \sa setOn(), toggle(), isToggleButton() toggled()
+*/
+
+/*! \property QPushButton::menuButton
+ \brief whether the push button has a menu button on it
+ \obsolete
+
+ If this property is set to TRUE, then a down arrow is drawn on the push
+ button to indicate that a menu will pop up if the user clicks on the
+ arrow.
+*/
+
+class QPushButtonPrivate
+{
+public:
+ QPushButtonPrivate()
+ :iconset( 0 )
+ {}
+ ~QPushButtonPrivate()
+ {
+#ifndef QT_NO_ICONSET
+ delete iconset;
+#endif
+ }
+#ifndef QT_NO_POPUPMENU
+ QGuardedPtr<QPopupMenu> popup;
+#endif
+ QIconSet* iconset;
+};
+
+
+/*!
+ Constructs a push button with no text.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QPushButton::QPushButton( QWidget *parent, const char *name )
+ : QButton( parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs a push button called \a name with the parent \a parent
+ and the text \a text.
+*/
+
+QPushButton::QPushButton( const QString &text, QWidget *parent,
+ const char *name )
+ : QButton( parent, name )
+{
+ init();
+ setText( text );
+}
+
+
+/*!
+ Constructs a push button with an \a icon and a \a text.
+
+ Note that you can also pass a QPixmap object as an icon (thanks to
+ the implicit type conversion provided by C++).
+
+ The \a parent and \a name arguments are sent to the QWidget
+ constructor.
+*/
+#ifndef QT_NO_ICONSET
+QPushButton::QPushButton( const QIconSet& icon, const QString &text,
+ QWidget *parent, const char *name )
+ : QButton( parent, name )
+{
+ init();
+ setText( text );
+ setIconSet( icon );
+}
+#endif
+
+
+/*!
+ Destroys the push button.
+*/
+QPushButton::~QPushButton()
+{
+ delete d;
+}
+
+void QPushButton::init()
+{
+ d = 0;
+ defButton = FALSE;
+ lastEnabled = FALSE;
+ hasMenuArrow = FALSE;
+ flt = FALSE;
+#ifndef QT_NO_DIALOG
+ autoDefButton = ::qt_cast<QDialog*>(topLevelWidget()) != 0;
+#else
+ autoDefButton = FALSE;
+#endif
+ setBackgroundMode( PaletteButton );
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+}
+
+
+/*
+ Makes the push button a toggle button if \a enable is TRUE or a normal
+ push button if \a enable is FALSE.
+
+ Toggle buttons have an on/off state similar to \link QCheckBox check
+ boxes. \endlink A push button is initially not a toggle button.
+
+ \sa setOn(), toggle(), isToggleButton() toggled()
+*/
+
+void QPushButton::setToggleButton( bool enable )
+{
+ QButton::setToggleButton( enable );
+}
+
+
+/*
+ Switches a toggle button on if \a enable is TRUE or off if \a enable is
+ FALSE.
+ \sa isOn(), toggle(), toggled(), isToggleButton()
+*/
+
+void QPushButton::setOn( bool enable )
+{
+ if ( !isToggleButton() )
+ return;
+ QButton::setOn( enable );
+}
+
+void QPushButton::setAutoDefault( bool enable )
+{
+ if ( (bool)autoDefButton == enable )
+ return;
+ autoDefButton = enable;
+ update();
+ updateGeometry();
+}
+
+
+void QPushButton::setDefault( bool enable )
+{
+ if ( (bool)defButton == enable )
+ return; // no change
+ defButton = enable;
+#ifndef QT_NO_DIALOG
+ if ( defButton && ::qt_cast<QDialog*>(topLevelWidget()) )
+ ((QDialog*)topLevelWidget())->setMainDefault( this );
+#endif
+ update();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::StateChanged );
+#endif
+}
+
+
+/*!
+ \reimp
+*/
+QSize QPushButton::sizeHint() const
+{
+ constPolish();
+
+ int w = 0, h = 0;
+
+ // calculate contents size...
+#ifndef QT_NO_ICONSET
+ if ( iconSet() && !iconSet()->isNull() ) {
+ int iw = iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4;
+ int ih = iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).height();
+ w += iw;
+ h = QMAX( h, ih );
+ }
+#endif
+ if ( isMenuButton() )
+ w += style().pixelMetric(QStyle::PM_MenuButtonIndicator, this);
+
+ if ( pixmap() ) {
+ QPixmap *pm = (QPixmap *)pixmap();
+ w += pm->width();
+ h += pm->height();
+ } else {
+ QString s( text() );
+ bool empty = s.isEmpty();
+ if ( empty )
+ s = QString::fromLatin1("XXXX");
+ QFontMetrics fm = fontMetrics();
+ QSize sz = fm.size( ShowPrefix, s );
+ if(!empty || !w)
+ w += sz.width();
+ if(!empty || !h)
+ h = QMAX(h, sz.height());
+ }
+
+ return (style().sizeFromContents(QStyle::CT_PushButton, this, QSize(w, h)).
+ expandedTo(QApplication::globalStrut()));
+}
+
+
+/*!
+ \reimp
+*/
+void QPushButton::move( int x, int y )
+{
+ QWidget::move( x, y );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::move( const QPoint &p )
+{
+ move( p.x(), p.y() );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::resize( int w, int h )
+{
+ QWidget::resize( w, h );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::resize( const QSize &s )
+{
+ resize( s.width(), s.height() );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::setGeometry( int x, int y, int w, int h )
+{
+ QWidget::setGeometry( x, y, w, h );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::setGeometry( const QRect &r )
+{
+ QWidget::setGeometry( r );
+}
+
+/*!
+ \reimp
+ */
+void QPushButton::resizeEvent( QResizeEvent * )
+{
+ if ( autoMask() )
+ updateMask();
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::drawButton( QPainter *paint )
+{
+ int diw = 0;
+ if ( isDefault() || autoDefault() ) {
+ diw = style().pixelMetric(QStyle::PM_ButtonDefaultIndicator, this);
+
+ if ( diw > 0 ) {
+ if (backgroundMode() == X11ParentRelative) {
+ erase( 0, 0, width(), diw );
+ erase( 0, 0, diw, height() );
+ erase( 0, height() - diw, width(), diw );
+ erase( width() - diw, 0, diw, height() );
+ } else if ( parentWidget() && parentWidget()->backgroundPixmap() ){
+ // pseudo tranparency
+ paint->drawTiledPixmap( 0, 0, width(), diw,
+ *parentWidget()->backgroundPixmap(),
+ x(), y() );
+ paint->drawTiledPixmap( 0, 0, diw, height(),
+ *parentWidget()->backgroundPixmap(),
+ x(), y() );
+ paint->drawTiledPixmap( 0, height()-diw, width(), diw,
+ *parentWidget()->backgroundPixmap(),
+ x(), y()+height() );
+ paint->drawTiledPixmap( width()-diw, 0, diw, height(),
+ *parentWidget()->backgroundPixmap(),
+ x()+width(), y() );
+ } else {
+ paint->fillRect( 0, 0, width(), diw,
+ colorGroup().brush(QColorGroup::Background) );
+ paint->fillRect( 0, 0, diw, height(),
+ colorGroup().brush(QColorGroup::Background) );
+ paint->fillRect( 0, height()-diw, width(), diw,
+ colorGroup().brush(QColorGroup::Background) );
+ paint->fillRect( width()-diw, 0, diw, height(),
+ colorGroup().brush(QColorGroup::Background) );
+ }
+
+ }
+ }
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ if (isOn())
+ flags |= QStyle::Style_On;
+ if (! isFlat() && ! isDown())
+ flags |= QStyle::Style_Raised;
+ if (isDefault())
+ flags |= QStyle::Style_ButtonDefault;
+
+ style().drawControl(QStyle::CE_PushButton, paint, this, rect(), colorGroup(), flags);
+ drawButtonLabel( paint );
+
+ lastEnabled = isEnabled();
+}
+
+
+/*!
+ \reimp
+*/
+void QPushButton::drawButtonLabel( QPainter *paint )
+{
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ if (isOn())
+ flags |= QStyle::Style_On;
+ if (! isFlat() && ! isDown())
+ flags |= QStyle::Style_Raised;
+ if (isDefault())
+ flags |= QStyle::Style_ButtonDefault;
+
+ style().drawControl(QStyle::CE_PushButtonLabel, paint, this,
+ style().subRect(QStyle::SR_PushButtonContents, this),
+ colorGroup(), flags);
+}
+
+
+/*!
+ \reimp
+ */
+void QPushButton::updateMask()
+{
+ QBitmap bm( size() );
+ bm.fill( color0 );
+
+ {
+ QPainter p( &bm, this );
+ style().drawControlMask(QStyle::CE_PushButton, &p, this, rect());
+ }
+
+ setMask( bm );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::focusInEvent( QFocusEvent *e )
+{
+ if (autoDefButton && !defButton) {
+ defButton = TRUE;
+#ifndef QT_NO_DIALOG
+ if ( defButton && ::qt_cast<QDialog*>(topLevelWidget()) )
+ ((QDialog*)topLevelWidget())->setDefault( this );
+#endif
+ }
+ QButton::focusInEvent( e );
+}
+
+/*!
+ \reimp
+*/
+void QPushButton::focusOutEvent( QFocusEvent *e )
+{
+#ifndef QT_NO_DIALOG
+ if ( defButton && autoDefButton ) {
+ if ( ::qt_cast<QDialog*>(topLevelWidget()) )
+ ((QDialog*)topLevelWidget())->setDefault( 0 );
+ }
+#endif
+
+ QButton::focusOutEvent( e );
+#ifndef QT_NO_POPUPMENU
+ if ( popup() && popup()->isVisible() ) // restore pressed status
+ setDown( TRUE );
+#endif
+}
+
+
+#ifndef QT_NO_POPUPMENU
+/*!
+ Associates the popup menu \a popup with this push button. This
+ turns the button into a menu button.
+
+ Ownership of the popup menu is \e not transferred to the push
+ button.
+
+ \sa popup()
+*/
+void QPushButton::setPopup( QPopupMenu* popup )
+{
+ if ( !d )
+ d = new QPushButtonPrivate;
+ if ( popup && !d->popup )
+ connect( this, SIGNAL( pressed() ), this, SLOT( popupPressed() ) );
+
+ d->popup = popup;
+ setIsMenuButton( popup != 0 );
+}
+#endif //QT_NO_POPUPMENU
+#ifndef QT_NO_ICONSET
+void QPushButton::setIconSet( const QIconSet& icon )
+{
+ if ( !d )
+ d = new QPushButtonPrivate;
+ if ( !icon.isNull() ) {
+ if ( d->iconset )
+ *d->iconset = icon;
+ else
+ d->iconset = new QIconSet( icon );
+ } else if ( d->iconset) {
+ delete d->iconset;
+ d->iconset = 0;
+ }
+
+ update();
+ updateGeometry();
+}
+
+
+QIconSet* QPushButton::iconSet() const
+{
+ return d ? d->iconset : 0;
+}
+#endif // QT_NO_ICONSET
+#ifndef QT_NO_POPUPMENU
+/*!
+ Returns the button's associated popup menu or 0 if no popup menu
+ has been set.
+
+ \sa setPopup()
+*/
+QPopupMenu* QPushButton::popup() const
+{
+ return d ? (QPopupMenu*)d->popup : 0;
+}
+
+void QPushButton::popupPressed()
+{
+ QPopupMenu* popup = d ? (QPopupMenu*) d->popup : 0;
+ QGuardedPtr<QPushButton> that = this;
+ if ( isDown() && popup ) {
+ bool horizontal = TRUE;
+ bool topLeft = TRUE; // ### always TRUE
+#ifndef QT_NO_TOOLBAR
+ QToolBar *tb = ::qt_cast<QToolBar*>(parentWidget());
+ if ( tb && tb->orientation() == Vertical )
+ horizontal = FALSE;
+#endif
+ if ( horizontal ) {
+ if ( topLeft ) {
+ if ( mapToGlobal( QPoint( 0, rect().bottom() ) ).y() + popup->sizeHint().height() <= qApp->desktop()->height() )
+ popup->exec( mapToGlobal( rect().bottomLeft() ) );
+ else
+ popup->exec( mapToGlobal( rect().topLeft() - QPoint( 0, popup->sizeHint().height() ) ) );
+ } else {
+ QSize sz( popup->sizeHint() );
+ QPoint p = mapToGlobal( rect().topLeft() );
+ p.ry() -= sz.height();
+ popup->exec( p );
+ }
+ } else {
+ if ( topLeft ) {
+ if ( mapToGlobal( QPoint( rect().right(), 0 ) ).x() + popup->sizeHint().width() <= qApp->desktop()->width() )
+ popup->exec( mapToGlobal( rect().topRight() ) );
+ else
+ popup->exec( mapToGlobal( rect().topLeft() - QPoint( popup->sizeHint().width(), 0 ) ) );
+ } else {
+ QSize sz( popup->sizeHint() );
+ QPoint p = mapToGlobal( rect().topLeft() );
+ p.rx() -= sz.width();
+ popup->exec( p );
+ }
+ }
+ if (that)
+ setDown( FALSE );
+ }
+}
+#endif
+
+void QPushButton::setFlat( bool f )
+{
+ flt = f;
+ update();
+}
+
+bool QPushButton::isFlat() const
+{
+ return flt;
+}
+
+/*!
+ \obsolete
+ \fn virtual void QPushButton::setIsMenuButton( bool enable )
+*/
+
+#endif
diff --git a/src/widgets/qpushbutton.h b/src/widgets/qpushbutton.h
new file mode 100644
index 0000000..ff1b98d
--- /dev/null
+++ b/src/widgets/qpushbutton.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Definition of QPushButton class
+**
+** Created : 940221
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QPUSHBUTTON_H
+#define QPUSHBUTTON_H
+
+#ifndef QT_H
+#include "qbutton.h"
+#include "qiconset.h"
+#endif // QT_H
+
+#ifndef QT_NO_PUSHBUTTON
+class QPushButtonPrivate;
+class QPopupMenu;
+
+class Q_EXPORT QPushButton : public QButton
+{
+ Q_OBJECT
+
+ Q_PROPERTY( bool autoDefault READ autoDefault WRITE setAutoDefault )
+ Q_PROPERTY( bool default READ isDefault WRITE setDefault )
+ Q_PROPERTY( bool menuButton READ isMenuButton DESIGNABLE false )
+ Q_PROPERTY( QIconSet iconSet READ iconSet WRITE setIconSet )
+ Q_OVERRIDE( bool toggleButton WRITE setToggleButton )
+ Q_OVERRIDE( bool on WRITE setOn )
+ Q_PROPERTY( bool flat READ isFlat WRITE setFlat )
+ Q_OVERRIDE( bool autoMask DESIGNABLE true SCRIPTABLE true )
+
+public:
+ QPushButton( QWidget *parent, const char* name=0 );
+ QPushButton( const QString &text, QWidget *parent, const char* name=0 );
+#ifndef QT_NO_ICONSET
+ QPushButton( const QIconSet& icon, const QString &text, QWidget *parent, const char* name=0 );
+#endif
+ ~QPushButton();
+
+ QSize sizeHint() const;
+
+ void move( int x, int y );
+ void move( const QPoint &p );
+ void resize( int w, int h );
+ void resize( const QSize & );
+ void setGeometry( int x, int y, int w, int h );
+
+ void setGeometry( const QRect & );
+
+ void setToggleButton( bool );
+
+ bool autoDefault() const { return autoDefButton; }
+ virtual void setAutoDefault( bool autoDef );
+ bool isDefault() const { return defButton; }
+ virtual void setDefault( bool def );
+
+ virtual void setIsMenuButton( bool enable ) { // obsolete functions
+ if ( (bool)hasMenuArrow == enable )
+ return;
+ hasMenuArrow = enable ? 1 : 0;
+ update();
+ updateGeometry();
+ }
+ bool isMenuButton() const { return hasMenuArrow; }
+
+#ifndef QT_NO_POPUPMENU
+ void setPopup( QPopupMenu* popup );
+ QPopupMenu* popup() const;
+#endif
+#ifndef QT_NO_ICONSET
+ void setIconSet( const QIconSet& );
+ QIconSet* iconSet() const;
+#endif
+ void setFlat( bool );
+ bool isFlat() const;
+
+public slots:
+ virtual void setOn( bool );
+
+protected:
+ void drawButton( QPainter * );
+ void drawButtonLabel( QPainter * );
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+ void resizeEvent( QResizeEvent * );
+ void updateMask();
+private slots:
+#ifndef QT_NO_POPUPMENU
+ void popupPressed();
+#endif
+private:
+ void init();
+
+ uint autoDefButton : 1;
+ uint defButton : 1;
+ uint flt : 1;
+ uint reserved : 1; // UNUSED
+ uint lastEnabled : 1; // UNUSED
+ uint hasMenuArrow : 1;
+
+ QPushButtonPrivate* d;
+
+ friend class QDialog;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QPushButton( const QPushButton & );
+ QPushButton &operator=( const QPushButton & );
+#endif
+};
+
+
+#endif // QT_NO_PUSHBUTTON
+
+#endif // QPUSHBUTTON_H
diff --git a/src/widgets/qradiobutton.cpp b/src/widgets/qradiobutton.cpp
new file mode 100644
index 0000000..13aa096
--- /dev/null
+++ b/src/widgets/qradiobutton.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Implementation of QRadioButton class
+**
+** Created : 940222
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qradiobutton.h"
+#ifndef QT_NO_RADIOBUTTON
+#include "qbuttongroup.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qpixmap.h"
+#include "qpixmapcache.h"
+#include "qbitmap.h"
+#include "qtextstream.h"
+#include "qapplication.h"
+#include "qstyle.h"
+
+/*!
+ \class QRadioButton qradiobutton.h
+ \brief The QRadioButton widget provides a radio button with a text or pixmap label.
+
+ \ingroup basic
+ \mainclass
+
+ QRadioButton and QCheckBox are both option buttons. That is, they
+ can be switched on (checked) or off (unchecked). The classes
+ differ in how the choices for the user are restricted. Check boxes
+ define "many of many" choices, whereas radio buttons provide 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.
+
+ The easiest way to implement a "one of many" choice is simply to
+ put the radio buttons into QButtonGroup.
+
+ Whenever a button is switched on or off it emits the signal
+ toggled(). Connect to this signal if you want to trigger an action
+ each time the button changes state. Otherwise, use isChecked() to
+ see if a particular button is selected.
+
+ Just like QPushButton, a radio button can display text or a
+ pixmap. The text can be set in the constructor or with setText();
+ the pixmap is set with setPixmap().
+
+ <img src=qradiobt-m.png> <img src=qradiobt-w.png>
+
+ \important text, setText, text, pixmap, setPixmap, accel, setAccel, isToggleButton, setDown, isDown, isOn, state, autoRepeat, isExclusiveToggle, group, setAutoRepeat, toggle, pressed, released, clicked, toggled, state stateChanged
+
+ \sa QPushButton QToolButton
+ \link guibooks.html#fowler GUI Design Handbook: Radio Button\endlink
+*/
+
+/*!
+ \property QRadioButton::checked \brief Whether the radio button is
+ checked
+
+ This property will not effect any other radio buttons unless they
+ have been placed in the same QButtonGroup. The default value is
+ FALSE (unchecked).
+*/
+
+/*!
+ \property QRadioButton::autoMask \brief whether the radio button
+ is automatically masked
+
+ \sa QWidget::setAutoMask()
+*/
+
+/*!
+ Constructs a radio button with no text.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QRadioButton::QRadioButton( QWidget *parent, const char *name )
+ : QButton( parent, name, WNoAutoErase | WMouseNoMask )
+{
+ init();
+}
+
+/*!
+ Constructs a radio button with the text \a text.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QRadioButton::QRadioButton( const QString &text, QWidget *parent,
+ const char *name )
+ : QButton( parent, name, WNoAutoErase | WMouseNoMask )
+{
+ init();
+ setText( text );
+}
+
+
+/*
+ Initializes the radio button.
+*/
+
+void QRadioButton::init()
+{
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+ setToggleButton( TRUE );
+#ifndef QT_NO_BUTTONGROUP
+ QButtonGroup *bgrp = ::qt_cast<QButtonGroup*>(parentWidget());
+ if ( bgrp )
+ bgrp->setRadioButtonExclusive( TRUE );
+#endif
+}
+
+void QRadioButton::setChecked( bool check )
+{
+ setOn( check );
+}
+
+
+
+
+/*!
+ \reimp
+*/
+QSize QRadioButton::sizeHint() const
+{
+ // Any more complex, and we will use style().itemRect()
+ // NB: QCheckBox::sizeHint() is similar
+ constPolish();
+
+ QPainter p(this);
+ QSize sz = style().itemRect(&p, QRect(0, 0, 1, 1), ShowPrefix, FALSE,
+ pixmap(), text()).size();
+
+ return (style().sizeFromContents(QStyle::CT_RadioButton, this, sz).
+ expandedTo(QApplication::globalStrut()));
+}
+
+
+/*!
+ \reimp
+*/
+bool QRadioButton::hitButton( const QPoint &pos ) const
+{
+ QRect r =
+ QStyle::visualRect( style().subRect( QStyle::SR_RadioButtonFocusRect,
+ this ), this );
+ if ( qApp->reverseLayout() ) {
+ r.setRight( width() );
+ } else {
+ r.setLeft( 0 );
+ }
+ return r.contains( pos );
+}
+
+
+/*!
+ \reimp
+*/
+void QRadioButton::drawButton( QPainter *paint )
+{
+ QPainter *p = paint;
+ QRect irect = QStyle::visualRect( style().subRect(QStyle::SR_RadioButtonIndicator, this), this );
+ const QColorGroup &cg = colorGroup();
+
+#if !defined( QT_NO_TEXTSTREAM ) && !defined( Q_WS_MACX )
+# define SAVE_RADIOBUTTON_PIXMAPS
+#endif
+#if defined(SAVE_RADIOBUTTON_PIXMAPS)
+ QString pmkey; // pixmap key
+ int kf = 0;
+ if ( isDown() )
+ kf |= 1;
+ if ( isOn() )
+ kf |= 2;
+ if ( isEnabled() )
+ kf |= 4;
+ if( isActiveWindow() )
+ kf |= 8;
+ if ( hasMouse() )
+ kf |= 16;
+ if ( hasFocus() )
+ kf |= 32;
+
+ QTextOStream os(&pmkey);
+ os << "$qt_radio_" << style().className() << "_"
+ << palette().serialNumber() << "_" << irect.width() << "x" << irect.height() << "_" << kf;
+ QPixmap *pm = QPixmapCache::find( pmkey );
+ if ( pm ) { // pixmap exists
+ drawButtonLabel( p );
+ p->drawPixmap( irect.topLeft(), *pm );
+ return;
+ }
+ bool use_pm = TRUE;
+ QPainter pmpaint;
+ int wx, wy;
+ if ( use_pm ) {
+ pm = new QPixmap( irect.size() ); // create new pixmap
+ Q_CHECK_PTR( pm );
+ pm->fill(paletteBackgroundColor());
+ QPainter::redirect(this, pm);
+ pmpaint.begin(this);
+ p = &pmpaint; // draw in pixmap
+ wx = irect.x(); // save x,y coords
+ wy = irect.y();
+ irect.moveTopLeft(QPoint(0, 0));
+ p->setBackgroundColor(paletteBackgroundColor());
+ }
+#endif
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if ( hasFocus() )
+ flags |= QStyle::Style_HasFocus;
+ if ( isDown() )
+ flags |= QStyle::Style_Down;
+ if ( hasMouse() )
+ flags |= QStyle::Style_MouseOver;
+ if ( state() == QButton::On )
+ flags |= QStyle::Style_On;
+ else if ( state() == QButton::Off )
+ flags |= QStyle::Style_Off;
+
+ style().drawControl(QStyle::CE_RadioButton, p, this, irect, cg, flags);
+
+#if defined(SAVE_RADIOBUTTON_PIXMAPS)
+ if ( use_pm ) {
+ pmpaint.end();
+ QPainter::redirect(this, NULL);
+ if ( backgroundPixmap() || backgroundMode() == X11ParentRelative ) {
+ QBitmap bm( pm->size() );
+ bm.fill( color0 );
+ pmpaint.begin( &bm );
+ style().drawControlMask(QStyle::CE_RadioButton, &pmpaint, this, irect);
+ pmpaint.end();
+ pm->setMask( bm );
+ }
+ p = paint; // draw in default device
+ p->drawPixmap( wx, wy, *pm );
+ if (!QPixmapCache::insert(pmkey, pm) ) // save in cache
+ delete pm;
+ }
+#endif
+
+ drawButtonLabel( p );
+}
+
+
+
+/*!
+ \reimp
+*/
+void QRadioButton::drawButtonLabel( QPainter *p )
+{
+ QRect r =
+ QStyle::visualRect( style().subRect(QStyle::SR_RadioButtonContents,
+ this), this );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ if (state() == QButton::On)
+ flags |= QStyle::Style_On;
+ else if (state() == QButton::Off)
+ flags |= QStyle::Style_Off;
+
+ style().drawControl(QStyle::CE_RadioButtonLabel, p, this, r, colorGroup(), flags);
+}
+
+
+/*!
+ \reimp
+*/
+void QRadioButton::resizeEvent( QResizeEvent* e )
+{
+ QButton::resizeEvent(e);
+ if ( isVisible() ) {
+ QPainter p(this);
+ QSize isz = style().itemRect(&p, QRect(0, 0, 1, 1), ShowPrefix, FALSE,
+ pixmap(), text()).size();
+ QSize wsz = (style().sizeFromContents(QStyle::CT_RadioButton, this, isz).
+ expandedTo(QApplication::globalStrut()));
+
+ update(wsz.width(), isz.width(), 0, wsz.height());
+ }
+ if (autoMask())
+ updateMask();
+}
+
+/*!
+ \reimp
+*/
+void QRadioButton::updateMask()
+{
+ QRect irect =
+ QStyle::visualRect( style().subRect( QStyle::SR_RadioButtonIndicator,
+ this ), this );
+
+ QBitmap bm(width(), height());
+ bm.fill(color0);
+
+ QPainter p( &bm, this );
+ style().drawControlMask(QStyle::CE_RadioButton, &p, this, irect);
+ if ( ! text().isNull() || ( pixmap() && ! pixmap()->isNull() ) ) {
+ QRect crect =
+ QStyle::visualRect( style().subRect( QStyle::SR_RadioButtonContents,
+ this ), this );
+ QRect frect =
+ QStyle::visualRect( style().subRect( QStyle::SR_RadioButtonFocusRect,
+ this ), this );
+ QRect label(crect.unite(frect));
+ p.fillRect(label, color1);
+ }
+ p.end();
+
+ setMask(bm);
+}
+
+#endif
diff --git a/src/widgets/qradiobutton.h b/src/widgets/qradiobutton.h
new file mode 100644
index 0000000..2234a71
--- /dev/null
+++ b/src/widgets/qradiobutton.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Definition of QRadioButton class
+**
+** Created : 940222
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QRADIOBUTTON_H
+#define QRADIOBUTTON_H
+
+#ifndef QT_H
+#include "qbutton.h"
+#endif // QT_H
+
+#ifndef QT_NO_RADIOBUTTON
+
+class Q_EXPORT QRadioButton : public QButton
+{
+ Q_OBJECT
+ Q_PROPERTY( bool checked READ isChecked WRITE setChecked )
+ Q_OVERRIDE( bool autoMask DESIGNABLE true SCRIPTABLE true )
+
+public:
+ QRadioButton( QWidget *parent, const char* name=0 );
+ QRadioButton( const QString &text, QWidget *parent, const char* name=0 );
+
+ bool isChecked() const;
+
+ QSize sizeHint() const;
+
+public slots:
+ virtual void setChecked( bool check );
+
+protected:
+ bool hitButton( const QPoint & ) const;
+ void drawButton( QPainter * );
+ void drawButtonLabel( QPainter * );
+ void updateMask();
+
+ void resizeEvent( QResizeEvent* );
+
+private:
+ void init();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QRadioButton( const QRadioButton & );
+ QRadioButton &operator=( const QRadioButton & );
+#endif
+};
+
+
+inline bool QRadioButton::isChecked() const
+{ return isOn(); }
+
+#endif // QT_NO_RADIOBUTTON
+
+#endif // QRADIOBUTTON_H
diff --git a/src/widgets/qrangecontrol.cpp b/src/widgets/qrangecontrol.cpp
new file mode 100644
index 0000000..c329831
--- /dev/null
+++ b/src/widgets/qrangecontrol.cpp
@@ -0,0 +1,565 @@
+/****************************************************************************
+**
+** Implementation of QRangeControl class
+**
+** Created : 940427
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qrangecontrol.h"
+#ifndef QT_NO_RANGECONTROL
+#include "qglobal.h"
+#include <limits.h>
+
+static bool sumOutOfRange(int current, int add);
+
+
+/*!
+ \class QRangeControl qrangecontrol.h
+ \brief The QRangeControl class provides an integer value within a range.
+
+ \ingroup misc
+
+ Although originally designed for the QScrollBar widget, the
+ QRangeControl can also be used in conjunction with other widgets
+ such as QSlider and QSpinBox. Here are the five main concepts in
+ the class:
+
+ \list 1
+
+ \i \e{Current value} The bounded integer that
+ QRangeControl maintains. value() returns it, and several
+ functions, including setValue(), set it.
+
+ \i \e{Minimum} The lowest value that value() can ever
+ return. Returned by minValue() and set by setRange() or one of the
+ constructors.
+
+ \i \e{Maximum} The highest value that value() can ever
+ return. Returned by maxValue() and set by setRange() or one of the
+ constructors.
+
+ \i \e{Line step} The smaller of two natural steps that
+ QRangeControl provides and typically corresponds to the user
+ pressing an arrow key. The line step is returned by lineStep()
+ and set using setSteps(). The functions addLine() and
+ subtractLine() respectively increment and decrement the current
+ value by lineStep().
+
+ \i \e{Page step} The larger of two natural steps that
+ QRangeControl provides and typically corresponds to the user
+ pressing PageUp or PageDown. The page step is returned by
+ pageStep() and set using setSteps(). The functions addPage() and
+ substractPage() respectively increment and decrement the current
+ value by pageStep().
+
+ \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 minValue() + \e n * lineStep() for integer values of \e n.
+ Some widgets may allow the user to set any value at all; others
+ may just provide multiples of lineStep() or pageStep().
+
+ QRangeControl provides three virtual functions that are well
+ suited for updating the on-screen representation of range controls
+ and emitting signals: valueChange(), rangeChange() and
+ stepChange().
+
+ QRangeControl also provides a function called bound() which lets
+ you force arbitrary integers to be within the allowed range of the
+ range control.
+
+ We recommend that all widgets that inherit QRangeControl provide
+ at least a signal called valueChanged(); many widgets will want to
+ provide addStep(), addPage(), substractStep() and substractPage()
+ as slots.
+
+ Note that you must use multiple inheritance if you plan to
+ implement a widget using QRangeControl because QRangeControl is
+ not derived from QWidget.
+*/
+
+
+/*!
+ Constructs a range control with a minimum value of 0, maximum
+ value of 99, line step of 1, page step of 10 and initial value 0.
+*/
+
+QRangeControl::QRangeControl()
+{
+ minVal = 0;
+ maxVal = 99;
+ line = 1;
+ page = 10;
+ val = 0;
+ prevVal = -1;
+ d = 0;
+}
+
+/*!
+ Constructs a range control whose value can never be smaller than
+ \a minValue or greater than \a maxValue, whose line step size is
+ \a lineStep and page step size is \a pageStep and whose value is
+ initially \a value (which is guaranteed to be in range using
+ bound()).
+*/
+
+QRangeControl::QRangeControl( int minValue, int maxValue,
+ int lineStep, int pageStep,
+ int value )
+{
+ minVal = minValue;
+ maxVal = maxValue;
+ line = QABS( lineStep );
+ page = QABS( pageStep );
+ prevVal = minVal - 1;
+ val = bound( value );
+ d = 0;
+}
+
+/*!
+ Destroys the range control
+*/
+
+QRangeControl::~QRangeControl()
+{
+}
+
+
+/*!
+ \fn int QRangeControl::value() const
+
+ Returns the current range control value. This is guaranteed to be
+ within the range [minValue(), maxValue()].
+
+ \sa setValue() prevValue()
+*/
+
+/*!
+ \fn int QRangeControl::prevValue() const
+
+ Returns the previous value of the range control. "Previous value"
+ means the value before the last change occurred. Setting a new
+ range may affect the value, too, because the value is forced to be
+ inside the specified range. When the range control is initially
+ created, this is the same as value().
+
+ prevValue() can be outside the current legal range if a call to
+ setRange() causes the current value to change. For example, if the
+ range was [0, 1000] and the current value is 500, setRange(0, 400)
+ makes value() return 400 and prevValue() return 500.
+
+ \sa value() setRange()
+*/
+
+/*!
+ Sets the range control's value to \a value and forces it to be
+ within the legal range.
+
+ Calls the virtual valueChange() function if the new value is
+ different from the previous value. The old value can still be
+ retrieved using prevValue().
+
+ \sa value()
+*/
+
+void QRangeControl::setValue( int value )
+{
+ directSetValue( value );
+ if ( prevVal != val )
+ valueChange();
+}
+
+/*!
+ Sets the range control \a value directly without calling
+ valueChange().
+
+ Forces the new \a value to be within the legal range.
+
+ You will rarely have to call this function. However, if you want
+ to change the range control's value inside the overloaded method
+ valueChange(), setValue() would call the function valueChange()
+ again. To avoid this recursion you must use directSetValue()
+ instead.
+
+ \sa setValue()
+*/
+
+void QRangeControl::directSetValue(int value)
+{
+ prevVal = val;
+ val = bound( value );
+}
+
+/*!
+ Equivalent to \c{setValue( value() + pageStep() )}.
+
+ If the value is changed, then valueChange() is called.
+
+ \sa subtractPage() addLine() setValue()
+*/
+
+void QRangeControl::addPage()
+{
+ if (!sumOutOfRange(value(), pageStep()))
+ setValue(value() + pageStep());
+}
+
+/*!
+ Equivalent to \c{setValue( value() - pageStep() )}.
+
+ If the value is changed, then valueChange() is called.
+
+ \sa addPage() subtractLine() setValue()
+*/
+
+void QRangeControl::subtractPage()
+{
+ if (!sumOutOfRange(value(), -pageStep()))
+ setValue(value() - pageStep());
+}
+
+/*!
+ Equivalent to \c{setValue( value() + lineStep() )}.
+
+ If the value is changed, then valueChange() is called.
+
+ \sa subtractLine() addPage() setValue()
+*/
+
+void QRangeControl::addLine()
+{
+ if (!sumOutOfRange(value(), lineStep()))
+ setValue(value() + lineStep());
+}
+
+/*!
+ Equivalent to \c{setValue( value() - lineStep() )}.
+
+ If the value is changed, then valueChange() is called.
+
+ \sa addLine() subtractPage() setValue()
+*/
+
+void QRangeControl::subtractLine()
+{
+ if (!sumOutOfRange(value(), -lineStep()))
+ setValue(value() - lineStep());
+}
+
+
+/*!
+ \fn int QRangeControl::minValue() const
+
+ Returns the minimum value of the range.
+
+ \sa setMinValue() setRange() maxValue()
+*/
+
+/*!
+ \fn int QRangeControl::maxValue() const
+
+ Returns the maximum value of the range.
+
+ \sa setMaxValue() setRange() minValue()
+*/
+
+/*!
+ Sets the minimum value of the range to \a minVal.
+
+ If necessary, the maxValue() is adjusted so that the range remains
+ valid.
+
+ \sa minValue() setMaxValue()
+*/
+void QRangeControl::setMinValue( int minVal )
+{
+ int maxVal = maxValue();
+ if ( maxVal < minVal )
+ maxVal = minVal;
+ setRange( minVal, maxVal );
+}
+
+/*!
+ Sets the minimum value of the range to \a maxVal.
+
+ If necessary, the minValue() is adjusted so that the range remains
+ valid.
+
+ \sa maxValue() setMinValue()
+*/
+void QRangeControl::setMaxValue( int maxVal )
+{
+ int minVal = minValue();
+ if ( minVal > maxVal )
+ minVal = maxVal;
+ setRange( minVal, maxVal );
+}
+
+/*!
+ Sets the range control's minimum value to \a minValue and its
+ maximum value to \a maxValue.
+
+ Calls the virtual rangeChange() function if one or both of the new
+ minimum and maximum values are different from the previous
+ setting. Calls the virtual valueChange() function if the current
+ value is adjusted because it was outside the new range.
+
+ If \a maxValue is smaller than \a minValue, \a minValue becomes
+ the only legal value.
+
+ \sa minValue() maxValue()
+*/
+
+void QRangeControl::setRange( int minValue, int maxValue )
+{
+ if ( minValue > maxValue ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QRangeControl::setRange: minValue %d > maxValue %d",
+ minValue, maxValue );
+#endif
+ maxValue = minValue;
+ }
+ if ( minValue == minVal && maxValue == maxVal )
+ return;
+ minVal = minValue;
+ maxVal = maxValue;
+ int tmp = bound( val );
+ rangeChange();
+ if ( tmp != val ) {
+ prevVal = val;
+ val = tmp;
+ valueChange();
+ }
+}
+
+
+/*!
+ \fn int QRangeControl::lineStep() const
+
+ Returns the line step.
+
+ \sa setSteps() pageStep()
+*/
+
+/*!
+ \fn int QRangeControl::pageStep() const
+
+ Returns the page step.
+
+ \sa setSteps() lineStep()
+*/
+
+/*!
+ Sets the range's line step to \a lineStep and page step to \a
+ pageStep.
+
+ Calls the virtual stepChange() function if the new line step
+ or page step are different from the previous settings.
+
+ \sa lineStep() pageStep() setRange()
+*/
+
+void QRangeControl::setSteps( int lineStep, int pageStep )
+{
+ if ( lineStep != line || pageStep != page ) {
+ line = QABS( lineStep );
+ page = QABS( pageStep );
+ stepChange();
+ }
+}
+
+
+/*!
+ This virtual function is called whenever the range control value
+ changes. You can reimplement it if you want to be notified when
+ the value changes. The default implementation does nothing.
+
+ Note that this method is called after the value has changed. The
+ previous value can be retrieved using prevValue().
+
+ \sa setValue(), addPage(), subtractPage(), addLine(),
+ subtractLine() rangeChange(), stepChange()
+*/
+
+void QRangeControl::valueChange()
+{
+}
+
+
+/*!
+ This virtual function is called whenever the range control's range
+ changes. You can reimplement it if you want to be notified when
+ the range changes. The default implementation does nothing.
+
+ Note that this method is called after the range has changed.
+
+ \sa setRange(), valueChange(), stepChange()
+*/
+
+void QRangeControl::rangeChange()
+{
+}
+
+
+/*!
+ This virtual function is called whenever the range control's
+ line or page step settings change. You can reimplement it if you
+ want to be notified when the step changes. The default
+ implementation does nothing.
+
+ Note that this method is called after a step setting has changed.
+
+ \sa setSteps(), rangeChange(), valueChange()
+*/
+
+void QRangeControl::stepChange()
+{
+}
+
+
+/*!
+ Forces the value \a v to be within the range from minValue() to
+ maxValue() inclusive, and returns the result.
+
+ This function is provided so that you can easily force other
+ numbers than value() into the allowed range. You do not need to
+ call it in order to use QRangeControl itself.
+
+ \sa setValue() value() minValue() maxValue()
+*/
+
+int QRangeControl::bound( int v ) const
+{
+ if ( v < minVal )
+ return minVal;
+ if ( v > maxVal )
+ return maxVal;
+ return v;
+}
+
+
+/*!
+ Converts \a logical_val to a pixel position. minValue() maps to 0,
+ maxValue() maps to \a span and other values are distributed evenly
+ in-between.
+
+ This function can handle the entire integer range without
+ overflow, providing \a span is \<= 4096.
+
+ Calling this method is useful when actually drawing a range
+ control such as a QScrollBar on-screen.
+
+ \sa valueFromPosition()
+*/
+
+int QRangeControl::positionFromValue( int logical_val, int span ) const
+{
+ if ( span <= 0 || logical_val < minValue() || maxValue() <= minValue() )
+ return 0;
+ if ( logical_val > maxValue() )
+ return span;
+
+ uint range = maxValue() - minValue();
+ uint p = logical_val - minValue();
+
+ if ( range > (uint)INT_MAX/4096 ) {
+ const int scale = 4096*2;
+ return ( (p/scale) * span ) / (range/scale);
+ // ### the above line is probably not 100% correct
+ // ### but fixing it isn't worth the extreme pain...
+ } else if ( range > (uint)span ) {
+ return (2*p*span + range) / (2*range);
+ } else {
+ uint div = span / range;
+ uint mod = span % range;
+ return p*div + (2*p*mod + range) / (2*range);
+ }
+ //equiv. to (p*span)/range + 0.5
+ // no overflow because of this implicit assumption:
+ // span <= 4096
+}
+
+
+/*!
+ Converts the pixel position \a pos to a value. 0 maps to
+ minValue(), \a span maps to maxValue() and other values are
+ distributed evenly in-between.
+
+ This function can handle the entire integer range without
+ overflow.
+
+ Calling this method is useful if you actually implemented a range
+ control widget such as QScrollBar and want to handle mouse press
+ events. This function then maps screen coordinates to the logical
+ values.
+
+ \sa positionFromValue()
+*/
+
+int QRangeControl::valueFromPosition( int pos, int span ) const
+{
+ if ( span <= 0 || pos <= 0 )
+ return minValue();
+ if ( pos >= span )
+ return maxValue();
+
+ uint range = maxValue() - minValue();
+
+ if ( (uint)span > range )
+ return minValue() + (2*pos*range + span) / (2*span);
+ else {
+ uint div = range / span;
+ uint mod = range % span;
+ return minValue() + pos*div + (2*pos*mod + span) / (2*span);
+ }
+ // equiv. to minValue() + (pos*range)/span + 0.5
+ // no overflow because of this implicit assumption:
+ // pos <= span < sqrt(INT_MAX+0.0625)+0.25 ~ sqrt(INT_MAX)
+}
+
+static bool sumOutOfRange(int current, int add)
+{
+ if (add > 0 && INT_MAX - add < current) {
+ return true;
+ }
+ if (add < 0 && INT_MIN - add > current) {
+ return true;
+ }
+ return false;
+}
+
+#endif
diff --git a/src/widgets/qrangecontrol.h b/src/widgets/qrangecontrol.h
new file mode 100644
index 0000000..4efb37d
--- /dev/null
+++ b/src/widgets/qrangecontrol.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Definition of QRangeControl class
+**
+** Created : 940427
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QRANGECONTROL_H
+#define QRANGECONTROL_H
+
+#ifndef QT_H
+#include "qglobal.h"
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_RANGECONTROL
+
+
+class QRangeControlPrivate;
+
+
+class Q_EXPORT QRangeControl
+{
+public:
+ QRangeControl();
+ QRangeControl( int minValue, int maxValue,
+ int lineStep, int pageStep, int value );
+ virtual ~QRangeControl();
+ int value() const;
+ void setValue( int );
+ void addPage();
+ void subtractPage();
+ void addLine();
+ void subtractLine();
+
+ int minValue() const;
+ int maxValue() const;
+ void setRange( int minValue, int maxValue );
+ void setMinValue( int minVal );
+ void setMaxValue( int minVal );
+
+ int lineStep() const;
+ int pageStep() const;
+ void setSteps( int line, int page );
+
+ int bound( int ) const;
+
+protected:
+ int positionFromValue( int val, int space ) const;
+ int valueFromPosition( int pos, int space ) const;
+ void directSetValue( int val );
+ int prevValue() const;
+
+ virtual void valueChange();
+ virtual void rangeChange();
+ virtual void stepChange();
+
+private:
+ int minVal, maxVal;
+ int line, page;
+ int val, prevVal;
+
+ QRangeControlPrivate * d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QRangeControl( const QRangeControl & );
+ QRangeControl &operator=( const QRangeControl & );
+#endif
+};
+
+
+inline int QRangeControl::value() const
+{ return val; }
+
+inline int QRangeControl::prevValue() const
+{ return prevVal; }
+
+inline int QRangeControl::minValue() const
+{ return minVal; }
+
+inline int QRangeControl::maxValue() const
+{ return maxVal; }
+
+inline int QRangeControl::lineStep() const
+{ return line; }
+
+inline int QRangeControl::pageStep() const
+{ return page; }
+
+
+#endif // QT_NO_RANGECONTROL
+
+#ifndef QT_NO_SPINWIDGET
+
+class QSpinWidgetPrivate;
+class Q_EXPORT QSpinWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QSpinWidget( QWidget* parent=0, const char* name=0 );
+ ~QSpinWidget();
+
+ void setEditWidget( QWidget * widget );
+ QWidget * editWidget();
+
+ QRect upRect() const;
+ QRect downRect() const;
+
+ void setUpEnabled( bool on );
+ void setDownEnabled( bool on );
+
+ bool isUpEnabled() const;
+ bool isDownEnabled() const;
+
+ enum ButtonSymbols { UpDownArrows, PlusMinus };
+ virtual void setButtonSymbols( ButtonSymbols bs );
+ ButtonSymbols buttonSymbols() const;
+
+ void arrange();
+
+signals:
+ void stepUpPressed();
+ void stepDownPressed();
+
+public slots:
+ void stepUp();
+ void stepDown();
+
+protected:
+ void mousePressEvent( QMouseEvent *e );
+ void resizeEvent( QResizeEvent* ev );
+ void mouseReleaseEvent( QMouseEvent *e );
+ void mouseMoveEvent( QMouseEvent *e );
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent * );
+#endif
+ void styleChange( QStyle& );
+ void paintEvent( QPaintEvent * );
+ void enableChanged( bool old );
+ void windowActivationChange( bool );
+
+private slots:
+ void timerDone();
+ void timerDoneEx();
+
+private:
+ QSpinWidgetPrivate * d;
+
+ void updateDisplay();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QSpinWidget( const QSpinWidget& );
+ QSpinWidget& operator=( const QSpinWidget& );
+#endif
+};
+
+#endif // QT_NO_SPINWIDGET
+
+#endif // QRANGECONTROL_H
diff --git a/src/widgets/qscrollbar.cpp b/src/widgets/qscrollbar.cpp
new file mode 100644
index 0000000..9a5e8f4
--- /dev/null
+++ b/src/widgets/qscrollbar.cpp
@@ -0,0 +1,1072 @@
+/****************************************************************************
+**
+** Implementation of QScrollBar class
+**
+** Created : 940427
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qscrollbar.h"
+#ifndef QT_NO_SCROLLBAR
+#include "qpainter.h"
+#include "qbitmap.h"
+#include "qapplication.h"
+#include "qtimer.h"
+#include "qstyle.h"
+#ifndef QT_NO_CURSOR
+#include <qcursor.h>
+#endif
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+#include <limits.h>
+
+/*!
+ \class QScrollBar
+ \brief The QScrollBar widget provides a vertical or horizontal scroll bar.
+
+ \ingroup basic
+
+ A scroll bar allows the user to control a value within a
+ program-definable range and gives users a visible indication of
+ the current value of a \link QRangeControl range control \endlink.
+
+ Scroll bars include four separate controls:
+
+ \list
+
+ \i The \e line-up and \e line-down controls are little buttons
+ which the user can use to move one "line" up or down. The meaning
+ of line is configurable. In editors and list boxes it means one
+ line of text; in an image viewer it might mean 20 pixels.
+
+ \i The \e slider is the handle that indicates the current value of
+ the scroll bar, which the user can drag to change the value. This
+ part of the scroll bar is sometimes called the "thumb".
+
+ \i The \e page-up/page-down control is the area on which the
+ slider slides (the scroll bar's background). Clicking here moves
+ the scroll bar towards the click. The meaning of "page" is also
+ configurable: in editors and list boxes it means as many lines as
+ there is space for in the widget.
+
+ \endlist
+
+ QScrollBar has very few of its own functions; it mostly relies on
+ QRangeControl. The most useful functions are setValue() to set the
+ scroll bar directly to some value; addPage(), addLine(),
+ subtractPage(), and subtractLine() to simulate the effects of
+ clicking (useful for accelerator keys); setSteps() to define the
+ values of pageStep() and lineStep(); and setRange() to set the
+ minValue() and maxValue() of the scroll bar. QScrollBar has a
+ convenience constructor with which you can set most of these
+ properties.
+
+ Some GUI styles (for example, the Windows and Motif styles
+ provided with Qt), also use the pageStep() value to calculate the
+ size of the slider.
+
+ In addition to the access functions from QRangeControl, QScrollBar
+ provides a comprehensive set of signals:
+ \table
+ \header \i Signal \i Emitted when
+ \row \i \l valueChanged()
+ \i the scroll bar's value has changed. The 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 nextLine()
+ \i the scroll bar has moved one line down or right. Line is
+ defined in QRangeControl.
+ \row \i \l prevLine()
+ \i the scroll bar has moved one line up or left.
+ \row \i \l nextPage()
+ \i the scroll bar has moved one page down or right.
+ \row \i \l prevPage()
+ \i the scroll bar has moved one page up or left.
+ \endtable
+
+ QScrollBar only provides integer ranges. Note that although
+ QScrollBar handles very large numbers, scroll bars on current
+ screens cannot usefully control ranges above about 100,000 pixels.
+ Beyond that, it becomes difficult for the user to control the
+ scroll bar using either the keyboard or the mouse.
+
+ A scroll bar can be controlled by the keyboard, but it has a
+ default focusPolicy() of \c NoFocus. Use setFocusPolicy() to
+ enable keyboard focus. See keyPressEvent() for a list of key
+ bindings.
+
+ If you need to add scroll bars to an interface, consider using the
+ QScrollView class, which encapsulates the common uses for scroll
+ bars.
+
+ <img src=qscrbar-m.png> <img src=qscrbar-w.png>
+
+ \sa QSlider QSpinBox QScrollView
+ \link guibooks.html#fowler GUI Design Handbook: Scroll Bar\endlink
+*/
+
+
+/*!
+ \fn void QScrollBar::valueChanged( int value )
+
+ This signal is emitted when the scroll bar value has changed, with
+ the new scroll bar \a value as an argument.
+*/
+
+/*!
+ \fn void QScrollBar::sliderPressed()
+
+ This signal is emitted when the user presses the slider with the
+ mouse.
+*/
+
+/*!
+ \fn void QScrollBar::sliderMoved( int value )
+
+ This signal is emitted when the slider is dragged by the user, with
+ the new scroll bar \a value as an argument.
+
+ This signal is emitted even when tracking is turned off.
+
+ \sa tracking() valueChanged() nextLine() prevLine() nextPage()
+ prevPage()
+*/
+
+/*!
+ \fn void QScrollBar::sliderReleased()
+
+ This signal is emitted when the user releases the slider with the
+ mouse.
+*/
+
+/*!
+ \fn void QScrollBar::nextLine()
+
+ This signal is emitted when the scroll bar scrolls one line down
+ or right.
+*/
+
+/*!
+ \fn void QScrollBar::prevLine()
+
+ This signal is emitted when the scroll bar scrolls one line up or
+ left.
+*/
+
+/*!
+ \fn void QScrollBar::nextPage()
+
+ This signal is emitted when the scroll bar scrolls one page down
+ or right.
+*/
+
+/*!
+ \fn void QScrollBar::prevPage()
+
+ This signal is emitted when the scroll bar scrolls one page up or
+ left.
+*/
+
+
+
+static const int thresholdTime = 500;
+static const int repeatTime = 50;
+
+#define HORIZONTAL (orientation() == Horizontal)
+#define VERTICAL !HORIZONTAL
+#define MOTIF_BORDER 2
+#define SLIDER_MIN 9
+
+
+/*!
+ Constructs a vertical scroll bar.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+
+ The \c minValue defaults to 0, the \c maxValue to 99, with a \c
+ lineStep size of 1 and a \c pageStep size of 10, and an initial
+ \c value of 0.
+*/
+
+QScrollBar::QScrollBar( QWidget *parent, const char *name )
+ : QWidget( parent, name ), orient( Vertical )
+{
+ init();
+}
+
+/*!
+ Constructs a scroll bar.
+
+ The \a orientation must be \c Qt::Vertical or \c Qt::Horizontal.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+
+ The \c minValue defaults to 0, the \c maxValue to 99, with a \c
+ lineStep size of 1 and a \c pageStep size of 10, and an initial
+ \c value of 0.
+*/
+
+QScrollBar::QScrollBar( Orientation orientation, QWidget *parent,
+ const char *name )
+ : QWidget( parent, name ), orient( orientation )
+{
+ init();
+}
+
+/*!
+ Constructs a scroll bar whose value can never be smaller than \a
+ minValue or greater than \a maxValue, whose line step size is \a
+ lineStep and page step size is \a pageStep and whose value is
+ initially \a value (which is guaranteed to be in range using
+ bound()).
+
+ If \a orientation is \c Vertical the scroll bar is vertical and if
+ it is \c Horizontal the scroll bar is horizontal.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QScrollBar::QScrollBar( int minValue, int maxValue, int lineStep, int pageStep,
+ int value, Orientation orientation,
+ QWidget *parent, const char *name )
+ : QWidget( parent, name ),
+ QRangeControl( minValue, maxValue, lineStep, pageStep, value ),
+ orient( orientation )
+{
+ init();
+}
+
+/*!
+ Destructor.
+*/
+QScrollBar::~QScrollBar()
+{
+}
+
+void QScrollBar::init()
+{
+ track = TRUE;
+ sliderPos = 0;
+ pressedControl = QStyle::SC_None;
+ clickedAt = FALSE;
+ setFocusPolicy( NoFocus );
+
+ repeater = 0;
+
+ setBackgroundMode((Qt::BackgroundMode)
+ style().styleHint(QStyle::SH_ScrollBar_BackgroundMode));
+
+ QSizePolicy sp( QSizePolicy::Minimum, QSizePolicy::Fixed );
+ if ( orient == Vertical )
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+}
+
+
+/*!
+ \property QScrollBar::orientation
+ \brief the orientation of the scroll bar
+
+ The orientation must be \l Qt::Vertical (the default) or \l
+ Qt::Horizontal.
+*/
+
+void QScrollBar::setOrientation( Orientation orientation )
+{
+ if ( orientation == orient )
+ return;
+ if ( !testWState( WState_OwnSizePolicy ) ) {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+ }
+
+ orient = orientation;
+
+ positionSliderFromValue();
+ update();
+ updateGeometry();
+}
+
+/*!
+ \property QScrollBar::tracking
+ \brief whether scroll bar tracking is enabled
+
+ If tracking is enabled (the default), the scroll bar emits the
+ valueChanged() signal while the slider is being dragged. If
+ tracking is disabled, the scroll bar emits the valueChanged()
+ signal only when the user releases the mouse button after moving
+ the slider.
+*/
+
+
+/*!
+ \property QScrollBar::draggingSlider
+ \brief whether the user has clicked the mouse on the slider and is currently dragging it
+*/
+
+bool QScrollBar::draggingSlider() const
+{
+ return pressedControl == QStyle::SC_ScrollBarSlider;
+}
+
+
+/*!
+ Reimplements the virtual function QWidget::setPalette().
+
+ Sets the background color to the mid color for Motif style scroll
+ bars using palette \a p.
+*/
+
+void QScrollBar::setPalette( const QPalette &p )
+{
+ QWidget::setPalette( p );
+ setBackgroundMode((Qt::BackgroundMode)
+ style().styleHint(QStyle::SH_ScrollBar_BackgroundMode));
+}
+
+
+/*! \reimp */
+QSize QScrollBar::sizeHint() const
+{
+ constPolish();
+ int sbextent = style().pixelMetric(QStyle::PM_ScrollBarExtent, this);
+
+ if ( orient == Horizontal ) {
+ return QSize( 30, sbextent );
+ } else {
+ return QSize( sbextent, 30 );
+ }
+}
+
+/*! \fn void QScrollBar::setSizePolicy( QSizePolicy::SizeType, QSizePolicy::SizeType, bool )
+ \reimp
+*/
+
+/*! \reimp */
+void QScrollBar::setSizePolicy( QSizePolicy sp )
+{
+ //## remove 4.0
+ QWidget::setSizePolicy( sp );
+}
+
+/*!
+ \internal
+ Implements the virtual QRangeControl function.
+*/
+
+void QScrollBar::valueChange()
+{
+ int tmp = sliderPos;
+ positionSliderFromValue();
+ if ( tmp != sliderPos && isVisible() )
+ drawControls(QStyle::SC_ScrollBarAddPage |
+ QStyle::SC_ScrollBarSubPage |
+ QStyle::SC_ScrollBarSlider,
+ pressedControl );
+ emit valueChanged(value());
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+/*!
+ \internal
+ Implements the virtual QRangeControl function.
+*/
+
+void QScrollBar::stepChange()
+{
+ rangeChange();
+}
+
+/*!
+ \internal
+ Implements the virtual QRangeControl function.
+*/
+
+void QScrollBar::rangeChange()
+{
+ positionSliderFromValue();
+
+ if ( isVisible() )
+ drawControls(QStyle::SC_ScrollBarAddLine |
+ QStyle::SC_ScrollBarSubLine |
+ QStyle::SC_ScrollBarAddPage |
+ QStyle::SC_ScrollBarSubPage |
+ QStyle::SC_ScrollBarFirst |
+ QStyle::SC_ScrollBarLast |
+ QStyle::SC_ScrollBarSlider,
+ pressedControl );
+}
+
+
+/*!
+ Handles timer events for the scroll bar.
+*/
+
+void QScrollBar::doAutoRepeat()
+{
+ bool sendRepeat = clickedAt;
+#if !defined( QT_NO_CURSOR ) && !defined( QT_NO_STYLE )
+ if(sendRepeat && (pressedControl == QStyle::SC_ScrollBarAddPage ||
+ pressedControl == QStyle::SC_ScrollBarSubPage) &&
+ style().styleHint(QStyle::SH_ScrollBar_StopMouseOverSlider, this) &&
+ style().querySubControl(QStyle::CC_ScrollBar, this,
+ mapFromGlobal(QCursor::pos()) ) == QStyle::SC_ScrollBarSlider)
+ sendRepeat = FALSE;
+#endif
+ if ( sendRepeat ){
+ if ( repeater )
+ repeater->changeInterval( repeatTime );
+ action( (QStyle::SubControl) pressedControl );
+ QApplication::syncX();
+ } else {
+ stopAutoRepeat();
+ }
+}
+
+
+/*!
+ Starts the auto-repeat logic. Some time after this function is
+ called, the auto-repeat starts taking effect and from then on
+ repeats until stopAutoRepeat() is called.
+*/
+
+void QScrollBar::startAutoRepeat()
+{
+ if ( !repeater ) {
+ repeater = new QTimer( this, "auto-repeat timer" );
+ connect( repeater, SIGNAL(timeout()),
+ this, SLOT(doAutoRepeat()) );
+ }
+ repeater->start( thresholdTime, FALSE );
+}
+
+
+/*!
+ Stops the auto-repeat logic.
+*/
+
+void QScrollBar::stopAutoRepeat()
+{
+ delete repeater;
+ repeater = 0;
+}
+
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QScrollBar::wheelEvent( QWheelEvent *e )
+{
+ static float offset = 0;
+ static QScrollBar* offset_owner = 0;
+ if (offset_owner != this){
+ offset_owner = this;
+ offset = 0;
+ }
+ if ( e->orientation() != orient && !rect().contains(e->pos()) )
+ return;
+ e->accept();
+ int step = QMIN( QApplication::wheelScrollLines()*lineStep(),
+ pageStep() );
+ if ( ( e->state() & ControlButton ) || ( e->state() & ShiftButton ) )
+ step = pageStep();
+ offset += -e->delta()*step/120;
+ if (QABS(offset)<1)
+ return;
+ setValue( value() + int(offset) );
+ offset -= int(offset);
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QScrollBar::keyPressEvent( QKeyEvent *e )
+{
+ // \list
+ // \i Left/Right move a horizontal scrollbar by one line.
+ // \i Up/Down move a vertical scrollbar by one line.
+ // \i PageUp moves up one page.
+ // \i PageDown moves down one page.
+ // \i Home moves to the start (minValue()).
+ // \i End moves to the end (maxValue()).
+ // \endlist
+
+ // Note that unless you call setFocusPolicy(), the default NoFocus
+ // will apply and the user will not be able to use the keyboard to
+ // interact with the scrollbar.
+ switch ( e->key() ) {
+ case Key_Left:
+ if ( orient == Horizontal )
+ subtractLine();
+ break;
+ case Key_Right:
+ if ( orient == Horizontal )
+ addLine();
+ break;
+ case Key_Up:
+ if ( orient == Vertical )
+ subtractLine();
+ break;
+ case Key_Down:
+ if ( orient == Vertical )
+ addLine();
+ break;
+ case Key_PageUp:
+ subtractPage();
+ break;
+ case Key_PageDown:
+ addPage();
+ break;
+ case Key_Home:
+ setValue( minValue() );
+ break;
+ case Key_End:
+ setValue( maxValue() );
+ break;
+ default:
+ e->ignore();
+ break;
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollBar::resizeEvent( QResizeEvent * )
+{
+ positionSliderFromValue();
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollBar::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ drawControls(QStyle::SC_ScrollBarAddLine |
+ QStyle::SC_ScrollBarSubLine |
+ QStyle::SC_ScrollBarAddPage |
+ QStyle::SC_ScrollBarSubPage |
+ QStyle::SC_ScrollBarFirst |
+ QStyle::SC_ScrollBarLast |
+ QStyle::SC_ScrollBarSlider,
+ pressedControl, &p );
+}
+
+static QCOORD sliderStartPos = 0;
+
+/*!
+ \reimp
+ */
+void QScrollBar::contextMenuEvent( QContextMenuEvent *e )
+{
+ if(clickedAt)
+ e->consume();
+ else
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void QScrollBar::mousePressEvent( QMouseEvent *e )
+{
+ bool midButtonAbsPos =
+ style().styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition,
+ this);
+
+ if ( !(e->button() == LeftButton ||
+ (midButtonAbsPos && e->button() == MidButton) ) )
+ return;
+
+ if ( maxValue() == minValue() ) // nothing to be done
+ return;
+
+ if ( e->state() & MouseButtonMask ) // another button was already pressed
+ return;
+
+ clickedAt = TRUE;
+ pressedControl = style().querySubControl(QStyle::CC_ScrollBar, this, e->pos() );
+
+ if ( (pressedControl == QStyle::SC_ScrollBarAddPage ||
+ pressedControl == QStyle::SC_ScrollBarSubPage ||
+ pressedControl == QStyle::SC_ScrollBarSlider ) &&
+ ((midButtonAbsPos && e->button() == MidButton) ||
+ style().styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition) && e->button() == LeftButton)) {
+
+ QRect sr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarSlider ),
+ gr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarGroove );
+ int sliderMin, sliderMax, sliderLength;
+ sliderMin = sliderMax = sliderLength = 0;
+ if (HORIZONTAL) {
+ sliderMin = gr.x();
+ sliderMax = sliderMin + gr.width();
+ sliderLength = sr.width();
+ } else {
+ sliderMin = gr.y();
+ sliderMax = sliderMin + gr.height();
+ sliderLength = sr.height();
+ }
+
+ int newSliderPos = (HORIZONTAL ? e->pos().x() : e->pos().y())
+ - sliderLength/2;
+ newSliderPos = QMIN( newSliderPos, sliderMax - sliderLength );
+ newSliderPos = QMAX( newSliderPos, sliderMin );
+ setValue( sliderPosToRangeValue(newSliderPos) );
+ sliderPos = newSliderPos;
+ pressedControl = QStyle::SC_ScrollBarSlider;
+ }
+
+ if ( pressedControl == QStyle::SC_ScrollBarSlider ) {
+ clickOffset = (QCOORD)( (HORIZONTAL ? e->pos().x() : e->pos().y())
+ - sliderPos );
+ slidePrevVal = value();
+ sliderStartPos = sliderPos;
+ drawControls( pressedControl, pressedControl );
+ emit sliderPressed();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ScrollingStart );
+#endif
+ } else if ( pressedControl != QStyle::SC_None ) {
+ drawControls( pressedControl, pressedControl );
+ action( (QStyle::SubControl) pressedControl );
+ startAutoRepeat();
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollBar::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !clickedAt )
+ return;
+
+ if ( e->stateAfter() & MouseButtonMask ) // some other button is still pressed
+ return;
+
+ QStyle::SubControl tmp = (QStyle::SubControl) pressedControl;
+ clickedAt = FALSE;
+ stopAutoRepeat();
+ mouseMoveEvent( e ); // Might have moved since last mouse move event.
+ pressedControl = QStyle::SC_None;
+
+ if (tmp == QStyle::SC_ScrollBarSlider) {
+ directSetValue( calculateValueFromSlider() );
+ emit sliderReleased();
+ if ( value() != prevValue() ) {
+ emit valueChanged( value() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+ }
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ScrollingEnd );
+#endif
+ }
+ drawControls( tmp, pressedControl );
+ if ( e->button() == MidButton )
+ repaint( FALSE );
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollBar::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !isVisible() ) {
+ clickedAt = FALSE;
+ return;
+ }
+
+ bool mcab = style().styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition,
+ this);
+ if ( ! clickedAt || ! (e->state() & LeftButton ||
+ ((e->state() & MidButton) && mcab)))
+ return;
+
+ int newSliderPos;
+ if ( pressedControl == QStyle::SC_ScrollBarSlider ) {
+ QRect gr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarGroove ),
+ sr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarSlider );
+ int sliderMin, sliderMax, sliderLength;
+
+ if (HORIZONTAL) {
+ sliderLength = sr.width();
+ sliderMin = gr.x();
+ sliderMax = gr.right() - sliderLength + 1;
+ } else {
+ sliderLength = sr.height();
+ sliderMin = gr.y();
+ sliderMax = gr.bottom() - sliderLength + 1;
+ }
+
+ QRect r = rect();
+ int m = style().pixelMetric(QStyle::PM_MaximumDragDistance, this);
+ if ( m >= 0 ) {
+ if ( orientation() == Horizontal )
+ r.setRect( r.x() - m, r.y() - 2*m, r.width() + 2*m, r.height() + 4*m );
+ else
+ r.setRect( r.x() - 2*m, r.y() - m, r.width() + 4*m, r.height() + 2*m );
+ if (! r.contains( e->pos()))
+ newSliderPos = sliderStartPos;
+ else
+ newSliderPos = (HORIZONTAL ? e->pos().x() :
+ e->pos().y()) -clickOffset;
+ } else
+ newSliderPos = (HORIZONTAL ? e->pos().x() :
+ e->pos().y()) -clickOffset;
+
+ if ( newSliderPos < sliderMin )
+ newSliderPos = sliderMin;
+ else if ( newSliderPos > sliderMax )
+ newSliderPos = sliderMax;
+ int newVal = sliderPosToRangeValue(newSliderPos);
+ if ( newVal != slidePrevVal )
+ emit sliderMoved( newVal );
+ if ( track && newVal != value() ) {
+ directSetValue( newVal ); // Set directly, painting done below
+ emit valueChanged( value() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+ }
+ slidePrevVal = newVal;
+ sliderPos = (QCOORD)newSliderPos;
+ drawControls( QStyle::SC_ScrollBarAddPage |
+ QStyle::SC_ScrollBarSlider |
+ QStyle::SC_ScrollBarSubPage,
+ pressedControl );
+ } else if (! style().styleHint(QStyle::SH_ScrollBar_ScrollWhenPointerLeavesControl)) {
+ // stop scrolling when the mouse pointer leaves a control
+ // similar to push buttons
+ if ( pressedControl != (uint)style().querySubControl(QStyle::CC_ScrollBar, this, e->pos() ) ) {
+ drawControls( pressedControl, QStyle::SC_None );
+ stopAutoRepeat();
+ } else if ( !repeater ) {
+ drawControls( pressedControl, pressedControl );
+ action( (QStyle::SubControl) pressedControl );
+ startAutoRepeat();
+ }
+ }
+}
+
+
+/*!
+ \fn int QScrollBar::sliderStart() const
+
+ Returns the pixel position where the scroll bar slider starts.
+
+ This is equivalent to sliderRect().y() for vertical scroll bars or
+ sliderRect().x() for horizontal scroll bars.
+*/
+
+/*!
+ Returns the scroll bar slider rectangle.
+
+ \sa sliderStart()
+*/
+
+QRect QScrollBar::sliderRect() const
+{
+ return style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarSlider );
+}
+
+void QScrollBar::positionSliderFromValue()
+{
+ sliderPos = (QCOORD)rangeValueToSliderPos( value() );
+}
+
+int QScrollBar::calculateValueFromSlider() const
+{
+ return sliderPosToRangeValue( sliderPos );
+}
+
+int QScrollBar::rangeValueToSliderPos( int v ) const
+{
+ QRect gr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarGroove );
+ QRect sr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarSlider );
+ int sliderMin, sliderMax, sliderLength;
+
+ if (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 positionFromValue( v, sliderMax-sliderMin ) + sliderMin;
+}
+
+int QScrollBar::sliderPosToRangeValue( int pos ) const
+{
+ QRect gr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarGroove );
+ QRect sr = style().querySubControlMetrics(QStyle::CC_ScrollBar, this,
+ QStyle::SC_ScrollBarSlider );
+ int sliderMin, sliderMax, sliderLength;
+
+ if (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 valueFromPosition( pos - sliderMin, sliderMax - sliderMin );
+}
+
+
+void QScrollBar::action( int control )
+{
+ switch( control ) {
+ case QStyle::SC_ScrollBarAddLine:
+ addLine();
+ emit nextLine();
+ break;
+ case QStyle::SC_ScrollBarSubLine:
+ subtractLine();
+ emit prevLine();
+ break;
+ case QStyle::SC_ScrollBarAddPage:
+ addPage();
+ emit nextPage();
+ break;
+ case QStyle::SC_ScrollBarSubPage:
+ subtractPage();
+ emit prevPage();
+ break;
+ case QStyle::SC_ScrollBarFirst:
+ setValue( minValue() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+ emit valueChanged( minValue() );
+ break;
+ case QStyle::SC_ScrollBarLast:
+ setValue( maxValue() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+ emit valueChanged( maxValue() );
+ break;
+ default:
+ break;
+ }
+}
+
+
+void QScrollBar::drawControls( uint controls, uint activeControl ) const
+{
+ QPainter p ( this );
+ drawControls( controls, activeControl, &p );
+}
+
+
+void QScrollBar::drawControls( uint controls, uint activeControl,
+ QPainter *p ) const
+{
+ if ( !isUpdatesEnabled() )
+ return;
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if ( orientation() == Horizontal )
+ flags |= QStyle::Style_Horizontal;
+
+ style().drawComplexControl(QStyle::CC_ScrollBar, p, this, rect(), colorGroup(),
+ flags, (QStyle::SubControl) controls,
+ (QStyle::SubControl) activeControl );
+}
+
+/*!
+ \reimp
+*/
+void QScrollBar::styleChange( QStyle& old )
+{
+ positionSliderFromValue();
+ setBackgroundMode((Qt::BackgroundMode)
+ style().styleHint(QStyle::SH_ScrollBar_BackgroundMode));
+ QWidget::styleChange( old );
+}
+
+/*!
+ \property QScrollBar::minValue
+ \brief the scroll bar's minimum value
+
+ When setting this property, the \l QScrollBar::maxValue is
+ adjusted if necessary to ensure that the range remains valid.
+
+ \sa setRange()
+*/
+int QScrollBar::minValue() const
+{
+ return QRangeControl::minValue();
+}
+
+void QScrollBar::setMinValue( int minVal )
+{
+ QRangeControl::setMinValue( minVal );
+}
+
+/*!
+ \property QScrollBar::maxValue
+ \brief the scroll bar's maximum value
+
+ When setting this property, the \l QScrollBar::minValue is
+ adjusted if necessary to ensure that the range remains valid.
+
+ \sa setRange()
+*/
+int QScrollBar::maxValue() const
+{
+ return QRangeControl::maxValue();
+}
+
+void QScrollBar::setMaxValue( int maxVal )
+{
+ QRangeControl::setMaxValue( maxVal );
+}
+
+/*!
+ \property QScrollBar::lineStep
+ \brief the line step
+
+ When setting lineStep, the virtual stepChange() function will be
+ called if the new line step is different from the previous
+ setting.
+
+ \sa setSteps() QRangeControl::pageStep() setRange()
+*/
+
+int QScrollBar::lineStep() const
+{
+ return QRangeControl::lineStep();
+}
+
+/*!
+ \property QScrollBar::pageStep
+ \brief the page step
+
+ When setting pageStep, the virtual stepChange() function will be
+ called if the new page step is different from the previous
+ setting.
+
+ \sa QRangeControl::setSteps() setLineStep() setRange()
+*/
+
+int QScrollBar::pageStep() const
+{
+ return QRangeControl::pageStep();
+}
+
+void QScrollBar::setLineStep( int i )
+{
+ setSteps( i, pageStep() );
+}
+
+void QScrollBar::setPageStep( int i )
+{
+ setSteps( lineStep(), i );
+}
+
+/*!
+ \property QScrollBar::value
+ \brief the scroll bar's value
+
+ \sa QRangeControl::value() prevValue()
+*/
+
+int QScrollBar::value() const
+{
+ return QRangeControl::value();
+}
+
+void QScrollBar::setValue( int i )
+{
+ QRangeControl::setValue( i );
+}
+
+
+/*!
+ This function is called when the scrollbar is hidden.
+*/
+void QScrollBar::hideEvent( QHideEvent* )
+{
+ pressedControl = QStyle::SC_None;
+ clickedAt = FALSE;
+}
+
+
+#undef ADD_LINE_ACTIVE
+#undef SUB_LINE_ACTIVE
+#endif
diff --git a/src/widgets/qscrollbar.h b/src/widgets/qscrollbar.h
new file mode 100644
index 0000000..c8960f4
--- /dev/null
+++ b/src/widgets/qscrollbar.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Definition of QScrollBar class
+**
+** Created : 940427
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSCROLLBAR_H
+#define QSCROLLBAR_H
+
+class QTimer;
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qrangecontrol.h"
+#endif // QT_H
+
+#ifndef QT_NO_SCROLLBAR
+
+class Q_EXPORT QScrollBar : public QWidget, public QRangeControl
+{
+ Q_OBJECT
+ Q_PROPERTY( int minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( int lineStep READ lineStep WRITE setLineStep )
+ Q_PROPERTY( int pageStep READ pageStep WRITE setPageStep )
+ Q_PROPERTY( int value READ value WRITE setValue )
+ Q_PROPERTY( bool tracking READ tracking WRITE setTracking )
+ Q_PROPERTY( bool draggingSlider READ draggingSlider )
+ Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation )
+
+public:
+ QScrollBar( QWidget *parent, const char* name = 0 );
+ QScrollBar( Orientation, QWidget *parent, const char* name = 0 );
+ QScrollBar( int minValue, int maxValue, int lineStep, int pageStep,
+ int value, Orientation, QWidget *parent, const char* name = 0 );
+ ~QScrollBar();
+
+ virtual void setOrientation( Orientation );
+ Orientation orientation() const;
+ virtual void setTracking( bool enable );
+ bool tracking() const;
+ bool draggingSlider() const;
+
+ virtual void setPalette( const QPalette & );
+ virtual QSize sizeHint() const;
+ virtual void setSizePolicy( QSizePolicy sp );
+ void setSizePolicy( QSizePolicy::SizeType hor, QSizePolicy::SizeType ver, bool hfw = FALSE );
+
+ int minValue() const;
+ int maxValue() const;
+ void setMinValue( int );
+ void setMaxValue( int );
+ int lineStep() const;
+ int pageStep() const;
+ void setLineStep( int );
+ void setPageStep( int );
+ int value() const;
+
+ int sliderStart() const;
+ QRect sliderRect() const;
+
+public slots:
+ void setValue( int );
+
+signals:
+ void valueChanged( int value );
+ void sliderPressed();
+ void sliderMoved( int value );
+ void sliderReleased();
+ void nextLine();
+ void prevLine();
+ void nextPage();
+ void prevPage();
+
+protected:
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent * );
+#endif
+ void keyPressEvent( QKeyEvent * );
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void contextMenuEvent( QContextMenuEvent * );
+ void hideEvent( QHideEvent* );
+
+ void valueChange();
+ void stepChange();
+ void rangeChange();
+
+ void styleChange( QStyle& );
+
+private slots:
+ void doAutoRepeat();
+
+private:
+ void init();
+ void positionSliderFromValue();
+ int calculateValueFromSlider() const;
+
+ void startAutoRepeat();
+ void stopAutoRepeat();
+
+ int rangeValueToSliderPos( int val ) const;
+ int sliderPosToRangeValue( int val ) const;
+
+ void action( int control );
+
+ void drawControls( uint controls, uint activeControl ) const;
+ void drawControls( uint controls, uint activeControl,
+ QPainter *p ) const;
+
+ uint pressedControl;
+ bool track;
+ bool clickedAt;
+ Orientation orient;
+
+ int slidePrevVal;
+ QCOORD sliderPos;
+ QCOORD clickOffset;
+
+ QTimer * repeater;
+ void * d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QScrollBar( const QScrollBar & );
+ QScrollBar &operator=( const QScrollBar & );
+#endif
+};
+
+
+inline void QScrollBar::setTracking( bool t )
+{
+ track = t;
+}
+
+inline bool QScrollBar::tracking() const
+{
+ return track;
+}
+
+inline QScrollBar::Orientation QScrollBar::orientation() const
+{
+ return orient;
+}
+
+inline int QScrollBar::sliderStart() const
+{
+ return sliderPos;
+}
+
+inline void QScrollBar::setSizePolicy( QSizePolicy::SizeType hor, QSizePolicy::SizeType ver, bool hfw )
+{
+ QWidget::setSizePolicy( hor, ver, hfw );
+}
+
+
+#endif // QT_NO_SCROLLBAR
+
+#endif // QSCROLLBAR_H
diff --git a/src/widgets/qscrollview.cpp b/src/widgets/qscrollview.cpp
new file mode 100644
index 0000000..6af8f12
--- /dev/null
+++ b/src/widgets/qscrollview.cpp
@@ -0,0 +1,2854 @@
+/****************************************************************************
+**
+** Implementation of QScrollView class
+**
+** Created : 950524
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qwidget.h"
+#ifndef QT_NO_SCROLLVIEW
+#include "qscrollbar.h"
+#include "qobjectlist.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qcursor.h"
+#include "qfocusdata.h"
+#include "qscrollview.h"
+#include "qptrdict.h"
+#include "qapplication.h"
+#include "qtimer.h"
+#include "qstyle.h"
+#include "qlistview.h"
+#ifdef Q_WS_MAC
+# include "qt_mac.h"
+#endif
+
+static const int coord_limit = 4000;
+static const int autoscroll_margin = 16;
+static const int initialScrollTime = 30;
+static const int initialScrollAccel = 5;
+
+struct QSVChildRec {
+ QSVChildRec(QWidget* c, int xx, int yy) :
+ child(c),
+ x(xx), y(yy)
+ {
+ }
+
+ void hideOrShow(QScrollView* sv, QWidget* clipped_viewport);
+ void moveTo(QScrollView* sv, int xx, int yy, QWidget* clipped_viewport)
+ {
+ if ( x != xx || y != yy ) {
+ x = xx;
+ y = yy;
+ hideOrShow(sv,clipped_viewport);
+ }
+ }
+ QWidget* child;
+ int x, y;
+};
+
+void QSVChildRec::hideOrShow(QScrollView* sv, QWidget* clipped_viewport)
+{
+ if ( clipped_viewport ) {
+ if ( x+child->width() < sv->contentsX()+clipped_viewport->x()
+ || x > sv->contentsX()+clipped_viewport->width()
+ || y+child->height() < sv->contentsY()+clipped_viewport->y()
+ || y > sv->contentsY()+clipped_viewport->height() ) {
+ child->move(clipped_viewport->width(),
+ clipped_viewport->height());
+ } else {
+ child->move(x-sv->contentsX()-clipped_viewport->x(),
+ y-sv->contentsY()-clipped_viewport->y());
+ }
+ } else {
+ child->move(x-sv->contentsX(), y-sv->contentsY());
+ }
+}
+
+class QViewportWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QViewportWidget( QScrollView* parent=0, const char* name=0, WFlags f = 0 )
+ : QWidget( parent, name, f ) {}
+};
+
+class QClipperWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QClipperWidget( QWidget * parent=0, const char * name=0, WFlags f=0 )
+ : QWidget ( parent,name,f) {}
+};
+
+#include "qscrollview.moc"
+
+class QScrollViewData {
+public:
+ QScrollViewData(QScrollView* parent, int vpwflags) :
+ hbar( new QScrollBar( QScrollBar::Horizontal, parent, "qt_hbar" ) ),
+ vbar( new QScrollBar( QScrollBar::Vertical, parent, "qt_vbar" ) ),
+ viewport( new QViewportWidget( parent, "qt_viewport", vpwflags ) ),
+ clipped_viewport( 0 ),
+ flags( vpwflags ),
+ vx( 0 ), vy( 0 ), vwidth( 1 ), vheight( 1 ),
+#ifndef QT_NO_DRAGANDDROP
+ autoscroll_timer( parent, "scrollview autoscroll timer" ),
+ drag_autoscroll( TRUE ),
+#endif
+ scrollbar_timer( parent, "scrollview scrollbar timer" ),
+ inresize( FALSE ), use_cached_size_hint( TRUE )
+ {
+ l_marg = r_marg = t_marg = b_marg = 0;
+ viewport->polish();
+ viewport->setBackgroundMode( QWidget::PaletteDark );
+ viewport->setBackgroundOrigin( QWidget::WidgetOrigin );
+ vMode = QScrollView::Auto;
+ hMode = QScrollView::Auto;
+ corner = 0;
+ defaultCorner = new QWidget( parent, "qt_default_corner" );
+ defaultCorner->hide();
+ vbar->setSteps( 20, 1/*set later*/ );
+ hbar->setSteps( 20, 1/*set later*/ );
+ policy = QScrollView::Default;
+ signal_choke = FALSE;
+ static_bg = FALSE;
+ fake_scroll = FALSE;
+ hbarPressed = FALSE;
+ vbarPressed = FALSE;
+ }
+ ~QScrollViewData();
+
+ QSVChildRec* rec(QWidget* w) { return childDict.find(w); }
+ QSVChildRec* ancestorRec(QWidget* w);
+ QSVChildRec* addChildRec(QWidget* w, int x, int y )
+ {
+ QSVChildRec *r = new QSVChildRec(w,x,y);
+ children.append(r);
+ childDict.insert(w, r);
+ return r;
+ }
+ void deleteChildRec(QSVChildRec* r)
+ {
+ childDict.remove(r->child);
+ children.removeRef(r);
+ delete r;
+ }
+
+ void hideOrShowAll(QScrollView* sv, bool isScroll = FALSE );
+ void moveAllBy(int dx, int dy);
+ bool anyVisibleChildren();
+ void autoMove(QScrollView* sv);
+ void autoResize(QScrollView* sv);
+ void autoResizeHint(QScrollView* sv);
+ void viewportResized( int w, int h );
+
+ QScrollBar* hbar;
+ QScrollBar* vbar;
+ bool hbarPressed;
+ bool vbarPressed;
+ QViewportWidget* viewport;
+ QClipperWidget* clipped_viewport;
+ int flags;
+ QPtrList<QSVChildRec> children;
+ QPtrDict<QSVChildRec> childDict;
+ QWidget* corner, *defaultCorner;
+ int vx, vy, vwidth, vheight; // for drawContents-style usage
+ int l_marg, r_marg, t_marg, b_marg;
+ QScrollView::ResizePolicy policy;
+ QScrollView::ScrollBarMode vMode;
+ QScrollView::ScrollBarMode hMode;
+#ifndef QT_NO_DRAGANDDROP
+ QPoint cpDragStart;
+ QTimer autoscroll_timer;
+ int autoscroll_time;
+ int autoscroll_accel;
+ bool drag_autoscroll;
+#endif
+ QTimer scrollbar_timer;
+
+ uint static_bg : 1;
+ uint fake_scroll : 1;
+
+ // This variable allows ensureVisible to move the contents then
+ // update both the sliders. Otherwise, updating the sliders would
+ // cause two image scrolls, creating ugly flashing.
+ //
+ uint signal_choke : 1;
+
+ // This variables indicates in updateScrollBars() that we are
+ // in a resizeEvent() and thus don't want to flash scrollbars
+ uint inresize : 1;
+ uint use_cached_size_hint : 1;
+ QSize cachedSizeHint;
+
+ inline int contentsX() const { return -vx; }
+ inline int contentsY() const { return -vy; }
+ inline int contentsWidth() const { return vwidth; }
+};
+
+inline QScrollViewData::~QScrollViewData()
+{
+ children.setAutoDelete( TRUE );
+}
+
+QSVChildRec* QScrollViewData::ancestorRec(QWidget* w)
+{
+ if ( clipped_viewport ) {
+ while (w->parentWidget() != clipped_viewport) {
+ w = w->parentWidget();
+ if (!w) return 0;
+ }
+ } else {
+ while (w->parentWidget() != viewport) {
+ w = w->parentWidget();
+ if (!w) return 0;
+ }
+ }
+ return rec(w);
+}
+
+void QScrollViewData::hideOrShowAll(QScrollView* sv, bool isScroll )
+{
+ if ( !clipped_viewport )
+ return;
+ if ( clipped_viewport->x() <= 0
+ && clipped_viewport->y() <= 0
+ && clipped_viewport->width()+clipped_viewport->x() >=
+ viewport->width()
+ && clipped_viewport->height()+clipped_viewport->y() >=
+ viewport->height() ) {
+ // clipped_viewport still covers viewport
+ if( static_bg )
+ clipped_viewport->repaint( TRUE );
+ else if ( ( !isScroll && !clipped_viewport->testWFlags( Qt::WStaticContents) )
+ || static_bg )
+ QApplication::postEvent( clipped_viewport,
+ new QPaintEvent( clipped_viewport->clipRegion(),
+ !clipped_viewport->testWFlags(Qt::WResizeNoErase) ) );
+ } else {
+ // Re-center
+ int nx = ( viewport->width() - clipped_viewport->width() ) / 2;
+ int ny = ( viewport->height() - clipped_viewport->height() ) / 2;
+ clipped_viewport->move(nx,ny);
+ clipped_viewport->update();
+ }
+ for (QSVChildRec *r = children.first(); r; r=children.next()) {
+ r->hideOrShow(sv, clipped_viewport);
+ }
+}
+
+void QScrollViewData::moveAllBy(int dx, int dy)
+{
+ if ( clipped_viewport && !static_bg ) {
+ clipped_viewport->move( clipped_viewport->x()+dx,
+ clipped_viewport->y()+dy );
+ } else {
+ for (QSVChildRec *r = children.first(); r; r=children.next()) {
+ r->child->move(r->child->x()+dx,r->child->y()+dy);
+ }
+ if ( static_bg )
+ viewport->repaint( TRUE );
+ }
+}
+
+bool QScrollViewData::anyVisibleChildren()
+{
+ for (QSVChildRec *r = children.first(); r; r=children.next()) {
+ if (r->child->isVisible()) return TRUE;
+ }
+ return FALSE;
+}
+
+void QScrollViewData::autoMove(QScrollView* sv)
+{
+ if ( policy == QScrollView::AutoOne ) {
+ QSVChildRec* r = children.first();
+ if (r)
+ sv->setContentsPos(-r->child->x(),-r->child->y());
+ }
+}
+
+void QScrollViewData::autoResize(QScrollView* sv)
+{
+ if ( policy == QScrollView::AutoOne ) {
+ QSVChildRec* r = children.first();
+ if (r)
+ sv->resizeContents(r->child->width(),r->child->height());
+ }
+}
+
+void QScrollViewData::autoResizeHint(QScrollView* sv)
+{
+ if ( policy == QScrollView::AutoOne ) {
+ QSVChildRec* r = children.first();
+ if (r) {
+ QSize s = r->child->sizeHint();
+ if ( s.isValid() )
+ r->child->resize(s);
+ }
+ } else if ( policy == QScrollView::AutoOneFit ) {
+ QSVChildRec* r = children.first();
+ if (r) {
+ QSize sh = r->child->sizeHint();
+ sh = sh.boundedTo( r->child->maximumSize() );
+ sv->resizeContents( sh.width(), sh.height() );
+ }
+ }
+}
+
+void QScrollViewData::viewportResized( int w, int h )
+{
+ if ( policy == QScrollView::AutoOneFit ) {
+ QSVChildRec* r = children.first();
+ if (r) {
+ QSize sh = r->child->sizeHint();
+ sh = sh.boundedTo( r->child->maximumSize() );
+ r->child->resize( QMAX(w,sh.width()), QMAX(h,sh.height()) );
+ }
+
+ }
+}
+
+
+/*!
+ \class QScrollView qscrollview.h
+ \brief The QScrollView widget provides a scrolling area with on-demand scroll bars.
+
+ \ingroup abstractwidgets
+ \mainclass
+
+ The QScrollView is a large canvas - potentially larger than the
+ coordinate system normally supported by the underlying window
+ system. This is important because it is quite easy to go beyond
+ these limitations (e.g. many web pages are more than 32000 pixels
+ high). Additionally, the QScrollView can have QWidgets positioned
+ on it that scroll around with the drawn content. These sub-widgets
+ can also have positions outside the normal coordinate range (but
+ they are still limited in size).
+
+ To provide content for the widget, inherit from QScrollView,
+ reimplement drawContents() and use resizeContents() to set the
+ size of the viewed area. Use addChild() and moveChild() to
+ position widgets on the view.
+
+ To use QScrollView effectively it is important to understand its
+ widget structure in the three styles of use: a single large child
+ widget, a large panning area with some widgets and a large panning
+ area with many widgets.
+
+ \section1 Using One Big Widget
+
+ \img qscrollview-vp2.png
+
+ The first, simplest usage of QScrollView (depicted above), is
+ appropriate for scrolling areas that are never more than about
+ 4000 pixels in either dimension (this is about the maximum
+ reliable size on X11 servers). In this usage, you just make one
+ large child in the QScrollView. The child should be a child of the
+ viewport() of the scrollview and be added with addChild():
+ \code
+ QScrollView* sv = new QScrollView(...);
+ QVBox* big_box = new QVBox(sv->viewport());
+ sv->addChild(big_box);
+ \endcode
+ You can go on to add arbitrary child widgets to the single child
+ in the scrollview as you would with any widget:
+ \code
+ QLabel* child1 = new QLabel("CHILD", big_box);
+ QLabel* child2 = new QLabel("CHILD", big_box);
+ QLabel* child3 = new QLabel("CHILD", big_box);
+ ...
+ \endcode
+
+ Here the QScrollView has four children: the viewport(), the
+ verticalScrollBar(), the horizontalScrollBar() and a small
+ cornerWidget(). The viewport() has one child: the big QVBox. The
+ QVBox has the three QLabel objects as child widgets. When the view
+ is scrolled, the QVBox is moved; its children move with it as
+ child widgets normally do.
+
+ \section1 Using a Very Big View with Some Widgets
+
+ \img qscrollview-vp.png
+
+ The second usage of QScrollView (depicted above) is appropriate
+ when few, if any, widgets are on a very large scrolling area that
+ is potentially larger than 4000 pixels in either dimension. In
+ this usage you call resizeContents() to set the size of the area
+ and reimplement drawContents() to paint the contents. You may also
+ add some widgets by making them children of the viewport() and
+ adding them with addChild() (this is the same as the process for
+ the single large widget in the previous example):
+ \code
+ QScrollView* sv = new QScrollView(...);
+ QLabel* child1 = new QLabel("CHILD", sv->viewport());
+ sv->addChild(child1);
+ QLabel* child2 = new QLabel("CHILD", sv->viewport());
+ sv->addChild(child2);
+ QLabel* child3 = new QLabel("CHILD", sv->viewport());
+ sv->addChild(child3);
+ \endcode
+ Here, the QScrollView has the same four children: the viewport(),
+ the verticalScrollBar(), the horizontalScrollBar() and a small
+ cornerWidget(). The viewport() has the three QLabel objects as
+ child widgets. When the view is scrolled, the scrollview moves the
+ child widgets individually.
+
+ \section1 Using a Very Big View with Many Widgets
+
+ \target enableclipper
+ \img qscrollview-cl.png
+
+ The final usage of QScrollView (depicted above) is appropriate
+ when many widgets are on a very large scrolling area that is
+ potentially larger than 4000 pixels in either dimension. In this
+ usage you call resizeContents() to set the size of the area and
+ reimplement drawContents() to paint the contents. You then call
+ enableClipper(TRUE) and add widgets, again by making them children
+ of the viewport(), and adding them with addChild():
+ \code
+ QScrollView* sv = new QScrollView(...);
+ sv->enableClipper(TRUE);
+ QLabel* child1 = new QLabel("CHILD", sv->viewport());
+ sv->addChild(child1);
+ QLabel* child2 = new QLabel("CHILD", sv->viewport());
+ sv->addChild(child2);
+ QLabel* child3 = new QLabel("CHILD", sv->viewport());
+ sv->addChild(child3);
+ \endcode
+
+ Here, the QScrollView has four children: the clipper() (not the
+ viewport() this time), the verticalScrollBar(), the
+ horizontalScrollBar() and a small cornerWidget(). The clipper()
+ has one child: the viewport(). The viewport() has the same three
+ labels as child widgets. When the view is scrolled the viewport()
+ is moved; its children move with it as child widgets normally do.
+
+ \target allviews
+ \section1 Details Relevant for All Views
+
+ Normally you will use the first or third method if you want any
+ child widgets in the view.
+
+ Note that the widget you see in the scrolled area is the
+ viewport() widget, not the QScrollView itself. So to turn mouse
+ tracking on, for example, use viewport()->setMouseTracking(TRUE).
+
+ To enable drag-and-drop, you would setAcceptDrops(TRUE) on the
+ QScrollView (because drag-and-drop events propagate to the
+ parent). But to work out the logical position in the view, you
+ would need to map the drop co-ordinate from being relative to the
+ QScrollView to being relative to the contents; use the function
+ viewportToContents() for this.
+
+ To handle mouse events on the scrolling area, subclass scrollview
+ as you would subclass other widgets, but rather than
+ reimplementing mousePressEvent(), reimplement
+ contentsMousePressEvent() instead. The contents specific event
+ handlers provide translated events in the coordinate system of the
+ scrollview. If you reimplement mousePressEvent(), you'll get
+ called only when part of the QScrollView is clicked: and the only
+ such part is the "corner" (if you don't set a cornerWidget()) and
+ the frame; everything else is covered up by the viewport, clipper
+ or scroll bars.
+
+ When you construct a QScrollView, some of the widget flags apply
+ to the viewport() instead of being sent to the QWidget constructor
+ for the QScrollView. This applies to \c WNoAutoErase, \c
+ WStaticContents, and \c WPaintClever. See \l Qt::WidgetFlags for
+ documentation about these flags. Here are some examples:
+
+ \list
+
+ \i An image-manipulation widget would use \c
+ WNoAutoErase|WStaticContents because the widget draws all pixels
+ itself, and when its size increases, it only needs a paint event
+ for the new part because the old part remains unchanged.
+
+ \i A scrolling game widget in which the background scrolls as the
+ characters move might use \c WNoAutoErase (in addition to \c
+ WStaticContents) so that the window system background does not
+ flash in and out during scrolling.
+
+ \i A word processing widget might use \c WNoAutoErase and repaint
+ itself line by line to get a less-flickery resizing. If the widget
+ is in a mode in which no text justification can take place, it
+ might use \c WStaticContents too, so that it would only get a
+ repaint for the newly visible parts.
+
+ \endlist
+
+ Child widgets may be moved using addChild() or moveChild(). Use
+ childX() and childY() to get the position of a child widget.
+
+ A widget may be placed in the corner between the vertical and
+ horizontal scrollbars with setCornerWidget(). You can get access
+ to the scrollbars using horizontalScrollBar() and
+ verticalScrollBar(), and to the viewport with viewport(). The
+ scroll view can be scrolled using scrollBy(), ensureVisible(),
+ setContentsPos() or center().
+
+ The visible area is given by visibleWidth() and visibleHeight(),
+ and the contents area by contentsWidth() and contentsHeight(). The
+ contents may be repainted using one of the repaintContents() or
+ updateContents() functions.
+
+ Coordinate conversion is provided by contentsToViewport() and
+ viewportToContents().
+
+ The contentsMoving() signal is emitted just before the contents
+ are moved to a new position.
+
+ \warning QScrollView currently does not erase the background when
+ resized, i.e. you must always clear the background manually in
+ scrollview subclasses. This will change in a future version of Qt
+ and we recommend specifying the WNoAutoErase flag explicitly.
+
+ <img src=qscrollview-m.png> <img src=qscrollview-w.png>
+*/
+
+
+/*!
+ \enum QScrollView::ResizePolicy
+
+ This enum type is used to control a QScrollView's reaction to
+ resize events.
+
+ \value Default the QScrollView selects one of the other settings
+ automatically when it has to. In this version of Qt, QScrollView
+ changes to \c Manual if you resize the contents with
+ resizeContents() and to \c AutoOne if a child is added.
+
+ \value Manual the contents stays the size set by resizeContents().
+
+ \value AutoOne if there is only one child widget the contents stays
+ the size of that widget. Otherwise the behavior is undefined.
+
+ \value AutoOneFit if there is only one child widget the contents stays
+ the size of that widget's sizeHint(). If the scrollview is resized
+ larger than the child's sizeHint(), the child will be resized to
+ fit. If there is more than one child, the behavior is undefined.
+
+*/
+//#### The widget will be resized to its sizeHint() when a LayoutHint event
+//#### is received
+
+/*!
+ Constructs a QScrollView called \a name with parent \a parent and
+ widget flags \a f.
+
+ The widget flags \c WStaticContents, \c WNoAutoErase and \c
+ WPaintClever are propagated to the viewport() widget. The other
+ widget flags are propagated to the parent constructor as usual.
+*/
+
+QScrollView::QScrollView( QWidget *parent, const char *name, WFlags f ) :
+ QFrame( parent, name, f & (~WStaticContents) & (~WResizeNoErase) )
+{
+ WFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents);
+ d = new QScrollViewData( this, flags );
+
+#ifndef QT_NO_DRAGANDDROP
+ connect( &d->autoscroll_timer, SIGNAL( timeout() ),
+ this, SLOT( doDragAutoScroll() ) );
+#endif
+
+ connect( d->hbar, SIGNAL( valueChanged(int) ),
+ this, SLOT( hslide(int) ) );
+ connect( d->vbar, SIGNAL( valueChanged(int) ),
+ this, SLOT( vslide(int) ) );
+
+ connect( d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed()) );
+ connect( d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased()) );
+ connect( d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed()) );
+ connect( d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased()) );
+
+
+ d->viewport->installEventFilter( this );
+
+ connect( &d->scrollbar_timer, SIGNAL( timeout() ),
+ this, SLOT( updateScrollBars() ) );
+
+ setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ setLineWidth( style().pixelMetric(QStyle::PM_DefaultFrameWidth, this) );
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
+}
+
+
+/*!
+ Destroys the QScrollView. Any children added with addChild() will
+ be deleted.
+*/
+QScrollView::~QScrollView()
+{
+ // Be careful not to get all those useless events...
+ if ( d->clipped_viewport )
+ d->clipped_viewport->removeEventFilter( this );
+ else
+ d->viewport->removeEventFilter( this );
+
+ // order is important
+ // ~QWidget may cause a WM_ERASEBKGND on Windows
+ delete d->vbar;
+ d->vbar = 0;
+ delete d->hbar;
+ d->hbar = 0;
+ delete d->viewport;
+ d->viewport = 0;
+ delete d;
+ d = 0;
+}
+
+/*!
+ \fn void QScrollView::horizontalSliderPressed()
+
+ This signal is emitted whenever the user presses the horizontal slider.
+*/
+/*!
+ \fn void QScrollView::horizontalSliderReleased()
+
+ This signal is emitted whenever the user releases the horizontal slider.
+*/
+/*!
+ \fn void QScrollView::verticalSliderPressed()
+
+ This signal is emitted whenever the user presses the vertical slider.
+*/
+/*!
+ \fn void QScrollView::verticalSliderReleased()
+
+ This signal is emitted whenever the user releases the vertical slider.
+*/
+void QScrollView::hbarIsPressed()
+{
+ d->hbarPressed = TRUE;
+ emit( horizontalSliderPressed() );
+}
+
+void QScrollView::hbarIsReleased()
+{
+ d->hbarPressed = FALSE;
+ emit( horizontalSliderReleased() );
+}
+
+/*!
+ Returns TRUE if horizontal slider is pressed by user; otherwise returns FALSE.
+*/
+bool QScrollView::isHorizontalSliderPressed()
+{
+ return d->hbarPressed;
+}
+
+void QScrollView::vbarIsPressed()
+{
+ d->vbarPressed = TRUE;
+ emit( verticalSliderPressed() );
+}
+
+void QScrollView::vbarIsReleased()
+{
+ d->vbarPressed = FALSE;
+ emit( verticalSliderReleased() );
+}
+
+/*!
+ Returns TRUE if vertical slider is pressed by user; otherwise returns FALSE.
+*/
+bool QScrollView::isVerticalSliderPressed()
+{
+ return d->vbarPressed;
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::styleChange( QStyle& old )
+{
+ QWidget::styleChange( old );
+ updateScrollBars();
+ d->cachedSizeHint = QSize();
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::fontChange( const QFont &old )
+{
+ QWidget::fontChange( old );
+ updateScrollBars();
+ d->cachedSizeHint = QSize();
+}
+
+void QScrollView::hslide( int pos )
+{
+ if ( !d->signal_choke ) {
+ moveContents( -pos, -d->contentsY() );
+ QApplication::syncX();
+ }
+}
+
+void QScrollView::vslide( int pos )
+{
+ if ( !d->signal_choke ) {
+ moveContents( -d->contentsX(), -pos );
+ QApplication::syncX();
+ }
+}
+
+/*!
+ Called when the horizontal scroll bar geometry changes. This is
+ provided as a protected function so that subclasses can do
+ interesting things such as providing extra buttons in some of the
+ space normally used by the scroll bars.
+
+ The default implementation simply gives all the space to \a hbar.
+ The new geometry is given by \a x, \a y, \a w and \a h.
+
+ \sa setVBarGeometry()
+*/
+void QScrollView::setHBarGeometry(QScrollBar& hbar,
+ int x, int y, int w, int h)
+{
+ hbar.setGeometry( x, y, w, h );
+}
+
+/*!
+ Called when the vertical scroll bar geometry changes. This is
+ provided as a protected function so that subclasses can do
+ interesting things such as providing extra buttons in some of the
+ space normally used by the scroll bars.
+
+ The default implementation simply gives all the space to \a vbar.
+ The new geometry is given by \a x, \a y, \a w and \a h.
+
+ \sa setHBarGeometry()
+*/
+void QScrollView::setVBarGeometry( QScrollBar& vbar,
+ int x, int y, int w, int h)
+{
+ vbar.setGeometry( x, y, w, h );
+}
+
+
+/*!
+ Returns the viewport size for size (\a x, \a y).
+
+ The viewport size depends on \a (x, y) (the size of the contents),
+ the size of this widget and the modes of the horizontal and
+ vertical scroll bars.
+
+ This function permits widgets that can trade vertical and
+ horizontal space for each other to control scroll bar appearance
+ better. For example, a word processor or web browser can control
+ the width of the right margin accurately, whether or not there
+ needs to be a vertical scroll bar.
+*/
+
+QSize QScrollView::viewportSize( int x, int y ) const
+{
+ int fw = frameWidth();
+ int lmarg = fw+d->l_marg;
+ int rmarg = fw+d->r_marg;
+ int tmarg = fw+d->t_marg;
+ int bmarg = fw+d->b_marg;
+
+ int w = width();
+ int h = height();
+
+ bool needh, needv;
+ bool showh, showv;
+ int hsbExt = horizontalScrollBar()->sizeHint().height();
+ int vsbExt = verticalScrollBar()->sizeHint().width();
+
+ if ( d->policy != AutoOne || d->anyVisibleChildren() ) {
+ // Do we definitely need the scrollbar?
+ needh = w-lmarg-rmarg < x;
+ needv = h-tmarg-bmarg < y;
+
+ // Do we intend to show the scrollbar?
+ if (d->hMode == AlwaysOn)
+ showh = TRUE;
+ else if (d->hMode == AlwaysOff)
+ showh = FALSE;
+ else
+ showh = needh;
+
+ if (d->vMode == AlwaysOn)
+ showv = TRUE;
+ else if (d->vMode == AlwaysOff)
+ showv = FALSE;
+ else
+ showv = needv;
+
+ // Given other scrollbar will be shown, NOW do we need one?
+ if ( showh && h-vsbExt-tmarg-bmarg < y ) {
+ if (d->vMode == Auto)
+ showv=TRUE;
+ }
+ if ( showv && w-hsbExt-lmarg-rmarg < x ) {
+ if (d->hMode == Auto)
+ showh=TRUE;
+ }
+ } else {
+ // Scrollbars not needed, only show scrollbar that are always on.
+ showh = d->hMode == AlwaysOn;
+ showv = d->vMode == AlwaysOn;
+ }
+
+ return QSize( w-lmarg-rmarg - (showv ? vsbExt : 0),
+ h-tmarg-bmarg - (showh ? hsbExt : 0) );
+}
+
+
+/*!
+ Updates scroll bars: all possibilities are considered. You should
+ never need to call this in your code.
+*/
+void QScrollView::updateScrollBars()
+{
+ if(!horizontalScrollBar() && !verticalScrollBar())
+ return;
+
+ // I support this should use viewportSize()... but it needs
+ // so many of the temporary variables from viewportSize. hm.
+ int fw = frameWidth();
+ int lmarg = fw+d->l_marg;
+ int rmarg = fw+d->r_marg;
+ int tmarg = fw+d->t_marg;
+ int bmarg = fw+d->b_marg;
+
+ int w = width();
+ int h = height();
+
+ int portw, porth;
+
+ bool needh;
+ bool needv;
+ bool showh;
+ bool showv;
+ bool showc = FALSE;
+
+ int hsbExt = horizontalScrollBar()->sizeHint().height();
+ int vsbExt = verticalScrollBar()->sizeHint().width();
+
+ QSize oldVisibleSize( visibleWidth(), visibleHeight() );
+
+ if ( d->policy != AutoOne || d->anyVisibleChildren() ) {
+ // Do we definitely need the scrollbar?
+ needh = w-lmarg-rmarg < d->contentsWidth();
+ if ( d->inresize )
+ needh = !horizontalScrollBar()->isHidden();
+ needv = h-tmarg-bmarg < contentsHeight();
+
+ // Do we intend to show the scrollbar?
+ if (d->hMode == AlwaysOn)
+ showh = TRUE;
+ else if (d->hMode == AlwaysOff)
+ showh = FALSE;
+ else
+ showh = needh;
+
+ if (d->vMode == AlwaysOn)
+ showv = TRUE;
+ else if (d->vMode == AlwaysOff)
+ showv = FALSE;
+ else
+ showv = needv;
+
+#ifdef Q_WS_MAC
+ bool mac_need_scroll = FALSE;
+ if(!parentWidget()) {
+ mac_need_scroll = TRUE;
+ } else {
+ QWidget *tlw = topLevelWidget();
+ QPoint tlw_br = QPoint(tlw->width(), tlw->height()),
+ my_br = posInWindow(this) + QPoint(w, h);
+ if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3)
+ mac_need_scroll = TRUE;
+ }
+ if(mac_need_scroll) {
+ WindowAttributes attr;
+ GetWindowAttributes((WindowPtr)handle(), &attr);
+ mac_need_scroll = (attr & kWindowResizableAttribute);
+ }
+ if(mac_need_scroll) {
+ showc = TRUE;
+ if(d->vMode == Auto)
+ showv = TRUE;
+ if(d->hMode == Auto)
+ showh = TRUE;
+ }
+#endif
+
+ // Given other scrollbar will be shown, NOW do we need one?
+ if ( showh && h-vsbExt-tmarg-bmarg < contentsHeight() ) {
+ needv=TRUE;
+ if (d->vMode == Auto)
+ showv=TRUE;
+ }
+ if ( showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth() ) {
+ needh=TRUE;
+ if (d->hMode == Auto)
+ showh=TRUE;
+ }
+ } else {
+ // Scrollbars not needed, only show scrollbar that are always on.
+ needh = needv = FALSE;
+ showh = d->hMode == AlwaysOn;
+ showv = d->vMode == AlwaysOn;
+ }
+
+ bool sc = d->signal_choke;
+ d->signal_choke=TRUE;
+
+ // Hide unneeded scrollbar, calculate viewport size
+ if ( showh ) {
+ porth=h-hsbExt-tmarg-bmarg;
+ } else {
+ if (!needh)
+ d->hbar->setValue(0);
+ d->hbar->hide();
+ porth=h-tmarg-bmarg;
+ }
+ if ( showv ) {
+ portw=w-vsbExt-lmarg-rmarg;
+ } else {
+ if (!needv)
+ d->vbar->setValue(0);
+ d->vbar->hide();
+ portw=w-lmarg-rmarg;
+ }
+
+ // Configure scrollbars that we will show
+ if ( needv ) {
+ d->vbar->setRange( 0, contentsHeight()-porth );
+ d->vbar->setSteps( QScrollView::d->vbar->lineStep(), porth );
+ } else {
+ d->vbar->setRange( 0, 0 );
+ }
+ if ( needh ) {
+ d->hbar->setRange( 0, QMAX(0, d->contentsWidth()-portw) );
+ d->hbar->setSteps( QScrollView::d->hbar->lineStep(), portw );
+ } else {
+ d->hbar->setRange( 0, 0 );
+ }
+
+ // Position the scrollbars, viewport and corner widget.
+ int bottom;
+ bool reverse = QApplication::reverseLayout();
+ int xoffset = ( reverse && (showv || cornerWidget() )) ? vsbExt : 0;
+ int xpos = reverse ? 0 : w - vsbExt;
+ bool frameContentsOnly =
+ style().styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
+
+ if( ! frameContentsOnly ) {
+ if ( reverse )
+ xpos += fw;
+ else
+ xpos -= fw;
+ }
+ if ( showh ) {
+ int right = ( showc || showv || cornerWidget() ) ? w-vsbExt : w;
+ if ( ! frameContentsOnly )
+ setHBarGeometry( *d->hbar, fw + xoffset, h-hsbExt-fw,
+ right-fw-fw, hsbExt );
+ else
+ setHBarGeometry( *d->hbar, 0 + xoffset, h-hsbExt, right,
+ hsbExt );
+ bottom=h-hsbExt;
+ } else {
+ bottom=h;
+ }
+ if ( showv ) {
+ clipper()->setGeometry( lmarg + xoffset, tmarg,
+ w-vsbExt-lmarg-rmarg,
+ bottom-tmarg-bmarg );
+ d->viewportResized( w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg );
+ if ( ! frameContentsOnly )
+ changeFrameRect(QRect(0, 0, w, h) );
+ else
+ changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom));
+ if (showc || cornerWidget()) {
+ if ( ! frameContentsOnly )
+ setVBarGeometry( *d->vbar, xpos,
+ fw, vsbExt,
+ h-hsbExt-fw-fw );
+ else
+ setVBarGeometry( *d->vbar, xpos, 0,
+ vsbExt,
+ h-hsbExt );
+ }
+ else {
+ if ( ! frameContentsOnly )
+ setVBarGeometry( *d->vbar, xpos,
+ fw, vsbExt,
+ bottom-fw-fw );
+ else
+ setVBarGeometry( *d->vbar, xpos, 0,
+ vsbExt, bottom );
+ }
+ } else {
+ if ( ! frameContentsOnly )
+ changeFrameRect(QRect(0, 0, w, h));
+ else
+ changeFrameRect(QRect(0, 0, w, bottom));
+ clipper()->setGeometry( lmarg, tmarg,
+ w-lmarg-rmarg, bottom-tmarg-bmarg );
+ d->viewportResized( w-lmarg-rmarg, bottom-tmarg-bmarg );
+ }
+
+ QWidget *corner = d->corner;
+ if ( !d->corner )
+ corner = d->defaultCorner;
+ if ( ! frameContentsOnly )
+ corner->setGeometry( xpos,
+ h-hsbExt-fw,
+ vsbExt,
+ hsbExt );
+ else
+ corner->setGeometry( xpos,
+ h-hsbExt,
+ vsbExt,
+ hsbExt );
+
+ d->signal_choke=sc;
+
+ if ( d->contentsX()+visibleWidth() > d->contentsWidth() ) {
+ int x;
+#if 0
+ if ( reverse )
+ x =QMIN(0,d->contentsWidth()-visibleWidth());
+ else
+#endif
+ x =QMAX(0,d->contentsWidth()-visibleWidth());
+ d->hbar->setValue(x);
+ // Do it even if it is recursive
+ moveContents( -x, -d->contentsY() );
+ }
+ if ( d->contentsY()+visibleHeight() > contentsHeight() ) {
+ int y=QMAX(0,contentsHeight()-visibleHeight());
+ d->vbar->setValue(y);
+ // Do it even if it is recursive
+ moveContents( -d->contentsX(), -y );
+ }
+
+ // Finally, show the scroll bars
+ if ( showh && ( d->hbar->isHidden() || !d->hbar->isVisible() ) )
+ d->hbar->show();
+ if ( showv && ( d->vbar->isHidden() || !d->vbar->isVisible() ) )
+ d->vbar->show();
+
+ d->signal_choke=TRUE;
+ d->vbar->setValue( d->contentsY() );
+ d->hbar->setValue( d->contentsX() );
+ d->signal_choke=FALSE;
+
+ QSize newVisibleSize( visibleWidth(), visibleHeight() );
+ if ( d->clipped_viewport && oldVisibleSize != newVisibleSize ) {
+ QResizeEvent e( newVisibleSize, oldVisibleSize );
+ viewportResizeEvent( &e );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollView::show()
+{
+ if ( isVisible() )
+ return;
+ QWidget::show();
+ updateScrollBars();
+ d->hideOrShowAll(this);
+}
+
+/*!
+ \reimp
+ */
+void QScrollView::resize( int w, int h )
+{
+ QWidget::resize( w, h );
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::resize( const QSize& s )
+{
+ resize( s.width(), s.height() );
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::resizeEvent( QResizeEvent* event )
+{
+ QFrame::resizeEvent( event );
+
+#if 0
+ if ( QApplication::reverseLayout() ) {
+ d->fake_scroll = TRUE;
+ scrollBy( -event->size().width() + event->oldSize().width(), 0 );
+ d->fake_scroll = FALSE;
+ }
+#endif
+
+ bool inresize = d->inresize;
+ d->inresize = TRUE;
+ updateScrollBars();
+ d->inresize = inresize;
+ d->scrollbar_timer.start( 0, TRUE );
+
+ d->hideOrShowAll(this);
+}
+
+
+
+/*!
+ \reimp
+*/
+void QScrollView::mousePressEvent( QMouseEvent * e) //#### remove for 4.0
+{
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::mouseReleaseEvent( QMouseEvent *e ) //#### remove for 4.0
+{
+ e->ignore();
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollView::mouseDoubleClickEvent( QMouseEvent *e ) //#### remove for 4.0
+{
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::mouseMoveEvent( QMouseEvent *e ) //#### remove for 4.0
+{
+ e->ignore();
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QScrollView::wheelEvent( QWheelEvent *e )
+{
+ QWheelEvent ce( viewport()->mapFromGlobal( e->globalPos() ),
+ e->globalPos(), e->delta(), e->state(), e->orientation());
+ viewportWheelEvent(&ce);
+ if ( !ce.isAccepted() ) {
+ if ( e->orientation() == Horizontal && horizontalScrollBar() && horizontalScrollBar()->isEnabled() )
+ QApplication::sendEvent( horizontalScrollBar(), e);
+ else if (e->orientation() == Vertical && verticalScrollBar() && verticalScrollBar()->isEnabled() )
+ QApplication::sendEvent( verticalScrollBar(), e);
+ } else {
+ e->accept();
+ }
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QScrollView::contextMenuEvent( QContextMenuEvent *e )
+{
+ if ( e->reason() != QContextMenuEvent::Keyboard ) {
+ e->ignore();
+ return;
+ }
+
+ QContextMenuEvent ce( e->reason(), viewport()->mapFromGlobal( e->globalPos() ),
+ e->globalPos(), e->state() );
+ viewportContextMenuEvent( &ce );
+ if ( ce.isAccepted() )
+ e->accept();
+ else
+ e->ignore();
+}
+
+QScrollView::ScrollBarMode QScrollView::vScrollBarMode() const
+{
+ return d->vMode;
+}
+
+
+/*!
+ \enum QScrollView::ScrollBarMode
+
+ This enum type describes the various modes of QScrollView's scroll
+ bars.
+
+ \value Auto QScrollView shows a scroll bar when the content is
+ too large to fit and not otherwise. This is the default.
+
+ \value AlwaysOff QScrollView never shows a scroll bar.
+
+ \value AlwaysOn QScrollView always shows a scroll bar.
+
+ (The modes for the horizontal and vertical scroll bars are
+ independent.)
+*/
+
+
+/*!
+ \property QScrollView::vScrollBarMode
+ \brief the mode for the vertical scroll bar
+
+ The default mode is \c QScrollView::Auto.
+
+ \sa hScrollBarMode
+*/
+void QScrollView::setVScrollBarMode( ScrollBarMode mode )
+{
+ if (d->vMode != mode) {
+ d->vMode = mode;
+ updateScrollBars();
+ }
+}
+
+
+/*!
+ \property QScrollView::hScrollBarMode
+ \brief the mode for the horizontal scroll bar
+
+ The default mode is \c QScrollView::Auto.
+
+ \sa vScrollBarMode
+*/
+QScrollView::ScrollBarMode QScrollView::hScrollBarMode() const
+{
+ return d->hMode;
+}
+
+void QScrollView::setHScrollBarMode( ScrollBarMode mode )
+{
+ if (d->hMode != mode) {
+ d->hMode = mode;
+ updateScrollBars();
+ }
+}
+
+
+/*!
+ Returns the widget in the corner between the two scroll bars.
+
+ By default, no corner widget is present.
+*/
+QWidget* QScrollView::cornerWidget() const
+{
+ return d->corner;
+}
+
+/*!
+ Sets the widget in the \a corner between the two scroll bars.
+
+ 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 \a corner widget is hidden.
+
+ You may call setCornerWidget() with the same widget at different
+ times.
+
+ All widgets set here will be deleted by the QScrollView 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 setVScrollBarMode(), setHScrollBarMode()
+*/
+void QScrollView::setCornerWidget(QWidget* corner)
+{
+ QWidget* oldcorner = d->corner;
+ if (oldcorner != corner) {
+ if (oldcorner) oldcorner->hide();
+ d->corner = corner;
+
+ if ( corner && corner->parentWidget() != this ) {
+ // #### No clean way to get current WFlags
+ corner->reparent( this, (((QScrollView*)corner))->getWFlags(),
+ QPoint(0,0), FALSE );
+ }
+
+ updateScrollBars();
+ if ( corner ) corner->show();
+ }
+}
+
+
+void QScrollView::setResizePolicy( ResizePolicy r )
+{
+ d->policy = r;
+}
+
+/*!
+ \property QScrollView::resizePolicy
+ \brief the resize policy
+
+ The default is \c Default.
+
+ \sa ResizePolicy
+*/
+QScrollView::ResizePolicy QScrollView::resizePolicy() const
+{
+ return d->policy;
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::setEnabled( bool enable )
+{
+ QFrame::setEnabled( enable );
+}
+
+/*!
+ Removes the \a child widget from the scrolled area. Note that this
+ happens automatically if the \a child is deleted.
+*/
+void QScrollView::removeChild(QWidget* child)
+{
+ if ( !d || !child ) // First check in case we are destructing
+ return;
+
+ QSVChildRec *r = d->rec(child);
+ if ( r ) d->deleteChildRec( r );
+}
+
+/*!
+ \reimp
+*/
+void QScrollView::removeChild(QObject* child)
+{
+ QFrame::removeChild(child);
+}
+
+/*!
+ Inserts the widget, \a child, into the scrolled area positioned at
+ (\a x, \a y). The position defaults to (0, 0). If the child is
+ already in the view, it is just moved.
+
+ You may want to call enableClipper(TRUE) if you add a large number
+ of widgets.
+*/
+void QScrollView::addChild(QWidget* child, int x, int y)
+{
+ if ( !child ) {
+#if defined(QT_CHECK_NULL)
+ qWarning( "QScrollView::addChild(): Cannot add null child" );
+#endif
+ return;
+ }
+ child->polish();
+ child->setBackgroundOrigin(WidgetOrigin);
+
+ if ( child->parentWidget() == viewport() ) {
+ // May already be there
+ QSVChildRec *r = d->rec(child);
+ if (r) {
+ r->moveTo(this,x,y,d->clipped_viewport);
+ if ( d->policy > Manual ) {
+ d->autoResizeHint(this);
+ d->autoResize(this); // #### better to just deal with this one widget!
+ }
+ return;
+ }
+ }
+
+ if ( d->children.isEmpty() && d->policy != Manual ) {
+ if ( d->policy == Default )
+ setResizePolicy( AutoOne );
+ child->installEventFilter( this );
+ } else if ( d->policy == AutoOne ) {
+ child->removeEventFilter( this ); //#### ?????
+ setResizePolicy( Manual );
+ }
+ if ( child->parentWidget() != viewport() ) {
+ child->reparent( viewport(), 0, QPoint(0,0), FALSE );
+ }
+ d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport);
+
+ if ( d->policy > Manual ) {
+ d->autoResizeHint(this);
+ d->autoResize(this); // #### better to just deal with this one widget!
+ }
+}
+
+/*!
+ Repositions the \a child widget to (\a x, \a y). This function is
+ the same as addChild().
+*/
+void QScrollView::moveChild(QWidget* child, int x, int y)
+{
+ addChild(child,x,y);
+}
+
+/*!
+ Returns the X position of the given \a child widget. Use this
+ rather than QWidget::x() for widgets added to the view.
+
+ This function returns 0 if \a child has not been added to the view.
+*/
+int QScrollView::childX(QWidget* child)
+{
+ QSVChildRec *r = d->rec(child);
+ return r ? r->x : 0;
+}
+
+/*!
+ Returns the Y position of the given \a child widget. Use this
+ rather than QWidget::y() for widgets added to the view.
+
+ This function returns 0 if \a child has not been added to the view.
+*/
+int QScrollView::childY(QWidget* child)
+{
+ QSVChildRec *r = d->rec(child);
+ return r ? r->y : 0;
+}
+
+/*! \fn bool QScrollView::childIsVisible(QWidget*)
+ \obsolete
+
+ Returns TRUE if \a child is visible. This is equivalent
+ to child->isVisible().
+*/
+
+/*! \fn void QScrollView::showChild(QWidget* child, bool y)
+ \obsolete
+
+ Sets the visibility of \a child. Equivalent to
+ QWidget::show() or QWidget::hide().
+*/
+
+/*!
+ This event filter ensures the scroll bars are updated when a
+ single contents widget is resized, shown, hidden or destroyed; it
+ passes mouse events to the QScrollView. The event is in \a e and
+ the object is in \a obj.
+*/
+
+bool QScrollView::eventFilter( QObject *obj, QEvent *e )
+{
+ if ( !d )
+ return FALSE; // we are destructing
+ if ( obj == d->viewport || obj == d->clipped_viewport ) {
+ switch ( e->type() ) {
+ /* Forward many events to viewport...() functions */
+ case QEvent::Paint:
+ viewportPaintEvent( (QPaintEvent*)e );
+ break;
+ case QEvent::Resize:
+ if ( !d->clipped_viewport )
+ viewportResizeEvent( (QResizeEvent *)e );
+ break;
+ case QEvent::MouseButtonPress:
+ viewportMousePressEvent( (QMouseEvent*)e );
+ if ( ((QMouseEvent*)e)->isAccepted() )
+ return TRUE;
+ break;
+ case QEvent::MouseButtonRelease:
+ viewportMouseReleaseEvent( (QMouseEvent*)e );
+ if ( ((QMouseEvent*)e)->isAccepted() )
+ return TRUE;
+ break;
+ case QEvent::MouseButtonDblClick:
+ viewportMouseDoubleClickEvent( (QMouseEvent*)e );
+ if ( ((QMouseEvent*)e)->isAccepted() )
+ return TRUE;
+ break;
+ case QEvent::MouseMove:
+ viewportMouseMoveEvent( (QMouseEvent*)e );
+ if ( ((QMouseEvent*)e)->isAccepted() )
+ return TRUE;
+ break;
+#ifndef QT_NO_DRAGANDDROP
+ case QEvent::DragEnter:
+ viewportDragEnterEvent( (QDragEnterEvent*)e );
+ break;
+ case QEvent::DragMove: {
+ if ( d->drag_autoscroll ) {
+ QPoint vp = ((QDragMoveEvent*) e)->pos();
+ QRect inside_margin( autoscroll_margin, autoscroll_margin,
+ visibleWidth() - autoscroll_margin * 2,
+ visibleHeight() - autoscroll_margin * 2 );
+ if ( !inside_margin.contains( vp ) ) {
+ startDragAutoScroll();
+ // Keep sending move events
+ ( (QDragMoveEvent*)e )->accept( QRect(0,0,0,0) );
+ }
+ }
+ viewportDragMoveEvent( (QDragMoveEvent*)e );
+ } break;
+ case QEvent::DragLeave:
+ stopDragAutoScroll();
+ viewportDragLeaveEvent( (QDragLeaveEvent*)e );
+ break;
+ case QEvent::Drop:
+ stopDragAutoScroll();
+ viewportDropEvent( (QDropEvent*)e );
+ break;
+#endif // QT_NO_DRAGANDDROP
+ case QEvent::ContextMenu:
+ viewportContextMenuEvent( (QContextMenuEvent*)e );
+ if ( ((QContextMenuEvent*)e)->isAccepted() )
+ return TRUE;
+ break;
+ case QEvent::ChildRemoved:
+ removeChild((QWidget*)((QChildEvent*)e)->child());
+ break;
+ case QEvent::LayoutHint:
+ d->autoResizeHint(this);
+ break;
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ return TRUE;
+ default:
+ break;
+ }
+ } else if ( d && d->rec((QWidget*)obj) ) { // must be a child
+ if ( e->type() == QEvent::Resize )
+ d->autoResize(this);
+ else if ( e->type() == QEvent::Move )
+ d->autoMove(this);
+ }
+ return QFrame::eventFilter( obj, e ); // always continue with standard event processing
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ mousePressEvent(): the press position in \a e is translated to be a point
+ on the contents.
+*/
+void QScrollView::contentsMousePressEvent( QMouseEvent* e )
+{
+ e->ignore();
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ mouseReleaseEvent(): the release position in \a e is translated to be a
+ point on the contents.
+*/
+void QScrollView::contentsMouseReleaseEvent( QMouseEvent* e )
+{
+ e->ignore();
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ mouseDoubleClickEvent(): the click position in \a e is translated to be a
+ point on the contents.
+
+ The default implementation generates a normal mouse press event.
+*/
+void QScrollView::contentsMouseDoubleClickEvent( QMouseEvent* e )
+{
+ contentsMousePressEvent(e); // try mouse press event
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ mouseMoveEvent(): the mouse position in \a e is translated to be a point
+ on the contents.
+*/
+void QScrollView::contentsMouseMoveEvent( QMouseEvent* e )
+{
+ e->ignore();
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ dragEnterEvent(): the drag position is translated to be a point
+ on the contents.
+*/
+void QScrollView::contentsDragEnterEvent( QDragEnterEvent * )
+{
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ dragMoveEvent(): the drag position is translated to be a point on
+ the contents.
+*/
+void QScrollView::contentsDragMoveEvent( QDragMoveEvent * )
+{
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ dragLeaveEvent(): the drag position is translated to be a point
+ on the contents.
+*/
+void QScrollView::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+}
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ dropEvent(): the drop position is translated to be a point on the
+ contents.
+*/
+void QScrollView::contentsDropEvent( QDropEvent * )
+{
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+ This event handler is called whenever the QScrollView receives a
+ wheelEvent() in \a{e}: the mouse position is translated to be a
+ point on the contents.
+*/
+#ifndef QT_NO_WHEELEVENT
+void QScrollView::contentsWheelEvent( QWheelEvent * e )
+{
+ e->ignore();
+}
+#endif
+/*!
+ This event handler is called whenever the QScrollView receives a
+ contextMenuEvent() in \a{e}: the mouse position is translated to
+ be a point on the contents.
+*/
+void QScrollView::contentsContextMenuEvent( QContextMenuEvent *e )
+{
+ e->ignore();
+}
+
+/*!
+ This is a low-level painting routine that draws the viewport
+ contents. Reimplement this if drawContents() is too high-level
+ (for example, if you don't want to open a QPainter on the
+ viewport). The paint event is passed in \a pe.
+*/
+void QScrollView::viewportPaintEvent( QPaintEvent* pe )
+{
+ QWidget* vp = viewport();
+
+ QPainter p(vp);
+ QRect r = pe->rect();
+
+ if ( d->clipped_viewport ) {
+ QRect rr(
+ -d->clipped_viewport->x(), -d->clipped_viewport->y(),
+ d->viewport->width(), d->viewport->height()
+ );
+ r &= rr;
+ if ( r.isValid() ) {
+ int ex = r.x() + d->clipped_viewport->x() + d->contentsX();
+ int ey = r.y() + d->clipped_viewport->y() + d->contentsY();
+ int ew = r.width();
+ int eh = r.height();
+ drawContentsOffset(&p,
+ d->contentsX()+d->clipped_viewport->x(),
+ d->contentsY()+d->clipped_viewport->y(),
+ ex, ey, ew, eh);
+ }
+ } else {
+ r &= d->viewport->rect();
+ int ex = r.x() + d->contentsX();
+ int ey = r.y() + d->contentsY();
+ int ew = r.width();
+ int eh = r.height();
+ drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh);
+ }
+}
+
+
+/*!
+ To provide simple processing of events on the contents, this
+ function receives all resize events sent to the viewport.
+
+ \sa QWidget::resizeEvent()
+*/
+void QScrollView::viewportResizeEvent( QResizeEvent* )
+{
+}
+
+/*! \internal
+
+ To provide simple processing of events on the contents, this
+ function receives all mouse press events sent to the viewport,
+ translates the event and calls contentsMousePressEvent().
+
+ \sa contentsMousePressEvent(), QWidget::mousePressEvent()
+*/
+void QScrollView::viewportMousePressEvent( QMouseEvent* e )
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMousePressEvent(&ce);
+ if ( !ce.isAccepted() )
+ e->ignore();
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all mouse release events sent to the viewport, translates
+ the event and calls contentsMouseReleaseEvent().
+
+ \sa QWidget::mouseReleaseEvent()
+*/
+void QScrollView::viewportMouseReleaseEvent( QMouseEvent* e )
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMouseReleaseEvent(&ce);
+ if ( !ce.isAccepted() )
+ e->ignore();
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all mouse double click events sent to the viewport,
+ translates the event and calls contentsMouseDoubleClickEvent().
+
+ \sa QWidget::mouseDoubleClickEvent()
+*/
+void QScrollView::viewportMouseDoubleClickEvent( QMouseEvent* e )
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMouseDoubleClickEvent(&ce);
+ if ( !ce.isAccepted() )
+ e->ignore();
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all mouse move events sent to the viewport, translates the
+ event and calls contentsMouseMoveEvent().
+
+ \sa QWidget::mouseMoveEvent()
+*/
+void QScrollView::viewportMouseMoveEvent( QMouseEvent* e )
+{
+ QMouseEvent ce(e->type(), viewportToContents(e->pos()),
+ e->globalPos(), e->button(), e->state());
+ contentsMouseMoveEvent(&ce);
+ if ( !ce.isAccepted() )
+ e->ignore();
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drag enter events sent to the viewport, translates the
+ event and calls contentsDragEnterEvent().
+
+ \sa QWidget::dragEnterEvent()
+*/
+void QScrollView::viewportDragEnterEvent( QDragEnterEvent* e )
+{
+ e->setPoint(viewportToContents(e->pos()));
+ contentsDragEnterEvent(e);
+ e->setPoint(contentsToViewport(e->pos()));
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drag move events sent to the viewport, translates the
+ event and calls contentsDragMoveEvent().
+
+ \sa QWidget::dragMoveEvent()
+*/
+void QScrollView::viewportDragMoveEvent( QDragMoveEvent* e )
+{
+ e->setPoint(viewportToContents(e->pos()));
+ contentsDragMoveEvent(e);
+ e->setPoint(contentsToViewport(e->pos()));
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drag leave events sent to the viewport and calls
+ contentsDragLeaveEvent().
+
+ \sa QWidget::dragLeaveEvent()
+*/
+void QScrollView::viewportDragLeaveEvent( QDragLeaveEvent* e )
+{
+ contentsDragLeaveEvent(e);
+}
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all drop events sent to the viewport, translates the event
+ and calls contentsDropEvent().
+
+ \sa QWidget::dropEvent()
+*/
+void QScrollView::viewportDropEvent( QDropEvent* e )
+{
+ e->setPoint(viewportToContents(e->pos()));
+ contentsDropEvent(e);
+ e->setPoint(contentsToViewport(e->pos()));
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!\internal
+
+ To provide simple processing of events on the contents, this function
+ receives all wheel events sent to the viewport, translates the
+ event and calls contentsWheelEvent().
+
+ \sa QWidget::wheelEvent()
+*/
+#ifndef QT_NO_WHEELEVENT
+void QScrollView::viewportWheelEvent( QWheelEvent* e )
+{
+ /*
+ Different than standard mouse events, because wheel events might
+ be sent to the focus widget if the widget-under-mouse doesn't want
+ the event itself.
+ */
+ QWheelEvent ce( viewportToContents(e->pos()),
+ e->globalPos(), e->delta(), e->state(), e->orientation());
+ contentsWheelEvent(&ce);
+ if ( ce.isAccepted() )
+ e->accept();
+ else
+ e->ignore();
+}
+#endif
+
+/*! \internal
+
+ To provide simple processing of events on the contents, this function
+ receives all context menu events sent to the viewport, translates the
+ event and calls contentsContextMenuEvent().
+*/
+void QScrollView::viewportContextMenuEvent( QContextMenuEvent *e )
+{
+ QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state() );
+ contentsContextMenuEvent( &ce );
+ if ( ce.isAccepted() )
+ e->accept();
+ else
+ e->ignore();
+}
+
+/*!
+ Returns the component horizontal scroll bar. It is made available
+ to allow accelerators, autoscrolling, etc.
+
+ It should not be used for other purposes.
+
+ This function never returns 0.
+*/
+QScrollBar* QScrollView::horizontalScrollBar() const
+{
+ return d->hbar;
+}
+
+/*!
+ Returns the component vertical scroll bar. It is made available to
+ allow accelerators, autoscrolling, etc.
+
+ It should not be used for other purposes.
+
+ This function never returns 0.
+*/
+QScrollBar* QScrollView::verticalScrollBar() const {
+ return d->vbar;
+}
+
+
+/*!
+ Scrolls the content so that the point \a (x, y) is visible with at
+ least 50-pixel margins (if possible, otherwise centered).
+*/
+void QScrollView::ensureVisible( int x, int y )
+{
+ ensureVisible(x, y, 50, 50);
+}
+
+/*!
+ \overload
+
+ Scrolls the content so that the point \a (x, y) is visible with at
+ least the \a xmargin and \a ymargin margins (if possible,
+ otherwise centered).
+*/
+void QScrollView::ensureVisible( int x, int y, int xmargin, int ymargin )
+{
+ int pw=visibleWidth();
+ int ph=visibleHeight();
+
+ int cx=-d->contentsX();
+ int cy=-d->contentsY();
+ int cw=d->contentsWidth();
+ int ch=contentsHeight();
+
+ if ( pw < xmargin*2 )
+ xmargin=pw/2;
+ if ( ph < ymargin*2 )
+ ymargin=ph/2;
+
+ if ( cw <= pw ) {
+ xmargin=0;
+ cx=0;
+ }
+ if ( ch <= ph ) {
+ ymargin=0;
+ cy=0;
+ }
+
+ if ( x < -cx+xmargin )
+ cx = -x+xmargin;
+ else if ( x >= -cx+pw-xmargin )
+ cx = -x+pw-xmargin;
+
+ if ( y < -cy+ymargin )
+ cy = -y+ymargin;
+ else if ( y >= -cy+ph-ymargin )
+ cy = -y+ph-ymargin;
+
+ if ( cx > 0 )
+ cx=0;
+ else if ( cx < pw-cw && cw>pw )
+ cx=pw-cw;
+
+ if ( cy > 0 )
+ cy=0;
+ else if ( cy < ph-ch && ch>ph )
+ cy=ph-ch;
+
+ setContentsPos( -cx, -cy );
+}
+
+/*!
+ Scrolls the content so that the point \a (x, y) is in the top-left
+ corner.
+*/
+void QScrollView::setContentsPos( int x, int y )
+{
+#if 0
+ // bounds checking...
+ if ( QApplication::reverseLayout() )
+ if ( x > d->contentsWidth() - visibleWidth() ) x = d->contentsWidth() - visibleWidth();
+ else
+#endif
+ if ( x < 0 ) x = 0;
+ if ( y < 0 ) y = 0;
+ // Choke signal handling while we update BOTH sliders.
+ d->signal_choke=TRUE;
+ moveContents( -x, -y );
+ d->vbar->setValue( y );
+ d->hbar->setValue( x );
+ d->signal_choke=FALSE;
+}
+
+/*!
+ Scrolls the content by \a dx to the left and \a dy upwards.
+*/
+void QScrollView::scrollBy( int dx, int dy )
+{
+ setContentsPos( QMAX( d->contentsX()+dx, 0 ), QMAX( d->contentsY()+dy, 0 ) );
+}
+
+/*!
+ Scrolls the content so that the point \a (x, y) is in the center
+ of visible area.
+*/
+void QScrollView::center( int x, int y )
+{
+ ensureVisible( x, y, 32000, 32000 );
+}
+
+/*!
+ \overload
+
+ Scrolls the content so that the point \a (x, y) is visible with
+ the \a xmargin and \a ymargin margins (as fractions of visible
+ the area).
+
+ For example:
+ \list
+ \i Margin 0.0 allows (x, y) to be on the edge of the visible area.
+ \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area.
+ \i Margin 1.0 ensures that (x, y) is in the center of the the visible area.
+ \endlist
+*/
+void QScrollView::center( int x, int y, float xmargin, float ymargin )
+{
+ int pw=visibleWidth();
+ int ph=visibleHeight();
+ ensureVisible( x, y, int( xmargin/2.0*pw+0.5 ), int( ymargin/2.0*ph+0.5 ) );
+}
+
+
+/*!
+ \fn void QScrollView::contentsMoving(int x, int y)
+
+ This signal is emitted just before the contents are moved to
+ position \a (x, y).
+
+ \sa contentsX(), contentsY()
+*/
+
+/*!
+ Moves the contents by \a (x, y).
+*/
+void QScrollView::moveContents(int x, int y)
+{
+ if ( -x+visibleWidth() > d->contentsWidth() )
+#if 0
+ if( QApplication::reverseLayout() )
+ x=QMAX(0,-d->contentsWidth()+visibleWidth());
+ else
+#endif
+ x=QMIN(0,-d->contentsWidth()+visibleWidth());
+ if ( -y+visibleHeight() > contentsHeight() )
+ y=QMIN(0,-contentsHeight()+visibleHeight());
+
+ int dx = x - d->vx;
+ int dy = y - d->vy;
+
+ if (!dx && !dy)
+ return; // Nothing to do
+
+ emit contentsMoving( -x, -y );
+
+ d->vx = x;
+ d->vy = y;
+
+ if ( d->clipped_viewport || d->static_bg ) {
+ // Cheap move (usually)
+ d->moveAllBy(dx,dy);
+ } else if ( /*dx && dy ||*/
+ ( QABS(dy) * 5 > visibleHeight() * 4 ) ||
+ ( QABS(dx) * 5 > visibleWidth() * 4 )
+ )
+ {
+ // Big move
+ if ( viewport()->isUpdatesEnabled() )
+ viewport()->update();
+ d->moveAllBy(dx,dy);
+ } else if ( !d->fake_scroll || d->contentsWidth() > visibleWidth() ) {
+ // Small move
+ clipper()->scroll(dx,dy);
+ }
+ d->hideOrShowAll(this, TRUE );
+}
+
+#if (QT_VERSION-0 >= 0x040000)
+#if defined(Q_CC_GNU)
+#warning "Should rename contents{X,Y,Width,Height} to viewport{...}"
+#endif
+// Because it's the viewport rectangle that is "moving", not the contents.
+#endif
+
+/*!
+ \property QScrollView::contentsX
+ \brief the X coordinate of the contents that are at the left edge of
+ the viewport.
+*/
+int QScrollView::contentsX() const
+{
+ return d->contentsX();
+}
+
+/*!
+ \property QScrollView::contentsY
+ \brief the Y coordinate of the contents that are at the top edge of
+ the viewport.
+*/
+int QScrollView::contentsY() const
+{
+ return d->contentsY();
+}
+
+/*!
+ \property QScrollView::contentsWidth
+ \brief the width of the contents area
+*/
+int QScrollView::contentsWidth() const
+{
+ return d->contentsWidth();
+}
+
+/*!
+ \property QScrollView::contentsHeight
+ \brief the height of the contents area
+*/
+int QScrollView::contentsHeight() const
+{
+ return d->vheight;
+}
+
+/*!
+ Sets the size of the contents area to \a w pixels wide and \a h
+ pixels high and updates the viewport accordingly.
+*/
+void QScrollView::resizeContents( int w, int h )
+{
+ int ow = d->vwidth;
+ int oh = d->vheight;
+ d->vwidth = w;
+ d->vheight = h;
+
+ d->scrollbar_timer.start( 0, TRUE );
+
+ if ( d->children.isEmpty() && d->policy == Default )
+ setResizePolicy( Manual );
+
+ if ( ow > w ) {
+ // Swap
+ int t=w;
+ w=ow;
+ ow=t;
+ }
+ // Refresh area ow..w
+ if ( ow < visibleWidth() && w >= 0 ) {
+ if ( ow < 0 )
+ ow = 0;
+ if ( w > visibleWidth() )
+ w = visibleWidth();
+ clipper()->update( d->contentsX()+ow, 0, w-ow, visibleHeight() );
+ }
+
+ if ( oh > h ) {
+ // Swap
+ int t=h;
+ h=oh;
+ oh=t;
+ }
+ // Refresh area oh..h
+ if ( oh < visibleHeight() && h >= 0 ) {
+ if ( oh < 0 )
+ oh = 0;
+ if ( h > visibleHeight() )
+ h = visibleHeight();
+ clipper()->update( 0, d->contentsY()+oh, visibleWidth(), h-oh);
+ }
+}
+
+/*!
+ Calls update() on a rectangle defined by \a x, \a y, \a w, \a h,
+ translated appropriately. If the rectangle is not visible, nothing
+ is repainted.
+
+ \sa repaintContents()
+*/
+void QScrollView::updateContents( int x, int y, int w, int h )
+{
+ if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
+ return;
+
+ QWidget* vp = viewport();
+
+ // Translate
+ x -= d->contentsX();
+ y -= d->contentsY();
+
+ // Clip to QCOORD space
+ if ( x < 0 ) {
+ w += x;
+ x = 0;
+ }
+ if ( y < 0 ) {
+ h += y;
+ y = 0;
+ }
+
+ if ( w < 0 || h < 0 )
+ return;
+ if ( x > visibleWidth() || y > visibleHeight() )
+ return;
+
+ if ( w > visibleWidth() )
+ w = visibleWidth();
+ if ( h > visibleHeight() )
+ h = visibleHeight();
+
+ if ( d->clipped_viewport ) {
+ // Translate clipper() to viewport()
+ x -= d->clipped_viewport->x();
+ y -= d->clipped_viewport->y();
+ }
+
+ vp->update( x, y, w, h );
+}
+
+/*!
+ \overload
+
+ Updates the contents in rectangle \a r
+*/
+void QScrollView::updateContents( const QRect& r )
+{
+ updateContents(r.x(), r.y(), r.width(), r.height());
+}
+
+/*!
+ \overload
+*/
+void QScrollView::updateContents()
+{
+ updateContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight() );
+}
+
+/*!
+ \overload
+
+ Repaints the contents of rectangle \a r. If \a erase is TRUE the
+ background is cleared using the background color.
+*/
+void QScrollView::repaintContents( const QRect& r, bool erase )
+{
+ repaintContents(r.x(), r.y(), r.width(), r.height(), erase);
+}
+
+
+/*!
+ \overload
+
+ Repaints the contents. If \a erase is TRUE the background is
+ cleared using the background color.
+*/
+void QScrollView::repaintContents( bool erase )
+{
+ repaintContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase );
+}
+
+
+/*!
+ Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h,
+ translated appropriately. If the rectangle is not visible, nothing
+ is repainted. If \a erase is TRUE the background is cleared using
+ the background color.
+
+ \sa updateContents()
+*/
+void QScrollView::repaintContents( int x, int y, int w, int h, bool erase )
+{
+ if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible )
+ return;
+
+ QWidget* vp = viewport();
+
+ // Translate logical to clipper()
+ x -= d->contentsX();
+ y -= d->contentsY();
+
+ // Clip to QCOORD space
+ if ( x < 0 ) {
+ w += x;
+ x = 0;
+ }
+ if ( y < 0 ) {
+ h += y;
+ y = 0;
+ }
+
+ if ( w < 0 || h < 0 )
+ return;
+ if ( w > visibleWidth() )
+ w = visibleWidth();
+ if ( h > visibleHeight() )
+ h = visibleHeight();
+
+ if ( d->clipped_viewport ) {
+ // Translate clipper() to viewport()
+ x -= d->clipped_viewport->x();
+ y -= d->clipped_viewport->y();
+ }
+
+ vp->repaint( x, y, w, h, erase );
+}
+
+
+/*!
+ For backward-compatibility only. It is easier to use
+ drawContents(QPainter*,int,int,int,int).
+
+ The default implementation translates the painter appropriately
+ and calls drawContents(QPainter*,int,int,int,int). See
+ drawContents() for an explanation of the parameters \a p, \a
+ offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph.
+*/
+void QScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph)
+{
+ p->translate(-offsetx,-offsety);
+ drawContents(p, clipx, clipy, clipw, cliph);
+}
+
+/*!
+ \fn void QScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph)
+
+ Reimplement this function if you are viewing a drawing area rather
+ than a widget.
+
+ The function should draw the rectangle (\a clipx, \a clipy, \a
+ clipw, \a cliph) of the contents using painter \a p. The clip
+ rectangle is in the scrollview's coordinates.
+
+ For example:
+ \code
+ {
+ // Fill a 40000 by 50000 rectangle at (100000,150000)
+
+ // Calculate the coordinates...
+ int x1 = 100000, y1 = 150000;
+ int x2 = x1+40000-1, y2 = y1+50000-1;
+
+ // Clip the coordinates so X/Windows will not have problems...
+ if (x1 < clipx) x1=clipx;
+ if (y1 < clipy) y1=clipy;
+ if (x2 > clipx+clipw-1) x2=clipx+clipw-1;
+ if (y2 > clipy+cliph-1) y2=clipy+cliph-1;
+
+ // Paint using the small coordinates...
+ if ( x2 >= x1 && y2 >= y1 )
+ p->fillRect(x1, y1, x2-x1+1, y2-y1+1, red);
+ }
+ \endcode
+
+ The clip rectangle and translation of the painter \a p is already
+ set appropriately.
+*/
+void QScrollView::drawContents(QPainter*, int, int, int, int)
+{
+}
+
+
+/*!
+ \reimp
+*/
+void QScrollView::frameChanged()
+{
+ // slight ugle-hack - the listview header needs readjusting when
+ // changing the frame
+ if (QListView *lv = ::qt_cast<QListView *>(this))
+ lv->triggerUpdate();
+ QFrame::frameChanged();
+ updateScrollBars();
+}
+
+
+/*!
+ Returns the viewport widget of the scrollview. This is the widget
+ containing the contents widget or which is the drawing area.
+*/
+QWidget* QScrollView::viewport() const
+{
+ if ( d->clipped_viewport )
+ return d->clipped_viewport;
+ return d->viewport;
+}
+
+/*!
+ Returns the clipper widget. Contents in the scrollview are
+ ultimately clipped to be inside the clipper widget.
+
+ You should not need to use this function.
+
+ \sa visibleWidth(), visibleHeight()
+*/
+QWidget* QScrollView::clipper() const
+{
+ return d->viewport;
+}
+
+/*!
+ \property QScrollView::visibleWidth
+ \brief the horizontal amount of the content that is visible
+*/
+int QScrollView::visibleWidth() const
+{
+ return clipper()->width();
+}
+
+/*!
+ \property QScrollView::visibleHeight
+ \brief the vertical amount of the content that is visible
+*/
+int QScrollView::visibleHeight() const
+{
+ return clipper()->height();
+}
+
+
+void QScrollView::changeFrameRect(const QRect& r)
+{
+ QRect oldr = frameRect();
+ if (oldr != r) {
+ QRect cr = contentsRect();
+ QRegion fr( frameRect() );
+ fr = fr.subtract( contentsRect() );
+ setFrameRect( r );
+ if ( isVisible() ) {
+ cr = cr.intersect( contentsRect() );
+ fr = fr.unite( frameRect() );
+ fr = fr.subtract( cr );
+ if ( !fr.isEmpty() )
+ QApplication::postEvent( this, new QPaintEvent( fr, FALSE ) );
+ }
+ }
+}
+
+
+/*!
+ 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
+ \e inside the frameRect() and is left blank; reimplement
+ drawFrame() or put widgets in the unused area.
+
+ By default all margins are zero.
+
+ \sa frameChanged()
+*/
+void QScrollView::setMargins(int left, int top, int right, int bottom)
+{
+ if ( left == d->l_marg &&
+ top == d->t_marg &&
+ right == d->r_marg &&
+ bottom == d->b_marg )
+ return;
+
+ d->l_marg = left;
+ d->t_marg = top;
+ d->r_marg = right;
+ d->b_marg = bottom;
+ updateScrollBars();
+}
+
+
+/*!
+ Returns the left margin.
+
+ \sa setMargins()
+*/
+int QScrollView::leftMargin() const
+{
+ return d->l_marg;
+}
+
+
+/*!
+ Returns the top margin.
+
+ \sa setMargins()
+*/
+int QScrollView::topMargin() const
+{
+ return d->t_marg;
+}
+
+
+/*!
+ Returns the right margin.
+
+ \sa setMargins()
+*/
+int QScrollView::rightMargin() const
+{
+ return d->r_marg;
+}
+
+
+/*!
+ Returns the bottom margin.
+
+ \sa setMargins()
+*/
+int QScrollView::bottomMargin() const
+{
+ return d->b_marg;
+}
+
+/*!
+ \reimp
+*/
+bool QScrollView::focusNextPrevChild( bool next )
+{
+ // Makes sure that the new focus widget is on-screen, if
+ // necessary by scrolling the scroll view.
+
+ // first set things up for the scan
+ QFocusData *f = focusData();
+ QWidget *startingPoint = f->home();
+ QWidget *candidate = 0;
+ QWidget *w = next ? f->next() : f->prev();
+ QSVChildRec *r;
+ extern bool qt_tab_all_widgets;
+ uint focus_flag = qt_tab_all_widgets ? TabFocus : StrongFocus;
+
+ // then scan for a possible focus widget candidate
+ while( !candidate && w != startingPoint ) {
+ if ( w != startingPoint &&
+ (w->focusPolicy() & focus_flag) == focus_flag
+ && w->isEnabled() &&!w->focusProxy() && w->isVisible() )
+ candidate = w;
+ w = next ? f->next() : f->prev();
+ }
+
+ // if we could not find one, maybe super or parentWidget() can?
+ if ( !candidate )
+ return QFrame::focusNextPrevChild( next );
+
+ // we've found one.
+ r = d->ancestorRec( candidate );
+ if ( r && ( r->child == candidate ||
+ candidate->isVisibleTo( r->child ) ) ) {
+ QPoint cp = r->child->mapToGlobal(QPoint(0,0));
+ QPoint cr = candidate->mapToGlobal(QPoint(0,0)) - cp;
+ ensureVisible( r->x+cr.x()+candidate->width()/2,
+ r->y+cr.y()+candidate->height()/2,
+ candidate->width()/2,
+ candidate->height()/2 );
+ }
+
+ candidate->setFocus();
+ return TRUE;
+}
+
+
+
+/*!
+ When a large numbers of child widgets are in a scrollview,
+ especially if they are close together, the scrolling performance
+ can suffer greatly. If \a y is TRUE the scrollview will use an
+ extra widget to group child widgets.
+
+ Note that you may only call enableClipper() prior to adding
+ widgets.
+
+ For a full discussion, see this class's \link #enableclipper
+ detailed description\endlink.
+*/
+void QScrollView::enableClipper(bool y)
+{
+ if ( !d->clipped_viewport == !y )
+ return;
+ if ( d->children.count() )
+ qFatal("May only call QScrollView::enableClipper() before adding widgets");
+ if ( y ) {
+ d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", d->flags);
+ d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2,
+ coord_limit,coord_limit);
+ d->clipped_viewport->setBackgroundMode( d->viewport->backgroundMode() );
+ d->viewport->setBackgroundMode(NoBackground); // no exposures for this
+ d->viewport->removeEventFilter( this );
+ d->clipped_viewport->installEventFilter( this );
+ d->clipped_viewport->show();
+ } else {
+ delete d->clipped_viewport;
+ d->clipped_viewport = 0;
+ }
+}
+
+/*!
+ Sets the scrollview to have a static background if \a y is TRUE,
+ or a scrolling background if \a y is FALSE. By default, the
+ background is scrolling.
+
+ Be aware that this mode is quite slow, as a full repaint of the
+ visible area has to be triggered on every contents move.
+
+ \sa hasStaticBackground()
+*/
+void QScrollView::setStaticBackground(bool y)
+{
+ d->static_bg = y;
+}
+
+/*!
+ Returns TRUE if QScrollView uses a static background; otherwise
+ returns FALSE.
+
+ \sa setStaticBackground()
+*/
+bool QScrollView::hasStaticBackground() const
+{
+ return d->static_bg;
+}
+
+/*!
+ \overload
+
+ Returns the point \a p translated to a point on the viewport()
+ widget.
+*/
+QPoint QScrollView::contentsToViewport( const QPoint& p ) const
+{
+ if ( d->clipped_viewport ) {
+ return QPoint( p.x() - d->contentsX() - d->clipped_viewport->x(),
+ p.y() - d->contentsY() - d->clipped_viewport->y() );
+ } else {
+ return QPoint( p.x() - d->contentsX(),
+ p.y() - d->contentsY() );
+ }
+}
+
+/*!
+ \overload
+
+ Returns the point on the viewport \a vp translated to a point in
+ the contents.
+*/
+QPoint QScrollView::viewportToContents( const QPoint& vp ) const
+{
+ if ( d->clipped_viewport ) {
+ return QPoint( vp.x() + d->contentsX() + d->clipped_viewport->x(),
+ vp.y() + d->contentsY() + d->clipped_viewport->y() );
+ } else {
+ return QPoint( vp.x() + d->contentsX(),
+ vp.y() + d->contentsY() );
+ }
+}
+
+
+/*!
+ Translates a point (\a x, \a y) in the contents to a point (\a vx,
+ \a vy) on the viewport() widget.
+*/
+void QScrollView::contentsToViewport( int x, int y, int& vx, int& vy ) const
+{
+ const QPoint v = contentsToViewport(QPoint(x,y));
+ vx = v.x();
+ vy = v.y();
+}
+
+/*!
+ Translates a point (\a vx, \a vy) on the viewport() widget to a
+ point (\a x, \a y) in the contents.
+*/
+void QScrollView::viewportToContents( int vx, int vy, int& x, int& y ) const
+{
+ const QPoint c = viewportToContents(QPoint(vx,vy));
+ x = c.x();
+ y = c.y();
+}
+
+/*!
+ \reimp
+*/
+QSize QScrollView::sizeHint() const
+{
+ if ( d->use_cached_size_hint && d->cachedSizeHint.isValid() )
+ return d->cachedSizeHint;
+
+ constPolish();
+ int f = 2 * frameWidth();
+ int h = fontMetrics().height();
+ QSize sz( f, f );
+ if ( d->policy > Manual ) {
+ QSVChildRec *r = d->children.first();
+ if ( r ) {
+ QSize cs = r->child->sizeHint();
+ if ( cs.isValid() )
+ sz += cs.boundedTo( r->child->maximumSize() );
+ else
+ sz += r->child->size();
+ }
+ } else {
+ sz += QSize( d->contentsWidth(), contentsHeight() );
+ }
+ if (d->vMode == AlwaysOn)
+ sz.setWidth(sz.width() + d->vbar->sizeHint().width());
+ if (d->hMode == AlwaysOn)
+ sz.setHeight(sz.height() + d->hbar->sizeHint().height());
+ return sz.expandedTo( QSize(12 * h, 8 * h) )
+ .boundedTo( QSize(36 * h, 24 * h) );
+}
+
+
+/*!
+ \reimp
+*/
+QSize QScrollView::minimumSizeHint() const
+{
+ int h = fontMetrics().height();
+ if ( h < 10 )
+ h = 10;
+ int f = 2 * frameWidth();
+ return QSize( (6 * h) + f, (4 * h) + f );
+}
+
+
+/*!
+ \reimp
+
+ (Implemented to get rid of a compiler warning.)
+*/
+void QScrollView::drawContents( QPainter * )
+{
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ \internal
+*/
+void QScrollView::startDragAutoScroll()
+{
+ if ( !d->autoscroll_timer.isActive() ) {
+ d->autoscroll_time = initialScrollTime;
+ d->autoscroll_accel = initialScrollAccel;
+ d->autoscroll_timer.start( d->autoscroll_time );
+ }
+}
+
+
+/*!
+ \internal
+*/
+void QScrollView::stopDragAutoScroll()
+{
+ d->autoscroll_timer.stop();
+}
+
+
+/*!
+ \internal
+*/
+void QScrollView::doDragAutoScroll()
+{
+ QPoint p = d->viewport->mapFromGlobal( QCursor::pos() );
+
+ if ( d->autoscroll_accel-- <= 0 && d->autoscroll_time ) {
+ d->autoscroll_accel = initialScrollAccel;
+ d->autoscroll_time--;
+ d->autoscroll_timer.start( d->autoscroll_time );
+ }
+ int l = QMAX( 1, ( initialScrollTime- d->autoscroll_time ) );
+
+ int dx = 0, dy = 0;
+ if ( p.y() < autoscroll_margin ) {
+ dy = -l;
+ } else if ( p.y() > visibleHeight() - autoscroll_margin ) {
+ dy = +l;
+ }
+ if ( p.x() < autoscroll_margin ) {
+ dx = -l;
+ } else if ( p.x() > visibleWidth() - autoscroll_margin ) {
+ dx = +l;
+ }
+ if ( dx || dy ) {
+ scrollBy(dx,dy);
+ } else {
+ stopDragAutoScroll();
+ }
+}
+
+
+/*!
+ \property QScrollView::dragAutoScroll
+ \brief whether autoscrolling in drag move events is enabled
+
+ If this property is set to TRUE (the default), the QScrollView
+ automatically scrolls the contents in drag move events if the user
+ moves the cursor close to a border of the view. Of course this
+ works only if the viewport accepts drops. Specifying FALSE
+ disables this autoscroll feature.
+
+ \warning Enabling this property might not be enough to
+ effectively turn on autoscrolling. If you put a custom widget in
+ the QScrollView, you might need to call QDragEvent::ignore() on
+ the event in the dragEnterEvent() and dragMoveEvent()
+ reimplementations.
+*/
+
+void QScrollView::setDragAutoScroll( bool b )
+{
+ d->drag_autoscroll = b;
+}
+
+bool QScrollView::dragAutoScroll() const
+{
+ return d->drag_autoscroll;
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!\internal
+ */
+void QScrollView::setCachedSizeHint( const QSize &sh ) const
+{
+ if ( isVisible() && !d->cachedSizeHint.isValid() )
+ d->cachedSizeHint = sh;
+}
+
+/*!\internal
+ */
+void QScrollView::disableSizeHintCaching()
+{
+ d->use_cached_size_hint = FALSE;
+}
+
+/*!\internal
+ */
+QSize QScrollView::cachedSizeHint() const
+{
+ return d->use_cached_size_hint ? d->cachedSizeHint : QSize();
+}
+
+#endif // QT_NO_SCROLLVIEW
diff --git a/src/widgets/qscrollview.h b/src/widgets/qscrollview.h
new file mode 100644
index 0000000..e2ace97
--- /dev/null
+++ b/src/widgets/qscrollview.h
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** Definition of QScrollView class
+**
+** Created : 970523
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+#ifndef QSCROLLVIEW_H
+#define QSCROLLVIEW_H
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qscrollbar.h"
+#endif // QT_H
+
+#ifndef QT_NO_SCROLLVIEW
+
+class QScrollViewData;
+
+class Q_EXPORT QScrollView : public QFrame
+{
+ Q_OBJECT
+ Q_ENUMS( ResizePolicy ScrollBarMode )
+ Q_PROPERTY( ResizePolicy resizePolicy READ resizePolicy WRITE setResizePolicy )
+ Q_PROPERTY( ScrollBarMode vScrollBarMode READ vScrollBarMode WRITE setVScrollBarMode )
+ Q_PROPERTY( ScrollBarMode hScrollBarMode READ hScrollBarMode WRITE setHScrollBarMode )
+ Q_PROPERTY( int visibleWidth READ visibleWidth )
+ Q_PROPERTY( int visibleHeight READ visibleHeight )
+ Q_PROPERTY( int contentsWidth READ contentsWidth )
+ Q_PROPERTY( int contentsHeight READ contentsHeight )
+ Q_PROPERTY( int contentsX READ contentsX )
+ Q_PROPERTY( int contentsY READ contentsY )
+#ifndef QT_NO_DRAGANDDROP
+ Q_PROPERTY( bool dragAutoScroll READ dragAutoScroll WRITE setDragAutoScroll )
+#endif
+
+public:
+ QScrollView(QWidget* parent=0, const char* name=0, WFlags f=0);
+ ~QScrollView();
+
+ enum ResizePolicy { Default, Manual, AutoOne, AutoOneFit };
+ virtual void setResizePolicy( ResizePolicy );
+ ResizePolicy resizePolicy() const;
+
+ void styleChange( QStyle & );
+ void removeChild(QWidget* child);
+ virtual void addChild( QWidget* child, int x=0, int y=0 );
+ virtual void moveChild( QWidget* child, int x, int y );
+ int childX(QWidget* child);
+ int childY(QWidget* child);
+ bool childIsVisible(QWidget* child) { return child->isVisible(); } // obsolete functions
+ void showChild(QWidget* child, bool yes=TRUE) {
+ if ( yes )
+ child->show();
+ else
+ child->hide();
+ }
+
+ enum ScrollBarMode { Auto, AlwaysOff, AlwaysOn };
+
+ ScrollBarMode vScrollBarMode() const;
+ virtual void setVScrollBarMode( ScrollBarMode );
+
+ ScrollBarMode hScrollBarMode() const;
+ virtual void setHScrollBarMode( ScrollBarMode );
+
+ QWidget* cornerWidget() const;
+ virtual void setCornerWidget(QWidget*);
+
+ // ### 4.0: Consider providing a factory function for scrollbars
+ // (e.g. make the two following functions virtual)
+ QScrollBar* horizontalScrollBar() const;
+ QScrollBar* verticalScrollBar() const;
+ QWidget* viewport() const;
+ QWidget* clipper() const;
+
+ int visibleWidth() const;
+ int visibleHeight() const;
+
+ int contentsWidth() const;
+ int contentsHeight() const;
+ int contentsX() const;
+ int contentsY() const;
+
+ void resize( int w, int h );
+ void resize( const QSize& );
+ void show();
+
+ void updateContents( int x, int y, int w, int h );
+ void updateContents( const QRect& r );
+ void updateContents();
+ void repaintContents( int x, int y, int w, int h, bool erase=TRUE );
+ void repaintContents( const QRect& r, bool erase=TRUE );
+ void repaintContents( bool erase=TRUE );
+ void contentsToViewport( int x, int y, int& vx, int& vy ) const;
+ void viewportToContents( int vx, int vy, int& x, int& y ) const;
+ QPoint contentsToViewport( const QPoint& ) const;
+ QPoint viewportToContents( const QPoint& ) const;
+ void enableClipper( bool y );
+
+ void setStaticBackground( bool y );
+ bool hasStaticBackground() const;
+
+ QSize viewportSize( int, int ) const;
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void removeChild(QObject* child);
+
+ bool isHorizontalSliderPressed();
+ bool isVerticalSliderPressed();
+
+#ifndef QT_NO_DRAGANDDROP
+ virtual void setDragAutoScroll( bool b );
+ bool dragAutoScroll() const;
+#endif
+
+signals:
+ void contentsMoving(int x, int y);
+ void horizontalSliderPressed();
+ void horizontalSliderReleased();
+ void verticalSliderPressed();
+ void verticalSliderReleased();
+
+public slots:
+ virtual void resizeContents( int w, int h );
+ void scrollBy( int dx, int dy );
+ virtual void setContentsPos( int x, int y );
+ void ensureVisible(int x, int y);
+ void ensureVisible(int x, int y, int xmargin, int ymargin);
+ void center(int x, int y);
+ void center(int x, int y, float xmargin, float ymargin);
+
+ void updateScrollBars(); // ### virtual in 4.0
+ void setEnabled( bool enable );
+
+protected:
+ virtual void drawContents(QPainter*, int cx, int cy, int cw, int ch);
+ virtual void drawContentsOffset(QPainter*, int ox, int oy,
+ int cx, int cy, int cw, int ch);
+
+
+ virtual void contentsMousePressEvent( QMouseEvent* );
+ virtual void contentsMouseReleaseEvent( QMouseEvent* );
+ virtual void contentsMouseDoubleClickEvent( QMouseEvent* );
+ virtual void contentsMouseMoveEvent( QMouseEvent* );
+#ifndef QT_NO_DRAGANDDROP
+ virtual void contentsDragEnterEvent( QDragEnterEvent * );
+ virtual void contentsDragMoveEvent( QDragMoveEvent * );
+ virtual void contentsDragLeaveEvent( QDragLeaveEvent * );
+ virtual void contentsDropEvent( QDropEvent * );
+#endif
+#ifndef QT_NO_WHEELEVENT
+ virtual void contentsWheelEvent( QWheelEvent * );
+#endif
+ virtual void contentsContextMenuEvent( QContextMenuEvent * );
+
+
+ virtual void viewportPaintEvent( QPaintEvent* );
+ virtual void viewportResizeEvent( QResizeEvent* );
+ virtual void viewportMousePressEvent( QMouseEvent* );
+ virtual void viewportMouseReleaseEvent( QMouseEvent* );
+ virtual void viewportMouseDoubleClickEvent( QMouseEvent* );
+ virtual void viewportMouseMoveEvent( QMouseEvent* );
+#ifndef QT_NO_DRAGANDDROP
+ virtual void viewportDragEnterEvent( QDragEnterEvent * );
+ virtual void viewportDragMoveEvent( QDragMoveEvent * );
+ virtual void viewportDragLeaveEvent( QDragLeaveEvent * );
+ virtual void viewportDropEvent( QDropEvent * );
+#endif
+#ifndef QT_NO_WHEELEVENT
+ virtual void viewportWheelEvent( QWheelEvent * );
+#endif
+ virtual void viewportContextMenuEvent( QContextMenuEvent * );
+
+ void frameChanged();
+
+ virtual void setMargins(int left, int top, int right, int bottom);
+ int leftMargin() const;
+ int topMargin() const;
+ int rightMargin() const;
+ int bottomMargin() const;
+
+ bool focusNextPrevChild( bool next );
+
+ virtual void setHBarGeometry(QScrollBar& hbar, int x, int y, int w, int h);
+ virtual void setVBarGeometry(QScrollBar& vbar, int x, int y, int w, int h);
+
+ void resizeEvent(QResizeEvent*);
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent * );
+#endif
+ void contextMenuEvent( QContextMenuEvent * );
+ bool eventFilter( QObject *, QEvent *e );
+
+ void setCachedSizeHint( const QSize &sh ) const;
+ QSize cachedSizeHint() const;
+ void fontChange( const QFont & );
+
+private:
+ void drawContents( QPainter* );
+ void moveContents(int x, int y);
+
+ QScrollViewData* d;
+
+private slots:
+ void hslide(int);
+ void vslide(int);
+ void hbarIsPressed();
+ void hbarIsReleased();
+ void vbarIsPressed();
+ void vbarIsReleased();
+#ifndef QT_NO_DRAGANDDROP
+ void doDragAutoScroll();
+ void startDragAutoScroll();
+ void stopDragAutoScroll();
+#endif
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QScrollView( const QScrollView & );
+ QScrollView &operator=( const QScrollView & );
+#endif
+ void changeFrameRect(const QRect&);
+
+public:
+ void disableSizeHintCaching();
+
+};
+
+#endif // QT_NO_SCROLLVIEW
+
+#endif // QSCROLLVIEW_H
diff --git a/src/widgets/qslider.cpp b/src/widgets/qslider.cpp
new file mode 100644
index 0000000..1573294
--- /dev/null
+++ b/src/widgets/qslider.cpp
@@ -0,0 +1,921 @@
+/****************************************************************************
+**
+** Implementation of QSlider class
+**
+** Created : 961019
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qslider.h"
+#ifndef QT_NO_SLIDER
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qtimer.h"
+#include "qbitmap.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+static const int thresholdTime = 300;
+static const int repeatTime = 100;
+
+struct QSliderPrivate
+{
+ // ### move these to QSlider in Qt 4.0
+ int sliderStartVal;
+ QSliderPrivate() : sliderStartVal( 0 ) { }
+};
+
+
+/*!
+ \class QSlider
+ \brief The QSlider widget provides a vertical or horizontal slider.
+
+ \ingroup basic
+ \mainclass
+
+ The slider is the classic widget for controlling a bounded value.
+ It lets the user move a slider along a horizontal or vertical
+ groove and translates the slider's position into an integer value
+ within the legal range.
+
+ QSlider inherits QRangeControl, which provides the "integer" side
+ of the slider. setRange() and value() are likely to be used by
+ practically all slider users; see the \l QRangeControl
+ documentation for information about the many other functions that
+ class provides.
+
+ The main functions offered by the slider itself are tickmark and
+ orientation control; you can use setTickmarks() to indicate where
+ you want the tickmarks to be, setTickInterval() to indicate how
+ many of them you want and setOrientation() to indicate whether the
+ slider is to be horizontal or vertical.
+
+ A slider accepts focus on Tab and uses the mouse wheel and a
+ suitable keyboard interface.
+
+ <img src=qslider-m.png> <img src=qslider-w.png>
+
+ \important setRange
+
+ \sa QScrollBar QSpinBox
+ \link guibooks.html#fowler GUI Design Handbook: Slider\endlink
+*/
+
+
+/*!
+ \enum QSlider::TickSetting
+
+ This enum specifies where the tickmarks are to be drawn relative
+ to the slider's groove and the handle the user moves.
+
+ \value NoMarks do not draw any tickmarks.
+ \value Both draw tickmarks on both sides of the groove.
+ \value Above draw tickmarks above the (horizontal) slider
+ \value Below draw tickmarks below the (horizontal) slider
+ \value Left draw tickmarks to the left of the (vertical) slider
+ \value Right draw tickmarks to the right of the (vertical) slider
+*/
+
+
+/*!
+ Constructs a vertical slider.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QSlider::QSlider( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ orient = Vertical;
+ init();
+}
+
+/*!
+ Constructs a slider.
+
+ The \a orientation must be \l Qt::Vertical or \l Qt::Horizontal.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QSlider::QSlider( Orientation orientation, QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ orient = orientation;
+ init();
+}
+
+/*!
+ Constructs a slider whose value can never be smaller than \a
+ minValue or greater than \a maxValue, whose page step size is \a
+ pageStep and whose value is initially \a value (which is
+ guaranteed to be in range using bound()).
+
+ If \a orientation is \c Qt::Vertical the slider is vertical and if it
+ is \c Qt::Horizontal the slider is horizontal.
+
+ The \a parent and \a name arguments are sent on to the QWidget
+ constructor.
+*/
+
+QSlider::QSlider( int minValue, int maxValue, int pageStep,
+ int value, Orientation orientation,
+ QWidget *parent, const char *name )
+ : QWidget( parent, name ),
+ QRangeControl( minValue, maxValue, 1, pageStep, value )
+{
+ orient = orientation;
+ init();
+ sliderVal = value;
+}
+
+/*!
+ Destructor.
+*/
+QSlider::~QSlider()
+{
+ delete d;
+}
+
+void QSlider::init()
+{
+ d = new QSliderPrivate;
+ timer = 0;
+ sliderPos = 0;
+ sliderVal = 0;
+ clickOffset = 0;
+ state = Idle;
+ track = TRUE;
+ ticks = NoMarks;
+ tickInt = 0;
+ setFocusPolicy( TabFocus );
+ initTicks();
+
+ QSizePolicy sp( QSizePolicy::Expanding, QSizePolicy::Fixed );
+ if ( orient == Vertical )
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+}
+
+
+/*
+ Does what's needed when someone changes the tickmark status.
+*/
+
+void QSlider::initTicks()
+{
+ tickOffset = style().pixelMetric( QStyle::PM_SliderTickmarkOffset, this );
+}
+
+
+/*!
+ \property QSlider::tracking
+ \brief whether slider tracking is enabled
+
+ If tracking is enabled (the default), the slider emits the
+ valueChanged() signal whenever the slider is being dragged. If
+ tracking is disabled, the slider emits the valueChanged() signal
+ when the user releases the mouse button (unless the value happens
+ to be the same as before).
+*/
+
+void QSlider::setTracking( bool enable )
+{
+ track = enable;
+}
+
+
+/*!
+ \fn void QSlider::valueChanged( int value )
+
+ This signal is emitted when the slider value is changed, with the
+ new slider \a value as its argument.
+*/
+
+/*!
+ \fn void QSlider::sliderPressed()
+
+ This signal is emitted when the user presses the slider with the
+ mouse.
+*/
+
+/*!
+ \fn void QSlider::sliderMoved( int value )
+
+ This signal is emitted when the slider is dragged, with the new
+ slider \a value as its argument.
+*/
+
+/*!
+ \fn void QSlider::sliderReleased()
+
+ This signal is emitted when the user releases the slider with the mouse.
+*/
+
+/*
+ Calculates slider position corresponding to value \a v.
+*/
+
+int QSlider::positionFromValue( int v ) const
+{
+ int a = available();
+ int x = QRangeControl::positionFromValue( v, a );
+ if ( orient == Horizontal && QApplication::reverseLayout() )
+ x = a - x;
+ return x;
+}
+
+/*
+ Returns the available space in which the slider can move.
+*/
+
+int QSlider::available() const
+{
+ return style().pixelMetric( QStyle::PM_SliderSpaceAvailable, this );
+}
+
+/*
+ Calculates a value corresponding to slider position \a p.
+*/
+
+int QSlider::valueFromPosition( int p ) const
+{
+ int a = available();
+ int x = QRangeControl::valueFromPosition( p, a );
+ if ( orient == Horizontal && QApplication::reverseLayout() )
+ x = maxValue() + minValue() - x;
+ return x;
+}
+
+/*!
+ Implements the virtual QRangeControl function.
+*/
+
+void QSlider::rangeChange()
+{
+ int newPos = positionFromValue( value() );
+ if ( newPos != sliderPos ) {
+ reallyMoveSlider( newPos );
+ }
+}
+
+/*!
+ Implements the virtual QRangeControl function.
+*/
+
+void QSlider::valueChange()
+{
+ if ( sliderVal != value() ) {
+ int newPos = positionFromValue( value() );
+ sliderVal = value();
+ reallyMoveSlider( newPos );
+ }
+ emit valueChanged(value());
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::resizeEvent( QResizeEvent * )
+{
+ rangeChange();
+ initTicks();
+}
+
+
+/*!
+ Reimplements the virtual function QWidget::setPalette().
+
+ Sets the background color to the mid color for Motif style sliders
+ using palette \a p.
+*/
+
+void QSlider::setPalette( const QPalette &p )
+{
+ QWidget::setPalette( p );
+}
+
+
+
+/*!
+ \property QSlider::orientation
+ \brief the slider's orientation
+
+ The orientation must be \l Qt::Vertical (the default) or \l
+ Qt::Horizontal.
+*/
+
+void QSlider::setOrientation( Orientation orientation )
+{
+ if ( orientation == orient )
+ return;
+
+ if ( !testWState( WState_OwnSizePolicy ) ) {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+ }
+
+ orient = orientation;
+
+ rangeChange();
+ update();
+}
+
+/*!
+ \fn int QSlider::sliderStart() const
+
+ Returns the start position of the slider.
+*/
+
+
+/*!
+ Returns the slider handle rectangle. (This is the visual marker
+ that the user can move.)
+*/
+
+QRect QSlider::sliderRect() const
+{
+ return style().querySubControlMetrics( QStyle::CC_Slider, this,
+ QStyle::SC_SliderHandle );
+}
+
+/*
+ Performs the actual moving of the slider.
+*/
+
+void QSlider::reallyMoveSlider( int newPos )
+{
+ QRegion oldR(sliderRect());
+ sliderPos = newPos;
+ QRegion newR(sliderRect());
+
+ /* just the one repaint if no background */
+ if (backgroundMode() == NoBackground)
+ repaint(newR | oldR, FALSE);
+ else {
+ repaint(oldR.subtract(newR));
+ repaint(newR, FALSE);
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+
+ QStyle::SCFlags sub = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
+ if ( tickmarks() != NoMarks )
+ sub |= QStyle::SC_SliderTickmarks;
+
+ style().drawComplexControl( QStyle::CC_Slider, &p, this, rect(), colorGroup(),
+ flags, sub, state == Dragging ? QStyle::SC_SliderHandle : QStyle::SC_None );
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::mousePressEvent( QMouseEvent *e )
+{
+ int slideLength = style().pixelMetric( QStyle::PM_SliderLength, this );
+ resetState();
+ d->sliderStartVal = sliderVal;
+ QRect r = sliderRect();
+
+ if ( e->button() == RightButton )
+ return;
+
+ if ( r.contains( e->pos() ) ) {
+ state = Dragging;
+ clickOffset = (QCOORD)( goodPart( e->pos() ) - sliderPos );
+ emit sliderPressed();
+ } else if ( e->button() == MidButton ) {
+ int pos = goodPart( e->pos() );
+ moveSlider( pos - slideLength / 2 );
+ state = Dragging;
+ clickOffset = slideLength / 2;
+ } else if ( orient == Horizontal && e->pos().x() < r.left() //### goodPart
+ || orient == Vertical && e->pos().y() < r.top() ) {
+ if ( orient == Horizontal && QApplication::reverseLayout() ) {
+ state = TimingUp;
+ addPage();
+ } else {
+ state = TimingDown;
+ subtractPage();
+ }
+ if ( !timer )
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
+ timer->start( thresholdTime, TRUE );
+ } else if ( orient == Horizontal && e->pos().x() > r.right() //### goodPart
+ || orient == Vertical && e->pos().y() > r.bottom() ) {
+ if ( orient == Horizontal && QApplication::reverseLayout() ) {
+ state = TimingDown;
+ subtractPage();
+ } else {
+ state = TimingUp;
+ addPage();
+ }
+ if ( !timer )
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
+ timer->start( thresholdTime, TRUE );
+ }
+ update( sliderRect() );
+}
+
+/*!
+ \reimp
+*/
+void QSlider::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( state != Dragging )
+ return;
+
+ QRect r = rect();
+ int m = style().pixelMetric( QStyle::PM_MaximumDragDistance,
+ this );
+ if ( m >= 0 ) {
+ if ( orientation() == Horizontal )
+ r.setRect( r.x() - m, r.y() - 2*m/3,
+ r.width() + 2*m, r.height() + 3*m );
+ else
+ r.setRect( r.x() - 2*m/3, r.y() - m,
+ r.width() + 3*m, r.height() + 2*m );
+ if ( !r.contains( e->pos() ) ) {
+ moveSlider( positionFromValue(d->sliderStartVal) );
+ return;
+ }
+ }
+
+ int pos = goodPart( e->pos() );
+ moveSlider( pos - clickOffset );
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QSlider::wheelEvent( QWheelEvent * e )
+{
+ if ( e->orientation() != orientation() && !rect().contains(e->pos()) )
+ return;
+
+ static float offset = 0;
+ static QSlider* offset_owner = 0;
+ if (offset_owner != this){
+ offset_owner = this;
+ offset = 0;
+ }
+ offset += -e->delta()*QMAX(pageStep(),lineStep())/120;
+ if (QABS(offset)<1)
+ return;
+ setValue( value() + int(offset) );
+ offset -= int(offset);
+ e->accept();
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QSlider::mouseReleaseEvent( QMouseEvent * )
+{
+ resetState();
+ update( sliderRect() );
+}
+
+/*!
+ \reimp
+*/
+void QSlider::focusInEvent( QFocusEvent * e)
+{
+ QWidget::focusInEvent( e );
+}
+
+/*!
+ \reimp
+*/
+void QSlider::focusOutEvent( QFocusEvent * e )
+{
+ QWidget::focusOutEvent( e );
+}
+
+/*!
+ Moves the left (or top) edge of the slider to position \a pos. The
+ slider is actually moved to the step position nearest the given \a
+ pos.
+*/
+
+void QSlider::moveSlider( int pos )
+{
+ int a = available();
+ int newPos = QMIN( a, QMAX( 0, pos ) );
+ int newVal = valueFromPosition( newPos );
+ if (style().styleHint(QStyle::SH_Slider_SnapToValue, this))
+ newPos = positionFromValue( newVal );
+ if ( sliderPos != newPos )
+ reallyMoveSlider( newPos );
+ if ( sliderVal != newVal ) {
+ sliderVal = newVal;
+ emit sliderMoved( sliderVal );
+ }
+ if ( tracking() && sliderVal != value() )
+ setValue( sliderVal );
+
+}
+
+
+/*
+ Resets all state information and stops the timer.
+*/
+
+void QSlider::resetState()
+{
+ if ( timer ) {
+ timer->stop();
+ timer->disconnect();
+ }
+ switch ( state ) {
+ case TimingUp:
+ case TimingDown:
+ break;
+ case Dragging: {
+ setValue( valueFromPosition( sliderPos ) );
+ emit sliderReleased();
+ break;
+ }
+ case Idle:
+ break;
+ default:
+ qWarning("QSlider: (%s) in wrong state", name( "unnamed" ) );
+ }
+ state = Idle;
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::keyPressEvent( QKeyEvent *e )
+{
+ bool sloppy = bool(style().styleHint(QStyle::SH_Slider_SloppyKeyEvents, this));
+ switch ( e->key() ) {
+ case Key_Left:
+ if ( sloppy || orient == Horizontal ) {
+ if (QApplication::reverseLayout())
+ addLine();
+ else
+ subtractLine();
+ }
+ break;
+ case Key_Right:
+ if ( sloppy || orient == Horizontal ) {
+ if (QApplication::reverseLayout())
+ subtractLine();
+ else
+ addLine();
+ }
+ break;
+ case Key_Up:
+ if ( sloppy || orient == Vertical )
+ subtractLine();
+ break;
+ case Key_Down:
+ if ( sloppy || orient == Vertical )
+ addLine();
+ break;
+ case Key_Prior:
+ subtractPage();
+ break;
+ case Key_Next:
+ addPage();
+ break;
+ case Key_Home:
+ setValue( minValue() );
+ break;
+ case Key_End:
+ setValue( maxValue() );
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+}
+
+void QSlider::setValue( int value )
+{
+ QRangeControl::setValue( value );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+
+/*! \reimp
+*/
+
+void QSlider::addLine()
+{
+ QRangeControl::addLine();
+}
+
+/*! \reimp
+*/
+
+void QSlider::subtractLine()
+{
+ QRangeControl::subtractLine();
+}
+
+/*!
+ Moves the slider one pageStep() up or right.
+*/
+
+void QSlider::addStep()
+{
+ addPage();
+}
+
+
+/*!
+ Moves the slider one pageStep() down or left.
+*/
+
+void QSlider::subtractStep()
+{
+ subtractPage();
+}
+
+
+/*
+ Waits for autorepeat.
+*/
+
+void QSlider::repeatTimeout()
+{
+ Q_ASSERT( timer );
+ timer->disconnect();
+ if ( state == TimingDown )
+ connect( timer, SIGNAL(timeout()), SLOT(subtractStep()) );
+ else if ( state == TimingUp )
+ connect( timer, SIGNAL(timeout()), SLOT(addStep()) );
+ timer->start( repeatTime, FALSE );
+}
+
+
+/*
+ Returns the relevant dimension of \a p.
+*/
+
+int QSlider::goodPart( const QPoint &p ) const
+{
+ return (orient == Horizontal) ? p.x() : p.y();
+}
+
+/*!
+ \reimp
+*/
+QSize QSlider::sizeHint() const
+{
+ constPolish();
+ const int length = 84, tickSpace = 5;
+ int thick = style().pixelMetric( QStyle::PM_SliderThickness, this );
+ if ( ticks & Above )
+ thick += tickSpace;
+ if ( ticks & Below )
+ thick += tickSpace;
+ int w = thick, h = length;
+ if ( orient == Horizontal ) {
+ w = length;
+ h = thick;
+ }
+ return (style().sizeFromContents(QStyle::CT_Slider, this,
+ QSize(w, h)).expandedTo(QApplication::globalStrut()));
+}
+
+
+
+/*!
+ \reimp
+*/
+
+QSize QSlider::minimumSizeHint() const
+{
+ QSize s = sizeHint();
+ int length = style().pixelMetric(QStyle::PM_SliderLength, this);
+ if ( orient == Horizontal )
+ s.setWidth( length );
+ else
+ s.setHeight( length );
+
+ return s;
+}
+
+/*! \fn void QSlider::setSizePolicy( QSizePolicy::SizeType, QSizePolicy::SizeType, bool )
+ \reimp
+*/
+
+/*! \reimp */
+void QSlider::setSizePolicy( QSizePolicy sp )
+{
+ // ## remove 4.0
+ QWidget::setSizePolicy( sp );
+}
+
+/*! \reimp */
+QSizePolicy QSlider::sizePolicy() const
+{
+ // ### 4.0 remove this reimplementation
+ return QWidget::sizePolicy();
+}
+
+/*!
+ \property QSlider::tickmarks
+ \brief the tickmark settings for this slider
+
+ The valid values are in \l{QSlider::TickSetting}. The default is
+ \c NoMarks.
+
+ \sa tickInterval
+*/
+
+void QSlider::setTickmarks( TickSetting s )
+{
+ ticks = s;
+ initTicks();
+ update();
+}
+
+
+/*!
+ \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 lineStep() and pageStep(). The initial
+ value of tickInterval is 0.
+
+ \sa QRangeControl::lineStep(), QRangeControl::pageStep()
+*/
+
+void QSlider::setTickInterval( int i )
+{
+ tickInt = QMAX( 0, i );
+ update();
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::styleChange( QStyle& old )
+{
+ QWidget::styleChange( old );
+}
+
+/*!
+ \property QSlider::minValue
+ \brief the current minimum value of the slider
+
+ When setting this property, the \l QSlider::maxValue is adjusted,
+ if necessary, to ensure that the range remains valid.
+
+ \sa setRange()
+*/
+int QSlider::minValue() const
+{
+ return QRangeControl::minValue();
+}
+
+/*!
+ \property QSlider::maxValue
+ \brief the current maximum value of the slider
+
+ When setting this property, the \l QSlider::minValue is adjusted,
+ if necessary, to ensure that the range remains valid.
+
+ \sa setRange()
+*/
+int QSlider::maxValue() const
+{
+ return QRangeControl::maxValue();
+}
+
+void QSlider::setMinValue( int minVal )
+{
+ QRangeControl::setMinValue( minVal );
+}
+
+void QSlider::setMaxValue( int maxVal )
+{
+ QRangeControl::setMaxValue( maxVal );
+}
+
+/*!
+ \property QSlider::lineStep
+ \brief the current line step
+
+ When setting lineStep, the virtual stepChange() function will be
+ called if the new line step is different from the previous
+ setting.
+
+ \sa setSteps() QRangeControl::pageStep() setRange()
+*/
+int QSlider::lineStep() const
+{
+ return QRangeControl::lineStep();
+}
+
+/*!
+ \property QSlider::pageStep
+ \brief the current page step
+
+ When setting pageStep, the virtual stepChange() function will be
+ called if the new page step is different from the previous
+ setting.
+
+ \sa QRangeControl::setSteps() setLineStep() setRange()
+*/
+
+int QSlider::pageStep() const
+{
+ return QRangeControl::pageStep();
+}
+
+void QSlider::setLineStep( int i )
+{
+ setSteps( i, pageStep() );
+}
+
+void QSlider::setPageStep( int i )
+{
+ setSteps( lineStep(), i );
+}
+
+/*!
+ \property QSlider::value
+ \brief the current slider value
+
+ \sa QRangeControl::value() prevValue()
+*/
+
+int QSlider::value() const
+{
+ return QRangeControl::value();
+}
+
+#endif
diff --git a/src/widgets/qslider.h b/src/widgets/qslider.h
new file mode 100644
index 0000000..e51b550
--- /dev/null
+++ b/src/widgets/qslider.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Definition of QSlider class
+**
+** Created : 961019
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSLIDER_H
+#define QSLIDER_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qrangecontrol.h"
+#endif // QT_H
+
+#ifndef QT_NO_SLIDER
+
+struct QSliderPrivate;
+
+class QTimer;
+
+class Q_EXPORT QSlider : public QWidget, public QRangeControl
+{
+ Q_OBJECT
+ Q_ENUMS( TickSetting )
+ Q_PROPERTY( int minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( int lineStep READ lineStep WRITE setLineStep )
+ Q_PROPERTY( int pageStep READ pageStep WRITE setPageStep )
+ Q_PROPERTY( int value READ value WRITE setValue )
+ Q_PROPERTY( bool tracking READ tracking WRITE setTracking )
+ Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation )
+ Q_PROPERTY( TickSetting tickmarks READ tickmarks WRITE setTickmarks )
+ Q_PROPERTY( int tickInterval READ tickInterval WRITE setTickInterval )
+
+public:
+ enum TickSetting { NoMarks = 0, Above = 1, Left = Above,
+ Below = 2, Right = Below, Both = 3 };
+
+ QSlider( QWidget *parent, const char* name = 0 );
+ QSlider( Orientation, QWidget *parent, const char* name = 0 );
+ QSlider( int minValue, int maxValue, int pageStep, int value, Orientation,
+ QWidget *parent, const char* name = 0 );
+ ~QSlider();
+
+ virtual void setOrientation( Orientation );
+ Orientation orientation() const;
+ virtual void setTracking( bool enable );
+ bool tracking() const;
+ virtual void setPalette( const QPalette & );
+
+ int sliderStart() const;
+ QRect sliderRect() const;
+ QSize sizeHint() const;
+ void setSizePolicy( QSizePolicy sp );
+ void setSizePolicy( QSizePolicy::SizeType hor, QSizePolicy::SizeType ver, bool hfw = FALSE );
+
+ QSizePolicy sizePolicy() const;
+ QSize minimumSizeHint() const;
+
+ virtual void setTickmarks( TickSetting );
+ TickSetting tickmarks() const { return ticks; }
+
+ virtual void setTickInterval( int );
+ int tickInterval() const { return tickInt; }
+
+ int minValue() const;
+ int maxValue() const;
+ void setMinValue( int );
+ void setMaxValue( int );
+ int lineStep() const;
+ int pageStep() const;
+ void setLineStep( int );
+ void setPageStep( int );
+ int value() const;
+
+public slots:
+ virtual void setValue( int );
+ void addStep();
+ void subtractStep();
+ void addLine();
+ void subtractLine();
+
+signals:
+ void valueChanged( int value );
+ void sliderPressed();
+ void sliderMoved( int value );
+ void sliderReleased();
+
+protected:
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+
+ void keyPressEvent( QKeyEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent * );
+#endif
+ void focusInEvent( QFocusEvent *e );
+ void focusOutEvent( QFocusEvent *e );
+
+ void styleChange( QStyle& );
+
+ void valueChange();
+ void rangeChange();
+
+private slots:
+ void repeatTimeout();
+
+private:
+ enum State { Idle, Dragging, TimingUp, TimingDown };
+
+ void init();
+ int positionFromValue( int ) const;
+ int valueFromPosition( int ) const;
+ void moveSlider( int );
+ void reallyMoveSlider( int );
+ void resetState();
+ int available() const;
+ int goodPart( const QPoint& ) const;
+ void initTicks();
+
+ QSliderPrivate *d;
+ QTimer *timer;
+ QCOORD sliderPos;
+ int sliderVal;
+ QCOORD clickOffset;
+ State state;
+ bool track;
+ QCOORD tickOffset;
+ TickSetting ticks;
+ int tickInt;
+ Orientation orient;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QSlider( const QSlider & );
+ QSlider &operator=( const QSlider & );
+#endif
+};
+
+inline bool QSlider::tracking() const
+{
+ return track;
+}
+
+inline QSlider::Orientation QSlider::orientation() const
+{
+ return orient;
+}
+
+inline int QSlider::sliderStart() const
+{
+ return sliderPos;
+}
+
+inline void QSlider::setSizePolicy( QSizePolicy::SizeType hor, QSizePolicy::SizeType ver, bool hfw )
+{
+ QWidget::setSizePolicy( hor, ver, hfw );
+}
+
+#endif // QT_NO_SLIDER
+
+#endif // QSLIDER_H
diff --git a/src/widgets/qspinbox.cpp b/src/widgets/qspinbox.cpp
new file mode 100644
index 0000000..76b5906
--- /dev/null
+++ b/src/widgets/qspinbox.cpp
@@ -0,0 +1,1116 @@
+/****************************************************************************
+**
+** Implementation of QSpinBox widget class
+**
+** Created : 970101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qspinbox.h"
+#ifndef QT_NO_SPINBOX
+
+#include "qcursor.h"
+#include "qpushbutton.h"
+#include "qpainter.h"
+#include "qbitmap.h"
+#include "qlineedit.h"
+#include "qvalidator.h"
+#include "qpixmapcache.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+static bool sumOutOfRange(int current, int add)
+{
+ if (add > 0 && INT_MAX - add < current) {
+ return true;
+ }
+ if (add < 0 && INT_MIN - add > current) {
+ return true;
+ }
+ return false;
+}
+
+class QSpinBoxPrivate
+{
+public:
+ QSpinBoxPrivate() {}
+ QSpinWidget* controls;
+ uint selreq : 1;
+};
+
+class QSpinBoxValidator : public QIntValidator
+{
+public:
+ QSpinBoxValidator( QSpinBox *sb, const char *name )
+ : QIntValidator( sb, name ), spinBox( sb ) { }
+
+ virtual State validate( QString& str, int& pos ) const;
+
+private:
+ QSpinBox *spinBox;
+};
+
+QValidator::State QSpinBoxValidator::validate( QString& str, int& pos ) const
+{
+ QString pref = spinBox->prefix();
+ QString suff = spinBox->suffix();
+ QString suffStriped = suff.stripWhiteSpace();
+ uint overhead = pref.length() + suff.length();
+ State state = Invalid;
+
+ ((QIntValidator *) this)->setRange( spinBox->minValue(),
+ spinBox->maxValue() );
+ if ( overhead == 0 ) {
+ state = QIntValidator::validate( str, pos );
+ } else {
+ bool stripedVersion = FALSE;
+ if ( str.length() >= overhead && str.startsWith(pref)
+ && (str.endsWith(suff)
+ || (stripedVersion = str.endsWith(suffStriped))) ) {
+ if ( stripedVersion )
+ overhead = pref.length() + suffStriped.length();
+ QString core = str.mid( pref.length(), str.length() - overhead );
+ int corePos = pos - pref.length();
+ state = QIntValidator::validate( core, corePos );
+ pos = corePos + pref.length();
+ str.replace( pref.length(), str.length() - overhead, core );
+ } else {
+ state = QIntValidator::validate( str, pos );
+ if ( state == Invalid ) {
+ // stripWhiteSpace(), cf. QSpinBox::interpretText()
+ QString special = spinBox->specialValueText().stripWhiteSpace();
+ QString candidate = str.stripWhiteSpace();
+
+ if ( special.startsWith(candidate) ) {
+ if ( candidate.length() == special.length() ) {
+ state = Acceptable;
+ } else {
+ state = Intermediate;
+ }
+ }
+ }
+ }
+ }
+ return state;
+}
+
+/*!
+ \class QSpinBox
+ \brief The QSpinBox class provides a spin box widget (spin button).
+
+ \ingroup basic
+ \mainclass
+
+ QSpinBox allows the user to choose a value either by clicking the
+ up/down buttons to increase/decrease the value currently displayed
+ or by typing the value directly into the spin box. If the value is
+ entered directly into the spin box, Enter (or Return) must be
+ pressed to apply the new value. The value is usually an integer.
+
+ Every time the value changes QSpinBox emits the valueChanged()
+ signal. The current value can be fetched with value() and set
+ with setValue().
+
+ The spin box keeps the value within a numeric range, and to
+ multiples of the lineStep() size (see QRangeControl for details).
+ 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 lineStep(). The minimum and maximum value and the
+ step size can be set using one of the constructors, and can be
+ changed later with setMinValue(), setMaxValue() and setLineStep().
+
+ 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. 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). currentValueText() returns
+ the spin box's current value as text.
+
+ Normally the spin box displays up and down arrows in the buttons.
+ You can use setButtonSymbols() to change the display to show
+ <b>+</b> and <b>-</b> symbols if you prefer. In either case the up
+ and down arrow keys work as expected.
+
+ 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.
+
+ The default \l QWidget::focusPolicy() is StrongFocus.
+
+ If using prefix(), suffix() and specialValueText() don't provide
+ enough control, you can ignore them and subclass QSpinBox instead.
+
+ QSpinBox can easily be subclassed to allow the user to input
+ things other than an integer value as long as the allowed input
+ can be mapped to a range of integers. This can be done by
+ overriding the virtual functions mapValueToText() and
+ mapTextToValue(), and setting another suitable validator using
+ setValidator().
+
+ For example, these functions could be changed so that the user
+ provided values from 0.0 to 10.0, or -1 to signify 'Auto', while
+ the range of integers used inside the program would be -1 to 100:
+
+ \code
+ class MySpinBox : public QSpinBox
+ {
+ Q_OBJECT
+ public:
+ ...
+
+ QString mapValueToText( int value )
+ {
+ if ( value == -1 ) // special case
+ return QString( "Auto" );
+
+ return QString( "%1.%2" ) // 0.0 to 10.0
+ .arg( value / 10 ).arg( value % 10 );
+ }
+
+ int mapTextToValue( bool *ok )
+ {
+ if ( text() == "Auto" ) // special case
+ return -1;
+
+ return (int) ( 10 * text().toFloat() ); // 0 to 100
+ }
+ };
+ \endcode
+
+ <img src=qspinbox-m.png> <img src=qspinbox-w.png>
+
+ \sa QScrollBar QSlider
+ \link guibooks.html#fowler GUI Design Handbook: Spin Box \endlink
+*/
+
+
+/*!
+ Constructs a spin box with the default QRangeControl range and
+ step values. It is called \a name and has parent \a parent.
+
+ \sa minValue(), maxValue(), setRange(), lineStep(), setSteps()
+*/
+
+QSpinBox::QSpinBox( QWidget * parent , const char *name )
+ : QWidget( parent, name, WNoAutoErase ),
+ QRangeControl()
+{
+ initSpinBox();
+}
+
+
+/*!
+ Constructs a spin box that allows values from \a minValue to \a
+ maxValue inclusive, with step amount \a step. The value is
+ initially set to \a minValue.
+
+ The spin box is called \a name and has parent \a parent.
+
+ \sa minValue(), maxValue(), setRange(), lineStep(), setSteps()
+*/
+
+QSpinBox::QSpinBox( int minValue, int maxValue, int step, QWidget* parent,
+ const char* name )
+ : QWidget( parent, name, WNoAutoErase ),
+ QRangeControl( minValue, maxValue, step, step, minValue )
+{
+ initSpinBox();
+}
+
+/*
+ \internal Initialization.
+*/
+
+void QSpinBox::initSpinBox()
+{
+ d = new QSpinBoxPrivate;
+
+ d->controls = new QSpinWidget( this, "controls" );
+ connect( d->controls, SIGNAL( stepUpPressed() ), SLOT( stepUp() ) );
+ connect( d->controls, SIGNAL( stepDownPressed() ), SLOT( stepDown() ) );
+
+ wrap = FALSE;
+ edited = FALSE;
+ d->selreq = FALSE;
+
+ validate = new QSpinBoxValidator( this, "validator" );
+ vi = new QLineEdit( this, "qt_spinbox_edit" );
+ d->controls->setEditWidget( vi );
+ vi->setValidator( validate );
+ vi->installEventFilter( this );
+ vi->setFrame( FALSE );
+ setFocusProxy( vi );
+
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+ setBackgroundMode( PaletteBackground, PaletteBase );
+
+ updateDisplay();
+
+ connect( vi, SIGNAL(textChanged(const QString&)), SLOT(textChanged()) );
+}
+
+/*!
+ Destroys the spin box, freeing all memory and other resources.
+*/
+
+QSpinBox::~QSpinBox()
+{
+ delete d;
+}
+
+
+/*!
+ \property QSpinBox::text
+ \brief the spin box's text, including any prefix() and suffix()
+
+ There is no default text.
+
+ \sa value()
+*/
+
+QString QSpinBox::text() const
+{
+ return vi->text();
+}
+
+
+
+/*!
+ \property QSpinBox::cleanText
+ \brief the spin box's text with no prefix(), suffix() or leading
+ or trailing whitespace.
+
+ \sa text, prefix, suffix
+*/
+
+QString QSpinBox::cleanText() const
+{
+ QString s = QString(text()).stripWhiteSpace();
+ if ( !prefix().isEmpty() ) {
+ QString px = QString(prefix()).stripWhiteSpace();
+ int len = px.length();
+ if ( len && s.left(len) == px ) // Remove _only_ if it is the prefix
+ s.remove( (uint)0, len );
+ }
+ if ( !suffix().isEmpty() ) {
+ QString sx = QString(suffix()).stripWhiteSpace();
+ int len = sx.length();
+ if ( len && s.right(len) == sx ) // Remove _only_ if it is the suffix
+ s.truncate( s.length() - len );
+ }
+ return s.stripWhiteSpace();
+}
+
+
+/*!
+ \property QSpinBox::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 minVal(). Typical use
+ is to indicate that this choice has a special (default) meaning.
+
+ For example, if your spin box allows the user to choose the margin
+ width in a print dialog and your application is able to
+ automatically choose a good margin width, you can set up the spin
+ box like this:
+ \code
+ QSpinBox marginBox( -1, 20, 1, parent, "marginBox" );
+ marginBox->setSuffix( " mm" );
+ marginBox->setSpecialValueText( "Auto" );
+ \endcode
+ The user will then be able to choose a margin width from 0-20
+ millimeters or select "Auto" to leave it to the application to
+ choose. Your code must then interpret the spin box value of -1 as
+ the user requesting automatic margin width.
+
+ All values are displayed with the prefix() and suffix() (if set),
+ \e except for the special value, which only shows the special
+ value text.
+
+ 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
+ QString::null.
+*/
+
+void QSpinBox::setSpecialValueText( const QString &text )
+{
+ specText = text;
+ updateDisplay();
+}
+
+
+QString QSpinBox::specialValueText() const
+{
+ if ( specText.isEmpty() )
+ return QString::null;
+ else
+ return specText;
+}
+
+
+/*!
+ \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:
+
+ \code
+ sb->setPrefix( "$" );
+ \endcode
+
+ To turn off the prefix display, set this property to an empty
+ string. The default is no prefix. The prefix is not displayed for
+ the minValue() if specialValueText() is not empty.
+
+ If no prefix is set, prefix() returns QString::null.
+
+ \sa suffix()
+*/
+
+void QSpinBox::setPrefix( const QString &text )
+{
+ pfix = text;
+ updateDisplay();
+}
+
+
+QString QSpinBox::prefix() const
+{
+ if ( pfix.isEmpty() )
+ return QString::null;
+ else
+ return pfix;
+}
+
+
+/*!
+ \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:
+
+ \code
+ sb->setSuffix( " km" );
+ \endcode
+
+ 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 minValue() if specialValueText() is not empty.
+
+ If no suffix is set, suffix() returns a QString::null.
+
+ \sa prefix()
+*/
+
+void QSpinBox::setSuffix( const QString &text )
+{
+ sfix = text;
+ updateDisplay();
+}
+
+QString QSpinBox::suffix() const
+{
+ if ( sfix.isEmpty() )
+ return QString::null;
+ else
+ return sfix;
+}
+
+
+/*!
+ \property QSpinBox::wrapping
+ \brief whether it is possible to step the value from the highest
+ value to the lowest value and vice versa
+
+ By default, wrapping is turned off.
+
+ If you have a range of 0..100 and wrapping is off when the user
+ reaches 100 and presses the Up Arrow nothing will happen; but if
+ wrapping is on the value will change from 100 to 0, then to 1,
+ etc. When wrapping is on, navigating past the highest value takes
+ you to the lowest and vice versa.
+
+ \sa minValue, maxValue, setRange()
+*/
+
+void QSpinBox::setWrapping( bool on )
+{
+ wrap = on;
+ updateDisplay();
+}
+
+bool QSpinBox::wrapping() const
+{
+ return wrap;
+}
+
+/*!
+ \reimp
+*/
+QSize QSpinBox::sizeHint() const
+{
+ constPolish();
+ QSize sz = vi->sizeHint();
+ int h = sz.height();
+ QFontMetrics fm( font() );
+ int w = 35;
+ int wx = fm.width( ' ' )*2;
+ QString s;
+ s = prefix() + ( (QSpinBox*)this )->mapValueToText( minValue() ) + suffix();
+ w = QMAX( w, fm.width( s ) + wx);
+ s = prefix() + ( (QSpinBox*)this )->mapValueToText( maxValue() ) + suffix();
+ w = QMAX(w, fm.width( s ) + wx );
+ if ( !specialValueText().isEmpty() ) {
+ s = specialValueText();
+ w = QMAX( w, fm.width( s ) + wx );
+ }
+ return style().sizeFromContents(QStyle::CT_SpinBox, this,
+ QSize( w + d->controls->downRect().width(),
+ h + style().pixelMetric( QStyle::PM_DefaultFrameWidth ) * 2).
+ expandedTo( QApplication::globalStrut() ));
+}
+
+
+/*!
+ \reimp
+*/
+QSize QSpinBox::minimumSizeHint() const
+{
+ int w = vi->minimumSizeHint().width() + d->controls->downRect().width();
+ int h = QMAX( vi->minimumSizeHint().height(), d->controls->minimumSizeHint().height() );
+ return QSize( w, h );
+}
+
+// Does the layout of the lineedit and the buttons
+
+void QSpinBox::arrangeWidgets()
+{
+ d->controls->arrange();
+}
+
+/*!
+ \property QSpinBox::value
+ \brief the value of the spin box
+
+ \sa QRangeControl::setValue()
+*/
+
+void QSpinBox::setValue( int value )
+{
+ edited = FALSE; // we ignore anything entered and not yet interpreted
+ QRangeControl::setValue( value );
+ updateDisplay();
+}
+
+int QSpinBox::value() const
+{
+ QSpinBox * that = (QSpinBox *) this;
+ if ( edited ) {
+ that->edited = FALSE; // avoid recursion
+ that->interpretText();
+ }
+ return QRangeControl::value();
+}
+
+
+/*!
+ Increases the spin box's value by one lineStep(), wrapping as
+ necessary if wrapping() is TRUE. This is the same as clicking on
+ the pointing-up button and can be used for keyboard accelerators,
+ for example.
+
+ \sa stepDown(), addLine(), lineStep(), setSteps(), setValue(), value()
+*/
+
+void QSpinBox::stepUp()
+{
+ if ( edited )
+ interpretText();
+ if ( wrapping() && ( value()+lineStep() > maxValue() || sumOutOfRange(value(), lineStep() ) ) ) {
+ setValue( minValue() );
+ } else {
+ addLine();
+ }
+}
+
+
+/*!
+ Decreases the spin box's value one lineStep(), wrapping as
+ necessary if wrapping() is TRUE. This is the same as clicking on
+ the pointing-down button and can be used for keyboard
+ accelerators, for example.
+
+ \sa stepUp(), subtractLine(), lineStep(), setSteps(), setValue(), value()
+*/
+
+void QSpinBox::stepDown()
+{
+ if ( edited )
+ interpretText();
+ if ( wrapping() && ( value()-lineStep() < minValue() || sumOutOfRange(value(), -lineStep() ) ) ) {
+ setValue( maxValue() );
+ } else {
+ subtractLine();
+ }
+}
+
+
+/*!
+ \fn void QSpinBox::valueChanged( int value )
+
+ This signal is emitted every time the value of the spin box
+ changes; the new value is passed in \a value. This signal will be
+ emitted as a result of a call to setValue(), or because the user
+ changed the value by using a keyboard accelerator or mouse click,
+ etc.
+
+ Note that the valueChanged() signal is emitted \e every time, not
+ just for the "last" step; i.e. if the user clicks "up" three
+ times, this signal is emitted three times.
+
+ \sa value()
+*/
+
+
+/*!
+ \fn void QSpinBox::valueChanged( const QString& valueText )
+
+ \overload
+
+ This signal is emitted whenever the valueChanged( int ) signal is
+ emitted, i.e. every time the value of the spin box changes
+ (whatever the cause, e.g. by setValue(), by a keyboard
+ accelerator, by mouse clicks, etc.).
+
+ The \a valueText parameter is the same string that is displayed in
+ the edit field of the spin box.
+
+ \sa value() prefix() suffix() specialValueText()
+*/
+
+
+
+/*!
+ Intercepts and handles the events coming to the embedded QLineEdit
+ that have special meaning for the QSpinBox. The object is passed
+ as \a o and the event is passed as \a ev.
+*/
+
+bool QSpinBox::eventFilter( QObject* o, QEvent* ev )
+{
+ if (o != vi)
+ return QWidget::eventFilter(o,ev);
+
+ if ( ev->type() == QEvent::KeyPress ) {
+ QKeyEvent* k = (QKeyEvent*)ev;
+
+ bool retval = FALSE; // workaround for MSVC++ optimization bug
+ if( (k->key() == Key_Tab) || (k->key() == Key_BackTab) ){
+ if ( k->state() & Qt::ControlButton )
+ return FALSE;
+ if ( edited )
+ interpretText();
+ qApp->sendEvent( this, ev );
+ retval = TRUE;
+ } if ( k->key() == Key_Up ) {
+ stepUp();
+ retval = TRUE;
+ } else if ( k->key() == Key_Down ) {
+ stepDown();
+ retval = TRUE;
+ } else if ( k->key() == Key_Enter || k->key() == Key_Return ) {
+ interpretText();
+ return FALSE;
+ }
+ if ( retval )
+ return retval;
+ } else if ( ev->type() == QEvent::FocusOut || ev->type() == QEvent::Hide ) {
+ if ( edited ) {
+ interpretText();
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/*!
+ \reimp
+ */
+void QSpinBox::setEnabled( bool enabled )
+{
+ QWidget::setEnabled( enabled );
+ updateDisplay();
+}
+
+/*!
+ \reimp
+*/
+void QSpinBox::leaveEvent( QEvent* )
+{
+}
+
+
+/*!
+ \reimp
+*/
+void QSpinBox::resizeEvent( QResizeEvent* )
+{
+ d->controls->resize( width(), height() );
+}
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QSpinBox::wheelEvent( QWheelEvent * e )
+{
+ e->accept();
+ static float offset = 0;
+ static QSpinBox* offset_owner = 0;
+ if (offset_owner != this) {
+ offset_owner = this;
+ offset = 0;
+ }
+ offset += -e->delta()/120;
+ if (QABS(offset) < 1)
+ return;
+ int ioff = int(offset);
+ int i;
+ for (i=0; i<QABS(ioff); i++)
+ offset > 0 ? stepDown() : stepUp();
+ offset -= ioff;
+}
+#endif
+
+/*!
+ This virtual function is called by QRangeControl whenever the
+ value has changed. The QSpinBox reimplementation updates the
+ display and emits the valueChanged() signals; if you need
+ additional processing, either reimplement this or connect to one
+ of the valueChanged() signals.
+*/
+
+void QSpinBox::valueChange()
+{
+ d->selreq = hasFocus();
+ updateDisplay();
+ d->selreq = FALSE;
+ emit valueChanged( value() );
+ emit valueChanged( currentValueText() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+}
+
+
+/*!
+ This virtual function is called by QRangeControl whenever the
+ range has changed. It adjusts the default validator and updates
+ the display; if you need additional processing, you can
+ reimplement this function.
+*/
+
+void QSpinBox::rangeChange()
+{
+ updateDisplay();
+}
+
+
+/*!
+ Sets the validator to \a v. The validator controls what keyboard
+ input is accepted when the user is editing in the value field. The
+ default is to use a suitable QIntValidator.
+
+ Use setValidator(0) to turn off input validation (entered input
+ will still be kept within the spin box's range).
+*/
+
+void QSpinBox::setValidator( const QValidator* v )
+{
+ if ( vi )
+ vi->setValidator( v );
+}
+
+
+/*!
+ Returns the validator that constrains editing for this spin box if
+ there is any; otherwise returns 0.
+
+ \sa setValidator() QValidator
+*/
+
+const QValidator * QSpinBox::validator() const
+{
+ return vi ? vi->validator() : 0;
+}
+
+/*!
+ Updates the contents of the embedded QLineEdit to reflect the
+ current value using mapValueToText(). Also enables/disables the
+ up/down push buttons accordingly.
+
+ \sa mapValueToText()
+*/
+void QSpinBox::updateDisplay()
+{
+ vi->setUpdatesEnabled( FALSE );
+ vi->setText( currentValueText() );
+ if ( d->selreq && isVisible() && ( hasFocus() || vi->hasFocus() ) ) {
+ selectAll();
+ } else {
+ if ( !suffix().isEmpty() && vi->text().endsWith(suffix()) )
+ vi->setCursorPosition( vi->text().length() - suffix().length() );
+ }
+ vi->setUpdatesEnabled( TRUE );
+ vi->repaint( FALSE ); // immediate repaint needed for some reason
+ edited = FALSE;
+
+ bool upEnabled = isEnabled() && ( wrapping() || value() < maxValue() );
+ bool downEnabled = isEnabled() && ( wrapping() || value() > minValue() );
+
+ d->controls->setUpEnabled( upEnabled );
+ d->controls->setDownEnabled( downEnabled );
+ vi->setEnabled( isEnabled() );
+ repaint( FALSE );
+}
+
+
+/*!
+ QSpinBox calls this after the user has manually edited the
+ contents of the spin box (i.e. by typing in the embedded
+ QLineEdit, rather than using the up/down buttons/keys).
+
+ The default implementation of this function interprets the new
+ text using mapTextToValue(). If mapTextToValue() is successful, it
+ changes the spin box's value; if not, the value is left unchanged.
+
+ \sa editor()
+*/
+
+void QSpinBox::interpretText()
+{
+ bool ok = TRUE;
+ bool done = FALSE;
+ int newVal = 0;
+ if ( !specialValueText().isEmpty() ) {
+ QString s = text().stripWhiteSpace();
+ QString t = specialValueText().stripWhiteSpace();
+ if ( s == t ) {
+ newVal = minValue();
+ done = TRUE;
+ }
+ }
+ if ( !done )
+ newVal = mapTextToValue( &ok );
+ if ( ok )
+ setValue( newVal );
+ updateDisplay(); // sometimes redundant
+}
+
+
+/*!
+ Returns the geometry of the "up" button.
+*/
+
+QRect QSpinBox::upRect() const
+{
+ return d->controls->upRect();
+}
+
+
+/*!
+ Returns the geometry of the "down" button.
+*/
+
+QRect QSpinBox::downRect() const
+{
+ return d->controls->downRect();
+}
+
+
+/*!
+ Returns a pointer to the embedded QLineEdit.
+*/
+
+QLineEdit* QSpinBox::editor() const
+{
+ return vi;
+}
+
+
+/*!
+ This slot is called whenever the user edits the spin box's text.
+*/
+
+void QSpinBox::textChanged()
+{
+ edited = TRUE; // this flag is cleared in updateDisplay()
+}
+
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ display value \a v. The default implementation returns a string
+ containing \a v printed in the standard way. Reimplementations may
+ return anything. (See the example in the detailed description.)
+
+ Note that Qt does not call this function for specialValueText()
+ and that neither prefix() nor suffix() are included in the return
+ value.
+
+ If you reimplement this, you may also need to reimplement
+ mapTextToValue().
+
+ \sa updateDisplay(), mapTextToValue()
+*/
+
+QString QSpinBox::mapValueToText( int v )
+{
+ QString s;
+ s.setNum( v );
+ return s;
+}
+
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ interpret text entered by the user as a value. The text is
+ available as text() and as cleanText(), and this function must
+ parse it if possible. If \a ok is not 0: if it parses the text
+ successfully, \a *ok is set to TRUE; otherwise \a *ok is set to
+ FALSE.
+
+ Subclasses that need to display spin box values in a non-numeric
+ way need to reimplement this function.
+
+ Note that Qt handles specialValueText() separately; this function
+ is only concerned with the other values.
+
+ The default implementation tries to interpret the text() as an
+ integer in the standard way and returns the integer value.
+
+ \sa interpretText(), mapValueToText()
+*/
+
+int QSpinBox::mapTextToValue( bool* ok )
+{
+ QString s = text();
+ int newVal = s.toInt( ok );
+ if ( !(*ok) && !( !prefix() && !suffix() ) ) {// Try removing any pre/suffix
+ s = cleanText();
+ newVal = s.toInt( ok );
+ }
+ return newVal;
+}
+
+
+/*!
+ Returns the full text calculated from the current value, including
+ any prefix and suffix. If there is special value text and the
+ value is minValue() the specialValueText() is returned.
+*/
+
+QString QSpinBox::currentValueText()
+{
+ QString s;
+ if ( (value() == minValue()) && !specialValueText().isEmpty() ) {
+ s = specialValueText();
+ } else {
+ s = prefix();
+ s.append( mapValueToText( value() ) );
+ s.append( suffix() );
+ }
+ return s;
+}
+
+/*!
+ \reimp
+*/
+
+void QSpinBox::styleChange( QStyle& old )
+{
+ arrangeWidgets();
+ QWidget::styleChange( old );
+}
+
+
+/*!
+ \enum QSpinBox::ButtonSymbols
+
+ This enum type determines what the buttons in a spin box show.
+
+ \value UpDownArrows the buttons show little arrows in the classic
+ style.
+
+ \value PlusMinus the buttons show <b>+</b> and <b>-</b> symbols.
+
+ \sa QSpinBox::buttonSymbols
+*/
+
+/*!
+ \property QSpinBox::buttonSymbols
+
+ \brief the current button symbol mode
+
+ The possible values can be either \c UpDownArrows or \c PlusMinus.
+ The default is \c UpDownArrows.
+
+ \sa ButtonSymbols
+*/
+
+void QSpinBox::setButtonSymbols( ButtonSymbols newSymbols )
+{
+ if ( buttonSymbols() == newSymbols )
+ return;
+
+ switch ( newSymbols ) {
+ case UpDownArrows:
+ d->controls->setButtonSymbols( QSpinWidget::UpDownArrows );
+ break;
+ case PlusMinus:
+ d->controls->setButtonSymbols( QSpinWidget::PlusMinus );
+ break;
+ }
+ // repaint( FALSE );
+}
+
+QSpinBox::ButtonSymbols QSpinBox::buttonSymbols() const
+{
+ switch( d->controls->buttonSymbols() ) {
+ case QSpinWidget::UpDownArrows:
+ return UpDownArrows;
+ case QSpinWidget::PlusMinus:
+ return PlusMinus;
+ }
+ return UpDownArrows;
+}
+
+/*!
+ \property QSpinBox::minValue
+
+ \brief the minimum value of the spin box
+
+ When setting this property, \l QSpinBox::maxValue is adjusted, if
+ necessary, to ensure that the range remains valid.
+
+ \sa setRange() setSpecialValueText()
+*/
+
+int QSpinBox::minValue() const
+{
+ return QRangeControl::minValue();
+}
+
+void QSpinBox::setMinValue( int minVal )
+{
+ QRangeControl::setMinValue( minVal );
+}
+
+/*!
+ \property QSpinBox::maxValue
+ \brief the maximum value of the spin box
+
+ When setting this property, \l QSpinBox::minValue is adjusted, if
+ necessary, to ensure that the range remains valid.
+
+ \sa setRange() setSpecialValueText()
+*/
+
+int QSpinBox::maxValue() const
+{
+ return QRangeControl::maxValue();
+}
+
+void QSpinBox::setMaxValue( int maxVal )
+{
+ QRangeControl::setMaxValue( maxVal );
+}
+
+/*!
+ \property QSpinBox::lineStep
+ \brief the line step
+
+ When the user uses the arrows to change the spin box's value the
+ value will be incremented/decremented by the amount of the line
+ step.
+
+ The setLineStep() function calls the virtual stepChange() function
+ if the new line step is different from the previous setting.
+
+ \sa QRangeControl::setSteps() setRange()
+*/
+
+int QSpinBox::lineStep() const
+{
+ return QRangeControl::lineStep();
+}
+
+void QSpinBox::setLineStep( int i )
+{
+ setSteps( i, pageStep() );
+}
+
+/*!
+ Selects all the text in the spin box's editor.
+*/
+
+void QSpinBox::selectAll()
+{
+ int overhead = prefix().length() + suffix().length();
+ if ( !overhead || currentValueText() == specialValueText() ) {
+ vi->selectAll();
+ } else {
+ vi->setSelection( prefix().length(), vi->text().length() - overhead );
+ }
+}
+
+#endif
diff --git a/src/widgets/qspinbox.h b/src/widgets/qspinbox.h
new file mode 100644
index 0000000..622537f
--- /dev/null
+++ b/src/widgets/qspinbox.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Definition of QSpinBox widget class
+**
+** Created : 970101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSPINBOX_H
+#define QSPINBOX_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qrangecontrol.h"
+#endif // QT_H
+
+#ifndef QT_NO_SPINBOX
+
+class QLineEdit;
+class QValidator;
+class QSpinBoxPrivate;
+
+class Q_EXPORT QSpinBox: public QWidget, public QRangeControl
+{
+ Q_OBJECT
+ Q_ENUMS( ButtonSymbols )
+ Q_PROPERTY( QString text READ text )
+ Q_PROPERTY( QString prefix READ prefix WRITE setPrefix )
+ Q_PROPERTY( QString suffix READ suffix WRITE setSuffix )
+ Q_PROPERTY( QString cleanText READ cleanText )
+ Q_PROPERTY( QString specialValueText READ specialValueText WRITE setSpecialValueText )
+ Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
+ Q_PROPERTY( ButtonSymbols buttonSymbols READ buttonSymbols WRITE setButtonSymbols )
+ Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( int minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( int lineStep READ lineStep WRITE setLineStep )
+ Q_PROPERTY( int value READ value WRITE setValue )
+
+public:
+ QSpinBox( QWidget* parent=0, const char* name=0 );
+ QSpinBox( int minValue, int maxValue, int step = 1,
+ QWidget* parent=0, const char* name=0 );
+ ~QSpinBox();
+
+ QString text() const;
+
+ virtual QString prefix() const;
+ virtual QString suffix() const;
+ virtual QString cleanText() const;
+
+ virtual void setSpecialValueText( const QString &text );
+ QString specialValueText() const;
+
+ virtual void setWrapping( bool on );
+ bool wrapping() const;
+
+ enum ButtonSymbols { UpDownArrows, PlusMinus };
+ virtual void setButtonSymbols( ButtonSymbols );
+ ButtonSymbols buttonSymbols() const;
+
+ virtual void setValidator( const QValidator* v );
+ const QValidator * validator() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ int minValue() const;
+ int maxValue() const;
+ void setMinValue( int );
+ void setMaxValue( int );
+ int lineStep() const;
+ void setLineStep( int );
+ int value() const;
+
+ QRect upRect() const;
+ QRect downRect() const;
+
+public slots:
+ virtual void setValue( int value );
+ virtual void setPrefix( const QString &text );
+ virtual void setSuffix( const QString &text );
+ virtual void stepUp();
+ virtual void stepDown();
+ virtual void setEnabled( bool enabled );
+ virtual void selectAll();
+
+signals:
+ void valueChanged( int value );
+ void valueChanged( const QString &valueText );
+
+protected:
+ virtual QString mapValueToText( int value );
+ virtual int mapTextToValue( bool* ok );
+ QString currentValueText();
+
+ virtual void updateDisplay();
+ virtual void interpretText();
+
+ QLineEdit* editor() const;
+
+ virtual void valueChange();
+ virtual void rangeChange();
+
+ bool eventFilter( QObject* obj, QEvent* ev );
+ void resizeEvent( QResizeEvent* ev );
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent( QWheelEvent * );
+#endif
+ void leaveEvent( QEvent* );
+
+ void styleChange( QStyle& );
+
+protected slots:
+ void textChanged();
+
+private:
+ void initSpinBox();
+ QSpinBoxPrivate* d;
+ QLineEdit* vi;
+ QValidator* validate;
+ QString pfix;
+ QString sfix;
+ QString specText;
+
+ uint wrap : 1;
+ uint edited : 1;
+
+ void arrangeWidgets();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QSpinBox( const QSpinBox& );
+ QSpinBox& operator=( const QSpinBox& );
+#endif
+
+};
+
+#endif // QT_NO_SPINBOX
+
+#endif // QSPINBOX_H
diff --git a/src/widgets/qspinwidget.cpp b/src/widgets/qspinwidget.cpp
new file mode 100644
index 0000000..427f710
--- /dev/null
+++ b/src/widgets/qspinwidget.cpp
@@ -0,0 +1,465 @@
+/****************************************************************************
+**
+** Implementation of QSpinWidget class
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qrangecontrol.h"
+
+#ifndef QT_NO_SPINWIDGET
+
+#include "qrect.h"
+#include "qtimer.h"
+#include "qstyle.h"
+#include "qpainter.h"
+
+class QSpinWidgetPrivate
+{
+public:
+ QSpinWidgetPrivate()
+ : upEnabled( TRUE ),
+ downEnabled( TRUE ),
+ theButton( 0 ),
+ buttonDown( 0 ),
+ timerUp( 0 ),
+ bsyms( QSpinWidget::UpDownArrows ),
+ ed ( 0 ) {}
+ uint upEnabled :1;
+ uint downEnabled :1;
+ uint theButton :2;
+ uint buttonDown :2;
+ uint timerUp : 1;
+ QRect up;
+ QRect down;
+ QTimer auRepTimer;
+ QSpinWidget::ButtonSymbols bsyms;
+ QWidget *ed;
+ void startTimer( int msec ) { auRepTimer.start( msec, TRUE ); }
+ void startTimer( bool up, int msec ) { timerUp = up; startTimer( msec ); }
+ void stopTimer() { auRepTimer.stop(); }
+};
+
+/*!
+
+ \class QSpinWidget qspinwidget.h
+ \brief The QSpinWidget class is an internal range control related class.
+
+ \internal
+
+ Constructs an empty range control widget with parent \a parent
+ called \a name.
+
+*/
+
+QSpinWidget::QSpinWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ d = new QSpinWidgetPrivate();
+ connect( &d->auRepTimer, SIGNAL( timeout() ), this, SLOT( timerDone() ) );
+ setFocusPolicy( StrongFocus );
+
+ arrange();
+ updateDisplay();
+}
+
+
+/*! Destroys the object and frees any allocated resources.
+
+*/
+
+QSpinWidget::~QSpinWidget()
+{
+ delete d;
+}
+
+/*! */
+QWidget * QSpinWidget::editWidget()
+{
+ return d->ed;
+}
+
+/*!
+ Sets the editing widget to \a w.
+*/
+void QSpinWidget::setEditWidget( QWidget * w )
+{
+ if ( w ) {
+ if (w->parentWidget() != this)
+ w->reparent( this, QPoint( 0, 0 ) );
+ setFocusProxy( w );
+ }
+ d->ed = w;
+ arrange();
+ updateDisplay();
+}
+
+/*! \reimp
+
+*/
+
+void QSpinWidget::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton ) {
+ d->stopTimer();
+ d->buttonDown = 0;
+ d->theButton = 0;
+ repaint( d->down.unite( d->up ), FALSE );
+ return;
+ }
+
+ uint oldButtonDown = d->buttonDown;
+
+ if ( d->down.contains( e->pos() ) && d->downEnabled )
+ d->buttonDown = 1;
+ else if ( d->up.contains( e->pos() ) && d->upEnabled )
+ d->buttonDown = 2;
+ else
+ d->buttonDown = 0;
+
+ d->theButton = d->buttonDown;
+ if ( oldButtonDown != d->buttonDown ) {
+ if ( !d->buttonDown ) {
+ repaint( d->down.unite( d->up ), FALSE );
+ } else if ( d->buttonDown & 1 ) {
+ repaint( d->down, FALSE );
+ stepDown();
+ d->startTimer( FALSE, 300 );
+ } else if ( d->buttonDown & 2 ) {
+ repaint( d->up, FALSE );
+ stepUp();
+ d->startTimer( TRUE, 300 );
+ }
+ }
+}
+
+/*!
+
+*/
+
+void QSpinWidget::arrange()
+{
+ d->up = QStyle::visualRect( style().querySubControlMetrics( QStyle::CC_SpinWidget, this,
+ QStyle::SC_SpinWidgetUp ), this );
+ d->down = QStyle::visualRect( style().querySubControlMetrics( QStyle::CC_SpinWidget, this,
+ QStyle::SC_SpinWidgetDown ), this );
+ if ( d->ed ) {
+ QRect r = QStyle::visualRect( style().querySubControlMetrics( QStyle::CC_SpinWidget, this,
+ QStyle::SC_SpinWidgetEditField ), this );
+ d->ed->setGeometry( r );
+ }
+}
+
+/*!
+
+*/
+
+void QSpinWidget::stepUp()
+{
+ emit stepUpPressed();
+}
+
+void QSpinWidget::resizeEvent( QResizeEvent* )
+{
+ arrange();
+}
+
+/*!
+
+*/
+
+void QSpinWidget::stepDown()
+{
+ emit stepDownPressed();
+}
+
+
+void QSpinWidget::timerDone()
+{
+ // we use a double timer to make it possible for users to do
+ // something with 0-timer on valueChanged.
+ QTimer::singleShot( 1, this, SLOT( timerDoneEx() ) );
+}
+
+void QSpinWidget::timerDoneEx()
+{
+ if ( !d->buttonDown )
+ return;
+ if ( d->timerUp )
+ stepUp();
+ else
+ stepDown();
+ d->startTimer( 100 );
+}
+
+
+void QSpinWidget::windowActivationChange( bool oldActive )
+{
+ //was active, but lost focus
+ if ( oldActive && d->buttonDown ) {
+ d->stopTimer();
+ d->buttonDown = 0;
+ d->theButton = 0;
+ }
+ QWidget::windowActivationChange( oldActive );
+}
+
+
+
+/*!
+ The event is passed in \a e.
+*/
+
+void QSpinWidget::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+
+ uint oldButtonDown = d->theButton;
+ d->theButton = 0;
+ if ( oldButtonDown != d->theButton ) {
+ if ( oldButtonDown & 1 )
+ repaint( d->down, FALSE );
+ else if ( oldButtonDown & 2 )
+ repaint( d->up, FALSE );
+ }
+ d->stopTimer();
+ d->buttonDown = 0;
+}
+
+
+/*!
+ The event is passed in \a e.
+*/
+
+void QSpinWidget::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !(e->state() & LeftButton ) )
+ return;
+
+ uint oldButtonDown = d->theButton;
+ if ( oldButtonDown & 1 && !d->down.contains( e->pos() ) ) {
+ d->stopTimer();
+ d->theButton = 0;
+ repaint( d->down, FALSE );
+ } else if ( oldButtonDown & 2 && !d->up.contains( e->pos() ) ) {
+ d->stopTimer();
+ d->theButton = 0;
+ repaint( d->up, FALSE );
+ } else if ( !oldButtonDown && d->up.contains( e->pos() ) && d->buttonDown & 2 ) {
+ d->startTimer( 500 );
+ d->theButton = 2;
+ repaint( d->up, FALSE );
+ } else if ( !oldButtonDown && d->down.contains( e->pos() ) && d->buttonDown & 1 ) {
+ d->startTimer( 500 );
+ d->theButton = 1;
+ repaint( d->down, FALSE );
+ }
+}
+
+
+/*!
+ The event is passed in \a e.
+*/
+#ifndef QT_NO_WHEELEVENT
+void QSpinWidget::wheelEvent( QWheelEvent *e )
+{
+ e->accept();
+ static float offset = 0;
+ static QSpinWidget* offset_owner = 0;
+ if ( offset_owner != this ) {
+ offset_owner = this;
+ offset = 0;
+ }
+ offset += -e->delta()/120;
+ if ( QABS( offset ) < 1 )
+ return;
+ int ioff = int(offset);
+ int i;
+ for( i=0; i < QABS( ioff ); i++ )
+ offset > 0 ? stepDown() : stepUp();
+ offset -= ioff;
+}
+#endif
+
+/*!
+
+*/
+void QSpinWidget::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus() || focusProxy() && focusProxy()->hasFocus())
+ flags |= QStyle::Style_HasFocus;
+
+ QStyle::SCFlags active;
+ if ( d->theButton & 1 )
+ active = QStyle::SC_SpinWidgetDown;
+ else if ( d->theButton & 2 )
+ active = QStyle::SC_SpinWidgetUp;
+ else
+ active = QStyle::SC_None;
+
+ QRect fr = QStyle::visualRect(
+ style().querySubControlMetrics( QStyle::CC_SpinWidget, this,
+ QStyle::SC_SpinWidgetFrame ), this );
+ style().drawComplexControl( QStyle::CC_SpinWidget, &p, this,
+ fr, colorGroup(),
+ flags,
+ (uint)QStyle::SC_All,
+ active );
+}
+
+
+/*!
+ The previous style is passed in \a old.
+*/
+
+void QSpinWidget::styleChange( QStyle& old )
+{
+ arrange();
+ QWidget::styleChange( old );
+}
+
+/*!
+*/
+
+QRect QSpinWidget::upRect() const
+{
+ return d->up;
+}
+
+/*!
+*/
+
+QRect QSpinWidget::downRect() const
+{
+ return d->down;
+}
+
+/*!
+*/
+
+void QSpinWidget::updateDisplay()
+{
+ if ( !isEnabled() ) {
+ d->upEnabled = FALSE;
+ d->downEnabled = FALSE;
+ }
+ if ( d->theButton & 1 && ( d->downEnabled ) == 0 ) {
+ d->theButton &= ~1;
+ d->buttonDown &= ~1;
+ }
+
+ if ( d->theButton & 2 && ( d->upEnabled ) == 0 ) {
+ d->theButton &= ~2;
+ d->buttonDown &= ~2;
+ }
+ repaint( FALSE );
+}
+
+
+/*!
+ The previous enabled state is passed in \a old.
+*/
+
+void QSpinWidget::enableChanged( bool )
+{
+ d->upEnabled = isEnabled();
+ d->downEnabled = isEnabled();
+ updateDisplay();
+}
+
+
+/*!
+ Sets up-enabled to \a on.
+*/
+
+void QSpinWidget::setUpEnabled( bool on )
+{
+ if ( (bool)d->upEnabled != on ) {
+ d->upEnabled = on;
+ updateDisplay();
+ }
+}
+
+/*!
+*/
+
+bool QSpinWidget::isUpEnabled() const
+{
+ return d->upEnabled;
+}
+
+/*!
+ Sets down-enabled to \a on.
+*/
+
+void QSpinWidget::setDownEnabled( bool on )
+{
+ if ( (bool)d->downEnabled != on ) {
+ d->downEnabled = on;
+ updateDisplay();
+ }
+}
+
+/*!
+*/
+
+bool QSpinWidget::isDownEnabled() const
+{
+ return d->downEnabled;
+}
+
+/*!
+ Sets the button symbol to \a bs.
+*/
+
+void QSpinWidget::setButtonSymbols( ButtonSymbols bs )
+{
+ d->bsyms = bs;
+}
+
+/*!
+*/
+
+QSpinWidget::ButtonSymbols QSpinWidget::buttonSymbols() const
+{
+ return d->bsyms;
+}
+
+#endif
diff --git a/src/widgets/qsplashscreen.cpp b/src/widgets/qsplashscreen.cpp
new file mode 100644
index 0000000..bb8687d
--- /dev/null
+++ b/src/widgets/qsplashscreen.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Definition of QSplashScreen class
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qsplashscreen.h"
+
+#ifndef QT_NO_SPLASHSCREEN
+
+#include "qapplication.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+
+class QSplashScreenPrivate
+{
+public:
+ QPixmap pixmap;
+ QString currStatus;
+ QColor currColor;
+ int currAlign;
+};
+
+/*!
+ \class QSplashScreen qsplashscreen.h
+ \brief The QSplashScreen widget provides a splash screen that can
+ be shown during application startup.
+
+ \ingroup misc
+ \mainclass
+
+ 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 centered on the screen. It may be useful to add
+ the \c WStyle_StaysOnTop if you desire to keep above all the windows in the
+ GUI.
+
+ 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.
+
+ \code
+ int main( int argc, char **argv )
+ {
+ QApplication app( argc, argv );
+ QPixmap pixmap( "splash.png" );
+ QSplashScreen *splash = new QSplashScreen( pixmap );
+ splash->show();
+ QMainWindow *mainWin = new QMainWindow;
+ ...
+ app.setMainWidget( mainWin );
+ mainWin->show();
+ splash->finish( mainWin );
+ delete splash;
+ return app.exec();
+ }
+ \endcode
+
+ It is sometimes useful to update the splash screen with messages,
+ for example, announcing connections established or modules loaded
+ as the application starts up. QSplashScreen supports this with the
+ message() 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().
+
+ 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.
+
+ \code
+ QPixmap pixmap( "splash.png" );
+ QSplashScreen *splash = new QSplashScreen( pixmap );
+ splash->show();
+ ... // Loading some items
+ splash->message( "Loaded modules" );
+ qApp->processEvents();
+ ... // Establishing connections
+ splash->message( "Established connections" );
+ qApp->processEvents();
+ \endcode
+
+*/
+
+/*!
+ Construct a splash screen that will display the \a pixmap.
+
+ There should be no need to set the widget flags, \a f, except
+ perhaps \c WDestructiveClose or \c WStyle_StaysOnTop.
+*/
+QSplashScreen::QSplashScreen( const QPixmap &pixmap, WFlags f )
+ : QWidget( 0, 0, WStyle_Customize | WStyle_Splash | f )
+{
+ d = new QSplashScreenPrivate();
+ d->pixmap = pixmap;
+ setPixmap( d->pixmap ); // Does an implicit repaint
+}
+
+/*!
+ Destructor.
+*/
+QSplashScreen::~QSplashScreen()
+{
+ delete d;
+}
+
+/*!
+ \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()
+{
+ drawContents();
+ 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 message(), clear()
+*/
+
+
+
+/*!
+ Draws the \a message text onto the splash screen with color \a
+ color and aligns the text according to the flags in \a alignment.
+
+ \sa Qt::AlignmentFlags clear()
+*/
+void QSplashScreen::message( const QString &message, int alignment,
+ const QColor &color )
+{
+ d->currStatus = message;
+ d->currAlign = alignment;
+ d->currColor = color;
+ emit messageChanged( d->currStatus );
+ repaint();
+}
+
+/*!
+ Removes the message being displayed on the splash screen
+
+ \sa message()
+ */
+void QSplashScreen::clear()
+{
+ d->currStatus = QString::null;
+ emit messageChanged( d->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_wait_for_window_manager( QWidget *mainWin );
+ qt_wait_for_window_manager( mainWin );
+#endif
+ }
+ close();
+}
+
+/*!
+ Sets the pixmap that will be used as the splash screen's image to
+ \a pixmap.
+*/
+void QSplashScreen::setPixmap( const QPixmap &pixmap )
+{
+ d->pixmap = pixmap;
+ QRect r(0, 0, d->pixmap.size().width(), d->pixmap.size().height());
+ resize( d->pixmap.size() );
+ move( QApplication::desktop()->screenGeometry().center() - r.center() );
+ repaint();
+}
+
+/*!
+ Returns the pixmap that is used in the splash screen. The image
+ does not have any of the text drawn by message() calls.
+*/
+QPixmap* QSplashScreen::pixmap() const
+{
+ return &( d->pixmap );
+}
+
+/*!
+ \internal
+*/
+void QSplashScreen::drawContents()
+{
+ QPixmap textPix = d->pixmap;
+ QPainter painter( &textPix, this );
+ drawContents( &painter );
+ setErasePixmap( textPix );
+}
+
+/*!
+ Draw the contents of the splash screen using painter \a painter.
+ The default implementation draws the message passed by message().
+ Reimplement this function if you want to do your own drawing on
+ the splash screen.
+*/
+void QSplashScreen::drawContents( QPainter *painter )
+{
+ painter->setPen( d->currColor );
+ QRect r = rect();
+ r.setRect( r.x() + 5, r.y() + 5, r.width() - 10, r.height() - 10 );
+ painter->drawText( r, d->currAlign, d->currStatus );
+}
+
+#endif //QT_NO_SPLASHSCREEN
diff --git a/src/widgets/qsplashscreen.h b/src/widgets/qsplashscreen.h
new file mode 100644
index 0000000..eb23a57
--- /dev/null
+++ b/src/widgets/qsplashscreen.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Definition of QSplashScreen class
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSPLASHSCREEN_H
+#define QSPLASHSCREEN_H
+
+#ifndef QT_H
+#include "qpixmap.h"
+#include "qwidget.h"
+#endif // QT_H
+
+#ifndef QT_NO_SPLASHSCREEN
+class QSplashScreenPrivate;
+
+class Q_EXPORT QSplashScreen : public QWidget
+{
+ Q_OBJECT
+public:
+ QSplashScreen( const QPixmap &pixmap = QPixmap(), WFlags f = 0 );
+ virtual ~QSplashScreen();
+
+ void setPixmap( const QPixmap &pixmap );
+ QPixmap* pixmap() const;
+ void finish( QWidget *w );
+ void repaint();
+
+public slots:
+ void message( const QString &str, int flags = AlignLeft,
+ const QColor &color = black );
+ void clear();
+
+signals:
+ void messageChanged( const QString &str );
+
+protected:
+ virtual void drawContents( QPainter *painter );
+ void mousePressEvent( QMouseEvent * );
+
+private:
+ void drawContents();
+
+ QSplashScreenPrivate *d;
+};
+#endif //QT_NO_SPLASHSCREEN
+#endif
diff --git a/src/widgets/qsplitter.cpp b/src/widgets/qsplitter.cpp
new file mode 100644
index 0000000..4810911
--- /dev/null
+++ b/src/widgets/qsplitter.cpp
@@ -0,0 +1,1429 @@
+/****************************************************************************
+**
+** Implementation of QSplitter class
+**
+** Created : 980105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qsplitter.h"
+#ifndef QT_NO_SPLITTER
+
+#include "qlayout.h"
+#include "../kernel/qlayoutengine_p.h"
+#include "qapplication.h"
+#include "qbitmap.h"
+#include "qdrawutil.h"
+#include "qmemarray.h"
+#include "qobjectlist.h"
+#include "qpainter.h"
+#include "qptrlist.h"
+#include "qstyle.h"
+
+class QSplitterHandle : public QWidget
+{
+ Q_OBJECT
+public:
+ QSplitterHandle( Orientation o,
+ QSplitter *parent, const char* name=0 );
+ void setOrientation( Orientation o );
+ Orientation orientation() const { return orient; }
+
+ bool opaque() const { return s->opaqueResize(); }
+
+ QSize sizeHint() const;
+
+ int id() const { return myId; } // d->list.at(id())->wid == this
+ void setId( int i ) { myId = i; }
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+
+private:
+ Orientation orient;
+ bool opaq;
+ int myId;
+
+ QSplitter *s;
+};
+
+#include "qsplitter.moc"
+
+const uint Default = 2;
+
+static int mouseOffset;
+static int opaqueOldPos = -1; // this assumes that there's only one mouse
+
+static QPoint toggle( QWidget *w, QPoint pos )
+{
+ QSize minS = qSmartMinSize( w );
+ return -pos - QPoint( minS.width(), minS.height() );
+}
+
+static bool isCollapsed( QWidget *w )
+{
+ return w->x() < 0 || w->y() < 0;
+}
+
+static QPoint topLeft( QWidget *w )
+{
+ if ( isCollapsed(w) ) {
+ return toggle( w, w->pos() );
+ } else {
+ return w->pos();
+ }
+}
+
+static QPoint bottomRight( QWidget *w )
+{
+ if ( isCollapsed(w) ) {
+ return toggle( w, w->pos() ) - QPoint( 1, 1 );
+ } else {
+ return w->geometry().bottomRight();
+ }
+}
+
+QSplitterHandle::QSplitterHandle( Orientation o, QSplitter *parent,
+ const char * name )
+ : QWidget( parent, name )
+{
+ s = parent;
+ setOrientation( o );
+}
+
+QSize QSplitterHandle::sizeHint() const
+{
+ int hw = s->handleWidth();
+ return parentWidget()->style().sizeFromContents( QStyle::CT_Splitter, s,
+ QSize(hw, hw) )
+ .expandedTo( QApplication::globalStrut() );
+}
+
+void QSplitterHandle::setOrientation( Orientation o )
+{
+ orient = o;
+#ifndef QT_NO_CURSOR
+ setCursor( o == QSplitter::Horizontal ? splitHCursor : splitVCursor );
+#endif
+}
+
+void QSplitterHandle::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !(e->state()&LeftButton) )
+ return;
+ QCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
+ - mouseOffset;
+ if ( opaque() ) {
+ s->moveSplitter( pos, id() );
+ } else {
+ s->setRubberband( s->adjustPos(pos, id()) );
+ }
+}
+
+void QSplitterHandle::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() == LeftButton )
+ mouseOffset = s->pick( e->pos() );
+}
+
+void QSplitterHandle::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !opaque() && e->button() == LeftButton ) {
+ QCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
+ - mouseOffset;
+ s->setRubberband( -1 );
+ s->moveSplitter( pos, id() );
+ }
+}
+
+void QSplitterHandle::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ parentWidget()->style().drawPrimitive( QStyle::PE_Splitter, &p, rect(),
+ colorGroup(),
+ (orientation() == Horizontal ?
+ QStyle::Style_Horizontal : 0) );
+}
+
+class QSplitterLayoutStruct : public Qt
+{
+public:
+ QCOORD sizer;
+ uint isHandle : 1;
+ uint collapsible : 2;
+ uint resizeMode : 2;
+ QWidget *wid;
+
+ QSplitterLayoutStruct()
+ : sizer( -1 ), collapsible( Default ) { }
+ QCOORD getSizer( Orientation orient );
+};
+
+QCOORD QSplitterLayoutStruct::getSizer( Orientation orient )
+{
+ if ( sizer == -1 ) {
+ QSize s = wid->sizeHint();
+ if ( !s.isValid() || wid->testWState(WState_Resized) )
+ s = wid->size();
+ sizer = ( orient == Horizontal ) ? s.width() : s.height();
+ }
+ return sizer;
+}
+
+class QSplitterPrivate
+{
+public:
+ QSplitterPrivate()
+ : opaque( FALSE ), firstShow( TRUE ), childrenCollapsible( TRUE ),
+ handleWidth( 0 ) { }
+
+ QPtrList<QSplitterLayoutStruct> list;
+ bool opaque : 8;
+ bool firstShow : 8;
+ bool childrenCollapsible : 8;
+ int handleWidth;
+};
+
+
+/*!
+ \class QSplitter
+ \brief The QSplitter class implements a splitter widget.
+
+ \ingroup organizers
+ \mainclass
+
+ 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.
+
+ To show a QListBox, a QListView and a QTextEdit side by side:
+ \code
+ QSplitter *split = new QSplitter( parent );
+ QListBox *lb = new QListBox( split );
+ QListView *lv = new QListView( split );
+ QTextEdit *ed = new QTextEdit( split );
+ \endcode
+
+ QSplitter lays out its children horizontally (side by side); you
+ can use setOrientation(QSplitter::Vertical) to lay out the
+ children 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. Use setResizeMode() to
+ specify that a widget should keep its size when the splitter is
+ resized, or set the stretch component of the \l sizePolicy.
+
+ Although QSplitter normally resizes the children only at the end
+ of a resize operation, if you call setOpaqueResize(TRUE) the
+ widgets are resized as often as possible.
+
+ The initial distribution of size between the widgets is determined
+ by the initial size of each widget. You can also use setSizes() to
+ set the sizes of all the widgets. The function sizes() returns the
+ sizes set by the user.
+
+ If you hide() a child its space will be distributed among the
+ other children. It will be reinstated when you show() it again. It
+ is also possible to reorder the widgets within the splitter using
+ moveToFirst() and moveToLast().
+
+ <img src=qsplitter-m.png> <img src=qsplitter-w.png>
+
+ \sa QTabBar
+*/
+
+
+/*!
+ Constructs a horizontal splitter with the \a parent and \a name
+ arguments being passed on to the QFrame constructor.
+*/
+
+QSplitter::QSplitter( QWidget *parent, const char *name )
+ : QFrame( parent, name, WPaintUnclipped )
+{
+ orient = Horizontal;
+ init();
+}
+
+
+/*!
+ Constructs a splitter with orientation \a o with the \a parent and
+ \a name arguments being passed on to the QFrame constructor.
+*/
+
+QSplitter::QSplitter( Orientation o, QWidget *parent, const char *name )
+ : QFrame( parent, name, WPaintUnclipped )
+{
+ orient = o;
+ init();
+}
+
+
+/*!
+ Destroys the splitter and any children.
+*/
+
+QSplitter::~QSplitter()
+{
+ delete d;
+}
+
+
+void QSplitter::init()
+{
+ d = new QSplitterPrivate;
+ d->list.setAutoDelete( TRUE );
+ QSizePolicy sp( QSizePolicy::Expanding, QSizePolicy::Preferred );
+ if ( orient == Vertical )
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+}
+
+/*!
+ \fn void QSplitter::refresh()
+
+ Updates the splitter's state. You should not need to call this
+ function.
+*/
+
+
+/*!
+ \property QSplitter::orientation
+ \brief the orientation of the splitter
+
+ By default the orientation is horizontal (the widgets are side by
+ side). The possible orientations are \c Horizontal and
+ \c Vertical.
+*/
+
+void QSplitter::setOrientation( Orientation o )
+{
+ if ( orient == o )
+ return;
+
+ if ( !testWState( WState_OwnSizePolicy ) ) {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+ clearWState( WState_OwnSizePolicy );
+ }
+
+ orient = o;
+
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->isHandle )
+ ((QSplitterHandle*)s->wid)->setOrientation( o );
+ s = d->list.next();
+ }
+ recalc( isVisible() );
+}
+
+/*!
+ \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; see
+ setCollapsible().
+*/
+
+void QSplitter::setChildrenCollapsible( bool collapse )
+{
+ d->childrenCollapsible = collapse;
+}
+
+bool QSplitter::childrenCollapsible() const
+{
+ return d->childrenCollapsible;
+}
+
+/*!
+ Sets whether the child widget \a w 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( QWidget *w, bool collapse )
+{
+ findWidget( w )->collapsible = collapse ? 1 : 0;
+}
+
+/*!
+ \reimp
+*/
+void QSplitter::resizeEvent( QResizeEvent * )
+{
+ doResize();
+}
+
+QSplitterLayoutStruct *QSplitter::findWidget( QWidget *w )
+{
+ processChildEvents();
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == w )
+ return s;
+ s = d->list.next();
+ }
+ return addWidget( w );
+}
+
+/*
+ Inserts the widget \a w at the end (or at the beginning if \a
+ prepend is TRUE) of the splitter's list of widgets.
+
+ It is the responsibility of the caller to make sure that \a w is
+ not already in the splitter and to call recalcId() if needed. (If
+ \a prepend is TRUE, then recalcId() is very probably needed.)
+*/
+
+QSplitterLayoutStruct *QSplitter::addWidget( QWidget *w, bool prepend )
+{
+ QSplitterLayoutStruct *s;
+ QSplitterHandle *newHandle = 0;
+ if ( d->list.count() > 0 ) {
+ s = new QSplitterLayoutStruct;
+ s->resizeMode = KeepSize;
+ QString tmp = "qt_splithandle_";
+ tmp += w->name();
+ newHandle = new QSplitterHandle( orientation(), this, tmp );
+ s->wid = newHandle;
+ newHandle->setId( d->list.count() );
+ s->isHandle = TRUE;
+ s->sizer = pick( newHandle->sizeHint() );
+ if ( prepend )
+ d->list.prepend( s );
+ else
+ d->list.append( s );
+ }
+ s = new QSplitterLayoutStruct;
+ s->resizeMode = DefaultResizeMode;
+ s->wid = w;
+ s->isHandle = FALSE;
+ if ( prepend )
+ d->list.prepend( s );
+ else
+ d->list.append( s );
+ if ( newHandle && isVisible() )
+ newHandle->show(); // will trigger sending of post events
+ return s;
+}
+
+
+/*!
+ Tells the splitter that the child widget described by \a c has
+ been inserted or removed.
+*/
+
+void QSplitter::childEvent( QChildEvent *c )
+{
+ if ( c->type() == QEvent::ChildInserted ) {
+ if ( !c->child()->isWidgetType() )
+ return;
+
+ if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
+ return;
+
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == c->child() )
+ return;
+ s = d->list.next();
+ }
+ addWidget( (QWidget*)c->child() );
+ recalc( isVisible() );
+ } else if ( c->type() == QEvent::ChildRemoved ) {
+ QSplitterLayoutStruct *prev = 0;
+ if ( d->list.count() > 1 )
+ prev = d->list.at( 1 ); // yes, this is correct
+ QSplitterLayoutStruct *curr = d->list.first();
+ while ( curr ) {
+ if ( curr->wid == c->child() ) {
+ d->list.removeRef( curr );
+ if ( prev && prev->isHandle ) {
+ QWidget *w = prev->wid;
+ d->list.removeRef( prev );
+ delete w; // will call childEvent()
+ }
+ recalcId();
+ doResize();
+ return;
+ }
+ prev = curr;
+ curr = d->list.next();
+ }
+ }
+}
+
+
+/*!
+ Displays a rubber band at position \a p. If \a p is negative, the
+ rubber band is removed.
+*/
+
+void QSplitter::setRubberband( int p )
+{
+ QPainter paint( this );
+ paint.setPen( gray );
+ paint.setBrush( gray );
+ paint.setRasterOp( XorROP );
+ QRect r = contentsRect();
+ const int rBord = 3; // customizable?
+ int hw = handleWidth();
+ if ( orient == Horizontal ) {
+ if ( opaqueOldPos >= 0 )
+ paint.drawRect( opaqueOldPos + hw / 2 - rBord, r.y(),
+ 2 * rBord, r.height() );
+ if ( p >= 0 )
+ paint.drawRect( p + hw / 2 - rBord, r.y(), 2 * rBord, r.height() );
+ } else {
+ if ( opaqueOldPos >= 0 )
+ paint.drawRect( r.x(), opaqueOldPos + hw / 2 - rBord,
+ r.width(), 2 * rBord );
+ if ( p >= 0 )
+ paint.drawRect( r.x(), p + hw / 2 - rBord, r.width(), 2 * rBord );
+ }
+ opaqueOldPos = p;
+}
+
+
+/*!
+ \reimp
+*/
+
+bool QSplitter::event( QEvent *e )
+{
+ switch ( e->type() ) {
+ case QEvent::Show:
+ if ( !d->firstShow )
+ break;
+ d->firstShow = FALSE;
+ // fall through
+ case QEvent::LayoutHint:
+ recalc( isVisible() );
+ break;
+ default:
+ ;
+ }
+ return QWidget::event( e );
+}
+
+
+/*!
+ \obsolete
+
+ Draws the splitter handle in the rectangle described by \a x, \a y,
+ \a w, \a h using painter \a p.
+ \sa QStyle::drawPrimitive()
+*/
+
+// ### Remove this in 4.0
+
+void QSplitter::drawSplitter( QPainter *p,
+ QCOORD x, QCOORD y, QCOORD w, QCOORD h )
+{
+ style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
+ (orientation() == Horizontal ?
+ QStyle::Style_Horizontal : 0));
+}
+
+
+/*!
+ Returns the ID of the widget to the right of or below the widget
+ \a w, or 0 if there is no such widget (i.e. it is either not in
+ this QSplitter or \a w is at the end).
+*/
+
+int QSplitter::idAfter( QWidget* w ) const
+{
+ QSplitterLayoutStruct *s = d->list.first();
+ bool seen_w = FALSE;
+ while ( s ) {
+ if ( s->isHandle && seen_w )
+ return d->list.at();
+ if ( !s->isHandle && s->wid == w )
+ seen_w = TRUE;
+ s = d->list.next();
+ }
+ return 0;
+}
+
+
+/*!
+ Moves the left/top edge of the splitter handle with ID \a id as
+ close as possible to position \a p, which is the distance from the
+ left (or top) edge of the widget.
+
+ For Arabic, Hebrew and other right-to-left languages the layout is
+ reversed. \a p is then the distance from the right (or top) edge
+ of the widget.
+
+ \sa idAfter()
+*/
+void QSplitter::moveSplitter( QCOORD p, int id )
+{
+ QSplitterLayoutStruct *s = d->list.at( id );
+ int farMin;
+ int min;
+ int max;
+ int farMax;
+
+ p = adjustPos( p, id, &farMin, &min, &max, &farMax );
+ int oldP = pick( s->wid->pos() );
+
+ if ( QApplication::reverseLayout() && orient == Horizontal ) {
+ int q = p + s->wid->width();
+ doMove( FALSE, q, id - 1, -1, (q > oldP), (p > max) );
+ doMove( TRUE, q, id, -1, (q > oldP), (p < min) );
+ } else {
+ doMove( FALSE, p, id, +1, (p < oldP), (p > max) );
+ doMove( TRUE, p, id - 1, +1, (p < oldP), (p < min) );
+ }
+ storeSizes();
+}
+
+
+void QSplitter::setGeo( QWidget *w, int p, int s, bool splitterMoved )
+{
+ QRect r;
+ if ( orient == Horizontal ) {
+ if ( QApplication::reverseLayout() && orient == Horizontal
+ && !splitterMoved )
+ p = contentsRect().width() - p - s;
+ r.setRect( p, contentsRect().y(), s, contentsRect().height() );
+ } else {
+ r.setRect( contentsRect().x(), p, contentsRect().width(), s );
+ }
+
+ /*
+ Hide the child widget, but without calling hide() so that the
+ splitter handle is still shown.
+ */
+ if ( !w->isHidden() && s <= 0 && pick(qSmartMinSize(w)) > 0 )
+ r.moveTopLeft( toggle(w, r.topLeft()) );
+ w->setGeometry( r );
+}
+
+
+void QSplitter::doMove( bool backwards, int pos, int id, int delta, bool upLeft,
+ bool mayCollapse )
+{
+ if ( id < 0 || id >= (int) d->list.count() )
+ return;
+
+ QSplitterLayoutStruct *s = d->list.at( id );
+ QWidget *w = s->wid;
+
+ int nextId = backwards ? id - delta : id + delta;
+
+ if ( w->isHidden() ) {
+ doMove( backwards, pos, nextId, delta, upLeft, TRUE );
+ } else {
+ if ( s->isHandle ) {
+ int dd = s->getSizer( orient );
+ int nextPos = backwards ? pos - dd : pos + dd;
+ int left = backwards ? pos - dd : pos;
+ setGeo( w, left, dd, TRUE );
+ doMove( backwards, nextPos, nextId, delta, upLeft, mayCollapse );
+ } else {
+ int dd = backwards ? pos - pick( topLeft(w) )
+ : pick( bottomRight(w) ) - pos + 1;
+ if ( dd > 0 || (!isCollapsed(w) && !mayCollapse) ) {
+ dd = QMAX( pick(qSmartMinSize(w)),
+ QMIN(dd, pick(w->maximumSize())) );
+ } else {
+ dd = 0;
+ }
+ setGeo( w, backwards ? pos - dd : pos, dd, TRUE );
+ doMove( backwards, backwards ? pos - dd : pos + dd, nextId, delta,
+ upLeft, TRUE );
+ }
+ }
+}
+
+int QSplitter::findWidgetJustBeforeOrJustAfter( int id, int delta, int &collapsibleSize )
+{
+ id += delta;
+ do {
+ QWidget *w = d->list.at( id )->wid;
+ if ( !w->isHidden() ) {
+ if ( collapsible(d->list.at(id)) )
+ collapsibleSize = pick( qSmartMinSize(w) );
+ return id;
+ }
+ id += 2 * delta; // go to previous (or next) widget, skip the handle
+ } while ( id >= 0 && id < (int)d->list.count() );
+
+ return -1;
+}
+
+void QSplitter::getRange( int id, int *farMin, int *min, int *max, int *farMax )
+{
+ int n = d->list.count();
+ if ( id <= 0 || id >= n - 1 )
+ return;
+
+ int collapsibleSizeBefore = 0;
+ int idJustBefore = findWidgetJustBeforeOrJustAfter( id, -1, collapsibleSizeBefore );
+
+ int collapsibleSizeAfter = 0;
+ int idJustAfter = findWidgetJustBeforeOrJustAfter( id, +1, collapsibleSizeAfter );
+
+ int minBefore = 0;
+ int minAfter = 0;
+ int maxBefore = 0;
+ int maxAfter = 0;
+ int i;
+
+ for ( i = 0; i < id; i++ )
+ addContribution( i, &minBefore, &maxBefore, i == idJustBefore );
+ for ( i = id; i < n; i++ )
+ addContribution( i, &minAfter, &maxAfter, i == idJustAfter );
+
+ QRect r = 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 );
+
+ if ( orient == Vertical || !QApplication::reverseLayout() ) {
+ 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;
+ } else {
+ int hw = handleWidth();
+ minVal = r.width() - smartMaxBefore - hw;
+ maxVal = r.width() - smartMinBefore - hw;
+
+ farMinVal = minVal;
+ if ( pick(r.size()) - (minAfter - collapsibleSizeAfter) <= maxBefore )
+ farMinVal -= collapsibleSizeAfter;
+ farMaxVal = maxVal;
+ if ( minBefore - collapsibleSizeBefore >= pick(r.size()) - maxAfter )
+ farMaxVal += collapsibleSizeBefore;
+ }
+
+ if ( farMin )
+ *farMin = farMinVal;
+ if ( min )
+ *min = minVal;
+ if ( max )
+ *max = maxVal;
+ if ( farMax )
+ *farMax = farMaxVal;
+}
+
+/*!
+ Returns the valid range of the splitter with ID \a id in \a *min
+ and \a *max if \a min and \a max are not 0.
+
+ \sa idAfter()
+*/
+
+void QSplitter::getRange( int id, int *min, int *max )
+{
+ getRange( id, min, 0, 0, max );
+}
+
+
+/*!
+ Returns the closest legal position to \a pos of the widget with ID
+ \a id.
+
+ \sa idAfter()
+*/
+
+int QSplitter::adjustPos( int pos, int id )
+{
+ int x, i, n, u;
+ return adjustPos( pos, id, &u, &n, &i, &x );
+}
+
+int QSplitter::adjustPos( int pos, int id, int *farMin, int *min, int *max,
+ int *farMax )
+{
+ const int Threshold = 40;
+
+ getRange( id, 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 QSplitter::collapsible( QSplitterLayoutStruct *s )
+{
+ if (pick(qSmartMinSize(s->wid)) == 1)
+ return FALSE;
+ if ( s->collapsible != Default ) {
+ return (bool) s->collapsible;
+ } else {
+ return d->childrenCollapsible;
+ }
+}
+
+void QSplitter::doResize()
+{
+ QRect r = contentsRect();
+ int n = d->list.count();
+ QMemArray<QLayoutStruct> a( n );
+
+ for ( int pass = 0; pass < 2; pass++ ) {
+ int numAutoWithStretch = 0;
+ int numAutoWithoutStretch = 0;
+
+ for ( int i = 0; i < n; i++ ) {
+ a[i].init();
+ QSplitterLayoutStruct *s = d->list.at( i );
+ if ( s->wid->isHidden() || isCollapsed(s->wid) ) {
+ a[i].maximumSize = 0;
+ } else if ( s->isHandle ) {
+ a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
+ a[i].empty = FALSE;
+ } else {
+ int mode = s->resizeMode;
+ int stretch = 1;
+
+ if ( mode == DefaultResizeMode ) {
+ QSizePolicy p = s->wid->sizePolicy();
+ int sizePolicyStretch =
+ pick( QSize(p.horStretch(), p.verStretch()) );
+ if ( sizePolicyStretch > 0 ) {
+ mode = Stretch;
+ stretch = sizePolicyStretch;
+ numAutoWithStretch++;
+ } else {
+ /*
+ Do things differently on the second pass,
+ if there's one. A second pass is necessary
+ if it was found out during the first pass
+ that all DefaultResizeMode items are
+ KeepSize items. In that case, we make them
+ all Stretch items instead, for a more Qt
+ 3.0-compatible behavior.
+ */
+ mode = ( pass == 0 ) ? KeepSize : Stretch;
+ numAutoWithoutStretch++;
+ }
+ }
+
+ a[i].minimumSize = pick( qSmartMinSize(s->wid) );
+ a[i].maximumSize = pick( s->wid->maximumSize() );
+ a[i].empty = FALSE;
+
+ if ( mode == Stretch ) {
+ if ( s->getSizer(orient) > 1 )
+ stretch *= s->getSizer( orient );
+ // QMIN(): ad hoc work-around for layout engine limitation
+ a[i].stretch = QMIN( stretch, 8192 );
+ a[i].sizeHint = a[i].minimumSize;
+ } else if ( mode == KeepSize ) {
+ a[i].sizeHint = s->getSizer( orient );
+ } else { // mode == FollowSizeHint
+ a[i].sizeHint = pick( s->wid->sizeHint() );
+ }
+ }
+ }
+
+ // a second pass would yield the same results
+ if ( numAutoWithStretch > 0 || numAutoWithoutStretch == 0 )
+ break;
+ }
+
+ qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
+
+ for ( int i = 0; i < n; i++ ) {
+ QSplitterLayoutStruct *s = d->list.at(i);
+ setGeo( s->wid, a[i].pos, a[i].size, FALSE );
+ }
+}
+
+void QSplitter::recalc( bool update )
+{
+ int fi = 2 * frameWidth();
+ int maxl = fi;
+ int minl = fi;
+ int maxt = QWIDGETSIZE_MAX;
+ int mint = fi;
+ int n = d->list.count();
+ bool first = TRUE;
+
+ /*
+ Splitter handles before the first visible widget or right
+ before a hidden widget must be hidden.
+ */
+ for ( int i = 0; i < n; i++ ) {
+ QSplitterLayoutStruct *s = d->list.at( i );
+ if ( !s->isHandle ) {
+ QSplitterLayoutStruct *p = 0;
+ if ( i > 0 )
+ p = d->list.at( i - 1 );
+
+ // may trigger new recalc
+ if ( p && p->isHandle )
+ p->wid->setHidden( first || s->wid->isHidden() );
+
+ if ( !s->wid->isHidden() )
+ first = FALSE;
+ }
+ }
+
+ bool empty = TRUE;
+ for ( int j = 0; j < n; j++ ) {
+ QSplitterLayoutStruct *s = d->list.at( j );
+ if ( !s->wid->isHidden() ) {
+ empty = FALSE;
+ if ( s->isHandle ) {
+ minl += s->getSizer( orient );
+ maxl += s->getSizer( orient );
+ } else {
+ QSize minS = qSmartMinSize( s->wid );
+ minl += pick( minS );
+ maxl += pick( s->wid->maximumSize() );
+ mint = QMAX( mint, trans(minS) );
+ int tm = trans( s->wid->maximumSize() );
+ if ( tm > 0 )
+ maxt = QMIN( maxt, tm );
+ }
+ }
+ }
+ if ( empty ) {
+ if ( ::qt_cast<QSplitter*>(parentWidget()) ) {
+ // nested splitters; be nice
+ maxl = maxt = 0;
+ } else {
+ // QSplitter with no children yet
+ maxl = QWIDGETSIZE_MAX;
+ }
+ } else {
+ maxl = QMIN( maxl, QWIDGETSIZE_MAX );
+ }
+ if ( maxt < mint )
+ maxt = mint;
+
+ if ( orient == Horizontal ) {
+ setMaximumSize( maxl, maxt );
+ setMinimumSize( minl, mint );
+ } else {
+ setMaximumSize( maxt, maxl );
+ setMinimumSize( mint, minl );
+ }
+ if ( update )
+ doResize();
+ else
+ d->firstShow = TRUE;
+}
+
+/*!
+ \enum QSplitter::ResizeMode
+
+ This enum type describes how QSplitter will resize each of its
+ child widgets.
+
+ \value Auto The widget will be resized according to the stretch
+ factors set in its sizePolicy().
+
+ \value Stretch The widget will be resized when the splitter
+ itself is resized.
+
+ \value KeepSize QSplitter will try to keep the widget's size
+ unchanged.
+
+ \value FollowSizeHint QSplitter will resize the widget when the
+ widget's size hint changes.
+*/
+
+/*!
+ Sets resize mode of widget \a w to \a mode. (The default is \c
+ Auto.)
+*/
+
+void QSplitter::setResizeMode( QWidget *w, ResizeMode mode )
+{
+ findWidget( w )->resizeMode = mode;
+}
+
+
+/*!
+ \property QSplitter::opaqueResize
+ \brief whether resizing is opaque
+
+ Opaque resizing is off by default.
+*/
+
+bool QSplitter::opaqueResize() const
+{
+ return d->opaque;
+}
+
+
+void QSplitter::setOpaqueResize( bool on )
+{
+ d->opaque = on;
+}
+
+
+/*!
+ Moves widget \a w to the leftmost/top position.
+*/
+
+void QSplitter::moveToFirst( QWidget *w )
+{
+ processChildEvents();
+ bool found = FALSE;
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == w ) {
+ found = TRUE;
+ QSplitterLayoutStruct *p = d->list.prev();
+ if ( p ) { // not already at first place
+ d->list.take(); // take p
+ d->list.take(); // take s
+ d->list.prepend( p );
+ d->list.prepend( s );
+ }
+ break;
+ }
+ s = d->list.next();
+ }
+ if ( !found )
+ addWidget( w, TRUE );
+ recalcId();
+}
+
+
+/*!
+ Moves widget \a w to the rightmost/bottom position.
+*/
+
+void QSplitter::moveToLast( QWidget *w )
+{
+ processChildEvents();
+ bool found = FALSE;
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == w ) {
+ found = TRUE;
+ d->list.take(); // take s
+ QSplitterLayoutStruct *p = d->list.current();
+ if ( p ) { // the splitter handle after s
+ d->list.take(); // take p
+ d->list.append( p );
+ }
+ d->list.append( s );
+ break;
+ }
+ s = d->list.next();
+ }
+ if ( !found )
+ addWidget( w );
+ recalcId();
+}
+
+
+void QSplitter::recalcId()
+{
+ int n = d->list.count();
+ for ( int i = 0; i < n; i++ ) {
+ QSplitterLayoutStruct *s = d->list.at( i );
+ if ( s->isHandle )
+ ((QSplitterHandle*)s->wid)->setId( i );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+QSize QSplitter::sizeHint() const
+{
+ constPolish();
+ int l = 0;
+ int t = 0;
+ if ( children() ) {
+ const QObjectList * c = children();
+ QObjectListIt it( *c );
+ QObject * o;
+
+ while( (o = it.current()) != 0 ) {
+ ++it;
+ if ( o->isWidgetType() && !((QWidget*)o)->isHidden() ) {
+ QSize s = ((QWidget*)o)->sizeHint();
+ if ( s.isValid() ) {
+ l += pick( s );
+ t = QMAX( t, trans( s ) );
+ }
+ }
+ }
+ }
+ return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize QSplitter::minimumSizeHint() const
+{
+ constPolish();
+ int l = 0;
+ int t = 0;
+ if ( children() ) {
+ const QObjectList * c = children();
+ QObjectListIt it( *c );
+ QObject * o;
+
+ while ( (o = it.current()) != 0 ) {
+ ++it;
+ if ( o->isWidgetType() && !((QWidget*)o)->isHidden() ) {
+ QSize s = qSmartMinSize( (QWidget*)o );
+ if ( s.isValid() ) {
+ l += pick( s );
+ t = QMAX( t, trans( s ) );
+ }
+ }
+ }
+ }
+ return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
+}
+
+
+void QSplitter::storeSizes()
+{
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( !s->isHandle )
+ s->sizer = pick( s->wid->size() );
+ s = d->list.next();
+ }
+}
+
+
+void QSplitter::addContribution( int id, int *min, int *max,
+ bool mayCollapse )
+{
+ QSplitterLayoutStruct *s = d->list.at( id );
+ if ( !s->wid->isHidden() ) {
+ if ( s->isHandle ) {
+ *min += s->getSizer( orient );
+ *max += s->getSizer( orient );
+ } else {
+ if ( mayCollapse || !isCollapsed(s->wid) )
+ *min += pick( qSmartMinSize(s->wid) );
+ *max += pick( s->wid->maximumSize() );
+ }
+ }
+}
+
+
+/*!
+ Returns a list of the size parameters of all the widgets in this
+ splitter.
+
+ If the splitter's orientation is horizontal, the list is a list of
+ widget widths; if the orientation is vertical, the list is a list
+ of widget heights.
+
+ Giving the values to another splitter's setSizes() function will
+ produce a splitter with the same layout as this one.
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \code
+ QValueList<int> list = mySplitter.sizes();
+ QValueList<int>::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+
+ \sa setSizes()
+*/
+
+QValueList<int> QSplitter::sizes() const
+{
+ if ( !testWState(WState_Polished) )
+ constPolish();
+
+ QValueList<int> list;
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( !s->isHandle )
+ list.append( isCollapsed(s->wid) ? 0 : pick(s->wid->size()));
+ s = d->list.next();
+ }
+ return list;
+}
+
+/*!
+ Sets the size parameters to the values given in the \a list. If
+ the splitter is horizontal, the values set the widths of each
+ widget going from left to right. If the splitter is vertical, the
+ values set the heights of each widget going 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.
+
+ Note that the values in \a list should be the height/width that
+ the widgets should be resized to.
+
+ \sa sizes()
+*/
+
+void QSplitter::setSizes( QValueList<int> list )
+{
+ processChildEvents();
+ QValueList<int>::Iterator it = list.begin();
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s && it != list.end() ) {
+ if ( !s->isHandle ) {
+ s->sizer = QMAX( *it, 0 );
+ int smartMinSize = pick( qSmartMinSize(s->wid) );
+ // Make sure that we reset the collapsed state.
+ if ( s->sizer == 0 ) {
+ if ( collapsible(s) && smartMinSize > 0 ) {
+ s->wid->move( -1, -1 );
+ } else {
+ s->sizer = smartMinSize;
+ s->wid->move( 0, 0 );
+ }
+ } else {
+ if ( s->sizer < smartMinSize )
+ s->sizer = smartMinSize;
+ s->wid->move( 0, 0 );
+ }
+ ++it;
+ }
+ s = d->list.next();
+ }
+ doResize();
+}
+
+/*!
+ \property QSplitter::handleWidth
+ \brief the width of the splitter handle
+*/
+
+int QSplitter::handleWidth() const
+{
+ if ( d->handleWidth > 0 ) {
+ return d->handleWidth;
+ } else {
+ return style().pixelMetric( QStyle::PM_SplitterWidth, this );
+ }
+}
+
+void QSplitter::setHandleWidth( int width )
+{
+ d->handleWidth = width;
+ updateHandles();
+}
+
+/*!
+ Processes all posted child events, ensuring that the internal state of
+ the splitter is kept consistent.
+*/
+
+void QSplitter::processChildEvents()
+{
+ QApplication::sendPostedEvents( this, QEvent::ChildInserted );
+}
+
+/*!
+ \reimp
+*/
+
+void QSplitter::styleChange( QStyle& old )
+{
+ updateHandles();
+ QFrame::styleChange( old );
+}
+
+void QSplitter::updateHandles()
+{
+ int hw = handleWidth();
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->isHandle )
+ s->sizer = hw;
+ s = d->list.next();
+ }
+ recalc( isVisible() );
+}
+
+#ifndef QT_NO_TEXTSTREAM
+/*!
+ \relates QSplitter
+
+ Writes the sizes and the hidden state of the widgets in the
+ splitter \a splitter to the text stream \a ts.
+
+ \sa operator>>(), sizes(), QWidget::isHidden()
+*/
+
+QTextStream& operator<<( QTextStream& ts, const QSplitter& splitter )
+{
+ QSplitterLayoutStruct *s = splitter.d->list.first();
+ bool first = TRUE;
+ ts << "[";
+
+ while ( s != 0 ) {
+ if ( !s->isHandle ) {
+ if ( !first )
+ ts << ",";
+
+ if ( s->wid->isHidden() ) {
+ ts << "H";
+ } else if ( isCollapsed(s->wid) ) {
+ ts << 0;
+ } else {
+ ts << s->getSizer( splitter.orientation() );
+ }
+ first = FALSE;
+ }
+ s = splitter.d->list.next();
+ }
+ ts << "]" << endl;
+ return ts;
+}
+
+/*!
+ \relates QSplitter
+
+ Reads the sizes and the hidden state of the widgets in the
+ splitter \a splitter from the text stream \a ts. The sizes must
+ have been previously written by the operator<<() function.
+
+ \sa operator<<(), setSizes(), QWidget::hide()
+*/
+
+QTextStream& operator>>( QTextStream& ts, QSplitter& splitter )
+{
+#undef SKIP_SPACES
+#define SKIP_SPACES() \
+ while ( line[i].isSpace() ) \
+ i++
+
+ splitter.processChildEvents();
+ QSplitterLayoutStruct *s = splitter.d->list.first();
+ QString line = ts.readLine();
+ int i = 0;
+
+ SKIP_SPACES();
+ if ( line[i] == '[' ) {
+ i++;
+ SKIP_SPACES();
+ while ( line[i] != ']' ) {
+ while ( s != 0 && s->isHandle )
+ s = splitter.d->list.next();
+ if ( s == 0 )
+ break;
+
+ if ( line[i].upper() == 'H' ) {
+ s->wid->hide();
+ i++;
+ } else {
+ s->wid->show();
+ int dim = 0;
+ while ( line[i].digitValue() >= 0 ) {
+ dim *= 10;
+ dim += line[i].digitValue();
+ i++;
+ }
+ s->sizer = dim;
+ if ( dim == 0 )
+ splitter.setGeo( s->wid, 0, 0, FALSE );
+ }
+ SKIP_SPACES();
+ if ( line[i] == ',' ) {
+ i++;
+ } else {
+ break;
+ }
+ SKIP_SPACES();
+ s = splitter.d->list.next();
+ }
+ }
+ splitter.doResize();
+ return ts;
+}
+#endif
+
+#endif
diff --git a/src/widgets/qsplitter.h b/src/widgets/qsplitter.h
new file mode 100644
index 0000000..97b95ad
--- /dev/null
+++ b/src/widgets/qsplitter.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Definition of QSplitter class
+**
+** Created : 980105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSPLITTER_H
+#define QSPLITTER_H
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qvaluelist.h"
+#endif // QT_H
+
+#ifndef QT_NO_SPLITTER
+
+class QSplitterHandle;
+class QSplitterPrivate;
+class QSplitterLayoutStruct;
+class QTextStream;
+
+class Q_EXPORT QSplitter : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( 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:
+ // ### Qt 4.0: remove Auto from public API
+ enum ResizeMode { Stretch, KeepSize, FollowSizeHint, Auto };
+
+ QSplitter( QWidget* parent = 0, const char* name = 0 );
+ QSplitter( Orientation, QWidget* parent = 0, const char* name = 0 );
+ ~QSplitter();
+
+ virtual void setOrientation( Orientation );
+ Orientation orientation() const { return orient; }
+
+ // ### Qt 4.0: make setChildrenCollapsible() and setCollapsible() virtual
+
+ void setChildrenCollapsible( bool );
+ bool childrenCollapsible() const;
+
+ void setCollapsible( QWidget *w, bool );
+ virtual void setResizeMode( QWidget *w, ResizeMode );
+ virtual void setOpaqueResize( bool = TRUE );
+ bool opaqueResize() const;
+
+ void moveToFirst( QWidget * );
+ void moveToLast( QWidget * );
+
+ void refresh() { recalc( TRUE ); }
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ QValueList<int> sizes() const;
+ void setSizes( QValueList<int> );
+
+ int handleWidth() const;
+ void setHandleWidth( int );
+
+protected:
+ void childEvent( QChildEvent * );
+
+ bool event( QEvent * );
+ void resizeEvent( QResizeEvent * );
+
+ int idAfter( QWidget* ) const;
+
+ void moveSplitter( QCOORD pos, int id );
+ virtual void drawSplitter( QPainter*, QCOORD x, QCOORD y,
+ QCOORD w, QCOORD h );
+ void styleChange( QStyle& );
+ int adjustPos( int, int );
+ virtual void setRubberband( int );
+ void getRange( int id, int *, int * );
+
+private:
+ enum { DefaultResizeMode = 3 };
+
+ void init();
+ void recalc( bool update = FALSE );
+ void doResize();
+ void storeSizes();
+ void getRange( int id, int *, int *, int *, int * );
+ void addContribution( int, int *, int *, bool );
+ int adjustPos( int, int, int *, int *, int *, int * );
+ bool collapsible( QSplitterLayoutStruct * );
+ void processChildEvents();
+ QSplitterLayoutStruct *findWidget( QWidget * );
+ QSplitterLayoutStruct *addWidget( QWidget *, bool prepend = FALSE );
+ void recalcId();
+ void doMove( bool backwards, int pos, int id, int delta, bool upLeft,
+ bool mayCollapse );
+ void setGeo( QWidget *w, int pos, int size, bool splitterMoved );
+ int findWidgetJustBeforeOrJustAfter( int id, int delta, int &collapsibleSize );
+ void updateHandles();
+
+ inline QCOORD pick( const QPoint &p ) const
+ { return orient == Horizontal ? p.x() : p.y(); }
+ inline QCOORD pick( const QSize &s ) const
+ { return orient == Horizontal ? s.width() : s.height(); }
+
+ inline QCOORD trans( const QPoint &p ) const
+ { return orient == Vertical ? p.x() : p.y(); }
+ inline QCOORD trans( const QSize &s ) const
+ { return orient == Vertical ? s.width() : s.height(); }
+
+ QSplitterPrivate *d;
+
+ Orientation orient;
+ friend class QSplitterHandle;
+
+#ifndef QT_NO_TEXTSTREAM
+ friend Q_EXPORT QTextStream& operator<<( QTextStream&, const QSplitter& );
+ friend Q_EXPORT QTextStream& operator>>( QTextStream&, QSplitter& );
+#endif
+
+private:
+#if defined(Q_DISABLE_COPY)
+ QSplitter( const QSplitter & );
+ QSplitter& operator=( const QSplitter & );
+#endif
+};
+
+#ifndef QT_NO_TEXTSTREAM
+Q_EXPORT QTextStream& operator<<( QTextStream&, const QSplitter& );
+Q_EXPORT QTextStream& operator>>( QTextStream&, QSplitter& );
+#endif
+
+#endif // QT_NO_SPLITTER
+
+#endif // QSPLITTER_H
diff --git a/src/widgets/qstatusbar.cpp b/src/widgets/qstatusbar.cpp
new file mode 100644
index 0000000..9a57704
--- /dev/null
+++ b/src/widgets/qstatusbar.cpp
@@ -0,0 +1,526 @@
+/****************************************************************************
+**
+** Implementation of QStatusBar class
+**
+** Created : 980119
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qstatusbar.h"
+#ifndef QT_NO_STATUSBAR
+
+#include "qptrlist.h"
+#include "qlayout.h"
+#include "qpainter.h"
+#include "qtimer.h"
+#include "qdrawutil.h"
+#include "qstyle.h"
+#include "qsizegrip.h"
+
+/*!
+ \class QStatusBar qstatusbar.h
+ \brief The QStatusBar class provides a horizontal bar suitable for
+ presenting status information.
+
+ \ingroup application
+ \ingroup helpsystem
+ \mainclass
+
+ Each status indicator falls into one of three categories:
+
+ \list
+ \i \e Temporary - briefly occupies most of the status bar. Used
+ to explain tool tip texts or menu entries, for example.
+ \i \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.
+ \i \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.
+
+ To display a \e temporary message, call message() (perhaps by
+ connecting a suitable signal to it). To remove a temporary
+ message, call clear(). There are two variants of message(): one
+ that displays the message until the next clear() or message() and
+ one that has a time limit:
+
+ \code
+ connect( loader, SIGNAL(progressMessage(const QString&)),
+ statusBar(), SLOT(message(const QString&)) );
+
+ statusBar()->message("Loading..."); // Initial message
+ loader.loadStuff(); // Emits progress messages
+ statusBar()->message("Done.", 2000); // Final message for 2 seconds
+ \endcode
+
+ \e Normal and \e Permanent messages are displayed by creating a
+ small widget and then adding it to the status bar with
+ addWidget(). Widgets like QLabel, QProgressBar or even QToolButton
+ are useful for adding to status bars. removeWidget() is used to
+ remove widgets.
+
+ \code
+ statusBar()->addWidget(new MyReadWriteIndication(statusBar()));
+ \endcode
+
+ By default QStatusBar provides a QSizeGrip in the lower-right
+ corner. You can disable it with setSizeGripEnabled(FALSE);
+
+ <img src=qstatusbar-m.png> <img src=qstatusbar-w.png>
+
+ \sa QToolBar QMainWindow QLabel
+ \link guibooks.html#fowler GUI Design Handbook: Status Bar.\endlink
+*/
+
+
+class QStatusBarPrivate
+{
+public:
+ QStatusBarPrivate() {}
+
+ struct SBItem {
+ SBItem( QWidget* widget, int stretch, bool permanent )
+ : s( stretch ), w( widget ), p( permanent ) {}
+ int s;
+ QWidget * w;
+ bool p;
+ };
+
+ QPtrList<SBItem> items;
+ QString tempItem;
+
+ QBoxLayout * box;
+ QTimer * timer;
+
+#ifndef QT_NO_SIZEGRIP
+ QSizeGrip * resizer;
+#endif
+
+ int savedStrut;
+};
+
+
+/*!
+ Constructs a status bar called \a name with parent \a parent and
+ with a size grip.
+
+ \sa setSizeGripEnabled()
+*/
+QStatusBar::QStatusBar( QWidget * parent, const char *name )
+ : QWidget( parent, name )
+{
+ d = new QStatusBarPrivate;
+ d->items.setAutoDelete( TRUE );
+ d->box = 0;
+ d->timer = 0;
+
+#ifndef QT_NO_SIZEGRIP
+ d->resizer = 0;
+ setSizeGripEnabled(TRUE); // causes reformat()
+#else
+ reformat();
+#endif
+}
+
+
+/*!
+ Destroys the status bar and frees any allocated resources and
+ child widgets.
+*/
+QStatusBar::~QStatusBar()
+{
+ delete d;
+ d = 0;
+}
+
+
+/*!
+ Adds \a widget to this status bar. \a widget is reparented if it
+ isn't already a child of the QStatusBar.
+
+ \a widget is permanently visible if \a permanent is TRUE and may
+ be obscured by temporary messages if \a permanent is FALSE. The
+ default is FALSE.
+
+ If \a permanent is TRUE, \a widget is located at the far right of
+ the status bar. If \a permanent is FALSE (the default), \a widget
+ is located just to the left of the first permanent widget.
+
+ \a stretch is used to compute a suitable size for \a widget as the
+ status bar grows and shrinks. The default of 0 uses a minimum of
+ space.
+
+ This function may cause some flicker.
+
+ \sa removeWidget()
+*/
+
+void QStatusBar::addWidget( QWidget * widget, int stretch, bool permanent )
+{
+ if ( !widget ) {
+#if defined(QT_CHECK_NULL)
+ qWarning( "QStatusBar::addWidget(): Cannot add null widget" );
+#endif
+ return;
+ }
+
+ if ( widget->parentWidget() != this )
+ widget->reparent( this, QPoint(0, 0), TRUE );
+
+ QStatusBarPrivate::SBItem* item
+ = new QStatusBarPrivate::SBItem( widget, stretch, permanent );
+
+ d->items.last();
+ while( !permanent && d->items.current() && d->items.current()->p )
+ d->items.prev();
+
+ d->items.insert( d->items.at() >= 0 ? d->items.at()+1 : 0, item );
+
+ if ( !d->tempItem.isEmpty() && !permanent )
+ widget->hide();
+
+ reformat();
+}
+
+
+/*!
+ Removes \a widget from the status bar.
+
+ This function may cause some flicker.
+
+ Note that \a widget is not deleted.
+
+ \sa addWidget()
+*/
+
+void QStatusBar::removeWidget( QWidget* widget )
+{
+ if ( !widget )
+ return;
+ bool found = FALSE;
+ QStatusBarPrivate::SBItem* item = d->items.first();
+ while ( item && !found ) {
+ if ( item->w == widget ) {
+ d->items.remove();
+ found = TRUE;
+ }
+ item = d->items.next();
+ }
+
+ 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 of the status bar is enabled
+
+ Enables or disables the QSizeGrip in the bottom right of the
+ status bar. By default, the size grip is enabled.
+*/
+
+bool QStatusBar::isSizeGripEnabled() const
+{
+#ifdef QT_NO_SIZEGRIP
+ return FALSE;
+#else
+ return !!d->resizer;
+#endif
+}
+
+void QStatusBar::setSizeGripEnabled(bool enabled)
+{
+#ifndef QT_NO_SIZEGRIP
+ if ( !enabled != !d->resizer ) {
+ if ( enabled ) {
+ d->resizer = new QSizeGrip( this, "QStatusBar::resizer" );
+ } else {
+ delete d->resizer;
+ d->resizer = 0;
+ }
+ reformat();
+ if ( d->resizer && isVisible() )
+ d->resizer->show();
+ }
+#endif
+}
+
+
+/*!
+ Changes the status bar's appearance to account for item changes.
+ Special subclasses may need this, but geometry management will
+ usually take care of any necessary rearrangements.
+*/
+void QStatusBar::reformat()
+{
+ if ( d->box )
+ delete d->box;
+
+ QBoxLayout *vbox;
+ if ( isSizeGripEnabled() ) {
+ d->box = new QHBoxLayout( this );
+ vbox = new QVBoxLayout( d->box );
+ } else {
+ vbox = d->box = new QVBoxLayout( this );
+ }
+ vbox->addSpacing( 3 );
+ QBoxLayout* l = new QHBoxLayout( vbox );
+ l->addSpacing( 3 );
+ l->setSpacing( 4 );
+
+ int maxH = fontMetrics().height();
+
+ QStatusBarPrivate::SBItem* item = d->items.first();
+ while ( item && !item->p ) {
+ l->addWidget( item->w, item->s );
+ int itemH = QMIN(item->w->sizeHint().height(),
+ item->w->maximumHeight());
+ maxH = QMAX( maxH, itemH );
+ item = d->items.next();
+ }
+
+ l->addStretch( 0 );
+
+ while ( item ) {
+ l->addWidget( item->w, item->s );
+ int itemH = QMIN(item->w->sizeHint().height(),
+ item->w->maximumHeight());
+ maxH = QMAX( maxH, itemH );
+ item = d->items.next();
+ }
+ l->addSpacing( 4 );
+#ifndef QT_NO_SIZEGRIP
+ if ( d->resizer ) {
+ maxH = QMAX( maxH, d->resizer->sizeHint().height() );
+ d->box->addSpacing( 1 );
+ d->box->addWidget( d->resizer, 0, AlignBottom );
+ }
+#endif
+ l->addStrut( maxH );
+ d->savedStrut = maxH;
+ vbox->addSpacing( 2 );
+ d->box->activate();
+ repaint();
+}
+
+
+
+
+/*!
+ Hides the normal status indicators and displays \a message until
+ clear() or another message() is called.
+
+ \sa clear()
+*/
+void QStatusBar::message( const QString &message )
+{
+ if ( d->tempItem == message )
+ return;
+ d->tempItem = message;
+ if ( d->timer ) {
+ delete d->timer;
+ d->timer = 0;
+ }
+ hideOrShow();
+}
+
+
+/*!
+ \overload
+
+ Hides the normal status indications and displays \a message for \a
+ ms milli-seconds or until clear() or another message() is called,
+ whichever occurs first.
+*/
+void QStatusBar::message( const QString &message, int ms )
+{
+ d->tempItem = message;
+
+ if ( !d->timer ) {
+ d->timer = new QTimer( this );
+ connect( d->timer, SIGNAL(timeout()), this, SLOT(clear()) );
+ }
+ if ( ms > 0 ) {
+ d->timer->start( ms );
+ } else if ( d->timer ) {
+ delete d->timer;
+ d->timer = 0;
+ }
+
+ hideOrShow();
+}
+
+
+/*!
+ Removes any temporary message being shown.
+
+ \sa message()
+*/
+
+void QStatusBar::clear()
+{
+ if ( d->tempItem.isEmpty() )
+ return;
+ if ( d->timer ) {
+ delete d->timer;
+ d->timer = 0;
+ }
+ d->tempItem = QString::null;
+ hideOrShow();
+}
+
+/*!
+ \fn QStatusBar::messageChanged( const QString &message )
+
+ This signal is emitted when the temporary status messages
+ changes. \a message is the new temporary message, and is a
+ null-string when the message has been removed.
+
+ \sa message(), clear()
+*/
+
+/*!
+ Ensures that the right widgets are visible. Used by message() and
+ clear().
+*/
+void QStatusBar::hideOrShow()
+{
+ bool haveMessage = !d->tempItem.isEmpty();
+
+ QStatusBarPrivate::SBItem* item = d->items.first();
+
+ while( item && !item->p ) {
+ if ( haveMessage )
+ item->w->hide();
+ else
+ item->w->show();
+ item = d->items.next();
+ }
+
+ emit messageChanged( d->tempItem );
+ repaint();
+}
+
+
+/*!
+ Shows the temporary message, if appropriate.
+*/
+void QStatusBar::paintEvent( QPaintEvent * )
+{
+ bool haveMessage = !d->tempItem.isEmpty();
+
+ QPainter p( this );
+ QStatusBarPrivate::SBItem* item = d->items.first();
+
+#ifndef QT_NO_SIZEGRIP
+ int psx = ( d->resizer && d->resizer->isVisible() ) ? d->resizer->x() : width()-12;
+#else
+ int psx = width() - 12;
+#endif
+
+ while ( item ) {
+ if ( !haveMessage || item->p )
+ if ( item->w->isVisible() ) {
+ if ( item->p && item->w->x()-1 < psx )
+ psx = item->w->x()-1;
+ style().drawPrimitive( QStyle::PE_StatusBarSection, &p,
+ QRect(item->w->x() - 1, item->w->y() - 1,
+ item->w->width()+2, item->w->height()+2),
+ colorGroup(), QStyle::Style_Default,
+ QStyleOption(item->w) );
+ }
+ item = d->items.next();
+ }
+ if ( haveMessage ) {
+ p.setPen( colorGroup().foreground() );
+ p.drawText( 6, 0, psx, height(), AlignVCenter | SingleLine, d->tempItem );
+ }
+}
+
+/*!
+ \reimp
+*/
+void QStatusBar::resizeEvent( QResizeEvent * e )
+{
+ QWidget::resizeEvent( e );
+}
+
+/*!
+ \reimp
+*/
+
+bool QStatusBar::event( QEvent *e )
+{
+ if ( e->type() == QEvent::LayoutHint ) {
+ // Calculate new strut height and call reformat() if it has changed
+ int maxH = fontMetrics().height();
+
+ QStatusBarPrivate::SBItem* item = d->items.first();
+ while ( item ) {
+ int itemH = QMIN(item->w->sizeHint().height(),
+ item->w->maximumHeight());
+ maxH = QMAX( maxH, itemH );
+ item = d->items.next();
+ }
+
+#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 = d->items.first();
+ while ( item ) {
+ if ( item->w == ( (QChildEvent*)e )->child() )
+ d->items.removeRef( item );
+ item = d->items.next();
+ }
+ }
+ return QWidget::event( e );
+}
+
+#endif
diff --git a/src/widgets/qstatusbar.h b/src/widgets/qstatusbar.h
new file mode 100644
index 0000000..12d50f2
--- /dev/null
+++ b/src/widgets/qstatusbar.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Definition of QStatusBar class
+**
+** Created : 980316
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSTATUSBAR_H
+#define QSTATUSBAR_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+
+#ifndef QT_NO_STATUSBAR
+
+
+class QStatusBarPrivate;
+
+
+class Q_EXPORT QStatusBar: public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY( bool sizeGripEnabled READ isSizeGripEnabled WRITE setSizeGripEnabled )
+
+public:
+ QStatusBar( QWidget* parent=0, const char* name=0 );
+ virtual ~QStatusBar();
+
+ virtual void addWidget( QWidget *, int stretch = 0, bool = FALSE );
+ virtual void removeWidget( QWidget * );
+
+ void setSizeGripEnabled(bool);
+ bool isSizeGripEnabled() const;
+
+public slots:
+ void message( const QString &);
+ void message( const QString &, int );
+ void clear();
+
+signals:
+ void messageChanged( const QString &text );
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void resizeEvent( QResizeEvent * );
+
+ void reformat();
+ void hideOrShow();
+ bool event( QEvent *);
+
+private:
+ QStatusBarPrivate * d;
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QStatusBar( const QStatusBar & );
+ QStatusBar& operator=( const QStatusBar & );
+#endif
+};
+
+#endif // QT_NO_STATUSBAR
+
+#endif // QSTATUSBAR_H
diff --git a/src/widgets/qsyntaxhighlighter.cpp b/src/widgets/qsyntaxhighlighter.cpp
new file mode 100644
index 0000000..220bdc7
--- /dev/null
+++ b/src/widgets/qsyntaxhighlighter.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Implementation of the QSyntaxHighlighter class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qsyntaxhighlighter.h"
+#include "private/qsyntaxhighlighter_p.h"
+
+#ifndef QT_NO_SYNTAXHIGHLIGHTER
+#include "../kernel/qrichtext_p.h"
+#include "qtextedit.h"
+#include "qtimer.h"
+
+/*!
+ \class QSyntaxHighlighter qsyntaxhighlighter.h
+ \brief The QSyntaxHighlighter class is a base class for
+ implementing QTextEdit syntax highlighters.
+
+ \ingroup basic
+ \ingroup text
+
+ A syntax highligher automatically highlights parts of the text in
+ a QTextEdit. Syntax highlighters are often used when the user is
+ entering text in a specific format (for example, source code) and
+ help the user to read the text and identify syntax errors.
+
+ To provide your own syntax highlighting for QTextEdit, you must
+ subclass QSyntaxHighlighter and reimplement highlightParagraph().
+
+ When you create an instance of your QSyntaxHighlighter subclass,
+ pass it the QTextEdit that you want the syntax highlighting to be
+ applied to. After this your highlightParagraph() function will be
+ called automatically whenever necessary. Use your
+ highlightParagraph() function to apply formatting (e.g. setting
+ the font and color) to the text that is passed to it.
+*/
+
+/*!
+ Constructs the QSyntaxHighlighter and installs it on \a textEdit.
+
+ It is the caller's responsibility to delete the
+ QSyntaxHighlighter when it is no longer needed.
+*/
+
+QSyntaxHighlighter::QSyntaxHighlighter( QTextEdit *textEdit )
+ : para( 0 ), edit( textEdit ), d( new QSyntaxHighlighterPrivate )
+{
+ textEdit->document()->setPreProcessor( new QSyntaxHighlighterInternal( this ) );
+ textEdit->document()->invalidate();
+ QTimer::singleShot( 0, textEdit->viewport(), SLOT( update() ) );
+}
+
+/*!
+ Destructor. Uninstalls this syntax highlighter from the textEdit()
+*/
+
+QSyntaxHighlighter::~QSyntaxHighlighter()
+{
+ delete d;
+ textEdit()->document()->setPreProcessor( 0 );
+}
+
+/*!
+ \fn int QSyntaxHighlighter::highlightParagraph( const QString &text, int endStateOfLastPara )
+
+ This function is called when necessary by the rich text engine,
+ i.e. on paragraphs which have changed.
+
+ In your reimplementation you should parse the paragraph's \a text
+ and call setFormat() as often as necessary to apply any font and
+ color changes that you require. Your function must return a value
+ which indicates the paragraph's end state: see below.
+
+ Some syntaxes can have constructs that span paragraphs. For
+ example, a C++ syntax highlighter should be able to cope with
+ \c{/}\c{*...*}\c{/} comments that span paragraphs. To deal
+ with these cases it is necessary to know the end state of the
+ previous paragraph (e.g. "in comment").
+
+ If your syntax does not have paragraph spanning constructs, simply
+ ignore the \a endStateOfLastPara parameter and always return 0.
+
+ Whenever highlightParagraph() is called it is passed a value for
+ \a endStateOfLastPara. For the very first paragraph this value is
+ always -2. For any other paragraph the value is the value returned
+ by the most recent highlightParagraph() call that applied to the
+ preceding paragraph.
+
+ The value you return is up to you. We recommend only returning 0
+ (to signify that this paragraph's syntax highlighting does not
+ affect the following paragraph), or a positive integer (to signify
+ that this paragraph has ended in the middle of a paragraph
+ spanning construct).
+
+ To find out which paragraph is highlighted, call
+ currentParagraph().
+
+ For example, if you're writing a simple C++ syntax highlighter,
+ you might designate 1 to signify "in comment". For a paragraph
+ that ended in the middle of a comment you'd return 1, and for
+ other paragraphs you'd return 0. In your parsing code if \a
+ endStateOfLastPara was 1, you would highlight the text as a C++
+ comment until you reached the closing \c{*}\c{/}.
+*/
+
+/*!
+ This function is applied to the syntax highlighter's current
+ paragraph (the text of which is passed to the highlightParagraph()
+ function).
+
+ The specified \a font and \a color are applied to the text from
+ position \a start for \a count characters. (If \a count is 0,
+ nothing is done.)
+*/
+
+void QSyntaxHighlighter::setFormat( int start, int count, const QFont &font, const QColor &color )
+{
+ if ( !para || count <= 0 )
+ return;
+ QTextFormat *f = 0;
+ f = para->document()->formatCollection()->format( font, color );
+ para->setFormat( start, count, f );
+ f->removeRef();
+}
+
+/*! \overload */
+
+void QSyntaxHighlighter::setFormat( int start, int count, const QColor &color )
+{
+ if ( !para || count <= 0 )
+ return;
+ QTextFormat *f = 0;
+ QFont fnt = textEdit()->QWidget::font();
+ f = para->document()->formatCollection()->format( fnt, color );
+ para->setFormat( start, count, f );
+ f->removeRef();
+}
+
+/*! \overload */
+
+void QSyntaxHighlighter::setFormat( int start, int count, const QFont &font )
+{
+ if ( !para || count <= 0 )
+ return;
+ QTextFormat *f = 0;
+ QColor c = textEdit()->viewport()->paletteForegroundColor();
+ f = para->document()->formatCollection()->format( font, c );
+ para->setFormat( start, count, f );
+ f->removeRef();
+}
+
+/*!
+ \fn QTextEdit *QSyntaxHighlighter::textEdit() const
+
+ Returns the QTextEdit on which this syntax highlighter is
+ installed
+*/
+
+/*! Redoes the highlighting of the whole document.
+*/
+
+void QSyntaxHighlighter::rehighlight()
+{
+ QTextParagraph *s = edit->document()->firstParagraph();
+ while ( s ) {
+ s->invalidate( 0 );
+ s->state = -1;
+ s->needPreProcess = TRUE;
+ s = s->next();
+ }
+ edit->repaintContents( FALSE );
+}
+
+/*!
+ Returns the id of the paragraph which is highlighted, or -1 of no
+ paragraph is currently highlighted.
+
+ Usually this function is called from within highlightParagraph().
+*/
+
+int QSyntaxHighlighter::currentParagraph() const
+{
+ return d->currentParagraph;
+}
+
+#endif
diff --git a/src/widgets/qsyntaxhighlighter.h b/src/widgets/qsyntaxhighlighter.h
new file mode 100644
index 0000000..5dbefea
--- /dev/null
+++ b/src/widgets/qsyntaxhighlighter.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Definition of the QSyntaxHighlighter class
+**
+** Created : 022407
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSYNTAXHIGHLIGHTER_H
+#define QSYNTAXHIGHLIGHTER_H
+
+#ifndef QT_H
+#include "qfont.h"
+#include "qcolor.h"
+#include "qstring.h"
+#endif // QT_H
+
+class QTextEdit;
+class QSyntaxHighlighterInternal;
+class QSyntaxHighlighterPrivate;
+class QTextParagraph;
+
+class Q_EXPORT QSyntaxHighlighter : public Qt
+{
+ friend class QSyntaxHighlighterInternal;
+
+public:
+ QSyntaxHighlighter( QTextEdit *textEdit );
+ virtual ~QSyntaxHighlighter();
+
+ virtual int highlightParagraph( const QString &text, int endStateOfLastPara ) = 0;
+
+ void setFormat( int start, int count, const QFont &font, const QColor &color );
+ void setFormat( int start, int count, const QColor &color );
+ void setFormat( int start, int count, const QFont &font );
+ QTextEdit *textEdit() const { return edit; }
+
+ void rehighlight();
+
+ int currentParagraph() const;
+
+private:
+ QTextParagraph *para;
+ QTextEdit *edit;
+ QSyntaxHighlighterPrivate *d;
+
+};
+
+#endif
diff --git a/src/widgets/qsyntaxhighlighter_p.h b/src/widgets/qsyntaxhighlighter_p.h
new file mode 100644
index 0000000..9d1ad4d
--- /dev/null
+++ b/src/widgets/qsyntaxhighlighter_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Definition of the internal QSyntaxHighlighterInternal class
+**
+** Created : 031111
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QSYNTAXHIGHLIGHTER_P_H
+#define QSYNTAXHIGHLIGHTER_P_H
+
+#ifndef QT_NO_SYNTAXHIGHLIGHTER
+#include "qsyntaxhighlighter.h"
+#include "private/qrichtext_p.h"
+
+class QSyntaxHighlighterPrivate
+{
+public:
+ QSyntaxHighlighterPrivate() :
+ currentParagraph( -1 )
+ {}
+
+ int currentParagraph;
+};
+
+class QSyntaxHighlighterInternal : public QTextPreProcessor
+{
+public:
+ QSyntaxHighlighterInternal( QSyntaxHighlighter *h ) : highlighter( h ) {}
+ void process( QTextDocument *doc, QTextParagraph *p, int, bool invalidate ) {
+ if ( p->prev() && p->prev()->endState() == -1 )
+ process( doc, p->prev(), 0, FALSE );
+
+ highlighter->para = p;
+ QString text = p->string()->toString();
+ int endState = p->prev() ? p->prev()->endState() : -2;
+ int oldEndState = p->endState();
+ highlighter->d->currentParagraph = p->paragId();
+ p->setEndState( highlighter->highlightParagraph( text, endState ) );
+ highlighter->d->currentParagraph = -1;
+ highlighter->para = 0;
+
+ p->setFirstPreProcess( FALSE );
+ QTextParagraph *op = p;
+ p = p->next();
+ if ( (!!oldEndState || !!op->endState()) && oldEndState != op->endState() &&
+ invalidate && p && !p->firstPreProcess() && p->endState() != -1 ) {
+ while ( p ) {
+ if ( p->endState() == -1 )
+ return;
+ p->setEndState( -1 );
+ p = p->next();
+ }
+ }
+ }
+ QTextFormat *format( int ) { return 0; }
+
+private:
+ QSyntaxHighlighter *highlighter;
+
+ friend class QTextEdit;
+};
+
+#endif // QT_NO_SYNTAXHIGHLIGHTER
+#endif // QSYNTAXHIGHLIGHTER_P_H
diff --git a/src/widgets/qt_widgets.pri b/src/widgets/qt_widgets.pri
new file mode 100644
index 0000000..a4917e9
--- /dev/null
+++ b/src/widgets/qt_widgets.pri
@@ -0,0 +1,139 @@
+# Qt widgets module
+
+widgets {
+ WIDGETS_P = widgets
+
+ HEADERS += $$WIDGETS_H/qbuttongroup.h \
+ $$WIDGETS_H/qbutton.h \
+ $$WIDGETS_P/qdialogbuttons_p.h \
+ $$WIDGETS_H/qcheckbox.h \
+ $$WIDGETS_H/qcombobox.h \
+ $$WIDGETS_P/qwidgetresizehandler_p.h \
+ $$WIDGETS_H/qdial.h \
+ $$WIDGETS_H/qdockarea.h \
+ $$WIDGETS_H/qdockwindow.h \
+ $$WIDGETS_H/qframe.h \
+ $$WIDGETS_H/qgrid.h \
+ $$WIDGETS_H/qgridview.h \
+ $$WIDGETS_H/qgroupbox.h \
+ $$WIDGETS_H/qhbuttongroup.h \
+ $$WIDGETS_H/qheader.h \
+ $$WIDGETS_H/qhgroupbox.h \
+ $$WIDGETS_H/qhbox.h \
+ $$WIDGETS_H/qlabel.h \
+ $$WIDGETS_H/qlcdnumber.h \
+ $$WIDGETS_H/qlineedit.h \
+ $$WIDGETS_H/qlistbox.h \
+ $$WIDGETS_H/qlistview.h \
+ $$WIDGETS_H/qmainwindow.h \
+ $$WIDGETS_H/qmenubar.h \
+ $$WIDGETS_H/qmenudata.h \
+ $$WIDGETS_H/qmultilineedit.h \
+ $$WIDGETS_H/qpopupmenu.h \
+ $$WIDGETS_H/qprogressbar.h \
+ $$WIDGETS_H/qpushbutton.h \
+ $$WIDGETS_H/qradiobutton.h \
+ $$WIDGETS_H/qrangecontrol.h \
+ $$WIDGETS_H/qscrollbar.h \
+ $$WIDGETS_H/qscrollview.h \
+ $$WIDGETS_H/qslider.h \
+ $$WIDGETS_H/qsplashscreen.h \
+ $$WIDGETS_H/qspinbox.h \
+ $$WIDGETS_H/qsplitter.h \
+ $$WIDGETS_H/qstatusbar.h \
+ $$WIDGETS_H/qtabbar.h \
+ $$WIDGETS_H/qsyntaxhighlighter.h \
+ $$WIDGETS_P/qsyntaxhighlighter_p.h \
+ $$WIDGETS_H/qtabwidget.h \
+ $$WIDGETS_P/qtitlebar_p.h \
+ $$WIDGETS_H/qtoolbar.h \
+ $$WIDGETS_H/qtoolbox.h \
+ $$WIDGETS_H/qtoolbutton.h \
+ $$WIDGETS_H/qtooltip.h \
+ $$WIDGETS_H/qvalidator.h \
+ $$WIDGETS_H/qvbox.h \
+ $$WIDGETS_H/qvbuttongroup.h \
+ $$WIDGETS_H/qvgroupbox.h \
+ $$WIDGETS_H/qwhatsthis.h \
+ $$WIDGETS_H/qwidgetstack.h \
+ $$WIDGETS_H/qaction.h \
+ $$WIDGETS_H/qdatetimeedit.h \
+ $$WIDGETS_H/qtextview.h \
+ $$WIDGETS_H/qtextbrowser.h \
+ $$WIDGETS_H/qtextedit.h \
+ $$WIDGETS_P/qwidgetinterface_p.h \
+ $$WIDGETS_H/qwidgetplugin.h
+
+ SOURCES += $$WIDGETS_CPP/qbuttongroup.cpp \
+ $$WIDGETS_CPP/qbutton.cpp \
+ $$WIDGETS_CPP/qdialogbuttons.cpp \
+ $$WIDGETS_CPP/qcheckbox.cpp \
+ $$WIDGETS_CPP/qcombobox.cpp \
+ $$WIDGETS_CPP/qwidgetresizehandler.cpp \
+ $$WIDGETS_CPP/qdial.cpp \
+ $$WIDGETS_CPP/qdockarea.cpp \
+ $$WIDGETS_CPP/qdockwindow.cpp \
+ $$WIDGETS_CPP/qframe.cpp \
+ $$WIDGETS_CPP/qgrid.cpp \
+ $$WIDGETS_CPP/qgridview.cpp \
+ $$WIDGETS_CPP/qgroupbox.cpp \
+ $$WIDGETS_CPP/qhbuttongroup.cpp \
+ $$WIDGETS_CPP/qheader.cpp \
+ $$WIDGETS_CPP/qhgroupbox.cpp \
+ $$WIDGETS_CPP/qhbox.cpp \
+ $$WIDGETS_CPP/qlabel.cpp \
+ $$WIDGETS_CPP/qlcdnumber.cpp \
+ $$WIDGETS_CPP/qlineedit.cpp \
+ $$WIDGETS_CPP/qlistbox.cpp \
+ $$WIDGETS_CPP/qlistview.cpp \
+ $$WIDGETS_CPP/qmainwindow.cpp \
+ $$WIDGETS_CPP/qmenubar.cpp \
+ $$WIDGETS_CPP/qmenudata.cpp \
+ $$WIDGETS_CPP/qmultilineedit.cpp \
+ $$WIDGETS_CPP/qpopupmenu.cpp \
+ $$WIDGETS_CPP/qprogressbar.cpp \
+ $$WIDGETS_CPP/qpushbutton.cpp \
+ $$WIDGETS_CPP/qradiobutton.cpp \
+ $$WIDGETS_CPP/qrangecontrol.cpp \
+ $$WIDGETS_CPP/qscrollbar.cpp \
+ $$WIDGETS_CPP/qscrollview.cpp \
+ $$WIDGETS_CPP/qslider.cpp \
+ $$WIDGETS_CPP/qsplashscreen.cpp \
+ $$WIDGETS_CPP/qspinbox.cpp \
+ $$WIDGETS_CPP/qspinwidget.cpp \
+ $$WIDGETS_CPP/qsplitter.cpp \
+ $$WIDGETS_CPP/qstatusbar.cpp \
+ $$WIDGETS_CPP/qsyntaxhighlighter.cpp \
+ $$WIDGETS_CPP/qtabbar.cpp \
+ $$WIDGETS_CPP/qtabwidget.cpp \
+ $$WIDGETS_CPP/qtitlebar.cpp \
+ $$WIDGETS_CPP/qtoolbar.cpp \
+ $$WIDGETS_CPP/qtoolbox.cpp \
+ $$WIDGETS_CPP/qtoolbutton.cpp \
+ $$WIDGETS_CPP/qtooltip.cpp \
+ $$WIDGETS_CPP/qvalidator.cpp \
+ $$WIDGETS_CPP/qvbox.cpp \
+ $$WIDGETS_CPP/qvbuttongroup.cpp \
+ $$WIDGETS_CPP/qvgroupbox.cpp \
+ $$WIDGETS_CPP/qwhatsthis.cpp \
+ $$WIDGETS_CPP/qwidgetstack.cpp \
+ $$WIDGETS_CPP/qaction.cpp \
+ $$WIDGETS_CPP/qdatetimeedit.cpp \
+ $$WIDGETS_CPP/qeffects.cpp \
+ $$WIDGETS_CPP/qtextview.cpp \
+ $$WIDGETS_CPP/qtextbrowser.cpp \
+ $$WIDGETS_CPP/qtextedit.cpp \
+ $$WIDGETS_CPP/qwidgetplugin.cpp
+ !embedded:mac:SOURCES += $$WIDGETS_CPP/qmenubar_mac.cpp
+}
+
+wince-* {
+ SOURCES += $$WIDGETS_CPP/ce/qcemainwindow.cpp
+ HEADERS += $$WIDGETS_H/ce/qcemainwindow.h
+
+ SOURCES -= $$WIDGETS_CPP/qsyntaxhighlighter.cpp \
+ $$WIDGETS_CPP/qsplashscreen.cpp
+
+ HEADERS -= $$WIDGETS_H/qsyntaxhighlighter.h \
+ $$WIDGETS_H/qsplashscreen.h
+}
diff --git a/src/widgets/qtabbar.cpp b/src/widgets/qtabbar.cpp
new file mode 100644
index 0000000..fca4957
--- /dev/null
+++ b/src/widgets/qtabbar.cpp
@@ -0,0 +1,1368 @@
+/****************************************************************************
+**
+** Implementation of QTab and QTabBar classes
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtabbar.h"
+#ifndef QT_NO_TABBAR
+#include "qaccel.h"
+#include "qbitmap.h"
+#include "qtoolbutton.h"
+#include "qtooltip.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qpainter.h"
+#include "qiconset.h"
+#include "qcursor.h"
+#include "../kernel/qinternal_p.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+
+#ifdef Q_WS_MACX
+#include <qmacstyle_mac.h>
+#endif
+
+
+/*!
+ \class QTab qtabbar.h
+ \brief The QTab class provides the structures in a QTabBar.
+
+ \ingroup advanced
+
+ This class is used for custom QTabBar tab headings.
+
+ \sa QTabBar
+*/
+
+
+/*!
+ Constructs an empty tab. All fields are set to empty.
+*/
+
+QTab::QTab()
+ : enabled( TRUE ),
+ id ( 0 ),
+ iconset( 0 ),
+ tb( 0 )
+{
+}
+
+/*!
+ Constructs a tab with the text \a text.
+*/
+
+QTab::QTab( const QString &text )
+ : label( text ),
+ enabled( TRUE ),
+ id( 0 ),
+ iconset( 0 ),
+ tb( 0 )
+{
+}
+
+/*!
+ Constructs a tab with an \a icon and the text, \a text.
+*/
+
+QTab::QTab( const QIconSet& icon, const QString& text )
+ : label( text ),
+ enabled( TRUE ),
+ id( 0 ),
+ iconset( new QIconSet(icon) ),
+ tb( 0 )
+{
+}
+
+/*!
+ \fn QString QTab::text() const
+
+ Returns the text of the QTab label.
+*/
+
+/*!
+ \fn QIconSet QTab::iconSet() const
+
+ Return the QIconSet of the QTab.
+*/
+
+/*!
+ \fn void QTab::setRect( const QRect &rect )
+
+ Set the QTab QRect to \a rect.
+*/
+
+/*!
+ \fn QRect QTab::rect() const
+
+ Return the QRect for the QTab.
+*/
+
+/*!
+ \fn void QTab::setEnabled( bool enable )
+
+ If \a enable is TRUE enable the QTab, otherwise disable it.
+*/
+
+/*!
+ \fn bool QTab::isEnabled() const
+
+ Returns TRUE if the QTab is enabled; otherwise returns FALSE.
+*/
+
+/*!
+ \fn void QTab::setIdentifier( int i )
+
+ Set the identifier for the QTab to \a i. Each QTab's identifier
+ within a QTabBar must be unique.
+*/
+
+/*!
+ \fn int QTab::identifier() const
+
+ Return the QTab's identifier.
+*/
+
+
+
+/*!
+ Destroys the tab and frees up all allocated resources.
+*/
+
+QTab::~QTab()
+{
+ delete iconset;
+ tb = 0;
+}
+
+/*!
+ \class QTabBar qtabbar.h
+ \brief The QTabBar class provides a tab bar, e.g. for use in tabbed dialogs.
+
+ \ingroup advanced
+
+ 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} and a
+ \l{QTabDialog}.
+
+ The choice of tab shape is a matter of taste, although tab dialogs
+ (for preferences and similar) invariably use \c RoundedAbove;
+ nobody uses \c TriangularAbove. Tab controls in windows other than
+ dialogs almost always use either \c RoundedBelow or \c
+ TriangularBelow. Many spreadsheets and other tab controls in which
+ all the pages are essentially similar use \c TriangularBelow,
+ whereas \c RoundedBelow is used mostly when the pages are
+ different (e.g. a multi-page tool palette).
+
+ The most important part of QTabBar's API is the selected() signal.
+ This is emitted whenever the selected page changes (even at
+ startup, when the selected page changes from 'none'). There is
+ also a slot, setCurrentTab(), which can be used to select a page
+ programmatically.
+
+ QTabBar creates automatic accelerator keys in the manner of
+ QButton; e.g. if a tab's label is "\&Graphics", Alt+G becomes an
+ accelerator key for switching to that tab.
+
+ The following virtual functions may need to be reimplemented:
+ \list
+ \i paint() paints a single tab. paintEvent() calls paint() for
+ each tab so that any overlap will look right.
+ \i addTab() creates a new tab and adds it to the bar.
+ \i selectTab() decides which tab, if any, the user selects with the mouse.
+ \endlist
+
+ The index of the current tab is returned by currentTab(). The tab
+ with a particular index is returned by tabAt(), the tab with a
+ particular id is returned by tab(). The index of a tab is returned
+ by indexOf(). The current tab can be set by index or tab pointer
+ using one of the setCurrentTab() functions.
+
+ <img src=qtabbar-m.png> <img src=qtabbar-w.png>
+*/
+
+/*!
+ \enum QTabBar::Shape
+
+ This enum type lists the built-in shapes supported by QTabBar:
+
+ \value RoundedAbove the normal rounded look above the pages
+
+ \value RoundedBelow the normal rounded look below the pages
+
+ \value TriangularAbove triangular tabs above the pages (very
+ unusual; included for completeness)
+
+ \value TriangularBelow triangular tabs similar to those used in
+ the Excel spreadsheet, for example
+*/
+
+class QTabBarToolTip;
+
+struct QTabPrivate {
+ int id;
+ int focus;
+#ifndef QT_NO_ACCEL
+ QAccel * a;
+#endif
+ QTab *pressed;
+ QTabBar::Shape s;
+ QToolButton* rightB;
+ QToolButton* leftB;
+ int btnWidth;
+ bool scrolls;
+ QTabBarToolTip * toolTips;
+};
+
+#ifndef QT_NO_TOOLTIP
+/* \internal
+*/
+class QTabBarToolTip : public QToolTip
+{
+public:
+ QTabBarToolTip( QWidget * parent )
+ : QToolTip( parent ) {}
+ virtual ~QTabBarToolTip() {}
+
+ void add( QTab * tab, const QString & tip )
+ {
+ tabTips.replace( tab, tip );
+ }
+
+ void remove( QTab * tab )
+ {
+ tabTips.erase( tab );
+ }
+
+ QString tipForTab( QTab * tab ) const
+ {
+ QMapConstIterator<QTab *, QString> it;
+ it = tabTips.find( tab );
+ if ( it != tabTips.end() )
+ return it.data();
+ else
+ return QString();
+ }
+
+protected:
+ void maybeTip( const QPoint & p )
+ {
+ QTabBar * tb = (QTabBar *) parentWidget();
+ if ( !tb )
+ return;
+
+ // check if the scroll buttons in the tab bar are visible -
+ // don't display any tips if the pointer is over one of them
+ QRect rectL, rectR;
+ rectL.setRect( tb->d->leftB->x(), tb->d->leftB->y(),
+ tb->d->leftB->width(), tb->d->leftB->height() );
+ rectR.setRect( tb->d->rightB->x(), tb->d->rightB->y(),
+ tb->d->rightB->width(), tb->d->rightB->height() );
+ if ( tb->d->scrolls && (rectL.contains( p ) || rectR.contains( p )) )
+ return;
+
+#ifndef QT_NO_TOOLTIP
+ // find and show the tool tip for the tab under the point p
+ QMapIterator<QTab *, QString> it;
+ for ( it = tabTips.begin(); it != tabTips.end(); ++it ) {
+ if ( it.key()->rect().contains( p ) )
+ tip( it.key()->rect(), it.data() );
+ }
+#endif
+ }
+
+private:
+ QMap<QTab *, QString> tabTips;
+};
+#endif
+
+/*!
+ \fn void QTabBar::selected( int id )
+
+ QTabBar emits this signal whenever any tab is selected, whether by
+ the program or by the user. The argument \a id is the id of the
+ tab as returned by addTab().
+
+ show() is guaranteed to emit this signal; you can display your
+ page in a slot connected to this signal.
+*/
+
+/*!
+ \fn void QTabBar::layoutChanged()
+
+ QTabBar emits the signal whenever the layout of the tab bar has
+ been recalculated, for example when the contents of a tab change.
+*/
+
+/*!
+ Constructs a new, empty tab bar; the \a parent and \a name
+ arguments are passed on to the QWidget constructor.
+*/
+
+QTabBar::QTabBar( QWidget * parent, const char *name )
+ : QWidget( parent, name, WNoAutoErase | WNoMousePropagation )
+{
+ d = new QTabPrivate;
+ d->pressed = 0;
+ d->id = 0;
+ d->focus = 0;
+ d->toolTips = 0;
+#ifndef QT_NO_ACCEL
+ d->a = new QAccel( this, "tab accelerators" );
+ connect( d->a, SIGNAL(activated(int)), this, SLOT(setCurrentTab(int)) );
+ connect( d->a, SIGNAL(activatedAmbiguously(int)), this, SLOT(setCurrentTab(int)) );
+#endif
+ d->s = RoundedAbove;
+ d->scrolls = FALSE;
+ d->leftB = new QToolButton( LeftArrow, this, "qt_left_btn" );
+ connect( d->leftB, SIGNAL( clicked() ), this, SLOT( scrollTabs() ) );
+ d->leftB->hide();
+ d->rightB = new QToolButton( RightArrow, this, "qt_right_btn" );
+ connect( d->rightB, SIGNAL( clicked() ), this, SLOT( scrollTabs() ) );
+ d->rightB->hide();
+ d->btnWidth = style().pixelMetric(QStyle::PM_TabBarScrollButtonWidth, this);
+ l = new QPtrList<QTab>;
+ lstatic = new QPtrList<QTab>;
+ lstatic->setAutoDelete( TRUE );
+ setFocusPolicy( TabFocus );
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+}
+
+
+/*!
+ Destroys the tab control, freeing memory used.
+*/
+
+QTabBar::~QTabBar()
+{
+#ifndef QT_NO_TOOLTIP
+ if ( d->toolTips )
+ delete d->toolTips;
+#endif
+ delete d;
+ d = 0;
+ delete l;
+ l = 0;
+ delete lstatic;
+ lstatic = 0;
+}
+
+
+/*!
+ Adds the tab, \a newTab, to the tab control.
+
+ Sets \a newTab's id to a new id and places the tab just to the
+ right of the existing tabs. If the tab's label contains an
+ ampersand, the letter following the ampersand is used as an
+ accelerator for the tab, e.g. if the label is "Bro\&wse" then
+ Alt+W becomes an accelerator which will move the focus to this
+ tab. Returns the id.
+
+ \sa insertTab()
+*/
+
+int QTabBar::addTab( QTab * newTab )
+{
+ return insertTab( newTab );
+}
+
+
+/*!
+ Inserts the tab, \a newTab, into the tab control.
+
+ If \a index is not specified, the tab is simply appended.
+ Otherwise it's inserted at the specified position.
+
+ Sets \a newTab's id to a new id. If the tab's label contains an
+ ampersand, the letter following the ampersand is used as an
+ accelerator for the tab, e.g. if the label is "Bro\&wse" then
+ Alt+W becomes an accelerator which will move the focus to this
+ tab. Returns the id.
+
+ \sa addTab()
+*/
+
+int QTabBar::insertTab( QTab * newTab, int index )
+{
+ newTab->id = d->id++;
+ if ( !tab( d->focus ) )
+ d->focus = newTab->id;
+
+ newTab->setTabBar( this );
+ l->insert( 0, newTab );
+ if ( index < 0 || index > int(lstatic->count()) )
+ lstatic->append( newTab );
+ else
+ lstatic->insert( index, newTab );
+
+ layoutTabs();
+ updateArrowButtons();
+ makeVisible( tab( currentTab() ) );
+
+#ifndef QT_NO_ACCEL
+ int p = QAccel::shortcutKey( newTab->label );
+ if ( p )
+ d->a->insertItem( p, newTab->id );
+#endif
+
+ return newTab->id;
+}
+
+
+/*!
+ Removes tab \a t from the tab control, and deletes the tab.
+*/
+void QTabBar::removeTab( QTab * t )
+{
+ //#### accelerator labels??
+#ifndef QT_NO_TOOLTIP
+ if ( d->toolTips )
+ d->toolTips->remove( t );
+#endif
+#ifndef QT_NO_ACCEL
+ if ( d->a )
+ d->a->removeItem( t->id );
+#endif
+ bool updateFocus = t->id == d->focus;
+ // remove the TabBar Reference
+ if(d->pressed == t)
+ d->pressed = 0;
+ t->setTabBar( 0 );
+ l->remove( t );
+ lstatic->remove( t );
+ layoutTabs();
+ updateArrowButtons();
+ makeVisible( tab( currentTab() ) );
+ if ( updateFocus )
+ d->focus = currentTab();
+ update();
+}
+
+
+/*!
+ Enables tab \a id if \a enabled is TRUE or disables it if \a
+ enabled is FALSE. If \a id is currently selected,
+ setTabEnabled(FALSE) makes another tab selected.
+
+ setTabEnabled() updates the display if this causes a change in \a
+ id's status.
+
+ \sa update(), isTabEnabled()
+*/
+
+void QTabBar::setTabEnabled( int id, bool enabled )
+{
+ QTab * t;
+ for( t = l->first(); t; t = l->next() ) {
+ if ( t && t->id == id ) {
+ if ( t->enabled != enabled ) {
+ t->enabled = enabled;
+#ifndef QT_NO_ACCEL
+ d->a->setItemEnabled( t->id, enabled );
+#endif
+ QRect r( t->r );
+ if ( !enabled && id == currentTab() ) {
+ QPoint p1( t->r.center() ), p2;
+ int m = 2147483647;
+ int distance;
+ // look for the closest enabled tab - measure the
+ // distance between the centers of the two tabs
+ for( QTab * n = l->first(); n; n = l->next() ) {
+ if ( n->enabled ) {
+ p2 = n->r.center();
+ distance = (p2.x() - p1.x())*(p2.x() - p1.x()) +
+ (p2.y() - p1.y())*(p2.y() - p1.y());
+ if ( distance < m ) {
+ t = n;
+ m = distance;
+ }
+ }
+ }
+ if ( t->enabled ) {
+ r = r.unite( t->r );
+ l->append( l->take( l->findRef( t ) ) );
+ emit selected( t->id );
+ }
+ }
+ repaint( r, FALSE );
+ }
+ return;
+ }
+ }
+}
+
+
+/*!
+ Returns TRUE if the tab with id \a id exists and is enabled;
+ otherwise returns FALSE.
+
+ \sa setTabEnabled()
+*/
+
+bool QTabBar::isTabEnabled( int id ) const
+{
+ QTab * t = tab( id );
+ if ( t )
+ return t->enabled;
+ return FALSE;
+}
+
+
+
+/*!
+ \reimp
+*/
+QSize QTabBar::sizeHint() const
+{
+ QSize sz(0, 0);
+ if ( QTab * t = l->first() ) {
+ QRect r( t->r );
+ while ( (t = l->next()) != 0 )
+ r = r.unite( t->r );
+ sz = r.size();
+ }
+ return sz.expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+
+QSize QTabBar::minimumSizeHint() const
+{
+ if(style().styleHint( QStyle::SH_TabBar_PreferNoArrows, this ))
+ return sizeHint();
+ return QSize( d->rightB->sizeHint().width() * 2 + 75, sizeHint().height() );
+}
+
+/*!
+ Paints the tab \a t using painter \a p. If and only if \a selected
+ is TRUE, \a t is drawn currently selected.
+
+ This virtual function may be reimplemented to change the look of
+ QTabBar. If you decide to reimplement it, you may also need to
+ reimplement sizeHint().
+*/
+
+void QTabBar::paint( QPainter * p, QTab * t, bool selected ) const
+{
+ QStyle::SFlags flags = QStyle::Style_Default;
+
+ if (isEnabled() && t->isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (topLevelWidget() == qApp->activeWindow())
+ flags |= QStyle::Style_Active;
+ if ( selected )
+ flags |= QStyle::Style_Selected;
+ else if(t == d->pressed)
+ flags |= QStyle::Style_Sunken;
+ //selection flags
+ if(t->rect().contains(mapFromGlobal(QCursor::pos())))
+ flags |= QStyle::Style_MouseOver;
+ style().drawControl( QStyle::CE_TabBarTab, p, this, t->rect(),
+ colorGroup(), flags, QStyleOption(t) );
+
+ QRect r( t->r );
+ p->setFont( font() );
+
+ int iw = 0;
+ int ih = 0;
+ if ( t->iconset != 0 ) {
+ iw = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4;
+ ih = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).height();
+ }
+ QFontMetrics fm = p->fontMetrics();
+ int fw = fm.width( t->label );
+ fw -= t->label.contains('&') * fm.width('&');
+ fw += t->label.contains("&&") * fm.width('&');
+ int w = iw + fw + 4;
+ int h = QMAX(fm.height() + 4, ih );
+ int offset = 3;
+#ifdef Q_WS_MAC
+ if (::qt_cast<QMacStyle *>(&style()))
+ offset = 0;
+#endif
+ paintLabel( p, QRect( r.left() + (r.width()-w)/2 - offset,
+ r.top() + (r.height()-h)/2,
+ w, h ), t, t->id == keyboardFocusTab() );
+}
+
+/*!
+ Paints the label of tab \a t centered in rectangle \a br using
+ painter \a p. A focus indication is drawn if \a has_focus is TRUE.
+*/
+
+void QTabBar::paintLabel( QPainter* p, const QRect& br,
+ QTab* t, bool has_focus ) const
+{
+ QRect r = br;
+ bool selected = currentTab() == t->id;
+ if ( t->iconset) {
+ // the tab has an iconset, draw it in the right mode
+ QIconSet::Mode mode = (t->enabled && isEnabled())
+ ? QIconSet::Normal : QIconSet::Disabled;
+ if ( mode == QIconSet::Normal && has_focus )
+ mode = QIconSet::Active;
+ QPixmap pixmap = t->iconset->pixmap( QIconSet::Small, mode );
+ int pixw = pixmap.width();
+ int pixh = pixmap.height();
+ r.setLeft( r.left() + pixw + 4 );
+ r.setRight( r.right() + 2 );
+
+ int xoff = 0, yoff = 0;
+ if(!selected) {
+ xoff = style().pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, this);
+ yoff = style().pixelMetric(QStyle::PM_TabBarTabShiftVertical, this);
+ }
+ p->drawPixmap( br.left() + 2 + xoff, br.center().y()-pixh/2 + yoff, pixmap );
+ }
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+
+ if (isEnabled() && t->isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (has_focus)
+ flags |= QStyle::Style_HasFocus;
+ if ( selected )
+ flags |= QStyle::Style_Selected;
+ else if(t == d->pressed)
+ flags |= QStyle::Style_Sunken;
+ if(t->rect().contains(mapFromGlobal(QCursor::pos())))
+ flags |= QStyle::Style_MouseOver;
+ style().drawControl( QStyle::CE_TabBarLabel, p, this, r,
+ t->isEnabled() ? colorGroup(): palette().disabled(),
+ flags, QStyleOption(t) );
+}
+
+
+/*!
+ Repaints the tab row. All the painting is done by paint();
+ paintEvent() only decides which tabs need painting and in what
+ order. The event is passed in \a e.
+
+ \sa paint()
+*/
+
+void QTabBar::paintEvent( QPaintEvent * e )
+{
+ if ( e->rect().isNull() )
+ return;
+
+ QSharedDoubleBuffer buffer( this, e->rect() );
+
+ QTab * t;
+ t = l->first();
+ do {
+ QTab * n = l->next();
+ if ( t && t->r.intersects( e->rect() ) )
+ paint( buffer.painter(), t, n == 0 );
+ t = n;
+ } while ( t != 0 );
+
+ if ( d->scrolls && lstatic->first()->r.left() < 0 ) {
+ QPointArray a;
+ int h = height();
+ if ( d->s == RoundedAbove ) {
+ buffer.painter()->fillRect( 0, 3, 4, h-5,
+ colorGroup().brush( QColorGroup::Background ) );
+ a.setPoints( 5, 0,2, 3,h/4, 0,h/2, 3,3*h/4, 0,h );
+ } else if ( d->s == RoundedBelow ) {
+ buffer.painter()->fillRect( 0, 2, 4, h-5,
+ colorGroup().brush( QColorGroup::Background ) );
+ a.setPoints( 5, 0,0, 3,h/4, 0,h/2, 3,3*h/4, 0,h-3 );
+ }
+
+ if ( !a.isEmpty() ) {
+ buffer.painter()->setPen( colorGroup().light() );
+ buffer.painter()->drawPolyline( a );
+ a.translate( 1, 0 );
+ buffer.painter()->setPen( colorGroup().midlight() );
+ buffer.painter()->drawPolyline( a );
+ }
+ }
+}
+
+
+/*!
+ This virtual function is called by the mouse event handlers to
+ determine which tab is pressed. The default implementation returns
+ a pointer to the tab whose bounding rectangle contains \a p, if
+ exactly one tab's bounding rectangle contains \a p. Otherwise it
+ returns 0.
+
+ \sa mousePressEvent() mouseReleaseEvent()
+*/
+
+QTab * QTabBar::selectTab( const QPoint & p ) const
+{
+ QTab * selected = 0;
+ bool moreThanOne = FALSE;
+
+ QPtrListIterator<QTab> i( *l );
+ while( i.current() ) {
+ QTab * t = i.current();
+ ++i;
+
+ if ( t && t->r.contains( p ) ) {
+ if ( selected )
+ moreThanOne = TRUE;
+ else
+ selected = t;
+ }
+ }
+
+ return moreThanOne ? 0 : selected;
+}
+
+
+/*!
+ \reimp
+*/
+void QTabBar::mousePressEvent( QMouseEvent * e )
+{
+ if ( e->button() != LeftButton ) {
+ e->ignore();
+ return;
+ }
+ QTab *t = selectTab( e->pos() );
+ if ( t && t->enabled ) {
+ d->pressed = t;
+ if(e->type() == style().styleHint( QStyle::SH_TabBar_SelectMouseType, this ))
+ setCurrentTab( t );
+ else
+ repaint(t->rect(), FALSE);
+ }
+}
+
+
+/*!
+ \reimp
+*/
+
+void QTabBar::mouseMoveEvent ( QMouseEvent *e )
+{
+ if ( e->state() != LeftButton ) {
+ e->ignore();
+ return;
+ }
+ if(style().styleHint( QStyle::SH_TabBar_SelectMouseType, this ) == QEvent::MouseButtonRelease) {
+ QTab *t = selectTab( e->pos() );
+ if(t != d->pressed) {
+ if(d->pressed)
+ repaint(d->pressed->rect(), FALSE);
+ if((d->pressed = t))
+ repaint(t->rect(), FALSE);
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QTabBar::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ e->ignore();
+ if(d->pressed) {
+ QTab *t = selectTab( e->pos() ) == d->pressed ? d->pressed : 0;
+ d->pressed = 0;
+ if(t && t->enabled && e->type() == style().styleHint( QStyle::SH_TabBar_SelectMouseType, this ))
+ setCurrentTab( t );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QTabBar::show()
+{
+ // ensures that one tab is selected.
+ QTab * t = l->last();
+ QWidget::show();
+
+ if ( t )
+ emit selected( t->id );
+}
+
+/*!
+ \property QTabBar::currentTab
+ \brief the id of the tab bar's visible tab
+
+ If no tab page is currently visible, the property's value is -1.
+ Even if the property's value is not -1, you cannot assume that the
+ user can see the relevant page, or that the tab is enabled. When
+ you need to display something the value of this property
+ represents the best page to display.
+
+ When this property is set to \e id, it will raise the tab with the
+ id \e id and emit the selected() signal.
+
+ \sa selected() isTabEnabled()
+*/
+
+int QTabBar::currentTab() const
+{
+ const QTab * t = l->getLast();
+
+ return t ? t->id : -1;
+}
+
+void QTabBar::setCurrentTab( int id )
+{
+ setCurrentTab( tab( id ) );
+}
+
+
+/*!
+ \overload
+
+ Raises \a tab and emits the selected() signal unless the tab was
+ already current.
+
+ \sa currentTab() selected()
+*/
+
+void QTabBar::setCurrentTab( QTab * tab )
+{
+ if ( tab && l ) {
+ if ( l->last() == tab )
+ return;
+
+ QRect r = l->last()->r;
+ if ( l->findRef( tab ) >= 0 )
+ l->append( l->take() );
+
+ d->focus = tab->id;
+
+ setMicroFocusHint( tab->rect().x(), tab->rect().y(), tab->rect().width(), tab->rect().height(), FALSE );
+
+ if ( tab->r.intersects( r ) ) {
+ repaint( r.unite( tab->r ), FALSE );
+ } else {
+#ifdef Q_WS_MACX
+ update();
+#else
+ repaint( r, FALSE );
+ repaint( tab->r, FALSE );
+#endif
+ }
+ makeVisible( tab );
+ emit selected( tab->id );
+
+#ifdef QT_ACCESSIBILITY_SUPPORT
+ QAccessible::updateAccessibility( this, indexOf(tab->id)+1, QAccessible::Focus );
+#endif
+ }
+}
+
+/*!
+ \property QTabBar::keyboardFocusTab
+ \brief the id of the tab that has the keyboard focus
+
+ This property contains the id of the tab that has the keyboard
+ focus or -1 if the tab bar does not have the keyboard focus.
+*/
+
+int QTabBar::keyboardFocusTab() const
+{
+ return hasFocus() ? d->focus : -1;
+}
+
+
+/*!
+ \reimp
+*/
+void QTabBar::keyPressEvent( QKeyEvent * e )
+{
+ // The right and left arrow keys move a selector, the spacebar
+ // makes the tab with the selector active. All other keys are
+ // ignored.
+
+ int old = d->focus;
+
+ bool reverse = QApplication::reverseLayout();
+ if ( ( !reverse && e->key() == Key_Left ) || ( reverse && e->key() == Key_Right ) ) {
+ // left - skip past any disabled ones
+ if ( d->focus >= 0 ) {
+ QTab * t = lstatic->last();
+ while ( t && t->id != d->focus )
+ t = lstatic->prev();
+ do {
+ t = lstatic->prev();
+ } while ( t && !t->enabled);
+ if (t)
+ d->focus = t->id;
+ }
+ if ( d->focus < 0 )
+ d->focus = old;
+ } else if ( ( !reverse && e->key() == Key_Right ) || ( reverse && e->key() == Key_Left ) ) {
+ QTab * t = lstatic->first();
+ while ( t && t->id != d->focus )
+ t = lstatic->next();
+ do {
+ t = lstatic->next();
+ } while ( t && !t->enabled);
+
+ if (t)
+ d->focus = t->id;
+ if ( d->focus >= d->id )
+ d->focus = old;
+ } else {
+ // other keys - ignore
+ e->ignore();
+ return;
+ }
+
+ // if the focus moved, repaint and signal
+ if ( old != d->focus ) {
+ setCurrentTab( d->focus );
+ }
+}
+
+
+/*!
+ Returns the tab with id \a id or 0 if there is no such tab.
+
+ \sa count()
+*/
+
+QTab * QTabBar::tab( int id ) const
+{
+ QTab * t;
+ for( t = l->first(); t; t = l->next() )
+ if ( t && t->id == id )
+ return t;
+ return 0;
+}
+
+
+/*!
+ Returns the tab at position \a index.
+
+ \sa indexOf()
+*/
+
+QTab * QTabBar::tabAt( int index ) const
+{
+ QTab * t;
+ t = lstatic->at( index );
+ return t;
+}
+
+
+/*!
+ Returns the position index of the tab with id \a id or -1 if no
+ tab has this \a id.
+
+ \sa tabAt()
+*/
+int QTabBar::indexOf( int id ) const
+{
+ QTab * t;
+ int idx = 0;
+ for( t = lstatic->first(); t; t = lstatic->next() ) {
+ if ( t && t->id == id )
+ return idx;
+ idx++;
+ }
+ return -1;
+}
+
+
+/*!
+ \property QTabBar::count
+ \brief the number of tabs in the tab bar
+
+ \sa tab()
+*/
+int QTabBar::count() const
+{
+ return l->count();
+}
+
+
+/*!
+ The list of QTab objects in the tab bar.
+
+ This list is unlikely to be in the order that the QTab elements
+ appear visually. One way of iterating over the tabs is like this:
+ \code
+ for ( uint i = 0; i < myTabBar->count(); ++i ) {
+ nextTab = myTabBar->tabAt( i );
+ // do something with nextTab
+ }
+ \endcode
+*/
+QPtrList<QTab> * QTabBar::tabList()
+{
+ return l;
+}
+
+
+/*!
+ \property QTabBar::shape
+ \brief the shape of the tabs in the tab bar
+
+ The value of this property is one of the following: \c
+ RoundedAbove (default), \c RoundedBelow, \c TriangularAbove or \c
+ TriangularBelow.
+
+ \sa Shape
+*/
+QTabBar::Shape QTabBar::shape() const
+{
+ return d ? d->s : RoundedAbove;
+}
+
+void QTabBar::setShape( Shape s )
+{
+ if ( !d || d->s == s )
+ return;
+ //######### must recalculate heights
+ d->s = s;
+ update();
+}
+
+/*!
+ Lays out all existing tabs according to their label and their
+ iconset.
+ */
+void QTabBar::layoutTabs()
+{
+ if ( lstatic->isEmpty() )
+ return;
+
+ QSize oldSh(0, 0);
+ if ( QTab * t = l->first() ) {
+ QRect r( t->r );
+ while ( (t = l->next()) != 0 )
+ r = r.unite( t->r );
+ oldSh = r.size();
+ }
+
+ d->btnWidth = style().pixelMetric(QStyle::PM_TabBarScrollButtonWidth, this);
+ int hframe, vframe, overlap;
+ hframe = style().pixelMetric( QStyle::PM_TabBarTabHSpace, this );
+ vframe = style().pixelMetric( QStyle::PM_TabBarTabVSpace, this );
+ overlap = style().pixelMetric( QStyle::PM_TabBarTabOverlap, this );
+
+ QFontMetrics fm = fontMetrics();
+ QRect r;
+ QTab *t;
+ bool reverse = QApplication::reverseLayout();
+ if ( reverse )
+ t = lstatic->last();
+ else
+ t = lstatic->first();
+ int x = 0;
+ int offset = (t && d->scrolls) ? t->r.x() : 0;
+ while ( t ) {
+ int lw = fm.width( t->label );
+ lw -= t->label.contains('&') * fm.width('&');
+ lw += t->label.contains("&&") * fm.width('&');
+ int iw = 0;
+ int ih = 0;
+ if ( t->iconset != 0 ) {
+ iw = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4;
+ ih = t->iconset->pixmap( QIconSet::Small, QIconSet::Normal ).height();
+ }
+ int h = QMAX( fm.height(), ih );
+ h = QMAX( h, QApplication::globalStrut().height() );
+
+ h += vframe;
+ t->r = QRect(QPoint(x, 0), style().sizeFromContents(QStyle::CT_TabBarTab, this,
+ QSize( QMAX( lw + hframe + iw, QApplication::globalStrut().width() ), h ),
+ QStyleOption(t) ));
+ x += t->r.width() - overlap;
+ r = r.unite( t->r );
+ if ( reverse )
+ t = lstatic->prev();
+ else
+ t = lstatic->next();
+ }
+ x += overlap;
+ int w = (d->scrolls) ? d->leftB->x() : width();
+ if (x + offset < w)
+ offset = w - x;
+ if (offset > 0)
+ offset = 0;
+
+ for ( t = lstatic->first(); t; t = lstatic->next() ) {
+ t->r.moveBy( offset, 0 );
+ t->r.setHeight( r.height() );
+ }
+
+ if ( sizeHint() != oldSh )
+ updateGeometry();
+
+ emit layoutChanged();
+}
+
+/*!
+ \reimp
+*/
+
+bool QTabBar::event( QEvent *e )
+{
+ if ( e->type() == QEvent::LanguageChange ) {
+ layoutTabs();
+ updateArrowButtons();
+ makeVisible( tab( currentTab() ));
+ }
+
+ return QWidget::event( e );
+}
+
+/*!
+ \reimp
+*/
+
+void QTabBar::styleChange( QStyle& old )
+{
+ layoutTabs();
+ updateArrowButtons();
+ QWidget::styleChange( old );
+}
+
+/*!
+ \reimp
+*/
+void QTabBar::focusInEvent( QFocusEvent * )
+{
+ QTab *t = tab( d->focus );
+ if ( t )
+ repaint( t->r, FALSE );
+}
+
+/*!
+ \reimp
+*/
+void QTabBar::focusOutEvent( QFocusEvent * )
+{
+ QTab *t = tab( d->focus );
+ if ( t )
+ repaint( t->r, FALSE );
+}
+
+/*!
+ \reimp
+*/
+void QTabBar::resizeEvent( QResizeEvent * )
+{
+ const int arrowWidth = QMAX( d->btnWidth, QApplication::globalStrut().width() );;
+ d->rightB->setGeometry( width() - arrowWidth, 0, arrowWidth, height() );
+ d->leftB->setGeometry( width() - 2*arrowWidth, 0, arrowWidth, height() );
+ layoutTabs();
+ updateArrowButtons();
+ makeVisible( tab( currentTab() ));
+}
+
+void QTabBar::scrollTabs()
+{
+ QTab* left = 0;
+ QTab* right = 0;
+ for ( QTab* t = lstatic->first(); t; t = lstatic->next() ) {
+ if ( t->r.left() < 0 && t->r.right() > 0 )
+ left = t;
+ if ( t->r.left() < d->leftB->x()+2 )
+ right = t;
+ }
+
+ if ( sender() == d->leftB )
+ makeVisible( left );
+ else if ( sender() == d->rightB )
+ makeVisible( right );
+}
+
+void QTabBar::makeVisible( QTab* tab )
+{
+ bool tooFarLeft = ( tab && tab->r.left() < 0 );
+ bool tooFarRight = ( tab && tab->r.right() >= d->leftB->x() );
+
+ if ( !d->scrolls || ( !tooFarLeft && ! tooFarRight ) )
+ return;
+
+ bool bs = signalsBlocked();
+ blockSignals(TRUE);
+ layoutTabs();
+ blockSignals(bs);
+
+ int offset = 0;
+
+ if ( tooFarLeft ) {
+ offset = tab->r.left();
+ if (tab != lstatic->first())
+ offset -= 8;
+ } else if ( tooFarRight ) {
+ offset = tab->r.right() - d->leftB->x() + 1;
+ }
+
+ for ( QTab* t = lstatic->first(); t; t = lstatic->next() )
+ t->r.moveBy( -offset, 0 );
+
+ d->leftB->setEnabled( lstatic->first()->r.left() < 0);
+ d->rightB->setEnabled( lstatic->last()->r.right() >= d->leftB->x() );
+
+ // Make sure disabled buttons pop up again
+ if ( !d->leftB->isEnabled() && d->leftB->isDown() )
+ d->leftB->setDown( FALSE );
+ if ( !d->rightB->isEnabled() && d->rightB->isDown() )
+ d->rightB->setDown( FALSE );
+
+ update();
+ emit layoutChanged();
+}
+
+void QTabBar::updateArrowButtons()
+{
+ if (lstatic->isEmpty()) {
+ d->scrolls = FALSE;
+ } else {
+ d->scrolls = (lstatic->last()->r.right() - lstatic->first()->r.left() > width());
+ }
+ if ( d->scrolls ) {
+ const int arrowWidth = QMAX( d->btnWidth, QApplication::globalStrut().width() );
+ if ( QApplication::reverseLayout() ) {
+ d->rightB->setGeometry( arrowWidth, 0, arrowWidth, height() );
+ d->leftB->setGeometry( 0, 0, arrowWidth, height() );
+ } else {
+ d->rightB->setGeometry( width() - arrowWidth, 0, arrowWidth, height() );
+ d->leftB->setGeometry( width() - 2*arrowWidth, 0, arrowWidth, height() );
+ }
+
+ d->leftB->setEnabled( lstatic->first()->r.left() < 0);
+ d->rightB->setEnabled( lstatic->last()->r.right() >= d->leftB->x() );
+ d->leftB->show();
+ d->rightB->show();
+ } else {
+ d->leftB->hide();
+ d->rightB->hide();
+ layoutTabs();
+ }
+}
+
+/*!
+ Removes the tool tip for the tab at index position \a index.
+*/
+void QTabBar::removeToolTip( int index )
+{
+#ifndef QT_NO_TOOLTIP
+ QTab * tab = tabAt( index );
+ if ( !tab || !d->toolTips )
+ return;
+ d->toolTips->remove( tab );
+#endif
+}
+
+/*!
+ Sets the tool tip for the tab at index position \a index to \a
+ tip.
+*/
+void QTabBar::setToolTip( int index, const QString & tip )
+{
+#ifndef QT_NO_TOOLTIP
+ QTab * tab = tabAt( index );
+ if ( !tab )
+ return;
+ if ( d->toolTips == 0 )
+ d->toolTips = new QTabBarToolTip( this );
+ d->toolTips->add( tab, tip );
+#endif
+}
+
+/*!
+ Returns the tool tip for the tab at index position \a index.
+*/
+QString QTabBar::toolTip( int index ) const
+{
+#ifndef QT_NO_TOOLTIP
+ if ( d->toolTips )
+ return d->toolTips->tipForTab( tabAt( index ) );
+ else
+#endif
+ return QString();
+}
+
+/*!
+ Sets the text of the tab to \a text.
+*/
+void QTab::setText( const QString& text )
+{
+ label = text;
+ if ( tb ) {
+#ifndef QT_NO_ACCEL
+ tb->d->a->removeItem( id );
+ int p = QAccel::shortcutKey( text );
+ if ( p )
+ tb->d->a->insertItem( p, id );
+#endif
+ tb->layoutTabs();
+ tb->repaint(FALSE);
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( tb, tb->indexOf(id)+1, QAccessible::NameChanged );
+#endif
+ }
+}
+
+/*!
+ Sets the tab's iconset to \a icon
+*/
+void QTab::setIconSet( const QIconSet &icon )
+{
+ iconset = new QIconSet( icon );
+}
+
+// this allows us to handle accelerators that are in a QTabBar.
+void QTab::setTabBar( QTabBar *newTb )
+{
+ tb = newTb;
+}
+
+/*!
+ \internal
+*/
+void QTabBar::fontChange( const QFont & oldFont )
+{
+ layoutTabs();
+ QWidget::fontChange( oldFont );
+}
+
+#endif
diff --git a/src/widgets/qtabbar.h b/src/widgets/qtabbar.h
new file mode 100644
index 0000000..063f34a
--- /dev/null
+++ b/src/widgets/qtabbar.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Definition of QTab and QTabBar classes
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTABBAR_H
+#define QTABBAR_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qptrlist.h"
+#endif // QT_H
+
+#ifndef QT_NO_TABBAR
+
+class QTabBar;
+class QIconSet;
+
+class Q_EXPORT QTab : public Qt
+{
+ friend class QTabBar;
+ friend class QTabWidget;
+
+public:
+ QTab();
+ virtual ~QTab();
+ QTab( const QString& text );
+ QTab( const QIconSet& icon, const QString& text = QString::null );
+
+ void setText( const QString& text);
+ QString text() const { return label; }
+ void setIconSet( const QIconSet& icon );
+ QIconSet* iconSet() const { return iconset; }
+ void setRect( const QRect& rect ) { r = rect; }
+ QRect rect() const { return r; }
+ void setEnabled( bool enable ) { enabled = enable; }
+ bool isEnabled() const { return enabled; }
+ void setIdentifier( int i ) { id = i; }
+ int identifier() const { return id; }
+
+private:
+ void setTabBar( QTabBar *tb );
+ QString label;
+ QRect r; // the bounding rectangle of this (may overlap with others)
+ bool enabled;
+ int id;
+ QIconSet* iconset; // optional iconset
+ QTabBar *tb;
+};
+
+
+struct QTabPrivate;
+//class *QAccel;
+
+class Q_EXPORT QTabBar: public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS( Shape )
+ Q_PROPERTY( Shape shape READ shape WRITE setShape )
+ Q_PROPERTY( int currentTab READ currentTab WRITE setCurrentTab )
+ Q_PROPERTY( int count READ count )
+ Q_PROPERTY( int keyboardFocusTab READ keyboardFocusTab )
+
+public:
+ QTabBar( QWidget* parent=0, const char* name=0 );
+ ~QTabBar();
+
+ enum Shape { RoundedAbove, RoundedBelow,
+ TriangularAbove, TriangularBelow };
+
+ Shape shape() const;
+ virtual void setShape( Shape );
+
+ void show();
+
+ virtual int addTab( QTab * );
+ virtual int insertTab( QTab *, int index = -1 );
+ virtual void removeTab( QTab * );
+
+ virtual void setTabEnabled( int, bool );
+ bool isTabEnabled( int ) const;
+
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ int currentTab() const;
+ int keyboardFocusTab() const;
+
+ QTab * tab( int ) const;
+ QTab * tabAt( int ) const;
+ int indexOf( int ) const;
+ int count() const;
+
+ virtual void layoutTabs();
+ virtual QTab * selectTab( const QPoint & p ) const;
+
+ void removeToolTip( int index );
+ void setToolTip( int index, const QString & tip );
+ QString toolTip( int index ) const;
+
+public slots:
+ virtual void setCurrentTab( int );
+ virtual void setCurrentTab( QTab * );
+
+signals:
+ void selected( int );
+ void layoutChanged();
+
+protected:
+ virtual void paint( QPainter *, QTab *, bool ) const; // ### not const
+ virtual void paintLabel( QPainter*, const QRect&, QTab*, bool ) const;
+
+ void focusInEvent( QFocusEvent *e );
+ void focusOutEvent( QFocusEvent *e );
+
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent * );
+ void mousePressEvent ( QMouseEvent * );
+ void mouseMoveEvent ( QMouseEvent * );
+ void mouseReleaseEvent ( QMouseEvent * );
+ void keyPressEvent( QKeyEvent * );
+ void styleChange( QStyle& );
+ void fontChange ( const QFont & );
+
+ bool event( QEvent *e );
+
+ QPtrList<QTab> * tabList();
+
+private slots:
+ void scrollTabs();
+
+private:
+ QPtrList<QTab> * l;
+ QPtrList<QTab> * lstatic;
+ void makeVisible( QTab* t = 0 );
+ void updateArrowButtons();
+ QTabPrivate * d;
+
+ friend class QTabBarToolTip;
+ friend class QTab;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QTabBar( const QTabBar & );
+ QTabBar& operator=( const QTabBar & );
+#endif
+};
+
+
+#endif // QT_NO_TABBAR
+
+#endif // QTABBAR_H
diff --git a/src/widgets/qtabwidget.cpp b/src/widgets/qtabwidget.cpp
new file mode 100644
index 0000000..f4e3d87
--- /dev/null
+++ b/src/widgets/qtabwidget.cpp
@@ -0,0 +1,1097 @@
+/****************************************************************************
+**
+** Implementation of QTabWidget class
+**
+** Created : 990318
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtabwidget.h"
+#ifndef QT_NO_TABWIDGET
+#include "qobjectlist.h"
+#include "qtabbar.h"
+#include "qapplication.h"
+#include "qwidgetstack.h"
+#include "qbitmap.h"
+#include "qaccel.h"
+#include "qstyle.h"
+#include "qpainter.h"
+#include "qtoolbutton.h"
+
+#ifdef Q_OS_MACX
+#include <qmacstyle_mac.h>
+#endif
+
+/*!
+ \class QTabWidget qtabwidget.h
+ \brief The QTabWidget class provides a stack of tabbed widgets.
+
+ \ingroup organizers
+ \ingroup advanced
+ \mainclass
+
+ A tab widget provides a tab bar of tabs and a `page area' below
+ (or above, see \l{TabPosition}) the tabs. Each tab is associated
+ with a different widget (called a `page'). Only the current tab's
+ page is shown in the page area; all the other tabs' pages are
+ hidden. The user can show a different page by clicking on its tab
+ or by pressing its Alt+\e{letter} accelerator if it has one.
+
+ The normal way to use QTabWidget is to do the following in the
+ constructor:
+ \list 1
+ \i Create a QTabWidget.
+ \i Create a QWidget for each of the pages in the tab dialog,
+ insert children into it, set up geometry management for it and use
+ addTab() (or insertTab()) to set up a tab and keyboard accelerator
+ for it.
+ \i Connect to the signals and slots.
+ \endlist
+
+ The position of the tabs is set with setTabPosition(), their shape
+ with setTabShape(), and their margin with setMargin().
+
+ If you don't call addTab() and the QTabWidget is already visible,
+ then the page you have created will not be visible. Don't
+ confuse the object name you supply to the QWidget constructor and
+ the tab label you supply to addTab(). addTab() takes a name which
+ indicates an accelerator and is meaningful and descriptive to the
+ user, whereas the widget name is used primarily for debugging.
+
+ The signal currentChanged() is emitted when the user selects a
+ page.
+
+ The current page is available as an index position with
+ currentPageIndex() or as a wiget pointer with currentPage(). You
+ can retrieve a pointer to a page with a given index using page(),
+ and can find the index position of a page with indexOf(). Use
+ setCurrentPage() to show a particular page by index, or showPage()
+ to show a page by widget pointer.
+
+ You can change a tab's label and iconset using changeTab() or
+ setTabLabel() and setTabIconSet(). A tab page can be removed with
+ removePage().
+
+ 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.
+
+ Although tab widgets can be a very good way to split up a complex
+ dialog, it's also very easy to get into a mess. See QTabDialog for
+ some design hints. An alternative is to use a QWidgetStack for
+ which you provide some means of navigating between pages, for
+ example, a QToolBar or a QListBox.
+
+ Most of the functionality in QTabWidget is provided by a QTabBar
+ (at the top, providing the tabs) and a QWidgetStack (most of the
+ area, organizing the individual pages).
+
+ <img src=qtabwidget-m.png> <img src=qtabwidget-w.png>
+
+ \sa QTabDialog, QToolBox
+*/
+
+/*!
+ \enum Qt::Corner
+ This enum type specifies a corner in a rectangle:
+ \value TopLeft top left corner
+ \value TopRight top right corner
+ \value BottomLeft bottom left corner
+ \value BottomRight bottom right corner
+*/
+
+/*!
+ \enum QTabWidget::TabPosition
+
+ This enum type defines where QTabWidget draws the tab row:
+ \value Top above the pages
+ \value Bottom below the pages
+*/
+
+/*!
+ \enum QTabWidget::TabShape
+
+ This enum type defines the shape of the tabs:
+ \value Rounded rounded look (normal)
+ \value Triangular triangular look (very unusual, included for completeness)
+*/
+
+/* undocumented now
+ \obsolete
+
+ \fn void QTabWidget::selected( const QString &tabLabel );
+
+ This signal is emitted whenever a tab is selected (raised),
+ including during the first show().
+
+ \sa raise()
+*/
+
+
+/*!
+ \fn void QTabWidget::currentChanged( QWidget* );
+
+ This signal is emitted whenever the current page changes. The
+ parameter is the new current page.
+
+ \sa currentPage(), showPage(), tabLabel()
+*/
+
+class QTabBarBase : public QWidget
+{
+public:
+ QTabBarBase( QTabWidget* parent=0, const char* name=0 )
+ : QWidget( parent, name ) {};
+protected:
+ void paintEvent( QPaintEvent * )
+ {
+ QObject * obj = parent();
+ if( obj ){
+ QTabWidget * t = (QTabWidget *) obj;
+ QPainter p( this );
+ QStyle::SFlags flags = QStyle::Style_Default;
+
+ if ( t->tabPosition() == QTabWidget::Top )
+ flags |= QStyle::Style_Top;
+ if ( t->tabPosition() == QTabWidget::Bottom )
+ flags |= QStyle::Style_Bottom;
+ if(parentWidget()->isEnabled())
+ flags |= QStyle::Style_Enabled;
+
+ style().drawPrimitive( QStyle::PE_TabBarBase, &p, rect(),
+ colorGroup(), flags );
+ }
+ }
+};
+
+class QTabWidgetData
+{
+public:
+ QTabWidgetData()
+ : tabs(0), tabBase(0), stack(0), dirty( TRUE ),
+ pos( QTabWidget::Top ), shape( QTabWidget::Rounded ),
+ leftCornerWidget(0), rightCornerWidget(0) {};
+ ~QTabWidgetData(){};
+ QTabBar* tabs;
+ QTabBarBase* tabBase;
+ QWidgetStack* stack;
+ bool dirty;
+ QTabWidget::TabPosition pos;
+ QTabWidget::TabShape shape;
+ int alignment;
+ QWidget* leftCornerWidget;
+ QWidget* rightCornerWidget;
+};
+
+/*!
+ Constructs a tabbed widget called \a name with parent \a parent,
+ and widget flags \a f.
+*/
+QTabWidget::QTabWidget( QWidget *parent, const char *name, WFlags f )
+ : QWidget( parent, name, f )
+{
+ d = new QTabWidgetData;
+ d->stack = new QWidgetStack( this, "tab pages" );
+ d->stack->installEventFilter( this );
+ d->tabBase = new QTabBarBase( this, "tab base" );
+ d->tabBase->resize( 1, 1 );
+ setTabBar( new QTabBar( this, "tab control" ) );
+
+ d->stack->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Raised );
+#ifdef Q_OS_TEMP
+ d->pos = Bottom;
+#endif
+
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
+ setFocusPolicy( TabFocus );
+ setFocusProxy( d->tabs );
+
+ installEventFilter( this );
+#ifdef Q_OS_MACX
+ if (::qt_cast<QMacStyle*>(&style()))
+ setMargin(10); // According to HIGuidelines at least.
+#endif
+}
+
+/*!
+ \reimp
+*/
+QTabWidget::~QTabWidget()
+{
+ delete d;
+}
+
+/*!
+ Adds another tab and page to the tab view.
+
+ The new page is \a child; the tab's label is \a label. Note the
+ difference between the widget name (which you supply to widget
+ constructors and to setTabEnabled(), for example) and the tab
+ label. The name is internal to the program and invariant, whereas
+ the label is shown on-screen and may vary according to language
+ and other factors.
+
+ If the tab's \a label contains an ampersand, the letter following
+ the ampersand is used as an accelerator for the tab, e.g. if the
+ label is "Bro\&wse" then Alt+W becomes an accelerator which will
+ move the focus to this tab.
+
+ If you call addTab() after show() the screen will flicker and the
+ user may be confused.
+
+ Adding the same child twice will have undefined behavior.
+
+ \sa insertTab()
+*/
+void QTabWidget::addTab( QWidget *child, const QString &label)
+{
+ insertTab( child, label );
+}
+
+
+/*!
+ \overload
+
+ Adds another tab and page to the tab view.
+
+ This function is the same as addTab(), but with an additional \a
+ iconset.
+*/
+void QTabWidget::addTab( QWidget *child, const QIconSet& iconset, const QString &label )
+{
+ insertTab( child, iconset, label );
+}
+
+/*!
+ \overload
+
+ This is a low-level function for adding tabs. It is useful if you
+ are using setTabBar() to set a QTabBar subclass with an overridden
+ QTabBar::paint() function for a subclass of QTab. The \a child is
+ the new page and \a tab is the tab to put the \a child on.
+*/
+void QTabWidget::addTab( QWidget *child, QTab* tab )
+{
+ insertTab( child, tab );
+}
+
+
+
+/*!
+ Inserts another tab and page to the tab view.
+
+ The new page is \a child; the tab's label is \a label. Note the
+ difference between the widget name (which you supply to widget
+ constructors and to setTabEnabled(), for example) and the tab
+ label. The name is internal to the program and invariant, whereas
+ the label is shown on-screen and may vary according to language
+ and other factors.
+
+ If the tab's \a label contains an ampersand, the letter following
+ the ampersand is used as an accelerator for the tab, e.g. if the
+ label is "Bro\&wse" then Alt+W becomes an accelerator which will
+ move the focus to this tab.
+
+ If \a index is not specified, the tab is simply appended.
+ Otherwise it is inserted at the specified position.
+
+ If you call insertTab() after show(), the screen will flicker and
+ the user may be confused.
+
+ \sa addTab()
+*/
+void QTabWidget::insertTab( QWidget *child, const QString &label, int index)
+{
+ QTab * t = new QTab();
+ Q_CHECK_PTR( t );
+ t->label = label;
+ insertTab( child, t, index );
+}
+
+
+/*!
+ \overload
+
+ Inserts another tab and page to the tab view.
+
+ This function is the same as insertTab(), but with an additional
+ \a iconset.
+*/
+void QTabWidget::insertTab( QWidget *child, const QIconSet& iconset, const QString &label, int index )
+{
+ QTab * t = new QTab();
+ Q_CHECK_PTR( t );
+ t->label = label;
+ t->iconset = new QIconSet( iconset );
+ insertTab( child, t, index );
+}
+
+/*!
+ \overload
+
+ This is a lower-level method for inserting tabs, similar to the
+ other insertTab() method. It is useful if you are using
+ setTabBar() to set a QTabBar subclass with an overridden
+ QTabBar::paint() function for a subclass of QTab. The \a child is
+ the new page, \a tab is the tab to put the \a child on and \a
+ index is the position in the tab bar that this page should occupy.
+*/
+void QTabWidget::insertTab( QWidget *child, QTab* tab, int index)
+{
+ tab->enabled = TRUE;
+ int id = d->tabs->insertTab( tab, index );
+ d->stack->addWidget( child, id );
+ if ( d->stack->frameStyle() != ( QFrame::TabWidgetPanel | QFrame::Raised ) )
+ d->stack->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Raised );
+ setUpLayout();
+}
+
+
+/*!
+ Defines a new \a label for page \a{w}'s tab.
+*/
+void QTabWidget::changeTab( QWidget *w, const QString &label)
+{
+ int id = d->stack->id( w );
+ if ( id < 0 )
+ return;
+ QTab* t = d->tabs->tab( id );
+ if ( !t )
+ return;
+ // this will update the accelerators
+ t->setText( label );
+
+ d->tabs->layoutTabs();
+ d->tabs->update();
+ setUpLayout();
+}
+
+/*!
+ \overload
+
+ Defines a new \a iconset and a new \a label for page \a{w}'s tab.
+*/
+void QTabWidget::changeTab( QWidget *w, const QIconSet& iconset, const QString &label)
+{
+ int id = d->stack->id( w );
+ if ( id < 0 )
+ return;
+ QTab* t = d->tabs->tab( id );
+ if ( !t )
+ return;
+ if ( t->iconset ) {
+ delete t->iconset;
+ t->iconset = 0;
+ }
+ // this will update the accelerators
+ t->iconset = new QIconSet( iconset );
+ t->setText( label );
+
+ d->tabs->layoutTabs();
+ d->tabs->update();
+ setUpLayout();
+}
+
+/*!
+ Returns TRUE if the page \a w is enabled; otherwise returns FALSE.
+
+ \sa setTabEnabled(), QWidget::isEnabled()
+*/
+
+bool QTabWidget::isTabEnabled( QWidget* w ) const
+{
+ int id = d->stack->id( w );
+ if ( id >= 0 )
+ return w->isEnabled();
+ else
+ return FALSE;
+}
+
+/*!
+ If \a enable is TRUE, page \a w is enabled; otherwise page \a w 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( QWidget* w, bool enable)
+{
+ int id = d->stack->id( w );
+ if ( id >= 0 ) {
+ w->setEnabled( enable );
+ d->tabs->setTabEnabled( id, enable );
+ }
+}
+
+/*!
+ Sets widget \a w to be the shown in the specified \a corner of the
+ tab widget.
+
+ Only the horizontal element of the \a corner will be used.
+
+ \sa cornerWidget(), setTabPosition()
+*/
+void QTabWidget::setCornerWidget( QWidget * w, Qt::Corner corner )
+{
+ if ( !w )
+ return;
+ if ( (uint)corner & 1 )
+ d->rightCornerWidget = w;
+ else
+ d->leftCornerWidget = w;
+}
+
+/*!
+ Returns the widget shown in the \a corner of the tab widget or 0.
+*/
+QWidget * QTabWidget::cornerWidget( Qt::Corner corner ) const
+{
+ if ( (uint)corner & 1 )
+ return d->rightCornerWidget;
+ return d->leftCornerWidget;
+}
+
+/*!
+ Ensures that page \a w is shown. This is useful mainly for
+ accelerators.
+
+ \warning Used carelessly, this function can easily surprise or
+ confuse the user.
+
+ \sa QTabBar::setCurrentTab()
+*/
+void QTabWidget::showPage( QWidget * w)
+{
+ int id = d->stack->id( w );
+ if ( id >= 0 ) {
+ d->stack->raiseWidget( w );
+ d->tabs->setCurrentTab( id );
+ // ### why overwrite the frame style?
+ if ( d->stack->frameStyle() != ( QFrame::TabWidgetPanel |QFrame::Raised ) )
+ d->stack->setFrameStyle( QFrame::TabWidgetPanel | QFrame::Raised );
+ }
+}
+
+/*!
+ Removes page \a w from this stack of widgets. Does not delete \a
+ w.
+
+ \sa addTab(), showPage(), QWidgetStack::removeWidget()
+*/
+void QTabWidget::removePage( QWidget * w )
+{
+ int id = d->stack->id( w );
+ if ( id >= 0 ) {
+ int oldId = d->stack->id(currentPage());
+ bool fixCurrentTab = oldId == id;
+ //switches to the next enabled tab
+ d->tabs->setTabEnabled( id, FALSE );
+ //if no next enabled page we fix the current page
+ fixCurrentTab = fixCurrentTab && oldId == d->stack->id(currentPage());
+
+ d->stack->removeWidget( w );
+ d->tabs->removeTab( d->tabs->tab(id) );
+ if ( fixCurrentTab )
+ showTab( d->tabs->currentTab() );
+ setUpLayout();
+
+ if ( d->tabs->count() == 0 )
+ d->stack->setFrameStyle( QFrame::NoFrame );
+ }
+}
+
+/*!
+ Returns the label text for the tab on page \a w.
+*/
+
+QString QTabWidget::tabLabel( QWidget * w ) const
+{
+ QTab * t = d->tabs->tab( d->stack->id( w ) );
+ return t ? t->label : QString::null;
+}
+
+/*!
+ Sets the tab label for page \a w to \a l
+*/
+
+void QTabWidget::setTabLabel( QWidget * w, const QString &l )
+{
+ QTab * t = d->tabs->tab( d->stack->id( w ) );
+ if ( t )
+ t->label = l;
+ d->tabs->layoutTabs();
+ d->tabs->update();
+ setUpLayout();
+}
+
+/*!
+ 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).
+*/
+
+QWidget * QTabWidget::currentPage() const
+{
+ return page( currentPageIndex() );
+}
+
+/*!
+ \property QTabWidget::autoMask
+ \brief whether the tab widget is automatically masked
+
+ \sa QWidget::setAutoMask()
+*/
+
+/*!
+ \property QTabWidget::currentPage
+ \brief the index position of the current tab page
+
+ \sa QTabBar::currentTab()
+*/
+
+int QTabWidget::currentPageIndex() const
+{
+ return d->tabs->indexOf( d->tabs->currentTab() );
+}
+
+void QTabWidget::setCurrentPage( int index )
+{
+ d->tabs->setCurrentTab( d->tabs->tabAt( index ) );
+ showTab( d->tabs->currentTab() );
+}
+
+
+/*!
+ Returns the index position of page \a w, or -1 if the widget
+ cannot be found.
+*/
+int QTabWidget::indexOf( QWidget* w ) const
+{
+ return d->tabs->indexOf( d->stack->id( 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)
+{
+ if ( tb->parentWidget() != this )
+ tb->reparent( this, QPoint(0,0), TRUE );
+ delete d->tabs;
+ d->tabs = tb;
+ setFocusProxy( d->tabs );
+ connect( d->tabs, SIGNAL(selected(int)),
+ this, SLOT(showTab(int)) );
+ setUpLayout();
+}
+
+
+/*!
+ Returns the current QTabBar.
+
+ \sa setTabBar()
+*/
+QTabBar* QTabWidget::tabBar() const
+{
+ return d->tabs;
+}
+
+/*!
+ Ensures that the selected tab's page is visible and appropriately
+ sized.
+*/
+
+void QTabWidget::showTab( int i )
+{
+ if ( d->stack->widget( i ) ) {
+ d->stack->raiseWidget( i );
+ emit selected( d->tabs->tab( i )->label );
+ emit currentChanged( d->stack->widget( i ) );
+ }
+}
+
+/*
+ Set up the layout.
+*/
+void QTabWidget::setUpLayout( bool onlyCheck )
+{
+ if ( onlyCheck && !d->dirty )
+ return; // nothing to do
+
+ if ( !isVisible() ) {
+ d->dirty = TRUE;
+ return; // we'll do it later
+ }
+
+ QSize t( 0, d->stack->frameWidth() );
+ if ( d->tabs->isVisibleTo(this) )
+ t = d->tabs->sizeHint();
+ int lcw = 0;
+ if ( d->leftCornerWidget && d->leftCornerWidget->isVisible() ) {
+ QSize sz = d->leftCornerWidget->sizeHint();
+ d->leftCornerWidget->resize(sz);
+ lcw = sz.width();
+ if ( t.height() > lcw )
+ lcw = t.height();
+ }
+ int rcw = 0;
+ if ( d->rightCornerWidget && d->rightCornerWidget->isVisible() ) {
+ QSize sz = d->rightCornerWidget->sizeHint();
+ d->rightCornerWidget->resize(sz);
+ rcw = sz.width();
+ if ( t.height() > rcw )
+ rcw = t.height();
+ }
+ int tw = width() - lcw - rcw;
+ if ( t.width() > tw )
+ t.setWidth( tw );
+ int lw = d->stack->lineWidth();
+ bool reverse = QApplication::reverseLayout();
+ int tabx, taby, stacky, exty, exth, overlap;
+
+ exth = style().pixelMetric( QStyle::PM_TabBarBaseHeight, this );
+ overlap = style().pixelMetric( QStyle::PM_TabBarBaseOverlap, this );
+
+ if ( d->pos == Bottom ) {
+ taby = height() - t.height() - lw;
+ stacky = 0;
+ exty = taby - (exth - overlap);
+ } else { // Top
+ taby = 0;
+ stacky = t.height()-lw + (exth - overlap);
+ exty = taby + t.height() - overlap;
+ }
+
+ int lhs = (QMAX( 0, lw - 2 ) + lcw);
+ int alignment = style().styleHint( QStyle::SH_TabBar_Alignment, this );
+ if ( alignment == AlignHCenter && t.width() < width() )
+ tabx = lhs + ((width()-(lcw+rcw))/2 - t.width()/2);
+ else if(reverse || alignment == AlignRight)
+ tabx = QMIN( width() - t.width(), width() - t.width() - lw + 2 ) - lcw;
+ else
+ tabx = lhs;
+
+ d->tabs->setGeometry( tabx, taby, t.width(), t.height() );
+ d->tabBase->setGeometry( 0, exty, width(), exth );
+ if ( exth == 0 )
+ d->tabBase->hide();
+ else
+ d->tabBase->show();
+
+ d->stack->setGeometry( 0, stacky, width(), height() - (exth-overlap) -
+ t.height()+QMAX(0, lw-2));
+
+ d->dirty = FALSE;
+
+ // move cornerwidgets
+ if ( d->leftCornerWidget ) {
+ int y = ( t.height() / 2 ) - ( d->leftCornerWidget->height() / 2 );
+ int x = ( reverse ? width() - lcw + y : y );
+ d->leftCornerWidget->move( x, y + taby );
+ }
+ if ( d->rightCornerWidget ) {
+ int y = ( t.height() / 2 ) - ( d->rightCornerWidget->height() / 2 );
+ int x = ( reverse ? y : width() - rcw + y );
+ d->rightCornerWidget->move( x, y + taby );
+ }
+ if ( !onlyCheck )
+ update();
+ updateGeometry();
+ if ( autoMask() )
+ updateMask();
+}
+
+/*!
+ \reimp
+*/
+QSize QTabWidget::sizeHint() const
+{
+ 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 s( d->stack->sizeHint() );
+ QSize t( d->tabs->sizeHint() );
+ if(!style().styleHint(QStyle::SH_TabBar_PreferNoArrows, d->tabs))
+ t = t.boundedTo( QSize(200,200) );
+ else
+ t = t.boundedTo( QApplication::desktop()->size() );
+
+ QSize sz( QMAX( s.width(), t.width() + rc.width() + lc.width() ),
+ s.height() + (QMAX( rc.height(), QMAX(lc.height(), t.height()))) + ( d->tabBase->isVisible() ? d->tabBase->height() : 0 ) );
+ return style().sizeFromContents(QStyle::CT_TabWidget, this, sz).expandedTo(QApplication::globalStrut());
+}
+
+
+/*!
+ \reimp
+
+ Returns a suitable minimum size for the tab widget.
+*/
+QSize QTabWidget::minimumSizeHint() const
+{
+ 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( QMAX( s.width(), t.width() + rc.width() + lc.width() ),
+ s.height() + (QMAX( rc.height(), QMAX(lc.height(), t.height()))) + ( d->tabBase->isVisible() ? d->tabBase->height() : 0 ) );
+ return style().sizeFromContents(QStyle::CT_TabWidget, this, sz).expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+ */
+void QTabWidget::showEvent( QShowEvent * )
+{
+ setUpLayout();
+}
+
+
+/*!
+ \property QTabWidget::tabPosition
+ \brief the position of the tabs in this tab widget
+
+ Possible values for this property are \c QTabWidget::Top and \c
+ QTabWidget::Bottom.
+
+ \sa TabPosition
+*/
+QTabWidget::TabPosition QTabWidget::tabPosition() const
+{
+ return d->pos;
+}
+
+void QTabWidget::setTabPosition( TabPosition pos)
+{
+ if (d->pos == pos)
+ return;
+ d->pos = pos;
+ if (d->tabs->shape() == QTabBar::TriangularAbove || d->tabs->shape() == QTabBar::TriangularBelow ) {
+ if ( pos == Bottom )
+ d->tabs->setShape( QTabBar::TriangularBelow );
+ else
+ d->tabs->setShape( QTabBar::TriangularAbove );
+ }
+ else {
+ if ( pos == Bottom )
+ d->tabs->setShape( QTabBar::RoundedBelow );
+ else
+ d->tabs->setShape( QTabBar::RoundedAbove );
+ }
+ d->tabs->layoutTabs();
+ setUpLayout();
+}
+
+/*!
+ \property QTabWidget::tabShape
+ \brief the shape of the tabs in this tab widget
+
+ Possible values for this property are \c QTabWidget::Rounded
+ (default) or \c QTabWidget::Triangular.
+
+ \sa TabShape
+*/
+
+QTabWidget::TabShape QTabWidget::tabShape() const
+{
+ return d->shape;
+}
+
+void QTabWidget::setTabShape( TabShape s )
+{
+ if ( d->shape == s )
+ return;
+ d->shape = s;
+ if ( d->pos == Top ) {
+ if ( s == Rounded )
+ d->tabs->setShape( QTabBar::RoundedAbove );
+ else
+ d->tabs->setShape( QTabBar::TriangularAbove );
+ } else {
+ if ( s == Rounded )
+ d->tabs->setShape( QTabBar::RoundedBelow );
+ else
+ d->tabs->setShape( QTabBar::TriangularBelow );
+ }
+ d->tabs->layoutTabs();
+ setUpLayout();
+}
+
+
+/*!
+ \property QTabWidget::margin
+ \brief the margin in this tab widget
+
+ The margin is the distance between the innermost pixel of the
+ frame and the outermost pixel of the pages.
+*/
+int QTabWidget::margin() const
+{
+ return d->stack->margin();
+}
+
+void QTabWidget::setMargin( int w )
+{
+ d->stack->setMargin( w );
+ setUpLayout();
+}
+
+
+/*!
+ \reimp
+ */
+void QTabWidget::styleChange( QStyle& old )
+{
+ QWidget::styleChange( old );
+ setUpLayout();
+}
+
+
+/*!
+ \reimp
+ */
+void QTabWidget::updateMask()
+{
+ if ( !autoMask() )
+ return;
+
+ QRect r;
+ QRegion reg( r );
+ reg += QRegion( d->tabs->geometry() );
+ reg += QRegion( d->stack->geometry() );
+ setMask( reg );
+}
+
+
+/*!
+ \reimp
+ */
+bool QTabWidget::eventFilter( QObject *o, QEvent * e)
+{
+ if ( o == this ) {
+ if ( e->type() == QEvent::LanguageChange || e->type() == QEvent::LayoutHint ) {
+ d->dirty = TRUE;
+ setUpLayout();
+ updateGeometry();
+ } else if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent *ke = (QKeyEvent*) e;
+ if ( ( ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab ) &&
+ count() > 1 &&
+ ke->state() & Qt::ControlButton ) {
+ int page = currentPageIndex();
+ if ( ke->key() == Qt::Key_Backtab || ke->state() & Qt::ShiftButton ) {
+ page--;
+ if ( page < 0 )
+ page = count() - 1;
+ } else {
+ page++;
+ if ( page >= count() )
+ page = 0;
+ }
+ setCurrentPage( page );
+ if ( !qApp->focusWidget() )
+ d->tabs->setFocus();
+ return TRUE;
+ }
+ }
+
+ } else if ( o == d->stack ) {
+ if ( e->type() == QEvent::ChildRemoved
+ && ( (QChildEvent*)e )->child()->isWidgetType() ) {
+ removePage( (QWidget*) ( (QChildEvent*)e )->child() );
+ return TRUE;
+ } else if ( e->type() == QEvent::LayoutHint ) {
+ updateGeometry();
+ }
+ }
+ return FALSE;
+}
+
+/*!
+ Returns the tab page at index position \a index or 0 if the \a
+ index is out of range.
+*/
+QWidget *QTabWidget::page( int index ) const
+{
+ QTab *t = d->tabs->tabAt(index);
+ if ( t )
+ return d->stack->widget( t->id );
+ // else
+ return 0;
+}
+
+/*!
+ Returns the label of the tab at index position \a index or
+ QString::null if the \a index is out of range.
+*/
+QString QTabWidget::label( int index ) const
+{
+ QTab *t = d->tabs->tabAt( index );
+ if ( t )
+ return t->label;
+ // else
+ return QString::null;
+}
+
+/*!
+ \property QTabWidget::count
+ \brief the number of tabs in the tab bar
+*/
+int QTabWidget::count() const
+{
+ return d->tabs->count();
+}
+
+/*!
+ Returns the iconset of page \a w or a \link QIconSet::QIconSet()
+ null iconset\endlink if \a w is not a tab page or does not have an
+ iconset.
+*/
+QIconSet QTabWidget::tabIconSet( QWidget * w ) const
+{
+ int id = d->stack->id( w );
+ if ( id < 0 )
+ return QIconSet();
+ QTab* t = d->tabs->tab( id );
+ if ( !t )
+ return QIconSet();
+ if ( t->iconset )
+ return QIconSet( *t->iconset );
+ else
+ return QIconSet();
+}
+
+/*!
+ Sets the iconset for page \a w to \a iconset.
+*/
+void QTabWidget::setTabIconSet( QWidget * w, const QIconSet & iconset )
+{
+ int id = d->stack->id( w );
+ if ( id < 0 )
+ return;
+ QTab* t = d->tabs->tab( id );
+ if ( !t )
+ return;
+ if ( t->iconset )
+ delete t->iconset;
+ t->iconset = new QIconSet( iconset );
+
+ d->tabs->layoutTabs();
+ d->tabs->update();
+ setUpLayout();
+}
+
+/*!
+ Sets the tab tool tip for page \a w to \a tip.
+
+ \sa removeTabToolTip(), tabToolTip()
+*/
+void QTabWidget::setTabToolTip( QWidget * w, const QString & tip )
+{
+ int index = d->tabs->indexOf( d->stack->id( w ) );
+ if ( index < 0 )
+ return;
+ d->tabs->setToolTip( index, tip );
+}
+
+/*!
+ Returns the tab tool tip for page \a w or QString::null if no tool
+ tip has been set.
+
+ \sa setTabToolTip(), removeTabToolTip()
+*/
+QString QTabWidget::tabToolTip( QWidget * w ) const
+{
+ int index = d->tabs->indexOf( d->stack->id( w ) );
+ if ( index < 0 )
+ return QString();
+ return d->tabs->toolTip( index );
+}
+
+/*!
+ Removes the tab tool tip for page \a w. If the page does not have
+ a tip, nothing happens.
+
+ \sa setTabToolTip(), tabToolTip()
+*/
+void QTabWidget::removeTabToolTip( QWidget * w )
+{
+ int index = d->tabs->indexOf( d->stack->id( w ) );
+ if ( index < 0 )
+ return;
+ d->tabs->removeToolTip( index );
+}
+
+#endif
diff --git a/src/widgets/qtabwidget.h b/src/widgets/qtabwidget.h
new file mode 100644
index 0000000..9c479db
--- /dev/null
+++ b/src/widgets/qtabwidget.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Definition of QTabWidget class
+**
+** Created : 990318
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTABWIDGET_H
+#define QTABWIDGET_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#include "qiconset.h"
+#endif // QT_H
+
+#ifndef QT_NO_TABWIDGET
+
+class QTabBar;
+class QTabWidgetData;
+class QTab;
+class QWidgetStack;
+
+
+class Q_EXPORT QTabWidget : public QWidget
+{
+ Q_OBJECT
+ Q_ENUMS( TabPosition )
+ Q_ENUMS( TabShape )
+ Q_PROPERTY( TabPosition tabPosition READ tabPosition WRITE setTabPosition )
+ Q_PROPERTY( TabShape tabShape READ tabShape WRITE setTabShape )
+ Q_PROPERTY( int margin READ margin WRITE setMargin )
+ Q_PROPERTY( int currentPage READ currentPageIndex WRITE setCurrentPage )
+ Q_PROPERTY( int count READ count )
+ Q_OVERRIDE( bool autoMask DESIGNABLE true SCRIPTABLE true )
+
+public:
+ QTabWidget( QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ ~QTabWidget();
+
+ virtual void addTab( QWidget *, const QString & ); // ### make these inline in 4.0
+ virtual void addTab( QWidget *child, const QIconSet& iconset,
+ const QString &label );
+ virtual void addTab( QWidget *, QTab* );
+
+ virtual void insertTab( QWidget *, const QString &, int index = -1 );
+ virtual void insertTab( QWidget *child, const QIconSet& iconset,
+ const QString &label, int index = -1 );
+ virtual void insertTab( QWidget *, QTab*, int index = -1 );
+
+ void changeTab( QWidget *, const QString &);
+ void changeTab( QWidget *child, const QIconSet& iconset,
+ const QString &label );
+
+ bool isTabEnabled( QWidget * ) const;
+ void setTabEnabled( QWidget *, bool );
+
+ void setCornerWidget( QWidget * w, Qt::Corner corner = Qt::TopRight );
+ QWidget * cornerWidget( Qt::Corner corner = Qt::TopRight ) const;
+
+ QString tabLabel( QWidget * ) const;
+ void setTabLabel( QWidget *p, const QString &l );
+
+ QIconSet tabIconSet( QWidget * w ) const;
+ void setTabIconSet( QWidget * w, const QIconSet & iconset );
+
+ void removeTabToolTip( QWidget * w );
+ void setTabToolTip( QWidget * w, const QString & tip );
+ QString tabToolTip( QWidget * w ) const;
+
+ QWidget * currentPage() const;
+ QWidget *page( int ) const;
+ QString label( int ) const;
+ int currentPageIndex() const;
+ int indexOf( QWidget * ) const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ enum TabPosition { Top, Bottom };
+ TabPosition tabPosition() const;
+ void setTabPosition( TabPosition );
+
+ enum TabShape { Rounded, Triangular };
+ TabShape tabShape() const;
+ void setTabShape( TabShape s );
+
+ int margin() const;
+ void setMargin( int );
+
+ int count() const;
+
+public slots:
+ void setCurrentPage( int );
+ virtual void showPage( QWidget * );
+ virtual void removePage( QWidget * );
+
+protected:
+ void showEvent( QShowEvent * );
+ void resizeEvent( QResizeEvent * );
+ void setTabBar( QTabBar * );
+ QTabBar* tabBar() const;
+ void styleChange( QStyle& );
+ void updateMask();
+ bool eventFilter( QObject *, QEvent * );
+
+signals:
+ void currentChanged( QWidget * );
+#ifndef Q_QDOC
+ void selected( const QString& );
+#endif
+
+private slots:
+ void showTab( int );
+
+private:
+ QTabWidgetData *d;
+ void setUpLayout( bool = FALSE );
+ friend class QTabDialog;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QTabWidget( const QTabWidget & );
+ QTabWidget& operator=( const QTabWidget & );
+#endif
+};
+
+#endif // QT_NO_TABWIDGET
+
+#endif // QTABWIDGET_H
diff --git a/src/widgets/qtextbrowser.cpp b/src/widgets/qtextbrowser.cpp
new file mode 100644
index 0000000..38e280b
--- /dev/null
+++ b/src/widgets/qtextbrowser.cpp
@@ -0,0 +1,555 @@
+/****************************************************************************
+**
+** Implementation of the QTextBrowser class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtextbrowser.h"
+#ifndef QT_NO_TEXTBROWSER
+#include "../kernel/qrichtext_p.h"
+
+#include "qapplication.h"
+#include "qlayout.h"
+#include "qpainter.h"
+
+#include "qvaluestack.h"
+#include "stdio.h"
+#include "qfile.h"
+#include "qtextstream.h"
+#include "qlayout.h"
+#include "qbitmap.h"
+#include "qtimer.h"
+#include "qimage.h"
+#include "qsimplerichtext.h"
+#include "qdragobject.h"
+#include "qurl.h"
+#include "qcursor.h"
+
+/*!
+ \class QTextBrowser qtextbrowser.h
+ \brief The QTextBrowser class provides a rich text browser with hypertext navigation.
+
+ \ingroup advanced
+ \ingroup helpsystem
+ \ingroup text
+ \mainclass
+
+ This class extends QTextEdit (in read-only mode), adding some
+ navigation functionality so that users can follow links in
+ hypertext documents. The contents of QTextEdit is set with
+ setText(), but QTextBrowser has an additional function,
+ setSource(), which makes it possible to set the text to a named
+ document. The name is looked up in the text view's mime source
+ 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 connetion
+ to the sourceChanged() signal.
+
+ 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 linkClicked()
+ signal is emitted when the user clicks a link.
+
+ By using QTextEdit::setMimeSourceFactory() you can provide your
+ own subclass of QMimeSourceFactory. This makes it possible to
+ access data from anywhere, for example from a network or from a
+ database. See QMimeSourceFactory::data() for details.
+
+ If you intend using the mime factory to read the data directly
+ from the file system, you may have to specify the encoding for the
+ file extension you are using. For example:
+ \code
+ mimeSourceFactory()->setExtensionType("qml", "text/utf8");
+ \endcode
+ This is to ensure that the factory is able to resolve the document
+ names.
+
+ QTextBrowser interprets the tags it processes in accordance with
+ the default style sheet. Change the style sheet with
+ \l{setStyleSheet()}; see QStyleSheet for details.
+
+ If you want to provide your users with editable rich text 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 QSimpleRichText or QLabel.
+
+ <img src=qtextbrowser-m.png> <img src=qtextbrowser-w.png>
+*/
+
+class QTextBrowserData
+{
+public:
+ QTextBrowserData():textOrSourceChanged(FALSE) {}
+
+ QValueStack<QString> stack;
+ QValueStack<QString> forwardStack;
+ QString home;
+ QString curmain;
+ QString curmark;
+
+ /*flag necessary to give the linkClicked() signal some meaningful
+ semantics when somebody connected to it calls setText() or
+ setSource() */
+ bool textOrSourceChanged;
+};
+
+
+/*!
+ Constructs an empty QTextBrowser called \a name, with parent \a
+ parent.
+*/
+QTextBrowser::QTextBrowser(QWidget *parent, const char *name)
+ : QTextEdit( parent, name )
+{
+ setReadOnly( TRUE );
+ d = new QTextBrowserData;
+
+ viewport()->setMouseTracking( TRUE );
+}
+
+/*!
+ \reimp
+*/
+QTextBrowser::~QTextBrowser()
+{
+ delete d;
+}
+
+
+/*!
+ \property QTextBrowser::source
+ \brief the name of the displayed document.
+
+ This is a QString::null if no document is displayed or if the
+ source is unknown.
+
+ Setting this property uses the mimeSourceFactory() to lookup the
+ named document. 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 setText().
+
+ If you are using the filesystem access capabilities of the mime
+ source factory, you must ensure that the factory knows about the
+ encoding of specified files; otherwise no data will be available.
+ The default factory handles a couple of common file extensions
+ such as \c *.html and \c *.txt with reasonable defaults. See
+ QMimeSourceFactory::data() for details.
+*/
+
+QString QTextBrowser::source() const
+{
+ if ( d->stack.isEmpty() )
+ return QString::null;
+ else
+ return d->stack.top();
+}
+
+/*!
+ \property QTextBrowser::undoDepth
+ \brief This text browser's undo depth.
+*/
+
+/*!
+ \property QTextBrowser::overwriteMode
+ \brief This text browser's overwrite mode.
+*/
+
+/*!
+ \property QTextBrowser::modified
+ \brief Whether the contents have been modified.
+*/
+
+/*!
+ \property QTextBrowser::readOnly
+ \brief Whether the contents are read only.
+*/
+
+/*!
+ \property QTextBrowser::undoRedoEnabled
+ \brief Whether undo and redo are enabled.
+*/
+
+
+
+/*!
+ Reloads the current set source.
+*/
+
+void QTextBrowser::reload()
+{
+ QString s = d->curmain;
+ d->curmain = "";
+ setSource( s );
+}
+
+
+void QTextBrowser::setSource(const QString& name)
+{
+#ifndef QT_NO_CURSOR
+ if ( isVisible() )
+ qApp->setOverrideCursor( waitCursor );
+#endif
+ d->textOrSourceChanged = TRUE;
+ QString source = name;
+ QString mark;
+ int hash = name.find('#');
+ if ( hash != -1) {
+ source = name.left( hash );
+ mark = name.mid( hash+1 );
+ }
+
+ if ( source.left(5) == "file:" )
+ source = source.mid(6);
+
+ QString url = mimeSourceFactory()->makeAbsolute( source, context() );
+ QString txt;
+ bool dosettext = FALSE;
+
+ if ( !source.isEmpty() && url != d->curmain ) {
+ const QMimeSource* m =
+ mimeSourceFactory()->data( source, context() );
+ if ( !m ){
+ qWarning("QTextBrowser: no mimesource for %s", source.latin1() );
+ }
+ else {
+ if ( !QTextDrag::decode( m, txt ) ) {
+ qWarning("QTextBrowser: cannot decode %s", source.latin1() );
+ }
+ }
+ if ( isVisible() ) {
+ QString firstTag = txt.left( txt.find( '>' ) + 1 );
+ if ( firstTag.left( 3 ) == "<qt" && firstTag.contains( "type" ) && firstTag.contains( "detail" ) ) {
+ popupDetail( txt, QCursor::pos() );
+#ifndef QT_NO_CURSOR
+ qApp->restoreOverrideCursor();
+#endif
+ return;
+ }
+ }
+
+ d->curmain = url;
+ dosettext = TRUE;
+ }
+
+ d->curmark = mark;
+
+ if ( !mark.isEmpty() ) {
+ url += "#";
+ url += mark;
+ }
+ if ( !d->home )
+ d->home = url;
+
+ if ( d->stack.isEmpty() || d->stack.top() != url)
+ d->stack.push( url );
+
+ int stackCount = (int)d->stack.count();
+ if ( d->stack.top() == url )
+ stackCount--;
+ emit backwardAvailable( stackCount > 0 );
+ stackCount = (int)d->forwardStack.count();
+ if ( d->forwardStack.isEmpty() || d->forwardStack.top() == url )
+ stackCount--;
+ emit forwardAvailable( stackCount > 0 );
+
+ if ( dosettext )
+ QTextEdit::setText( txt, url );
+
+ if ( !mark.isEmpty() )
+ scrollToAnchor( mark );
+ else
+ setContentsPos( 0, 0 );
+
+#ifndef QT_NO_CURSOR
+ if ( isVisible() )
+ qApp->restoreOverrideCursor();
+#endif
+
+ emit sourceChanged( url );
+}
+
+/*!
+ \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::sourceChanged( const QString& src)
+
+ This signal is emitted when the mime 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 QString &link)
+
+ This signal is emitted when the user has selected but not
+ activated a link in the document. \a link is the value of the \c
+ href i.e. the name of the target document.
+*/
+
+/*!
+ \fn void QTextBrowser::linkClicked( const QString& link)
+
+ This signal is emitted when the user clicks a link. The \a link is
+ the value of the \c href i.e. the name of the target document.
+
+ The \a link will be the absolute location of the document, based
+ on the value of the anchor's href tag and the current context of
+ the document.
+
+ \sa anchorClicked(), context()
+*/
+
+/*!
+ \fn void QTextBrowser::anchorClicked( const QString& name, const QString &link)
+
+ This signal is emitted when the user clicks an anchor. The \a link is
+ the value of the \c href i.e. the name of the target document. The \a name
+ is the name of the anchor.
+
+ \sa linkClicked()
+*/
+
+/*!
+ 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()
+{
+ if ( d->stack.count() <= 1)
+ return;
+ d->forwardStack.push( d->stack.pop() );
+ setSource( d->stack.pop() );
+ emit forwardAvailable( TRUE );
+}
+
+/*!
+ 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()
+{
+ if ( d->forwardStack.isEmpty() )
+ return;
+ setSource( d->forwardStack.pop() );
+ emit forwardAvailable( !d->forwardStack.isEmpty() );
+}
+
+/*!
+ Changes the document displayed to be the first document the
+ browser displayed.
+*/
+void QTextBrowser::home()
+{
+ if (!d->home.isNull() )
+ setSource( d->home );
+}
+
+/*!
+ The event \a e 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 * e )
+{
+ if ( e->state() & AltButton ) {
+ switch (e->key()) {
+ case Key_Right:
+ forward();
+ return;
+ case Key_Left:
+ backward();
+ return;
+ case Key_Up:
+ home();
+ return;
+ }
+ }
+ QTextEdit::keyPressEvent(e);
+}
+
+class QTextDetailPopup : public QWidget
+{
+public:
+ QTextDetailPopup()
+ : QWidget ( 0, "automatic QText detail widget", WType_Popup | WDestructiveClose )
+ {
+ }
+
+protected:
+
+ void mousePressEvent( QMouseEvent*)
+ {
+ close();
+ }
+};
+
+
+void QTextBrowser::popupDetail( const QString& contents, const QPoint& pos )
+{
+
+ const int shadowWidth = 6; // also used as '5' and '6' and even '8' below
+ const int vMargin = 8;
+ const int hMargin = 12;
+
+ QWidget* popup = new QTextDetailPopup;
+ popup->setBackgroundMode( QWidget::NoBackground );
+
+ QSimpleRichText* doc = new QSimpleRichText( contents, popup->font() );
+ doc->adjustSize();
+ QRect r( 0, 0, doc->width(), doc->height() );
+
+ int w = r.width() + 2*hMargin;
+ int h = r.height() + 2*vMargin;
+
+ popup->resize( w + shadowWidth, h + shadowWidth );
+
+ // okay, now to find a suitable location
+ //###### we need a global fancy popup positioning somewhere
+ popup->move(pos - popup->rect().center());
+ if (popup->geometry().right() > QApplication::desktop()->width())
+ popup->move( QApplication::desktop()->width() - popup->width(),
+ popup->y() );
+ if (popup->geometry().bottom() > QApplication::desktop()->height())
+ popup->move( popup->x(),
+ QApplication::desktop()->height() - popup->height() );
+ if ( popup->x() < 0 )
+ popup->move( 0, popup->y() );
+ if ( popup->y() < 0 )
+ popup->move( popup->x(), 0 );
+
+
+ popup->show();
+
+ // now for super-clever shadow stuff. super-clever mostly in
+ // how many window system problems it skirts around.
+
+ QPainter p( popup );
+ p.setPen( QApplication::palette().active().foreground() );
+ p.drawRect( 0, 0, w, h );
+ p.setPen( QApplication::palette().active().mid() );
+ p.setBrush( QColor( 255, 255, 240 ) );
+ p.drawRect( 1, 1, w-2, h-2 );
+ p.setPen( black );
+
+ doc->draw( &p, hMargin, vMargin, r, popup->colorGroup(), 0 );
+ delete doc;
+
+ p.drawPoint( w + 5, 6 );
+ p.drawLine( w + 3, 6,
+ w + 5, 8 );
+ p.drawLine( w + 1, 6,
+ w + 5, 10 );
+ int i;
+ for( i=7; i < h; i += 2 )
+ p.drawLine( w, i,
+ w + 5, i + 5 );
+ for( i = w - i + h; i > 6; i -= 2 )
+ p.drawLine( i, h,
+ i + 5, h + 5 );
+ for( ; i > 0 ; i -= 2 )
+ p.drawLine( 6, h + 6 - i,
+ i + 5, h + 5 );
+}
+
+/*!
+ \fn void QTextBrowser::setText( const QString &txt )
+
+ \overload
+
+ Sets the text to \a txt.
+*/
+
+/*!
+ \reimp
+*/
+
+void QTextBrowser::setText( const QString &txt, const QString &context )
+{
+ d->textOrSourceChanged = TRUE;
+ d->curmark = "";
+ d->curmain = "";
+ QTextEdit::setText( txt, context );
+}
+
+void QTextBrowser::emitHighlighted( const QString &s )
+{
+ emit highlighted( s );
+}
+
+void QTextBrowser::emitLinkClicked( const QString &s )
+{
+ d->textOrSourceChanged = FALSE;
+ emit linkClicked( s );
+ if ( !d->textOrSourceChanged )
+ setSource( s );
+}
+
+#endif // QT_NO_TEXTBROWSER
diff --git a/src/widgets/qtextbrowser.h b/src/widgets/qtextbrowser.h
new file mode 100644
index 0000000..50b02eb
--- /dev/null
+++ b/src/widgets/qtextbrowser.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Definition of the QTextBrowser class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTEXTBROWSER_H
+#define QTEXTBROWSER_H
+
+#ifndef QT_H
+#include "qptrlist.h"
+#include "qpixmap.h"
+#include "qcolor.h"
+#include "qtextedit.h"
+#endif // QT_H
+
+#ifndef QT_NO_TEXTBROWSER
+
+class QTextBrowserData;
+
+class Q_EXPORT QTextBrowser : public QTextEdit
+{
+ Q_OBJECT
+ Q_PROPERTY( QString source READ source WRITE setSource )
+ Q_OVERRIDE( int undoDepth DESIGNABLE false SCRIPTABLE false )
+ Q_OVERRIDE( bool overwriteMode DESIGNABLE false SCRIPTABLE false )
+ Q_OVERRIDE( bool modified SCRIPTABLE false)
+ Q_OVERRIDE( bool readOnly DESIGNABLE false SCRIPTABLE false )
+ Q_OVERRIDE( bool undoRedoEnabled DESIGNABLE false SCRIPTABLE false )
+
+public:
+ QTextBrowser( QWidget* parent=0, const char* name=0 );
+ ~QTextBrowser();
+
+ QString source() const;
+
+public slots:
+ virtual void setSource(const QString& name);
+ virtual void backward();
+ virtual void forward();
+ virtual void home();
+ virtual void reload();
+ void setText( const QString &txt ) { setText( txt, QString::null ); }
+ virtual void setText( const QString &txt, const QString &context );
+
+signals:
+ void backwardAvailable( bool );
+ void forwardAvailable( bool );
+ void sourceChanged( const QString& );
+ void highlighted( const QString& );
+ void linkClicked( const QString& );
+ void anchorClicked( const QString&, const QString& );
+
+protected:
+ void keyPressEvent( QKeyEvent * e);
+
+private:
+ void popupDetail( const QString& contents, const QPoint& pos );
+ bool linksEnabled() const { return TRUE; }
+ void emitHighlighted( const QString &s );
+ void emitLinkClicked( const QString &s );
+ QTextBrowserData *d;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QTextBrowser( const QTextBrowser & );
+ QTextBrowser& operator=( const QTextBrowser & );
+#endif
+};
+
+#endif // QT_NO_TEXTBROWSER
+
+#endif // QTEXTBROWSER_H
diff --git a/src/widgets/qtextedit.cpp b/src/widgets/qtextedit.cpp
new file mode 100644
index 0000000..0908e84
--- /dev/null
+++ b/src/widgets/qtextedit.cpp
@@ -0,0 +1,7467 @@
+/****************************************************************************
+**
+** Implementation of the QTextEdit class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtextedit.h"
+
+#ifndef QT_NO_TEXTEDIT
+
+// Keep this position to avoid patch rejection
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#endif
+
+#include "../kernel/qrichtext_p.h"
+#include "qpainter.h"
+#include "qpen.h"
+#include "qbrush.h"
+#include "qpixmap.h"
+#include "qfont.h"
+#include "qcolor.h"
+#include "qstyle.h"
+#include "qsize.h"
+#include "qevent.h"
+#include "qtimer.h"
+#include "qapplication.h"
+#include "qlistbox.h"
+#include "qvbox.h"
+#include "qapplication.h"
+#include "qclipboard.h"
+#include "qcolordialog.h"
+#include "qfontdialog.h"
+#include "qstylesheet.h"
+#include "qdragobject.h"
+#include "qurl.h"
+#include "qcursor.h"
+#include "qregexp.h"
+#include "qpopupmenu.h"
+#include "qptrstack.h"
+#include "qmetaobject.h"
+#include "qtextbrowser.h"
+#include <private/qucom_p.h>
+#include "private/qsyntaxhighlighter_p.h"
+#include <qguardedptr.h>
+
+#ifndef QT_NO_ACCEL
+#include <qkeysequence.h>
+#define ACCEL_KEY(k) "\t" + QString(QKeySequence( Qt::CTRL | Qt::Key_ ## k ))
+#else
+#define ACCEL_KEY(k) "\t" + QString("Ctrl+" #k)
+#endif
+
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+#define LOGOFFSET(i) d->logOffset + i
+#endif
+
+struct QUndoRedoInfoPrivate
+{
+ QTextString text;
+};
+
+class QTextEditPrivate
+{
+public:
+ QTextEditPrivate()
+ :preeditStart(-1),preeditLength(-1),ensureCursorVisibleInShowEvent(FALSE),
+ tabChangesFocus(FALSE),
+#ifndef QT_NO_CLIPBOARD
+ clipboard_mode( QClipboard::Clipboard ),
+#endif
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ od(0), optimMode(FALSE),
+ maxLogLines(-1),
+ logOffset(0),
+#endif
+ autoFormatting( (uint)QTextEdit::AutoAll )
+ {
+ for ( int i=0; i<7; i++ )
+ id[i] = 0;
+ }
+ int id[ 7 ];
+ int preeditStart;
+ int preeditLength;
+ bool composeMode() const { return ( preeditLength > 0 ); }
+
+ uint ensureCursorVisibleInShowEvent : 1;
+ uint tabChangesFocus : 1;
+ QString scrollToAnchor; // used to deferr scrollToAnchor() until the show event when we are resized
+ QString pressedName;
+ QString onName;
+#ifndef QT_NO_CLIPBOARD
+ QClipboard::Mode clipboard_mode;
+#endif
+ QTimer *trippleClickTimer;
+ QPoint trippleClickPoint;
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ QTextEditOptimPrivate * od;
+ bool optimMode : 1;
+ int maxLogLines;
+ int logOffset;
+#endif
+ uint autoFormatting;
+};
+
+#ifndef QT_NO_MIME
+class QRichTextDrag : public QTextDrag
+{
+public:
+ QRichTextDrag( QWidget *dragSource = 0, const char *name = 0 );
+
+ void setPlainText( const QString &txt ) { setText( txt ); }
+ void setRichText( const QString &txt ) { richTxt = txt; }
+
+ virtual QByteArray encodedData( const char *mime ) const;
+ virtual const char* format( int i ) const;
+
+ static bool decode( QMimeSource *e, QString &str, const QCString &mimetype,
+ const QCString &subtype );
+ static bool canDecode( QMimeSource* e );
+
+private:
+ QString richTxt;
+
+};
+
+QRichTextDrag::QRichTextDrag( QWidget *dragSource, const char *name )
+ : QTextDrag( dragSource, name )
+{
+}
+
+QByteArray QRichTextDrag::encodedData( const char *mime ) const
+{
+ if ( qstrcmp( "application/x-qrichtext", mime ) == 0 ) {
+ return richTxt.utf8(); // #### perhaps we should use USC2 instead?
+ } else
+ return QTextDrag::encodedData( mime );
+}
+
+bool QRichTextDrag::decode( QMimeSource *e, QString &str, const QCString &mimetype,
+ const QCString &subtype )
+{
+ if ( mimetype == "application/x-qrichtext" ) {
+ // do richtext decode
+ const char *mime;
+ int i;
+ for ( i = 0; ( mime = e->format( i ) ); ++i ) {
+ if ( qstrcmp( "application/x-qrichtext", mime ) != 0 )
+ continue;
+ str = QString::fromUtf8( e->encodedData( mime ) );
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ // do a regular text decode
+ QCString subt = subtype;
+ return QTextDrag::decode( e, str, subt );
+}
+
+bool QRichTextDrag::canDecode( QMimeSource* e )
+{
+ if ( e->provides( "application/x-qrichtext" ) )
+ return TRUE;
+ return QTextDrag::canDecode( e );
+}
+
+const char* QRichTextDrag::format( int i ) const
+{
+ if ( QTextDrag::format( i ) )
+ return QTextDrag::format( i );
+ if ( QTextDrag::format( i-1 ) )
+ return "application/x-qrichtext";
+ return 0;
+}
+
+#endif
+
+static bool block_set_alignment = FALSE;
+
+/*!
+ \class QTextEdit qtextedit.h
+ \brief The QTextEdit widget provides a powerful single-page rich text editor.
+
+ \ingroup basic
+ \ingroup text
+ \mainclass
+
+ \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 has four modes of operation:
+ \table
+ \header \i Mode \i Command \i Notes
+ \row \i Plain Text Editor \i setTextFormat(PlainText)
+ \i Set text with setText(); text() returns plain text. Text
+ attributes (e.g. colors) can be set, but plain text is always
+ returned.
+ \row \i Rich Text Editor \i setTextFormat(RichText)
+ \i Set text with setText(); text() returns rich text. Rich
+ text editing is fairly limited. You can't set margins or
+ insert images for example (although you can read and
+ correctly display files that have margins set and that
+ include images). This mode is mostly useful for editing small
+ amounts of rich text. <sup>1.</sup>
+ \row \i Text Viewer \i setReadOnly(TRUE)
+ \i Set text with setText() or append() (which has no undo
+ history so is faster and uses less memory); text() returns
+ plain or rich text depending on the textFormat(). This mode
+ can correctly display a large subset of HTML tags.
+ \row \i Log Viewer \i setTextFormat(LogText)
+ \i Append text using append(). The widget is set to be read
+ only and rich text support is disabled although a few HTML
+ tags (for color, bold, italic and underline) may be used.
+ (See \link #logtextmode LogText mode\endlink for details.)
+ \endtable
+
+ <sup>1.</sup><small>A more complete API that supports setting
+ margins, images, etc., is planned for a later Qt release.</small>
+
+ QTextEdit can be used as a syntax highlighting editor when used in
+ conjunction with QSyntaxHighlighter.
+
+ We recommend that you always call setTextFormat() to set the mode
+ you want to use. If you use \c AutoText then setText() and
+ append() will try to determine whether the text they are given is
+ plain text or rich text. If you use \c RichText then setText() and
+ append() will assume that the text they are given is rich text.
+ insert() simply inserts the text it is given.
+
+ 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
+ signify a paragraph. A document consists of zero or more
+ paragraphs, indexed from 0. Characters are indexed on a
+ per-paragraph basis, also indexed from 0. 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.
+
+ The text edit documentation uses the following concepts:
+ \list
+ \i \e{current format} --
+ this is the format at the current cursor position, \e and it
+ is the format of the selected text if any.
+ \i \e{current paragraph} -- the paragraph which contains the
+ cursor.
+ \endlist
+
+ QTextEdit can display images (using QMimeSourceFactory), lists and
+ tables. If the text is too large to view within the text edit's
+ viewport, scrollbars will appear. The text edit can load both
+ plain text and HTML files (a subset of HTML 3.2 and 4). The
+ rendering style and the set of valid tags are defined by a
+ styleSheet(). Custom tags can be created and placed in a custom
+ style sheet. Change the style sheet with \l{setStyleSheet()}; see
+ QStyleSheet for details. The images identified by image tags are
+ displayed if they can be interpreted using the text edit's
+ \l{QMimeSourceFactory}; see setMimeSourceFactory().
+
+ If you want a text browser with more navigation use QTextBrowser.
+ If you just need to display a small piece of rich text use QLabel
+ or QSimpleRichText.
+
+ If you create a new QTextEdit, and want to allow the user to edit
+ rich text, call setTextFormat(Qt::RichText) to ensure that the
+ text is treated as rich text. (Rich text uses HTML tags to set
+ text formatting attributes. See QStyleSheet for information on the
+ HTML tags that are supported.). If you don't call setTextFormat()
+ explicitly the text edit will guess from the text itself whether
+ it is rich text or plain text. This means that if the text looks
+ like HTML or XML it will probably be interpreted as rich text, so
+ you should call setTextFormat(Qt::PlainText) to preserve such
+ text.
+
+ Note that we do not intend to add a full-featured web browser
+ widget to Qt (because that would easily double Qt's size and only
+ a few applications would benefit from it). 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.
+
+ \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 setText() which deletes any
+ existing text and replaces it with the text passed in the
+ setText() call. If you call setText() with legacy HTML (with
+ setTextFormat(RichText) in force), and then call text(), the text
+ that is returned may have different markup, but will render the
+ same. Text can be inserted with insert(), paste(), pasteSubType()
+ and append(). Text that is appended does not go into the undo
+ history; this makes append() faster and consumes less memory. Text
+ can also be cut(). The entire text is deleted with clear() and the
+ selected text is deleted with removeSelectedText(). Selected
+ (marked) text can also be deleted with del() (which will delete
+ the character to the right of the cursor if no text is selected).
+
+ Loading and saving text is achieved using setText() and text(),
+ for example:
+ \code
+ QFile file( fileName ); // Read the text from a file
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ textEdit->setText( stream.read() );
+ }
+
+ QFile file( fileName ); // Write the text to a file
+ if ( file.open( IO_WriteOnly ) ) {
+ QTextStream stream( &file );
+ stream << textEdit->text();
+ textEdit->setModified( FALSE );
+ }
+ \endcode
+
+ By default the text edit wraps words at whitespace to fit within
+ the text edit widget. The setWordWrap() function is used to
+ specify the kind of word wrap you want, or \c NoWrap if you don't
+ want any wrapping. Call setWordWrap() to set a fixed pixel width
+ \c FixedPixelWidth, or character column (e.g. 80 column) \c
+ FixedColumnWidth with the pixels or columns specified with
+ setWrapColumnOrWidth(). If you use word wrap to the widget's width
+ \c WidgetWidth, you can specify whether to break on whitespace or
+ anywhere with setWrapPolicy().
+
+ The background color is set differently than other widgets, using
+ setPaper(). You specify a brush style which could be a plain color
+ or a complex pixmap.
+
+ Hypertext links are automatically underlined; this can be changed
+ with setLinkUnderline(). The tab stop width is set with
+ setTabStopWidth().
+
+ The zoomIn() and zoomOut() functions can be used to resize the
+ text by increasing (decreasing for zoomOut()) the point size used.
+ Images are not affected by the zoom functions.
+
+ The lines() function returns the number of lines in the text and
+ paragraphs() returns the number of paragraphs. The number of lines
+ within a particular paragraph is returned by linesOfParagraph().
+ The length of the entire text in characters is returned by
+ length().
+
+ You can scroll to an anchor in the text, e.g.
+ \c{<a name="anchor">} with scrollToAnchor(). The find() function
+ can be used to find and select a given string within the text.
+
+ A read-only QTextEdit provides the same functionality as the
+ (obsolete) QTextView. (QTextView is still supplied for
+ compatibility with old code.)
+
+ \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 UpArrow \i Move one line up
+ \row \i DownArrow \i Move one line down
+ \row \i LeftArrow \i Move one character left
+ \row \i RightArrow \i Move one character right
+ \row \i PageUp \i Move one (viewport) page up
+ \row \i PageDown \i Move one (viewport) page down
+ \row \i Home \i Move to the beginning of the text
+ \row \i End \i Move to the end of the text
+ \row \i Shift+Wheel
+ \i Scroll the page horizontally (the Wheel is the mouse wheel)
+ \row \i Ctrl+Wheel \i Zoom the 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.
+
+ The text displayed in a text edit has a \e context. The context is
+ a path which the text edit's QMimeSourceFactory uses to resolve
+ the locations of files and images. It is passed to the
+ mimeSourceFactory() when quering data. (See QTextEdit() and
+ \l{context()}.)
+
+ \target logtextmode
+ \section2 Using QTextEdit in LogText Mode
+
+ Setting the text format to \c LogText puts the widget in a special
+ mode which is optimized for very large texts. Editing, word wrap,
+ and rich text support are disabled in this mode (the widget is
+ explicitly made read-only). This allows the text to be stored in a
+ different, more memory efficient manner. However, a certain degree
+ of text formatting is supported through the use of formatting tags.
+ A tag is delimited by \c < and \c {>}. The characters \c {<}, \c >
+ and \c & are escaped by using \c {&lt;}, \c {&gt;} and \c {&amp;}.
+ A tag pair consists of a left and a right tag (or open/close tags).
+ Left-tags mark the starting point for formatting, while right-tags
+ mark the ending point. A right-tag always start with a \c / before
+ the tag keyword. For example \c <b> and \c </b> are a tag pair.
+ Tags can be nested, but they have to be closed in the same order as
+ they are opened. For example, \c <b><u></u></b> is valid, while \c
+ <b><u></b></u> will output an error message.
+
+ By using tags it is possible to change the color, bold, italic and
+ underline settings for a piece of text. A color can be specified
+ by using the HTML font tag \c {<font color=colorname>}. The color
+ name can be one of the color names from the X11 color database, or
+ a RGB hex value (e.g \c {#00ff00}). Example of valid color tags:
+ \c {<font color=red>}, \c {<font color="light blue">}, \c {<font
+ color="#223344">}. Bold, italic and underline settings can be
+ specified by the tags \c {<b>}, \c <i> and \c {<u>}. Note that a
+ tag does not necessarily have to be closed. A valid example:
+ \code
+ This is <font color=red>red</font> while <b>this</b> is <font color=blue>blue</font>.
+ <font color=green><font color=yellow>Yellow,</font> and <u>green</u>.
+ \endcode
+
+ Stylesheets can also be used in LogText mode. To create and use a
+ custom tag, you could do the following:
+ \code
+ QTextEdit * log = new QTextEdit( this );
+ log->setTextFormat( Qt::LogText );
+ QStyleSheetItem * item = new QStyleSheetItem( log->styleSheet(), "mytag" );
+ item->setColor( "red" );
+ item->setFontWeight( QFont::Bold );
+ item->setFontUnderline( TRUE );
+ log->append( "This is a <mytag>custom tag</mytag>!" );
+ \endcode
+ Note that only the color, bold, underline and italic attributes of
+ a QStyleSheetItem is used in LogText mode.
+
+ Note that you can use setMaxLogLines() to limit the number of
+ lines the widget can hold in LogText mode.
+
+ There are a few things that you need to be aware of when the
+ widget is in this mode:
+ \list
+ \i Functions that deal with rich text formatting and cursor
+ movement will not work or return anything valid.
+ \i Lines are equivalent to paragraphs.
+ \endlist
+
+ \section1 Using QTextEdit as an Editor
+
+ All the information about using QTextEdit as a display widget also
+ applies here.
+
+ The current format's attributes are set with setItalic(),
+ setBold(), setUnderline(), setFamily() (font family),
+ setPointSize(), setColor() and setCurrentFont(). The current
+ paragraph's alignment is set with setAlignment().
+
+ Use setSelection() to select text. The setSelectionAttributes()
+ function is used to indicate how selected text should be
+ displayed. Use hasSelectedText() to find out if any text is
+ selected. The currently selected text's position is available
+ using getSelection() and the selected text itself is returned by
+ selectedText(). The selection can be copied to the clipboard with
+ copy(), or cut to the clipboard with cut(). It can be deleted with
+ removeSelectedText(). The entire text can be selected (or
+ unselected) using selectAll(). QTextEdit supports multiple
+ selections. Most of the selection functions operate on the default
+ selection, selection 0. If the user presses a non-selecting key,
+ e.g. a cursor key without also holding down Shift, all selections
+ are cleared.
+
+ Set and get the position of the cursor with setCursorPosition()
+ and getCursorPosition() respectively. When the cursor is moved,
+ the signals currentFontChanged(), currentColorChanged() and
+ currentAlignmentChanged() are emitted to reflect the font, color
+ and alignment at the new cursor position.
+
+ If the text changes, the textChanged() signal is emitted, and if
+ the user inserts a new line by pressing Return or Enter,
+ returnPressed() is emitted. The isModified() function will return
+ TRUE if the text has been modified.
+
+ QTextEdit provides command-based undo and redo. To set the depth
+ of the command history use setUndoDepth() which defaults to 100
+ steps. To undo or redo the last operation call undo() or redo().
+ The signals undoAvailable() and redoAvailable() indicate whether
+ the undo and redo operations can be executed.
+
+ The indent() function is used to reindent a paragraph. It is
+ useful for code editors, for example in \link designer-manual.book
+ Qt Designer\endlink's code editor \e{Ctrl+I} invokes the indent()
+ function.
+
+ \section2 Editing key bindings
+
+ The list of key-bindings which are implemented for editing:
+ \table
+ \header \i Keypresses \i Action
+ \row \i Backspace \i Delete the character to the left of the cursor
+ \row \i Delete \i Delete the character to the right of the cursor
+ \row \i Ctrl+A \i Move the cursor to the beginning of the line
+ \row \i Ctrl+B \i Move the cursor one character left
+ \row \i Ctrl+C \i Copy the marked text to the clipboard (also
+ Ctrl+Insert under Windows)
+ \row \i Ctrl+D \i Delete the character to the right of the cursor
+ \row \i Ctrl+E \i Move the cursor to the end of the line
+ \row \i Ctrl+F \i Move the cursor one character right
+ \row \i Ctrl+H \i Delete the character to the left of the cursor
+ \row \i Ctrl+K \i Delete to end of line
+ \row \i Ctrl+N \i Move the cursor one line down
+ \row \i Ctrl+P \i Move the cursor one line up
+ \row \i Ctrl+V \i Paste the clipboard text into line edit
+ (also Shift+Insert under Windows)
+ \row \i Ctrl+X \i Cut the marked text, copy to clipboard
+ (also Shift+Delete under Windows)
+ \row \i Ctrl+Z \i Undo the last operation
+ \row \i Ctrl+Y \i Redo the last operation
+ \row \i LeftArrow \i Move the cursor one character left
+ \row \i Ctrl+LeftArrow \i Move the cursor one word left
+ \row \i RightArrow \i Move the cursor one character right
+ \row \i Ctrl+RightArrow \i Move the cursor one word right
+ \row \i UpArrow \i Move the cursor one line up
+ \row \i Ctrl+UpArrow \i Move the cursor one word up
+ \row \i DownArrow \i Move the cursor one line down
+ \row \i Ctrl+Down Arrow \i Move the cursor one word down
+ \row \i PageUp \i Move the cursor one page up
+ \row \i PageDown \i Move the cursor one page down
+ \row \i Home \i Move the cursor to the beginning of the line
+ \row \i Ctrl+Home \i Move the cursor to the beginning of the text
+ \row \i End \i Move the cursor to the end of the line
+ \row \i Ctrl+End \i Move the cursor to the end of the text
+ \row \i Shift+Wheel \i Scroll the page horizontally
+ (the Wheel is the mouse wheel)
+ \row \i Ctrl+Wheel \i Zoom 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.
+
+ By default the text edit widget operates in insert mode so all
+ text that the user enters is inserted into the text edit and any
+ text to the right of the cursor is moved out of the way. The mode
+ can be changed to overwrite, where new text overwrites any text to
+ the right of the cursor, using setOverwriteMode().
+*/
+
+/*!
+ \enum QTextEdit::AutoFormatting
+
+ \value AutoNone Do not perform any automatic formatting
+ \value AutoBulletList Only automatically format bulletted lists
+ \value AutoAll Apply all available autoformatting
+*/
+
+
+/*!
+ \enum QTextEdit::KeyboardAction
+
+ This enum is used by doKeyboardAction() to specify which action
+ should be executed:
+
+ \value ActionBackspace Delete the character to the left of the
+ cursor.
+
+ \value ActionDelete Delete the character to the right of the
+ cursor.
+
+ \value ActionReturn Split the paragraph at the cursor position.
+
+ \value ActionKill If the cursor is not at the end of the
+ paragraph, delete the text from the cursor position until the end
+ of the paragraph. If the cursor is at the end of the paragraph,
+ delete the hard line break at the end of the paragraph: this will
+ cause this paragraph to be joined with the following paragraph.
+
+ \value ActionWordBackspace Delete the word to the left of the
+ cursor position.
+
+ \value ActionWordDelete Delete the word to the right of the
+ cursor position
+
+*/
+
+/*!
+ \enum QTextEdit::VerticalAlignment
+
+ This enum is used to set the vertical alignment of the text.
+
+ \value AlignNormal Normal alignment
+ \value AlignSuperScript Superscript
+ \value AlignSubScript Subscript
+*/
+
+/*!
+ \enum QTextEdit::TextInsertionFlags
+
+ \internal
+
+ \value RedoIndentation
+ \value CheckNewLines
+ \value RemoveSelected
+*/
+
+
+/*!
+ \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::textChanged()
+
+ This signal is emitted whenever the text in the text edit changes.
+
+ \sa setText() append()
+*/
+
+/*!
+ \fn void QTextEdit::selectionChanged()
+
+ This signal is emitted whenever the selection changes.
+
+ \sa setSelection() copyAvailable()
+*/
+
+/*! \fn QTextDocument *QTextEdit::document() const
+
+ \internal
+
+ This function returns the QTextDocument which is used by the text
+ edit.
+*/
+
+/*! \fn void QTextEdit::setDocument( QTextDocument *doc )
+
+ \internal
+
+ This function sets the QTextDocument which should be used by the text
+ edit to \a doc. This can be used, for example, if you want to
+ display a document using multiple views. You would create a
+ QTextDocument and set it to the text edits which should display it.
+ You would need to connect to the textChanged() and
+ selectionChanged() signals of all the text edits and update them all
+ accordingly (preferably with a slight delay for efficiency reasons).
+*/
+
+/*!
+ \enum QTextEdit::CursorAction
+
+ This enum is used by moveCursor() to specify in which direction
+ the cursor should be moved:
+
+ \value MoveBackward Moves the cursor one character backward
+
+ \value MoveWordBackward Moves the cursor one word backward
+
+ \value MoveForward Moves the cursor one character forward
+
+ \value MoveWordForward Moves the cursor one word forward
+
+ \value MoveUp Moves the cursor up one line
+
+ \value MoveDown Moves the cursor down one line
+
+ \value MoveLineStart Moves the cursor to the beginning of the line
+
+ \value MoveLineEnd Moves the cursor to the end of the line
+
+ \value MoveHome Moves the cursor to the beginning of the document
+
+ \value MoveEnd Moves the cursor to the end of the document
+
+ \value MovePgUp Moves the cursor one viewport page up
+
+ \value MovePgDown Moves the cursor one viewport page down
+*/
+
+/*!
+ \enum Qt::AnchorAttribute
+
+ An anchor has one or more of the following attributes:
+
+ \value AnchorName the name attribute of the anchor. This attribute is
+ used when scrolling to an anchor in the document.
+
+ \value AnchorHref the href attribute of the anchor. This attribute is
+ used when a link is clicked to determine what content to load.
+*/
+
+/*!
+ \property QTextEdit::overwriteMode
+ \brief the text edit's overwrite mode
+
+ If FALSE (the default) characters entered by the user are inserted
+ with any characters to the right being moved out of the way. If
+ TRUE, the editor is in overwrite mode, i.e. characters entered by
+ the user overwrite any characters to the right of the cursor
+ position.
+*/
+
+/*!
+ \fn void QTextEdit::setCurrentFont( const QFont &f )
+
+ Sets the font of the current format to \a f.
+
+ If the widget is in \c LogText mode this function will do
+ nothing. Use setFont() instead.
+
+ \sa currentFont() setPointSize() setFamily()
+*/
+
+/*!
+ \property QTextEdit::undoDepth
+ \brief the depth of the undo history
+
+ The maximum number of steps in the undo/redo history. The default
+ is 100.
+
+ \sa undo() redo()
+*/
+
+/*!
+ \fn void QTextEdit::undoAvailable( bool yes )
+
+ This signal is emitted when the availability of undo changes. If
+ \a yes is TRUE, then undo() will work until undoAvailable( FALSE )
+ is next emitted.
+
+ \sa undo() undoDepth()
+*/
+
+/*!
+ \fn void QTextEdit::modificationChanged( bool m )
+
+ This signal is emitted when the modification status of the
+ document has changed. If \a m is TRUE, the document was modified,
+ otherwise the modification state has been reset to unmodified.
+
+ \sa modified
+*/
+
+/*!
+ \fn void QTextEdit::redoAvailable( bool yes )
+
+ This signal is emitted when the availability of redo changes. If
+ \a yes is TRUE, then redo() will work until redoAvailable( FALSE )
+ is next emitted.
+
+ \sa redo() undoDepth()
+*/
+
+/*!
+ \fn void QTextEdit::currentFontChanged( const QFont &f )
+
+ This signal is emitted if the font of the current format has
+ changed.
+
+ The new font is \a f.
+
+ \sa setCurrentFont()
+*/
+
+/*!
+ \fn void QTextEdit::currentColorChanged( const QColor &c )
+
+ This signal is emitted if the color of the current format has
+ changed.
+
+ The new color is \a c.
+
+ \sa setColor()
+*/
+
+/*!
+ \fn void QTextEdit::currentVerticalAlignmentChanged( VerticalAlignment a )
+
+ This signal is emitted if the vertical alignment of the current
+ format has changed.
+
+ The new vertical alignment is \a a.
+
+ \sa setVerticalAlignment()
+*/
+
+/*!
+ \fn void QTextEdit::currentAlignmentChanged( int a )
+
+ This signal is emitted if the alignment of the current paragraph
+ has changed.
+
+ The new alignment is \a a.
+
+ \sa setAlignment()
+*/
+
+/*!
+ \fn void QTextEdit::cursorPositionChanged( QTextCursor *c )
+
+ \internal
+*/
+
+/*!
+ \fn void QTextEdit::cursorPositionChanged( int para, int pos )
+
+ This signal is emitted if the position of the cursor has changed.
+ \a para contains the paragraph index and \a pos contains the
+ character position within the paragraph.
+
+ \sa setCursorPosition()
+*/
+
+/*!
+ \fn void QTextEdit::clicked( int para, int pos )
+
+ This signal is emitted when the mouse is clicked on the paragraph
+ \a para at character position \a pos.
+
+ \sa doubleClicked()
+*/
+
+/*! \fn void QTextEdit::doubleClicked( int para, int pos )
+
+ This signal is emitted when the mouse is double-clicked on the
+ paragraph \a para at character position \a pos.
+
+ \sa clicked()
+*/
+
+
+/*!
+ \fn void QTextEdit::returnPressed()
+
+ This signal is emitted if the user pressed the Return or the Enter
+ key.
+*/
+
+/*!
+ \fn QTextCursor *QTextEdit::textCursor() const
+
+ Returns the text edit's text cursor.
+
+ \warning QTextCursor is not in the public API, but in special
+ circumstances you might wish to use it.
+*/
+
+/*!
+ Constructs an empty QTextEdit called \a name, with parent \a
+ parent.
+*/
+
+QTextEdit::QTextEdit( QWidget *parent, const char *name )
+ : QScrollView( parent, name, WStaticContents | WNoAutoErase ),
+ doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
+{
+ init();
+}
+
+/*!
+ Constructs a QTextEdit called \a name, with parent \a parent. The
+ text edit will display the text \a text using context \a context.
+
+ The \a context is a path which the text edit's QMimeSourceFactory
+ uses to resolve the locations of files and images. It is passed to
+ the mimeSourceFactory() when quering data.
+
+ For example if the text contains an image tag,
+ \c{<img src="image.png">}, and the context is "path/to/look/in", the
+ QMimeSourceFactory will try to load the image from
+ "path/to/look/in/image.png". If the tag was
+ \c{<img src="/image.png">}, the context will not be used (because
+ QMimeSourceFactory recognizes that we have used an absolute path)
+ and will try to load "/image.png". The context is applied in exactly
+ the same way to \e hrefs, for example,
+ \c{<a href="target.html">Target</a>}, would resolve to
+ "path/to/look/in/target.html".
+*/
+
+QTextEdit::QTextEdit( const QString& text, const QString& context,
+ QWidget *parent, const char *name)
+ : QScrollView( parent, name, WStaticContents | WNoAutoErase ),
+ doc( new QTextDocument( 0 ) ), undoRedoInfo( doc )
+{
+ init();
+ setText( text, context );
+}
+
+/*!
+ \reimp
+*/
+
+QTextEdit::~QTextEdit()
+{
+ delete undoRedoInfo.d;
+ undoRedoInfo.d = 0;
+ delete cursor;
+ delete doc;
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ delete d->od;
+#endif
+ delete d;
+}
+
+void QTextEdit::init()
+{
+ d = new QTextEditPrivate;
+ doc->formatCollection()->setPaintDevice( this );
+ undoEnabled = TRUE;
+ readonly = TRUE;
+ setReadOnly( FALSE );
+ setFrameStyle( LineEditPanel | Sunken );
+ connect( doc, SIGNAL( minimumWidthChanged(int) ),
+ this, SLOT( documentWidthChanged(int) ) );
+
+ mousePressed = FALSE;
+ inDoubleClick = FALSE;
+ modified = FALSE;
+ onLink = QString::null;
+ d->onName = QString::null;
+ overWrite = FALSE;
+ wrapMode = WidgetWidth;
+ wrapWidth = -1;
+ wPolicy = AtWhiteSpace;
+ inDnD = FALSE;
+ doc->setFormatter( new QTextFormatterBreakWords );
+ doc->formatCollection()->defaultFormat()->setFont( QScrollView::font() );
+ doc->formatCollection()->defaultFormat()->setColor( colorGroup().color( QColorGroup::Text ) );
+ currentFormat = doc->formatCollection()->defaultFormat();
+ currentAlignment = Qt::AlignAuto;
+
+ setBackgroundMode( PaletteBase );
+ viewport()->setBackgroundMode( PaletteBase );
+ viewport()->setAcceptDrops( TRUE );
+ resizeContents( 0, doc->lastParagraph() ?
+ ( doc->lastParagraph()->paragId() + 1 ) * doc->formatCollection()->defaultFormat()->height() : 0 );
+
+ setKeyCompression( TRUE );
+ viewport()->setMouseTracking( TRUE );
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ cursor = new QTextCursor( doc );
+
+ formatTimer = new QTimer( this );
+ connect( formatTimer, SIGNAL( timeout() ),
+ this, SLOT( formatMore() ) );
+ lastFormatted = doc->firstParagraph();
+
+ scrollTimer = new QTimer( this );
+ connect( scrollTimer, SIGNAL( timeout() ),
+ this, SLOT( autoScrollTimerDone() ) );
+
+ interval = 0;
+ changeIntervalTimer = new QTimer( this );
+ connect( changeIntervalTimer, SIGNAL( timeout() ),
+ this, SLOT( doChangeInterval() ) );
+
+ cursorVisible = TRUE;
+ blinkTimer = new QTimer( this );
+ connect( blinkTimer, SIGNAL( timeout() ),
+ this, SLOT( blinkCursor() ) );
+
+#ifndef QT_NO_DRAGANDDROP
+ dragStartTimer = new QTimer( this );
+ connect( dragStartTimer, SIGNAL( timeout() ),
+ this, SLOT( startDrag() ) );
+#endif
+
+ d->trippleClickTimer = new QTimer( this );
+
+ formatMore();
+
+ blinkCursorVisible = FALSE;
+
+ viewport()->setFocusProxy( this );
+ viewport()->setFocusPolicy( WheelFocus );
+ setInputMethodEnabled( TRUE );
+ viewport()->installEventFilter( this );
+ connect( this, SIGNAL(horizontalSliderReleased()), this, SLOT(sliderReleased()) );
+ connect( this, SIGNAL(verticalSliderReleased()), this, SLOT(sliderReleased()) );
+ installEventFilter( this );
+}
+
+void QTextEdit::paintDocument( bool drawAll, QPainter *p, int cx, int cy, int cw, int ch )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ Q_ASSERT( !d->optimMode );
+ if ( d->optimMode )
+ return;
+#endif
+
+ bool drawCur = hasFocus() || viewport()->hasFocus();
+ if (( hasSelectedText() && !style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ) ) ||
+ isReadOnly() || !cursorVisible || doc->hasSelection( QTextDocument::IMSelectionText ))
+ drawCur = FALSE;
+ QColorGroup g = colorGroup();
+ const QColorGroup::ColorRole backRole = QPalette::backgroundRoleFromMode(backgroundMode());
+ if ( doc->paper() )
+ g.setBrush( backRole, *doc->paper() );
+
+ if ( contentsY() < doc->y() ) {
+ p->fillRect( contentsX(), contentsY(), visibleWidth(), doc->y(),
+ g.brush( backRole ) );
+ }
+ if ( drawAll && doc->width() - contentsX() < cx + cw ) {
+ p->fillRect( doc->width() - contentsX(), cy, cx + cw - doc->width() + contentsX(), ch,
+ g.brush( backRole ) );
+ }
+
+ p->setBrushOrigin( -contentsX(), -contentsY() );
+
+ lastFormatted = doc->draw( p, cx, cy, cw, ch, g, !drawAll, drawCur, cursor );
+
+ if ( lastFormatted == doc->lastParagraph() )
+ resizeContents( contentsWidth(), doc->height() );
+
+ if ( contentsHeight() < visibleHeight() && ( !doc->lastParagraph() || doc->lastParagraph()->isValid() ) && drawAll )
+ p->fillRect( 0, contentsHeight(), visibleWidth(),
+ visibleHeight() - contentsHeight(), g.brush( backRole ) );
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::drawContents( QPainter *p, int cx, int cy, int cw, int ch )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimDrawContents( p, cx, cy, cw, ch );
+ return;
+ }
+#endif
+ paintDocument( TRUE, p, cx, cy, cw, ch );
+ int v;
+ p->setPen( foregroundColor() );
+ if ( document()->isPageBreakEnabled() && ( v = document()->flow()->pageSize() ) > 0 ) {
+ int l = int(cy / v) * v;
+ while ( l < cy + ch ) {
+ p->drawLine( cx, l, cx + cw - 1, l );
+ l += v;
+ }
+ }
+
+ // This invocation is required to follow dragging of active window
+ // by the showed candidate window.
+ updateMicroFocusHint();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::drawContents( QPainter *p )
+{
+ if ( horizontalScrollBar()->isVisible() &&
+ verticalScrollBar()->isVisible() ) {
+ const QRect verticalRect = verticalScrollBar()->geometry();
+ const QRect horizontalRect = horizontalScrollBar()->geometry();
+
+ QRect cornerRect;
+ cornerRect.setTop( verticalRect.bottom() );
+ cornerRect.setBottom( horizontalRect.bottom() );
+ cornerRect.setLeft( verticalRect.left() );
+ cornerRect.setRight( verticalRect.right() );
+
+ p->fillRect( cornerRect, colorGroup().background() );
+ }
+}
+
+/*!
+ \reimp
+*/
+
+bool QTextEdit::event( QEvent *e )
+{
+ if ( e->type() == QEvent::AccelOverride && !isReadOnly() ) {
+ QKeyEvent* ke = (QKeyEvent*) e;
+ switch(ke->state()) {
+ case NoButton:
+ case Keypad:
+ case ShiftButton:
+ if ( ke->key() < Key_Escape ) {
+ ke->accept();
+ } else {
+ switch ( ke->key() ) {
+ case Key_Return:
+ case Key_Enter:
+ case Key_Delete:
+ case Key_Home:
+ case Key_End:
+ case Key_Backspace:
+ case Key_Left:
+ case Key_Right:
+ ke->accept();
+ default:
+ break;
+ }
+ }
+ break;
+
+ case ControlButton:
+ case ControlButton|ShiftButton:
+ case ControlButton|Keypad:
+ case ControlButton|ShiftButton|Keypad:
+ switch ( ke->key() ) {
+ case Key_Tab:
+ case Key_Backtab:
+ ke->ignore();
+ break;
+// Those are too frequently used for application functionality
+/* case Key_A:
+ case Key_B:
+ case Key_D:
+ case Key_E:
+ case Key_F:
+ case Key_H:
+ case Key_I:
+ case Key_K:
+ case Key_N:
+ case Key_P:
+ case Key_T:
+*/
+ case Key_C:
+ case Key_V:
+ case Key_X:
+ case Key_Y:
+ case Key_Z:
+ case Key_Left:
+ case Key_Right:
+ case Key_Up:
+ case Key_Down:
+ case Key_Home:
+ case Key_End:
+#if defined (Q_WS_WIN)
+ case Key_Insert:
+ case Key_Delete:
+#endif
+ ke->accept();
+ default:
+ break;
+ }
+ break;
+
+ default:
+ switch ( ke->key() ) {
+#if defined (Q_WS_WIN)
+ case Key_Insert:
+ ke->accept();
+#endif
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ if ( e->type() == QEvent::Show ) {
+ if (
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ !d->optimMode &&
+#endif
+ d->ensureCursorVisibleInShowEvent ) {
+ ensureCursorVisible();
+ d->ensureCursorVisibleInShowEvent = FALSE;
+ }
+ if ( !d->scrollToAnchor.isEmpty() ) {
+ scrollToAnchor( d->scrollToAnchor );
+ d->scrollToAnchor = QString::null;
+ }
+ }
+ return QWidget::event( e );
+}
+
+/*!
+ Processes the key event, \a e. By default key events are used to
+ provide keyboard navigation and text editing.
+*/
+
+void QTextEdit::keyPressEvent( QKeyEvent *e )
+{
+ changeIntervalTimer->stop();
+ interval = 10;
+ bool unknownKey = FALSE;
+ if ( isReadOnly() ) {
+ if ( !handleReadOnlyKeyEvent( e ) )
+ QScrollView::keyPressEvent( e );
+ changeIntervalTimer->start( 100, TRUE );
+ return;
+ }
+
+
+ bool selChanged = FALSE;
+ for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
+ selChanged = doc->removeSelection( i ) || selChanged;
+
+ if ( selChanged ) {
+ cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
+ repaintChanged();
+ }
+
+ bool clearUndoRedoInfo = TRUE;
+
+
+ switch ( e->key() ) {
+ case Key_Left:
+ case Key_Right: {
+ // a bit hacky, but can't change this without introducing new enum values for move and keeping the
+ // correct semantics and movement for BiDi and non BiDi text.
+ CursorAction a;
+ if ( cursor->paragraph()->string()->isRightToLeft() == (e->key() == Key_Right) )
+ a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
+ else
+ a = e->state() & ControlButton ? MoveWordForward : MoveForward;
+ moveCursor( a, e->state() & ShiftButton );
+ break;
+ }
+ case Key_Up:
+ moveCursor( e->state() & ControlButton ? MovePgUp : MoveUp, e->state() & ShiftButton );
+ break;
+ case Key_Down:
+ moveCursor( e->state() & ControlButton ? MovePgDown : MoveDown, e->state() & ShiftButton );
+ break;
+ case Key_Home:
+ moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
+ break;
+ case Key_End:
+ moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
+ break;
+ case Key_Prior:
+ moveCursor( MovePgUp, e->state() & ShiftButton );
+ break;
+ case Key_Next:
+ moveCursor( MovePgDown, e->state() & ShiftButton );
+ break;
+ case Key_Return: case Key_Enter:
+ if ( doc->hasSelection( QTextDocument::Standard, FALSE ) )
+ removeSelectedText();
+ if ( textFormat() == Qt::RichText && ( e->state() & ControlButton ) ) {
+ // Ctrl-Enter inserts a line break in rich text mode
+ insert( QString( QChar( 0x2028) ), TRUE, FALSE );
+ } else {
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ clearUndoRedoInfo = FALSE;
+ doKeyboardAction( ActionReturn );
+ emit returnPressed();
+ }
+ break;
+ case Key_Delete:
+#if defined (Q_WS_WIN)
+ if ( e->state() & ShiftButton ) {
+ cut();
+ break;
+ } else
+#endif
+ if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
+ removeSelectedText();
+ break;
+ }
+ doKeyboardAction( e->state() & ControlButton ? ActionWordDelete
+ : ActionDelete );
+ clearUndoRedoInfo = FALSE;
+
+ break;
+ case Key_Insert:
+ if ( e->state() & ShiftButton )
+ paste();
+#if defined (Q_WS_WIN)
+ else if ( e->state() & ControlButton )
+ copy();
+#endif
+ else
+ setOverwriteMode( !isOverwriteMode() );
+ break;
+ case Key_Backspace:
+#if defined (Q_WS_WIN)
+ if ( e->state() & AltButton ) {
+ if (e->state() & ControlButton ) {
+ break;
+ } else if ( e->state() & ShiftButton ) {
+ redo();
+ break;
+ } else {
+ undo();
+ break;
+ }
+ } else
+#endif
+ if ( doc->hasSelection( QTextDocument::Standard, TRUE ) ) {
+ removeSelectedText();
+ break;
+ }
+
+ doKeyboardAction( e->state() & ControlButton ? ActionWordBackspace
+ : ActionBackspace );
+ clearUndoRedoInfo = FALSE;
+ break;
+ case Key_F16: // Copy key on Sun keyboards
+ copy();
+ break;
+ case Key_F18: // Paste key on Sun keyboards
+ paste();
+ break;
+ case Key_F20: // Cut key on Sun keyboards
+ cut();
+ break;
+ case Key_Direction_L:
+ if ( doc->textFormat() == Qt::PlainText ) {
+ // change the whole doc
+ QTextParagraph *p = doc->firstParagraph();
+ while ( p ) {
+ p->setDirection( QChar::DirL );
+ p->setAlignment( Qt::AlignLeft );
+ p->invalidate( 0 );
+ p = p->next();
+ }
+ } else {
+ if ( !cursor->paragraph() || cursor->paragraph()->direction() == QChar::DirL )
+ return;
+ cursor->paragraph()->setDirection( QChar::DirL );
+ if ( cursor->paragraph()->length() <= 1&&
+ ( (cursor->paragraph()->alignment() & (Qt::AlignLeft | Qt::AlignRight) ) != 0 ) )
+ setAlignment( Qt::AlignLeft );
+ }
+ repaintChanged();
+ break;
+ case Key_Direction_R:
+ if ( doc->textFormat() == Qt::PlainText ) {
+ // change the whole doc
+ QTextParagraph *p = doc->firstParagraph();
+ while ( p ) {
+ p->setDirection( QChar::DirR );
+ p->setAlignment( Qt::AlignRight );
+ p->invalidate( 0 );
+ p = p->next();
+ }
+ } else {
+ if ( !cursor->paragraph() || cursor->paragraph()->direction() == QChar::DirR )
+ return;
+ cursor->paragraph()->setDirection( QChar::DirR );
+ if ( cursor->paragraph()->length() <= 1&&
+ ( (cursor->paragraph()->alignment() & (Qt::AlignLeft | Qt::AlignRight) ) != 0 ) )
+ setAlignment( Qt::AlignRight );
+ }
+ repaintChanged();
+ break;
+ default: {
+ if ( e->text().length() &&
+ ( !( e->state() & ControlButton ) &&
+#ifndef Q_OS_MACX
+ !( e->state() & AltButton ) &&
+#endif
+ !( e->state() & MetaButton ) ||
+ ( ( (e->state()&ControlButton) | AltButton ) == (ControlButton|AltButton) ) ) &&
+ ( !e->ascii() || e->ascii() >= 32 || e->text() == "\t" ) ) {
+ clearUndoRedoInfo = FALSE;
+ if ( e->key() == Key_Tab ) {
+ if ( d->tabChangesFocus ) {
+ e->ignore();
+ break;
+ }
+ if ( textFormat() == Qt::RichText && cursor->index() == 0
+ && ( cursor->paragraph()->isListItem() || cursor->paragraph()->listDepth() ) ) {
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Style;
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.eid = undoRedoInfo.id;
+ undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
+ cursor->paragraph()->setListDepth( cursor->paragraph()->listDepth() +1 );
+ clearUndoRedo();
+ drawCursor( FALSE );
+ repaintChanged();
+ drawCursor( TRUE );
+ break;
+ }
+ } else if ( e->key() == Key_BackTab ) {
+ if ( d->tabChangesFocus ) {
+ e->ignore();
+ break;
+ }
+ }
+
+ if ( ( autoFormatting() & AutoBulletList ) &&
+ textFormat() == Qt::RichText && cursor->index() == 0
+ && !cursor->paragraph()->isListItem()
+ && ( e->text()[0] == '-' || e->text()[0] == '*' ) ) {
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Style;
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.eid = undoRedoInfo.id;
+ undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
+ setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
+ clearUndoRedo();
+ drawCursor( FALSE );
+ repaintChanged();
+ drawCursor( TRUE );
+ break;
+ }
+ if (overWrite && !cursor->atParagEnd() && !doc->hasSelection(QTextDocument::Standard)) {
+ doKeyboardAction(ActionDelete);
+ clearUndoRedoInfo = FALSE;
+ }
+ QString t = e->text();
+#ifdef Q_WS_X11
+ extern bool qt_hebrew_keyboard_hack;
+ if ( qt_hebrew_keyboard_hack ) {
+ // the X11 keyboard layout is broken and does not reverse
+ // braces correctly. This is a hack to get halfway correct
+ // behaviour
+ QTextParagraph *p = cursor->paragraph();
+ if ( p && p->string() && p->string()->isRightToLeft() ) {
+ QChar *c = (QChar *)t.unicode();
+ int l = t.length();
+ while( l-- ) {
+ if ( c->mirrored() )
+ *c = c->mirroredChar();
+ c++;
+ }
+ }
+ }
+#endif
+ insert( t, TRUE, FALSE );
+ break;
+ } else if ( e->state() & ControlButton ) {
+ switch ( e->key() ) {
+ case Key_C: case Key_F16: // Copy key on Sun keyboards
+ copy();
+ break;
+ case Key_V:
+ paste();
+ break;
+ case Key_X:
+ cut();
+ break;
+ case Key_I: case Key_T: case Key_Tab:
+ if ( !d->tabChangesFocus )
+ indent();
+ break;
+ case Key_A:
+#if defined(Q_WS_X11)
+ moveCursor( MoveLineStart, e->state() & ShiftButton );
+#else
+ selectAll( TRUE );
+#endif
+ break;
+ case Key_B:
+ moveCursor( MoveBackward, e->state() & ShiftButton );
+ break;
+ case Key_F:
+ moveCursor( MoveForward, e->state() & ShiftButton );
+ break;
+ case Key_D:
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ removeSelectedText();
+ break;
+ }
+ doKeyboardAction( ActionDelete );
+ clearUndoRedoInfo = FALSE;
+ break;
+ case Key_H:
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ removeSelectedText();
+ break;
+ }
+ if ( !cursor->paragraph()->prev() &&
+ cursor->atParagStart() )
+ break;
+
+ doKeyboardAction( ActionBackspace );
+ clearUndoRedoInfo = FALSE;
+ break;
+ case Key_E:
+ moveCursor( MoveLineEnd, e->state() & ShiftButton );
+ break;
+ case Key_N:
+ moveCursor( MoveDown, e->state() & ShiftButton );
+ break;
+ case Key_P:
+ moveCursor( MoveUp, e->state() & ShiftButton );
+ break;
+ case Key_Z:
+ if(e->state() & ShiftButton)
+ redo();
+ else
+ undo();
+ break;
+ case Key_Y:
+ redo();
+ break;
+ case Key_K:
+ doKeyboardAction( ActionKill );
+ break;
+#if defined(Q_WS_WIN)
+ case Key_Insert:
+ copy();
+ break;
+ case Key_Delete:
+ del();
+ break;
+#endif
+ default:
+ unknownKey = FALSE;
+ break;
+ }
+ } else {
+ unknownKey = TRUE;
+ }
+ }
+ }
+
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+ if ( clearUndoRedoInfo )
+ clearUndoRedo();
+ changeIntervalTimer->start( 100, TRUE );
+ if ( unknownKey )
+ e->ignore();
+}
+
+/*!
+ This function is not intended as polymorphic usage. Just a shared code
+ fragment that calls QWidget::sendMouseEventToInputContext() easily for this
+ class.
+ */
+bool QTextEdit::sendMouseEventToInputContext( QMouseEvent *e )
+{
+#ifndef QT_NO_IM
+ if ( d->composeMode() ) {
+ QTextCursor c( doc );
+ if ( c.place( e->pos(), doc->firstParagraph(), FALSE, FALSE, FALSE ) ) {
+ int mousePos = c.index() - d->preeditStart;
+ if ( cursor->globalY() == c.globalY() &&
+ mousePos >= 0 && mousePos < d->preeditLength ) {
+ QWidget::sendMouseEventToInputContext( mousePos, e->type(),
+ e->button(), e->state() );
+ }
+ } else if ( e->type() != QEvent::MouseMove ) {
+ // send button events on out of preedit
+ QWidget::sendMouseEventToInputContext( -1, e->type(),
+ e->button(), e->state() );
+ }
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+
+/*!
+ \reimp
+*/
+void QTextEdit::imStartEvent( QIMEvent *e )
+{
+ if ( isReadOnly() ) {
+ e->ignore();
+ return;
+ }
+
+ if ( hasSelectedText() )
+ removeSelectedText();
+ d->preeditStart = cursor->index();
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::IME;
+}
+
+/*!
+ \reimp
+*/
+void QTextEdit::imComposeEvent( QIMEvent *e )
+{
+ if ( isReadOnly() ) {
+ e->ignore();
+ return;
+ }
+
+ doc->removeSelection( QTextDocument::IMCompositionText );
+ doc->removeSelection( QTextDocument::IMSelectionText );
+
+ if ( d->composeMode() && cursor->paragraph() )
+ cursor->paragraph()->remove( d->preeditStart, d->preeditLength );
+ cursor->setIndex( d->preeditStart );
+ d->preeditLength = e->text().length();
+
+ int sellen = e->selectionLength();
+ uint insertionFlags = CheckNewLines | RemoveSelected | AsIMCompositionText;
+ if ( sellen > 0 ) {
+ insertionFlags |= WithIMSelection;
+ }
+ insert( e->text(), insertionFlags );
+ // insert can trigger an imEnd event as it emits a textChanged signal, so better
+ // be careful
+ if(d->preeditStart != -1) {
+ cursor->setIndex( d->preeditStart + d->preeditLength );
+ QTextCursor c = *cursor;
+ cursor->setIndex( d->preeditStart );
+ doc->setSelectionStart( QTextDocument::IMCompositionText, *cursor );
+ doc->setSelectionEnd( QTextDocument::IMCompositionText, c );
+
+ cursor->setIndex( d->preeditStart + e->cursorPos() );
+
+ if ( sellen > 0 ) {
+ cursor->setIndex( d->preeditStart + e->cursorPos() + sellen );
+ c = *cursor;
+ cursor->setIndex( d->preeditStart + e->cursorPos() );
+ doc->setSelectionStart( QTextDocument::IMSelectionText, *cursor );
+ doc->setSelectionEnd( QTextDocument::IMSelectionText, c );
+#if 0
+ // Disabled for Asian input method that shows candidate
+ // window. This behavior is same as Qt/E 2.3.7 which supports
+ // Asian input methods. Asian input methods need start point
+ // of IM selection text to place candidate window as adjacent
+ // to the selection text.
+ cursor->setIndex( d->preeditStart + d->preeditLength );
+#endif
+ }
+ }
+
+ updateMicroFocusHint();
+ repaintChanged();
+}
+
+/*!
+ \reimp
+*/
+void QTextEdit::imEndEvent( QIMEvent *e )
+{
+ if ( isReadOnly() ) {
+ e->ignore();
+ return;
+ }
+
+ doc->removeSelection( QTextDocument::IMCompositionText );
+ doc->removeSelection( QTextDocument::IMSelectionText );
+
+ if (undoRedoInfo.type == UndoRedoInfo::IME)
+ undoRedoInfo.type = UndoRedoInfo::Invalid;
+
+ if ( d->composeMode() && cursor->paragraph() )
+ cursor->paragraph()->remove( d->preeditStart, d->preeditLength );
+ if ( d->preeditStart >= 0 ) {
+ cursor->setIndex( d->preeditStart );
+ //TODO: Qt 4 we should use the new virtual insert function
+ insert( e->text(), FALSE );
+ }
+ d->preeditStart = d->preeditLength = -1;
+
+ repaintChanged();
+}
+
+
+static bool qtextedit_ignore_readonly = FALSE;
+
+/*!
+ Executes keyboard action \a action. This is normally called by a
+ key event handler.
+*/
+
+void QTextEdit::doKeyboardAction( KeyboardAction action )
+{
+ if ( isReadOnly() && !qtextedit_ignore_readonly )
+ return;
+
+ if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
+ return;
+
+ lastFormatted = cursor->paragraph();
+ drawCursor( FALSE );
+ bool doUpdateCurrentFormat = TRUE;
+
+ switch ( action ) {
+ case ActionWordDelete:
+ case ActionDelete:
+ if ( action == ActionDelete && !cursor->atParagEnd() ) {
+ if ( undoEnabled ) {
+ checkUndoRedoInfo( UndoRedoInfo::Delete );
+ if ( !undoRedoInfo.valid() ) {
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.index = cursor->index();
+ undoRedoInfo.d->text = QString::null;
+ }
+ int idx = cursor->index();
+ do {
+ undoRedoInfo.d->text.insert( undoRedoInfo.d->text.length(), cursor->paragraph()->at( idx++ ), TRUE );
+ } while ( !cursor->paragraph()->string()->validCursorPosition( idx ) );
+ }
+ cursor->remove();
+ } else {
+ clearUndoRedo();
+ doc->setSelectionStart( QTextDocument::Temp, *cursor );
+ if ( action == ActionWordDelete && !cursor->atParagEnd() ) {
+ cursor->gotoNextWord();
+ } else {
+ cursor->gotoNextLetter();
+ }
+ doc->setSelectionEnd( QTextDocument::Temp, *cursor );
+ removeSelectedText( QTextDocument::Temp );
+ }
+ break;
+ case ActionWordBackspace:
+ case ActionBackspace:
+ if ( textFormat() == Qt::RichText
+ && (cursor->paragraph()->isListItem()
+ || cursor->paragraph()->listDepth() )
+ && cursor->index() == 0 ) {
+ if ( undoEnabled ) {
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Style;
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.eid = undoRedoInfo.id;
+ undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
+ }
+ int ldepth = cursor->paragraph()->listDepth();
+ if ( cursor->paragraph()->isListItem() && ldepth == 1 ) {
+ cursor->paragraph()->setListItem( FALSE );
+ } else if ( QMAX( ldepth, 1 ) == 1 ) {
+ cursor->paragraph()->setListItem( FALSE );
+ cursor->paragraph()->setListDepth( 0 );
+ } else {
+ cursor->paragraph()->setListDepth( ldepth - 1 );
+ }
+ clearUndoRedo();
+ lastFormatted = cursor->paragraph();
+ repaintChanged();
+ drawCursor( TRUE );
+ return;
+ }
+
+ if ( action == ActionBackspace && !cursor->atParagStart() ) {
+ if ( undoEnabled ) {
+ checkUndoRedoInfo( UndoRedoInfo::Delete );
+ if ( !undoRedoInfo.valid() ) {
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.index = cursor->index();
+ undoRedoInfo.d->text = QString::null;
+ }
+ undoRedoInfo.d->text.insert( 0, cursor->paragraph()->at( cursor->index()-1 ), TRUE );
+ undoRedoInfo.index = cursor->index()-1;
+ }
+ cursor->removePreviousChar();
+ lastFormatted = cursor->paragraph();
+ } else if ( cursor->paragraph()->prev()
+ || (action == ActionWordBackspace
+ && !cursor->atParagStart()) ) {
+ clearUndoRedo();
+ doc->setSelectionStart( QTextDocument::Temp, *cursor );
+ if ( action == ActionWordBackspace && !cursor->atParagStart() ) {
+ cursor->gotoPreviousWord();
+ } else {
+ cursor->gotoPreviousLetter();
+ }
+ doc->setSelectionEnd( QTextDocument::Temp, *cursor );
+ removeSelectedText( QTextDocument::Temp );
+ }
+ break;
+ case ActionReturn:
+ if ( undoEnabled ) {
+ checkUndoRedoInfo( UndoRedoInfo::Return );
+ if ( !undoRedoInfo.valid() ) {
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.index = cursor->index();
+ undoRedoInfo.d->text = QString::null;
+ }
+ undoRedoInfo.d->text += "\n";
+ }
+ cursor->splitAndInsertEmptyParagraph();
+ if ( cursor->paragraph()->prev() ) {
+ lastFormatted = cursor->paragraph()->prev();
+ lastFormatted->invalidate( 0 );
+ }
+ doUpdateCurrentFormat = FALSE;
+ break;
+ case ActionKill:
+ clearUndoRedo();
+ doc->setSelectionStart( QTextDocument::Temp, *cursor );
+ if ( cursor->atParagEnd() )
+ cursor->gotoNextLetter();
+ else
+ cursor->setIndex( cursor->paragraph()->length() - 1 );
+ doc->setSelectionEnd( QTextDocument::Temp, *cursor );
+ removeSelectedText( QTextDocument::Temp );
+ break;
+ }
+
+ formatMore();
+ repaintChanged();
+ ensureCursorVisible();
+ drawCursor( TRUE );
+ updateMicroFocusHint();
+ if ( doUpdateCurrentFormat )
+ updateCurrentFormat();
+ setModified();
+ emit textChanged();
+}
+
+void QTextEdit::readFormats( QTextCursor &c1, QTextCursor &c2, QTextString &text, bool fillStyles )
+{
+#ifndef QT_NO_DATASTREAM
+ QDataStream styleStream( undoRedoInfo.styleInformation, IO_WriteOnly );
+#endif
+ c2.restoreState();
+ c1.restoreState();
+ int lastIndex = text.length();
+ if ( c1.paragraph() == c2.paragraph() ) {
+ for ( int i = c1.index(); i < c2.index(); ++i )
+ text.insert( lastIndex + i - c1.index(), c1.paragraph()->at( i ), TRUE );
+#ifndef QT_NO_DATASTREAM
+ if ( fillStyles ) {
+ styleStream << (int) 1;
+ c1.paragraph()->writeStyleInformation( styleStream );
+ }
+#endif
+ } else {
+ int i;
+ for ( i = c1.index(); i < c1.paragraph()->length()-1; ++i )
+ text.insert( lastIndex++, c1.paragraph()->at( i ), TRUE );
+ int num = 2; // start and end, being different
+ text += "\n"; lastIndex++;
+
+ if (c1.paragraph()->next() != c2.paragraph()) {
+ num += text.appendParagraphs(c1.paragraph()->next(), c2.paragraph());
+ lastIndex = text.length();
+ }
+
+ for ( i = 0; i < c2.index(); ++i )
+ text.insert( i + lastIndex, c2.paragraph()->at( i ), TRUE );
+#ifndef QT_NO_DATASTREAM
+ if ( fillStyles ) {
+ styleStream << num;
+ for ( QTextParagraph *p = c1.paragraph(); --num >= 0; p = p->next() )
+ p->writeStyleInformation( styleStream );
+ }
+#endif
+ }
+}
+
+/*!
+ Removes the selection \a selNum (by default 0). This does not
+ remove the selected text.
+
+ \sa removeSelectedText()
+*/
+
+void QTextEdit::removeSelection( int selNum )
+{
+ doc->removeSelection( selNum );
+ repaintChanged();
+}
+
+/*!
+ Deletes the text of selection \a selNum (by default, the default
+ selection, 0). If there is no selected text nothing happens.
+
+ \sa selectedText removeSelection()
+*/
+
+void QTextEdit::removeSelectedText( int selNum )
+{
+ if(selNum != 0)
+ resetInputContext();
+
+ QTextCursor c1 = doc->selectionStartCursor( selNum );
+ c1.restoreState();
+ QTextCursor c2 = doc->selectionEndCursor( selNum );
+ c2.restoreState();
+
+ // ### no support for editing tables yet, plus security for broken selections
+ if ( c1.nestedDepth() || c2.nestedDepth() )
+ return;
+
+ for ( int i = 0; i < (int)doc->numSelections(); ++i ) {
+ if ( i == selNum )
+ continue;
+ doc->removeSelection( i );
+ }
+
+ drawCursor( FALSE );
+ if ( undoEnabled ) {
+ checkUndoRedoInfo( UndoRedoInfo::RemoveSelected );
+ if ( !undoRedoInfo.valid() ) {
+ doc->selectionStart( selNum, undoRedoInfo.id, undoRedoInfo.index );
+ undoRedoInfo.d->text = QString::null;
+ }
+ readFormats( c1, c2, undoRedoInfo.d->text, TRUE );
+ }
+
+ doc->removeSelectedText( selNum, cursor );
+ if ( cursor->isValid() ) {
+ lastFormatted = 0; // make sync a noop
+ ensureCursorVisible();
+ lastFormatted = cursor->paragraph();
+ formatMore();
+ repaintContents( FALSE );
+ ensureCursorVisible();
+ drawCursor( TRUE );
+ clearUndoRedo();
+#if defined(Q_WS_WIN)
+ // there seems to be a problem with repainting or erasing the area
+ // of the scrollview which is not the contents on windows
+ if ( contentsHeight() < visibleHeight() )
+ viewport()->repaint( 0, contentsHeight(), visibleWidth(), visibleHeight() - contentsHeight(), TRUE );
+#endif
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ updateMicroFocusHint();
+ } else {
+ delete cursor;
+ cursor = new QTextCursor( doc );
+ drawCursor( TRUE );
+ repaintContents( TRUE );
+ }
+ setModified();
+ emit textChanged();
+ emit selectionChanged();
+ emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
+}
+
+/*!
+ Moves the text cursor according to \a action. This is normally
+ used by some key event handler. \a select specifies whether the
+ text between the current cursor position and the new position
+ should be selected.
+*/
+
+void QTextEdit::moveCursor( CursorAction action, bool select )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return;
+#endif
+#ifdef Q_WS_MACX
+ QTextCursor c1 = *cursor;
+ QTextCursor c2;
+#endif
+ drawCursor( FALSE );
+ if ( select ) {
+ if ( !doc->hasSelection( QTextDocument::Standard ) )
+ doc->setSelectionStart( QTextDocument::Standard, *cursor );
+ moveCursor( action );
+#ifdef Q_WS_MACX
+ c2 = *cursor;
+ if (c1 == c2)
+ if (action == MoveDown || action == MovePgDown)
+ moveCursor( MoveEnd );
+ else if (action == MoveUp || action == MovePgUp)
+ moveCursor( MoveHome );
+#endif
+ if ( doc->setSelectionEnd( QTextDocument::Standard, *cursor ) ) {
+ cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
+ repaintChanged();
+ } else {
+ drawCursor( TRUE );
+ }
+ ensureCursorVisible();
+ emit selectionChanged();
+ emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
+ } else {
+#ifdef Q_WS_MACX
+ QTextCursor cStart = doc->selectionStartCursor( QTextDocument::Standard );
+ QTextCursor cEnd = doc->selectionEndCursor( QTextDocument::Standard );
+ bool redraw = doc->removeSelection( QTextDocument::Standard );
+ if (redraw && action == MoveDown)
+ *cursor = cEnd;
+ else if (redraw && action == MoveUp)
+ *cursor = cStart;
+ if (redraw && action == MoveForward)
+ *cursor = cEnd;
+ else if (redraw && action == MoveBackward)
+ *cursor = cStart;
+ else
+ moveCursor( action );
+ c2 = *cursor;
+ if (c1 == c2)
+ if (action == MoveDown)
+ moveCursor( MoveEnd );
+ else if (action == MoveUp)
+ moveCursor( MoveHome );
+#else
+ bool redraw = doc->removeSelection( QTextDocument::Standard );
+ moveCursor( action );
+#endif
+ if ( !redraw ) {
+ ensureCursorVisible();
+ drawCursor( TRUE );
+ } else {
+ cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
+ repaintChanged();
+ ensureCursorVisible();
+ drawCursor( TRUE );
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ }
+ if ( redraw ) {
+ emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
+ emit selectionChanged();
+ }
+ }
+
+ drawCursor( TRUE );
+ updateCurrentFormat();
+ updateMicroFocusHint();
+}
+
+/*!
+ \overload
+*/
+
+void QTextEdit::moveCursor( CursorAction action )
+{
+ resetInputContext();
+ switch ( action ) {
+ case MoveBackward:
+ cursor->gotoPreviousLetter();
+ break;
+ case MoveWordBackward:
+ cursor->gotoPreviousWord();
+ break;
+ case MoveForward:
+ cursor->gotoNextLetter();
+ break;
+ case MoveWordForward:
+ cursor->gotoNextWord();
+ break;
+ case MoveUp:
+ cursor->gotoUp();
+ break;
+ case MovePgUp:
+ cursor->gotoPageUp( visibleHeight() );
+ break;
+ case MoveDown:
+ cursor->gotoDown();
+ break;
+ case MovePgDown:
+ cursor->gotoPageDown( visibleHeight() );
+ break;
+ case MoveLineStart:
+ cursor->gotoLineStart();
+ break;
+ case MoveHome:
+ cursor->gotoHome();
+ break;
+ case MoveLineEnd:
+ cursor->gotoLineEnd();
+ break;
+ case MoveEnd:
+ ensureFormatted( doc->lastParagraph() );
+ cursor->gotoEnd();
+ break;
+ }
+ updateMicroFocusHint();
+ updateCurrentFormat();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::resizeEvent( QResizeEvent *e )
+{
+ QScrollView::resizeEvent( e );
+ if ( doc->visibleWidth() == 0 )
+ doResize();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::viewportResizeEvent( QResizeEvent *e )
+{
+ QScrollView::viewportResizeEvent( e );
+ if ( e->oldSize().width() != e->size().width() ) {
+ bool stayAtBottom = e->oldSize().height() != e->size().height() &&
+ contentsY() > 0 && contentsY() >= doc->height() - e->oldSize().height();
+ doResize();
+ if ( stayAtBottom )
+ scrollToBottom();
+ }
+}
+
+/*!
+ Ensures that the cursor is visible by scrolling the text edit if
+ necessary.
+
+ \sa setCursorPosition()
+*/
+
+void QTextEdit::ensureCursorVisible()
+{
+ // Not visible or the user is draging the window, so don't position to caret yet
+ if ( !isUpdatesEnabled() || !isVisible() || isHorizontalSliderPressed() || isVerticalSliderPressed() ) {
+ d->ensureCursorVisibleInShowEvent = TRUE;
+ return;
+ }
+ sync();
+ QTextStringChar *chr = cursor->paragraph()->at( cursor->index() );
+ int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
+ int x = cursor->paragraph()->rect().x() + chr->x + cursor->offsetX();
+ int y = 0; int dummy;
+ cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y );
+ y += cursor->paragraph()->rect().y() + cursor->offsetY();
+ int w = 1;
+ ensureVisible( x, y + h / 2, w, h / 2 + 2 );
+}
+
+/*!
+ \internal
+*/
+void QTextEdit::sliderReleased()
+{
+ if ( d->ensureCursorVisibleInShowEvent && isVisible() ) {
+ d->ensureCursorVisibleInShowEvent = FALSE;
+ ensureCursorVisible();
+ }
+}
+
+/*!
+ \internal
+*/
+void QTextEdit::drawCursor( bool visible )
+{
+ if ( !isUpdatesEnabled() ||
+ !viewport()->isUpdatesEnabled() ||
+ !cursor->paragraph() ||
+ !cursor->paragraph()->isValid() ||
+ ( !style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ) &&
+ ( d->optimMode ? optimHasSelection() : doc->hasSelection( QTextDocument::Standard, TRUE ))) ||
+ ( visible && !hasFocus() && !viewport()->hasFocus() && !inDnD ) ||
+ doc->hasSelection( QTextDocument::IMSelectionText ) ||
+ isReadOnly() )
+ return;
+
+ // Asian users regard selection text as cursor on candidate
+ // selection phase of input method, so ordinary cursor should be
+ // invisible if IM selection text exists.
+ if ( doc->hasSelection( QTextDocument::IMSelectionText ) ) {
+ visible = FALSE;
+ }
+
+ QPainter p( viewport() );
+ QRect r( cursor->topParagraph()->rect() );
+ cursor->paragraph()->setChanged( TRUE );
+ p.translate( -contentsX() + cursor->totalOffsetX(), -contentsY() + cursor->totalOffsetY() );
+ QPixmap *pix = 0;
+ QColorGroup cg( colorGroup() );
+ const QColorGroup::ColorRole backRole = QPalette::backgroundRoleFromMode(backgroundMode());
+ if ( cursor->paragraph()->background() )
+ cg.setBrush( backRole, *cursor->paragraph()->background() );
+ else if ( doc->paper() )
+ cg.setBrush( backRole, *doc->paper() );
+ p.setBrushOrigin( -contentsX(), -contentsY() );
+ cursor->paragraph()->document()->nextDoubleBuffered = TRUE;
+ if ( !cursor->nestedDepth() ) {
+ int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
+ int dist = 5;
+ if ( ( cursor->paragraph()->alignment() & Qt::AlignJustify ) == Qt::AlignJustify )
+ dist = 50;
+ int x = r.x() - cursor->totalOffsetX() + cursor->x() - dist;
+ x = QMAX( x, 0 );
+ p.setClipRect( QRect( x - contentsX(),
+ r.y() - cursor->totalOffsetY() + cursor->y() - contentsY(), 2 * dist, h ) );
+ doc->drawParagraph( &p, cursor->paragraph(), x,
+ r.y() - cursor->totalOffsetY() + cursor->y(), 2 * dist, h, pix, cg, visible, cursor );
+ } else {
+ doc->drawParagraph( &p, cursor->paragraph(), r.x() - cursor->totalOffsetX(),
+ r.y() - cursor->totalOffsetY(), r.width(), r.height(),
+ pix, cg, visible, cursor );
+ }
+ cursorVisible = visible;
+}
+
+enum {
+ IdUndo = 0,
+ IdRedo = 1,
+ IdCut = 2,
+ IdCopy = 3,
+ IdPaste = 4,
+ IdClear = 5,
+ IdSelectAll = 6
+};
+
+/*!
+ \reimp
+*/
+#ifndef QT_NO_WHEELEVENT
+void QTextEdit::contentsWheelEvent( QWheelEvent *e )
+{
+ if ( isReadOnly() ) {
+ if ( e->state() & ControlButton ) {
+ if ( e->delta() > 0 )
+ zoomOut();
+ else if ( e->delta() < 0 )
+ zoomIn();
+ return;
+ }
+ }
+ QScrollView::contentsWheelEvent( e );
+}
+#endif
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsMousePressEvent( QMouseEvent *e )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimMousePressEvent( e );
+ return;
+ }
+#endif
+
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+
+ if ( d->trippleClickTimer->isActive() &&
+ ( e->globalPos() - d->trippleClickPoint ).manhattanLength() <
+ QApplication::startDragDistance() ) {
+ QTextCursor c1 = *cursor;
+ QTextCursor c2 = *cursor;
+ c1.gotoLineStart();
+ c2.gotoLineEnd();
+ doc->setSelectionStart( QTextDocument::Standard, c1 );
+ doc->setSelectionEnd( QTextDocument::Standard, c2 );
+ *cursor = c2;
+ repaintChanged();
+ mousePressed = TRUE;
+ return;
+ }
+
+ clearUndoRedo();
+ QTextCursor oldCursor = *cursor;
+ QTextCursor c = *cursor;
+ mousePos = e->pos();
+ mightStartDrag = FALSE;
+ pressedLink = QString::null;
+ d->pressedName = QString::null;
+
+ if ( e->button() == LeftButton ) {
+ mousePressed = TRUE;
+ drawCursor( FALSE );
+ placeCursor( e->pos() );
+ ensureCursorVisible();
+
+ if ( isReadOnly() && linksEnabled() ) {
+ QTextCursor c = *cursor;
+ placeCursor( e->pos(), &c, TRUE );
+ if ( c.paragraph() && c.paragraph()->at( c.index() ) &&
+ c.paragraph()->at( c.index() )->isAnchor() ) {
+ pressedLink = c.paragraph()->at( c.index() )->anchorHref();
+ d->pressedName = c.paragraph()->at( c.index() )->anchorName();
+ }
+ }
+
+#ifndef QT_NO_DRAGANDDROP
+ if ( doc->inSelection( QTextDocument::Standard, e->pos() ) ) {
+ mightStartDrag = TRUE;
+ drawCursor( TRUE );
+ dragStartTimer->start( QApplication::startDragTime(), TRUE );
+ dragStartPos = e->pos();
+ return;
+ }
+#endif
+
+ bool redraw = FALSE;
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ if ( !( e->state() & ShiftButton ) ) {
+ redraw = doc->removeSelection( QTextDocument::Standard );
+ doc->setSelectionStart( QTextDocument::Standard, *cursor );
+ } else {
+ redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
+ }
+ } else {
+ if ( isReadOnly() || !( e->state() & ShiftButton ) ) {
+ doc->setSelectionStart( QTextDocument::Standard, *cursor );
+ } else {
+ doc->setSelectionStart( QTextDocument::Standard, c );
+ redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
+ }
+ }
+
+ for ( int i = 1; i < doc->numSelections(); ++i ) // start with 1 as we don't want to remove the Standard-Selection
+ redraw = doc->removeSelection( i ) || redraw;
+
+ if ( !redraw ) {
+ drawCursor( TRUE );
+ } else {
+ repaintChanged();
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ }
+ } else if ( e->button() == MidButton ) {
+ bool redraw = doc->removeSelection( QTextDocument::Standard );
+ if ( !redraw ) {
+ drawCursor( TRUE );
+ } else {
+ repaintChanged();
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ }
+ }
+
+ if ( *cursor != oldCursor )
+ updateCurrentFormat();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsMouseMoveEvent( QMouseEvent *e )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimMouseMoveEvent( e );
+ return;
+ }
+#endif
+ if ( sendMouseEventToInputContext( e ) ) {
+ // don't return from here to avoid cursor vanishing
+ } else if ( mousePressed ) {
+#ifndef QT_NO_DRAGANDDROP
+ if ( mightStartDrag ) {
+ dragStartTimer->stop();
+ if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() ) {
+ QGuardedPtr<QTextEdit> guard( this );
+ startDrag();
+ if (guard.isNull()) // we got deleted during the dnd
+ return;
+ }
+#ifndef QT_NO_CURSOR
+ if ( !isReadOnly() )
+ viewport()->setCursor( ibeamCursor );
+#endif
+ return;
+ }
+#endif
+ mousePos = e->pos();
+ handleMouseMove( mousePos );
+ oldMousePos = mousePos;
+ }
+
+#ifndef QT_NO_CURSOR
+ if ( !isReadOnly() && !mousePressed ) {
+ if ( doc->hasSelection( QTextDocument::Standard ) && doc->inSelection( QTextDocument::Standard, e->pos() ) )
+ viewport()->setCursor( arrowCursor );
+ else
+ viewport()->setCursor( ibeamCursor );
+ }
+#endif
+ updateCursor( e->pos() );
+}
+
+void QTextEdit::copyToClipboard()
+{
+#ifndef QT_NO_CLIPBOARD
+ if (QApplication::clipboard()->supportsSelection()) {
+ d->clipboard_mode = QClipboard::Selection;
+
+ // don't listen to selection changes
+ disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
+ copy();
+ // listen to selection changes
+ connect( QApplication::clipboard(), SIGNAL(selectionChanged()),
+ this, SLOT(clipboardChanged()) );
+
+ d->clipboard_mode = QClipboard::Clipboard;
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsMouseReleaseEvent( QMouseEvent * e )
+{
+ if ( !inDoubleClick && !d->composeMode() ) { // could be the release of a dblclick
+ int para = 0;
+ int index = charAt( e->pos(), &para );
+ emit clicked( para, index );
+ }
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimMouseReleaseEvent( e );
+ return;
+ }
+#endif
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+ QTextCursor oldCursor = *cursor;
+ if ( scrollTimer->isActive() )
+ scrollTimer->stop();
+#ifndef QT_NO_DRAGANDDROP
+ if ( dragStartTimer->isActive() )
+ dragStartTimer->stop();
+ if ( mightStartDrag ) {
+ selectAll( FALSE );
+ mousePressed = FALSE;
+ }
+#endif
+ bool mouseWasPressed = mousePressed;
+ if ( mousePressed ) {
+ mousePressed = FALSE;
+ copyToClipboard();
+ }
+#ifndef QT_NO_CLIPBOARD
+ else if ( e->button() == MidButton && !isReadOnly() ) {
+ // only do middle-click pasting on systems that have selections (ie. X11)
+ if (QApplication::clipboard()->supportsSelection()) {
+ drawCursor( FALSE );
+ placeCursor( e->pos() );
+ ensureCursorVisible();
+ doc->setSelectionStart( QTextDocument::Standard, oldCursor );
+ bool redraw = FALSE;
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ redraw = doc->removeSelection( QTextDocument::Standard );
+ doc->setSelectionStart( QTextDocument::Standard, *cursor );
+ } else {
+ doc->setSelectionStart( QTextDocument::Standard, *cursor );
+ }
+ // start with 1 as we don't want to remove the Standard-Selection
+ for ( int i = 1; i < doc->numSelections(); ++i )
+ redraw = doc->removeSelection( i ) || redraw;
+ if ( !redraw ) {
+ drawCursor( TRUE );
+ } else {
+ repaintChanged();
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( ibeamCursor );
+#endif
+ }
+ d->clipboard_mode = QClipboard::Selection;
+ paste();
+ d->clipboard_mode = QClipboard::Clipboard;
+ }
+ }
+#endif
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+ if ( oldCursor != *cursor )
+ updateCurrentFormat();
+ inDoubleClick = FALSE;
+
+#ifndef QT_NO_NETWORKPROTOCOL
+ if ( ( (!onLink.isEmpty() && onLink == pressedLink)
+ || (!d->onName.isEmpty() && d->onName == d->pressedName))
+ && linksEnabled() && mouseWasPressed ) {
+ if (!onLink.isEmpty()) {
+ QUrl u( doc->context(), onLink, TRUE );
+ emitLinkClicked( u.toString( FALSE, FALSE ) );
+ }
+ if (::qt_cast<QTextBrowser*>(this)) { // change for 4.0
+ QConnectionList *clist = receivers(
+ "anchorClicked(const QString&,const QString&)");
+ if (!signalsBlocked() && clist) {
+ QUObject o[3];
+ static_QUType_QString.set(o+1, d->onName);
+ static_QUType_QString.set(o+2, onLink);
+ activate_signal( clist, o);
+ }
+ }
+
+ // emitting linkClicked() may result in that the cursor winds
+ // up hovering over a different valid link - check this and
+ // set the appropriate cursor shape
+ updateCursor( e->pos() );
+ }
+#endif
+ drawCursor( TRUE );
+ if ( !doc->hasSelection( QTextDocument::Standard, TRUE ) )
+ doc->removeSelection( QTextDocument::Standard );
+
+ emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
+ emit selectionChanged();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsMouseDoubleClickEvent( QMouseEvent * e )
+{
+ if ( e->button() != Qt::LeftButton && !d->composeMode() ) {
+ e->ignore();
+ return;
+ }
+ int para = 0;
+ int index = charAt( e->pos(), &para );
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ QString str = d->od->lines[ LOGOFFSET(para) ];
+ int startIdx = index, endIdx = index, i;
+ if ( !str[ index ].isSpace() ) {
+ i = startIdx;
+ // find start of word
+ while ( i >= 0 && !str[ i ].isSpace() ) {
+ startIdx = i--;
+ }
+ i = endIdx;
+ // find end of word..
+ while ( (uint) i < str.length() && !str[ i ].isSpace() ) {
+ endIdx = ++i;
+ }
+ // ..and start of next
+ while ( (uint) i < str.length() && str[ i ].isSpace() ) {
+ endIdx = ++i;
+ }
+ optimSetSelection( para, startIdx, para, endIdx );
+ repaintContents( FALSE );
+ }
+ } else
+#endif
+ {
+ if ( sendMouseEventToInputContext( e ) )
+ return;
+
+ QTextCursor c1 = *cursor;
+ QTextCursor c2 = *cursor;
+#if defined(Q_OS_MAC)
+ QTextParagraph *para = cursor->paragraph();
+ if ( cursor->isValid() ) {
+ if ( para->at( cursor->index() )->c.isLetterOrNumber() ) {
+ while ( c1.index() > 0 &&
+ c1.paragraph()->at( c1.index()-1 )->c.isLetterOrNumber() )
+ c1.gotoPreviousLetter();
+ while ( c2.paragraph()->at( c2.index() )->c.isLetterOrNumber() &&
+ !c2.atParagEnd() )
+ c2.gotoNextLetter();
+ } else if ( para->at( cursor->index() )->c.isSpace() ) {
+ while ( c1.index() > 0 &&
+ c1.paragraph()->at( c1.index()-1 )->c.isSpace() )
+ c1.gotoPreviousLetter();
+ while ( c2.paragraph()->at( c2.index() )->c.isSpace() &&
+ !c2.atParagEnd() )
+ c2.gotoNextLetter();
+ } else if ( !c2.atParagEnd() ) {
+ c2.gotoNextLetter();
+ }
+ }
+#else
+ if ( cursor->index() > 0 && !cursor->paragraph()->at( cursor->index()-1 )->c.isSpace() )
+ c1.gotoPreviousWord();
+ if ( !cursor->paragraph()->at( cursor->index() )->c.isSpace() && !cursor->atParagEnd() )
+ c2.gotoNextWord();
+#endif
+ doc->setSelectionStart( QTextDocument::Standard, c1 );
+ doc->setSelectionEnd( QTextDocument::Standard, c2 );
+
+ *cursor = c2;
+
+ repaintChanged();
+
+ d->trippleClickTimer->start( qApp->doubleClickInterval(), TRUE );
+ d->trippleClickPoint = e->globalPos();
+ }
+ inDoubleClick = TRUE;
+ mousePressed = TRUE;
+ emit doubleClicked( para, index );
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
+ e->ignore();
+ return;
+ }
+ e->acceptAction();
+ inDnD = TRUE;
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if ( isReadOnly() || !QTextDrag::canDecode( e ) ) {
+ e->ignore();
+ return;
+ }
+ drawCursor( FALSE );
+ placeCursor( e->pos(), cursor );
+ drawCursor( TRUE );
+ e->acceptAction();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsDragLeaveEvent( QDragLeaveEvent * )
+{
+ drawCursor( FALSE );
+ inDnD = FALSE;
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::contentsDropEvent( QDropEvent *e )
+{
+ if ( isReadOnly() )
+ return;
+ inDnD = FALSE;
+ e->acceptAction();
+ bool intern = FALSE;
+ if ( QRichTextDrag::canDecode( e ) ) {
+ bool hasSel = doc->hasSelection( QTextDocument::Standard );
+ bool internalDrag = e->source() == this || e->source() == viewport();
+ int dropId, dropIndex;
+ QTextCursor insertCursor = *cursor;
+ dropId = cursor->paragraph()->paragId();
+ dropIndex = cursor->index();
+ if ( hasSel && internalDrag ) {
+ QTextCursor c1, c2;
+ int selStartId, selStartIndex;
+ int selEndId, selEndIndex;
+ c1 = doc->selectionStartCursor( QTextDocument::Standard );
+ c1.restoreState();
+ c2 = doc->selectionEndCursor( QTextDocument::Standard );
+ c2.restoreState();
+ selStartId = c1.paragraph()->paragId();
+ selStartIndex = c1.index();
+ selEndId = c2.paragraph()->paragId();
+ selEndIndex = c2.index();
+ if ( ( ( dropId > selStartId ) ||
+ ( dropId == selStartId && dropIndex > selStartIndex ) ) &&
+ ( ( dropId < selEndId ) ||
+ ( dropId == selEndId && dropIndex <= selEndIndex ) ) )
+ insertCursor = c1;
+ if ( dropId == selEndId && dropIndex > selEndIndex ) {
+ insertCursor = c1;
+ if ( selStartId == selEndId ) {
+ insertCursor.setIndex( dropIndex -
+ ( selEndIndex - selStartIndex ) );
+ } else {
+ insertCursor.setIndex( dropIndex - selEndIndex +
+ selStartIndex );
+ }
+ }
+ }
+
+ if ( internalDrag && e->action() == QDropEvent::Move ) {
+ removeSelectedText();
+ intern = TRUE;
+ doc->removeSelection( QTextDocument::Standard );
+ } else {
+ doc->removeSelection( QTextDocument::Standard );
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ }
+ drawCursor( FALSE );
+ cursor->setParagraph( insertCursor.paragraph() );
+ cursor->setIndex( insertCursor.index() );
+ drawCursor( TRUE );
+ if ( !cursor->nestedDepth() ) {
+ QString subType = "plain";
+ if ( textFormat() != PlainText ) {
+ if ( e->provides( "application/x-qrichtext" ) )
+ subType = "x-qrichtext";
+ }
+#ifndef QT_NO_CLIPBOARD
+ pasteSubType( subType.latin1(), e );
+#endif
+ // emit appropriate signals.
+ emit selectionChanged();
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+ } else {
+ if ( intern )
+ undo();
+ e->ignore();
+ }
+ }
+}
+
+#endif
+
+/*!
+ \reimp
+*/
+void QTextEdit::contentsContextMenuEvent( QContextMenuEvent *e )
+{
+ e->accept();
+#ifndef QT_NO_IM
+ if ( d->composeMode() )
+ return;
+#endif
+
+ clearUndoRedo();
+ mousePressed = FALSE;
+
+#ifndef QT_NO_POPUPMENU
+ QGuardedPtr<QTextEdit> that = this;
+ QGuardedPtr<QPopupMenu> popup = createPopupMenu( e->pos() );
+ if ( !popup )
+ popup = createPopupMenu();
+ if ( !popup )
+ return;
+
+ int r = popup->exec( e->globalPos() );
+ delete popup;
+ if (!that)
+ return;
+
+ if ( r == d->id[ IdClear ] )
+ clear();
+ else if ( r == d->id[ IdSelectAll ] ) {
+ selectAll();
+#ifndef QT_NO_CLIPBOARD
+ // if the clipboard support selections, put the newly selected text into
+ // the clipboard
+ if (QApplication::clipboard()->supportsSelection()) {
+ d->clipboard_mode = QClipboard::Selection;
+
+ // don't listen to selection changes
+ disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
+ copy();
+ // listen to selection changes
+ connect( QApplication::clipboard(), SIGNAL(selectionChanged()),
+ this, SLOT(clipboardChanged()) );
+
+ d->clipboard_mode = QClipboard::Clipboard;
+ }
+#endif
+ } else if ( r == d->id[ IdUndo ] )
+ undo();
+ else if ( r == d->id[ IdRedo ] )
+ redo();
+#ifndef QT_NO_CLIPBOARD
+ else if ( r == d->id[ IdCut ] )
+ cut();
+ else if ( r == d->id[ IdCopy ] )
+ copy();
+ else if ( r == d->id[ IdPaste ] )
+ paste();
+#endif
+#endif
+}
+
+
+void QTextEdit::autoScrollTimerDone()
+{
+ if ( mousePressed )
+ handleMouseMove( viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) ) );
+}
+
+void QTextEdit::handleMouseMove( const QPoint& pos )
+{
+ if ( !mousePressed )
+ return;
+
+ if ( !scrollTimer->isActive() && pos.y() < contentsY() || pos.y() > contentsY() + visibleHeight() )
+ scrollTimer->start( 100, FALSE );
+ else if ( scrollTimer->isActive() && pos.y() >= contentsY() && pos.y() <= contentsY() + visibleHeight() )
+ scrollTimer->stop();
+
+ drawCursor( FALSE );
+ QTextCursor oldCursor = *cursor;
+
+ placeCursor( pos );
+
+ if ( inDoubleClick ) {
+ QTextCursor cl = *cursor;
+ cl.gotoPreviousWord();
+ QTextCursor cr = *cursor;
+ cr.gotoNextWord();
+
+ int diff = QABS( oldCursor.paragraph()->at( oldCursor.index() )->x - mousePos.x() );
+ int ldiff = QABS( cl.paragraph()->at( cl.index() )->x - mousePos.x() );
+ int rdiff = QABS( cr.paragraph()->at( cr.index() )->x - mousePos.x() );
+
+
+ if ( cursor->paragraph()->lineStartOfChar( cursor->index() ) !=
+ oldCursor.paragraph()->lineStartOfChar( oldCursor.index() ) )
+ diff = 0xFFFFFF;
+
+ if ( rdiff < diff && rdiff < ldiff )
+ *cursor = cr;
+ else if ( ldiff < diff && ldiff < rdiff )
+ *cursor = cl;
+ else
+ *cursor = oldCursor;
+
+ }
+ ensureCursorVisible();
+
+ bool redraw = FALSE;
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ redraw = doc->setSelectionEnd( QTextDocument::Standard, *cursor ) || redraw;
+ }
+
+ if ( !redraw ) {
+ drawCursor( TRUE );
+ } else {
+ repaintChanged();
+ drawCursor( TRUE );
+ }
+
+ if ( currentFormat && currentFormat->key() != cursor->paragraph()->at( cursor->index() )->format()->key() ) {
+ currentFormat->removeRef();
+ currentFormat = doc->formatCollection()->format( cursor->paragraph()->at( cursor->index() )->format() );
+ if ( currentFormat->isMisspelled() ) {
+ currentFormat->removeRef();
+ currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
+ }
+ emit currentFontChanged( currentFormat->font() );
+ emit currentColorChanged( currentFormat->color() );
+ emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
+ }
+
+ if ( currentAlignment != cursor->paragraph()->alignment() ) {
+ currentAlignment = cursor->paragraph()->alignment();
+ block_set_alignment = TRUE;
+ emit currentAlignmentChanged( currentAlignment );
+ block_set_alignment = FALSE;
+ }
+}
+
+/*! \internal */
+
+void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c, bool link )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return;
+#endif
+ if ( !c )
+ c = cursor;
+
+ resetInputContext();
+ c->restoreState();
+ QTextParagraph *s = doc->firstParagraph();
+ c->place( pos, s, link );
+ updateMicroFocusHint();
+}
+
+
+void QTextEdit::updateMicroFocusHint()
+{
+ QTextCursor c( *cursor );
+#if 0
+ // Disabled for Asian input method that shows candidate
+ // window. This behavior is same as Qt/E 2.3.7 which supports
+ // Asian input methods. Asian input methods need start point of IM
+ // selection text to place candidate window as adjacent to the
+ // selection text.
+ if ( d->preeditStart != -1 ) {
+ c.setIndex( d->preeditStart );
+ if(doc->hasSelection(QTextDocument::IMSelectionText)) {
+ int para, index;
+ doc->selectionStart(QTextDocument::IMSelectionText, para, index);
+ c.setIndex(index);
+ }
+ }
+#endif
+
+ if ( hasFocus() || viewport()->hasFocus() ) {
+ int h = c.paragraph()->lineHeightOfChar( cursor->index() );
+ if ( !readonly ) {
+ QFont f = c.paragraph()->at( c.index() )->format()->font();
+ setMicroFocusHint( c.x() - contentsX() + frameWidth(),
+ c.y() + cursor->paragraph()->rect().y() - contentsY() + frameWidth(), 0, h, TRUE, &f );
+ }
+ }
+}
+
+
+
+void QTextEdit::formatMore()
+{
+ if ( !lastFormatted )
+ return;
+
+ int bottom = contentsHeight();
+ int lastTop = -1;
+ int lastBottom = -1;
+ int to = 20;
+ bool firstVisible = FALSE;
+ QRect cr( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
+ for ( int i = 0; lastFormatted &&
+ ( i < to || ( firstVisible && lastTop < contentsY()+height() ) );
+ i++ ) {
+ lastFormatted->format();
+ lastTop = lastFormatted->rect().top();
+ lastBottom = lastFormatted->rect().bottom();
+ if ( i == 0 )
+ firstVisible = lastBottom < cr.bottom();
+ bottom = QMAX( bottom, lastBottom );
+ lastFormatted = lastFormatted->next();
+ }
+
+ if ( bottom > contentsHeight() ) {
+ resizeContents( contentsWidth(), QMAX( doc->height(), bottom ) );
+ } else if ( !lastFormatted && lastBottom < contentsHeight() ) {
+ resizeContents( contentsWidth(), QMAX( doc->height(), lastBottom ) );
+ if ( contentsHeight() < visibleHeight() )
+ updateContents( 0, contentsHeight(), visibleWidth(),
+ visibleHeight() - contentsHeight() );
+ }
+
+ if ( lastFormatted )
+ formatTimer->start( interval, TRUE );
+ else
+ interval = QMAX( 0, interval );
+}
+
+void QTextEdit::doResize()
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( !d->optimMode )
+#endif
+ {
+ if ( wrapMode == FixedPixelWidth )
+ return;
+ doc->setMinimumWidth( -1 );
+ resizeContents( 0, 0 );
+ doc->setWidth( visibleWidth() );
+ doc->invalidate();
+ lastFormatted = doc->firstParagraph();
+ interval = 0;
+ formatMore();
+ }
+ repaintContents( FALSE );
+}
+
+/*! \internal */
+
+void QTextEdit::doChangeInterval()
+{
+ interval = 0;
+}
+
+/*!
+ \reimp
+*/
+
+bool QTextEdit::eventFilter( QObject *o, QEvent *e )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( !d->optimMode && (o == this || o == viewport()) ) {
+#else
+ if ( o == this || o == viewport() ) {
+#endif
+ if ( e->type() == QEvent::FocusIn ) {
+ if ( QApplication::cursorFlashTime() > 0 )
+ blinkTimer->start( QApplication::cursorFlashTime() / 2 );
+ drawCursor( TRUE );
+ updateMicroFocusHint();
+ } else if ( e->type() == QEvent::FocusOut ) {
+ blinkTimer->stop();
+ drawCursor( FALSE );
+ }
+ }
+
+ if ( o == this && e->type() == QEvent::PaletteChange ) {
+ QColor old( viewport()->colorGroup().color( QColorGroup::Text ) );
+ if ( old != colorGroup().color( QColorGroup::Text ) ) {
+ QColor c( colorGroup().color( QColorGroup::Text ) );
+ doc->setMinimumWidth( -1 );
+ doc->setDefaultFormat( doc->formatCollection()->defaultFormat()->font(), c );
+ lastFormatted = doc->firstParagraph();
+ formatMore();
+ repaintChanged();
+ }
+ }
+
+ return QScrollView::eventFilter( o, e );
+}
+
+/*!
+ \obsolete
+ */
+void QTextEdit::insert( const QString &text, bool indent,
+ bool checkNewLine, bool removeSelected )
+{
+ uint f = 0;
+ if ( indent )
+ f |= RedoIndentation;
+ if ( checkNewLine )
+ f |= CheckNewLines;
+ if ( removeSelected )
+ f |= RemoveSelected;
+ insert( text, f );
+}
+
+/*!
+ Inserts \a text at the current cursor position.
+
+ The \a insertionFlags define how the text is inserted. If \c
+ RedoIndentation is set, the paragraph is re-indented. If \c
+ CheckNewLines is set, newline characters in \a text result in hard
+ line breaks (i.e. new paragraphs). If \c checkNewLine is not set,
+ the behaviour of the editor is undefined if the \a text contains
+ newlines. (It is not possible to change QTextEdit's newline handling
+ behavior, but you can use QString::replace() to preprocess text
+ before inserting it.) If \c RemoveSelected is set, any selected
+ text (in selection 0) is removed before the text is inserted.
+
+ The default flags are \c CheckNewLines | \c RemoveSelected.
+
+ If the widget is in \c LogText mode this function will do nothing.
+
+ \sa paste() pasteSubType()
+*/
+
+
+void QTextEdit::insert( const QString &text, uint insertionFlags )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return;
+#endif
+
+ if ( cursor->nestedDepth() != 0 ) // #### for 3.0, disable editing of tables as this is not advanced enough
+ return;
+
+ bool indent = insertionFlags & RedoIndentation;
+ bool checkNewLine = insertionFlags & CheckNewLines;
+ bool removeSelected = insertionFlags & RemoveSelected;
+ bool imComposition = insertionFlags & AsIMCompositionText;
+ bool imSelection = insertionFlags & WithIMSelection;
+ QString txt( text );
+ drawCursor( FALSE );
+ if ( !isReadOnly() && doc->hasSelection( QTextDocument::Standard ) && removeSelected )
+ removeSelectedText();
+ QTextCursor c2 = *cursor;
+ int oldLen = 0;
+
+ if ( undoEnabled && !isReadOnly() && undoRedoInfo.type != UndoRedoInfo::IME ) {
+ checkUndoRedoInfo( UndoRedoInfo::Insert );
+
+ if (undoRedoInfo.valid() && undoRedoInfo.index + undoRedoInfo.d->text.length() != cursor->index()) {
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Insert;
+ }
+
+ if ( !undoRedoInfo.valid() ) {
+ undoRedoInfo.id = cursor->paragraph()->paragId();
+ undoRedoInfo.index = cursor->index();
+ undoRedoInfo.d->text = QString::null;
+ }
+ oldLen = undoRedoInfo.d->text.length();
+ }
+
+ lastFormatted = checkNewLine && cursor->paragraph()->prev() ?
+ cursor->paragraph()->prev() : cursor->paragraph();
+ QTextCursor oldCursor = *cursor;
+ cursor->insert( txt, checkNewLine );
+ if ( doc->useFormatCollection() && !doc->preProcessor() ) {
+ doc->setSelectionStart( QTextDocument::Temp, oldCursor );
+ doc->setSelectionEnd( QTextDocument::Temp, *cursor );
+ doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
+ doc->removeSelection( QTextDocument::Temp );
+ }
+
+ if ( indent && ( txt == "{" || txt == "}" || txt == ":" || txt == "#" ) )
+ cursor->indent();
+ formatMore();
+ repaintChanged();
+ ensureCursorVisible();
+ // Asian users regard selection text as cursor on candidate
+ // selection phase of input method, so ordinary cursor should be
+ // invisible if IM selection text exists.
+ drawCursor( !imSelection );
+
+ if ( undoEnabled && !isReadOnly() && undoRedoInfo.type != UndoRedoInfo::IME ) {
+ undoRedoInfo.d->text += txt;
+ if ( !doc->preProcessor() ) {
+ for ( int i = 0; i < (int)txt.length(); ++i ) {
+ if ( txt[ i ] != '\n' && c2.paragraph()->at( c2.index() )->format() ) {
+ c2.paragraph()->at( c2.index() )->format()->addRef();
+ undoRedoInfo.d->text.
+ setFormat( oldLen + i,
+ c2.paragraph()->at( c2.index() )->format(), TRUE );
+ }
+ c2.gotoNextLetter();
+ }
+ }
+ }
+
+ if ( !removeSelected ) {
+ doc->setSelectionStart( QTextDocument::Standard, oldCursor );
+ doc->setSelectionEnd( QTextDocument::Standard, *cursor );
+ repaintChanged();
+ }
+ // updateMicroFocusHint() should not be invoked here when this
+ // function is invoked from imComposeEvent() because cursor
+ // postion is incorrect yet. imComposeEvent() invokes
+ // updateMicroFocusHint() later.
+ if ( !imComposition ) {
+ updateMicroFocusHint();
+ }
+ setModified();
+ emit textChanged();
+}
+
+/*!
+ Inserts \a text in the paragraph \a para at position \a index.
+*/
+
+void QTextEdit::insertAt( const QString &text, int para, int index )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimInsert( text, para, index );
+ return;
+ }
+#endif
+ resetInputContext();
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return;
+ removeSelection( QTextDocument::Standard );
+ QTextCursor tmp = *cursor;
+ cursor->setParagraph( p );
+ cursor->setIndex( index );
+ insert( text, FALSE, TRUE, FALSE );
+ *cursor = tmp;
+ removeSelection( QTextDocument::Standard );
+}
+
+/*!
+ Inserts \a text as a new paragraph at position \a para. If \a para
+ is -1, the text is appended. Use append() if the append operation
+ is performance critical.
+*/
+
+void QTextEdit::insertParagraph( const QString &text, int para )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimInsert( text + "\n", para, 0 );
+ return;
+ }
+#endif
+ resetInputContext();
+ for ( int i = 0; i < (int)doc->numSelections(); ++i )
+ doc->removeSelection( i );
+
+ QTextParagraph *p = doc->paragAt( para );
+
+ bool append = !p;
+ if ( !p )
+ p = doc->lastParagraph();
+
+ QTextCursor old = *cursor;
+ drawCursor( FALSE );
+
+ cursor->setParagraph( p );
+ cursor->setIndex( 0 );
+ clearUndoRedo();
+ qtextedit_ignore_readonly = TRUE;
+ if ( append && cursor->paragraph()->length() > 1 ) {
+ cursor->setIndex( cursor->paragraph()->length() - 1 );
+ doKeyboardAction( ActionReturn );
+ }
+ insert( text, FALSE, TRUE, TRUE );
+ doKeyboardAction( ActionReturn );
+ qtextedit_ignore_readonly = FALSE;
+
+ drawCursor( FALSE );
+ *cursor = old;
+ drawCursor( TRUE );
+
+ repaintChanged();
+}
+
+/*!
+ Removes the paragraph \a para.
+*/
+
+void QTextEdit::removeParagraph( int para )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return;
+#endif
+ resetInputContext();
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return;
+
+ for ( int i = 0; i < doc->numSelections(); ++i )
+ doc->removeSelection( i );
+
+ QTextCursor start( doc );
+ QTextCursor end( doc );
+ start.setParagraph( p );
+ start.setIndex( 0 );
+ end.setParagraph( p );
+ end.setIndex( p->length() - 1 );
+
+ if ( !(p == doc->firstParagraph() && p == doc->lastParagraph()) ) {
+ if ( p->next() ) {
+ end.setParagraph( p->next() );
+ end.setIndex( 0 );
+ } else if ( p->prev() ) {
+ start.setParagraph( p->prev() );
+ start.setIndex( p->prev()->length() - 1 );
+ }
+ }
+
+ doc->setSelectionStart( QTextDocument::Temp, start );
+ doc->setSelectionEnd( QTextDocument::Temp, end );
+ removeSelectedText( QTextDocument::Temp );
+}
+
+/*!
+ 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 undoAvailable() redo() undoDepth()
+*/
+
+void QTextEdit::undo()
+{
+ clearUndoRedo();
+ if ( isReadOnly() || !doc->commands()->isUndoAvailable() || !undoEnabled )
+ return;
+
+ resetInputContext();
+ for ( int i = 0; i < (int)doc->numSelections(); ++i )
+ doc->removeSelection( i );
+
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+
+ clearUndoRedo();
+ drawCursor( FALSE );
+ QTextCursor *c = doc->undo( cursor );
+ if ( !c ) {
+ drawCursor( TRUE );
+ return;
+ }
+ lastFormatted = 0;
+ repaintChanged();
+ ensureCursorVisible();
+ drawCursor( TRUE );
+ updateMicroFocusHint();
+ setModified();
+ // ### If we get back to a completely blank textedit, it
+ // is possible that cursor is invalid and further actions
+ // might not fix the problem, so reset the cursor here.
+ // This is copied from removeSeletedText(), it might be
+ // okay to just call that.
+ if ( !cursor->isValid() ) {
+ delete cursor;
+ cursor = new QTextCursor( doc );
+ drawCursor( TRUE );
+ repaintContents( TRUE );
+ }
+ emit undoAvailable( isUndoAvailable() );
+ emit redoAvailable( isRedoAvailable() );
+ emit textChanged();
+}
+
+/*!
+ 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 redoAvailable() undo() undoDepth()
+*/
+
+void QTextEdit::redo()
+{
+ if ( isReadOnly() || !doc->commands()->isRedoAvailable() || !undoEnabled )
+ return;
+
+ resetInputContext();
+ for ( int i = 0; i < (int)doc->numSelections(); ++i )
+ doc->removeSelection( i );
+
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+
+ clearUndoRedo();
+ drawCursor( FALSE );
+ QTextCursor *c = doc->redo( cursor );
+ if ( !c ) {
+ drawCursor( TRUE );
+ return;
+ }
+ lastFormatted = 0;
+ ensureCursorVisible();
+ repaintChanged();
+ ensureCursorVisible();
+ drawCursor( TRUE );
+ updateMicroFocusHint();
+ setModified();
+ emit undoAvailable( isUndoAvailable() );
+ emit redoAvailable( isRedoAvailable() );
+ emit textChanged();
+}
+
+/*!
+ Pastes the text from the clipboard into the text edit at the
+ current cursor position. Only plain text is pasted.
+
+ If there is no text in the clipboard nothing happens.
+
+ \sa pasteSubType() cut() QTextEdit::copy()
+*/
+
+void QTextEdit::paste()
+{
+#ifndef QT_NO_MIMECLIPBOARD
+ if ( isReadOnly() )
+ return;
+ QString subType = "plain";
+ if ( textFormat() != PlainText ) {
+ QMimeSource *m = QApplication::clipboard()->data( d->clipboard_mode );
+ if ( !m )
+ return;
+ if ( m->provides( "application/x-qrichtext" ) )
+ subType = "x-qrichtext";
+ }
+
+ pasteSubType( subType.latin1() );
+ updateMicroFocusHint();
+#endif
+}
+
+void QTextEdit::checkUndoRedoInfo( UndoRedoInfo::Type t )
+{
+ if ( undoRedoInfo.valid() && t != undoRedoInfo.type ) {
+ clearUndoRedo();
+ }
+ undoRedoInfo.type = t;
+}
+
+/*!
+ Repaints any paragraphs that have changed.
+
+ Although used extensively internally you shouldn't need to call
+ this yourself.
+*/
+
+void QTextEdit::repaintChanged()
+{
+ if ( !isUpdatesEnabled() || !viewport()->isUpdatesEnabled() )
+ return;
+
+ QPainter p( viewport() );
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimDrawContents( &p, contentsX(), contentsY(), visibleWidth(), visibleHeight() );
+ return;
+ }
+#endif
+ p.translate( -contentsX(), -contentsY() );
+ paintDocument( FALSE, &p, contentsX(), contentsY(), visibleWidth(), visibleHeight() );
+}
+
+#ifndef QT_NO_MIME
+QTextDrag *QTextEdit::dragObject( QWidget *parent ) const
+{
+ if ( !doc->hasSelection( QTextDocument::Standard ) ||
+ doc->selectedText( QTextDocument::Standard ).isEmpty() )
+ return 0;
+ if ( textFormat() != RichText )
+ return new QTextDrag( doc->selectedText( QTextDocument::Standard ), parent );
+ QRichTextDrag *drag = new QRichTextDrag( parent );
+ drag->setPlainText( doc->selectedText( QTextDocument::Standard ) );
+ drag->setRichText( doc->selectedText( QTextDocument::Standard, TRUE ) );
+ return drag;
+}
+#endif
+
+/*!
+ Copies the selected text (from selection 0) to the clipboard and
+ deletes it from the text edit.
+
+ If there is no selected text (in selection 0) nothing happens.
+
+ \sa QTextEdit::copy() paste() pasteSubType()
+*/
+
+void QTextEdit::cut()
+{
+ if ( isReadOnly() )
+ return;
+ resetInputContext();
+ normalCopy();
+ removeSelectedText();
+ updateMicroFocusHint();
+}
+
+void QTextEdit::normalCopy()
+{
+#ifndef QT_NO_MIME
+ QTextDrag *drag = dragObject();
+ if ( !drag )
+ return;
+#ifndef QT_NO_MIMECLIPBOARD
+ QApplication::clipboard()->setData( drag, d->clipboard_mode );
+#endif // QT_NO_MIMECLIPBOARD
+#endif // QT_NO_MIME
+}
+
+/*!
+ Copies any selected text (from selection 0) to the clipboard.
+
+ \sa hasSelectedText() copyAvailable()
+*/
+
+void QTextEdit::copy()
+{
+#ifndef QT_NO_CLIPBOARD
+# ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode && optimHasSelection() )
+ QApplication::clipboard()->setText( optimSelectedText(), d->clipboard_mode );
+ else
+ normalCopy();
+# else
+ normalCopy();
+# endif
+#endif
+}
+
+/*!
+ \internal
+
+ Re-indents the current paragraph.
+*/
+
+void QTextEdit::indent()
+{
+ if ( isReadOnly() )
+ return;
+
+ drawCursor( FALSE );
+ if ( !doc->hasSelection( QTextDocument::Standard ) )
+ cursor->indent();
+ else
+ doc->indentSelection( QTextDocument::Standard );
+ repaintChanged();
+ drawCursor( TRUE );
+ setModified();
+ emit textChanged();
+}
+
+/*!
+ Reimplemented to allow tabbing through links. If \a n is TRUE the
+ tab moves the focus to the next child; if \a n is FALSE the tab
+ moves the focus to the previous child. Returns TRUE if the focus
+ was moved; otherwise returns FALSE.
+ */
+
+bool QTextEdit::focusNextPrevChild( bool n )
+{
+ if ( !isReadOnly() || !linksEnabled() )
+ return FALSE;
+ bool b = doc->focusNextPrevChild( n );
+ repaintChanged();
+ if ( b ) {
+ QTextParagraph *p = doc->focusIndicator.parag;
+ int start = doc->focusIndicator.start;
+ int len = doc->focusIndicator.len;
+
+ int y = p->rect().y();
+ while ( p
+ && len == 0
+ && p->at( start )->isCustom()
+ && p->at( start )->customItem()->isNested() ) {
+
+ QTextTable *t = (QTextTable*)p->at( start )->customItem();
+ QPtrList<QTextTableCell> cells = t->tableCells();
+ QTextTableCell *c;
+ for ( c = cells.first(); c; c = cells.next() ) {
+ QTextDocument *cellDoc = c->richText();
+ if ( cellDoc->hasFocusParagraph() ) {
+ y += c->geometry().y() + c->verticalAlignmentOffset();
+
+ p = cellDoc->focusIndicator.parag;
+ start = cellDoc->focusIndicator.start;
+ len = cellDoc->focusIndicator.len;
+ if ( p )
+ y += p->rect().y();
+
+ break;
+ }
+ }
+ }
+ setContentsPos( contentsX(), QMIN( y, contentsHeight() - visibleHeight() ) );
+ }
+ return b;
+}
+
+/*!
+ \internal
+
+ This functions sets the current format to \a f. Only the fields of \a
+ f which are specified by the \a flags are used.
+*/
+
+void QTextEdit::setFormat( QTextFormat *f, int flags )
+{
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ drawCursor( FALSE );
+ QTextCursor c1 = doc->selectionStartCursor( QTextDocument::Standard );
+ c1.restoreState();
+ QTextCursor c2 = doc->selectionEndCursor( QTextDocument::Standard );
+ c2.restoreState();
+ if ( undoEnabled ) {
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Format;
+ undoRedoInfo.id = c1.paragraph()->paragId();
+ undoRedoInfo.index = c1.index();
+ undoRedoInfo.eid = c2.paragraph()->paragId();
+ undoRedoInfo.eindex = c2.index();
+ readFormats( c1, c2, undoRedoInfo.d->text );
+ undoRedoInfo.format = f;
+ undoRedoInfo.flags = flags;
+ clearUndoRedo();
+ }
+ doc->setFormat( QTextDocument::Standard, f, flags );
+ repaintChanged();
+ formatMore();
+ drawCursor( TRUE );
+ setModified();
+ emit textChanged();
+ }
+ if ( currentFormat && currentFormat->key() != f->key() ) {
+ currentFormat->removeRef();
+ currentFormat = doc->formatCollection()->format( f );
+ if ( currentFormat->isMisspelled() ) {
+ currentFormat->removeRef();
+ currentFormat = doc->formatCollection()->format( currentFormat->font(),
+ currentFormat->color() );
+ }
+ emit currentFontChanged( currentFormat->font() );
+ emit currentColorChanged( currentFormat->color() );
+ emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
+ if ( cursor->index() == cursor->paragraph()->length() - 1 ) {
+ currentFormat->addRef();
+ cursor->paragraph()->string()->setFormat( cursor->index(), currentFormat, TRUE );
+ if ( cursor->paragraph()->length() == 1 ) {
+ cursor->paragraph()->invalidate( 0 );
+ cursor->paragraph()->format();
+ repaintChanged();
+ }
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::setPalette( const QPalette &p )
+{
+ QScrollView::setPalette( p );
+ if ( textFormat() == PlainText ) {
+ QTextFormat *f = doc->formatCollection()->defaultFormat();
+ f->setColor( colorGroup().text() );
+ updateContents();
+ }
+}
+
+/*! \internal
+ \warning In Qt 3.1 we will provide a cleaer API for the
+ functionality which is provided by this function and in Qt 4.0 this
+ function will go away.
+
+ Sets the paragraph style of the current paragraph
+ to \a dm. If \a dm is QStyleSheetItem::DisplayListItem, the
+ type of the list item is set to \a listStyle.
+
+ \sa setAlignment()
+*/
+
+void QTextEdit::setParagType( QStyleSheetItem::DisplayMode dm,
+ QStyleSheetItem::ListStyle listStyle )
+{
+ if ( isReadOnly() )
+ return;
+
+ drawCursor( FALSE );
+ QTextParagraph *start = cursor->paragraph();
+ QTextParagraph *end = start;
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ start = doc->selectionStartCursor( QTextDocument::Standard ).topParagraph();
+ end = doc->selectionEndCursor( QTextDocument::Standard ).topParagraph();
+ if ( end->paragId() < start->paragId() )
+ return; // do not trust our selections
+ }
+
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Style;
+ undoRedoInfo.id = start->paragId();
+ undoRedoInfo.eid = end->paragId();
+ undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
+
+ while ( start != end->next() ) {
+ start->setListStyle( listStyle );
+ if ( dm == QStyleSheetItem::DisplayListItem ) {
+ start->setListItem( TRUE );
+ if( start->listDepth() == 0 )
+ start->setListDepth( 1 );
+ } else if ( start->isListItem() ) {
+ start->setListItem( FALSE );
+ start->setListDepth( QMAX( start->listDepth()-1, 0 ) );
+ }
+ start = start->next();
+ }
+
+ clearUndoRedo();
+ repaintChanged();
+ formatMore();
+ drawCursor( TRUE );
+ setModified();
+ emit textChanged();
+}
+
+/*!
+ Sets the alignment of the current paragraph to \a a. Valid
+ alignments are \c Qt::AlignLeft, \c Qt::AlignRight,
+ \c Qt::AlignJustify and \c Qt::AlignCenter (which centers
+ horizontally).
+*/
+
+void QTextEdit::setAlignment( int a )
+{
+ if ( isReadOnly() || block_set_alignment )
+ return;
+
+ drawCursor( FALSE );
+ QTextParagraph *start = cursor->paragraph();
+ QTextParagraph *end = start;
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ start = doc->selectionStartCursor( QTextDocument::Standard ).topParagraph();
+ end = doc->selectionEndCursor( QTextDocument::Standard ).topParagraph();
+ if ( end->paragId() < start->paragId() )
+ return; // do not trust our selections
+ }
+
+ clearUndoRedo();
+ undoRedoInfo.type = UndoRedoInfo::Style;
+ undoRedoInfo.id = start->paragId();
+ undoRedoInfo.eid = end->paragId();
+ undoRedoInfo.styleInformation = QTextStyleCommand::readStyleInformation( doc, undoRedoInfo.id, undoRedoInfo.eid );
+
+ while ( start != end->next() ) {
+ start->setAlignment( a );
+ start = start->next();
+ }
+
+ clearUndoRedo();
+ repaintChanged();
+ formatMore();
+ drawCursor( TRUE );
+ if ( currentAlignment != a ) {
+ currentAlignment = a;
+ emit currentAlignmentChanged( currentAlignment );
+ }
+ setModified();
+ emit textChanged();
+}
+
+void QTextEdit::updateCurrentFormat()
+{
+ int i = cursor->index();
+ if ( i > 0 )
+ --i;
+ if ( doc->useFormatCollection() &&
+ ( !currentFormat || currentFormat->key() != cursor->paragraph()->at( i )->format()->key() ) ) {
+ if ( currentFormat )
+ currentFormat->removeRef();
+ currentFormat = doc->formatCollection()->format( cursor->paragraph()->at( i )->format() );
+ if ( currentFormat->isMisspelled() ) {
+ currentFormat->removeRef();
+ currentFormat = doc->formatCollection()->format( currentFormat->font(), currentFormat->color() );
+ }
+ emit currentFontChanged( currentFormat->font() );
+ emit currentColorChanged( currentFormat->color() );
+ emit currentVerticalAlignmentChanged( (VerticalAlignment)currentFormat->vAlign() );
+ }
+
+ if ( currentAlignment != cursor->paragraph()->alignment() ) {
+ currentAlignment = cursor->paragraph()->alignment();
+ block_set_alignment = TRUE;
+ emit currentAlignmentChanged( currentAlignment );
+ block_set_alignment = FALSE;
+ }
+}
+
+/*!
+ If \a b is TRUE sets the current format to italic; otherwise sets
+ the current format to non-italic.
+
+ \sa italic()
+*/
+
+void QTextEdit::setItalic( bool b )
+{
+ QTextFormat f( *currentFormat );
+ f.setItalic( b );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat(f2, QTextFormat::Italic );
+}
+
+/*!
+ If \a b is TRUE sets the current format to bold; otherwise sets
+ the current format to non-bold.
+
+ \sa bold()
+*/
+
+void QTextEdit::setBold( bool b )
+{
+ QTextFormat f( *currentFormat );
+ f.setBold( b );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::Bold );
+}
+
+/*!
+ If \a b is TRUE sets the current format to underline; otherwise
+ sets the current format to non-underline.
+
+ \sa underline()
+*/
+
+void QTextEdit::setUnderline( bool b )
+{
+ QTextFormat f( *currentFormat );
+ f.setUnderline( b );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::Underline );
+}
+
+/*!
+ Sets the font family of the current format to \a fontFamily.
+
+ \sa family() setCurrentFont()
+*/
+
+void QTextEdit::setFamily( const QString &fontFamily )
+{
+ QTextFormat f( *currentFormat );
+ f.setFamily( fontFamily );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::Family );
+}
+
+/*!
+ Sets the point size of the current format to \a s.
+
+ Note that if \a s is zero or negative, the behaviour of this
+ function is not defined.
+
+ \sa pointSize() setCurrentFont() setFamily()
+*/
+
+void QTextEdit::setPointSize( int s )
+{
+ QTextFormat f( *currentFormat );
+ f.setPointSize( s );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::Size );
+}
+
+/*!
+ Sets the color of the current format, i.e. of the text, to \a c.
+
+ \sa color() setPaper()
+*/
+
+void QTextEdit::setColor( const QColor &c )
+{
+ QTextFormat f( *currentFormat );
+ f.setColor( c );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::Color );
+}
+
+/*!
+ Sets the vertical alignment of the current format, i.e. of the
+ text, to \a a.
+
+ \sa color() setPaper()
+*/
+
+void QTextEdit::setVerticalAlignment( VerticalAlignment a )
+{
+ QTextFormat f( *currentFormat );
+ f.setVAlign( (QTextFormat::VerticalAlignment)a );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::VAlign );
+}
+
+void QTextEdit::setFontInternal( const QFont &f_ )
+{
+ QTextFormat f( *currentFormat );
+ f.setFont( f_ );
+ QTextFormat *f2 = doc->formatCollection()->format( &f );
+ setFormat( f2, QTextFormat::Font );
+}
+
+
+QString QTextEdit::text() const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return optimText();
+#endif
+
+ QTextParagraph *p = doc->firstParagraph();
+ if ( !p || (!p->next() && p->length() <= 1) )
+ return QString::fromLatin1("");
+
+ if ( isReadOnly() )
+ return doc->originalText();
+ return doc->text();
+}
+
+/*!
+ \overload
+
+ Returns the text of paragraph \a para.
+
+ If textFormat() is \c RichText the text will contain HTML
+ formatting tags.
+*/
+
+QString QTextEdit::text( int para ) const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode && (d->od->numLines >= para) ) {
+ QString paraStr = d->od->lines[ LOGOFFSET(para) ];
+ if ( paraStr.isEmpty() )
+ paraStr = "\n";
+ return paraStr;
+ } else
+#endif
+ return doc->text( para );
+}
+
+/*!
+ \overload
+
+ Changes the text of the text edit to the string \a text and the
+ context to \a context. Any previous text is removed.
+
+ \a text may be interpreted either as plain text or as rich text,
+ depending on the textFormat(). The default setting is \c AutoText,
+ i.e. the text edit auto-detects the format from \a text.
+
+ For rich text the rendering style and available tags are defined
+ by a styleSheet(); see QStyleSheet for details.
+
+ The optional \a context is a path which the text edit's
+ QMimeSourceFactory uses to resolve the locations of files and
+ images. (See \l{QTextEdit::QTextEdit()}.) It is passed to the text
+ edit's QMimeSourceFactory when quering data.
+
+ Note that the undo/redo history is cleared by this function.
+
+ \sa text(), setTextFormat()
+*/
+
+void QTextEdit::setText( const QString &text, const QString &context )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimSetText( text );
+ return;
+ }
+#endif
+ resetInputContext();
+ if ( !isModified() && isReadOnly() &&
+ this->context() == context && this->text() == text )
+ return;
+
+ emit undoAvailable( FALSE );
+ emit redoAvailable( FALSE );
+ undoRedoInfo.clear();
+ doc->commands()->clear();
+
+ lastFormatted = 0;
+ int oldCursorPos = cursor->index();
+ int oldCursorPar = cursor->paragraph()->paragId();
+ cursor->restoreState();
+ delete cursor;
+ doc->setText( text, context );
+
+ if ( wrapMode == FixedPixelWidth ) {
+ resizeContents( wrapWidth, 0 );
+ doc->setWidth( wrapWidth );
+ doc->setMinimumWidth( wrapWidth );
+ } else {
+ doc->setMinimumWidth( -1 );
+ resizeContents( 0, 0 );
+ }
+
+ lastFormatted = doc->firstParagraph();
+ cursor = new QTextCursor( doc );
+ updateContents();
+
+ if ( isModified() )
+ setModified( FALSE );
+ emit textChanged();
+ if ( cursor->index() != oldCursorPos || cursor->paragraph()->paragId() != oldCursorPar ) {
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+ }
+ formatMore();
+ updateCurrentFormat();
+ d->scrollToAnchor = QString::null;
+}
+
+/*!
+ \property QTextEdit::text
+ \brief the text edit's text
+
+ There is no default text.
+
+ On setting, any previous text is deleted.
+
+ The text may be interpreted either as plain text or as rich text,
+ depending on the textFormat(). The default setting is \c AutoText,
+ i.e. the text edit auto-detects the format of the text.
+
+ For richtext, calling text() on an editable QTextEdit will cause
+ the text to be regenerated from the textedit. This may mean that
+ the QString returned may not be exactly the same as the one that
+ was set.
+
+ \sa textFormat
+*/
+
+
+/*!
+ \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.
+*/
+
+/*!
+ Finds the next occurrence of the string, \a expr. Returns TRUE if
+ \a expr was found; otherwise returns FALSE.
+
+ If \a para and \a index are both 0 the search begins from the
+ current cursor position. If \a para and \a index are both not 0,
+ the search begins from the \a *index character position in the
+ \a *para paragraph.
+
+ If \a cs is TRUE the search is case sensitive, otherwise it is
+ case insensitive. If \a wo is TRUE the search looks for whole word
+ matches only; otherwise it searches for any matching text. If \a
+ forward is TRUE (the default) the search works forward from the
+ starting position to the end of the text, otherwise it works
+ backwards to the beginning of the text.
+
+ If \a expr is found the function returns TRUE. If \a index and \a
+ para are not 0, the number of the paragraph in which the first
+ character of the match was found is put into \a *para, and the
+ index position of that character within the paragraph is put into
+ \a *index.
+
+ If \a expr is not found the function returns FALSE. If \a index
+ and \a para are not 0 and \a expr is not found, \a *index
+ and \a *para are undefined.
+
+ Please note that this function will make the next occurrence of
+ the string (if found) the current selection, and will thus
+ modify the cursor position.
+
+ Using the \a para and \a index parameters will not work correctly
+ in case the document contains tables.
+*/
+
+bool QTextEdit::find( const QString &expr, bool cs, bool wo, bool forward,
+ int *para, int *index )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return optimFind( expr, cs, wo, forward, para, index );
+#endif
+ drawCursor( FALSE );
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ QTextCursor findcur = *cursor;
+ if ( para && index ) {
+ if ( doc->paragAt( *para ) )
+ findcur.gotoPosition( doc->paragAt(*para), *index );
+ else
+ findcur.gotoEnd();
+ } else if ( doc->hasSelection( QTextDocument::Standard ) ){
+ // maks sure we do not find the same selection again
+ if ( forward )
+ findcur.gotoNextLetter();
+ else
+ findcur.gotoPreviousLetter();
+ } else if (!forward && findcur.index() == 0 && findcur.paragraph() == findcur.topParagraph()) {
+ findcur.gotoEnd();
+ }
+ removeSelection( QTextDocument::Standard );
+ bool found = doc->find( findcur, expr, cs, wo, forward );
+ if ( found ) {
+ if ( para )
+ *para = findcur.paragraph()->paragId();
+ if ( index )
+ *index = findcur.index();
+ *cursor = findcur;
+ repaintChanged();
+ ensureCursorVisible();
+ }
+ drawCursor( TRUE );
+ if (found) {
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+ }
+ return found;
+}
+
+void QTextEdit::blinkCursor()
+{
+ if ( !cursorVisible )
+ return;
+ bool cv = cursorVisible;
+ blinkCursorVisible = !blinkCursorVisible;
+ drawCursor( blinkCursorVisible );
+ cursorVisible = cv;
+}
+
+/*!
+ Sets the cursor to position \a index in paragraph \a para.
+
+ \sa getCursorPosition()
+*/
+
+void QTextEdit::setCursorPosition( int para, int index )
+{
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return;
+
+ resetInputContext();
+ if ( index > p->length() - 1 )
+ index = p->length() - 1;
+
+ drawCursor( FALSE );
+ cursor->setParagraph( p );
+ cursor->setIndex( index );
+ ensureCursorVisible();
+ drawCursor( TRUE );
+ updateCurrentFormat();
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+}
+
+/*!
+ This function sets the \a *para and \a *index parameters to the
+ current cursor position. \a para and \a index must not be 0.
+
+ \sa setCursorPosition()
+*/
+
+void QTextEdit::getCursorPosition( int *para, int *index ) const
+{
+ if ( !para || !index )
+ return;
+ *para = cursor->paragraph()->paragId();
+ *index = cursor->index();
+}
+
+/*!
+ Sets a selection which starts at position \a indexFrom in
+ paragraph \a paraFrom and ends at position \a indexTo in paragraph
+ \a paraTo.
+
+ Any existing selections which have a different id (\a selNum) are
+ left alone, but if an existing selection has the same id as \a
+ selNum it is removed and replaced by this selection.
+
+ Uses the selection settings of selection \a selNum. If \a selNum
+ is 0, this is the default selection.
+
+ The cursor is moved to the end of the selection if \a selNum is 0,
+ otherwise the cursor position remains unchanged.
+
+ \sa getSelection() selectedText
+*/
+
+void QTextEdit::setSelection( int paraFrom, int indexFrom,
+ int paraTo, int indexTo, int selNum )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if (d->optimMode) {
+ optimSetSelection(paraFrom, indexFrom, paraTo, indexTo);
+ repaintContents(FALSE);
+ return;
+ }
+#endif
+ resetInputContext();
+ if ( doc->hasSelection( selNum ) ) {
+ doc->removeSelection( selNum );
+ repaintChanged();
+ }
+ if ( selNum > doc->numSelections() - 1 )
+ doc->addSelection( selNum );
+ QTextParagraph *p1 = doc->paragAt( paraFrom );
+ if ( !p1 )
+ return;
+ QTextParagraph *p2 = doc->paragAt( paraTo );
+ if ( !p2 )
+ return;
+
+ if ( indexFrom > p1->length() - 1 )
+ indexFrom = p1->length() - 1;
+ if ( indexTo > p2->length() - 1 )
+ indexTo = p2->length() - 1;
+
+ drawCursor( FALSE );
+ QTextCursor c = *cursor;
+ QTextCursor oldCursor = *cursor;
+ c.setParagraph( p1 );
+ c.setIndex( indexFrom );
+ cursor->setParagraph( p2 );
+ cursor->setIndex( indexTo );
+ doc->setSelectionStart( selNum, c );
+ doc->setSelectionEnd( selNum, *cursor );
+ repaintChanged();
+ ensureCursorVisible();
+ if ( selNum != QTextDocument::Standard )
+ *cursor = oldCursor;
+ drawCursor( TRUE );
+}
+
+/*!
+ If there is a selection, \a *paraFrom is set to the number of the
+ paragraph in which the selection begins and \a *paraTo is set to
+ the number of the paragraph in which the selection ends. (They
+ could be the same.) \a *indexFrom is set to the index at which the
+ selection begins within \a *paraFrom, and \a *indexTo is set to
+ the index at which the selection ends within \a *paraTo.
+
+ If there is no selection, \a *paraFrom, \a *indexFrom, \a *paraTo
+ and \a *indexTo are all set to -1.
+
+ If \a paraFrom, \a indexFrom, \a paraTo or \a indexTo is 0 this
+ function does nothing.
+
+ The \a selNum is the number of the selection (multiple selections
+ are supported). It defaults to 0 (the default selection).
+
+ \sa setSelection() selectedText
+*/
+
+void QTextEdit::getSelection( int *paraFrom, int *indexFrom,
+ int *paraTo, int *indexTo, int selNum ) const
+{
+ if ( !paraFrom || !paraTo || !indexFrom || !indexTo )
+ return;
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if (d->optimMode) {
+ *paraFrom = d->od->selStart.line;
+ *paraTo = d->od->selEnd.line;
+ *indexFrom = d->od->selStart.index;
+ *indexTo = d->od->selEnd.index;
+ return;
+ }
+#endif
+ if ( !doc->hasSelection( selNum ) ) {
+ *paraFrom = -1;
+ *indexFrom = -1;
+ *paraTo = -1;
+ *indexTo = -1;
+ return;
+ }
+
+ doc->selectionStart( selNum, *paraFrom, *indexFrom );
+ doc->selectionEnd( selNum, *paraTo, *indexTo );
+}
+
+/*!
+ \property QTextEdit::textFormat
+ \brief the text format: rich text, plain text, log text or auto text.
+
+ The text format is one of the following:
+ \list
+ \i PlainText - all characters, except newlines, are displayed
+ verbatim, including spaces. Whenever a newline appears in the text
+ the text edit inserts a hard line break and begins a new
+ paragraph.
+ \i RichText - rich text rendering. The available styles are
+ defined in the default stylesheet QStyleSheet::defaultSheet().
+ \i LogText - optimized mode for very large texts. Supports a very
+ limited set of formatting tags (color, bold, underline and italic
+ settings).
+ \i AutoText - this is the default. The text edit autodetects which
+ rendering style is best, \c PlainText or \c RichText. This is done
+ by using the QStyleSheet::mightBeRichText() function.
+ \endlist
+*/
+
+void QTextEdit::setTextFormat( TextFormat format )
+{
+ doc->setTextFormat( format );
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ checkOptimMode();
+#endif
+}
+
+Qt::TextFormat QTextEdit::textFormat() const
+{
+ return doc->textFormat();
+}
+
+/*!
+ Returns the number of paragraphs in the text; an empty textedit is always
+ considered to have one paragraph, so 1 is returned in this case.
+*/
+
+int QTextEdit::paragraphs() const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ return d->od->numLines;
+ }
+#endif
+ return doc->lastParagraph()->paragId() + 1;
+}
+
+/*!
+ Returns the number of lines in paragraph \a para, or -1 if there
+ is no paragraph with index \a para.
+*/
+
+int QTextEdit::linesOfParagraph( int para ) const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ if ( d->od->numLines >= para )
+ return 1;
+ else
+ return -1;
+ }
+#endif
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return -1;
+ return p->lines();
+}
+
+/*!
+ Returns the length of the paragraph \a para (i.e. the number of
+ characters), or -1 if there is no paragraph with index \a para.
+
+ This function ignores newlines.
+*/
+
+int QTextEdit::paragraphLength( int para ) const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ if ( d->od->numLines >= para ) {
+ if ( d->od->lines[ LOGOFFSET(para) ].isEmpty() ) // CR
+ return 1;
+ else
+ return d->od->lines[ LOGOFFSET(para) ].length();
+ }
+ return -1;
+ }
+#endif
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return -1;
+ return p->length() - 1;
+}
+
+/*!
+ Returns the number of lines in the text edit; this could be 0.
+
+ \warning This function may be slow. Lines change all the time
+ during word wrapping, so this function has to iterate over all the
+ paragraphs and get the number of lines from each one individually.
+*/
+
+int QTextEdit::lines() const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ return d->od->numLines;
+ }
+#endif
+ QTextParagraph *p = doc->firstParagraph();
+ int l = 0;
+ while ( p ) {
+ l += p->lines();
+ p = p->next();
+ }
+
+ return l;
+}
+
+/*!
+ Returns the line number of the line in paragraph \a para in which
+ the character at position \a index appears. The \a index position is
+ relative to the beginning of the paragraph. If there is no such
+ paragraph or no such character at the \a index position (e.g. the
+ index is out of range) -1 is returned.
+*/
+
+int QTextEdit::lineOfChar( int para, int index )
+{
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return -1;
+
+ int idx, line;
+ QTextStringChar *c = p->lineStartOfChar( index, &idx, &line );
+ if ( !c )
+ return -1;
+
+ return line;
+}
+
+void QTextEdit::setModified( bool m )
+{
+ bool oldModified = modified;
+ modified = m;
+ if ( modified && doc->oTextValid )
+ doc->invalidateOriginalText();
+ if ( oldModified != modified )
+ emit modificationChanged( modified );
+}
+
+/*!
+ \property QTextEdit::modified
+ \brief whether the document has been modified by the user
+*/
+
+bool QTextEdit::isModified() const
+{
+ return modified;
+}
+
+void QTextEdit::setModified()
+{
+ if ( !isModified() )
+ setModified( TRUE );
+}
+
+/*!
+ Returns TRUE if the current format is italic; otherwise returns FALSE.
+
+ \sa setItalic()
+*/
+
+bool QTextEdit::italic() const
+{
+ return currentFormat->font().italic();
+}
+
+/*!
+ Returns TRUE if the current format is bold; otherwise returns FALSE.
+
+ \sa setBold()
+*/
+
+bool QTextEdit::bold() const
+{
+ return currentFormat->font().bold();
+}
+
+/*!
+ Returns TRUE if the current format is underlined; otherwise returns
+ FALSE.
+
+ \sa setUnderline()
+*/
+
+bool QTextEdit::underline() const
+{
+ return currentFormat->font().underline();
+}
+
+/*!
+ Returns the font family of the current format.
+
+ \sa setFamily() setCurrentFont() setPointSize()
+*/
+
+QString QTextEdit::family() const
+{
+ return currentFormat->font().family();
+}
+
+/*!
+ Returns the point size of the font of the current format.
+
+ \sa setFamily() setCurrentFont() setPointSize()
+*/
+
+int QTextEdit::pointSize() const
+{
+ return currentFormat->font().pointSize();
+}
+
+/*!
+ Returns the color of the current format.
+
+ \sa setColor() setPaper()
+*/
+
+QColor QTextEdit::color() const
+{
+ return currentFormat->color();
+}
+
+/*!
+ \obsolete
+
+ Returns QScrollView::font()
+
+ \warning In previous versions this function returned the font of
+ the current format. This lead to confusion. Please use
+ currentFont() instead.
+*/
+
+QFont QTextEdit::font() const
+{
+ return QScrollView::font();
+}
+
+/*!
+ Returns the font of the current format.
+
+ \sa setCurrentFont() setFamily() setPointSize()
+*/
+
+QFont QTextEdit::currentFont() const
+{
+ return currentFormat->font();
+}
+
+
+/*!
+ Returns the alignment of the current paragraph.
+
+ \sa setAlignment()
+*/
+
+int QTextEdit::alignment() const
+{
+ return currentAlignment;
+}
+
+void QTextEdit::startDrag()
+{
+#ifndef QT_NO_DRAGANDDROP
+ mousePressed = FALSE;
+ inDoubleClick = FALSE;
+ QDragObject *drag = dragObject( viewport() );
+ if ( !drag )
+ return;
+ if ( isReadOnly() ) {
+ drag->dragCopy();
+ } else {
+ if ( drag->drag() && QDragObject::target() != this && QDragObject::target() != viewport() )
+ removeSelectedText();
+ }
+#endif
+}
+
+/*!
+ If \a select is TRUE (the default), all the text is selected as
+ selection 0. If \a select is FALSE any selected text is
+ unselected, i.e. the default selection (selection 0) is cleared.
+
+ \sa selectedText
+*/
+
+void QTextEdit::selectAll( bool select )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ if ( select )
+ optimSelectAll();
+ else
+ optimRemoveSelection();
+ return;
+ }
+#endif
+ if ( !select )
+ doc->removeSelection( QTextDocument::Standard );
+ else
+ doc->selectAll( QTextDocument::Standard );
+ repaintChanged();
+ emit copyAvailable( doc->hasSelection( QTextDocument::Standard ) );
+ emit selectionChanged();
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+}
+
+void QTextEdit::UndoRedoInfo::clear()
+{
+ if ( valid() ) {
+ if ( type == Insert || type == Return )
+ doc->addCommand( new QTextInsertCommand( doc, id, index, d->text.rawData(), styleInformation ) );
+ else if ( type == Format )
+ doc->addCommand( new QTextFormatCommand( doc, id, index, eid, eindex, d->text.rawData(), format, flags ) );
+ else if ( type == Style )
+ doc->addCommand( new QTextStyleCommand( doc, id, eid, styleInformation ) );
+ else if ( type != Invalid ) {
+ doc->addCommand( new QTextDeleteCommand( doc, id, index, d->text.rawData(), styleInformation ) );
+ }
+ }
+ type = Invalid;
+ d->text = QString::null;
+ id = -1;
+ index = -1;
+ styleInformation = QByteArray();
+}
+
+
+/*!
+ If there is some selected text (in selection 0) it is deleted. If
+ there is no selected text (in selection 0) the character to the
+ right of the text cursor is deleted.
+
+ \sa removeSelectedText() cut()
+*/
+
+void QTextEdit::del()
+{
+ if ( doc->hasSelection( QTextDocument::Standard ) ) {
+ removeSelectedText();
+ return;
+ }
+
+ doKeyboardAction( ActionDelete );
+}
+
+
+QTextEdit::UndoRedoInfo::UndoRedoInfo( QTextDocument *dc )
+ : type( Invalid ), doc( dc )
+{
+ d = new QUndoRedoInfoPrivate;
+ d->text = QString::null;
+ id = -1;
+ index = -1;
+}
+
+QTextEdit::UndoRedoInfo::~UndoRedoInfo()
+{
+ delete d;
+}
+
+bool QTextEdit::UndoRedoInfo::valid() const
+{
+ return id >= 0 && type != Invalid;
+}
+
+/*!
+ \internal
+
+ Resets the current format to the default format.
+*/
+
+void QTextEdit::resetFormat()
+{
+ setAlignment( Qt::AlignAuto );
+ setParagType( QStyleSheetItem::DisplayBlock, QStyleSheetItem::ListDisc );
+ setFormat( doc->formatCollection()->defaultFormat(), QTextFormat::Format );
+}
+
+/*!
+ Returns the QStyleSheet which is being used by this text edit.
+
+ \sa setStyleSheet()
+*/
+
+QStyleSheet* QTextEdit::styleSheet() const
+{
+ return doc->styleSheet();
+}
+
+/*!
+ Sets the stylesheet to use with this text edit to \a styleSheet.
+ Changes will only take effect for new text added with setText() or
+ append().
+
+ \sa styleSheet()
+*/
+
+void QTextEdit::setStyleSheet( QStyleSheet* styleSheet )
+{
+ doc->setStyleSheet( styleSheet );
+}
+
+/*!
+ \property QTextEdit::paper
+ \brief the background (paper) brush.
+
+ The brush that is currently used to draw the background of the
+ text edit. The initial setting is an empty brush.
+*/
+
+void QTextEdit::setPaper( const QBrush& pap )
+{
+ doc->setPaper( new QBrush( pap ) );
+
+ if ( pap.pixmap() ) {
+ viewport()->setBackgroundPixmap( *pap.pixmap() );
+ } else {
+ setPaletteBackgroundColor( pap.color() );
+ viewport()->setPaletteBackgroundColor( pap.color() );
+ }
+
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ // force a repaint of the entire viewport - using updateContents()
+ // would clip the coords to the content size
+ if (d->optimMode)
+ repaintContents(contentsX(), contentsY(), viewport()->width(), viewport()->height());
+ else
+#endif
+ updateContents();
+}
+
+QBrush QTextEdit::paper() const
+{
+ if ( doc->paper() )
+ return *doc->paper();
+ return QBrush( colorGroup().base() );
+}
+
+/*!
+ \property QTextEdit::linkUnderline
+ \brief whether hypertext links will be underlined
+
+ If TRUE (the default) hypertext links will be displayed
+ underlined. If FALSE links will not be displayed underlined.
+*/
+
+void QTextEdit::setLinkUnderline( bool b )
+{
+ if ( doc->underlineLinks() == b )
+ return;
+ doc->setUnderlineLinks( b );
+ repaintChanged();
+}
+
+bool QTextEdit::linkUnderline() const
+{
+ return doc->underlineLinks();
+}
+
+/*!
+ Sets the text edit's mimesource factory to \a factory. See
+ QMimeSourceFactory for further details.
+
+ \sa mimeSourceFactory()
+ */
+
+#ifndef QT_NO_MIME
+void QTextEdit::setMimeSourceFactory( QMimeSourceFactory* factory )
+{
+ doc->setMimeSourceFactory( factory );
+}
+
+/*!
+ Returns the QMimeSourceFactory which is being used by this text
+ edit.
+
+ \sa setMimeSourceFactory()
+*/
+
+QMimeSourceFactory* QTextEdit::mimeSourceFactory() const
+{
+ return doc->mimeSourceFactory();
+}
+#endif
+
+/*!
+ Returns how many pixels high the text edit needs to be to display
+ all the text if the text edit is \a w pixels wide.
+*/
+
+int QTextEdit::heightForWidth( int w ) const
+{
+ int oldw = doc->width();
+ doc->doLayout( 0, w );
+ int h = doc->height();
+ doc->setWidth( oldw );
+ doc->invalidate();
+ ( (QTextEdit*)this )->formatMore();
+ return h;
+}
+
+/*!
+ Appends a new paragraph with \a text to the end of the text edit. Note that
+ the undo/redo history is cleared by this function, and no undo
+ history is kept for appends which makes them faster than
+ insert()s. If you want to append text which is added to the
+ undo/redo history as well, use insertParagraph().
+*/
+
+void QTextEdit::append( const QString &text )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimAppend( text );
+ return;
+ }
+#endif
+ // flush and clear the undo/redo stack if necessary
+ undoRedoInfo.clear();
+ doc->commands()->clear();
+
+ doc->removeSelection( QTextDocument::Standard );
+ TextFormat f = doc->textFormat();
+ if ( f == AutoText ) {
+ if ( QStyleSheet::mightBeRichText( text ) )
+ f = RichText;
+ else
+ f = PlainText;
+ }
+
+ drawCursor( FALSE );
+ QTextCursor oldc( *cursor );
+ ensureFormatted( doc->lastParagraph() );
+ bool atBottom = contentsY() >= contentsHeight() - visibleHeight();
+ cursor->gotoEnd();
+ if ( cursor->index() > 0 )
+ cursor->splitAndInsertEmptyParagraph();
+ QTextCursor oldCursor2 = *cursor;
+
+ if ( f == Qt::PlainText ) {
+ cursor->insert( text, TRUE );
+ if ( doc->useFormatCollection() && !doc->preProcessor() &&
+ currentFormat != cursor->paragraph()->at( cursor->index() )->format() ) {
+ doc->setSelectionStart( QTextDocument::Temp, oldCursor2 );
+ doc->setSelectionEnd( QTextDocument::Temp, *cursor );
+ doc->setFormat( QTextDocument::Temp, currentFormat, QTextFormat::Format );
+ doc->removeSelection( QTextDocument::Temp );
+ }
+ } else {
+ cursor->paragraph()->setListItem( FALSE );
+ cursor->paragraph()->setListDepth( 0 );
+ if ( cursor->paragraph()->prev() )
+ cursor->paragraph()->prev()->invalidate(0); // vertical margins might have to change
+ doc->setRichTextInternal( text );
+ }
+ formatMore();
+ repaintChanged();
+ if ( atBottom )
+ scrollToBottom();
+ *cursor = oldc;
+ if ( !isReadOnly() )
+ cursorVisible = TRUE;
+ setModified();
+ emit textChanged();
+}
+
+/*!
+ \property QTextEdit::hasSelectedText
+ \brief whether some text is selected in selection 0
+*/
+
+bool QTextEdit::hasSelectedText() const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return optimHasSelection();
+ else
+#endif
+ return doc->hasSelection( QTextDocument::Standard );
+}
+
+/*!
+ \property QTextEdit::selectedText
+ \brief The selected text (from selection 0) or an empty string if
+ there is no currently selected text (in selection 0).
+
+ The text is always returned as \c PlainText if the textFormat() is
+ \c PlainText or \c AutoText, otherwise it is returned as HTML.
+
+ \sa hasSelectedText
+*/
+
+QString QTextEdit::selectedText() const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return optimSelectedText();
+ else
+#endif
+ return doc->selectedText( QTextDocument::Standard, textFormat() == RichText );
+}
+
+bool QTextEdit::handleReadOnlyKeyEvent( QKeyEvent *e )
+{
+ switch( e->key() ) {
+ case Key_Down:
+ setContentsPos( contentsX(), contentsY() + 10 );
+ break;
+ case Key_Up:
+ setContentsPos( contentsX(), contentsY() - 10 );
+ break;
+ case Key_Left:
+ setContentsPos( contentsX() - 10, contentsY() );
+ break;
+ case Key_Right:
+ setContentsPos( contentsX() + 10, contentsY() );
+ break;
+ case Key_PageUp:
+ setContentsPos( contentsX(), contentsY() - visibleHeight() );
+ break;
+ case Key_PageDown:
+ setContentsPos( contentsX(), contentsY() + visibleHeight() );
+ break;
+ case Key_Home:
+ setContentsPos( contentsX(), 0 );
+ break;
+ case Key_End:
+ setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
+ break;
+ case Key_F16: // Copy key on Sun keyboards
+ copy();
+ break;
+#ifndef QT_NO_NETWORKPROTOCOL
+ case Key_Return:
+ case Key_Enter:
+ case Key_Space: {
+ if (!doc->focusIndicator.href.isEmpty()
+ || !doc->focusIndicator.name.isEmpty()) {
+ if (!doc->focusIndicator.href.isEmpty()) {
+ QUrl u( doc->context(), doc->focusIndicator.href, TRUE );
+ emitLinkClicked( u.toString( FALSE, FALSE ) );
+ }
+ if (!doc->focusIndicator.name.isEmpty()) {
+ if (::qt_cast<QTextBrowser*>(this)) { // change for 4.0
+ QConnectionList *clist = receivers(
+ "anchorClicked(const QString&,const QString&)");
+ if (!signalsBlocked() && clist) {
+ QUObject o[3];
+ static_QUType_QString.set(o+1,
+ doc->focusIndicator.name);
+ static_QUType_QString.set(o+2,
+ doc->focusIndicator.href);
+ activate_signal( clist, o);
+ }
+ }
+ }
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ }
+ } break;
+#endif
+ default:
+ if ( e->state() & ControlButton ) {
+ switch ( e->key() ) {
+ case Key_C: case Key_F16: // Copy key on Sun keyboards
+ copy();
+ break;
+#ifdef Q_WS_WIN
+ case Key_Insert:
+ copy();
+ break;
+ case Key_A:
+ selectAll();
+ break;
+#endif
+ }
+
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*!
+ Returns the context of the text edit. The context is a path which
+ the text edit's QMimeSourceFactory uses to resolve the locations
+ of files and images.
+
+ \sa text
+*/
+
+QString QTextEdit::context() const
+{
+ return doc->context();
+}
+
+/*!
+ \property QTextEdit::documentTitle
+ \brief the title of the document parsed from the text.
+
+ For \c PlainText the title will be an empty string. For \c
+ RichText the title will be the text between the \c{<title>} tags,
+ if present, otherwise an empty string.
+*/
+
+QString QTextEdit::documentTitle() const
+{
+ return doc->attributes()[ "title" ];
+}
+
+void QTextEdit::makeParagVisible( QTextParagraph *p )
+{
+ setContentsPos( contentsX(), QMIN( p->rect().y(), contentsHeight() - visibleHeight() ) );
+}
+
+/*!
+ Scrolls the text edit to make the text at the anchor called \a
+ name visible, if it can be found in the document. If the anchor
+ isn't found no scrolling will occur. An anchor is defined using
+ the HTML anchor tag, e.g. \c{<a name="target">}.
+*/
+
+void QTextEdit::scrollToAnchor( const QString& name )
+{
+ if ( !isVisible() ) {
+ d->scrollToAnchor = name;
+ return;
+ }
+ if ( name.isEmpty() )
+ return;
+ sync();
+ QTextCursor cursor( doc );
+ QTextParagraph* last = doc->lastParagraph();
+ for (;;) {
+ QTextStringChar* c = cursor.paragraph()->at( cursor.index() );
+ if( c->isAnchor() ) {
+ QString a = c->anchorName();
+ if ( a == name ||
+ (a.contains( '#' ) && QStringList::split( '#', a ).contains( name ) ) ) {
+ setContentsPos( contentsX(), QMIN( cursor.paragraph()->rect().top() + cursor.totalOffsetY(), contentsHeight() - visibleHeight() ) );
+ break;
+ }
+ }
+ if ( cursor.paragraph() == last && cursor.atParagEnd() )
+ break;
+ cursor.gotoNextLetter();
+ }
+}
+
+#if (QT_VERSION-0 >= 0x040000)
+#error "function anchorAt(const QPoint& pos) should be merged into function anchorAt(const QPoint& pos, AnchorAttribute attr)"
+#endif
+
+/*!
+ \overload
+
+ If there is an anchor at position \a pos (in contents
+ coordinates), its \c href is returned, otherwise QString::null is
+ returned.
+*/
+
+QString QTextEdit::anchorAt( const QPoint& pos )
+{
+ return anchorAt(pos, AnchorHref);
+}
+
+/*!
+ If there is an anchor at position \a pos (in contents
+ coordinates), the text for attribute \a attr is returned,
+ otherwise QString::null is returned.
+*/
+
+QString QTextEdit::anchorAt( const QPoint& pos, AnchorAttribute attr )
+{
+ QTextCursor c( doc );
+ placeCursor( pos, &c );
+ switch(attr) {
+ case AnchorName:
+ return c.paragraph()->at( c.index() )->anchorName();
+ case AnchorHref:
+ return c.paragraph()->at( c.index() )->anchorHref();
+ }
+ // incase the compiler is really dumb about determining if a function
+ // returns something :)
+ return QString::null;
+}
+
+void QTextEdit::documentWidthChanged( int w )
+{
+ resizeContents( QMAX( visibleWidth(), w), contentsHeight() );
+}
+
+/*! \internal
+
+ This function does nothing
+*/
+
+void QTextEdit::updateStyles()
+{
+}
+
+void QTextEdit::setDocument( QTextDocument *dc )
+{
+ if ( dc == 0 ) {
+ qWarning( "Q3TextEdit::setDocument() called with null Q3TextDocument pointer" );
+ return;
+ }
+ if ( dc == doc )
+ return;
+ resetInputContext();
+ doc = dc;
+ delete cursor;
+ cursor = new QTextCursor( doc );
+ clearUndoRedo();
+ undoRedoInfo.doc = doc;
+ lastFormatted = 0;
+}
+
+#ifndef QT_NO_CLIPBOARD
+
+/*!
+ Pastes the text with format \a subtype from the clipboard into the
+ text edit at the current cursor position. The \a subtype can be
+ "plain" or "html".
+
+ If there is no text with format \a subtype in the clipboard
+ nothing happens.
+
+ \sa paste() cut() QTextEdit::copy()
+*/
+
+void QTextEdit::pasteSubType( const QCString &subtype )
+{
+#ifndef QT_NO_MIMECLIPBOARD
+ QMimeSource *m = QApplication::clipboard()->data( d->clipboard_mode );
+ pasteSubType( subtype, m );
+#endif
+}
+
+/*! \internal */
+
+void QTextEdit::pasteSubType( const QCString& subtype, QMimeSource *m )
+{
+#ifndef QT_NO_MIME
+ QCString st = subtype;
+ if ( subtype != "x-qrichtext" )
+ st.prepend( "text/" );
+ else
+ st.prepend( "application/" );
+ if ( !m )
+ return;
+ if ( doc->hasSelection( QTextDocument::Standard ) )
+ removeSelectedText();
+ if ( !QRichTextDrag::canDecode( m ) )
+ return;
+ QString t;
+ if ( !QRichTextDrag::decode( m, t, st.data(), subtype ) )
+ return;
+ if ( st == "application/x-qrichtext" ) {
+ int start;
+ if ( (start = t.find( "<!--StartFragment-->" )) != -1 ) {
+ start += 20;
+ int end = t.find( "<!--EndFragment-->" );
+ QTextCursor oldC = *cursor;
+
+ // during the setRichTextInternal() call the cursors
+ // paragraph might get joined with the provious one, so
+ // the cursors one would get deleted and oldC.paragraph()
+ // would be a dnagling pointer. To avoid that try to go
+ // one letter back and later go one forward again.
+ oldC.gotoPreviousLetter();
+ bool couldGoBack = oldC != *cursor;
+ // first para might get deleted, so remember to reset it
+ bool wasAtFirst = oldC.paragraph() == doc->firstParagraph();
+
+ if ( start < end )
+ t = t.mid( start, end - start );
+ else
+ t = t.mid( start );
+ lastFormatted = cursor->paragraph();
+ if ( lastFormatted->prev() )
+ lastFormatted = lastFormatted->prev();
+ doc->setRichTextInternal( t, cursor );
+
+ // the first para might have been deleted in
+ // setRichTextInternal(). To be sure, reset it if
+ // necessary.
+ if ( wasAtFirst ) {
+ int index = oldC.index();
+ oldC.setParagraph( doc->firstParagraph() );
+ oldC.setIndex( index );
+ }
+
+ // if we went back one letter before (see last comment),
+ // go one forward to point to the right position
+ if ( couldGoBack )
+ oldC.gotoNextLetter();
+
+ if ( undoEnabled && !isReadOnly() ) {
+ doc->setSelectionStart( QTextDocument::Temp, oldC );
+ doc->setSelectionEnd( QTextDocument::Temp, *cursor );
+
+ checkUndoRedoInfo( UndoRedoInfo::Insert );
+ if ( !undoRedoInfo.valid() ) {
+ undoRedoInfo.id = oldC.paragraph()->paragId();
+ undoRedoInfo.index = oldC.index();
+ undoRedoInfo.d->text = QString::null;
+ }
+ int oldLen = undoRedoInfo.d->text.length();
+ if ( !doc->preProcessor() ) {
+ QString txt = doc->selectedText( QTextDocument::Temp );
+ undoRedoInfo.d->text += txt;
+ for ( int i = 0; i < (int)txt.length(); ++i ) {
+ if ( txt[ i ] != '\n' && oldC.paragraph()->at( oldC.index() )->format() ) {
+ oldC.paragraph()->at( oldC.index() )->format()->addRef();
+ undoRedoInfo.d->text.
+ setFormat( oldLen + i, oldC.paragraph()->at( oldC.index() )->format(), TRUE );
+ }
+ oldC.gotoNextLetter();
+ }
+ }
+ undoRedoInfo.clear();
+ removeSelection( QTextDocument::Temp );
+ }
+
+ formatMore();
+ setModified();
+ emit textChanged();
+ repaintChanged();
+ ensureCursorVisible();
+ return;
+ }
+ } else {
+#if defined(Q_OS_WIN32)
+ // Need to convert CRLF to LF
+ t.replace( "\r\n", "\n" );
+#elif defined(Q_OS_MAC)
+ //need to convert CR to LF
+ t.replace( '\r', '\n' );
+#endif
+ QChar *uc = (QChar *)t.unicode();
+ for ( int i=0; (uint) i<t.length(); i++ ) {
+ if ( uc[ i ] < ' ' && uc[ i ] != '\n' && uc[ i ] != '\t' )
+ uc[ i ] = ' ';
+ }
+ if ( !t.isEmpty() )
+ insert( t, FALSE, TRUE );
+ }
+#endif //QT_NO_MIME
+}
+
+#ifndef QT_NO_MIMECLIPBOARD
+/*!
+ Prompts the user to choose a type from a list of text types
+ available, then copies text from the clipboard (if there is any)
+ into the text edit at the current text cursor position. Any
+ selected text (in selection 0) is first deleted.
+*/
+void QTextEdit::pasteSpecial( const QPoint& pt )
+{
+ QCString st = pickSpecial( QApplication::clipboard()->data( d->clipboard_mode ),
+ TRUE, pt );
+ if ( !st.isEmpty() )
+ pasteSubType( st );
+}
+#endif
+#ifndef QT_NO_MIME
+QCString QTextEdit::pickSpecial( QMimeSource* ms, bool always_ask, const QPoint& pt )
+{
+ if ( ms ) {
+#ifndef QT_NO_POPUPMENU
+ QPopupMenu popup( this, "qt_pickspecial_menu" );
+ QString fmt;
+ int n = 0;
+ QDict<void> done;
+ for (int i = 0; !( fmt = ms->format( i ) ).isNull(); i++) {
+ int semi = fmt.find( ";" );
+ if ( semi >= 0 )
+ fmt = fmt.left( semi );
+ if ( fmt.left( 5 ) == "text/" ) {
+ fmt = fmt.mid( 5 );
+ if ( !done.find( fmt ) ) {
+ done.insert( fmt,(void*)1 );
+ popup.insertItem( fmt, i );
+ n++;
+ }
+ }
+ }
+ if ( n ) {
+ int i = n ==1 && !always_ask ? popup.idAt( 0 ) : popup.exec( pt );
+ if ( i >= 0 )
+ return popup.text(i).latin1();
+ }
+#else
+ QString fmt;
+ for (int i = 0; !( fmt = ms->format( i ) ).isNull(); i++) {
+ int semi = fmt.find( ";" );
+ if ( semi >= 0 )
+ fmt = fmt.left( semi );
+ if ( fmt.left( 5 ) == "text/" ) {
+ fmt = fmt.mid( 5 );
+ return fmt.latin1();
+ }
+ }
+#endif
+ }
+ return QCString();
+}
+#endif // QT_NO_MIME
+#endif // QT_NO_CLIPBOARD
+
+/*!
+ \enum QTextEdit::WordWrap
+
+ This enum defines the QTextEdit's word wrap modes.
+
+ \value NoWrap Do not wrap the text.
+
+ \value WidgetWidth Wrap the text at the current width of the
+ widget (this is the default). Wrapping is at whitespace by
+ default; this can be changed with setWrapPolicy().
+
+ \value FixedPixelWidth Wrap the text at a fixed number of pixels
+ from the widget's left side. The number of pixels is set with
+ wrapColumnOrWidth().
+
+ \value FixedColumnWidth Wrap the text at a fixed number of
+ character columns from the widget's left side. The number of
+ characters is set with wrapColumnOrWidth(). This is useful if you
+ need formatted text that can also be displayed gracefully on
+ devices with monospaced fonts, for example a standard VT100
+ terminal, where you might set wrapColumnOrWidth() to 80.
+
+ \sa setWordWrap() wordWrap()
+*/
+
+/*!
+ \property QTextEdit::wordWrap
+ \brief the word wrap mode
+
+ The default mode is \c 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 setWrapPolicy(). If you set a wrap mode of
+ \c FixedPixelWidth or \c FixedColumnWidth you should also call
+ setWrapColumnOrWidth() with the width you want.
+
+ \sa WordWrap, wrapColumnOrWidth, wrapPolicy,
+*/
+
+void QTextEdit::setWordWrap( WordWrap mode )
+{
+ if ( wrapMode == mode )
+ return;
+ wrapMode = mode;
+ switch ( mode ) {
+ case NoWrap:
+ document()->formatter()->setWrapEnabled( FALSE );
+ document()->formatter()->setWrapAtColumn( -1 );
+ doc->setWidth( visibleWidth() );
+ doc->setMinimumWidth( -1 );
+ doc->invalidate();
+ updateContents();
+ lastFormatted = doc->firstParagraph();
+ interval = 0;
+ formatMore();
+ break;
+ case WidgetWidth:
+ document()->formatter()->setWrapEnabled( TRUE );
+ document()->formatter()->setWrapAtColumn( -1 );
+ doResize();
+ break;
+ case FixedPixelWidth:
+ document()->formatter()->setWrapEnabled( TRUE );
+ document()->formatter()->setWrapAtColumn( -1 );
+ if ( wrapWidth < 0 )
+ wrapWidth = 200;
+ setWrapColumnOrWidth( wrapWidth );
+ break;
+ case FixedColumnWidth:
+ if ( wrapWidth < 0 )
+ wrapWidth = 80;
+ document()->formatter()->setWrapEnabled( TRUE );
+ document()->formatter()->setWrapAtColumn( wrapWidth );
+ setWrapColumnOrWidth( wrapWidth );
+ break;
+ }
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ checkOptimMode();
+#endif
+}
+
+QTextEdit::WordWrap QTextEdit::wordWrap() const
+{
+ return wrapMode;
+}
+
+/*!
+ \property QTextEdit::wrapColumnOrWidth
+ \brief the position (in pixels or columns depending on the wrap mode) where text will be wrapped
+
+ If the wrap mode is \c 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 \c FixedColumnWidth, the value is the
+ column number (in character columns) from the left edge of the
+ text edit at which text should be wrapped.
+
+ \sa wordWrap
+*/
+void QTextEdit::setWrapColumnOrWidth( int value )
+{
+ wrapWidth = value;
+ if ( wrapMode == FixedColumnWidth ) {
+ document()->formatter()->setWrapAtColumn( wrapWidth );
+ resizeContents( 0, 0 );
+ doc->setWidth( visibleWidth() );
+ doc->setMinimumWidth( -1 );
+ } else if (wrapMode == FixedPixelWidth ) {
+ document()->formatter()->setWrapAtColumn( -1 );
+ resizeContents( wrapWidth, 0 );
+ doc->setWidth( wrapWidth );
+ doc->setMinimumWidth( wrapWidth );
+ } else {
+ return;
+ }
+ doc->invalidate();
+ updateContents();
+ lastFormatted = doc->firstParagraph();
+ interval = 0;
+ formatMore();
+}
+
+int QTextEdit::wrapColumnOrWidth() const
+{
+ if ( wrapMode == WidgetWidth )
+ return visibleWidth();
+ return wrapWidth;
+}
+
+
+/*!
+ \enum QTextEdit::WrapPolicy
+
+ This enum defines where text can be wrapped in word wrap mode.
+
+ \value AtWhiteSpace Don't use this deprecated value (it is a
+ synonym for \c AtWordBoundary which you should use instead).
+ \value Anywhere Break anywhere, including within words.
+ \value AtWordBoundary Break lines at word boundaries, e.g. spaces or
+ newlines
+ \value AtWordOrDocumentBoundary Break lines at whitespace, e.g.
+ spaces or newlines if possible. Break it anywhere otherwise.
+
+ \sa setWrapPolicy()
+*/
+
+/*!
+ \property QTextEdit::wrapPolicy
+ \brief the word wrap policy, at whitespace or anywhere
+
+ Defines where text can be wrapped when word wrap mode is not \c
+ NoWrap. The choices are \c AtWordBoundary (the default), \c
+ Anywhere and \c AtWordOrDocumentBoundary
+
+ \sa wordWrap
+*/
+
+void QTextEdit::setWrapPolicy( WrapPolicy policy )
+{
+ if ( wPolicy == policy )
+ return;
+ wPolicy = policy;
+ QTextFormatter *formatter;
+ if ( policy == AtWordBoundary || policy == AtWordOrDocumentBoundary ) {
+ formatter = new QTextFormatterBreakWords;
+ formatter->setAllowBreakInWords( policy == AtWordOrDocumentBoundary );
+ } else {
+ formatter = new QTextFormatterBreakInWords;
+ }
+ formatter->setWrapAtColumn( document()->formatter()->wrapAtColumn() );
+ formatter->setWrapEnabled( document()->formatter()->isWrapEnabled( 0 ) );
+ document()->setFormatter( formatter );
+ doc->invalidate();
+ updateContents();
+ lastFormatted = doc->firstParagraph();
+ interval = 0;
+ formatMore();
+}
+
+QTextEdit::WrapPolicy QTextEdit::wrapPolicy() const
+{
+ return wPolicy;
+}
+
+/*!
+ Deletes all the text in the text edit.
+
+ \sa cut() removeSelectedText() setText()
+*/
+
+void QTextEdit::clear()
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ optimSetText("");
+ } else
+#endif
+ {
+ // make clear undoable
+ doc->selectAll( QTextDocument::Temp );
+ removeSelectedText( QTextDocument::Temp );
+ setContentsPos( 0, 0 );
+ if ( cursor->isValid() )
+ cursor->restoreState();
+ doc->clear( TRUE );
+ delete cursor;
+ cursor = new QTextCursor( doc );
+ lastFormatted = 0;
+ }
+ updateContents();
+
+ emit cursorPositionChanged( cursor );
+ emit cursorPositionChanged( cursor->paragraph()->paragId(), cursor->index() );
+}
+
+int QTextEdit::undoDepth() const
+{
+ return document()->undoDepth();
+}
+
+/*!
+ \property QTextEdit::length
+ \brief the number of characters in the text
+*/
+
+int QTextEdit::length() const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode )
+ return d->od->len;
+ else
+#endif
+ return document()->length();
+}
+
+/*!
+ \property QTextEdit::tabStopWidth
+ \brief the tab stop width in pixels
+*/
+
+int QTextEdit::tabStopWidth() const
+{
+ return document()->tabStopWidth();
+}
+
+void QTextEdit::setUndoDepth( int d )
+{
+ document()->setUndoDepth( d );
+}
+
+void QTextEdit::setTabStopWidth( int ts )
+{
+ document()->setTabStops( ts );
+ doc->invalidate();
+ lastFormatted = doc->firstParagraph();
+ interval = 0;
+ formatMore();
+ updateContents();
+}
+
+/*!
+ \reimp
+*/
+
+QSize QTextEdit::sizeHint() const
+{
+ // cf. QScrollView::sizeHint()
+ constPolish();
+ int f = 2 * frameWidth();
+ int h = fontMetrics().height();
+ QSize sz( f, f );
+ return sz.expandedTo( QSize(12 * h, 8 * h) );
+}
+
+void QTextEdit::clearUndoRedo()
+{
+ if ( !undoEnabled )
+ return;
+ undoRedoInfo.clear();
+ emit undoAvailable( doc->commands()->isUndoAvailable() );
+ emit redoAvailable( doc->commands()->isRedoAvailable() );
+}
+
+/*! \internal
+ \warning In Qt 3.1 we will provide a cleaer API for the
+ functionality which is provided by this function and in Qt 4.0 this
+ function will go away.
+
+ This function gets the format of the character at position \a
+ index in paragraph \a para. Sets \a font to the character's font, \a
+ color to the character's color and \a verticalAlignment to the
+ character's vertical alignment.
+
+ Returns FALSE if \a para or \a index is out of range otherwise
+ returns TRUE.
+*/
+
+bool QTextEdit::getFormat( int para, int index, QFont *font, QColor *color, VerticalAlignment *verticalAlignment )
+{
+ if ( !font || !color )
+ return FALSE;
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return FALSE;
+ if ( index < 0 || index >= p->length() )
+ return FALSE;
+ *font = p->at( index )->format()->font();
+ *color = p->at( index )->format()->color();
+ *verticalAlignment = (VerticalAlignment)p->at( index )->format()->vAlign();
+ return TRUE;
+}
+
+/*! \internal
+ \warning In Qt 3.1 we will provide a cleaer API for the
+ functionality which is provided by this function and in Qt 4.0 this
+ function will go away.
+
+ This function gets the format of the paragraph \a para. Sets \a
+ font to the paragraphs's font, \a color to the paragraph's color, \a
+ verticalAlignment to the paragraph's vertical alignment, \a
+ alignment to the paragraph's alignment, \a displayMode to the
+ paragraph's display mode, \a listStyle to the paragraph's list style
+ (if the display mode is QStyleSheetItem::DisplayListItem) and \a
+ listDepth to the depth of the list (if the display mode is
+ QStyleSheetItem::DisplayListItem).
+
+ Returns FALSE if \a para is out of range otherwise returns TRUE.
+*/
+
+bool QTextEdit::getParagraphFormat( int para, QFont *font, QColor *color,
+ VerticalAlignment *verticalAlignment, int *alignment,
+ QStyleSheetItem::DisplayMode *displayMode,
+ QStyleSheetItem::ListStyle *listStyle,
+ int *listDepth )
+{
+ if ( !font || !color || !alignment || !displayMode || !listStyle )
+ return FALSE;
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return FALSE;
+ *font = p->at(0)->format()->font();
+ *color = p->at(0)->format()->color();
+ *verticalAlignment = (VerticalAlignment)p->at(0)->format()->vAlign();
+ *alignment = p->alignment();
+ *displayMode = p->isListItem() ? QStyleSheetItem::DisplayListItem : QStyleSheetItem::DisplayBlock;
+ *listStyle = p->listStyle();
+ *listDepth = p->listDepth();
+ return TRUE;
+}
+
+
+
+/*!
+ This function is called to create a right mouse button popup menu
+ at the document position \a pos. If you want to create a custom
+ popup menu, reimplement this function and return the created popup
+ menu. Ownership of the popup menu is transferred to the caller.
+
+ \warning The QPopupMenu ID values 0-7 are reserved, and they map to the
+ standard operations. When inserting items into your custom popup menu, be
+ sure to specify ID values larger than 7.
+*/
+
+QPopupMenu *QTextEdit::createPopupMenu( const QPoint& pos )
+{
+ Q_UNUSED( pos )
+#ifndef QT_NO_POPUPMENU
+ QPopupMenu *popup = new QPopupMenu( this, "qt_edit_menu" );
+ if ( !isReadOnly() ) {
+ d->id[ IdUndo ] = popup->insertItem( tr( "&Undo" ) + ACCEL_KEY( Z ) );
+ d->id[ IdRedo ] = popup->insertItem( tr( "&Redo" ) + ACCEL_KEY( Y ) );
+ popup->insertSeparator();
+ }
+#ifndef QT_NO_CLIPBOARD
+ if ( !isReadOnly() )
+ d->id[ IdCut ] = popup->insertItem( tr( "Cu&t" ) + ACCEL_KEY( X ) );
+ d->id[ IdCopy ] = popup->insertItem( tr( "&Copy" ) + ACCEL_KEY( C ) );
+ if ( !isReadOnly() )
+ d->id[ IdPaste ] = popup->insertItem( tr( "&Paste" ) + ACCEL_KEY( V ) );
+#endif
+ if ( !isReadOnly() ) {
+ d->id[ IdClear ] = popup->insertItem( tr( "Clear" ) );
+ popup->insertSeparator();
+ }
+#if defined(Q_WS_X11)
+ d->id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) );
+#else
+ d->id[ IdSelectAll ] = popup->insertItem( tr( "Select All" ) + ACCEL_KEY( A ) );
+#endif
+
+#ifndef QT_NO_IM
+ QInputContext *qic = getInputContext();
+ if ( qic )
+ qic->addMenusTo( popup );
+#endif
+
+ popup->setItemEnabled( d->id[ IdUndo ], !isReadOnly() && doc->commands()->isUndoAvailable() );
+ popup->setItemEnabled( d->id[ IdRedo ], !isReadOnly() && doc->commands()->isRedoAvailable() );
+#ifndef QT_NO_CLIPBOARD
+ popup->setItemEnabled( d->id[ IdCut ], !isReadOnly() && doc->hasSelection( QTextDocument::Standard, TRUE ) );
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ popup->setItemEnabled( d->id[ IdCopy ], d->optimMode ? optimHasSelection() : doc->hasSelection( QTextDocument::Standard, TRUE ) );
+#else
+ popup->setItemEnabled( d->id[ IdCopy ], doc->hasSelection( QTextDocument::Standard, TRUE ) );
+#endif
+ popup->setItemEnabled( d->id[ IdPaste ], !isReadOnly() && !QApplication::clipboard()->text( d->clipboard_mode ).isEmpty() );
+#endif
+ const bool isEmptyDocument = (length() == 0);
+ popup->setItemEnabled( d->id[ IdClear ], !isReadOnly() && !isEmptyDocument );
+ popup->setItemEnabled( d->id[ IdSelectAll ], !isEmptyDocument );
+ return popup;
+#else
+ return 0;
+#endif
+}
+
+/*! \overload
+ \obsolete
+ This function is called to create a right mouse button popup menu.
+ If you want to create a custom popup menu, reimplement this function
+ and return the created popup menu. Ownership of the popup menu is
+ transferred to the caller.
+
+ This function is only called if createPopupMenu( const QPoint & )
+ returns 0.
+*/
+
+QPopupMenu *QTextEdit::createPopupMenu()
+{
+ return 0;
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::setFont( const QFont &f )
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ QScrollView::setFont( f );
+ doc->setDefaultFormat( f, doc->formatCollection()->defaultFormat()->color() );
+ // recalculate the max string width
+ QFontMetrics fm(f);
+ int i, sw;
+ d->od->maxLineWidth = 0;
+ for ( i = 0; i < d->od->numLines; i++ ) {
+ sw = fm.width(d->od->lines[LOGOFFSET(i)]);
+ if (d->od->maxLineWidth < sw)
+ d->od->maxLineWidth = sw;
+ }
+ resizeContents(d->od->maxLineWidth + 4, d->od->numLines * fm.lineSpacing() + 1);
+ return;
+ }
+#endif
+ QScrollView::setFont( f );
+ doc->setMinimumWidth( -1 );
+ doc->setDefaultFormat( f, doc->formatCollection()->defaultFormat()->color() );
+ lastFormatted = doc->firstParagraph();
+ formatMore();
+ repaintChanged();
+}
+
+/*!
+ \fn QTextEdit::zoomIn()
+
+ \overload
+
+ Zooms in on the text by making the base font size one point
+ larger and recalculating all font sizes to be the new size. This
+ does not change the size of any images.
+
+ \sa zoomOut()
+*/
+
+/*!
+ \fn QTextEdit::zoomOut()
+
+ \overload
+
+ Zooms out on the text by making the base font size one point
+ smaller and recalculating all font sizes to be the new size. This
+ does not change the size of any images.
+
+ \sa zoomIn()
+*/
+
+
+/*!
+ 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( QScrollView::font() );
+ f.setPointSize( QFontInfo(f).pointSize() + range );
+ setFont( f );
+}
+
+/*!
+ 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 )
+{
+ QFont f( QScrollView::font() );
+ f.setPointSize( QMAX( 1, QFontInfo(f).pointSize() - range ) );
+ setFont( f );
+}
+
+/*!
+ Zooms the text by making the base font size \a size points and
+ recalculating all font sizes to be the new size. This does not
+ change the size of any images.
+*/
+
+void QTextEdit::zoomTo( int size )
+{
+ QFont f( QScrollView::font() );
+ f.setPointSize( size );
+ setFont( f );
+}
+
+/*!
+ QTextEdit is optimized for large amounts text. One of its
+ optimizations is to format only the visible text, formatting the rest
+ on demand, e.g. as the user scrolls, so you don't usually need to
+ call this function.
+
+ In some situations you may want to force the whole text
+ to be formatted. For example, if after calling setText(), you wanted
+ to know the height of the document (using contentsHeight()), you
+ would call this function first.
+*/
+
+void QTextEdit::sync()
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ QFontMetrics fm( QScrollView::font() );
+ resizeContents( d->od->maxLineWidth + 4, d->od->numLines * fm.lineSpacing() + 1 );
+ } else
+#endif
+ {
+ while ( lastFormatted ) {
+ lastFormatted->format();
+ lastFormatted = lastFormatted->next();
+ }
+ resizeContents( contentsWidth(), doc->height() );
+ }
+ updateScrollBars();
+}
+
+/*!
+ \reimp
+*/
+
+void QTextEdit::setEnabled( bool b )
+{
+ QScrollView::setEnabled( b );
+ if ( textFormat() == PlainText ) {
+ QTextFormat *f = doc->formatCollection()->defaultFormat();
+ f->setColor( colorGroup().text() );
+ updateContents();
+ }
+}
+
+/*!
+ Sets the background color of selection number \a selNum to \a back
+ and specifies whether the text of this selection should be
+ inverted with \a invertText.
+
+ This only works for \a selNum > 0. The default selection (\a
+ selNum == 0) gets its attributes from the text edit's
+ colorGroup().
+*/
+
+void QTextEdit::setSelectionAttributes( int selNum, const QColor &back, bool invertText )
+{
+ if ( selNum < 1 )
+ return;
+ if ( selNum > doc->numSelections() )
+ doc->addSelection( selNum );
+ doc->setSelectionColor( selNum, back );
+ doc->setInvertSelectionText( selNum, invertText );
+}
+
+/*!
+ \reimp
+*/
+void QTextEdit::windowActivationChange( bool oldActive )
+{
+ if ( oldActive && scrollTimer )
+ scrollTimer->stop();
+ if ( palette().active() != palette().inactive() )
+ updateContents();
+ QScrollView::windowActivationChange( oldActive );
+}
+
+void QTextEdit::setReadOnly( bool b )
+{
+ if ( (bool) readonly == b )
+ return;
+ readonly = b;
+#ifndef QT_NO_CURSOR
+ if ( readonly )
+ viewport()->setCursor( arrowCursor );
+ else
+ viewport()->setCursor( ibeamCursor );
+ setInputMethodEnabled( !readonly );
+#endif
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ checkOptimMode();
+#endif
+}
+
+/*!
+ Scrolls to the bottom of the document and does formatting if
+ required.
+*/
+
+void QTextEdit::scrollToBottom()
+{
+ sync();
+ setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
+}
+
+/*!
+ Returns the rectangle of the paragraph \a para in contents
+ coordinates, or an invalid rectangle if \a para is out of range.
+*/
+
+QRect QTextEdit::paragraphRect( int para ) const
+{
+ QTextEdit *that = (QTextEdit *)this;
+ that->sync();
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return QRect( -1, -1, -1, -1 );
+ return p->rect();
+}
+
+/*!
+ Returns the paragraph which is at position \a pos (in contents
+ coordinates).
+*/
+
+int QTextEdit::paragraphAt( const QPoint &pos ) const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ QFontMetrics fm( QScrollView::font() );
+ int parag = pos.y() / fm.lineSpacing();
+ if ( parag <= d->od->numLines )
+ return parag;
+ else
+ return 0;
+ }
+#endif
+ QTextCursor c( doc );
+ c.place( pos, doc->firstParagraph() );
+ if ( c.paragraph() )
+ return c.paragraph()->paragId();
+ return -1; // should never happen..
+}
+
+/*!
+ Returns the index of the character (relative to its paragraph) at
+ position \a pos (in contents coordinates). If \a para is not 0,
+ \a *para is set to the character's paragraph.
+*/
+
+int QTextEdit::charAt( const QPoint &pos, int *para ) const
+{
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ if ( d->optimMode ) {
+ int par = paragraphAt( pos );
+ if ( para )
+ *para = par;
+ return optimCharIndex( d->od->lines[ LOGOFFSET(par) ], pos.x() );
+ }
+#endif
+ QTextCursor c( doc );
+ c.place( pos, doc->firstParagraph() );
+ if ( c.paragraph() ) {
+ if ( para )
+ *para = c.paragraph()->paragId();
+ return c.index();
+ }
+ return -1; // should never happen..
+}
+
+/*!
+ Sets the background color of the paragraph \a para to \a bg.
+*/
+
+void QTextEdit::setParagraphBackgroundColor( int para, const QColor &bg )
+{
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return;
+ p->setBackgroundColor( bg );
+ repaintChanged();
+}
+
+/*!
+ Clears the background color of the paragraph \a para, so that the
+ default color is used again.
+*/
+
+void QTextEdit::clearParagraphBackground( int para )
+{
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return;
+ p->clearBackgroundColor();
+ repaintChanged();
+}
+
+/*!
+ Returns the background color of the paragraph \a para or an
+ invalid color if \a para is out of range or the paragraph has no
+ background set
+*/
+
+QColor QTextEdit::paragraphBackgroundColor( int para ) const
+{
+ QTextParagraph *p = doc->paragAt( para );
+ if ( !p )
+ return QColor();
+ QColor *c = p->backgroundColor();
+ if ( c )
+ return *c;
+ return QColor();
+}
+
+/*!
+ \property QTextEdit::undoRedoEnabled
+ \brief whether undo/redo is enabled
+
+ When changing this property, the undo/redo history is cleared.
+
+ The default is TRUE.
+*/
+
+void QTextEdit::setUndoRedoEnabled( bool b )
+{
+ undoRedoInfo.clear();
+ doc->commands()->clear();
+
+ undoEnabled = b;
+}
+
+bool QTextEdit::isUndoRedoEnabled() const
+{
+ return undoEnabled;
+}
+
+/*!
+ Returns TRUE if undo is available; otherwise returns FALSE.
+*/
+
+bool QTextEdit::isUndoAvailable() const
+{
+ return undoEnabled && (doc->commands()->isUndoAvailable() || undoRedoInfo.valid());
+}
+
+/*!
+ Returns TRUE if redo is available; otherwise returns FALSE.
+*/
+
+bool QTextEdit::isRedoAvailable() const
+{
+ return undoEnabled && doc->commands()->isRedoAvailable();
+}
+
+void QTextEdit::ensureFormatted( QTextParagraph *p )
+{
+ while ( !p->isValid() ) {
+ if ( !lastFormatted )
+ return;
+ formatMore();
+ }
+}
+
+/*! \internal */
+void QTextEdit::updateCursor( const QPoint & pos )
+{
+ if ( isReadOnly() && linksEnabled() ) {
+ QTextCursor c = *cursor;
+ placeCursor( pos, &c, TRUE );
+
+#ifndef QT_NO_NETWORKPROTOCOL
+ bool insideParagRect = TRUE;
+ if (c.paragraph() == doc->lastParagraph()
+ && c.paragraph()->rect().y() + c.paragraph()->rect().height() < pos.y())
+ insideParagRect = FALSE;
+ if (insideParagRect && c.paragraph() && c.paragraph()->at( c.index() ) &&
+ c.paragraph()->at( c.index() )->isAnchor()) {
+ if (!c.paragraph()->at( c.index() )->anchorHref().isEmpty()
+ && c.index() < c.paragraph()->length() - 1 )
+ onLink = c.paragraph()->at( c.index() )->anchorHref();
+ else
+ onLink = QString::null;
+
+ if (!c.paragraph()->at( c.index() )->anchorName().isEmpty()
+ && c.index() < c.paragraph()->length() - 1 )
+ d->onName = c.paragraph()->at( c.index() )->anchorName();
+ else
+ d->onName = QString::null;
+
+ if (!c.paragraph()->at( c.index() )->anchorHref().isEmpty() ) {
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( onLink.isEmpty() ? arrowCursor : pointingHandCursor );
+#endif
+ QUrl u( doc->context(), onLink, TRUE );
+ emitHighlighted( u.toString( FALSE, FALSE ) );
+ }
+ } else {
+#ifndef QT_NO_CURSOR
+ viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor );
+#endif
+ onLink = QString::null;
+ emitHighlighted( QString::null );
+ }
+#endif
+ }
+}
+
+/*!
+ Places the cursor \a c at the character which is closest to position
+ \a pos (in contents coordinates). If \a c is 0, the default text
+ cursor is used.
+
+ \sa setCursorPosition()
+*/
+void QTextEdit::placeCursor( const QPoint &pos, QTextCursor *c )
+{
+ placeCursor( pos, c, FALSE );
+}
+
+/*! \internal */
+void QTextEdit::clipboardChanged()
+{
+#ifndef QT_NO_CLIPBOARD
+ // don't listen to selection changes
+ disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
+#endif
+ selectAll(FALSE);
+}
+
+/*! \property QTextEdit::tabChangesFocus
+ \brief whether 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 TAB key, as this breaks
+ the focus chain. The default is FALSE.
+
+*/
+
+void QTextEdit::setTabChangesFocus( bool b )
+{
+ d->tabChangesFocus = b;
+}
+
+bool QTextEdit::tabChangesFocus() const
+{
+ return d->tabChangesFocus;
+}
+
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+/* Implementation of optimized LogText mode follows */
+
+static void qSwap( int * a, int * b )
+{
+ if ( !a || !b )
+ return;
+ int tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+/*! \internal */
+bool QTextEdit::checkOptimMode()
+{
+ bool oldMode = d->optimMode;
+ if ( textFormat() == LogText ) {
+ setReadOnly( TRUE );
+ d->optimMode = TRUE;
+ } else {
+ d->optimMode = FALSE;
+ }
+
+ // when changing mode - try to keep selections and text
+ if ( oldMode != d->optimMode ) {
+ if ( d->optimMode ) {
+ d->od = new QTextEditOptimPrivate;
+ connect( scrollTimer, SIGNAL( timeout() ), this, SLOT( optimDoAutoScroll() ) );
+ disconnect( doc, SIGNAL( minimumWidthChanged(int) ), this, SLOT( documentWidthChanged(int) ) );
+ disconnect( scrollTimer, SIGNAL( timeout() ), this, SLOT( autoScrollTimerDone() ) );
+ disconnect( formatTimer, SIGNAL( timeout() ), this, SLOT( formatMore() ) );
+ optimSetText( doc->originalText() );
+ doc->clear(TRUE);
+ delete cursor;
+ cursor = new QTextCursor( doc );
+ } else {
+ disconnect( scrollTimer, SIGNAL( timeout() ), this, SLOT( optimDoAutoScroll() ) );
+ connect( doc, SIGNAL( minimumWidthChanged(int) ), this, SLOT( documentWidthChanged(int) ) );
+ connect( scrollTimer, SIGNAL( timeout() ), this, SLOT( autoScrollTimerDone() ) );
+ connect( formatTimer, SIGNAL( timeout() ), this, SLOT( formatMore() ) );
+ setText( optimText() );
+ delete d->od;
+ d->od = 0;
+ }
+ }
+ return d->optimMode;
+}
+
+/*! \internal */
+QString QTextEdit::optimText() const
+{
+ QString str, tmp;
+
+ if ( d->od->len == 0 )
+ return str;
+
+ // concatenate all strings
+ int i;
+ int offset;
+ QMapConstIterator<int,QTextEditOptimPrivate::Tag *> it;
+ QTextEditOptimPrivate::Tag * ftag = 0;
+ for ( i = 0; i < d->od->numLines; i++ ) {
+ if ( d->od->lines[ LOGOFFSET(i) ].isEmpty() ) { // CR lines are empty
+ str += "\n";
+ } else {
+ tmp = d->od->lines[ LOGOFFSET(i) ] + "\n";
+ // inject the tags for this line
+ if ( (it = d->od->tagIndex.find( LOGOFFSET(i) )) != d->od->tagIndex.end() )
+ ftag = it.data();
+ offset = 0;
+ while ( ftag && ftag->line == i ) {
+ tmp.insert( ftag->index + offset, "<" + ftag->tag + ">" );
+ offset += ftag->tag.length() + 2; // 2 -> the '<' and '>' chars
+ ftag = ftag->next;
+ }
+ str += tmp;
+ }
+ }
+ return str;
+}
+
+/*! \internal */
+void QTextEdit::optimSetText( const QString &str )
+{
+ optimRemoveSelection();
+// this is just too slow - but may have to go in due to compatibility reasons
+// if ( str == optimText() )
+// return;
+ d->od->numLines = 0;
+ d->od->lines.clear();
+ d->od->maxLineWidth = 0;
+ d->od->len = 0;
+ d->od->clearTags();
+ QFontMetrics fm( QScrollView::font() );
+ if ( !(str.isEmpty() || str.isNull() || d->maxLogLines == 0) ) {
+ QStringList strl = QStringList::split( '\n', str, TRUE );
+ int lWidth = 0;
+ for ( QStringList::Iterator it = strl.begin(); it != strl.end(); ++it ) {
+ optimParseTags( &*it );
+ optimCheckLimit( *it );
+ lWidth = fm.width( *it );
+ if ( lWidth > d->od->maxLineWidth )
+ d->od->maxLineWidth = lWidth;
+ }
+ }
+ resizeContents( d->od->maxLineWidth + 4, d->od->numLines * fm.lineSpacing() + 1 );
+ repaintContents();
+ emit textChanged();
+}
+
+/*! \internal
+
+ Append \a tag to the tag list.
+*/
+QTextEditOptimPrivate::Tag * QTextEdit::optimAppendTag( int index, const QString & tag )
+{
+ QTextEditOptimPrivate::Tag * t = new QTextEditOptimPrivate::Tag, * tmp;
+
+ if ( d->od->tags == 0 )
+ d->od->tags = t;
+ t->bold = t->italic = t->underline = FALSE;
+ t->line = d->od->numLines;
+ t->index = index;
+ t->tag = tag;
+ t->leftTag = 0;
+ t->parent = 0;
+ t->prev = d->od->lastTag;
+ if ( d->od->lastTag )
+ d->od->lastTag->next = t;
+ t->next = 0;
+ d->od->lastTag = t;
+ tmp = d->od->tagIndex[ LOGOFFSET(t->line) ];
+ if ( !tmp || (tmp && tmp->index > t->index) ) {
+ d->od->tagIndex.replace( LOGOFFSET(t->line), t );
+ }
+ return t;
+}
+
+ /*! \internal
+
+ Insert \a tag in the tag - according to line and index numbers
+*/
+
+QTextEditOptimPrivate::Tag *QTextEdit::optimInsertTag(int line, int index, const QString &tag)
+{
+ QTextEditOptimPrivate::Tag *t = new QTextEditOptimPrivate::Tag, *tmp;
+
+ if (d->od->tags == 0)
+ d->od->tags = t;
+ t->bold = t->italic = t->underline = FALSE;
+ t->line = line;
+ t->index = index;
+ t->tag = tag;
+ t->leftTag = 0;
+ t->parent = 0;
+ t->next = 0;
+ t->prev = 0;
+
+ // find insertion pt. in tag struct.
+ QMap<int,QTextEditOptimPrivate::Tag *>::ConstIterator it;
+ if ((it = d->od->tagIndex.find(LOGOFFSET(line))) != d->od->tagIndex.end()) {
+ tmp = *it;
+ if (tmp->index >= index) { // the exisiting tag may be placed AFTER the one we want to insert
+ tmp = tmp->prev;
+ } else {
+ while (tmp && tmp->next && tmp->next->line == line && tmp->next->index <= index)
+ tmp = tmp->next;
+ }
+ } else {
+ tmp = d->od->tags;
+ while (tmp && tmp->next && tmp->next->line < line)
+ tmp = tmp->next;
+ if (tmp == d->od->tags)
+ tmp = 0;
+ }
+
+ t->prev = tmp;
+ t->next = tmp ? tmp->next : 0;
+ if (t->next)
+ t->next->prev = t;
+ if (tmp)
+ tmp->next = t;
+
+ tmp = d->od->tagIndex[LOGOFFSET(t->line)];
+ if (!tmp || (tmp && tmp->index >= t->index)) {
+ d->od->tagIndex.replace(LOGOFFSET(t->line), t);
+ }
+ return t;
+}
+
+
+/*! \internal
+
+ Find tags in \a line, remove them from \a line and put them in a
+ structure.
+
+ A tag is delimited by '<' and '>'. The characters '<', '>' and '&'
+ are escaped by using '&lt;', '&gt;' and '&amp;'. Left-tags marks
+ the starting point for formatting, while right-tags mark the ending
+ point. A right-tag is the same as a left-tag, but with a '/'
+ appearing before the tag keyword. E.g a valid left-tag: <b>, and
+ a valid right-tag: </b>. Tags can be nested, but they have to be
+ closed in the same order as they are opened. E.g:
+ <font color=red><font color=blue>blue</font>red</font> - is valid, while:
+ <font color=red><b>bold red</font> just bold</b> - is invalid since the font tag is
+ closed before the bold tag. Note that a tag does not have to be
+ closed: '<font color=blue>Lots of text - and then some..' is perfectly valid for
+ setting all text appearing after the tag to blue. A tag can be used
+ to change the color of a piece of text, or set one of the following
+ formatting attributes: bold, italic and underline. These attributes
+ are set using the <b>, <i> and <u> tags. Example of valid tags:
+ <font color=red>, </font>, <b>, <u>, <i>, </i>.
+ Example of valid text:
+ This is some <font color=red>red text</font>, while this is some <font color=green>green
+ text</font>. <font color=blue><font color=yellow>This is yellow</font>, while this is
+ blue.</font>
+
+ Note that only the color attribute of the HTML font tag is supported.
+
+ Limitations:
+ 1. A tag cannot span several lines.
+ 2. Very limited error checking - mismatching left/right-tags is the
+ only thing that is detected.
+
+*/
+void QTextEdit::optimParseTags( QString * line, int lineNo, int indexOffset )
+{
+ int len = line->length();
+ int i, startIndex = -1, endIndex = -1, escIndex = -1;
+ int state = 0; // 0 = outside tag, 1 = inside tag
+ bool tagOpen, tagClose;
+ int bold = 0, italic = 0, underline = 0;
+ QString tagStr;
+ QPtrStack<QTextEditOptimPrivate::Tag> tagStack;
+
+ for ( i = 0; i < len; i++ ) {
+ tagOpen = (*line)[i] == '<';
+ tagClose = (*line)[i] == '>';
+
+ // handle '&lt;' and '&gt;' and '&amp;'
+ if ( (*line)[i] == '&' ) {
+ escIndex = i;
+ continue;
+ } else if ( escIndex != -1 && (*line)[i] == ';' ) {
+ QString esc = line->mid( escIndex, i - escIndex + 1 );
+ QString c;
+ if ( esc == "&lt;" )
+ c = '<';
+ else if ( esc == "&gt;" )
+ c = '>';
+ else if ( esc == "&amp;" )
+ c = '&';
+ line->replace( escIndex, i - escIndex + 1, c );
+ len = line->length();
+ i -= i-escIndex;
+ escIndex = -1;
+ continue;
+ }
+
+ if ( state == 0 && tagOpen ) {
+ state = 1;
+ startIndex = i;
+ continue;
+ }
+ if ( state == 1 && tagClose ) {
+ state = 0;
+ endIndex = i;
+ if ( !tagStr.isEmpty() ) {
+ QTextEditOptimPrivate::Tag * tag, * cur, * tmp;
+ bool format = TRUE;
+
+ if ( tagStr == "b" )
+ bold++;
+ else if ( tagStr == "/b" )
+ bold--;
+ else if ( tagStr == "i" )
+ italic++;
+ else if ( tagStr == "/i" )
+ italic--;
+ else if ( tagStr == "u" )
+ underline++;
+ else if ( tagStr == "/u" )
+ underline--;
+ else
+ format = FALSE;
+ if ( lineNo > -1 )
+ tag = optimInsertTag( lineNo, startIndex + indexOffset, tagStr );
+ else
+ tag = optimAppendTag( startIndex, tagStr );
+ // everything that is not a b, u or i tag is considered
+ // to be a color tag.
+ tag->type = format ? QTextEditOptimPrivate::Format
+ : QTextEditOptimPrivate::Color;
+ if ( tagStr[0] == '/' ) {
+ // this is a right-tag - search for the left-tag
+ // and possible parent tag
+ cur = tag->prev;
+ if ( !cur ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "QTextEdit::optimParseTags: no left-tag for '<%s>' in line %d.", tag->tag.ascii(), tag->line + 1 );
+#endif
+ return; // something is wrong - give up
+ }
+ while ( cur ) {
+ if ( cur->leftTag ) { // push right-tags encountered
+ tagStack.push( cur );
+ } else {
+ tmp = tagStack.pop();
+ if ( !tmp ) {
+ if ( (("/" + cur->tag) == tag->tag) ||
+ (tag->tag == "/font" && cur->tag.left(4) == "font") ) {
+ // set up the left and parent of this tag
+ tag->leftTag = cur;
+ tmp = cur->prev;
+ if ( tmp && tmp->parent ) {
+ tag->parent = tmp->parent;
+ } else if ( tmp && !tmp->leftTag ) {
+ tag->parent = tmp;
+ }
+ break;
+ } else if ( !cur->leftTag ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "QTextEdit::optimParseTags: mismatching %s-tag for '<%s>' in line %d.", cur->tag[0] == '/' ? "left" : "right", cur->tag.ascii(), cur->line + 1 );
+#endif
+ return; // something is amiss - give up
+ }
+ }
+ }
+ cur = cur->prev;
+ }
+ } else {
+ tag->bold = bold > 0;
+ tag->italic = italic > 0;
+ tag->underline = underline > 0;
+ tmp = tag->prev;
+ while ( tmp && tmp->leftTag ) {
+ tmp = tmp->leftTag->parent;
+ }
+ if ( tmp ) {
+ tag->bold |= tmp->bold;
+ tag->italic |= tmp->italic;
+ tag->underline |= tmp->underline;
+ }
+ }
+ }
+ if ( startIndex != -1 ) {
+ int l = (endIndex == -1) ?
+ line->length() - startIndex : endIndex - startIndex;
+ line->remove( startIndex, l+1 );
+ len = line->length();
+ i -= l+1;
+ }
+ tagStr = "";
+ continue;
+ }
+
+ if ( state == 1 ) {
+ tagStr += (*line)[i];
+ }
+ }
+}
+
+// calculate the width of a string in pixels inc. tabs
+static int qStrWidth(const QString& str, int tabWidth, const QFontMetrics& fm)
+{
+ int tabs = str.contains('\t');
+
+ if (!tabs)
+ return fm.width(str);
+
+ int newIdx = 0;
+ int lastIdx = 0;
+ int strWidth = 0;
+ int tn;
+ for (tn = 1; tn <= tabs; ++tn) {
+ newIdx = str.find('\t', newIdx);
+ strWidth += fm.width(str.mid(lastIdx, newIdx - lastIdx));
+ if (strWidth >= tn * tabWidth) {
+ int u = tn;
+ while (strWidth >= u * tabWidth)
+ ++u;
+ strWidth = u * tabWidth;
+ } else {
+ strWidth = tn * tabWidth;
+ }
+ lastIdx = ++newIdx;
+ }
+ if ((int)str.length() > newIdx)
+ strWidth += fm.width(str.mid(newIdx));
+ return strWidth;
+}
+
+bool QTextEdit::optimHasBoldMetrics(int line)
+{
+ QTextEditOptimPrivate::Tag *t;
+ QMapConstIterator<int,QTextEditOptimPrivate::Tag *> it;
+ if ((it = d->od->tagIndex.find(line)) != d->od->tagIndex.end()) {
+ t = *it;
+ while (t && t->line == line) {
+ if (t->bold)
+ return TRUE;
+ t = t->next;
+ }
+ } else if ((t = optimPreviousLeftTag(line)) && t->bold) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*! \internal
+
+ Append \a str to the current text buffer. Parses each line to find
+ formatting tags.
+*/
+void QTextEdit::optimAppend( const QString &str )
+{
+ if ( str.isEmpty() || str.isNull() || d->maxLogLines == 0 )
+ return;
+
+ QStringList strl = QStringList::split( '\n', str, TRUE );
+ QStringList::Iterator it = strl.begin();
+
+ QFontMetrics fm(QScrollView::font());
+ int lWidth = 0;
+
+ for ( ; it != strl.end(); ++it ) {
+ optimParseTags( &*it );
+ optimCheckLimit( *it );
+ if (optimHasBoldMetrics(d->od->numLines-1)) {
+ QFont fnt = QScrollView::font();
+ fnt.setBold(TRUE);
+ fm = QFontMetrics(fnt);
+ }
+ lWidth = qStrWidth(*it, tabStopWidth(), fm) + 4;
+ if ( lWidth > d->od->maxLineWidth )
+ d->od->maxLineWidth = lWidth;
+ }
+ bool scrollToEnd = contentsY() >= contentsHeight() - visibleHeight();
+ resizeContents( d->od->maxLineWidth + 4, d->od->numLines * fm.lineSpacing() + 1 );
+ if ( scrollToEnd ) {
+ updateScrollBars();
+ ensureVisible( contentsX(), contentsHeight(), 0, 0 );
+ }
+ // when a max log size is set, the text may not be redrawn because
+ // the size of the viewport may not have changed
+ if ( d->maxLogLines > -1 )
+ viewport()->update();
+ emit textChanged();
+}
+
+
+static void qStripTags(QString *line)
+{
+ int len = line->length();
+ int i, startIndex = -1, endIndex = -1, escIndex = -1;
+ int state = 0; // 0 = outside tag, 1 = inside tag
+ bool tagOpen, tagClose;
+
+ for ( i = 0; i < len; i++ ) {
+ tagOpen = (*line)[i] == '<';
+ tagClose = (*line)[i] == '>';
+
+ // handle '&lt;' and '&gt;' and '&amp;'
+ if ( (*line)[i] == '&' ) {
+ escIndex = i;
+ continue;
+ } else if ( escIndex != -1 && (*line)[i] == ';' ) {
+ QString esc = line->mid( escIndex, i - escIndex + 1 );
+ QString c;
+ if ( esc == "&lt;" )
+ c = '<';
+ else if ( esc == "&gt;" )
+ c = '>';
+ else if ( esc == "&amp;" )
+ c = '&';
+ line->replace( escIndex, i - escIndex + 1, c );
+ len = line->length();
+ i -= i-escIndex;
+ escIndex = -1;
+ continue;
+ }
+
+ if ( state == 0 && tagOpen ) {
+ state = 1;
+ startIndex = i;
+ continue;
+ }
+ if ( state == 1 && tagClose ) {
+ state = 0;
+ endIndex = i;
+ if ( startIndex != -1 ) {
+ int l = (endIndex == -1) ?
+ line->length() - startIndex : endIndex - startIndex;
+ line->remove( startIndex, l+1 );
+ len = line->length();
+ i -= l+1;
+ }
+ continue;
+ }
+ }
+}
+
+/*! \internal
+
+ Inserts the text into \a line at index \a index.
+*/
+
+void QTextEdit::optimInsert(const QString& text, int line, int index)
+{
+ if (text.isEmpty() || d->maxLogLines == 0)
+ return;
+ if (line < 0)
+ line = 0;
+ if (line > d->od->numLines-1)
+ line = d->od->numLines-1;
+ if (index < 0)
+ index = 0;
+ if (index > (int) d->od->lines[line].length())
+ index = d->od->lines[line].length();
+
+ QStringList strl = QStringList::split('\n', text, TRUE);
+ int numNewLines = (int)strl.count() - 1;
+ QTextEditOptimPrivate::Tag *tag = 0;
+ QMap<int,QTextEditOptimPrivate::Tag *>::ConstIterator ii;
+ int x;
+
+ if (numNewLines == 0) {
+ // Case 1. Fast single line case - just inject it!
+ QString stripped = text;
+ qStripTags( &stripped );
+ d->od->lines[LOGOFFSET(line)].insert(index, stripped);
+ // move the tag indices following the insertion pt.
+ if ((ii = d->od->tagIndex.find(LOGOFFSET(line))) != d->od->tagIndex.end()) {
+ tag = *ii;
+ while (tag && (LOGOFFSET(tag->line) == line && tag->index < index))
+ tag = tag->next;
+ while (tag && (LOGOFFSET(tag->line) == line)) {
+ tag->index += stripped.length();
+ tag = tag->next;
+ }
+ }
+ stripped = text;
+ optimParseTags(&stripped, line, index);
+ } else if (numNewLines > 0) {
+ // Case 2. We have at least 1 newline char - split at
+ // insertion pt. and make room for new lines - complex and slow!
+ QString left = d->od->lines[LOGOFFSET(line)].left(index);
+ QString right = d->od->lines[LOGOFFSET(line)].mid(index);
+
+ // rearrange lines for insertion
+ for (x = d->od->numLines - 1; x > line; x--)
+ d->od->lines[x + numNewLines] = d->od->lines[x];
+ d->od->numLines += numNewLines;
+
+ // fix the tag index and the tag line/index numbers - this
+ // might take a while..
+ for (x = line; x < d->od->numLines; x++) {
+ if ((ii = d->od->tagIndex.find(LOGOFFSET(line))) != d->od->tagIndex.end()) {
+ tag = ii.data();
+ if (LOGOFFSET(tag->line) == line)
+ while (tag && (LOGOFFSET(tag->line) == line && tag->index < index))
+ tag = tag->next;
+ }
+ }
+
+ // relabel affected tags with new line numbers and new index
+ // positions
+ while (tag) {
+ if (LOGOFFSET(tag->line) == line)
+ tag->index -= index;
+ tag->line += numNewLines;
+ tag = tag->next;
+ }
+
+ // generate a new tag index
+ d->od->tagIndex.clear();
+ tag = d->od->tags;
+ while (tag) {
+ if (!((ii = d->od->tagIndex.find(LOGOFFSET(tag->line))) != d->od->tagIndex.end()))
+ d->od->tagIndex[LOGOFFSET(tag->line)] = tag;
+ tag = tag->next;
+ }
+
+ // update the tag indices on the spliced line - needs to be done before new tags are added
+ QString stripped = strl[strl.count() - 1];
+ qStripTags(&stripped);
+ if ((ii = d->od->tagIndex.find(LOGOFFSET(line + numNewLines))) != d->od->tagIndex.end()) {
+ tag = *ii;
+ while (tag && (LOGOFFSET(tag->line) == line + numNewLines)) {
+ tag->index += stripped.length();
+ tag = tag->next;
+ }
+ }
+
+ // inject the new lines
+ QStringList::Iterator it = strl.begin();
+ x = line;
+ int idx;
+ for (; it != strl.end(); ++it) {
+ stripped = *it;
+ qStripTags(&stripped);
+ if (x == line) {
+ stripped = left + stripped;
+ idx = index;
+ } else {
+ idx = 0;
+ }
+ d->od->lines[LOGOFFSET(x)] = stripped;
+ optimParseTags(&*it, x++, idx);
+ }
+ d->od->lines[LOGOFFSET(x - 1)] += right;
+ }
+ // recalculate the pixel width of the longest injected line -
+ QFontMetrics fm(QScrollView::font());
+ int lWidth = 0;
+
+ for (x = line; x < line + numNewLines; x++) {
+ if (optimHasBoldMetrics(x)) {
+ QFont fnt = QScrollView::font();
+ fnt.setBold(TRUE);
+ fm = QFontMetrics(fnt);
+ }
+ lWidth = fm.width(d->od->lines[x]) + 4;
+ if (lWidth > d->od->maxLineWidth)
+ d->od->maxLineWidth = lWidth;
+ }
+ resizeContents(d->od->maxLineWidth + 4, d->od->numLines * fm.lineSpacing() + 1);
+ repaintContents();
+ emit textChanged();
+}
+
+
+
+/*! \internal
+
+ Returns the first open left-tag appearing before line \a line.
+ */
+QTextEditOptimPrivate::Tag * QTextEdit::optimPreviousLeftTag( int line )
+{
+ QTextEditOptimPrivate::Tag * ftag = 0;
+ QMapConstIterator<int,QTextEditOptimPrivate::Tag *> it;
+ if ( (it = d->od->tagIndex.find( LOGOFFSET(line) )) != d->od->tagIndex.end() )
+ ftag = it.data();
+ if ( !ftag ) {
+ // start searching for an open tag
+ ftag = d->od->tags;
+ while ( ftag ) {
+ if ( ftag->line > line || ftag->next == 0 ) {
+ if ( ftag->line > line )
+ ftag = ftag->prev;
+ break;
+ }
+ ftag = ftag->next;
+ }
+ } else {
+ ftag = ftag->prev;
+ }
+
+ if ( ftag ) {
+ if ( ftag && ftag->parent ) // use the open parent tag
+ ftag = ftag->parent;
+ else if ( ftag && ftag->leftTag ) // this is a right-tag with no parent
+ ftag = 0;
+ }
+ return ftag;
+}
+
+/*! \internal
+
+ Set the format for the string starting at index \a start and ending
+ at \a end according to \a tag. If \a tag is a Format tag, find the
+ first open color tag appearing before \a tag and use that tag to
+ color the string.
+*/
+void QTextEdit::optimSetTextFormat( QTextDocument * td, QTextCursor * cur,
+ QTextFormat * f, int start, int end,
+ QTextEditOptimPrivate::Tag * tag )
+{
+ int formatFlags = QTextFormat::Bold | QTextFormat::Italic |
+ QTextFormat::Underline;
+ cur->setIndex( start );
+ td->setSelectionStart( 0, *cur );
+ cur->setIndex( end );
+ td->setSelectionEnd( 0, *cur );
+ QStyleSheetItem * ssItem = styleSheet()->item( tag->tag );
+ if ( !ssItem || tag->type == QTextEditOptimPrivate::Format ) {
+ f->setBold( tag->bold );
+ f->setItalic( tag->italic );
+ f->setUnderline( tag->underline );
+ if ( tag->type == QTextEditOptimPrivate::Format ) {
+ // check to see if there are any open color tags prior to
+ // this format tag
+ tag = tag->prev;
+ while ( tag && (tag->type == QTextEditOptimPrivate::Format ||
+ tag->leftTag) ) {
+ tag = tag->leftTag ? tag->parent : tag->prev;
+ }
+ }
+ if ( tag ) {
+ QString col = tag->tag.simplifyWhiteSpace();
+ if ( col.left( 10 ) == "font color" ) {
+ int i = col.find( '=', 10 );
+ col = col.mid( i + 1 ).simplifyWhiteSpace();
+ if ( col[0] == '\"' )
+ col = col.mid( 1, col.length() - 2 );
+ }
+ QColor color = QColor( col );
+ if ( color.isValid() ) {
+ formatFlags |= QTextFormat::Color;
+ f->setColor( color );
+ }
+ }
+ } else { // use the stylesheet tag definition
+ if ( ssItem->color().isValid() ) {
+ formatFlags |= QTextFormat::Color;
+ f->setColor( ssItem->color() );
+ }
+ f->setBold( ssItem->fontWeight() == QFont::Bold );
+ f->setItalic( ssItem->fontItalic() );
+ f->setUnderline( ssItem->fontUnderline() );
+ }
+ td->setFormat( 0, f, formatFlags );
+ td->removeSelection( 0 );
+}
+
+/*! \internal */
+void QTextEdit::optimDrawContents( QPainter * p, int clipx, int clipy,
+ int clipw, int cliph )
+{
+ QFontMetrics fm( QScrollView::font() );
+ int startLine = clipy / fm.lineSpacing();
+
+ // we always have to fetch at least two lines for drawing because the
+ // painter may be translated so that parts of two lines cover the area
+ // of a single line
+ int nLines = (cliph / fm.lineSpacing()) + 2;
+ int endLine = startLine + nLines;
+
+ if ( startLine >= d->od->numLines )
+ return;
+ if ( (startLine + nLines) > d->od->numLines )
+ nLines = d->od->numLines - startLine;
+
+ int i = 0;
+ QString str;
+ for ( i = startLine; i < (startLine + nLines); i++ )
+ str.append( d->od->lines[ LOGOFFSET(i) ] + "\n" );
+
+ QTextDocument * td = new QTextDocument( 0 );
+ td->setDefaultFormat( QScrollView::font(), QColor() );
+ td->setPlainText( str );
+ td->setFormatter( new QTextFormatterBreakWords ); // deleted by QTextDoc
+ td->formatter()->setWrapEnabled( FALSE );
+ td->setTabStops(doc->tabStopWidth());
+
+ // get the current text color from the current format
+ td->selectAll( QTextDocument::Standard );
+ QTextFormat f;
+ f.setColor( colorGroup().text() );
+ f.setFont( QScrollView::font() );
+ td->setFormat( QTextDocument::Standard, &f,
+ QTextFormat::Color | QTextFormat::Font );
+ td->removeSelection( QTextDocument::Standard );
+
+ // add tag formatting
+ if ( d->od->tags ) {
+ int i = startLine;
+ QMapConstIterator<int,QTextEditOptimPrivate::Tag *> it;
+ QTextEditOptimPrivate::Tag * tag = 0, * tmp = 0;
+ QTextCursor cur( td );
+ // Step 1 - find previous left-tag
+ tmp = optimPreviousLeftTag( i );
+ for ( ; i < startLine + nLines; i++ ) {
+ if ( (it = d->od->tagIndex.find( LOGOFFSET(i) )) != d->od->tagIndex.end() )
+ tag = it.data();
+ // Step 2 - iterate over tags on the current line
+ int lastIndex = 0;
+ while ( tag && tag->line == i ) {
+ tmp = 0;
+ if ( tag->prev && !tag->prev->leftTag ) {
+ tmp = tag->prev;
+ } else if ( tag->prev && tag->prev->parent ) {
+ tmp = tag->prev->parent;
+ }
+ if ( (tag->index - lastIndex) > 0 && tmp ) {
+ optimSetTextFormat( td, &cur, &f, lastIndex, tag->index, tmp );
+ }
+ lastIndex = tag->index;
+ tmp = tag;
+ tag = tag->next;
+ }
+ // Step 3 - color last part of the line - if necessary
+ if ( tmp && tmp->parent )
+ tmp = tmp->parent;
+ if ( (cur.paragraph()->length()-1 - lastIndex) > 0 && tmp && !tmp->leftTag ) {
+ optimSetTextFormat( td, &cur, &f, lastIndex,
+ cur.paragraph()->length() - 1, tmp );
+ }
+ cur.setParagraph( cur.paragraph()->next() );
+ }
+ // useful debug info
+ //
+// tag = d->od->tags;
+// qWarning("###");
+// while ( tag ) {
+// qWarning( "Tag: %p, parent: %09p, leftTag: %09p, Name: %-15s, ParentName: %s, %d%d%d", tag,
+// tag->parent, tag->leftTag, tag->tag.latin1(), tag->parent ? tag->parent->tag.latin1():"<none>",
+// tag->bold, tag->italic, tag->underline );
+// tag = tag->next;
+// }
+ }
+
+ // if there is a selection, make sure that the selection in the
+ // part we need to redraw is set correctly
+ if ( optimHasSelection() ) {
+ QTextCursor c1( td );
+ QTextCursor c2( td );
+ int selStart = d->od->selStart.line;
+ int idxStart = d->od->selStart.index;
+ int selEnd = d->od->selEnd.line;
+ int idxEnd = d->od->selEnd.index;
+ if ( selEnd < selStart ) {
+ qSwap( &selStart, &selEnd );
+ qSwap( &idxStart, &idxEnd );
+ }
+ if ( selEnd > d->od->numLines-1 ) {
+ selEnd = d->od->numLines-1;
+ }
+ if ( startLine <= selStart && endLine >= selEnd ) {
+ // case 1: area to paint covers entire selection
+ int paragS = selStart - startLine;
+ int paragE = paragS + (selEnd - selStart);
+ QTextParagraph * parag = td->paragAt( paragS );
+ if ( parag ) {
+ c1.setParagraph( parag );
+ if ( td->text( paragS ).length() >= (uint) idxStart )
+ c1.setIndex( idxStart );
+ }
+ parag = td->paragAt( paragE );
+ if ( parag ) {
+ c2.setParagraph( parag );
+ if ( td->text( paragE ).length() >= (uint) idxEnd )
+ c2.setIndex( idxEnd );
+ }
+ } else if ( startLine > selStart && endLine < selEnd ) {
+ // case 2: area to paint is all part of the selection
+ td->selectAll( QTextDocument::Standard );
+ } else if ( startLine > selStart && endLine >= selEnd &&
+ startLine <= selEnd ) {
+ // case 3: area to paint starts inside a selection, ends past it
+ c1.setParagraph( td->firstParagraph() );
+ c1.setIndex( 0 );
+ int paragE = selEnd - startLine;
+ QTextParagraph * parag = td->paragAt( paragE );
+ if ( parag ) {
+ c2.setParagraph( parag );
+ if ( td->text( paragE ).length() >= (uint) idxEnd )
+ c2.setIndex( idxEnd );
+ }
+ } else if ( startLine <= selStart && endLine < selEnd &&
+ endLine > selStart ) {
+ // case 4: area to paint starts before a selection, ends inside it
+ int paragS = selStart - startLine;
+ QTextParagraph * parag = td->paragAt( paragS );
+ if ( parag ) {
+ c1.setParagraph( parag );
+ c1.setIndex( idxStart );
+ }
+ c2.setParagraph( td->lastParagraph() );
+ c2.setIndex( td->lastParagraph()->string()->toString().length() - 1 );
+
+ }
+ // previously selected?
+ if ( !td->hasSelection( QTextDocument::Standard ) ) {
+ td->setSelectionStart( QTextDocument::Standard, c1 );
+ td->setSelectionEnd( QTextDocument::Standard, c2 );
+ }
+ }
+ td->doLayout( p, contentsWidth() );
+
+ // have to align the painter so that partly visible lines are
+ // drawn at the correct position within the area that needs to be
+ // painted
+ int offset = clipy % fm.lineSpacing() + 2;
+ QRect r( clipx, 0, clipw, cliph + offset );
+ p->translate( 0, clipy - offset );
+ td->draw( p, r.x(), r.y(), r.width(), r.height(), colorGroup() );
+ p->translate( 0, -(clipy - offset) );
+ delete td;
+}
+
+/*! \internal */
+void QTextEdit::optimMousePressEvent( QMouseEvent * e )
+{
+ if ( e->button() != LeftButton )
+ return;
+
+ QFontMetrics fm( QScrollView::font() );
+ mousePressed = TRUE;
+ mousePos = e->pos();
+ d->od->selStart.line = e->y() / fm.lineSpacing();
+ if ( d->od->selStart.line > d->od->numLines-1 ) {
+ d->od->selStart.line = d->od->numLines-1;
+ d->od->selStart.index = d->od->lines[ LOGOFFSET(d->od->numLines-1) ].length();
+ } else {
+ QString str = d->od->lines[ LOGOFFSET(d->od->selStart.line) ];
+ d->od->selStart.index = optimCharIndex( str, mousePos.x() );
+ }
+ d->od->selEnd.line = d->od->selStart.line;
+ d->od->selEnd.index = d->od->selStart.index;
+ oldMousePos = e->pos();
+ repaintContents( FALSE );
+}
+
+/*! \internal */
+void QTextEdit::optimMouseReleaseEvent( QMouseEvent * e )
+{
+ if ( e->button() != LeftButton )
+ return;
+
+ if ( scrollTimer->isActive() )
+ scrollTimer->stop();
+ if ( !inDoubleClick ) {
+ QFontMetrics fm( QScrollView::font() );
+ d->od->selEnd.line = e->y() / fm.lineSpacing();
+ if ( d->od->selEnd.line > d->od->numLines-1 ) {
+ d->od->selEnd.line = d->od->numLines-1;
+ }
+ QString str = d->od->lines[ LOGOFFSET(d->od->selEnd.line) ];
+ mousePos = e->pos();
+ d->od->selEnd.index = optimCharIndex( str, mousePos.x() );
+ if ( d->od->selEnd.line < d->od->selStart.line ) {
+ qSwap( &d->od->selStart.line, &d->od->selEnd.line );
+ qSwap( &d->od->selStart.index, &d->od->selEnd.index );
+ } else if ( d->od->selStart.line == d->od->selEnd.line &&
+ d->od->selStart.index > d->od->selEnd.index ) {
+ qSwap( &d->od->selStart.index, &d->od->selEnd.index );
+ }
+ oldMousePos = e->pos();
+ repaintContents( FALSE );
+ }
+ if ( mousePressed ) {
+ mousePressed = FALSE;
+ copyToClipboard();
+ }
+
+ inDoubleClick = FALSE;
+ emit copyAvailable( optimHasSelection() );
+ emit selectionChanged();
+}
+
+/*! \internal */
+void QTextEdit::optimMouseMoveEvent( QMouseEvent * e )
+{
+ mousePos = e->pos();
+ optimDoAutoScroll();
+ oldMousePos = mousePos;
+}
+
+/*! \internal */
+void QTextEdit::optimDoAutoScroll()
+{
+ if ( !mousePressed )
+ return;
+
+ QFontMetrics fm( QScrollView::font() );
+ QPoint pos( mapFromGlobal( QCursor::pos() ) );
+ bool doScroll = FALSE;
+ int xx = contentsX() + pos.x();
+ int yy = contentsY() + pos.y();
+
+ // find out how much we have to scroll in either dir.
+ if ( pos.x() < 0 || pos.x() > viewport()->width() ||
+ pos.y() < 0 || pos.y() > viewport()->height() ) {
+ int my = yy;
+ if ( pos.x() < 0 )
+ xx = contentsX() - fm.width( 'w');
+ else if ( pos.x() > viewport()->width() )
+ xx = contentsX() + viewport()->width() + fm.width('w');
+
+ if ( pos.y() < 0 ) {
+ my = contentsY() - 1;
+ yy = (my / fm.lineSpacing()) * fm.lineSpacing() + 1;
+ } else if ( pos.y() > viewport()->height() ) {
+ my = contentsY() + viewport()->height() + 1;
+ yy = (my / fm.lineSpacing() + 1) * fm.lineSpacing() - 1;
+ }
+ d->od->selEnd.line = my / fm.lineSpacing();
+ mousePos.setX( xx );
+ mousePos.setY( my );
+ doScroll = TRUE;
+ } else {
+ d->od->selEnd.line = mousePos.y() / fm.lineSpacing();
+ }
+
+ if ( d->od->selEnd.line < 0 ) {
+ d->od->selEnd.line = 0;
+ } else if ( d->od->selEnd.line > d->od->numLines-1 ) {
+ d->od->selEnd.line = d->od->numLines-1;
+ }
+
+ QString str = d->od->lines[ LOGOFFSET(d->od->selEnd.line) ];
+ d->od->selEnd.index = optimCharIndex( str, mousePos.x() );
+
+ // have to have a valid index before generating a paint event
+ if ( doScroll )
+ ensureVisible( xx, yy, 1, 1 );
+
+ // if the text document is smaller than the heigth of the viewport
+ // - redraw the whole thing otherwise calculate the rect that
+ // needs drawing.
+ if ( d->od->numLines * fm.lineSpacing() < viewport()->height() ) {
+ repaintContents( contentsX(), contentsY(), width(), height(), FALSE );
+ } else {
+ int h = QABS(mousePos.y() - oldMousePos.y()) + fm.lineSpacing() * 2;
+ int y;
+ if ( oldMousePos.y() < mousePos.y() ) {
+ y = oldMousePos.y() - fm.lineSpacing();
+ } else {
+ // expand paint area for a fully selected line
+ h += fm.lineSpacing();
+ y = mousePos.y() - fm.lineSpacing()*2;
+ }
+ if ( y < 0 )
+ y = 0;
+ repaintContents( contentsX(), y, width(), h, FALSE );
+ }
+
+ if ( !scrollTimer->isActive() && pos.y() < 0 || pos.y() > height() )
+ scrollTimer->start( 100, FALSE );
+ else if ( scrollTimer->isActive() && pos.y() >= 0 && pos.y() <= height() )
+ scrollTimer->stop();
+}
+
+/*! \internal
+
+ Returns the index of the character in the string \a str that is
+ currently under the mouse pointer.
+*/
+int QTextEdit::optimCharIndex( const QString &str, int mx ) const
+{
+ QFontMetrics fm(QScrollView::font());
+ uint i = 0;
+ int dd, dist = 10000000;
+ int curpos = 0;
+ int strWidth;
+ mx = mx - 4; // ### get the real margin from somewhere
+
+ if (!str.contains('\t') && mx > fm.width(str))
+ return str.length();
+
+ while (i < str.length()) {
+ strWidth = qStrWidth(str.left(i), tabStopWidth(), fm);
+ dd = strWidth - mx;
+ if (QABS(dd) <= dist) {
+ dist = QABS(dd);
+ if (mx >= strWidth)
+ curpos = i;
+ }
+ ++i;
+ }
+ return curpos;
+}
+
+/*! \internal */
+void QTextEdit::optimSelectAll()
+{
+ d->od->selStart.line = d->od->selStart.index = 0;
+ d->od->selEnd.line = d->od->numLines - 1;
+ d->od->selEnd.index = d->od->lines[ LOGOFFSET(d->od->selEnd.line) ].length();
+
+ repaintContents( FALSE );
+ emit copyAvailable( optimHasSelection() );
+ emit selectionChanged();
+}
+
+/*! \internal */
+void QTextEdit::optimRemoveSelection()
+{
+ d->od->selStart.line = d->od->selEnd.line = -1;
+ d->od->selStart.index = d->od->selEnd.index = -1;
+ repaintContents( FALSE );
+}
+
+/*! \internal */
+void QTextEdit::optimSetSelection( int startLine, int startIdx,
+ int endLine, int endIdx )
+{
+ d->od->selStart.line = startLine;
+ d->od->selEnd.line = endLine;
+ d->od->selStart.index = startIdx;
+ d->od->selEnd.index = endIdx;
+}
+
+/*! \internal */
+bool QTextEdit::optimHasSelection() const
+{
+ if ( d->od->selStart.line != d->od->selEnd.line ||
+ d->od->selStart.index != d->od->selEnd.index )
+ return TRUE;
+ return FALSE;
+}
+
+/*! \internal */
+QString QTextEdit::optimSelectedText() const
+{
+ QString str;
+
+ if ( !optimHasSelection() )
+ return str;
+
+ // concatenate all strings
+ if ( d->od->selStart.line == d->od->selEnd.line ) {
+ str = d->od->lines[ LOGOFFSET(d->od->selEnd.line) ].mid( d->od->selStart.index,
+ d->od->selEnd.index - d->od->selStart.index );
+ } else {
+ int i = d->od->selStart.line;
+ str = d->od->lines[ LOGOFFSET(i) ].right( d->od->lines[ LOGOFFSET(i) ].length() -
+ d->od->selStart.index ) + "\n";
+ i++;
+ for ( ; i < d->od->selEnd.line; i++ ) {
+ if ( d->od->lines[ LOGOFFSET(i) ].isEmpty() ) // CR lines are empty
+ str += "\n";
+ else
+ str += d->od->lines[ LOGOFFSET(i) ] + "\n";
+ }
+ str += d->od->lines[ LOGOFFSET(d->od->selEnd.line) ].left( d->od->selEnd.index );
+ }
+ return str;
+}
+
+/*! \internal */
+bool QTextEdit::optimFind( const QString & expr, bool cs, bool /*wo*/,
+ bool fw, int * para, int * index )
+{
+ bool found = FALSE;
+ int parag = para ? *para : d->od->search.line,
+ idx = index ? *index : d->od->search.index, i;
+
+ if ( d->od->len == 0 )
+ return FALSE;
+
+ for ( i = parag; fw ? i < d->od->numLines : i >= 0; fw ? i++ : i-- ) {
+ idx = fw ? d->od->lines[ LOGOFFSET(i) ].find( expr, idx, cs ) :
+ d->od->lines[ LOGOFFSET(i) ].findRev( expr, idx, cs );
+ if ( idx != -1 ) {
+ found = TRUE;
+ break;
+ } else if ( fw )
+ idx = 0;
+ }
+
+ if ( found ) {
+ if ( index )
+ *index = idx;
+ if ( para )
+ *para = i;
+ d->od->search.index = idx + 1;
+ d->od->search.line = i;
+ optimSetSelection( i, idx, i, idx + expr.length() );
+ QFontMetrics fm( QScrollView::font() );
+ int h = fm.lineSpacing();
+ int x = fm.width( d->od->lines[ LOGOFFSET(i) ].left( idx + expr.length()) ) + 4;
+ ensureVisible( x, i * h + h / 2, 1, h / 2 + 2 );
+ repaintContents(); // could possibly be optimized
+ }
+ return found;
+}
+
+/*! \reimp */
+void QTextEdit::polish()
+{
+ // this will ensure that the last line is visible if text have
+ // been added to the widget before it is shown
+ if ( d->optimMode )
+ scrollToBottom();
+ QWidget::polish();
+}
+
+/*!
+ Sets the maximum number of lines a QTextEdit can hold in \c
+ LogText mode to \a limit. If \a limit is -1 (the default), this
+ signifies an unlimited number of lines.
+
+ \warning Never use formatting tags that span more than one line
+ when the maximum log lines is set. When lines are removed from the
+ top of the buffer it could result in an unbalanced tag pair, i.e.
+ the left formatting tag is removed before the right one.
+ */
+void QTextEdit::setMaxLogLines( int limit )
+{
+ d->maxLogLines = limit;
+ if ( d->maxLogLines < -1 )
+ d->maxLogLines = -1;
+ if ( d->maxLogLines == -1 )
+ d->logOffset = 0;
+}
+
+/*!
+ Returns the maximum number of lines QTextEdit can hold in \c
+ LogText mode. By default the number of lines is unlimited, which
+ is signified by a value of -1.
+ */
+int QTextEdit::maxLogLines()
+{
+ return d->maxLogLines;
+}
+
+/*!
+ Check if the number of lines in the buffer is limited, and uphold
+ that limit when appending new lines.
+ */
+void QTextEdit::optimCheckLimit( const QString& str )
+{
+ if ( d->maxLogLines > -1 && d->maxLogLines <= d->od->numLines ) {
+ // NB! Removing the top line in the buffer will potentially
+ // destroy the structure holding the formatting tags - if line
+ // spanning tags are used.
+ QTextEditOptimPrivate::Tag *t = d->od->tags, *tmp, *itr;
+ QPtrList<QTextEditOptimPrivate::Tag> lst;
+ while ( t ) {
+ t->line -= 1;
+ // unhook the ptr from the tag structure
+ if ( ((uint) LOGOFFSET(t->line) < (uint) d->logOffset &&
+ (uint) LOGOFFSET(t->line) < (uint) LOGOFFSET(d->od->numLines) &&
+ (uint) LOGOFFSET(d->od->numLines) > (uint) d->logOffset) )
+ {
+ if ( t->prev )
+ t->prev->next = t->next;
+ if ( t->next )
+ t->next->prev = t->prev;
+ if ( d->od->tags == t )
+ d->od->tags = t->next;
+ if ( d->od->lastTag == t ) {
+ if ( t->prev )
+ d->od->lastTag = t->prev;
+ else
+ d->od->lastTag = d->od->tags;
+ }
+ tmp = t;
+ t = t->next;
+ lst.append( tmp );
+ delete tmp;
+ } else {
+ t = t->next;
+ }
+ }
+ // Remove all references to the ptrs we just deleted
+ itr = d->od->tags;
+ while ( itr ){
+ for ( tmp = lst.first(); tmp; tmp = lst.next() ) {
+ if ( itr->parent == tmp )
+ itr->parent = 0;
+ if ( itr->leftTag == tmp )
+ itr->leftTag = 0;
+ }
+ itr = itr->next;
+ }
+ // ...in the tag index as well
+ QMapIterator<int, QTextEditOptimPrivate::Tag *> idx;
+ if ( (idx = d->od->tagIndex.find( d->logOffset )) != d->od->tagIndex.end() )
+ d->od->tagIndex.remove( idx );
+
+ QMapIterator<int,QString> it;
+ if ( (it = d->od->lines.find( d->logOffset )) != d->od->lines.end() ) {
+ d->od->len -= (*it).length();
+ d->od->lines.remove( it );
+ d->od->numLines--;
+ d->logOffset = LOGOFFSET(1);
+ }
+ }
+ d->od->len += str.length();
+ d->od->lines[ LOGOFFSET(d->od->numLines++) ] = str;
+}
+
+#endif // QT_TEXTEDIT_OPTIMIZATION
+
+/*!
+ \property QTextEdit::autoFormatting
+ \brief the enabled set of auto formatting features
+
+ The value can be any combination of the values in the \c
+ AutoFormatting enum. The default is \c AutoAll. Choose \c AutoNone
+ to disable all automatic formatting.
+
+ Currently, the only automatic formatting feature provided is \c
+ AutoBulletList; future versions of Qt may offer more.
+*/
+
+void QTextEdit::setAutoFormatting( uint features )
+{
+ d->autoFormatting = features;
+}
+
+uint QTextEdit::autoFormatting() const
+{
+ return d->autoFormatting;
+}
+
+/*!
+ Returns the QSyntaxHighlighter set on this QTextEdit. 0 is
+ returned if no syntax highlighter is set.
+ */
+QSyntaxHighlighter * QTextEdit::syntaxHighlighter() const
+{
+ if (document()->preProcessor())
+ return ((QSyntaxHighlighterInternal *) document()->preProcessor())->highlighter;
+ else
+ return 0;
+}
+
+#endif //QT_NO_TEXTEDIT
diff --git a/src/widgets/qtextedit.h b/src/widgets/qtextedit.h
new file mode 100644
index 0000000..c015c2c
--- /dev/null
+++ b/src/widgets/qtextedit.h
@@ -0,0 +1,616 @@
+/****************************************************************************
+**
+** Definition of the QTextEdit class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTEXTEDIT_H
+#define QTEXTEDIT_H
+
+#ifndef QT_H
+#include "qscrollview.h"
+#include "qstylesheet.h"
+#include "qptrvector.h"
+#include "qvaluelist.h"
+#include "qptrlist.h"
+#endif // QT_H
+
+#ifndef QT_NO_TEXTEDIT
+// uncomment below to enable optimization mode - also uncomment the
+// optimDoAutoScroll() private slot since moc ignores #ifdefs..
+#define QT_TEXTEDIT_OPTIMIZATION
+
+class QPainter;
+class QTextDocument;
+class QTextCursor;
+class QKeyEvent;
+class QResizeEvent;
+class QMouseEvent;
+class QTimer;
+class QTextString;
+class QTextCommand;
+class QTextParagraph;
+class QTextFormat;
+class QFont;
+class QColor;
+class QTextEdit;
+class QTextBrowser;
+class QTextString;
+struct QUndoRedoInfoPrivate;
+class QPopupMenu;
+class QTextEditPrivate;
+class QSyntaxHighlighter;
+
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+class QTextEditOptimPrivate
+{
+public:
+ // Note: no left-tag has any value for leftTag or parent, and
+ // no right-tag has any formatting flags set.
+ enum TagType { Color = 0, Format = 1 };
+ struct Tag {
+ TagType type:2;
+ bool bold:1;
+ bool italic:1;
+ bool underline:1;
+ int line;
+ int index;
+ Tag * leftTag; // ptr to left-tag in a left-right tag pair
+ Tag * parent; // ptr to parent left-tag in a nested tag
+ Tag * prev;
+ Tag * next;
+ QString tag;
+ };
+ QTextEditOptimPrivate()
+ {
+ len = numLines = maxLineWidth = 0;
+ selStart.line = selStart.index = -1;
+ selEnd.line = selEnd.index = -1;
+ search.line = search.index = 0;
+ tags = lastTag = 0;
+ }
+ void clearTags()
+ {
+ Tag * itr = tags;
+ while ( tags ) {
+ itr = tags;
+ tags = tags->next;
+ delete itr;
+ }
+ tags = lastTag = 0;
+ tagIndex.clear();
+ }
+ ~QTextEditOptimPrivate()
+ {
+ clearTags();
+ }
+ int len;
+ int numLines;
+ int maxLineWidth;
+ struct Selection {
+ int line;
+ int index;
+ };
+ Selection selStart, selEnd, search;
+ Tag * tags, * lastTag;
+ QMap<int, QString> lines;
+ QMap<int, Tag *> tagIndex;
+};
+#endif
+
+class Q_EXPORT QTextEdit : public QScrollView
+{
+ friend class QTextBrowser;
+ friend class QSyntaxHighlighter;
+
+ Q_OBJECT
+ Q_ENUMS( WordWrap WrapPolicy )
+ Q_SETS( AutoFormatting )
+ Q_PROPERTY( TextFormat textFormat READ textFormat WRITE setTextFormat )
+ Q_PROPERTY( QString text READ text WRITE setText )
+ Q_PROPERTY( QBrush paper READ paper WRITE setPaper )
+ Q_PROPERTY( bool linkUnderline READ linkUnderline WRITE setLinkUnderline )
+ Q_PROPERTY( QString documentTitle READ documentTitle )
+ Q_PROPERTY( int length READ length )
+ Q_PROPERTY( WordWrap wordWrap READ wordWrap WRITE setWordWrap )
+ Q_PROPERTY( int wrapColumnOrWidth READ wrapColumnOrWidth WRITE setWrapColumnOrWidth )
+ Q_PROPERTY( WrapPolicy wrapPolicy READ wrapPolicy WRITE setWrapPolicy )
+ Q_PROPERTY( bool hasSelectedText READ hasSelectedText )
+ Q_PROPERTY( QString selectedText READ selectedText )
+ Q_PROPERTY( int undoDepth READ undoDepth WRITE setUndoDepth )
+ Q_PROPERTY( bool overwriteMode READ isOverwriteMode WRITE setOverwriteMode )
+ Q_PROPERTY( bool modified READ isModified WRITE setModified DESIGNABLE false )
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
+ Q_PROPERTY( bool undoRedoEnabled READ isUndoRedoEnabled WRITE setUndoRedoEnabled )
+ Q_PROPERTY( int tabStopWidth READ tabStopWidth WRITE setTabStopWidth )
+ Q_PROPERTY( bool tabChangesFocus READ tabChangesFocus WRITE setTabChangesFocus )
+ Q_PROPERTY( AutoFormatting autoFormatting READ autoFormatting WRITE setAutoFormatting )
+
+public:
+ enum WordWrap {
+ NoWrap,
+ WidgetWidth,
+ FixedPixelWidth,
+ FixedColumnWidth
+ };
+
+ enum WrapPolicy {
+ AtWordBoundary,
+ AtWhiteSpace = AtWordBoundary, // AtWhiteSpace is deprecated
+ Anywhere,
+ AtWordOrDocumentBoundary
+ };
+
+ enum AutoFormatting {
+ AutoNone = 0,
+ AutoBulletList = 0x00000001,
+ AutoAll = 0xffffffff
+ };
+
+ enum KeyboardAction {
+ ActionBackspace,
+ ActionDelete,
+ ActionReturn,
+ ActionKill,
+ ActionWordBackspace,
+ ActionWordDelete
+ };
+
+ enum CursorAction {
+ MoveBackward,
+ MoveForward,
+ MoveWordBackward,
+ MoveWordForward,
+ MoveUp,
+ MoveDown,
+ MoveLineStart,
+ MoveLineEnd,
+ MoveHome,
+ MoveEnd,
+ MovePgUp,
+ MovePgDown
+ };
+
+ enum VerticalAlignment {
+ AlignNormal,
+ AlignSuperScript,
+ AlignSubScript
+ };
+
+ enum TextInsertionFlags {
+ RedoIndentation = 0x0001,
+ CheckNewLines = 0x0002,
+ RemoveSelected = 0x0004,
+ AsIMCompositionText = 0x0008, // internal use
+ WithIMSelection = 0x0010 // internal use
+ };
+
+ QTextEdit( const QString& text, const QString& context = QString::null,
+ QWidget* parent=0, const char* name=0);
+ QTextEdit( QWidget* parent=0, const char* name=0 );
+ virtual ~QTextEdit();
+ void setPalette( const QPalette & );
+
+ QString text() const;
+ QString text( int para ) const;
+ TextFormat textFormat() const;
+ QString context() const;
+ QString documentTitle() const;
+
+ void getSelection( int *paraFrom, int *indexFrom,
+ int *paraTo, int *indexTo, int selNum = 0 ) const;
+ virtual bool find( const QString &expr, bool cs, bool wo, bool forward = TRUE,
+ int *para = 0, int *index = 0 );
+
+ int paragraphs() const;
+ int lines() const;
+ int linesOfParagraph( int para ) const;
+ int lineOfChar( int para, int chr );
+ int length() const;
+ QRect paragraphRect( int para ) const;
+ int paragraphAt( const QPoint &pos ) const;
+ int charAt( const QPoint &pos, int *para ) const;
+ int paragraphLength( int para ) const;
+
+ QStyleSheet* styleSheet() const;
+#ifndef QT_NO_MIME
+ QMimeSourceFactory* mimeSourceFactory() const;
+#endif
+ QBrush paper() const;
+ bool linkUnderline() const;
+
+ int heightForWidth( int w ) const;
+
+ bool hasSelectedText() const;
+ QString selectedText() const;
+ bool isUndoAvailable() const;
+ bool isRedoAvailable() const;
+
+ WordWrap wordWrap() const;
+ int wrapColumnOrWidth() const;
+ WrapPolicy wrapPolicy() const;
+
+ int tabStopWidth() const;
+
+ QString anchorAt( const QPoint& pos );
+ QString anchorAt( const QPoint& pos, AnchorAttribute a );
+
+ QSize sizeHint() const;
+
+ bool isReadOnly() const { return readonly; }
+
+ void getCursorPosition( int *parag, int *index ) const;
+
+ bool isModified() const;
+ bool italic() const;
+ bool bold() const;
+ bool underline() const;
+ QString family() const;
+ int pointSize() const;
+ QColor color() const;
+ QFont font() const;
+ QFont currentFont() const;
+ int alignment() const;
+ int undoDepth() const;
+
+ // do not use, will go away
+ virtual bool getFormat( int para, int index, QFont *font, QColor *color, VerticalAlignment *verticalAlignment );
+ // do not use, will go away
+ virtual bool getParagraphFormat( int para, QFont *font, QColor *color,
+ VerticalAlignment *verticalAlignment, int *alignment,
+ QStyleSheetItem::DisplayMode *displayMode,
+ QStyleSheetItem::ListStyle *listStyle,
+ int *listDepth );
+
+
+ bool isOverwriteMode() const { return overWrite; }
+ QColor paragraphBackgroundColor( int para ) const;
+
+ bool isUndoRedoEnabled() const;
+ bool eventFilter( QObject *o, QEvent *e );
+ bool tabChangesFocus() const;
+
+ void setAutoFormatting( uint features );
+ uint autoFormatting() const;
+ QSyntaxHighlighter *syntaxHighlighter() const;
+
+public slots:
+ void setEnabled( bool );
+#ifndef QT_NO_MIME
+ virtual void setMimeSourceFactory( QMimeSourceFactory* factory );
+#endif
+ virtual void setStyleSheet( QStyleSheet* styleSheet );
+ virtual void scrollToAnchor( const QString& name );
+ virtual void setPaper( const QBrush& pap );
+ virtual void setLinkUnderline( bool );
+
+ virtual void setWordWrap( WordWrap mode );
+ virtual void setWrapColumnOrWidth( int );
+ virtual void setWrapPolicy( WrapPolicy policy );
+
+ virtual void copy();
+ virtual void append( const QString& text );
+
+ void setText( const QString &txt ) { setText( txt, QString::null ); }
+ virtual void setText( const QString &txt, const QString &context );
+ virtual void setTextFormat( TextFormat f );
+
+ virtual void selectAll( bool select = TRUE );
+ virtual void setTabStopWidth( int ts );
+ virtual void zoomIn( int range );
+ virtual void zoomIn() { zoomIn( 1 ); }
+ virtual void zoomOut( int range );
+ virtual void zoomOut() { zoomOut( 1 ); }
+ virtual void zoomTo( int size );
+
+ virtual void sync();
+ virtual void setReadOnly( bool b );
+
+ virtual void undo();
+ virtual void redo();
+ virtual void cut();
+ virtual void paste();
+#ifndef QT_NO_CLIPBOARD
+ virtual void pasteSubType( const QCString &subtype );
+#endif
+ virtual void clear();
+ virtual void del();
+ virtual void indent();
+ virtual void setItalic( bool b );
+ virtual void setBold( bool b );
+ virtual void setUnderline( bool b );
+ virtual void setFamily( const QString &f );
+ virtual void setPointSize( int s );
+ virtual void setColor( const QColor &c );
+ virtual void setFont( const QFont &f );
+ virtual void setVerticalAlignment( VerticalAlignment a );
+ virtual void setAlignment( int a );
+
+ // do not use, will go away
+ virtual void setParagType( QStyleSheetItem::DisplayMode dm, QStyleSheetItem::ListStyle listStyle );
+
+ virtual void setCursorPosition( int parag, int index );
+ virtual void setSelection( int parag_from, int index_from, int parag_to, int index_to, int selNum = 0 );
+ virtual void setSelectionAttributes( int selNum, const QColor &back, bool invertText );
+ virtual void setModified( bool m );
+ virtual void resetFormat();
+ virtual void setUndoDepth( int d );
+ virtual void setFormat( QTextFormat *f, int flags );
+ virtual void ensureCursorVisible();
+ virtual void placeCursor( const QPoint &pos, QTextCursor *c = 0 );
+ virtual void moveCursor( CursorAction action, bool select );
+ virtual void doKeyboardAction( KeyboardAction action );
+ virtual void removeSelectedText( int selNum = 0 );
+ virtual void removeSelection( int selNum = 0 );
+ virtual void setCurrentFont( const QFont &f );
+ virtual void setOverwriteMode( bool b ) { overWrite = b; }
+
+ virtual void scrollToBottom();
+
+ void insert( const QString &text, uint insertionFlags = CheckNewLines | RemoveSelected ); // ## virtual in 4.0
+
+ // obsolete
+ virtual void insert( const QString &text, bool, bool = TRUE, bool = TRUE );
+
+ virtual void insertAt( const QString &text, int para, int index );
+ virtual void removeParagraph( int para );
+ virtual void insertParagraph( const QString &text, int para );
+
+ virtual void setParagraphBackgroundColor( int para, const QColor &bg );
+ virtual void clearParagraphBackground( int para );
+
+ virtual void setUndoRedoEnabled( bool b );
+ void setTabChangesFocus( bool b ); // ### make virtual in 4.0
+
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ void polish();
+ void setMaxLogLines( int numLines );
+ int maxLogLines();
+#endif
+
+signals:
+ void textChanged();
+ void selectionChanged();
+ void copyAvailable( bool );
+ void undoAvailable( bool yes );
+ void redoAvailable( bool yes );
+ void currentFontChanged( const QFont &f );
+ void currentColorChanged( const QColor &c );
+ void currentAlignmentChanged( int a );
+ void currentVerticalAlignmentChanged( VerticalAlignment a );
+ void cursorPositionChanged( QTextCursor *c );
+ void cursorPositionChanged( int para, int pos );
+ void returnPressed();
+ void modificationChanged( bool m );
+ void clicked( int parag, int index );
+ void doubleClicked( int parag, int index );
+
+protected:
+ void repaintChanged();
+ void updateStyles();
+ void drawContents( QPainter *p, int cx, int cy, int cw, int ch );
+ bool event( QEvent *e );
+ void keyPressEvent( QKeyEvent *e );
+ void resizeEvent( QResizeEvent *e );
+ void viewportResizeEvent( QResizeEvent* );
+ void contentsMousePressEvent( QMouseEvent *e );
+ void contentsMouseMoveEvent( QMouseEvent *e );
+ void contentsMouseReleaseEvent( QMouseEvent *e );
+ void contentsMouseDoubleClickEvent( QMouseEvent *e );
+#ifndef QT_NO_WHEELEVENT
+ void contentsWheelEvent( QWheelEvent *e );
+#endif
+ void imStartEvent( QIMEvent * );
+ void imComposeEvent( QIMEvent * );
+ void imEndEvent( QIMEvent * );
+#ifndef QT_NO_DRAGANDDROP
+ void contentsDragEnterEvent( QDragEnterEvent *e );
+ void contentsDragMoveEvent( QDragMoveEvent *e );
+ void contentsDragLeaveEvent( QDragLeaveEvent *e );
+ void contentsDropEvent( QDropEvent *e );
+#endif
+ void contentsContextMenuEvent( QContextMenuEvent *e );
+ bool sendMouseEventToInputContext( QMouseEvent *e );
+ bool focusNextPrevChild( bool next );
+ QTextDocument *document() const;
+ QTextCursor *textCursor() const;
+ void setDocument( QTextDocument *doc );
+ virtual QPopupMenu *createPopupMenu( const QPoint& pos );
+ virtual QPopupMenu *createPopupMenu();
+ void drawCursor( bool visible );
+
+ void windowActivationChange( bool );
+
+protected slots:
+ virtual void doChangeInterval();
+ void sliderReleased(); // ### make virtual in 4.0
+#if (QT_VERSION >= 0x040000)
+#error "Some functions need to be changed to virtual for Qt 4.0"
+#endif
+
+private slots:
+ void formatMore();
+ void doResize();
+ void autoScrollTimerDone();
+ void blinkCursor();
+ void setModified();
+ void startDrag();
+ void documentWidthChanged( int w );
+ void clipboardChanged();
+
+private:
+ struct Q_EXPORT UndoRedoInfo {
+ enum Type { Invalid, Insert, Delete, Backspace, Return, RemoveSelected, Format, Style, IME };
+
+ UndoRedoInfo( QTextDocument *dc );
+ ~UndoRedoInfo();
+ void clear();
+ bool valid() const;
+
+ QUndoRedoInfoPrivate *d;
+ int id;
+ int index;
+ int eid;
+ int eindex;
+ QTextFormat *format;
+ int flags;
+ Type type;
+ QTextDocument *doc;
+ QByteArray styleInformation;
+ };
+
+private:
+ void updateCursor( const QPoint & pos );
+ void handleMouseMove( const QPoint& pos );
+ void drawContents( QPainter * );
+ virtual bool linksEnabled() const { return FALSE; }
+ void init();
+ void checkUndoRedoInfo( UndoRedoInfo::Type t );
+ void updateCurrentFormat();
+ bool handleReadOnlyKeyEvent( QKeyEvent *e );
+ void makeParagVisible( QTextParagraph *p );
+ void normalCopy();
+ void copyToClipboard();
+#ifndef QT_NO_MIME
+ QCString pickSpecial(QMimeSource* ms, bool always_ask, const QPoint&);
+ QTextDrag *dragObject( QWidget *parent = 0 ) const;
+#endif
+#ifndef QT_NO_MIMECLIPBOARD
+ void pasteSpecial(const QPoint&);
+#endif
+ void setFontInternal( const QFont &f );
+
+ virtual void emitHighlighted( const QString & ) {}
+ virtual void emitLinkClicked( const QString & ) {}
+
+ void readFormats( QTextCursor &c1, QTextCursor &c2, QTextString &text, bool fillStyles = FALSE );
+ void clearUndoRedo();
+ void paintDocument( bool drawAll, QPainter *p, int cx = -1, int cy = -1, int cw = -1, int ch = -1 );
+ void moveCursor( CursorAction action );
+ void ensureFormatted( QTextParagraph *p );
+ void placeCursor( const QPoint &pos, QTextCursor *c, bool link );
+ void updateMicroFocusHint();
+
+#ifdef QT_TEXTEDIT_OPTIMIZATION
+ bool checkOptimMode();
+ QString optimText() const;
+ void optimSetText( const QString &str );
+ void optimAppend( const QString &str );
+ void optimInsert( const QString &str, int line, int index );
+ void optimDrawContents( QPainter * p, int cx, int cy, int cw, int ch );
+ void optimMousePressEvent( QMouseEvent * e );
+ void optimMouseReleaseEvent( QMouseEvent * e );
+ void optimMouseMoveEvent( QMouseEvent * e );
+ int optimCharIndex( const QString &str, int mx ) const;
+ void optimSelectAll();
+ void optimRemoveSelection();
+ void optimSetSelection( int startLine, int startIdx, int endLine,
+ int endIdx );
+ bool optimHasSelection() const;
+ QString optimSelectedText() const;
+ bool optimFind( const QString & str, bool, bool, bool, int *, int * );
+ void optimParseTags( QString * str, int lineNo = -1, int indexOffset = 0 );
+ QTextEditOptimPrivate::Tag * optimPreviousLeftTag( int line );
+ void optimSetTextFormat( QTextDocument *, QTextCursor *, QTextFormat * f,
+ int, int, QTextEditOptimPrivate::Tag * t );
+ QTextEditOptimPrivate::Tag * optimAppendTag( int index, const QString & tag );
+ QTextEditOptimPrivate::Tag * optimInsertTag( int line, int index, const QString & tag );
+ void optimCheckLimit( const QString& str );
+ bool optimHasBoldMetrics( int line );
+
+private slots:
+ void optimDoAutoScroll();
+#endif // QT_TEXTEDIT_OPTIMIZATION
+
+private:
+#ifndef QT_NO_CLIPBOARD
+ void pasteSubType( const QCString &subtype, QMimeSource *m );
+#endif
+
+private:
+ QTextDocument *doc;
+ QTextCursor *cursor;
+ QTimer *formatTimer, *scrollTimer, *changeIntervalTimer, *blinkTimer, *dragStartTimer;
+ QTextParagraph *lastFormatted;
+ int interval;
+ UndoRedoInfo undoRedoInfo;
+ QTextFormat *currentFormat;
+ int currentAlignment;
+ QPoint oldMousePos, mousePos;
+ QPoint dragStartPos;
+ QString onLink;
+ WordWrap wrapMode;
+ WrapPolicy wPolicy;
+ int wrapWidth;
+ QString pressedLink;
+ QTextEditPrivate *d;
+ bool inDoubleClick : 1;
+ bool mousePressed : 1;
+ bool cursorVisible : 1;
+ bool blinkCursorVisible : 1;
+ bool readOnly : 1;
+ bool modified : 1;
+ bool mightStartDrag : 1;
+ bool inDnD : 1;
+ bool readonly : 1;
+ bool undoEnabled : 1;
+ bool overWrite : 1;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QTextEdit( const QTextEdit & );
+ QTextEdit &operator=( const QTextEdit & );
+#endif
+};
+
+inline QTextDocument *QTextEdit::document() const
+{
+ return doc;
+}
+
+inline QTextCursor *QTextEdit::textCursor() const
+{
+ return cursor;
+}
+
+inline void QTextEdit::setCurrentFont( const QFont &f )
+{
+ QTextEdit::setFontInternal( f );
+}
+
+#endif //QT_NO_TEXTEDIT
+#endif //QTEXTVIEW_H
diff --git a/src/widgets/qtextview.cpp b/src/widgets/qtextview.cpp
new file mode 100644
index 0000000..67276e8
--- /dev/null
+++ b/src/widgets/qtextview.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Implementation of the QTextView class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtextview.h"
+
+#ifndef QT_NO_TEXTVIEW
+
+/*! \class QTextView
+ \brief The QTextView class provides a rich-text viewer.
+
+ \obsolete
+
+ This class wraps a read-only \l QTextEdit.
+ Use a \l QTextEdit instead, and call setReadOnly(TRUE)
+ to disable editing.
+*/
+
+/*! \reimp */
+
+QTextView::QTextView( const QString& text, const QString& context,
+ QWidget *parent, const char *name )
+ : QTextEdit( text, context, parent, name )
+{
+ setReadOnly( TRUE );
+}
+
+/*! \reimp */
+
+QTextView::QTextView( QWidget *parent, const char *name )
+ : QTextEdit( parent, name )
+{
+ setReadOnly( TRUE );
+}
+
+/*! \reimp */
+
+QTextView::~QTextView()
+{
+}
+
+/*!
+ \property QTextView::undoDepth
+ \brief the number of undoable steps
+*/
+
+/*!
+ \property QTextView::overwriteMode
+ \brief whether new text overwrites or pushes aside existing text
+*/
+
+/*!
+ \property QTextView::modified
+ \brief Whether the text view's contents have been modified.
+*/
+
+/*!
+ \property QTextView::readOnly
+ \brief Whether the text view's contents are read only.
+*/
+
+/*!
+ \property QTextView::undoRedoEnabled
+ \brief Whether undo and redo are enabled.
+*/
+
+#endif
diff --git a/src/widgets/qtextview.h b/src/widgets/qtextview.h
new file mode 100644
index 0000000..b17874d
--- /dev/null
+++ b/src/widgets/qtextview.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Definition of the QTextView class
+**
+** Created : 990101
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTEXTVIEW_H
+#define QTEXTVIEW_H
+
+#ifndef QT_H
+#include "qtextedit.h"
+#endif // QT_H
+
+#ifndef QT_NO_TEXTVIEW
+
+class Q_EXPORT QTextView : public QTextEdit
+{
+ Q_OBJECT
+ Q_OVERRIDE( int undoDepth DESIGNABLE false SCRIPTABLE false )
+ Q_OVERRIDE( bool overwriteMode DESIGNABLE false SCRIPTABLE false )
+ Q_OVERRIDE( bool modified SCRIPTABLE false)
+ Q_OVERRIDE( bool readOnly DESIGNABLE false SCRIPTABLE false )
+ Q_OVERRIDE( bool undoRedoEnabled DESIGNABLE false SCRIPTABLE false )
+
+public:
+ QTextView( const QString& text, const QString& context = QString::null,
+ QWidget* parent=0, const char* name=0);
+ QTextView( QWidget* parent=0, const char* name=0 );
+
+ virtual ~QTextView();
+
+private:
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ QTextView( const QTextView & );
+ QTextView &operator=( const QTextView & );
+#endif
+};
+
+#endif //QT_NO_TEXTVIEW
+#endif //QTEXTVIEW_H
diff --git a/src/widgets/qtitlebar.cpp b/src/widgets/qtitlebar.cpp
new file mode 100644
index 0000000..c81ea7d
--- /dev/null
+++ b/src/widgets/qtitlebar.cpp
@@ -0,0 +1,671 @@
+/****************************************************************************
+**
+** Implementation of some Qt private functions.
+**
+** Created : 001101
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qplatformdefs.h"
+
+#include "qtitlebar_p.h"
+
+#ifndef QT_NO_TITLEBAR
+
+#include <qcursor.h>
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qdatetime.h"
+#include "private/qapplication_p.h"
+#include "qtooltip.h"
+#include "qimage.h"
+#include "qtimer.h"
+#include "qpainter.h"
+#include "qstyle.h"
+#include "private/qinternal_p.h"
+#ifndef QT_NO_WORKSPACE
+#include "qworkspace.h"
+#endif
+#if defined(Q_WS_WIN)
+#include "qt_windows.h"
+#endif
+
+#ifndef QT_NO_TOOLTIP
+class QTitleBarTip : public QToolTip
+{
+public:
+ QTitleBarTip( QWidget * parent ) : QToolTip( parent ) { }
+
+ void maybeTip( const QPoint &pos )
+ {
+ if ( !::qt_cast<QTitleBar*>(parentWidget()) )
+ return;
+ QTitleBar *t = (QTitleBar *)parentWidget();
+
+ QString tipstring;
+ QStyle::SubControl ctrl = t->style().querySubControl(QStyle::CC_TitleBar, t, pos);
+ QSize controlSize = t->style().querySubControlMetrics(QStyle::CC_TitleBar, t, ctrl).size();
+
+ QWidget *window = t->window();
+ if ( window ) {
+ switch(ctrl) {
+ case QStyle::SC_TitleBarSysMenu:
+ if ( t->testWFlags( WStyle_SysMenu ) )
+ tipstring = QTitleBar::tr( "System Menu" );
+ break;
+
+ case QStyle::SC_TitleBarShadeButton:
+ if ( t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_MinMax ) )
+ tipstring = QTitleBar::tr( "Shade" );
+ break;
+
+ case QStyle::SC_TitleBarUnshadeButton:
+ if ( t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_MinMax ) )
+ tipstring = QTitleBar::tr( "Unshade" );
+ break;
+
+ case QStyle::SC_TitleBarNormalButton:
+ case QStyle::SC_TitleBarMinButton:
+ if ( !t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_Minimize ) ) {
+ if( window->isMinimized() )
+ tipstring = QTitleBar::tr( "Normalize" );
+ else
+ tipstring = QTitleBar::tr( "Minimize" );
+ }
+ break;
+
+ case QStyle::SC_TitleBarMaxButton:
+ if ( !t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_Maximize ) )
+ tipstring = QTitleBar::tr( "Maximize" );
+ break;
+
+ case QStyle::SC_TitleBarCloseButton:
+ if ( t->testWFlags( WStyle_SysMenu ) )
+ tipstring = QTitleBar::tr( "Close" );
+ break;
+
+ default:
+ break;
+ }
+ }
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ if ( tipstring.isEmpty() ) {
+ if ( t->visibleText() != t->caption() )
+ tipstring = t->caption();
+ }
+#endif
+ if(!tipstring.isEmpty())
+ tip( QRect(pos, controlSize), tipstring );
+ }
+};
+#endif
+
+class QTitleBarPrivate
+{
+public:
+ QTitleBarPrivate()
+ : toolTip( 0 ), act( 0 ), window( 0 ), movable( 1 ), pressed( 0 ), autoraise(0)
+ {
+ }
+
+ QStyle::SCFlags buttonDown;
+ QPoint moveOffset;
+ QToolTip *toolTip;
+ bool act :1;
+ QWidget* window;
+ bool movable :1;
+ bool pressed :1;
+ bool autoraise :1;
+ QString cuttext;
+#ifdef QT_NO_WIDGET_TOPEXTRA
+ QString cap;
+#endif
+};
+
+QTitleBar::QTitleBar(QWidget* w, QWidget* parent, const char* name)
+ : QWidget( parent, name, WStyle_Customize | WStyle_NoBorder | WNoAutoErase )
+{
+ d = new QTitleBarPrivate();
+
+#ifndef QT_NO_TOOLTIP
+ d->toolTip = new QTitleBarTip( this );
+#endif
+ d->window = w;
+ d->buttonDown = QStyle::SC_None;
+ d->act = 0;
+ if ( w ) {
+ setWFlags( ((QTitleBar*)w)->getWFlags() | WNoAutoErase );
+ if ( w->minimumSize() == w->maximumSize() )
+ clearWFlags( WStyle_Maximize );
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ setCaption( w->caption() );
+#endif
+ } else {
+ setWFlags( WStyle_Customize | WNoAutoErase );
+ }
+
+ readColors();
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
+ setMouseTracking(TRUE);
+}
+
+QTitleBar::~QTitleBar()
+{
+#ifndef QT_NO_TOOLTIP
+ delete d->toolTip;
+#endif
+
+ delete d;
+ d = 0;
+}
+
+#ifdef Q_WS_WIN
+extern QRgb qt_colorref2qrgb(COLORREF col);
+#endif
+
+void QTitleBar::readColors()
+{
+ QPalette pal = 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, QColorGroup::Highlight, qt_colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)) );
+ pal.setColor( QPalette::Inactive, QColorGroup::Highlight, qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)) );
+ pal.setColor( QPalette::Active, QColorGroup::HighlightedText, qt_colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)) );
+ pal.setColor( QPalette::Inactive, QColorGroup::HighlightedText, qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)) );
+ if ( qt_winver != Qt::WV_95 && qt_winver != WV_NT ) {
+ colorsInitialized = TRUE;
+ BOOL gradient;
+ QT_WA( {
+ SystemParametersInfo( SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0 );
+ } , {
+ SystemParametersInfoA( SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0 );
+ } );
+ if ( gradient ) {
+ pal.setColor( QPalette::Active, QColorGroup::Base, qt_colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)) );
+ pal.setColor( QPalette::Inactive, QColorGroup::Base, qt_colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)) );
+ } else {
+ pal.setColor( QPalette::Active, QColorGroup::Base, palette().active().highlight() );
+ pal.setColor( QPalette::Inactive, QColorGroup::Base, palette().inactive().highlight() );
+ }
+ }
+ }
+#endif // Q_WS_WIN
+ if ( !colorsInitialized ) {
+ pal.setColor( QPalette::Active, QColorGroup::Highlight, palette().active().highlight() );
+ pal.setColor( QPalette::Active, QColorGroup::Base, palette().active().highlight() );
+ pal.setColor( QPalette::Inactive, QColorGroup::Highlight, palette().inactive().dark() );
+ pal.setColor( QPalette::Inactive, QColorGroup::Base, palette().inactive().dark() );
+ pal.setColor( QPalette::Inactive, QColorGroup::HighlightedText, palette().inactive().background() );
+ }
+
+ setPalette( pal );
+ setActive( d->act );
+}
+
+void QTitleBar::mousePressEvent( QMouseEvent * e)
+{
+ if ( !d->act )
+ emit doActivate();
+ if ( e->button() == LeftButton ) {
+ d->pressed = TRUE;
+ QStyle::SCFlags ctrl = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
+ switch (ctrl) {
+ case QStyle::SC_TitleBarSysMenu:
+ if ( testWFlags( WStyle_SysMenu ) && !testWFlags( WStyle_Tool ) ) {
+ d->buttonDown = QStyle::SC_None;
+ static QTime* t = 0;
+ static QTitleBar* tc = 0;
+ if ( !t )
+ t = new QTime;
+ 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 ( testWFlags( WStyle_MinMax ) && testWFlags( WStyle_Tool ) )
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarNormalButton:
+ if( testWFlags( WStyle_Minimize ) && !testWFlags( WStyle_Tool ) )
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarMinButton:
+ if( testWFlags( WStyle_Minimize ) && !testWFlags( WStyle_Tool ) )
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarMaxButton:
+ if ( testWFlags( WStyle_Maximize ) && !testWFlags( WStyle_Tool ) )
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarCloseButton:
+ if ( testWFlags( WStyle_SysMenu ) )
+ d->buttonDown = ctrl;
+ break;
+
+ case QStyle::SC_TitleBarLabel:
+ d->buttonDown = ctrl;
+ d->moveOffset = mapToParent( e->pos() );
+ break;
+
+ default:
+ break;
+ }
+ repaint( FALSE );
+ } else {
+ d->pressed = FALSE;
+ }
+}
+
+void QTitleBar::contextMenuEvent( QContextMenuEvent *e )
+{
+ QStyle::SCFlags ctrl = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
+ if( ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu )
+ emit popupOperationMenu(e->globalPos());
+ else
+ e->ignore();
+}
+
+void QTitleBar::mouseReleaseEvent( QMouseEvent * e)
+{
+ if ( e->button() == LeftButton && d->pressed) {
+ QStyle::SCFlags ctrl = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
+
+ if (ctrl == d->buttonDown) {
+ switch(ctrl) {
+ case QStyle::SC_TitleBarShadeButton:
+ case QStyle::SC_TitleBarUnshadeButton:
+ if( testWFlags( WStyle_MinMax ) && testWFlags( WStyle_Tool ) )
+ emit doShade();
+ break;
+
+ case QStyle::SC_TitleBarNormalButton:
+ if( testWFlags( WStyle_MinMax ) && !testWFlags( WStyle_Tool ) )
+ emit doNormal();
+ break;
+
+ case QStyle::SC_TitleBarMinButton:
+ if( testWFlags( WStyle_Minimize ) && !testWFlags( WStyle_Tool ) )
+ emit doMinimize();
+ break;
+
+ case QStyle::SC_TitleBarMaxButton:
+ if( d->window && testWFlags( WStyle_Maximize ) && !testWFlags( WStyle_Tool ) ) {
+ if(d->window->isMaximized())
+ emit doNormal();
+ else
+ emit doMaximize();
+ }
+ break;
+
+ case QStyle::SC_TitleBarCloseButton:
+ if( testWFlags( WStyle_SysMenu ) ) {
+ d->buttonDown = QStyle::SC_None;
+ repaint(FALSE);
+ emit doClose();
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ d->buttonDown = QStyle::SC_None;
+ repaint(FALSE);
+ d->pressed = FALSE;
+ }
+}
+
+void QTitleBar::mouseMoveEvent( QMouseEvent * e)
+{
+ switch (d->buttonDown) {
+ case QStyle::SC_None:
+ if(autoRaise())
+ repaint( FALSE );
+ break;
+ case QStyle::SC_TitleBarSysMenu:
+ break;
+ case QStyle::SC_TitleBarShadeButton:
+ case QStyle::SC_TitleBarUnshadeButton:
+ case QStyle::SC_TitleBarNormalButton:
+ case QStyle::SC_TitleBarMinButton:
+ case QStyle::SC_TitleBarMaxButton:
+ case QStyle::SC_TitleBarCloseButton:
+ {
+ QStyle::SCFlags last_ctrl = d->buttonDown;
+ d->buttonDown = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
+ if( d->buttonDown != last_ctrl)
+ d->buttonDown = QStyle::SC_None;
+ repaint(FALSE);
+ d->buttonDown = last_ctrl;
+ }
+ break;
+
+ case QStyle::SC_TitleBarLabel:
+ if ( d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed ) {
+ if ( (d->moveOffset - mapToParent( e->pos() ) ).manhattanLength() >= 4 ) {
+ QPoint p = mapFromGlobal(e->globalPos());
+#ifndef QT_NO_WORKSPACE
+ if(d->window && d->window->parentWidget()->inherits("QWorkspaceChild")) {
+ QWorkspace *workspace = ::qt_cast<QWorkspace*>(d->window->parentWidget()->parentWidget());
+ if(workspace) {
+ 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();
+ }
+ }
+ }
+#endif
+ QPoint pp = p - d->moveOffset;
+ if (!parentWidget()->isMaximized())
+ parentWidget()->move( pp );
+ }
+ } else {
+ QStyle::SCFlags last_ctrl = d->buttonDown;
+ d->buttonDown = QStyle::SC_None;
+ if( d->buttonDown != last_ctrl)
+ repaint(FALSE);
+ }
+ break;
+ }
+}
+
+void QTitleBar::resizeEvent( QResizeEvent *r)
+{
+ QWidget::resizeEvent(r);
+ cutText();
+}
+
+void QTitleBar::paintEvent(QPaintEvent *)
+{
+ QStyle::SCFlags ctrls = QStyle::SC_TitleBarLabel;
+ if ( testWFlags( WStyle_SysMenu) ) {
+ if ( testWFlags( WStyle_Tool ) ) {
+ ctrls |= QStyle::SC_TitleBarCloseButton;
+ if ( d->window && testWFlags( WStyle_MinMax ) ) {
+ if ( d->window->isMinimized() )
+ ctrls |= QStyle::SC_TitleBarUnshadeButton;
+ else
+ ctrls |= QStyle::SC_TitleBarShadeButton;
+ }
+ } else {
+ ctrls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
+ if ( d->window && testWFlags( WStyle_Minimize ) ) {
+ if( d->window && d->window->isMinimized() )
+ ctrls |= QStyle::SC_TitleBarNormalButton;
+ else
+ ctrls |= QStyle::SC_TitleBarMinButton;
+ }
+ if ( d->window && testWFlags( WStyle_Maximize ) && !d->window->isMaximized() )
+ ctrls |= QStyle::SC_TitleBarMaxButton;
+ }
+ }
+
+ QStyle::SCFlags under_mouse = QStyle::SC_None;
+ if( autoRaise() && hasMouse() ) {
+ QPoint p(mapFromGlobal(QCursor::pos()));
+ under_mouse = style().querySubControl(QStyle::CC_TitleBar, this, p);
+ ctrls ^= under_mouse;
+ }
+
+ QSharedDoubleBuffer buffer( this, rect() );
+ style().drawComplexControl(QStyle::CC_TitleBar, buffer.painter(), this, rect(),
+ colorGroup(),
+ isEnabled() ? QStyle::Style_Enabled :
+ QStyle::Style_Default, ctrls, d->buttonDown);
+ if(under_mouse != QStyle::SC_None)
+ style().drawComplexControl(QStyle::CC_TitleBar, buffer.painter(), this, rect(),
+ colorGroup(),
+ QStyle::Style_MouseOver |
+ (isEnabled() ? QStyle::Style_Enabled : 0),
+ under_mouse, d->buttonDown);
+}
+
+void QTitleBar::mouseDoubleClickEvent( QMouseEvent *e )
+{
+ if ( e->button() != LeftButton )
+ return;
+
+ switch(style().querySubControl(QStyle::CC_TitleBar, this, e->pos())) {
+ case QStyle::SC_TitleBarLabel:
+ emit doubleClicked();
+ break;
+
+ case QStyle::SC_TitleBarSysMenu:
+ if ( testWFlags( WStyle_SysMenu ) )
+ emit doClose();
+ break;
+
+ default:
+ break;
+ }
+}
+
+#ifdef QT_NO_WIDGET_TOPEXTRA
+// We provide one, since titlebar is useless otherwise.
+QString QTitleBar::caption() const
+{
+ return d->cap;
+}
+#endif
+
+void QTitleBar::cutText()
+{
+ QFontMetrics fm( font() );
+
+ int maxw = style().querySubControlMetrics(QStyle::CC_TitleBar, this,
+ QStyle::SC_TitleBarLabel).width();
+ if ( !d->window )
+ maxw = width() - 20;
+ const QString txt = caption();
+ d->cuttext = txt;
+ if ( fm.width( txt + "m" ) > maxw ) {
+ int i = txt.length();
+ int dotlength = fm.width( "..." );
+ while ( i>0 && fm.width(txt.left( i )) + dotlength > maxw )
+ i--;
+ if(i != (int)txt.length())
+ d->cuttext = txt.left( i ) + "...";
+ }
+}
+
+void QTitleBar::setCaption( const QString& title )
+{
+ if( caption() == title)
+ return;
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ QWidget::setCaption( title );
+#else
+ d->cap = title;
+#endif
+ cutText();
+
+ update();
+}
+
+
+void QTitleBar::setIcon( const QPixmap& icon )
+{
+#ifndef QT_NO_WIDGET_TOPEXTRA
+#ifndef QT_NO_IMAGE_SMOOTHSCALE
+ QRect menur = style().querySubControlMetrics(QStyle::CC_TitleBar, this,
+ QStyle::SC_TitleBarSysMenu);
+
+ QPixmap theIcon;
+ if (icon.width() > menur.width()) {
+ // try to keep something close to the same aspect
+ int aspect = (icon.height() * 100) / icon.width();
+ int newh = (aspect * menur.width()) / 100;
+ theIcon.convertFromImage( icon.convertToImage().smoothScale(menur.width(),
+ newh) );
+ } else if (icon.height() > menur.height()) {
+ // try to keep something close to the same aspect
+ int aspect = (icon.width() * 100) / icon.height();
+ int neww = (aspect * menur.height()) / 100;
+ theIcon.convertFromImage( icon.convertToImage().smoothScale(neww,
+ menur.height()) );
+ } else
+ theIcon = icon;
+
+ QWidget::setIcon( theIcon );
+#else
+ QWidget::setIcon( icon );
+#endif
+
+ update();
+#endif
+}
+
+void QTitleBar::leaveEvent( QEvent * )
+{
+ if(autoRaise() && !d->pressed)
+ repaint( FALSE );
+}
+
+void QTitleBar::enterEvent( QEvent * )
+{
+ if(autoRaise() && !d->pressed)
+ repaint( FALSE );
+ QEvent e( QEvent::Leave );
+ QApplication::sendEvent( parentWidget(), &e );
+}
+
+void QTitleBar::setActive( bool active )
+{
+ if ( d->act == active )
+ return ;
+
+ d->act = active;
+ update();
+}
+
+bool QTitleBar::isActive() const
+{
+ return d->act;
+}
+
+bool QTitleBar::usesActiveColor() const
+{
+ return ( isActive() && isActiveWindow() ) ||
+ ( !window() && topLevelWidget()->isActiveWindow() );
+}
+
+QString QTitleBar::visibleText() const
+{
+ return d->cuttext;
+}
+
+QWidget *QTitleBar::window() const
+{
+ return d->window;
+}
+
+bool QTitleBar::event( QEvent* e )
+{
+ if ( e->type() == QEvent::ApplicationPaletteChange ) {
+ readColors();
+ return TRUE;
+ } else if ( e->type() == QEvent::WindowActivate ) {
+ setActive( d->act );
+ } else if ( e->type() == QEvent::WindowDeactivate ) {
+ bool wasActive = d->act;
+ setActive( FALSE );
+ d->act = wasActive;
+ }
+
+ return QWidget::event( e );
+}
+
+void QTitleBar::setMovable(bool b)
+{
+ d->movable = b;
+}
+
+bool QTitleBar::isMovable() const
+{
+ return d->movable;
+}
+
+void QTitleBar::setAutoRaise(bool b)
+{
+ d->autoraise = b;
+}
+
+bool QTitleBar::autoRaise() const
+{
+ return d->autoraise;
+}
+
+QSize QTitleBar::sizeHint() const
+{
+ constPolish();
+ QRect menur = style().querySubControlMetrics(QStyle::CC_TitleBar, this,
+ QStyle::SC_TitleBarSysMenu);
+ return QSize( menur.width(), style().pixelMetric( QStyle::PM_TitleBarHeight, this ) );
+}
+
+#endif //QT_NO_TITLEBAR
diff --git a/src/widgets/qtitlebar_p.h b/src/widgets/qtitlebar_p.h
new file mode 100644
index 0000000..edd8fe2
--- /dev/null
+++ b/src/widgets/qtitlebar_p.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Definition of some Qt private functions.
+**
+** Created : 000101
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTITLEBAR_P_H
+#define QTITLEBAR_P_H
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qworkspace.cpp and qdockwindow.cpp. This header file may change
+// from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+
+#ifndef QT_H
+#include "qbutton.h"
+#include "qlabel.h"
+#endif // QT_H
+
+#if !defined(QT_NO_TITLEBAR)
+
+class QToolTip;
+class QTitleBarPrivate;
+class QPixmap;
+
+class Q_EXPORT QTitleBar : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY( bool autoRaise READ autoRaise WRITE setAutoRaise )
+ Q_PROPERTY( bool movable READ isMovable WRITE setMovable )
+
+public:
+ QTitleBar (QWidget* w, QWidget* parent, const char* name=0);
+ ~QTitleBar();
+
+ bool isActive() const;
+ bool usesActiveColor() const;
+ virtual QString visibleText() const;
+
+ bool isMovable() const;
+ void setMovable(bool);
+
+ bool autoRaise() const;
+ void setAutoRaise(bool);
+
+ QWidget *window() const;
+
+ QSize sizeHint() const;
+
+#ifdef QT_NO_WIDGET_TOPEXTRA
+ // We provide one, since titlebar is useless otherwise.
+ QString caption() const;
+#endif
+
+public slots:
+ void setActive( bool );
+ void setCaption( const QString& title );
+ void setIcon( const QPixmap& icon );
+
+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 *);
+ void resizeEvent( QResizeEvent *);
+ void contextMenuEvent( QContextMenuEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void enterEvent( QEvent *e );
+ void leaveEvent( QEvent *e );
+ void paintEvent( QPaintEvent *p );
+
+ virtual void cutText();
+
+private:
+ void readColors();
+
+ QTitleBarPrivate *d;
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ QTitleBar( const QTitleBar & );
+ QTitleBar &operator=( const QTitleBar & );
+#endif
+};
+
+#endif
+#endif //QTITLEBAR_P_H
diff --git a/src/widgets/qtoolbar.cpp b/src/widgets/qtoolbar.cpp
new file mode 100644
index 0000000..22d4d5d
--- /dev/null
+++ b/src/widgets/qtoolbar.cpp
@@ -0,0 +1,815 @@
+/****************************************************************************
+**
+** Implementation of QToolBar class
+**
+** Created : 980315
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtoolbar.h"
+#ifndef QT_NO_TOOLBAR
+
+#include "qmainwindow.h"
+#include "qtooltip.h"
+#include "qcursor.h"
+#include "qlayout.h"
+#include "qframe.h"
+#include "qobjectlist.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qtoolbutton.h"
+#include "qpopupmenu.h"
+#include "qcombobox.h"
+#include "qtimer.h"
+#include "qwidgetlist.h"
+#include "qstyle.h"
+
+static const char * const arrow_v_xpm[] = {
+ "7 9 3 1",
+ " c None",
+ ". c #000000",
+ "+ c none",
+ ".+++++.",
+ "..+++..",
+ "+..+..+",
+ "++...++",
+ ".++.++.",
+ "..+++..",
+ "+..+..+",
+ "++...++",
+ "+++.+++"};
+
+static const char * const arrow_h_xpm[] = {
+ "9 7 3 1",
+ " c None",
+ ". c #000000",
+ "+ c none",
+ "..++..+++",
+ "+..++..++",
+ "++..++..+",
+ "+++..++..",
+ "++..++..+",
+ "+..++..++",
+ "..++..+++"};
+
+class QToolBarExtensionWidget;
+
+class QToolBarPrivate
+{
+public:
+ QToolBarPrivate() : moving( FALSE ) {
+ }
+
+ bool moving;
+ QToolBarExtensionWidget *extension;
+ QPopupMenu *extensionPopup;
+};
+
+
+class QToolBarSeparator : public QWidget
+{
+ Q_OBJECT
+public:
+ QToolBarSeparator( Orientation, QToolBar *parent, const char* name=0 );
+
+ QSize sizeHint() const;
+ Orientation orientation() const { return orient; }
+public slots:
+ void setOrientation( Orientation );
+protected:
+ void styleChange( QStyle& );
+ void paintEvent( QPaintEvent * );
+
+private:
+ Orientation orient;
+};
+
+class QToolBarExtensionWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QToolBarExtensionWidget( QWidget *w );
+ void setOrientation( Orientation o );
+ QToolButton *button() const { return tb; }
+
+protected:
+ void resizeEvent( QResizeEvent *e ) {
+ QWidget::resizeEvent( e );
+ layOut();
+ }
+
+private:
+ void layOut();
+ QToolButton *tb;
+ Orientation orient;
+
+};
+
+QToolBarExtensionWidget::QToolBarExtensionWidget( QWidget *w )
+ : QWidget( w, "qt_dockwidget_internal" )
+{
+ tb = new QToolButton( this, "qt_toolbar_ext_button" );
+ tb->setAutoRaise( TRUE );
+ setOrientation( Horizontal );
+}
+
+void QToolBarExtensionWidget::setOrientation( Orientation o )
+{
+ orient = o;
+ if ( orient == Horizontal )
+ tb->setPixmap( QPixmap( (const char **)arrow_h_xpm ) );
+ else
+ tb->setPixmap( QPixmap( (const char **)arrow_v_xpm ) );
+ layOut();
+}
+
+void QToolBarExtensionWidget::layOut()
+{
+ tb->setGeometry( 2, 2, width() - 4, height() - 4 );
+}
+
+QToolBarSeparator::QToolBarSeparator(Orientation o , QToolBar *parent,
+ const char* name )
+ : QWidget( parent, name )
+{
+ connect( parent, SIGNAL(orientationChanged(Orientation)),
+ this, SLOT(setOrientation(Orientation)) );
+ setOrientation( o );
+ setBackgroundMode( parent->backgroundMode() );
+ setBackgroundOrigin( ParentOrigin );
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+}
+
+
+
+void QToolBarSeparator::setOrientation( Orientation o )
+{
+ orient = o;
+}
+
+void QToolBarSeparator::styleChange( QStyle& )
+{
+ setOrientation( orient );
+}
+
+QSize QToolBarSeparator::sizeHint() const
+{
+ int extent = style().pixelMetric( QStyle::PM_DockWindowSeparatorExtent,
+ this );
+ if ( orient == Horizontal )
+ return QSize( extent, 0 );
+ else
+ return QSize( 0, extent );
+}
+
+void QToolBarSeparator::paintEvent( QPaintEvent * )
+{
+ QPainter p( this );
+ QStyle::SFlags flags = QStyle::Style_Default;
+
+ if ( orientation() == Horizontal )
+ flags |= QStyle::Style_Horizontal;
+
+ style().drawPrimitive( QStyle::PE_DockWindowSeparator, &p, rect(),
+ colorGroup(), flags );
+}
+
+#include "qtoolbar.moc"
+
+
+/*!
+ \class QToolBar qtoolbar.h
+ \brief The QToolBar class provides a movable panel containing
+ widgets such as tool buttons.
+
+ \ingroup application
+ \mainclass
+
+ A toolbar is a panel that contains a set of controls, usually
+ represented by small icons. It's purpose is to provide quick
+ access to frequently used commands or options. Within a
+ QMainWindow the user can drag toolbars within and between the
+ \link QDockArea dock areas\endlink. Toolbars can also be dragged
+ out of any dock area to float freely as top-level windows.
+
+ QToolBar is a specialization of QDockWindow, and so provides all
+ the functionality of a QDockWindow.
+
+ To use QToolBar you simply create a QToolBar as a child of a
+ QMainWindow, create a number of QToolButton widgets (or other
+ widgets) in left to right (or top to bottom) order and call
+ addSeparator() when you want a separator. When a toolbar is
+ floated the caption used is the label given in the constructor
+ call. This can be changed with setLabel().
+
+ \quotefile action/application.cpp
+ \skipto new QToolBar
+ \printuntil fileSaveAction
+
+ This extract from the \l application/application.cpp example shows
+ the creation of a new toolbar as a child of a QMainWindow and
+ adding two QActions.
+
+ You may use most widgets within a toolbar, with QToolButton and
+ QComboBox being the most common.
+
+ If you create a new widget on an already visible QToolBar, this
+ widget will automatically become visible without needing a show()
+ call. (This differs from every other Qt widget container. We
+ recommend calling show() anyway since we hope to fix this anomaly
+ in a future release.)
+
+ QToolBars, like QDockWindows, are located in \l{QDockArea}s or
+ float as top-level windows. QMainWindow provides four QDockAreas
+ (top, left, right and bottom). When you create a new toolbar (as
+ in the example above) as a child of a QMainWindow the toolbar will
+ be added to the top dock area. You can move it to another dock
+ area (or float it) by calling QMainWindow::moveDockWindow(). QDock
+ areas lay out their windows in \link qdockarea.html#lines
+ Lines\endlink.
+
+ If the main window is resized so that the area occupied by the
+ toolbar is too small to show all its widgets a little arrow button
+ (which looks like a right-pointing chevron, '&#187;') will appear
+ at the right or bottom of the toolbar depending on its
+ orientation. Clicking this button pops up a menu that shows the
+ 'overflowing' items. QToolButtons are represented in the menu using
+ their textLabel property, other QButton subclasses are represented
+ using their text property, and QComboBoxes are represented as submenus,
+ with the caption text being used in the submenu item.
+
+ Usually a toolbar will get precisely the space it needs. However,
+ with setHorizontalStretchable(), setVerticalStretchable() or
+ setStretchableWidget() you can tell the main window to expand the
+ toolbar to fill all available space in the specified orientation.
+
+ The toolbar arranges its buttons either horizontally or vertically
+ (see orientation() for details). Generally, QDockArea will set the
+ orientation correctly for you, but you can set it yourself with
+ setOrientation() and track any changes by connecting to the
+ orientationChanged() signal.
+
+ You can use the clear() method to remove all items from a toolbar.
+
+ \img qdockwindow.png Toolbar (dock window)
+ \caption A floating QToolbar (dock window)
+
+ \sa QToolButton QMainWindow \link http://www.iarchitect.com/visual.htm Parts of Isys on Visual Design\endlink \link guibooks.html#fowler GUI Design Handbook: Tool Bar\endlink.
+*/
+
+/*!
+ \fn QToolBar::QToolBar( const QString &label,
+ QMainWindow *, ToolBarDock = Top,
+ bool newLine = FALSE, const char * name = 0 );
+ \obsolete
+*/
+
+/*!
+ Constructs an empty toolbar.
+
+ The toolbar is called \a name and is a child of \a parent and is
+ managed by \a parent. It is initially located in dock area \a dock
+ and is labeled \a label. If \a newLine is TRUE the toolbar will be
+ placed on a new line in the dock area.
+*/
+
+QToolBar::QToolBar( const QString &label,
+ QMainWindow * parent, QMainWindow::ToolBarDock dock,
+ bool newLine, const char * name )
+ : QDockWindow( InDock, parent, name, 0, TRUE )
+{
+ mw = parent;
+ init();
+
+ if ( parent )
+ parent->addToolBar( this, label, dock, newLine );
+}
+
+
+/*!
+ Constructs an empty horizontal toolbar.
+
+ The toolbar is called \a name and is a child of \a parent and is
+ managed by \a mainWindow. The \a label and \a newLine parameters
+ are passed straight to QMainWindow::addDockWindow(). \a name and
+ the widget flags \a f are passed on to the QDockWindow constructor.
+
+ Use this constructor if you want to create torn-off (undocked,
+ floating) toolbars or toolbars in the \link QStatusBar status
+ bar\endlink.
+*/
+
+QToolBar::QToolBar( const QString &label, QMainWindow * mainWindow,
+ QWidget * parent, bool newLine, const char * name,
+ WFlags f )
+ : QDockWindow( InDock, parent, name, f, TRUE )
+{
+ mw = mainWindow;
+ init();
+
+ clearWFlags( WType_Dialog | WStyle_Customize | WStyle_NoBorder );
+ reparent( parent, QPoint( 0, 0 ), FALSE );
+
+ if ( mainWindow )
+ mainWindow->addToolBar( this, label, QMainWindow::DockUnmanaged, newLine );
+}
+
+
+/*!
+ \overload
+
+ Constructs an empty toolbar called \a name, with parent \a parent,
+ in its \a parent's top dock area, without any label and without
+ requiring a newline.
+*/
+
+QToolBar::QToolBar( QMainWindow * parent, const char * name )
+ : QDockWindow( InDock, parent, name, 0, TRUE )
+{
+ mw = parent;
+ init();
+
+ if ( parent )
+ parent->addToolBar( this, QString::null, QMainWindow::DockTop );
+}
+
+/*!
+ \internal
+
+ Common initialization code. Requires that \c mw and \c o are set.
+ Does not call QMainWindow::addDockWindow().
+*/
+void QToolBar::init()
+{
+ d = new QToolBarPrivate;
+ d->extension = 0;
+ d->extensionPopup = 0;
+ sw = 0;
+
+ setBackgroundMode( PaletteButton);
+ setFocusPolicy( NoFocus );
+ setFrameStyle( QFrame::ToolBarPanel | QFrame::Raised);
+ boxLayout()->setSpacing(style().pixelMetric(QStyle::PM_ToolBarItemSpacing));
+}
+
+/*!
+ \reimp
+*/
+
+QToolBar::~QToolBar()
+{
+ delete d;
+ d = 0;
+}
+
+/*!
+ \reimp
+*/
+
+void QToolBar::setOrientation( Orientation o )
+{
+ QDockWindow::setOrientation( o );
+ if (d->extension)
+ d->extension->setOrientation( o );
+ QObjectList *childs = queryList( "QToolBarSeparator" );
+ if ( childs ) {
+ QObject *ob = 0;
+ for ( ob = childs->first(); ob; ob = childs->next() ) {
+ QToolBarSeparator* w = (QToolBarSeparator*)ob;
+ w->setOrientation( o );
+ }
+ }
+ delete childs;
+}
+
+/*!
+ Adds a separator to the right/bottom of the toolbar.
+*/
+
+void QToolBar::addSeparator()
+{
+ (void) new QToolBarSeparator( orientation(), this, "toolbar separator" );
+}
+
+/*!
+ \reimp
+*/
+
+void QToolBar::styleChange( QStyle& )
+{
+ QObjectList *childs = queryList( "QWidget" );
+ if ( childs ) {
+ QObject *ob = 0;
+ for ( ob = childs->first(); ob; ob = childs->next() ) {
+ QWidget *w = (QWidget*)ob;
+ if ( ::qt_cast<QToolButton*>(w) || ::qt_cast<QToolBarSeparator*>(w) )
+ w->setStyle( &style() );
+ }
+ }
+ delete childs;
+ boxLayout()->setSpacing(style().pixelMetric(QStyle::PM_ToolBarItemSpacing));
+}
+
+/*!
+ \reimp.
+*/
+
+void QToolBar::show()
+{
+ QDockWindow::show();
+ if ( mw )
+ mw->triggerLayout( FALSE );
+ checkForExtension( size() );
+}
+
+
+/*!
+ \reimp
+*/
+
+void QToolBar::hide()
+{
+ QDockWindow::hide();
+ if ( mw )
+ mw->triggerLayout( FALSE );
+}
+
+/*!
+ Returns a pointer to the QMainWindow which manages this toolbar.
+*/
+
+QMainWindow * QToolBar::mainWindow() const
+{
+ return mw;
+}
+
+
+/*!
+ Sets the widget \a w to be expanded if this toolbar is requested
+ to stretch.
+
+ The request to stretch might occur because QMainWindow
+ right-justifies the dock area the toolbar is in, or because this
+ toolbar's isVerticalStretchable() or isHorizontalStretchable() is
+ set to TRUE.
+
+ If you call this function and the toolbar is not yet stretchable,
+ setStretchable() is called.
+
+ \sa QMainWindow::setRightJustification(), setVerticalStretchable(),
+ setHorizontalStretchable()
+*/
+
+void QToolBar::setStretchableWidget( QWidget * w )
+{
+ sw = w;
+ boxLayout()->setStretchFactor( w, 1 );
+
+ if ( !isHorizontalStretchable() && !isVerticalStretchable() ) {
+ if ( orientation() == Horizontal )
+ setHorizontalStretchable( TRUE );
+ else
+ setVerticalStretchable( TRUE );
+ }
+}
+
+
+/*!
+ \reimp
+*/
+
+bool QToolBar::event( QEvent * e )
+{
+ bool r = QDockWindow::event( e );
+ // After the event filters have dealt with it, do our stuff.
+ if ( e->type() == QEvent::ChildInserted ) {
+ QObject * child = ((QChildEvent*)e)->child();
+ if ( child && child->isWidgetType() && !((QWidget*)child)->isTopLevel()
+ && child->parent() == this
+ && qstrcmp("qt_dockwidget_internal", child->name()) != 0 ) {
+ boxLayout()->addWidget( (QWidget*)child );
+ if ( isVisible() ) {
+ if ( ((QWidget*)child)->testWState( WState_CreatedHidden ) )
+ ((QWidget*)child)->show();
+ checkForExtension( size() );
+ }
+ }
+ if ( child && child->isWidgetType() && ((QWidget*)child) == sw )
+ boxLayout()->setStretchFactor( (QWidget*)child, 1 );
+ } else if ( e->type() == QEvent::Show ) {
+ layout()->activate();
+ } else if ( e->type() == QEvent::LayoutHint && place() == OutsideDock ) {
+ adjustSize();
+ }
+ return r;
+}
+
+
+/*!
+ \property QToolBar::label
+ \brief the toolbar's label.
+
+ If the toolbar is floated the label becomes the toolbar window's
+ caption. There is no default label text.
+*/
+
+void QToolBar::setLabel( const QString & label )
+{
+ l = label;
+ setCaption( l );
+}
+
+QString QToolBar::label() const
+{
+ return l;
+}
+
+
+/*!
+ Deletes all the toolbar's child widgets.
+*/
+
+void QToolBar::clear()
+{
+ if ( !children() )
+ return;
+ QObjectListIt it( *children() );
+ QObject * obj;
+ while( (obj=it.current()) != 0 ) {
+ ++it;
+ if ( obj->isWidgetType() &&
+ qstrcmp( "qt_dockwidget_internal", obj->name() ) != 0 )
+ delete obj;
+ }
+}
+
+/*!
+ \reimp
+*/
+
+QSize QToolBar::minimumSize() const
+{
+ if ( orientation() == Horizontal )
+ return QSize( 0, QDockWindow::minimumSize().height() );
+ return QSize( QDockWindow::minimumSize().width(), 0 );
+}
+
+/*!
+ \reimp
+*/
+
+QSize QToolBar::minimumSizeHint() const
+{
+ if ( orientation() == Horizontal )
+ return QSize( 0, QDockWindow::minimumSizeHint().height() );
+ return QSize( QDockWindow::minimumSizeHint().width(), 0 );
+}
+
+void QToolBar::createPopup()
+{
+ if (!d->extensionPopup) {
+ d->extensionPopup = new QPopupMenu( this, "qt_dockwidget_internal" );
+ connect( d->extensionPopup, SIGNAL( aboutToShow() ), this, SLOT( createPopup() ) );
+ }
+
+ if (!d->extension) {
+ d->extension = new QToolBarExtensionWidget( this );
+ d->extension->setOrientation(orientation());
+ d->extension->button()->setPopup( d->extensionPopup );
+ d->extension->button()->setPopupDelay( -1 );
+ }
+
+ d->extensionPopup->clear();
+ // clear doesn't delete submenus, so do this explicitly
+ QObjectList *childlist = d->extensionPopup->queryList( "QPopupMenu", 0, FALSE, TRUE );
+ childlist->setAutoDelete(TRUE);
+ delete childlist;
+
+ childlist = queryList( "QWidget", 0, FALSE, TRUE );
+ QObjectListIt it( *childlist );
+ bool hide = FALSE;
+ bool doHide = FALSE;
+ int id;
+ while ( it.current() ) {
+ int j = 2;
+ if ( !it.current()->isWidgetType() || it.current() == d->extension->button() ||
+ qstrcmp( "qt_dockwidget_internal", it.current()->name() ) == 0 ) {
+ ++it;
+ continue;
+ }
+ QWidget *w = (QWidget*)it.current();
+#ifndef QT_NO_COMBOBOX
+ if ( ::qt_cast<QComboBox*>(w) )
+ j = 1;
+#endif
+ hide = FALSE;
+ QPoint p = w->parentWidget()->mapTo( this, w->geometry().bottomRight() );
+ if ( orientation() == Horizontal ) {
+ if ( p.x() > ( doHide ? width() - d->extension->width() / j : width() ) )
+ hide = TRUE;
+ } else {
+ if ( p.y() > ( doHide ? height()- d->extension->height() / j : height() ) )
+ hide = TRUE;
+ }
+ if ( hide && w->isVisible() ) {
+ doHide = TRUE;
+ if ( ::qt_cast<QToolButton*>(w) ) {
+ QToolButton *b = (QToolButton*)w;
+ QString s = b->textLabel();
+ if ( s.isEmpty() )
+ s = b->text();
+ if ( b->popup() && b->popupDelay() <= 0 )
+ id = d->extensionPopup->insertItem( b->iconSet(), s, b->popup() );
+ else
+ id = d->extensionPopup->insertItem( b->iconSet(), s, b, SLOT( emulateClick() ) ) ;
+ if ( b->isToggleButton() )
+ d->extensionPopup->setItemChecked( id, b->isOn() );
+ if ( !b->isEnabled() )
+ d->extensionPopup->setItemEnabled( id, FALSE );
+ } else if ( ::qt_cast<QButton*>(w) ) {
+ QButton *b = (QButton*)w;
+ QString s = b->text();
+ if ( s.isEmpty() )
+ s = "";
+ if ( b->pixmap() )
+ id = d->extensionPopup->insertItem( *b->pixmap(), s, b, SLOT( emulateClick() ) );
+ else
+ id = d->extensionPopup->insertItem( s, b, SLOT( emulateClick() ) );
+ if ( b->isToggleButton() )
+ d->extensionPopup->setItemChecked( id, b->isOn() );
+ if ( !b->isEnabled() )
+ d->extensionPopup->setItemEnabled( id, FALSE );
+#ifndef QT_NO_COMBOBOX
+ } else if ( ::qt_cast<QComboBox*>(w) ) {
+ QComboBox *c = (QComboBox*)w;
+ if ( c->count() != 0 ) {
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ QString s = c->caption();
+#else
+ QString s;
+#endif
+ if ( s.isEmpty() )
+ s = c->currentText();
+ uint maxItems = 0;
+ QPopupMenu *cp = new QPopupMenu(d->extensionPopup);
+ cp->setEnabled(c->isEnabled());
+ d->extensionPopup->insertItem( s, cp );
+ connect( cp, SIGNAL( activated(int) ), c, SLOT( internalActivate(int) ) );
+ for ( int i = 0; i < c->count(); ++i ) {
+ QString tmp = c->text( i );
+ cp->insertItem( tmp, i );
+ if ( c->currentText() == tmp )
+ cp->setItemChecked( i, TRUE );
+ if ( !maxItems ) {
+ if ( cp->count() == 10 ) {
+ int h = cp->sizeHint().height();
+ maxItems = QApplication::desktop()->height() * 10 / h;
+ }
+ } else if ( cp->count() >= maxItems - 1 ) {
+ QPopupMenu* sp = new QPopupMenu(d->extensionPopup);
+ cp->insertItem( tr( "More..." ), sp );
+ cp = sp;
+ connect( cp, SIGNAL( activated(int) ), c, SLOT( internalActivate(int) ) );
+ }
+ }
+ }
+#endif //QT_NO_COMBOBOX
+ }
+ }
+ ++it;
+ }
+ delete childlist;
+}
+
+
+/*!
+ \reimp
+*/
+
+void QToolBar::resizeEvent( QResizeEvent *e )
+{
+ checkForExtension( e->size() );
+}
+
+void QToolBar::checkForExtension( const QSize &sz )
+{
+ if (!isVisible())
+ return;
+
+ bool tooSmall;
+ if ( orientation() == Horizontal )
+ tooSmall = sz.width() < sizeHint().width();
+ else
+ tooSmall = sz.height() < sizeHint().height();
+
+ if ( tooSmall ) {
+ createPopup();
+ if ( d->extensionPopup->count() ) {
+ if ( orientation() == Horizontal )
+ d->extension->setGeometry( width() - 20, 1, 20, height() - 2 );
+ else
+ d->extension->setGeometry( 1, height() - 20, width() - 2, 20 );
+ d->extension->show();
+ d->extension->raise();
+ } else {
+ delete d->extension;
+ d->extension = 0;
+ delete d->extensionPopup;
+ d->extensionPopup = 0;
+ }
+ } else {
+ delete d->extension;
+ d->extension = 0;
+ delete d->extensionPopup;
+ d->extensionPopup = 0;
+ }
+}
+
+
+/*!
+ \reimp
+*/
+
+void QToolBar::setMinimumSize( int, int )
+{
+}
+
+/* from chaunsee:
+
+1. Tool Bars should contain only high-frequency functions. Avoid putting
+things like About and Exit on a tool bar unless they are frequent functions.
+
+2. All tool bar buttons must have some keyboard access method (it can be a
+menu or shortcut key or a function in a dialog box that can be accessed
+through the keyboard).
+
+3. Make tool bar functions as efficient as possible (the common example is to
+Print in Microsoft applications, it doesn't bring up the Print dialog box, it
+prints immediately to the default printer).
+
+4. Avoid turning tool bars into graphical menu bars. To me, a tool bar should
+be efficient. Once you make almost all the items in a tool bar into graphical
+pull-down menus, you start to lose efficiency.
+
+5. Make sure that adjacent icons are distinctive. There are some tool bars
+where you see a group of 4-5 icons that represent related functions, but they
+are so similar that you can't differentiate among them. These tool bars are
+often a poor attempt at a "common visual language".
+
+6. Use any de facto standard icons of your platform (for windows use the
+cut, copy and paste icons provided in dev kits rather than designing your
+own).
+
+7. Avoid putting a highly destructive tool bar button (delete database) by a
+safe, high-frequency button (Find) -- this will yield 1-0ff errors).
+
+8. Tooltips in many Microsoft products simply reiterate the menu text even
+when that is not explanatory. Consider making your tooltips slightly more
+verbose and explanatory than the corresponding menu item.
+
+9. Keep the tool bar as stable as possible when you click on different
+objects. Consider disabling tool bar buttons if they are used in most, but not
+all contexts.
+
+10. If you have multiple tool bars (like the Microsoft MMC snap-ins have),
+put the most stable tool bar to at the left with less stable ones to the
+right. This arrangement (stable to less stable) makes the tool bar somewhat
+more predictable.
+
+11. Keep a single tool bar to fewer than 20 items divided into 4-7 groups of
+items.
+*/
+#endif
diff --git a/src/widgets/qtoolbar.h b/src/widgets/qtoolbar.h
new file mode 100644
index 0000000..f07c1a8
--- /dev/null
+++ b/src/widgets/qtoolbar.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Definition of QToolBar class
+**
+** Created : 980306
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTOOLBAR_H
+#define QTOOLBAR_H
+
+#ifndef QT_H
+#include "qdockwindow.h"
+#endif // QT_H
+
+#ifndef QT_NO_TOOLBAR
+
+class QMainWindow;
+class QButton;
+class QBoxLayout;
+class QToolBarPrivate;
+
+class Q_EXPORT QToolBar: public QDockWindow
+{
+ Q_OBJECT
+ Q_PROPERTY( QString label READ label WRITE setLabel )
+
+public:
+ QToolBar( const QString &label,
+ QMainWindow *, ToolBarDock = DockTop,
+ bool newLine = FALSE, const char* name=0 );
+ QToolBar( const QString &label, QMainWindow *, QWidget *,
+ bool newLine = FALSE, const char* name=0, WFlags f = 0 );
+ QToolBar( QMainWindow* parent=0, const char* name=0 );
+ ~QToolBar();
+
+ void addSeparator();
+
+ void show();
+ void hide();
+
+ QMainWindow * mainWindow() const;
+
+ virtual void setStretchableWidget( QWidget * );
+
+ bool event( QEvent * e );
+
+ virtual void setLabel( const QString & );
+ QString label() const;
+
+ virtual void clear();
+
+ QSize minimumSize() const;
+ QSize minimumSizeHint() const;
+
+ void setOrientation( Orientation o );
+ void setMinimumSize( int minw, int minh );
+
+protected:
+ void resizeEvent( QResizeEvent *e );
+ void styleChange( QStyle & );
+
+private slots:
+ void createPopup();
+
+private:
+ void init();
+ void checkForExtension( const QSize &sz );
+ QToolBarPrivate * d;
+ QMainWindow * mw;
+ QWidget * sw;
+ QString l;
+
+ friend class QMainWindow;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QToolBar( const QToolBar & );
+ QToolBar& operator=( const QToolBar & );
+#endif
+};
+
+#endif // QT_NO_TOOLBAR
+
+#endif // QTOOLBAR_H
diff --git a/src/widgets/qtoolbox.cpp b/src/widgets/qtoolbox.cpp
new file mode 100644
index 0000000..64fc148
--- /dev/null
+++ b/src/widgets/qtoolbox.cpp
@@ -0,0 +1,692 @@
+/****************************************************************************
+**
+** Implementation of QToolBox widget class
+**
+** Created : 961105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtoolbox.h"
+
+#ifndef QT_NO_TOOLBOX
+
+#include <qbutton.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qobjectlist.h>
+#include <qapplication.h>
+#include <qwidgetlist.h>
+#include <qlayout.h>
+#include <qvaluelist.h>
+#include <qtooltip.h>
+#include <qeventloop.h>
+#include <qdatetime.h>
+
+class QToolBoxButton : public QButton
+{
+public:
+ QToolBoxButton( QWidget *parent, const char *name )
+ : QButton( parent, name ), selected( FALSE )
+ {
+ setBackgroundMode(PaletteBackground);
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ setFocusPolicy(NoFocus);
+ }
+
+ inline void setSelected( bool b ) { selected = b; update(); }
+ inline void setTextLabel( const QString &text ) { label = text; update(); }
+ inline QString textLabel() const { return label; }
+ inline void setIconSet( const QIconSet &is ) { icon = is; update(); }
+ inline QIconSet iconSet() const { return icon; }
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+protected:
+ void drawButton( QPainter * );
+
+private:
+ bool selected;
+ QString label;
+ QIconSet icon;
+};
+
+class QToolBoxPrivate
+{
+public:
+ struct Page
+ {
+ QToolBoxButton *button;
+ QScrollView *sv;
+ QWidget *widget;
+ QString toolTip;
+
+ inline void setTextLabel( const QString &text ) { button->setTextLabel(text); }
+ inline void setIconSet( const QIconSet &is ) { button->setIconSet(is); }
+ inline void setToolTip( const QString &tip )
+ {
+ toolTip = tip;
+ QToolTip::remove( button );
+ if ( !tip.isNull() )
+ QToolTip::add( button, tip );
+ }
+
+ inline bool operator==(const Page& other) const
+ {
+ return widget == other.widget;
+ }
+ };
+ typedef QValueList<Page> PageList;
+
+ inline QToolBoxPrivate()
+ : currentPage( 0 )
+ {
+ }
+
+ Page *page( QWidget *widget );
+ Page *page( int index );
+
+ void updateTabs();
+
+ PageList pageList;
+ QVBoxLayout *layout;
+ Page *currentPage;
+};
+
+QToolBoxPrivate::Page *QToolBoxPrivate::page( QWidget *widget )
+{
+ 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 < (int)pageList.size() )
+ return &*pageList.at(index);
+ return 0;
+}
+
+void QToolBoxPrivate::updateTabs()
+{
+ QToolBoxButton *lastButton = currentPage ? currentPage->button : 0;
+ bool after = FALSE;
+ for ( PageList::ConstIterator i = pageList.constBegin(); i != pageList.constEnd(); ++i ) {
+ if (after) {
+ (*i).button->setEraseColor((*i).widget->eraseColor());
+ (*i).button->update();
+ } else if ( (*i).button->backgroundMode() != Qt::PaletteBackground ) {
+ (*i).button->setBackgroundMode( Qt::PaletteBackground );
+ (*i).button->update();
+ }
+ after = (*i).button == lastButton;
+ }
+}
+
+QSize QToolBoxButton::sizeHint() const
+{
+ QSize iconSize(8, 8);
+ if ( !icon.isNull() )
+ iconSize += icon.pixmap( QIconSet::Small, QIconSet::Normal ).size() + QSize( 2, 0 );
+ QSize textSize = fontMetrics().size( Qt::ShowPrefix, label ) + 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();
+ return QSize(8, 8) + icon.pixmap( QIconSet::Small, QIconSet::Normal ).size();
+}
+
+void QToolBoxButton::drawButton( QPainter *p )
+{
+ QStyle::SFlags flags = QStyle::Style_Default;
+ const QColorGroup &cg = colorGroup();
+
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ if ( selected )
+ flags |= QStyle::Style_Selected;
+ if ( hasFocus() )
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ style().drawControl( QStyle::CE_ToolBoxTab, p, parentWidget(), rect(), cg, flags );
+
+ QPixmap pm = icon.pixmap( QIconSet::Small, isEnabled() ? QIconSet::Normal : QIconSet::Disabled );
+
+ QRect cr = style().subRect( QStyle::SR_ToolBoxTabContents, this );
+ QRect tr, ir;
+ int ih = 0;
+ if ( pm.isNull() ) {
+ tr = cr;
+ tr.addCoords( 4, 0, -8, 0 );
+ } else {
+ int iw = pm.width() + 4;
+ ih = pm.height();
+ ir = QRect( cr.left() + 4, cr.top(), iw + 2, ih );
+ tr = QRect( ir.right(), cr.top(), cr.width() - ir.right() - 4, cr.height() );
+ }
+
+ if ( selected && style().styleHint( QStyle::SH_ToolBox_SelectedPageTitleBold ) ) {
+ QFont f( p->font() );
+ f.setBold( TRUE );
+ p->setFont( f );
+ }
+
+ QString txt;
+ if ( p->fontMetrics().width(label) < tr.width() ) {
+ txt = label;
+ } else {
+ txt = label.left( 1 );
+ int ew = p->fontMetrics().width( "..." );
+ int i = 1;
+ while ( p->fontMetrics().width( txt ) + ew +
+ p->fontMetrics().width( label[i] ) < tr.width() )
+ txt += label[i++];
+ txt += "...";
+ }
+
+ if ( ih )
+ p->drawPixmap( ir.left(), (height() - ih) / 2, pm );
+
+ QToolBox *tb = (QToolBox*)parentWidget();
+
+ const QColor* fill = 0;
+ if ( selected &&
+ style().styleHint( QStyle::SH_ToolBox_SelectedPageTitleBold ) &&
+ tb->backgroundMode() != NoBackground )
+ fill = &cg.color( QPalette::foregroundRoleFromMode( tb->backgroundMode() ) );
+
+ int alignment = AlignLeft | AlignVCenter | ShowPrefix;
+ if (!style().styleHint(QStyle::SH_UnderlineAccelerator, this))
+ alignment |= NoAccel;
+ style().drawItem( p, tr, alignment, cg,
+ isEnabled(), 0, txt, -1, fill );
+
+ if ( !txt.isEmpty() && hasFocus() )
+ style().drawPrimitive( QStyle::PE_FocusRect, p, tr, cg );
+}
+
+/*!
+ \class QToolBox
+
+ \brief The QToolBox class provides a column of tabbed widget
+ items.
+
+ \mainclass
+ \ingroup advanced
+
+ 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 itemLabel(), an optional icon, itemIconSet(), an
+ optional itemToolTip(), and a \link item() widget\endlink. The
+ item's attributes can be changed with setItemLabel(),
+ setItemIconSet() and setItemToolTip().
+
+ 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 to move items to different positions.
+
+ The current item widget is returned by currentItem() and set with
+ setCurrentItem(). If you prefer you can work in terms of indexes
+ using currentIndex(), setCurrentIndex(), indexOf() and 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 changed. The new
+ current item's index is passed in \a index, or -1 if there is no
+ current item.
+*/
+
+/*!
+ Constructs a toolbox called \a name with parent \a parent and flags \a f.
+*/
+
+QToolBox::QToolBox( QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f )
+{
+ d = new QToolBoxPrivate;
+ d->layout = new QVBoxLayout( this );
+ QWidget::setBackgroundMode( PaletteButton );
+}
+
+/*! \reimp */
+
+QToolBox::~QToolBox()
+{
+ delete d;
+}
+
+/*!
+ \fn int QToolBox::addItem( QWidget *w, const QString &label )
+ \overload
+
+ Adds the widget \a w in a new tab at bottom of the toolbox. The
+ new tab's label is set to \a label. Returns the new tab's index.
+*/
+
+/*!
+ \fn int QToolBox::addItem( QWidget *item, const QIconSet &iconSet,const QString &label )
+ Adds the widget \a item in a new tab at bottom of the toolbox. The
+ new tab's label is set to \a label, and the \a iconSet is
+ displayed to the left of the \a label. Returns the new tab's index.
+*/
+
+/*!
+ \fn int QToolBox::insertItem( int index, QWidget *item, const QString &label )
+ \overload
+
+ Inserts the widget \a item at position \a index, or at the bottom
+ of the toolbox if \a index is out of range. The new item's label is
+ set to \a label. Returns the new item's index.
+*/
+
+/*!
+ Inserts the widget \a item at position \a index, or at the bottom
+ of the toolbox if \a index is out of range. The new item's label
+ is set to \a label, and the \a iconSet is displayed to the left of
+ the \a label. Returns the new item's index.
+*/
+
+int QToolBox::insertItem( int index, QWidget *item, const QIconSet &iconSet,
+ const QString &label )
+{
+ if ( !item )
+ return -1;
+
+ connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(itemDestroyed(QObject*)));
+
+ QToolBoxPrivate::Page c;
+ c.widget = item;
+ c.button = new QToolBoxButton( this, label.latin1() );
+ connect( c.button, SIGNAL( clicked() ), this, SLOT( buttonClicked() ) );
+
+ c.sv = new QScrollView( this );
+ c.sv->hide();
+ c.sv->setResizePolicy( QScrollView::AutoOneFit );
+ c.sv->addChild( item );
+ c.sv->setFrameStyle( QFrame::NoFrame );
+
+ c.setTextLabel( label );
+ c.setIconSet( iconSet );
+
+ if ( index < 0 || index >= (int)d->pageList.count() ) {
+ index = (int)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( d->pageList.at(index), c );
+ 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 QToolBox::buttonClicked()
+{
+ QToolBoxButton *tb = ::qt_cast<QToolBoxButton*>(sender());
+ QWidget* item = 0;
+ for ( QToolBoxPrivate::PageList::ConstIterator i = d->pageList.constBegin(); i != d->pageList.constEnd(); ++i )
+ if ( (*i).button == tb ) {
+ item = (*i).widget;
+ break;
+ }
+
+ setCurrentItem( item );
+}
+
+/*!
+ \property QToolBox::count
+ \brief The number of items contained in the toolbox.
+*/
+
+int QToolBox::count() const
+{
+ return (int)d->pageList.count();
+}
+
+void QToolBox::setCurrentIndex( int index )
+{
+ setCurrentItem( item( index ) );
+}
+
+/*!
+ Sets the current item to be \a item.
+*/
+
+void QToolBox::setCurrentItem( QWidget *item )
+{
+ QToolBoxPrivate::Page *c = d->page( item );
+ 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( indexOf(item) );
+}
+
+void QToolBox::relayout()
+{
+ delete d->layout;
+ d->layout = new QVBoxLayout( this );
+ for ( QToolBoxPrivate::PageList::ConstIterator i = d->pageList.constBegin(); i != d->pageList.constEnd(); ++i ) {
+ d->layout->addWidget( (*i).button );
+ d->layout->addWidget( (*i).sv );
+ }
+}
+
+void QToolBox::itemDestroyed(QObject *object)
+{
+ // no verification - vtbl corrupted already
+ QWidget *page = (QWidget*)object;
+
+ QToolBoxPrivate::Page *c = d->page(page);
+ if ( !page || !c )
+ return;
+
+ d->layout->remove( c->sv );
+ d->layout->remove( c->button );
+ c->sv->deleteLater(); // page might still be a child of sv
+ delete c->button;
+
+ bool removeCurrent = c == d->currentPage;
+ d->pageList.remove( *c );
+
+ if ( !d->pageList.count() ) {
+ d->currentPage = 0;
+ emit currentChanged(-1);
+ } else if ( removeCurrent ) {
+ d->currentPage = 0;
+ setCurrentIndex(0);
+ }
+}
+
+/*!
+ Removes the widget \a item from the toolbox. Note that the widget
+ is \e not deleted. Returns the removed widget's index, or -1 if
+ the widget was not in this tool box.
+*/
+
+int QToolBox::removeItem( QWidget *item )
+{
+ int index = indexOf(item);
+ if (index >= 0) {
+ disconnect(item, SIGNAL(destroyed(QObject*)), this, SLOT(itemDestroyed(QObject*)));
+ item->reparent( this, QPoint(0,0) );
+ // destroy internal data
+ itemDestroyed(item);
+ }
+ itemRemoved(index);
+ return index;
+}
+
+
+/*!
+ Returns the toolbox's current item, or 0 if the toolbox is empty.
+*/
+
+QWidget *QToolBox::currentItem() const
+{
+ return d->currentPage ? d->currentPage->widget : 0;
+}
+
+/*!
+ \property QToolBox::currentIndex
+ \brief the index of the current item, or -1 if the toolbox is empty.
+ \sa currentItem(), indexOf(), item()
+*/
+
+
+int QToolBox::currentIndex() const
+{
+ return d->currentPage ? indexOf( d->currentPage->widget ) : -1;
+}
+
+/*!
+ Returns the item at position \a index, or 0 if there is no such
+ item.
+*/
+
+QWidget *QToolBox::item( int index ) const
+{
+ if ( index < 0 || index >= (int) d->pageList.size() )
+ return 0;
+ return (*d->pageList.at( index )).widget;
+}
+
+/*!
+ Returns the index of item \a item, or -1 if the item does not
+ exist.
+*/
+
+int QToolBox::indexOf( QWidget *item ) const
+{
+ QToolBoxPrivate::Page *c = d->page(item);
+ return c ? d->pageList.findIndex( *c ) : -1;
+}
+
+/*!
+ If \a enabled is TRUE then the item at position \a index is enabled; otherwise item
+ \a index is disabled.
+*/
+
+void QToolBox::setItemEnabled( int index, bool enabled )
+{
+ 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 = (int)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 label of the item at position \a index to \a label.
+*/
+
+void QToolBox::setItemLabel( int index, const QString &label )
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ if ( c )
+ c->setTextLabel( label );
+}
+
+/*!
+ Sets the icon of the item at position \a index to \a iconSet.
+*/
+
+void QToolBox::setItemIconSet( int index, const QIconSet &iconSet )
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ if ( c )
+ c->setIconSet( iconSet );
+}
+
+/*!
+ Sets the tooltip of the item at position \a index to \a toolTip.
+*/
+
+void QToolBox::setItemToolTip( int index, const QString &toolTip )
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ if ( c )
+ c->setToolTip( toolTip );
+}
+
+/*!
+ Returns TRUE if the item at position \a index is enabled; otherwise returns FALSE.
+*/
+
+bool QToolBox::isItemEnabled( int index ) const
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ return c && c->button->isEnabled();
+}
+
+/*!
+ Returns the label of the item at position \a index, or a null string if
+ \a index is out of range.
+*/
+
+QString QToolBox::itemLabel( int index ) const
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ return ( c ? c->button->textLabel() : QString::null );
+}
+
+/*!
+ Returns the icon of the item at position \a index, or a null
+ icon if \a index is out of range.
+*/
+
+QIconSet QToolBox::itemIconSet( int index ) const
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ return ( c ? c->button->iconSet() : QIconSet() );
+}
+
+/*!
+ Returns the tooltip of the item at position \a index, or a null
+ string if \a index is out of range.
+*/
+
+QString QToolBox::itemToolTip( int index ) const
+{
+ QToolBoxPrivate::Page *c = d->page( index );
+ return ( c ? c->toolTip : QString::null );
+}
+
+/*! \reimp */
+void QToolBox::showEvent( QShowEvent *e )
+{
+ QWidget::showEvent( e );
+}
+
+/*! \reimp */
+void QToolBox::frameChanged()
+{
+ d->layout->setMargin( frameWidth() );
+ QFrame::frameChanged();
+}
+
+/*! \reimp */
+void QToolBox::styleChange(QStyle &style)
+{
+ d->updateTabs();
+ QFrame::styleChange(style);
+}
+
+/*!
+ This virtual handler is called after a new item was added or
+ inserted at position \a index.
+ */
+void QToolBox::itemInserted( int index )
+{
+ Q_UNUSED(index)
+}
+
+/*!
+ This virtual handler is called after an item was removed from
+ position \a index.
+ */
+void QToolBox::itemRemoved( int index )
+{
+ Q_UNUSED(index)
+}
+
+#endif //QT_NO_TOOLBOX
diff --git a/src/widgets/qtoolbox.h b/src/widgets/qtoolbox.h
new file mode 100644
index 0000000..b100cf6
--- /dev/null
+++ b/src/widgets/qtoolbox.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Definition of QToolBox widget class
+**
+** Created : 961105
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTOOLBOX_H
+#define QTOOLBOX_H
+
+#ifndef QT_H
+#include <qframe.h>
+#include <qiconset.h>
+#endif // QT_H
+
+#ifndef QT_NO_TOOLBOX
+
+class QToolBoxPrivate;
+class QWidgetList;
+
+class Q_EXPORT QToolBox : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( int currentIndex READ currentIndex WRITE setCurrentIndex )
+ Q_PROPERTY( int count READ count )
+
+public:
+ QToolBox( QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ ~QToolBox();
+
+ int addItem( QWidget *item, const QString &label );
+ int addItem( QWidget *item, const QIconSet &iconSet, const QString &label );
+ int insertItem( int index, QWidget *item, const QString &label );
+ int insertItem( int index, QWidget *item, const QIconSet &iconSet, const QString &label );
+
+ int removeItem( QWidget *item );
+
+ void setItemEnabled( int index, bool enabled );
+ bool isItemEnabled( int index ) const;
+
+ void setItemLabel( int index, const QString &label );
+ QString itemLabel( int index ) const;
+
+ void setItemIconSet( int index, const QIconSet &iconSet );
+ QIconSet itemIconSet( int index ) const;
+
+ void setItemToolTip( int index, const QString &toolTip );
+ QString itemToolTip( int index ) const;
+
+ QWidget *currentItem() const;
+ void setCurrentItem( QWidget *item );
+
+ int currentIndex() const;
+ QWidget *item( int index ) const;
+ int indexOf( QWidget *item ) const;
+ int count() const;
+
+public slots:
+ void setCurrentIndex( int index );
+
+signals:
+ void currentChanged( int index );
+
+private slots:
+ void buttonClicked();
+ void itemDestroyed(QObject*);
+
+protected:
+ virtual void itemInserted( int index );
+ virtual void itemRemoved( int index );
+ void showEvent( QShowEvent *e );
+ void frameChanged();
+ void styleChange(QStyle&);
+
+private:
+ void relayout();
+
+private:
+ QToolBoxPrivate *d;
+
+};
+
+
+inline int QToolBox::addItem( QWidget *item, const QString &label )
+{ return insertItem( -1, item, QIconSet(), label ); }
+inline int QToolBox::addItem( QWidget *item, const QIconSet &iconSet,
+ const QString &label )
+{ return insertItem( -1, item, iconSet, label ); }
+inline int QToolBox::insertItem( int index, QWidget *item, const QString &label )
+{ return insertItem( index, item, QIconSet(), label ); }
+
+#endif // QT_NO_TOOLBOX
+#endif
diff --git a/src/widgets/qtoolbutton.cpp b/src/widgets/qtoolbutton.cpp
new file mode 100644
index 0000000..f11b613
--- /dev/null
+++ b/src/widgets/qtoolbutton.cpp
@@ -0,0 +1,1041 @@
+/****************************************************************************
+**
+** Implementation of QToolButton class
+**
+** Created : 980320
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#undef QT_NO_COMPAT
+#include "qtoolbutton.h"
+#ifndef QT_NO_TOOLBUTTON
+
+#include "qdrawutil.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qwmatrix.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qmainwindow.h"
+#include "qtooltip.h"
+#include "qtoolbar.h"
+#include "qimage.h"
+#include "qiconset.h"
+#include "qtimer.h"
+#include "qpopupmenu.h"
+#include "qguardedptr.h"
+
+class QToolButtonPrivate
+{
+ // ### add tool tip magic here
+public:
+#ifndef QT_NO_POPUPMENU
+ QGuardedPtr<QPopupMenu> popup;
+ QTimer* popupTimer;
+ int delay;
+#endif
+ Qt::ArrowType arrow;
+ uint instantPopup : 1;
+ uint autoraise : 1;
+ uint repeat : 1;
+ uint discardNextMouseEvent : 1;
+ QToolButton::TextPosition textPos;
+};
+
+
+/*!
+ \class QToolButton qtoolbutton.h
+ \brief The QToolButton class provides a quick-access button to
+ commands or options, usually used inside a QToolBar.
+
+ \ingroup basic
+ \mainclass
+
+ 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. Its classic usage is to select tools, for example
+ the "pen" tool in a drawing program. This would be implemented
+ with a QToolButton as 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 QIconSet. 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
+ setUsesBigPixmap() and setUsesTextLabel(). When used inside a
+ QToolBar in a QMainWindow, the button automatically adjusts to
+ QMainWindow's settings (see QMainWindow::setUsesTextLabel() and
+ QMainWindow::setUsesBigPixmaps()). The pixmap set on a QToolButton
+ will be set to 22x22 if it is bigger than this size. If
+ usesBigPixmap() is TRUE, then the pixmap will be set to 32x32.
+
+ A tool button can offer additional choices in a popup menu. The
+ feature 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. With
+ QToolButton you can set a popup menu using setPopup(). The default
+ delay is 600ms; you can adjust it with setPopupDelay().
+
+ \img qdockwindow.png Toolbar with Toolbuttons \caption A floating
+ QToolbar with QToolbuttons
+
+ \sa QPushButton QToolBar QMainWindow \link guibooks.html#fowler
+ GUI Design Handbook: Push Button\endlink
+*/
+
+/*!
+ \enum QToolButton::TextPosition
+
+ The position of the tool button's textLabel in relation to the
+ tool button's icon.
+
+ \value BesideIcon The text appears beside the icon.
+ \value BelowIcon The text appears below the icon.
+*/
+
+
+/*!
+ Constructs an empty tool button called \a name, with parent \a
+ parent.
+*/
+
+QToolButton::QToolButton( QWidget * parent, const char *name )
+ : QButton( parent, name )
+{
+ init();
+#ifndef QT_NO_TOOLBAR
+ QToolBar* tb = ::qt_cast<QToolBar*>(parent);
+ if ( tb ) {
+ setAutoRaise( TRUE );
+ if ( tb->mainWindow() ) {
+ connect( tb->mainWindow(), SIGNAL(pixmapSizeChanged(bool)),
+ this, SLOT(setUsesBigPixmap(bool)) );
+ setUsesBigPixmap( tb->mainWindow()->usesBigPixmaps() );
+ connect( tb->mainWindow(), SIGNAL(usesTextLabelChanged(bool)),
+ this, SLOT(setUsesTextLabel(bool)) );
+ setUsesTextLabel( tb->mainWindow()->usesTextLabel() );
+ } else {
+ setUsesBigPixmap( FALSE );
+ }
+ } else
+#endif
+ {
+ setUsesBigPixmap( FALSE );
+ }
+}
+
+
+/*!
+ Constructs a tool button as an arrow button. The \c ArrowType \a
+ type defines the arrow direction. Possible values are \c
+ LeftArrow, \c RightArrow, \c UpArrow and \c 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( ArrowType type, QWidget *parent, const char *name )
+ : QButton( parent, name )
+{
+ init();
+ setUsesBigPixmap( FALSE );
+ setAutoRepeat( TRUE );
+ d->arrow = type;
+ hasArrow = TRUE;
+}
+
+
+/* Set-up code common to all the constructors */
+
+void QToolButton::init()
+{
+ d = new QToolButtonPrivate;
+ d->textPos = Under;
+#ifndef QT_NO_POPUPMENU
+ d->delay = 600;
+ d->popup = 0;
+ d->popupTimer = 0;
+#endif
+ d->autoraise = FALSE;
+ d->arrow = LeftArrow;
+ d->instantPopup = FALSE;
+ d->discardNextMouseEvent = FALSE;
+ bpID = bp.serialNumber();
+ spID = sp.serialNumber();
+
+ utl = FALSE;
+ ubp = TRUE;
+ hasArrow = FALSE;
+
+ s = 0;
+
+ setFocusPolicy( NoFocus );
+ setBackgroundMode( PaletteButton);
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+}
+
+#ifndef QT_NO_TOOLBAR
+
+/*!
+ Constructs a tool button called \a name, that is a child of \a
+ parent (which must be a QToolBar).
+
+ The tool button will display \a iconSet, with its text label and
+ tool tip set to \a textLabel and its status bar message set to \a
+ grouptext. It will be connected to the \a slot in object \a
+ receiver.
+*/
+
+QToolButton::QToolButton( const QIconSet& iconSet, const QString &textLabel,
+ const QString& grouptext,
+ QObject * receiver, const char *slot,
+ QToolBar * parent, const char *name )
+ : QButton( parent, name )
+{
+ init();
+ setAutoRaise( TRUE );
+ setIconSet( iconSet );
+ setTextLabel( textLabel );
+ if ( receiver && slot )
+ connect( this, SIGNAL(clicked()), receiver, slot );
+ if ( parent->mainWindow() ) {
+ connect( parent->mainWindow(), SIGNAL(pixmapSizeChanged(bool)),
+ this, SLOT(setUsesBigPixmap(bool)) );
+ setUsesBigPixmap( parent->mainWindow()->usesBigPixmaps() );
+ connect( parent->mainWindow(), SIGNAL(usesTextLabelChanged(bool)),
+ this, SLOT(setUsesTextLabel(bool)) );
+ setUsesTextLabel( parent->mainWindow()->usesTextLabel() );
+ } else {
+ setUsesBigPixmap( FALSE );
+ }
+#ifndef QT_NO_TOOLTIP
+ if ( !textLabel.isEmpty() ) {
+ if ( !grouptext.isEmpty() && parent->mainWindow() )
+ QToolTip::add( this, textLabel,
+ parent->mainWindow()->toolTipGroup(), grouptext );
+ else
+ QToolTip::add( this, textLabel );
+ } else if ( !grouptext.isEmpty() && parent->mainWindow() )
+ QToolTip::add( this, QString::null,
+ parent->mainWindow()->toolTipGroup(), grouptext );
+#endif
+}
+
+#endif
+
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QToolButton::~QToolButton()
+{
+#ifndef QT_NO_POPUPMENU
+ d->popupTimer = 0;
+ d->popup = 0;
+#endif
+ delete d;
+ delete s;
+}
+
+
+/*!
+ \property QToolButton::backgroundMode
+ \brief the toolbutton's background mode
+
+ Get this property with backgroundMode().
+
+ \sa QWidget::setBackgroundMode()
+*/
+
+/*!
+ \property QToolButton::toggleButton
+ \brief whether this tool button is a toggle button.
+
+ Toggle buttons have an on/off state similar to \link QCheckBox
+ check boxes. \endlink A tool button is not a toggle button by
+ default.
+
+ \sa setOn(), toggle()
+*/
+
+void QToolButton::setToggleButton( bool enable )
+{
+ QButton::setToggleButton( enable );
+}
+
+
+/*!
+ \reimp
+*/
+QSize QToolButton::sizeHint() const
+{
+ constPolish();
+
+ int w = 0, h = 0;
+
+ if ( iconSet().isNull() && !text().isNull() && !usesTextLabel() ) {
+ w = fontMetrics().width( text() );
+ h = fontMetrics().height(); // boundingRect()?
+ } else if ( usesBigPixmap() ) {
+ QPixmap pm = iconSet().pixmap( QIconSet::Large, QIconSet::Normal );
+ w = pm.width();
+ h = pm.height();
+ QSize iconSize = QIconSet::iconSize( QIconSet::Large );
+ if ( w < iconSize.width() )
+ w = iconSize.width();
+ if ( h < iconSize.height() )
+ h = iconSize.height();
+ } else if ( !iconSet().isNull() ) {
+ // ### in 3.1, use QIconSet::iconSize( QIconSet::Small );
+ QPixmap pm = iconSet().pixmap( QIconSet::Small, QIconSet::Normal );
+ w = pm.width();
+ h = pm.height();
+ if ( w < 16 )
+ w = 16;
+ if ( h < 16 )
+ h = 16;
+ }
+
+ if ( usesTextLabel() ) {
+ QSize textSize = fontMetrics().size( Qt::ShowPrefix, textLabel() );
+ textSize.setWidth( textSize.width() + fontMetrics().width(' ')*2 );
+ if ( d->textPos == Under ) {
+ h += 4 + textSize.height();
+ if ( textSize.width() > w )
+ w = textSize.width();
+ } else { // Right
+ w += 4 + textSize.width();
+ if ( textSize.height() > h )
+ h = textSize.height();
+ }
+ }
+
+#ifndef QT_NO_POPUPMENU
+ if ( popup() && ! popupDelay() )
+ w += style().pixelMetric(QStyle::PM_MenuButtonIndicator, this);
+#endif
+ return (style().sizeFromContents(QStyle::CT_ToolButton, this, QSize(w, h)).
+ expandedTo(QApplication::globalStrut()));
+}
+
+/*!
+ \reimp
+ */
+QSize QToolButton::minimumSizeHint() const
+{
+ return sizeHint();
+}
+
+/*!
+ \property QToolButton::usesBigPixmap
+ \brief whether this toolbutton uses big pixmaps.
+
+ QToolButton automatically connects this property to the relevant
+ signal in the QMainWindow in which it resides. We strongly
+ recommend that you use QMainWindow::setUsesBigPixmaps() instead.
+
+ This property's default is TRUE.
+
+ \warning If you set some buttons (in a QMainWindow) to have big
+ pixmaps and others to have small pixmaps, QMainWindow may not get
+ the geometry right.
+*/
+
+void QToolButton::setUsesBigPixmap( bool enable )
+{
+ if ( (bool)ubp == enable )
+ return;
+
+ ubp = enable;
+ if ( isVisible() ) {
+ update();
+ updateGeometry();
+ }
+}
+
+
+/*!
+ \property QToolButton::usesTextLabel
+ \brief whether the toolbutton displays a text label below the button pixmap.
+
+ The default is FALSE.
+
+ QToolButton automatically connects this slot to the relevant
+ signal in the QMainWindow in which is resides.
+*/
+
+void QToolButton::setUsesTextLabel( bool enable )
+{
+ if ( (bool)utl == enable )
+ return;
+
+ utl = enable;
+ if ( isVisible() ) {
+ update();
+ updateGeometry();
+ }
+}
+
+
+/*!
+ \property QToolButton::on
+ \brief whether this tool button is on.
+
+ This property has no effect on \link isToggleButton() non-toggling
+ buttons. \endlink The default is FALSE (i.e. off).
+
+ \sa isToggleButton() toggle()
+*/
+
+void QToolButton::setOn( bool enable )
+{
+ if ( !isToggleButton() )
+ return;
+ QButton::setOn( enable );
+}
+
+
+/*!
+ Toggles the state of this tool button.
+
+ This function has no effect on \link isToggleButton() non-toggling
+ buttons. \endlink
+
+ \sa isToggleButton() toggled()
+*/
+
+void QToolButton::toggle()
+{
+ if ( !isToggleButton() )
+ return;
+ QButton::setOn( !isOn() );
+}
+
+
+/*!
+ \reimp
+*/
+void QToolButton::drawButton( QPainter * p )
+{
+ QStyle::SCFlags controls = QStyle::SC_ToolButton;
+ QStyle::SCFlags active = QStyle::SC_None;
+
+ Qt::ArrowType arrowtype = d->arrow;
+
+ if (isDown())
+ active |= QStyle::SC_ToolButton;
+
+#ifndef QT_NO_POPUPMENU
+ if (d->popup && !d->delay) {
+ controls |= QStyle::SC_ToolButtonMenu;
+ if (d->instantPopup || isDown())
+ active |= QStyle::SC_ToolButtonMenu;
+ }
+#endif
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ if (isOn())
+ flags |= QStyle::Style_On;
+ if (autoRaise()) {
+ flags |= QStyle::Style_AutoRaise;
+ if (uses3D()) {
+ flags |= QStyle::Style_MouseOver;
+ if (! isOn() && ! isDown())
+ flags |= QStyle::Style_Raised;
+ }
+ } else if (! isOn() && ! isDown())
+ flags |= QStyle::Style_Raised;
+
+ style().drawComplexControl(QStyle::CC_ToolButton, p, this, rect(), colorGroup(),
+ flags, controls, active,
+ hasArrow ? QStyleOption(arrowtype) :
+ QStyleOption());
+ drawButtonLabel(p);
+}
+
+
+/*!
+ \reimp
+*/
+void QToolButton::drawButtonLabel(QPainter *p)
+{
+ QRect r =
+ QStyle::visualRect(style().subRect(QStyle::SR_ToolButtonContents, this), this);
+
+ Qt::ArrowType arrowtype = d->arrow;
+
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ if (hasFocus())
+ flags |= QStyle::Style_HasFocus;
+ if (isDown())
+ flags |= QStyle::Style_Down;
+ if (isOn())
+ flags |= QStyle::Style_On;
+ if (autoRaise()) {
+ flags |= QStyle::Style_AutoRaise;
+ if (uses3D()) {
+ flags |= QStyle::Style_MouseOver;
+ if (! isOn() && ! isDown())
+ flags |= QStyle::Style_Raised;
+ }
+ } else if (! isOn() && ! isDown())
+ flags |= QStyle::Style_Raised;
+
+ style().drawControl(QStyle::CE_ToolButtonLabel, p, this, r,
+ colorGroup(), flags,
+ hasArrow ? QStyleOption(arrowtype) :
+ QStyleOption());
+}
+
+
+/*!
+ \reimp
+ */
+void QToolButton::enterEvent( QEvent * e )
+{
+ if ( autoRaise() && isEnabled() )
+ repaint(FALSE);
+
+ QButton::enterEvent( e );
+}
+
+
+/*!
+ \reimp
+ */
+void QToolButton::leaveEvent( QEvent * e )
+{
+ if ( autoRaise() && isEnabled() )
+ repaint(FALSE);
+
+ QButton::leaveEvent( e );
+}
+
+/*!
+ \reimp
+ */
+void QToolButton::moveEvent( QMoveEvent * )
+{
+ // Reimplemented to handle pseudo transparency in case the toolbars
+ // has a fancy pixmap background.
+ if ( parentWidget() && parentWidget()->backgroundPixmap() &&
+ autoRaise() && !uses3D() )
+ repaint( FALSE );
+}
+
+/*!
+ \reimp
+*/
+void QToolButton::mousePressEvent( QMouseEvent *e )
+{
+ QRect popupr =
+ QStyle::visualRect( style().querySubControlMetrics(QStyle::CC_ToolButton, this,
+ QStyle::SC_ToolButtonMenu), this );
+ d->instantPopup = (popupr.isValid() && popupr.contains(e->pos()));
+
+#ifndef QT_NO_POPUPMENU
+ if ( d->discardNextMouseEvent ) {
+ d->discardNextMouseEvent = FALSE;
+ d->instantPopup = FALSE;
+ d->popup->removeEventFilter( this );
+ return;
+ }
+ if ( e->button() == LeftButton && d->delay <= 0 && d->popup && d->instantPopup && !d->popup->isVisible() ) {
+ openPopup();
+ return;
+ }
+#endif
+
+ d->instantPopup = FALSE;
+ QButton::mousePressEvent( e );
+}
+
+/*!
+ \reimp
+*/
+bool QToolButton::eventFilter( QObject *o, QEvent *e )
+{
+#ifndef QT_NO_POPUPMENU
+ if ( o != d->popup )
+ return QButton::eventFilter( o, e );
+ switch ( e->type() ) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ {
+ QMouseEvent *me = (QMouseEvent*)e;
+ QPoint p = me->globalPos();
+ if ( QApplication::widgetAt( p, TRUE ) == this )
+ d->discardNextMouseEvent = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+ return QButton::eventFilter( o, e );
+}
+
+/*!
+ Returns TRUE if this button should be drawn using raised edges;
+ otherwise returns FALSE.
+
+ \sa drawButton()
+*/
+
+bool QToolButton::uses3D() const
+{
+ return style().styleHint(QStyle::SH_ToolButton_Uses3D)
+ && (!autoRaise() || ( hasMouse() && isEnabled() )
+#ifndef QT_NO_POPUPMENU
+ || ( d->popup && d->popup->isVisible() && d->delay <= 0 ) || d->instantPopup
+#endif
+ );
+}
+
+
+/*!
+ \property QToolButton::textLabel
+ \brief the label of this button.
+
+ Setting this property automatically sets the text as a tool tip
+ too. There is no default text.
+*/
+
+void QToolButton::setTextLabel( const QString &newLabel )
+{
+ setTextLabel( newLabel, TRUE );
+}
+
+/*!
+ \overload
+
+ Sets the label of this button to \a newLabel and automatically
+ sets it as a tool tip if \a tipToo is TRUE.
+*/
+
+void QToolButton::setTextLabel( const QString &newLabel , bool tipToo )
+{
+ if ( tl == newLabel )
+ return;
+
+#ifndef QT_NO_TOOLTIP
+ if ( tipToo ) {
+ QToolTip::remove( this );
+ QToolTip::add( this, newLabel );
+ }
+#endif
+
+ tl = newLabel;
+ if ( usesTextLabel() && isVisible() ) {
+ update();
+ updateGeometry();
+ }
+
+}
+
+#ifndef QT_NO_COMPAT
+
+QIconSet QToolButton::onIconSet() const
+{
+ return iconSet();
+}
+
+QIconSet QToolButton::offIconSet( ) const
+{
+ return iconSet();
+}
+
+
+/*!
+ \property QToolButton::onIconSet
+ \brief the icon set that is used when the button is in an "on" state
+
+ \obsolete
+
+ Since Qt 3.0, QIconSet contains both the On and Off icons. There is
+ now an \l QToolButton::iconSet property that replaces both \l
+ QToolButton::onIconSet and \l QToolButton::offIconSet.
+
+ For ease of porting, this property is a synonym for \l
+ QToolButton::iconSet. You probably want to go over your application
+ code and use the QIconSet On/Off mechanism.
+
+ \sa iconSet QIconSet::State
+*/
+void QToolButton::setOnIconSet( const QIconSet& set )
+{
+ setIconSet( set );
+ /*
+ ### Get rid of all qWarning in this file in 4.0.
+ Also consider inlining the obsolete functions then.
+ */
+ qWarning( "QToolButton::setOnIconSet(): This function is not supported"
+ " anymore" );
+}
+
+/*!
+ \property QToolButton::offIconSet
+ \brief the icon set that is used when the button is in an "off" state
+
+ \obsolete
+
+ Since Qt 3.0, QIconSet contains both the On and Off icons. There is
+ now an \l QToolButton::iconSet property that replaces both \l
+ QToolButton::onIconSet and \l QToolButton::offIconSet.
+
+ For ease of porting, this property is a synonym for \l
+ QToolButton::iconSet. You probably want to go over your application
+ code and use the QIconSet On/Off mechanism.
+
+ \sa iconSet QIconSet::State
+*/
+void QToolButton::setOffIconSet( const QIconSet& set )
+{
+ setIconSet( set );
+}
+
+#endif
+
+/*! \property QToolButton::pixmap
+ \brief the pixmap of the button
+
+ The pixmap property has no meaning for tool buttons. Use the
+ iconSet property instead.
+*/
+
+/*!
+ \property QToolButton::iconSet
+ \brief the icon set providing the icon shown on the button
+
+ Setting this property sets \l QToolButton::pixmap to a null
+ pixmap. There is no default iconset.
+
+ \sa pixmap(), setToggleButton(), isOn()
+*/
+void QToolButton::setIconSet( const QIconSet & set )
+{
+ if ( s )
+ delete s;
+ setPixmap( QPixmap() );
+ s = new QIconSet( set );
+ if ( isVisible() )
+ update();
+}
+
+/*! \overload
+ \obsolete
+
+ Since Qt 3.0, QIconSet contains both the On and Off icons.
+
+ For ease of porting, this function ignores the \a on parameter and
+ sets the \l iconSet property. If you relied on the \a on parameter,
+ you probably want to update your code to use the QIconSet On/Off
+ mechanism.
+
+ \sa iconSet QIconSet::State
+*/
+
+#ifndef QT_NO_COMPAT
+
+void QToolButton::setIconSet( const QIconSet & set, bool /* on */ )
+{
+ setIconSet( set );
+ qWarning( "QToolButton::setIconSet(): 'on' parameter ignored" );
+}
+
+#endif
+
+QIconSet QToolButton::iconSet() const
+{
+ QToolButton *that = (QToolButton *) this;
+
+ if ( pixmap() && !pixmap()->isNull() &&
+ (!that->s || (that->s->pixmap().serialNumber() !=
+ pixmap()->serialNumber())) ) {
+ if ( that->s )
+ delete that->s;
+ that->s = new QIconSet( *pixmap() );
+ }
+ if ( that->s )
+ return *that->s;
+ /*
+ In 2.x, we used to return a temporary nonnull QIconSet. If you
+ revert to the old behavior, you will break calls to
+ QIconSet::isNull() in this file.
+ */
+ return QIconSet();
+}
+
+#ifndef QT_NO_COMPAT
+/*! \overload
+ \obsolete
+
+ Since Qt 3.0, QIconSet contains both the On and Off icons.
+
+ For ease of porting, this function ignores the \a on parameter and
+ returns the \l iconSet property. If you relied on the \a on
+ parameter, you probably want to update your code to use the QIconSet
+ On/Off mechanism.
+*/
+QIconSet QToolButton::iconSet( bool /* on */ ) const
+{
+ return iconSet();
+}
+
+#endif
+
+#ifndef QT_NO_POPUPMENU
+/*!
+ Associates the popup menu \a popup with this tool button.
+
+ The popup will be shown each time the tool button has been pressed
+ down for a certain amount of time. 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.
+
+ Ownership of the popup menu is not transferred to the tool button.
+
+ \sa popup()
+*/
+void QToolButton::setPopup( QPopupMenu* popup )
+{
+ if ( popup && !d->popupTimer ) {
+ connect( this, SIGNAL( pressed() ), this, SLOT( popupPressed() ) );
+ d->popupTimer = new QTimer( this );
+ connect( d->popupTimer, SIGNAL( timeout() ), this, SLOT( popupTimerDone() ) );
+ }
+ d->popup = popup;
+
+ update();
+}
+
+/*!
+ Returns the associated popup menu, or 0 if no popup menu has been
+ defined.
+
+ \sa setPopup()
+*/
+QPopupMenu* QToolButton::popup() const
+{
+ return d->popup;
+}
+
+/*!
+ Opens (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::openPopup()
+{
+ if ( !d->popup )
+ return;
+
+ d->instantPopup = TRUE;
+ repaint( FALSE );
+ if ( d->popupTimer )
+ d->popupTimer->stop();
+ QGuardedPtr<QToolButton> that = this;
+ popupTimerDone();
+ if ( !that )
+ return;
+ d->instantPopup = FALSE;
+ repaint( FALSE );
+}
+
+void QToolButton::popupPressed()
+{
+ if ( d->popupTimer && d->delay > 0 )
+ d->popupTimer->start( d->delay, TRUE );
+}
+
+void QToolButton::popupTimerDone()
+{
+ if ( (!isDown() && d->delay > 0 ) || !d->popup )
+ return;
+
+ d->popup->installEventFilter( this );
+ d->repeat = autoRepeat();
+ setAutoRepeat( FALSE );
+ bool horizontal = TRUE;
+#ifndef QT_NO_TOOLBAR
+ QToolBar *tb = ::qt_cast<QToolBar*>(parentWidget());
+ if ( tb && tb->orientation() == Vertical )
+ horizontal = FALSE;
+#endif
+ QPoint p;
+ QRect screen = qApp->desktop()->availableGeometry( this );
+ if ( horizontal ) {
+ if ( QApplication::reverseLayout() ) {
+ if ( mapToGlobal( QPoint( 0, rect().bottom() ) ).y() + d->popup->sizeHint().height() <= screen.height() ) {
+ p = mapToGlobal( rect().bottomRight() );
+ } else {
+ p = mapToGlobal( rect().topRight() - QPoint( 0, d->popup->sizeHint().height() ) );
+ }
+ p.rx() -= d->popup->sizeHint().width();
+ } else {
+ if ( mapToGlobal( QPoint( 0, rect().bottom() ) ).y() + d->popup->sizeHint().height() <= screen.height() ) {
+ p = mapToGlobal( rect().bottomLeft() );
+ } else {
+ p = mapToGlobal( rect().topLeft() - QPoint( 0, d->popup->sizeHint().height() ) );
+ }
+ }
+ } else {
+ if ( QApplication::reverseLayout() ) {
+ if ( mapToGlobal( QPoint( rect().left(), 0 ) ).x() - d->popup->sizeHint().width() <= screen.x() ) {
+ p = mapToGlobal( rect().topRight() );
+ } else {
+ p = mapToGlobal( rect().topLeft() );
+ p.rx() -= d->popup->sizeHint().width();
+ }
+ } else {
+ if ( mapToGlobal( QPoint( rect().right(), 0 ) ).x() + d->popup->sizeHint().width() <= screen.width() ) {
+ p = mapToGlobal( rect().topRight() );
+ } else {
+ p = mapToGlobal( rect().topLeft() - QPoint( d->popup->sizeHint().width(), 0 ) );
+ }
+ }
+ }
+ QGuardedPtr<QToolButton> that = this;
+ d->popup->exec( p, -1 );
+ if ( !that )
+ return;
+
+ setDown( FALSE );
+ if ( d->repeat )
+ setAutoRepeat( TRUE );
+}
+
+/*!
+ \property QToolButton::popupDelay
+ \brief the time delay between pressing the button and the appearance of the associated popup menu in milliseconds.
+
+ Usually this is around half a second. A value of 0 draws the down
+ arrow button to the side of the button which can be used to open
+ up the popup menu.
+
+ \sa setPopup()
+*/
+void QToolButton::setPopupDelay( int delay )
+{
+ d->delay = delay;
+
+ update();
+}
+
+int QToolButton::popupDelay() const
+{
+ return d->delay;
+}
+#endif
+
+
+/*!
+ \property QToolButton::autoRaise
+ \brief whether auto-raising is enabled or not.
+
+ The default is disabled (i.e. FALSE).
+*/
+void QToolButton::setAutoRaise( bool enable )
+{
+ d->autoraise = enable;
+
+ update();
+}
+
+bool QToolButton::autoRaise() const
+{
+ return d->autoraise;
+}
+
+/*!
+ \property QToolButton::textPosition
+ \brief the position of the text label of this button.
+*/
+
+QToolButton::TextPosition QToolButton::textPosition() const
+{
+ return d->textPos;
+}
+
+void QToolButton::setTextPosition( TextPosition pos )
+{
+ d->textPos = pos;
+ updateGeometry();
+ update();
+}
+
+/*! \reimp */
+
+void QToolButton::setText( const QString &txt )
+{
+ QButton::setText( txt );
+ if ( !text().isEmpty() ) {
+ delete s;
+ s = 0;
+ }
+}
+
+#ifndef QT_NO_PALETTE
+/*!
+ \reimp
+*/
+void QToolButton::paletteChange( const QPalette & )
+{
+ if ( s )
+ s->clearGenerated();
+}
+#endif
+
+#endif
diff --git a/src/widgets/qtoolbutton.h b/src/widgets/qtoolbutton.h
new file mode 100644
index 0000000..0642360
--- /dev/null
+++ b/src/widgets/qtoolbutton.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Definition of QToolButton class
+**
+** Created : 979899
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTOOLBUTTON_H
+#define QTOOLBUTTON_H
+
+#ifndef QT_H
+#include "qbutton.h"
+#include "qstring.h"
+#include "qpixmap.h"
+#include "qiconset.h"
+#endif // QT_H
+
+#ifndef QT_NO_TOOLBUTTON
+
+class QToolButtonPrivate;
+class QToolBar;
+class QPopupMenu;
+
+class Q_EXPORT QToolButton : public QButton
+{
+ Q_OBJECT
+ Q_ENUMS( TextPosition )
+
+ Q_PROPERTY( QIconSet iconSet READ iconSet WRITE setIconSet )
+ Q_PROPERTY( QIconSet onIconSet READ onIconSet WRITE setOnIconSet DESIGNABLE false STORED false )
+ Q_PROPERTY( QIconSet offIconSet READ offIconSet WRITE setOffIconSet DESIGNABLE false STORED false )
+ Q_PROPERTY( bool usesBigPixmap READ usesBigPixmap WRITE setUsesBigPixmap )
+ Q_PROPERTY( bool usesTextLabel READ usesTextLabel WRITE setUsesTextLabel )
+ Q_PROPERTY( QString textLabel READ textLabel WRITE setTextLabel )
+ Q_PROPERTY( int popupDelay READ popupDelay WRITE setPopupDelay )
+ Q_PROPERTY( bool autoRaise READ autoRaise WRITE setAutoRaise )
+ Q_PROPERTY( TextPosition textPosition READ textPosition WRITE setTextPosition )
+
+ Q_OVERRIDE( bool toggleButton WRITE setToggleButton )
+ Q_OVERRIDE( bool on WRITE setOn )
+ Q_OVERRIDE( QPixmap pixmap DESIGNABLE false STORED false )
+ Q_OVERRIDE( BackgroundMode backgroundMode DESIGNABLE true)
+
+public:
+ enum TextPosition {
+ BesideIcon,
+ BelowIcon,
+ Right = BesideIcon, // obsolete
+ Under = BelowIcon // obsolete
+ };
+ QToolButton( QWidget * parent, const char* name=0 );
+#ifndef QT_NO_TOOLBAR
+ QToolButton( const QIconSet& s, const QString &textLabel,
+ const QString& grouptext,
+ QObject * receiver, const char* slot,
+ QToolBar * parent, const char* name=0 );
+#endif
+ QToolButton( ArrowType type, QWidget *parent, const char* name=0 );
+ ~QToolButton();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+#ifndef QT_NO_COMPAT
+ void setOnIconSet( const QIconSet& );
+ void setOffIconSet( const QIconSet& );
+ void setIconSet( const QIconSet &, bool on );
+ QIconSet onIconSet() const;
+ QIconSet offIconSet( ) const;
+ QIconSet iconSet( bool on ) const;
+#endif
+ virtual void setIconSet( const QIconSet & );
+ QIconSet iconSet() const;
+
+ bool usesBigPixmap() const { return ubp; }
+ bool usesTextLabel() const { return utl; }
+ QString textLabel() const { return tl; }
+
+#ifndef QT_NO_POPUPMENU
+ void setPopup( QPopupMenu* popup );
+ QPopupMenu* popup() const;
+
+ void setPopupDelay( int delay );
+ int popupDelay() const;
+
+ void openPopup();
+#endif
+
+ void setAutoRaise( bool enable );
+ bool autoRaise() const;
+ TextPosition textPosition() const;
+
+ void setText( const QString &txt );
+
+public slots:
+ virtual void setUsesBigPixmap( bool enable );
+ virtual void setUsesTextLabel( bool enable );
+ virtual void setTextLabel( const QString &, bool );
+
+ virtual void setToggleButton( bool enable );
+
+ virtual void setOn( bool enable );
+ void toggle();
+ void setTextLabel( const QString & );
+ void setTextPosition( TextPosition pos );
+
+protected:
+ void mousePressEvent( QMouseEvent * );
+ void drawButton( QPainter * );
+ void drawButtonLabel(QPainter *);
+
+ void enterEvent( QEvent * );
+ void leaveEvent( QEvent * );
+ void moveEvent( QMoveEvent * );
+
+ // ### Make virtual in 4.0, maybe act like QPushButton with
+ // regards to setFlat() instead? Andy
+ bool uses3D() const;
+#if (QT_VERSION >= 0x040000)
+#error "Some functions need to be changed to virtual for Qt 4.0"
+#endif
+
+ bool eventFilter( QObject *o, QEvent *e );
+
+#ifndef QT_NO_PALETTE
+ void paletteChange( const QPalette & );
+#endif
+
+private slots:
+ void popupTimerDone();
+ void popupPressed();
+
+private:
+ void init();
+
+ QPixmap bp;
+ int bpID;
+ QPixmap sp;
+ int spID;
+
+ QString tl;
+
+ QToolButtonPrivate *d;
+ QIconSet *s;
+
+ uint utl : 1;
+ uint ubp : 1;
+ uint hasArrow : 1;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QToolButton( const QToolButton & );
+ QToolButton& operator=( const QToolButton & );
+#endif
+};
+
+#endif // QT_NO_TOOLBUTTON
+
+#endif // QTOOLBUTTON_H
diff --git a/src/widgets/qtooltip.cpp b/src/widgets/qtooltip.cpp
new file mode 100644
index 0000000..c327859
--- /dev/null
+++ b/src/widgets/qtooltip.cpp
@@ -0,0 +1,1270 @@
+/****************************************************************************
+**
+** Tool Tips (or Balloon Help) for any widget or rectangle
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qtooltip.h"
+#ifndef QT_NO_TOOLTIP
+#include "qlabel.h"
+#include "qptrdict.h"
+#include "qapplication.h"
+#include "qguardedptr.h"
+#include "qtimer.h"
+#include "qeffects_p.h"
+
+static bool globally_enabled = TRUE;
+
+// Magic value meaning an entire widget - if someone tries to insert a
+// tool tip on this part of a widget it will be interpreted as the
+// entire widget.
+
+static inline QRect entireWidget()
+{
+ return QRect( -QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX,
+ 2*QWIDGETSIZE_MAX, 2*QWIDGETSIZE_MAX );
+}
+
+// Internal class - don't touch
+
+class QTipLabel : public QLabel
+{
+ Q_OBJECT
+public:
+ QTipLabel( QWidget* parent, const QString& text) : QLabel( parent, "toolTipTip",
+ WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM )
+ {
+ setMargin(1);
+ setAutoMask( FALSE );
+ setFrameStyle( QFrame::Plain | QFrame::Box );
+ setLineWidth( 1 );
+ setAlignment( AlignAuto | AlignTop );
+ setIndent(0);
+ polish();
+ setText(text);
+ adjustSize();
+ x11SetWindowType( X11WindowTypeTooltip );
+ }
+ void setWidth( int w ) { resize( sizeForWidth( w ) ); }
+};
+
+// Internal class - don't touch
+
+class QTipManager : public QObject
+{
+ Q_OBJECT
+public:
+ QTipManager();
+ ~QTipManager();
+
+ struct Tip
+ {
+ QRect rect;
+ QString text;
+ QString groupText;
+ QToolTipGroup *group;
+ QToolTip *tip;
+ bool autoDelete;
+ QRect geometry;
+ Tip *next;
+ };
+
+ bool eventFilter( QObject * o, QEvent * e );
+ void add( const QRect &gm, QWidget *, const QRect &, const QString& ,
+ QToolTipGroup *, const QString& , QToolTip *, bool );
+ void add( QWidget *, const QRect &, const QString& ,
+ QToolTipGroup *, const QString& , QToolTip *, bool );
+ void remove( QWidget *, const QRect &, bool delayhide = FALSE );
+ void remove( QWidget * );
+
+ void removeFromGroup( QToolTipGroup * );
+
+ void hideTipAndSleep();
+
+ QString find( QWidget *, const QPoint& );
+ void setWakeUpDelay(int);
+
+public slots:
+ void hideTip();
+
+private slots:
+ void labelDestroyed();
+ void clientWidgetDestroyed();
+ void showTip();
+ void allowAnimation();
+
+private:
+ QTimer wakeUp;
+ int wakeUpDelay;
+ QTimer fallAsleep;
+
+ QPtrDict<Tip> *tips;
+ QTipLabel *label;
+ QPoint pos;
+ QGuardedPtr<QWidget> widget;
+ Tip *currentTip;
+ Tip *previousTip;
+ bool preventAnimation;
+ bool isApplicationFilter;
+ QTimer *removeTimer;
+};
+
+
+// We have a global, internal QTipManager object
+
+static QTipManager *tipManager = 0;
+
+static void initTipManager()
+{
+ if ( !tipManager ) {
+ tipManager = new QTipManager;
+ Q_CHECK_PTR( tipManager );
+ }
+}
+
+
+QTipManager::QTipManager()
+ : QObject( qApp, "toolTipManager" )
+{
+ wakeUpDelay = 700;
+ tips = new QPtrDict<QTipManager::Tip>( 313 );
+ currentTip = 0;
+ previousTip = 0;
+ label = 0;
+ preventAnimation = FALSE;
+ isApplicationFilter = FALSE;
+ connect( &wakeUp, SIGNAL(timeout()), SLOT(showTip()) );
+ connect( &fallAsleep, SIGNAL(timeout()), SLOT(hideTip()) );
+ removeTimer = new QTimer( this );
+}
+
+
+QTipManager::~QTipManager()
+{
+ if ( isApplicationFilter && !qApp->closingDown() ) {
+ qApp->setGlobalMouseTracking( FALSE );
+ qApp->removeEventFilter( tipManager );
+ }
+
+ delete label;
+ label = 0;
+
+ if ( tips ) {
+ QPtrDictIterator<QTipManager::Tip> i( *tips );
+ QTipManager::Tip *t, *n;
+ void *k;
+ while( (t = i.current()) != 0 ) {
+ k = i.currentKey();
+ ++i;
+ tips->take( k );
+ while ( t ) {
+ n = t->next;
+ delete t;
+ t = n;
+ }
+ }
+ delete tips;
+ }
+
+ tipManager = 0;
+}
+
+void QTipManager::add( const QRect &gm, QWidget *w,
+ const QRect &r, const QString &s,
+ QToolTipGroup *g, const QString& gs,
+ QToolTip *tt, bool a )
+{
+ remove( w, r, TRUE );
+ QTipManager::Tip *h = (*tips)[ w ];
+ QTipManager::Tip *t = new QTipManager::Tip;
+ t->next = h;
+ t->tip = tt;
+ t->autoDelete = a;
+ t->text = s;
+ t->rect = r;
+ t->groupText = gs;
+ t->group = g;
+ t->geometry = gm;
+
+ if ( h ) {
+ tips->take( w );
+ if ( h != currentTip && h->autoDelete ) {
+ t->next = h->next;
+ delete h;
+ }
+ } else
+ connect( w, SIGNAL(destroyed()), this, SLOT(clientWidgetDestroyed()) );
+
+ tips->insert( w, t );
+
+ if ( a && t->rect.contains( pos ) && (!g || g->enabled()) ) {
+ removeTimer->stop();
+ showTip();
+ }
+
+ if ( !isApplicationFilter && qApp ) {
+ isApplicationFilter = TRUE;
+ qApp->installEventFilter( tipManager );
+ qApp->setGlobalMouseTracking( TRUE );
+ }
+
+ if ( t->group ) {
+ disconnect( removeTimer, SIGNAL( timeout() ),
+ t->group, SIGNAL( removeTip() ) );
+ connect( removeTimer, SIGNAL( timeout() ),
+ t->group, SIGNAL( removeTip() ) );
+ }
+}
+
+void QTipManager::add( QWidget *w, const QRect &r, const QString &s,
+ QToolTipGroup *g, const QString& gs,
+ QToolTip *tt, bool a )
+{
+ add( QRect( -1, -1, -1, -1 ), w, r, s, g, gs, tt, a );
+}
+
+
+void QTipManager::remove( QWidget *w, const QRect & r, bool delayhide )
+{
+ QTipManager::Tip *t = (*tips)[ w ];
+ if ( t == 0 )
+ return;
+
+ if ( t == currentTip )
+ if (!delayhide)
+ hideTip();
+ else
+ currentTip->autoDelete = TRUE;
+
+ if ( t == previousTip )
+ previousTip = 0;
+
+ if ( ( currentTip != t || !delayhide ) && t->rect == r ) {
+ tips->take( w );
+ if ( t->next )
+ tips->insert( w, t->next );
+ delete t;
+ } else {
+ while( t->next && t->next->rect != r && ( currentTip != t->next || !delayhide ))
+ t = t->next;
+ if ( t->next ) {
+ QTipManager::Tip *d = t->next;
+ t->next = t->next->next;
+ delete d;
+ }
+ }
+
+ if ( (*tips)[ w ] == 0 )
+ disconnect( w, SIGNAL(destroyed()), this, SLOT(clientWidgetDestroyed()) );
+#if 0 // not needed, leads sometimes to crashes
+ if ( tips->isEmpty() ) {
+ // the manager will be recreated if needed
+ delete tipManager;
+ tipManager = 0;
+ }
+#endif
+}
+
+
+/*
+ The label was destroyed in the program cleanup phase.
+*/
+
+void QTipManager::labelDestroyed()
+{
+ label = 0;
+}
+
+
+/*
+ Remove sender() from the tool tip data structures.
+*/
+
+void QTipManager::clientWidgetDestroyed()
+{
+ const QObject *s = sender();
+ if ( s )
+ remove( (QWidget*) s );
+}
+
+
+void QTipManager::remove( QWidget *w )
+{
+ QTipManager::Tip *t = (*tips)[ w ];
+ if ( t == 0 )
+ return;
+
+ tips->take( w );
+ QTipManager::Tip * d;
+ while ( t ) {
+ if ( t == currentTip )
+ hideTip();
+ d = t->next;
+ delete t;
+ t = d;
+ }
+
+ disconnect( w, SIGNAL(destroyed()), this, SLOT(clientWidgetDestroyed()) );
+#if 0
+ if ( tips->isEmpty() ) {
+ delete tipManager;
+ tipManager = 0;
+ }
+#endif
+}
+
+
+void QTipManager::removeFromGroup( QToolTipGroup *g )
+{
+ QPtrDictIterator<QTipManager::Tip> i( *tips );
+ QTipManager::Tip *t;
+ while( (t = i.current()) != 0 ) {
+ ++i;
+ while ( t ) {
+ if ( t->group == g ) {
+ if ( t->group )
+ disconnect( removeTimer, SIGNAL( timeout() ),
+ t->group, SIGNAL( removeTip() ) );
+ t->group = 0;
+ }
+ t = t->next;
+ }
+ }
+}
+
+
+
+bool QTipManager::eventFilter( QObject *obj, QEvent *e )
+{
+ // avoid dumping core in case of application madness, and return
+ // quickly for some common but irrelevant events
+ if ( e->type() == QEvent::WindowDeactivate &&
+ qApp && !qApp->activeWindow() &&
+ label && label->isVisible() )
+ hideTipAndSleep();
+
+ if ( !qApp
+ || !obj || !obj->isWidgetType() // isWidgetType() catches most stuff
+ || e->type() == QEvent::Paint
+ || e->type() == QEvent::Timer
+ || e->type() == QEvent::SockAct
+ || !tips )
+ return FALSE;
+ QWidget *w = (QWidget *)obj;
+
+ if ( e->type() == QEvent::FocusOut || e->type() == QEvent::FocusIn ) {
+ // user moved focus somewhere - hide the tip and sleep
+ if ( ((QFocusEvent*)e)->reason() != QFocusEvent::Popup )
+ hideTipAndSleep();
+ return FALSE;
+ }
+
+ QTipManager::Tip *t = 0;
+ while( w && !t ) {
+ t = (*tips)[ w ];
+ if ( !t )
+ w = w->isTopLevel() ? 0 : w->parentWidget();
+ }
+ if ( !w )
+ return FALSE;
+
+ if ( !t && e->type() != QEvent::MouseMove) {
+ if ( ( e->type() >= QEvent::MouseButtonPress &&
+ e->type() <= QEvent::FocusOut) || e->type() == QEvent::Leave )
+ hideTip();
+ return FALSE;
+ }
+
+ // with that out of the way, let's get down to action
+
+ switch( e->type() ) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ // input - turn off tool tip mode
+ hideTipAndSleep();
+ break;
+ case QEvent::MouseMove:
+ {
+ QMouseEvent * m = (QMouseEvent *)e;
+ QPoint mousePos = w->mapFromGlobal( m->globalPos() );
+
+ if ( currentTip && !currentTip->rect.contains( mousePos ) ) {
+ hideTip();
+ if ( m->state() == 0 )
+ return FALSE;
+ }
+
+ wakeUp.stop();
+ if ( m->state() == 0 &&
+ mousePos.x() >= 0 && mousePos.x() < w->width() &&
+ mousePos.y() >= 0 && mousePos.y() < w->height() ) {
+ if ( label && label->isVisible() ) {
+ return FALSE;
+ } else {
+ if ( fallAsleep.isActive() ) {
+ wakeUp.start( 1, TRUE );
+ } else {
+ previousTip = 0;
+ wakeUp.start( wakeUpDelay, TRUE );
+ }
+ if ( t->group && t->group->ena &&
+ !t->group->del && !t->groupText.isEmpty() ) {
+ removeTimer->stop();
+ emit t->group->showTip( t->groupText );
+ currentTip = t;
+ }
+ }
+ widget = w;
+ pos = mousePos;
+ return FALSE;
+ } else {
+ hideTip();
+ }
+ }
+ break;
+ case QEvent::Leave:
+ case QEvent::Hide:
+ case QEvent::Destroy:
+ if ( w == widget )
+ hideTip();
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+
+
+void QTipManager::showTip()
+{
+ if ( !widget || !globally_enabled
+#ifndef Q_WS_X11
+ || !widget->isActiveWindow()
+#endif
+ )
+ return;
+
+ QTipManager::Tip *t = (*tips)[ widget ];
+ while ( t && !t->rect.contains( pos ) )
+ t = t->next;
+ if ( t == 0 )
+ return;
+
+ if ( t == currentTip && label && label->isVisible() )
+ return; // nothing to do
+
+ if ( t->tip ) {
+ t->tip->maybeTip( pos );
+ return;
+ }
+
+ if ( t->group && !t->group->ena )
+ return;
+
+ int scr;
+ if ( QApplication::desktop()->isVirtualDesktop() )
+ scr = QApplication::desktop()->screenNumber( widget->mapToGlobal( pos ) );
+ else
+ scr = QApplication::desktop()->screenNumber( widget );
+
+ if ( label
+#if defined(Q_WS_X11)
+ && label->x11Screen() == widget->x11Screen()
+#endif
+ ) {
+ // the next two lines are a workaround for QLabel being too intelligent.
+ // QLabel turns on the wordbreak flag once it gets a richtext. The two lines below
+ // ensure we get correct textflags when switching back and forth between a richtext and
+ // non richtext tooltip
+ label->setText( "" );
+ label->setAlignment( AlignAuto | AlignTop );
+ label->setText( t->text );
+ label->adjustSize();
+ if ( t->geometry != QRect( -1, -1, -1, -1 ) )
+ label->resize( t->geometry.size() );
+ } else {
+ delete label;
+ label = new QTipLabel( QApplication::desktop()->screen( scr ), t->text);
+ if ( t->geometry != QRect( -1, -1, -1, -1 ) )
+ label->resize( t->geometry.size() );
+ Q_CHECK_PTR( label );
+ connect( label, SIGNAL(destroyed()), SLOT(labelDestroyed()) );
+ }
+ // the above deletion and creation of a QTipLabel causes events to be sent. We had reports that the widget
+ // pointer was 0 after this. This is in principle possible if the wrong kind of events get sent through our event
+ // filter in this time. So better be safe and check widget once again here.
+ if (!widget)
+ return;
+
+#ifdef Q_WS_X11
+ label->x11SetWindowTransient( widget->topLevelWidget());
+#endif
+
+#ifdef Q_WS_MAC
+ QRect screen = QApplication::desktop()->availableGeometry( scr );
+#else
+ QRect screen = QApplication::desktop()->screenGeometry( scr );
+#endif
+ QPoint p;
+ if ( t->geometry == QRect( -1, -1, -1, -1 ) ) {
+ p = widget->mapToGlobal( pos ) +
+#ifdef Q_WS_WIN
+ QPoint( 2, 24 );
+#else
+ QPoint( 2, 16 );
+#endif
+ if ( p.x() + label->width() > screen.x() + screen.width() )
+ p.rx() -= 4 + label->width();
+ if ( p.y() + label->height() > screen.y() + screen.height() )
+ p.ry() -= 24 + label->height();
+ } else {
+ p = widget->mapToGlobal( t->geometry.topLeft() );
+ label->setAlignment( WordBreak | AlignCenter );
+ label->setWidth( t->geometry.width() - 4 );
+ }
+ if ( p.y() < screen.y() )
+ p.setY( screen.y() );
+ if ( p.x() + label->width() > screen.x() + screen.width() )
+ p.setX( screen.x() + screen.width() - label->width() );
+ if ( p.x() < screen.x() )
+ p.setX( screen.x() );
+ if ( p.y() + label->height() > screen.y() + screen.height() )
+ p.setY( screen.y() + screen.height() - label->height() );
+ if ( label->text().length() ) {
+ label->move( p );
+
+#ifndef QT_NO_EFFECTS
+ if ( QApplication::isEffectEnabled( UI_AnimateTooltip ) == FALSE ||
+ previousTip || preventAnimation )
+ label->show();
+ else if ( QApplication::isEffectEnabled( UI_FadeTooltip ) )
+ qFadeEffect( label );
+ else
+ qScrollEffect( label );
+#else
+ label->show();
+#endif
+
+ label->raise();
+ fallAsleep.start( 10000, TRUE );
+ }
+
+ if ( t->group && t->group->del && !t->groupText.isEmpty() ) {
+ removeTimer->stop();
+ emit t->group->showTip( t->groupText );
+ }
+
+ currentTip = t;
+ previousTip = 0;
+}
+
+
+void QTipManager::hideTip()
+{
+ QTimer::singleShot( 250, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ if ( label && label->isVisible() ) {
+ label->hide();
+ fallAsleep.start( 2000, TRUE );
+ wakeUp.stop();
+ if ( currentTip && currentTip->group )
+ removeTimer->start( 100, TRUE );
+ } else if ( wakeUp.isActive() ) {
+ wakeUp.stop();
+ if ( currentTip && currentTip->group &&
+ !currentTip->group->del && !currentTip->groupText.isEmpty() )
+ removeTimer->start( 100, TRUE );
+ } else if ( currentTip && currentTip->group ) {
+ removeTimer->start( 100, TRUE );
+ }
+
+ previousTip = currentTip;
+ currentTip = 0;
+ if ( previousTip && previousTip->autoDelete )
+ remove( widget, previousTip->rect );
+ widget = 0;
+}
+
+void QTipManager::hideTipAndSleep()
+{
+ hideTip();
+ fallAsleep.stop();
+}
+
+
+void QTipManager::allowAnimation()
+{
+ preventAnimation = FALSE;
+}
+
+QString QTipManager::find( QWidget *w, const QPoint& pos )
+{
+ Tip *t = (*tips)[ w ];
+ while ( t && !t->rect.contains( pos ) )
+ t = t->next;
+
+ return t ? t->text : QString::null;
+}
+
+void QTipManager::setWakeUpDelay ( int i )
+{
+ wakeUpDelay = i;
+}
+
+/*!
+ \class QToolTip qtooltip.h
+ \brief The QToolTip class provides tool tips (balloon help) for
+ any widget or rectangular part of a widget.
+
+ \ingroup helpsystem
+ \mainclass
+
+ The tip is a short, single line of text reminding the user of the
+ widget's or rectangle's function. It is drawn immediately below
+ the region in a distinctive black-on-yellow combination.
+
+ The tip can be any Rich-Text formatted string.
+
+ QToolTipGroup provides a way for tool tips to display another text
+ elsewhere (most often in a \link QStatusBar status bar\endlink).
+
+ At any point in time, QToolTip is either dormant or active. In
+ dormant mode the tips are not shown and in active mode they are.
+ The mode is global, not particular to any one widget.
+
+ QToolTip switches from dormant to active mode when the user hovers
+ the mouse on a tip-equipped region for a second or so and remains
+ active until the user either clicks a mouse button, presses a key,
+ lets the mouse hover for five seconds or moves the mouse outside
+ \e all tip-equipped regions for at least a second.
+
+ The QToolTip class can be used in three different ways:
+ \list 1
+ \i Adding a tip to an entire widget.
+ \i Adding a tip to a fixed rectangle within a widget.
+ \i Adding a tip to a dynamic rectangle within a widget.
+ \endlist
+
+ To add a tip to a widget, call the \e static function
+ QToolTip::add() with the widget and tip as arguments:
+
+ \code
+ QToolTip::add( quitButton, "Leave the application" );
+ \endcode
+
+ This is the simplest and most common use of QToolTip. The tip
+ will be deleted automatically when \e quitButton is deleted, but
+ you can remove it yourself, too:
+
+ \code
+ QToolTip::remove( quitButton );
+ \endcode
+
+ You can also display another text (typically in a \link QStatusBar
+ status bar),\endlink courtesy of \l{QToolTipGroup}. This example
+ assumes that \e grp is a \c{QToolTipGroup *} and is already
+ connected to the appropriate status bar:
+
+ \code
+ QToolTip::add( quitButton, "Leave the application", grp,
+ "Leave the application, prompting to save if necessary" );
+ QToolTip::add( closeButton, "Close this window", grp,
+ "Close this window, prompting to save if necessary" );
+ \endcode
+
+ To add a tip to a fixed rectangle within a widget, call the static
+ function QToolTip::add() with the widget, rectangle and tip as
+ arguments. (See the \c tooltip/tooltip.cpp example.) Again, you
+ can supply a \c{QToolTipGroup *} and another text if you want.
+
+ Both of these are one-liners and cover the majority of cases. The
+ third and most general way to use QToolTip requires you to
+ reimplement a pure virtual function to decide whether to pop up a
+ tool tip. The \c tooltip/tooltip.cpp example demonstrates this
+ too. This mode can be used to implement tips for text that can
+ move as the user scrolls, for example.
+
+ To use QToolTip like this, you must subclass QToolTip and
+ reimplement maybeTip(). QToolTip calls maybeTip() when a tip
+ should pop up, and maybeTip() decides whether to show a tip.
+
+ Tool tips can be globally disabled using
+ QToolTip::setGloballyEnabled() or disabled in groups with
+ QToolTipGroup::setEnabled().
+
+ You can retrieve the text of a tooltip for a given position within
+ a widget using textFor().
+
+ The global tooltip font and palette can be set with the static
+ setFont() and setPalette() functions respectively.
+
+ \sa QStatusBar QWhatsThis QToolTipGroup
+ \link guibooks.html#fowler GUI Design Handbook: Tool Tip\endlink
+*/
+
+
+/*!
+ Returns the font common to all tool tips.
+
+ \sa setFont()
+*/
+
+QFont QToolTip::font()
+{
+ QTipLabel l(0,"");
+ return QApplication::font( &l );
+}
+
+
+/*!
+ Sets the font for all tool tips to \a font.
+
+ \sa font()
+*/
+
+void QToolTip::setFont( const QFont &font )
+{
+ QApplication::setFont( font, TRUE, "QTipLabel" );
+}
+
+
+/*!
+ Returns the palette common to all tool tips.
+
+ \sa setPalette()
+*/
+
+QPalette QToolTip::palette()
+{
+ QTipLabel l(0,"");
+ return QApplication::palette( &l );
+}
+
+
+/*!
+ Sets the palette for all tool tips to \a palette.
+
+ \sa palette()
+*/
+
+void QToolTip::setPalette( const QPalette &palette )
+{
+ QApplication::setPalette( palette, TRUE, "QTipLabel" );
+}
+
+/*!
+ Constructs a tool tip object. This is only necessary if you need
+ tool tips on regions that can move within the widget (most often
+ because the widget's contents can scroll).
+
+ \a widget is the widget you want to add dynamic tool tips to and
+ \a group (optional) is the tool tip group they should belong to.
+
+ \warning QToolTip is not a subclass of QObject, so the instance of
+ QToolTip is not deleted when \a widget is deleted.
+
+ \warning If you delete the tool tip before you have deleted
+ \a widget then you need to make sure you call remove() yourself from
+ \a widget in your reimplemented QToolTip destructor.
+
+ \code
+ MyToolTip::~MyToolTip()
+ {
+ remove( widget );
+ }
+ \endcode
+
+ \sa maybeTip().
+*/
+
+QToolTip::QToolTip( QWidget * widget, QToolTipGroup * group )
+{
+ p = widget;
+ g = group;
+ initTipManager();
+ tipManager->add( p, entireWidget(),
+ QString::null, g, QString::null, this, FALSE );
+}
+
+
+/*!
+ Adds a tool tip to \a widget. \a text is the text to be shown in
+ the tool tip.
+
+ This is the most common entry point to the QToolTip class; it is
+ suitable for adding tool tips to buttons, checkboxes, comboboxes
+ and so on.
+*/
+
+void QToolTip::add( QWidget *widget, const QString &text )
+{
+ initTipManager();
+ tipManager->add( widget, entireWidget(),
+ text, 0, QString::null, 0, FALSE );
+}
+
+
+/*!
+ \overload
+
+ Adds a tool tip to \a widget and to tool tip group \a group.
+
+ \a text is the text shown in the tool tip and \a longText is the
+ text emitted from \a group.
+
+ Normally, \a longText is shown in a \link QStatusBar status
+ bar\endlink or similar.
+*/
+
+void QToolTip::add( QWidget *widget, const QString &text,
+ QToolTipGroup *group, const QString& longText )
+{
+ initTipManager();
+ tipManager->add( widget, entireWidget(), text, group, longText, 0, FALSE );
+}
+
+
+/*!
+ Removes the tool tip from \a widget.
+
+ If there is more than one tool tip on \a widget, only the one
+ covering the entire widget is removed.
+*/
+
+void QToolTip::remove( QWidget * widget )
+{
+ if ( tipManager )
+ tipManager->remove( widget, entireWidget() );
+}
+
+/*!
+ \overload
+
+ Adds a tool tip to a fixed rectangle, \a rect, within \a widget.
+ \a text is the text shown in the tool tip.
+*/
+
+void QToolTip::add( QWidget * widget, const QRect & rect, const QString &text )
+{
+ initTipManager();
+ tipManager->add( widget, rect, text, 0, QString::null, 0, FALSE );
+}
+
+
+/*!
+ \overload
+
+ Adds a tool tip to an entire \a widget and to tool tip group \a
+ group. The tooltip will disappear when the mouse leaves the \a
+ rect.
+
+ \a text is the text shown in the tool tip and \a groupText is the
+ text emitted from \a group.
+
+ Normally, \a groupText is shown in a \link QStatusBar status
+ bar\endlink or similar.
+*/
+
+void QToolTip::add( QWidget *widget, const QRect &rect,
+ const QString& text,
+ QToolTipGroup *group, const QString& groupText )
+{
+ initTipManager();
+ tipManager->add( widget, rect, text, group, groupText, 0, FALSE );
+}
+
+
+/*!
+ \overload
+
+ Removes any tool tip for \a rect from \a widget.
+
+ If there is more than one tool tip on \a widget, only the one
+ covering rectangle \a rect is removed.
+*/
+
+void QToolTip::remove( QWidget * widget, const QRect & rect )
+{
+ if ( tipManager )
+ tipManager->remove( widget, rect );
+}
+
+/*!
+ Returns the tool tip text for \a widget at position \a pos, or
+ QString::null if there is no tool tip for the given widget and
+ position.
+*/
+
+QString QToolTip::textFor( QWidget *widget, const QPoint& pos )
+{
+ if ( tipManager )
+ return tipManager->find( widget, pos );
+ return QString::null;
+}
+
+/*!
+ Hides any tip that is currently being shown.
+
+ Normally, there is no need to call this function; QToolTip takes
+ care of showing and hiding the tips as the user moves the mouse.
+*/
+
+void QToolTip::hide()
+{
+ if ( tipManager )
+ tipManager->hideTipAndSleep();
+}
+
+/*!
+ \fn virtual void QToolTip::maybeTip( const QPoint & p);
+
+ This pure virtual function is half of the most versatile interface
+ QToolTip offers.
+
+ It is called when there is a possibility that a tool tip should be
+ shown and must decide whether there is a tool tip for the point \a
+ p in the widget that this QToolTip object relates to. If so,
+ maybeTip() must call tip() with the rectangle the tip applies to,
+ the tip's text and optionally the QToolTipGroup details and the
+ geometry in screen coordinates.
+
+ \a p is given in that widget's local coordinates. Most maybeTip()
+ implementations will be of the form:
+
+ \code
+ if ( <something> ) {
+ tip( <something>, <something> );
+ }
+ \endcode
+
+ The first argument to tip() (a rectangle) must encompass \a p,
+ i.e. the tip must apply to the current mouse position; otherwise
+ QToolTip's operation is undefined.
+
+ Note that the tip will disappear once the mouse moves outside the
+ rectangle you give to tip(), and will not reappear if the mouse
+ moves back in: maybeTip() is called again instead.
+
+ \sa tip()
+*/
+
+
+/*!
+ Immediately pops up a tip saying \a text and removes the tip once
+ the cursor moves out of rectangle \a rect (which is given in the
+ coordinate system of the widget this QToolTip relates to).
+
+ The tip will not reappear if the cursor moves back; your
+ maybeTip() must reinstate it each time.
+*/
+
+void QToolTip::tip( const QRect & rect, const QString &text )
+{
+ initTipManager();
+ tipManager->add( parentWidget(), rect, text, 0, QString::null, 0, TRUE );
+}
+
+/*!
+ \overload
+
+ Immediately pops up a tip saying \a text and removes that tip once
+ the cursor moves out of rectangle \a rect (which is given in the
+ coordinate system of the widget this QToolTip relates to). \a
+ groupText is the text emitted from the group.
+
+ The tip will not reappear if the cursor moves back; your
+ maybeTip() must reinstate it each time.
+*/
+
+void QToolTip::tip( const QRect & rect, const QString &text,
+ const QString& groupText )
+{
+ initTipManager();
+ tipManager->add( parentWidget(), rect, text, group(), groupText, 0, TRUE );
+}
+
+/*!
+ \overload
+
+ Immediately pops up a tip within the rectangle \a geometry, saying
+ \a text and removes the tip once the cursor moves out of rectangle
+ \a rect. Both rectangles are given in the coordinate system of the
+ widget this QToolTip relates to.
+
+ The tip will not reappear if the cursor moves back; your
+ maybeTip() must reinstate it each time.
+
+ If the tip does not fit inside \a geometry, the tip expands.
+*/
+
+void QToolTip::tip( const QRect &rect, const QString &text, const QRect &geometry )
+{
+ initTipManager();
+ tipManager->add( geometry, parentWidget(), rect, text, 0, QString::null, 0, TRUE );
+}
+
+/*!
+ \overload
+
+ Immediately pops up a tip within the rectangle \a geometry, saying
+ \a text and removes the tip once the cursor moves out of rectangle
+ \a rect. \a groupText is the text emitted from the group. Both
+ rectangles are given in the coordinate system of the widget this
+ QToolTip relates to.
+
+ The tip will not reappear if the cursor moves back; your
+ maybeTip() must reinstate it each time.
+
+ If the tip does not fit inside \a geometry, the tip expands.
+*/
+
+void QToolTip::tip( const QRect &rect, const QString &text, const QString& groupText, const QRect &geometry )
+{
+ initTipManager();
+ tipManager->add( geometry, parentWidget(), rect, text, group(), groupText, 0, TRUE );
+}
+
+
+
+/*!
+ Immediately removes all tool tips for this tooltip's parent
+ widget.
+*/
+
+void QToolTip::clear()
+{
+ if ( tipManager )
+ tipManager->remove( parentWidget() );
+}
+
+
+/*!
+ \fn QWidget * QToolTip::parentWidget() const
+
+ Returns the widget this QToolTip applies to.
+
+ The tool tip is destroyed automatically when the parent widget is
+ destroyed.
+
+ \sa group()
+*/
+
+
+/*!
+ \fn QToolTipGroup * QToolTip::group() const
+
+ Returns the tool tip group this QToolTip is a member of or 0 if it
+ isn't a member of any group.
+
+ The tool tip group is the object responsible for maintaining
+ contact between tool tips and a \link QStatusBar status
+ bar\endlink or something else which can show the longer help text.
+
+ \sa parentWidget(), QToolTipGroup
+*/
+
+
+/*!
+ \class QToolTipGroup qtooltip.h
+ \brief The QToolTipGroup class collects tool tips into related groups.
+
+ \ingroup helpsystem
+
+ Tool tips can display \e two texts: one in the tip and
+ (optionally) one that is typically in a \link QStatusBar status
+ bar\endlink. QToolTipGroup provides a way to link tool tips to
+ this status bar.
+
+ QToolTipGroup has practically no API; it is only used as an
+ argument to QToolTip's member functions, for example like this:
+
+ \code
+ QToolTipGroup * grp = new QToolTipGroup( this, "tool tip relay" );
+ connect( grp, SIGNAL(showTip(const QString&)),
+ myLabel, SLOT(setText(const QString&)) );
+ connect( grp, SIGNAL(removeTip()),
+ myLabel, SLOT(clear()) );
+ QToolTip::add( giraffeButton, "feed giraffe",
+ grp, "Give the giraffe a meal" );
+ QToolTip::add( gorillaButton, "feed gorilla",
+ grp, "Give the gorilla a meal" );
+ \endcode
+
+ This example makes the object myLabel (which you must supply)
+ display (one assumes, though you can make myLabel do anything, of
+ course) the strings "Give the giraffe a meal" and "Give the
+ gorilla a meal" while the relevant tool tips are being displayed.
+
+ Deleting a tool tip group removes the tool tips in it.
+*/
+
+/*!
+ \fn void QToolTipGroup::showTip (const QString &longText)
+
+ This signal is emitted when one of the tool tips in the group is
+ displayed. \a longText is the extra text for the displayed tool
+ tip.
+
+ \sa removeTip()
+*/
+
+/*!
+ \fn void QToolTipGroup::removeTip ()
+
+ This signal is emitted when a tool tip in this group is hidden.
+ See the QToolTipGroup documentation for an example of use.
+
+ \sa showTip()
+*/
+
+
+/*!
+ Constructs a tool tip group called \a name, with parent \a parent.
+*/
+
+QToolTipGroup::QToolTipGroup( QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+ del = TRUE;
+ ena = TRUE;
+}
+
+
+/*!
+ Destroys this tool tip group and all tool tips in it.
+*/
+
+QToolTipGroup::~QToolTipGroup()
+{
+ if ( tipManager )
+ tipManager->removeFromGroup( this );
+}
+
+
+/*!
+ \property QToolTipGroup::delay
+ \brief whether the display of the group text is delayed.
+
+ If set to TRUE (the default), the group text is displayed at the
+ same time as the tool tip. Otherwise, the group text is displayed
+ immediately when the cursor enters the widget.
+*/
+
+bool QToolTipGroup::delay() const
+{
+ return del;
+}
+
+void QToolTipGroup::setDelay( bool enable )
+{
+#if 0
+ if ( enable && !del ) {
+ // maybe we should show the text at once?
+ }
+#endif
+ del = enable;
+}
+
+/*!
+ \fn static void QToolTip::setEnabled( bool enable )
+
+ \obsolete
+*/
+/*!
+ \fn static bool QToolTip::enabled()
+
+ \obsolete
+*/
+/*!
+ \property QToolTipGroup::enabled
+ \brief whether tool tips in the group are enabled.
+
+ This property's default is TRUE.
+*/
+
+void QToolTipGroup::setEnabled( bool enable )
+{
+ ena = enable;
+}
+
+bool QToolTipGroup::enabled() const
+{
+ return (bool)ena;
+}
+
+/*!
+ If \a enable is TRUE sets all tool tips to be enabled (shown when
+ needed); if \a enable is FALSE sets all tool tips to be disabled
+ (never shown).
+
+ By default, tool tips are enabled. Note that this function affects
+ all tool tips in the entire application.
+
+ \sa QToolTipGroup::setEnabled()
+*/
+
+void QToolTip::setGloballyEnabled( bool enable )
+{
+ globally_enabled = enable;
+}
+
+/*!
+ Returns whether tool tips are enabled globally.
+
+ \sa setGloballyEnabled()
+*/
+bool QToolTip::isGloballyEnabled()
+{
+ return globally_enabled;
+}
+
+/*!
+ Sets the wakeup delay for all tooltips to \a i
+ milliseconds.
+*/
+void QToolTip::setWakeUpDelay ( int i )
+{
+ initTipManager();
+ tipManager->setWakeUpDelay(i);
+}
+
+
+#include "qtooltip.moc"
+#endif
diff --git a/src/widgets/qtooltip.h b/src/widgets/qtooltip.h
new file mode 100644
index 0000000..2cd38c1
--- /dev/null
+++ b/src/widgets/qtooltip.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Definition of Tool Tips (or Balloon Help) for any widget or rectangle
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QTOOLTIP_H
+#define QTOOLTIP_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+
+#ifndef QT_NO_TOOLTIP
+
+#if __GNUC__ - 0 > 3
+#pragma GCC system_header
+#endif
+
+class QTipManager;
+class QIconViewToolTip;
+class QListViewToolTip;
+
+class Q_EXPORT QToolTipGroup: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY( bool delay READ delay WRITE setDelay )
+ Q_PROPERTY( bool enabled READ enabled WRITE setEnabled )
+
+public:
+ QToolTipGroup( QObject *parent, const char *name = 0 );
+ ~QToolTipGroup();
+
+ bool delay() const;
+ bool enabled() const;
+
+public slots:
+ void setDelay( bool );
+ void setEnabled( bool );
+
+signals:
+ void showTip( const QString &);
+ void removeTip();
+
+private:
+ uint del:1;
+ uint ena:1;
+
+ friend class QTipManager;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QToolTipGroup( const QToolTipGroup & );
+ QToolTipGroup& operator=( const QToolTipGroup & );
+#endif
+};
+
+
+class Q_EXPORT QToolTip: public Qt
+{
+public:
+ QToolTip( QWidget *, QToolTipGroup * = 0 );
+ //### add virtual d'tor for 4.0
+
+ static void add( QWidget *, const QString &);
+ static void add( QWidget *, const QString &,
+ QToolTipGroup *, const QString& );
+ static void remove( QWidget * );
+
+ static void add( QWidget *, const QRect &, const QString &);
+ static void add( QWidget *, const QRect &, const QString &,
+ QToolTipGroup *, const QString& );
+ static void remove( QWidget *, const QRect & );
+
+ static QString textFor( QWidget *, const QPoint & pos = QPoint() );
+
+ static void hide();
+
+ static QFont font();
+ static void setFont( const QFont & );
+ static QPalette palette();
+ static void setPalette( const QPalette & );
+
+#ifndef QT_NO_COMPAT
+ static void setEnabled( bool enable ) { setGloballyEnabled( enable ); }
+ static bool enabled() { return isGloballyEnabled(); }
+#endif
+ static void setGloballyEnabled( bool );
+ static bool isGloballyEnabled();
+ static void setWakeUpDelay(int);
+
+protected:
+ virtual void maybeTip( const QPoint & ) = 0;
+ void tip( const QRect &, const QString &);
+ void tip( const QRect &, const QString& , const QString &);
+ void tip( const QRect &, const QString &, const QRect & );
+ void tip( const QRect &, const QString&, const QString &, const QRect &);
+
+ void clear();
+
+public:
+ QWidget *parentWidget() const { return p; }
+ QToolTipGroup *group() const { return g; }
+
+private:
+ QWidget *p;
+ QToolTipGroup *g;
+ static QFont *ttFont;
+ static QPalette *ttPalette;
+
+ friend class QTipManager;
+};
+
+
+#endif // QT_NO_TOOLTIP
+
+#endif // QTOOLTIP_H
diff --git a/src/widgets/qvalidator.cpp b/src/widgets/qvalidator.cpp
new file mode 100644
index 0000000..cc0eea4
--- /dev/null
+++ b/src/widgets/qvalidator.cpp
@@ -0,0 +1,672 @@
+/****************************************************************************
+**
+** Implementation of validator classes
+**
+** Created : 970610
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qvalidator.h"
+#ifndef QT_NO_VALIDATOR
+
+#include <limits.h>
+#include <math.h>
+
+/*!
+ \class QValidator
+ \brief The QValidator class provides validation of input text.
+
+ \ingroup misc
+ \mainclass
+
+ The class itself is abstract. Two subclasses, \l QIntValidator and
+ \l QDoubleValidator, provide basic numeric-range checking, and \l
+ QRegExpValidator provides general checking using a custom regular
+ expression.
+
+ If the built-in validators aren't sufficient, you can subclass
+ QValidator. The class has two virtual functions: validate() and
+ fixup().
+
+ \l validate() must be implemented by every subclass. It returns
+ \c Invalid, \c Intermediate or \c Acceptable depending on whether
+ its argument is valid (for the subclass's definition of valid).
+
+ These three states require some explanation. An \c Invalid string
+ is \e clearly invalid. \c Intermediate is less obvious: the
+ concept of validity is slippery when the string is incomplete
+ (still being edited). QValidator defines \c Intermediate as the
+ property of a string that is neither clearly invalid nor
+ acceptable as a final result. \c Acceptable means that the string
+ is acceptable as a final result. One might say that any string
+ that is a plausible intermediate state during entry of an \c
+ Acceptable string is \c Intermediate.
+
+ Here are some examples:
+
+ \list
+
+ \i For a line edit that accepts integers from 0 to 999 inclusive,
+ 42 and 123 are \c Acceptable, the empty string and 1114 are \c
+ Intermediate and asdf is \c Invalid.
+
+ \i For an editable combobox that accepts URLs, any well-formed URL
+ is \c Acceptable, "http://www.trolltech.com/," is \c Intermediate
+ (it might be a cut and paste operation that accidentally took in a
+ comma at the end), the empty string is \c Intermediate (the user
+ might select and delete all of the text in preparation for entering
+ a new URL), and "http:///./" is \c Invalid.
+
+ \i For a spin box that accepts lengths, "11cm" and "1in" are \c
+ Acceptable, "11" and the empty string are \c Intermediate and
+ "http://www.trolltech.com" and "hour" are \c Invalid.
+
+ \endlist
+
+ \l fixup() is provided for validators that can repair some user
+ errors. The default implementation does nothing. QLineEdit, for
+ example, will call fixup() if the user presses Enter (or Return)
+ and the content is not currently valid. This allows the fixup()
+ function the opportunity of performing some magic to make an \c
+ Invalid string \c Acceptable.
+
+ QValidator is typically used with QLineEdit, QSpinBox and
+ QComboBox.
+*/
+
+
+/*!
+ \enum QValidator::State
+
+ This enum type defines the states in which a validated string can
+ exist.
+
+ \value Invalid the string is \e clearly invalid.
+
+ \value Intermediate the string is a plausible intermediate value
+ during editing.
+
+ \value Acceptable the string is acceptable as a final result,
+ i.e. it is valid.
+*/
+
+
+/*!
+ Sets up the validator. The \a parent and \a name parameters are
+ passed on to the QObject constructor.
+*/
+
+QValidator::QValidator( QObject * parent, const char *name )
+ : QObject( parent, name )
+{
+}
+
+
+/*!
+ Destroys the validator, freeing any storage and other resources
+ used.
+*/
+
+QValidator::~QValidator()
+{
+}
+
+
+/*!
+ \fn QValidator::State QValidator::validate( QString& input, int& pos ) const
+
+ This pure virtual function returns \c Invalid if \a input is
+ invalid according to this validator's rules, \c Intermediate if it
+ is likely that a little more editing will make the input
+ acceptable (e.g. the user types '4' into a widget which accepts
+ integers between 10 and 99) and \c Acceptable if the input is
+ valid.
+
+ The function can change \a input and \a pos (the cursor position)
+ if it wants to.
+*/
+
+
+/*!
+ \fn void QValidator::fixup( QString & input ) const
+
+ This function attempts to change \a input to be valid according to
+ this validator's rules. It need not result in a valid string:
+ callers of this function must re-test afterwards; the default does
+ nothing.
+
+ Reimplementations of this function can change \a input even if
+ they do not produce a valid string. For example, an ISBN validator
+ might want to delete every character except digits and "-", even
+ if the result is still not a valid ISBN; a surname validator might
+ want to remove whitespace from the start and end of the string,
+ even if the resulting string is not in the list of accepted
+ surnames.
+*/
+
+void QValidator::fixup( QString & ) const
+{
+}
+
+
+/*!
+ \class QIntValidator
+ \brief The QIntValidator class provides a validator which ensures
+ that a string contains a valid integer within a specified range.
+
+ \ingroup misc
+
+ Example of use:
+
+ \code
+ QValidator* validator = new QIntValidator( 100, 999, this );
+ QLineEdit* edit = new QLineEdit( this );
+
+ // the edit lineedit will only accept integers between 100 and 999
+ edit->setValidator( validator );
+ \endcode
+
+ Below we present some examples of validators. In practice they would
+ normally be associated with a widget as in the example above.
+
+ \code
+ QString str;
+ int pos = 0;
+ QIntValidator v( 100, 999, this );
+
+ str = "1";
+ v.validate( str, pos ); // returns Intermediate
+ str = "12";
+ v.validate( str, pos ); // returns Intermediate
+
+ str = "123";
+ v.validate( str, pos ); // returns Acceptable
+ str = "678";
+ v.validate( str, pos ); // returns Acceptable
+
+ str = "1234";
+ v.validate( str, pos ); // returns Invalid
+ str = "-123";
+ v.validate( str, pos ); // returns Invalid
+ str = "abc";
+ v.validate( str, pos ); // returns Invalid
+ str = "12cm";
+ v.validate( str, pos ); // returns Invalid
+ \endcode
+
+ The minimum and maximum values are set in one call with setRange()
+ or individually with setBottom() and setTop().
+
+ \sa QDoubleValidator QRegExpValidator
+*/
+
+
+/*!
+ Constructs a validator called \a name with parent \a parent, that
+ accepts all integers.
+*/
+
+QIntValidator::QIntValidator( QObject * parent, const char *name )
+ : QValidator( parent, name )
+{
+ b = INT_MIN;
+ t = INT_MAX;
+}
+
+
+/*!
+ Constructs a validator called \a name with parent \a parent, that
+ accepts integers from \a minimum to \a maximum inclusive.
+*/
+
+QIntValidator::QIntValidator( int minimum, int maximum,
+ QObject * parent, const char* name )
+ : QValidator( parent, name )
+{
+ b = minimum;
+ t = maximum;
+}
+
+
+/*!
+ Destroys the validator, freeing any resources allocated.
+*/
+
+QIntValidator::~QIntValidator()
+{
+ // nothing
+}
+
+
+/*!
+ Returns \c Acceptable if the \a input is an integer within the
+ valid range, \c Intermediate if the \a input is an integer outside
+ the valid range and \c Invalid if the \a input is not an integer.
+
+ Note: If the valid range consists of just positive integers (e.g. 32 - 100)
+ and \a input is a negative integer then Invalid is returned.
+
+ \code
+ int pos = 0;
+ s = "abc";
+ v.validate( s, pos ); // returns Invalid
+
+ s = "5";
+ v.validate( s, pos ); // returns Intermediate
+
+ s = "50";
+ v.validate( s, pos ); // returns Valid
+ \endcode
+*/
+
+QValidator::State QIntValidator::validate( QString & input, int & ) const
+{
+ QString stripped = input.stripWhiteSpace();
+ if ( stripped.isEmpty() || (b < 0 && stripped == "-") )
+ return Intermediate;
+ bool ok;
+ long entered = input.toLong( &ok );
+ if ( !ok || (entered < 0 && b >= 0) ) {
+ return Invalid;
+ } else if ( entered >= b && entered <= t ) {
+ return Acceptable;
+ } else {
+ if ( entered >= 0 )
+ return ( entered > t ) ? Invalid : Intermediate;
+ else
+ return ( entered < b ) ? Invalid : Intermediate;
+ }
+}
+
+
+/*!
+ Sets the range of the validator to only accept integers between \a
+ bottom and \a top inclusive.
+*/
+
+void QIntValidator::setRange( int bottom, int top )
+{
+ b = bottom;
+ t = top;
+}
+
+
+/*!
+ \property QIntValidator::bottom
+ \brief the validator's lowest acceptable value
+
+ \sa setRange()
+*/
+void QIntValidator::setBottom( int bottom )
+{
+ setRange( bottom, top() );
+}
+
+/*!
+ \property QIntValidator::top
+ \brief the validator's highest acceptable value
+
+ \sa setRange()
+*/
+void QIntValidator::setTop( int top )
+{
+ setRange( bottom(), top );
+}
+
+
+#ifndef QT_NO_REGEXP
+
+/*!
+ \class QDoubleValidator
+
+ \brief The QDoubleValidator class provides range checking of
+ floating-point numbers.
+
+ \ingroup misc
+
+ QDoubleValidator provides an upper bound, a lower bound and a
+ limit on the number of digits after the decimal point. It does not
+ provide a fixup() function.
+
+ You can set the acceptable range in one call with setRange(), or
+ with setBottom() and setTop(). Set the number of decimal places
+ with setDecimals(). The validate() function returns the validation
+ state.
+
+ \sa QIntValidator QRegExpValidator
+*/
+
+/*!
+ Constructs a validator object with parent \a parent, called \a
+ name, which accepts any double.
+*/
+
+QDoubleValidator::QDoubleValidator( QObject * parent, const char *name )
+ : QValidator( parent, name )
+{
+ b = -HUGE_VAL;
+ t = HUGE_VAL;
+ d = 1000;
+}
+
+
+/*!
+ Constructs a validator object with parent \a parent, called \a
+ name. This validator will accept doubles from \a bottom to \a top
+ inclusive, with up to \a decimals digits after the decimal point.
+*/
+
+QDoubleValidator::QDoubleValidator( double bottom, double top, int decimals,
+ QObject * parent, const char* name )
+ : QValidator( parent, name )
+{
+ b = bottom;
+ t = top;
+ d = decimals;
+}
+
+
+/*!
+ Destroys the validator, freeing any resources used.
+*/
+
+QDoubleValidator::~QDoubleValidator()
+{
+}
+
+
+/*!
+ Returns \c Acceptable if the string \a input contains a double
+ that is within the valid range and is in the correct format.
+
+ Returns \c Intermediate if \a input contains a double that is
+ outside the range or is in the wrong format, e.g. with too many
+ digits after the decimal point or is empty.
+
+ Returns \c Invalid if the \a input is not a double.
+
+ Note: If the valid range consists of just positive doubles (e.g. 0.0 - 100.0)
+ and \a input is a negative double then Invalid is returned.
+*/
+
+QValidator::State QDoubleValidator::validate( QString & input, int & ) const
+{
+ QRegExp empty( QString::fromLatin1(" *-?\\.? *") );
+ if ( b >= 0 &&
+ input.stripWhiteSpace().startsWith(QString::fromLatin1("-")) )
+ return Invalid;
+ if ( empty.exactMatch(input) )
+ return Intermediate;
+ bool ok = TRUE;
+ double entered = input.toDouble( &ok );
+ int nume = input.contains( 'e', FALSE );
+ if ( !ok ) {
+ // explicit exponent regexp
+ QRegExp expexpexp( QString::fromLatin1("[Ee][+-]?\\d*$") );
+ int eeePos = expexpexp.search( input );
+ if ( eeePos > 0 && nume == 1 ) {
+ QString mantissa = input.left( eeePos );
+ entered = mantissa.toDouble( &ok );
+ if ( !ok )
+ return Invalid;
+ } else if ( eeePos == 0 ) {
+ return Intermediate;
+ } else {
+ return Invalid;
+ }
+ }
+
+ int i = input.find( '.' );
+ if ( i >= 0 && nume == 0 ) {
+ // has decimal point (but no E), now count digits after that
+ i++;
+ int j = i;
+ while( input[j].isDigit() )
+ j++;
+ if ( j - i > d )
+ return Intermediate;
+ }
+
+ if ( entered < b || entered > t )
+ return Intermediate;
+ else
+ return Acceptable;
+}
+
+
+/*!
+ Sets the validator to accept doubles from \a minimum to \a maximum
+ inclusive, with at most \a decimals digits after the decimal
+ point.
+*/
+
+void QDoubleValidator::setRange( double minimum, double maximum, int decimals )
+{
+ b = minimum;
+ t = maximum;
+ d = decimals;
+}
+
+/*!
+ \property QDoubleValidator::bottom
+ \brief the validator's minimum acceptable value
+
+ \sa setRange()
+*/
+
+void QDoubleValidator::setBottom( double bottom )
+{
+ setRange( bottom, top(), decimals() );
+}
+
+
+/*!
+ \property QDoubleValidator::top
+ \brief the validator's maximum acceptable value
+
+ \sa setRange()
+*/
+
+void QDoubleValidator::setTop( double top )
+{
+ setRange( bottom(), top, decimals() );
+}
+
+/*!
+ \property QDoubleValidator::decimals
+ \brief the validator's maximum number of digits after the decimal point
+
+ \sa setRange()
+*/
+
+void QDoubleValidator::setDecimals( int decimals )
+{
+ setRange( bottom(), top(), decimals );
+}
+
+
+/*!
+ \class QRegExpValidator
+ \brief The QRegExpValidator class is used to check a string
+ against a regular expression.
+
+ \ingroup misc
+
+ QRegExpValidator contains a regular expression, "regexp", used to
+ determine whether an input string is \c Acceptable, \c
+ Intermediate or \c Invalid.
+
+ The regexp is treated as if it begins with the start of string
+ assertion, <b>^</b>, and ends with the end of string assertion
+ <b>$</b> so the match is against the entire input string, or from
+ the given position if a start position greater than zero is given.
+
+ For a brief introduction to Qt's regexp engine see \l QRegExp.
+
+ Example of use:
+ \code
+ // regexp: optional '-' followed by between 1 and 3 digits
+ QRegExp rx( "-?\\d{1,3}" );
+ QValidator* validator = new QRegExpValidator( rx, this );
+
+ QLineEdit* edit = new QLineEdit( this );
+ edit->setValidator( validator );
+ \endcode
+
+ Below we present some examples of validators. In practice they would
+ normally be associated with a widget as in the example above.
+
+ \code
+ // integers 1 to 9999
+ QRegExp rx( "[1-9]\\d{0,3}" );
+ // the validator treats the regexp as "^[1-9]\\d{0,3}$"
+ QRegExpValidator v( rx, 0 );
+ QString s;
+ int pos = 0;
+
+ s = "0"; v.validate( s, pos ); // returns Invalid
+ s = "12345"; v.validate( s, pos ); // returns Invalid
+ s = "1"; v.validate( s, pos ); // returns Acceptable
+
+ rx.setPattern( "\\S+" ); // one or more non-whitespace characters
+ v.setRegExp( rx );
+ s = "myfile.txt"; v.validate( s, pos ); // Returns Acceptable
+ s = "my file.txt"; v.validate( s, pos ); // Returns Invalid
+
+ // A, B or C followed by exactly five digits followed by W, X, Y or Z
+ rx.setPattern( "[A-C]\\d{5}[W-Z]" );
+ v.setRegExp( rx );
+ s = "a12345Z"; v.validate( s, pos ); // Returns Invalid
+ s = "A12345Z"; v.validate( s, pos ); // Returns Acceptable
+ s = "B12"; v.validate( s, pos ); // Returns Intermediate
+
+ // match most 'readme' files
+ rx.setPattern( "read\\S?me(\.(txt|asc|1st))?" );
+ rx.setCaseSensitive( FALSE );
+ v.setRegExp( rx );
+ s = "readme"; v.validate( s, pos ); // Returns Acceptable
+ s = "README.1ST"; v.validate( s, pos ); // Returns Acceptable
+ s = "read me.txt"; v.validate( s, pos ); // Returns Invalid
+ s = "readm"; v.validate( s, pos ); // Returns Intermediate
+ \endcode
+
+ \sa QRegExp QIntValidator QDoubleValidator
+*/
+
+/*!
+ Constructs a validator that accepts any string (including an empty
+ one) as valid. The object's parent is \a parent and its name is \a
+ name.
+*/
+
+QRegExpValidator::QRegExpValidator( QObject *parent, const char *name )
+ : QValidator( parent, name ), r( QString::fromLatin1(".*") )
+{
+}
+
+/*!
+ Constructs a validator which accepts all strings that match the
+ regular expression \a rx. The object's parent is \a parent and its
+ name is \a name.
+
+ The match is made against the entire string, e.g. if the regexp is
+ <b>[A-Fa-f0-9]+</b> it will be treated as <b>^[A-Fa-f0-9]+$</b>.
+*/
+
+QRegExpValidator::QRegExpValidator( const QRegExp& rx, QObject *parent,
+ const char *name )
+ : QValidator( parent, name ), r( rx )
+{
+}
+
+/*!
+ Destroys the validator, freeing any resources allocated.
+*/
+
+QRegExpValidator::~QRegExpValidator()
+{
+}
+
+/*!
+ Returns \c Acceptable if \a input is matched by the regular
+ expression for this validator, \c Intermediate if it has matched
+ partially (i.e. could be a valid match if additional valid
+ characters are added), and \c Invalid if \a input is not matched.
+
+ The \a pos parameter is set to the length of the \a input parameter.
+
+ For example, if the regular expression is <b>\\w\\d\\d</b> (that
+ is, word-character, digit, digit) then "A57" is \c Acceptable,
+ "E5" is \c Intermediate and "+9" is \c Invalid.
+
+ \sa QRegExp::match() QRegExp::search()
+*/
+
+QValidator::State QRegExpValidator::validate( QString& input, int& pos ) const
+{
+ if ( r.exactMatch(input) ) {
+ return Acceptable;
+ } else {
+ if ( ((QRegExp&) r).matchedLength() == (int) input.length() ) {
+ return Intermediate;
+ } else {
+ pos = input.length();
+ return Invalid;
+ }
+ }
+}
+
+/*!
+ Sets the regular expression used for validation to \a rx.
+
+ \sa regExp()
+*/
+
+void QRegExpValidator::setRegExp( const QRegExp& rx )
+{
+ r = rx;
+}
+
+/*!
+ \fn const QRegExp& QRegExpValidator::regExp() const
+
+ Returns the regular expression used for validation.
+
+ \sa setRegExp()
+*/
+
+#endif
+
+#endif
diff --git a/src/widgets/qvalidator.h b/src/widgets/qvalidator.h
new file mode 100644
index 0000000..1e4310c
--- /dev/null
+++ b/src/widgets/qvalidator.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Definition of validator classes
+**
+** Created : 970610
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QVALIDATOR_H
+#define QVALIDATOR_H
+
+#ifndef QT_H
+#include "qobject.h"
+#include "qstring.h" // char*->QString conversion
+#include "qregexp.h" // QString->QRegExp conversion
+#endif // QT_H
+
+#ifndef QT_NO_VALIDATOR
+
+
+class Q_EXPORT QValidator : public QObject
+{
+ Q_OBJECT
+public:
+ QValidator( QObject * parent, const char *name = 0 );
+ ~QValidator();
+
+ enum State { Invalid, Intermediate, Valid=Intermediate, Acceptable };
+
+ virtual State validate( QString &, int & ) const = 0;
+ virtual void fixup( QString & ) const;
+
+private:
+#if defined(Q_DISABLE_COPY)
+ QValidator( const QValidator & );
+ QValidator& operator=( const QValidator & );
+#endif
+};
+
+
+class Q_EXPORT QIntValidator : public QValidator
+{
+ Q_OBJECT
+ Q_PROPERTY( int bottom READ bottom WRITE setBottom )
+ Q_PROPERTY( int top READ top WRITE setTop )
+
+public:
+ QIntValidator( QObject * parent, const char *name = 0 );
+ QIntValidator( int bottom, int top,
+ QObject * parent, const char *name = 0 );
+ ~QIntValidator();
+
+ QValidator::State validate( QString &, int & ) const;
+
+ void setBottom( int );
+ void setTop( int );
+ virtual void setRange( int bottom, int top );
+
+ int bottom() const { return b; }
+ int top() const { return t; }
+
+private:
+#if defined(Q_DISABLE_COPY)
+ QIntValidator( const QIntValidator & );
+ QIntValidator& operator=( const QIntValidator & );
+#endif
+
+ int b, t;
+};
+
+#ifndef QT_NO_REGEXP
+
+class Q_EXPORT QDoubleValidator : public QValidator
+{
+ Q_OBJECT
+ Q_PROPERTY( double bottom READ bottom WRITE setBottom )
+ Q_PROPERTY( double top READ top WRITE setTop )
+ Q_PROPERTY( int decimals READ decimals WRITE setDecimals )
+
+public:
+ QDoubleValidator( QObject * parent, const char *name = 0 );
+ QDoubleValidator( double bottom, double top, int decimals,
+ QObject * parent, const char *name = 0 );
+ ~QDoubleValidator();
+
+ QValidator::State validate( QString &, int & ) const;
+
+ virtual void setRange( double bottom, double top, int decimals = 0 );
+ void setBottom( double );
+ void setTop( double );
+ void setDecimals( int );
+
+ double bottom() const { return b; }
+ double top() const { return t; }
+ int decimals() const { return d; }
+
+private:
+#if defined(Q_DISABLE_COPY)
+ QDoubleValidator( const QDoubleValidator & );
+ QDoubleValidator& operator=( const QDoubleValidator & );
+#endif
+
+ double b, t;
+ int d;
+};
+
+
+class Q_EXPORT QRegExpValidator : public QValidator
+{
+ Q_OBJECT
+ // Q_PROPERTY( QRegExp regExp READ regExp WRITE setRegExp )
+
+public:
+ QRegExpValidator( QObject *parent, const char *name = 0 );
+ QRegExpValidator( const QRegExp& rx, QObject *parent,
+ const char *name = 0 );
+ ~QRegExpValidator();
+
+ virtual QValidator::State validate( QString& input, int& pos ) const;
+
+ void setRegExp( const QRegExp& rx );
+ const QRegExp& regExp() const { return r; }
+
+private:
+#if defined(Q_DISABLE_COPY)
+ QRegExpValidator( const QRegExpValidator& );
+ QRegExpValidator& operator=( const QRegExpValidator& );
+#endif
+
+ QRegExp r;
+};
+#endif // QT_NO_REGEXP
+
+
+#endif // QT_NO_VALIDATOR
+
+#endif // QVALIDATOR_H
diff --git a/src/widgets/qvbox.cpp b/src/widgets/qvbox.cpp
new file mode 100644
index 0000000..82d1e12
--- /dev/null
+++ b/src/widgets/qvbox.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Implementation of vertical box layout widget class
+**
+** Created : 990124
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+
+#include "qvbox.h"
+#ifndef QT_NO_VBOX
+
+/*!
+ \class QVBox qvbox.h
+ \brief The QVBox widget provides vertical geometry management of
+ its child widgets.
+
+ \ingroup geomanagement
+ \ingroup appearance
+ \ingroup organizers
+
+ All its child widgets will be placed vertically and sized
+ according to their sizeHint()s.
+
+ \img qvbox-m.png QVBox
+
+ \sa QHBox
+*/
+
+
+/*!
+ Constructs a vbox widget called \a name with parent \a parent and
+ widget flags \a f.
+ */
+QVBox::QVBox( QWidget *parent, const char *name, WFlags f )
+ :QHBox( FALSE, parent, name, f )
+{
+}
+#endif
diff --git a/src/widgets/qvbox.h b/src/widgets/qvbox.h
new file mode 100644
index 0000000..8500f11
--- /dev/null
+++ b/src/widgets/qvbox.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Definition of vertical box layout widget class
+**
+** Created : 990124
+**
+** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QVBOX_H
+#define QVBOX_H
+
+#ifndef QT_H
+#include "qhbox.h"
+#endif // QT_H
+
+#ifndef QT_NO_VBOX
+
+class Q_EXPORT QVBox : public QHBox
+{
+ Q_OBJECT
+public:
+ QVBox( QWidget* parent=0, const char* name=0, WFlags f=0 );
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QVBox( const QVBox & );
+ QVBox& operator=( const QVBox & );
+#endif
+};
+
+#endif // QT_NO_VBOX
+
+#endif // QVBOX_H
diff --git a/src/widgets/qvbuttongroup.cpp b/src/widgets/qvbuttongroup.cpp
new file mode 100644
index 0000000..70247fd
--- /dev/null
+++ b/src/widgets/qvbuttongroup.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Implementation of QVButtonGroup class
+**
+** Created : 990602
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qvbuttongroup.h"
+#ifndef QT_NO_VBUTTONGROUP
+
+/*!
+ \class QVButtonGroup qvbuttongroup.h
+ \brief The QVButtonGroup widget organizes QButton widgets in a
+ vertical column.
+
+ \ingroup geomanagement
+ \ingroup organizers
+ \ingroup appearance
+
+ QVButtonGroup is a convenience class that offers a thin layer on top
+ of QButtonGroup. Think of it as a QVBox that offers a frame with a
+ title and is specifically designed for buttons.
+
+ \img qbuttongroup-v.png QButtonGroup
+
+ \sa QHButtonGroup
+*/
+
+/*!
+ Constructs a vertical button group with no title.
+
+ The \a parent and \a name arguments are passed on to the QWidget
+ constructor.
+*/
+QVButtonGroup::QVButtonGroup( QWidget *parent, const char *name )
+ : QButtonGroup( 1, Horizontal /* sic! */, parent, name )
+{
+}
+
+/*!
+ Constructs a vertical button group with the title \a title.
+
+ The \a parent and \a name arguments are passed on to the QWidget
+ constructor.
+*/
+
+QVButtonGroup::QVButtonGroup( const QString &title, QWidget *parent,
+ const char *name )
+ : QButtonGroup( 1, Horizontal /* sic! */, title, parent, name )
+{
+}
+
+/*!
+ Destroys the vertical button group, deleting its child widgets.
+*/
+QVButtonGroup::~QVButtonGroup()
+{
+}
+#endif
diff --git a/src/widgets/qvbuttongroup.h b/src/widgets/qvbuttongroup.h
new file mode 100644
index 0000000..9aab80e
--- /dev/null
+++ b/src/widgets/qvbuttongroup.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Definition of QVButtonGroup class
+**
+** Created : 990602
+**
+** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QVBUTTONGROUP_H
+#define QVBUTTONGROUP_H
+
+#ifndef QT_H
+#include "qbuttongroup.h"
+#endif // QT_H
+
+#ifndef QT_NO_VBUTTONGROUP
+
+class Q_EXPORT QVButtonGroup : public QButtonGroup
+{
+ Q_OBJECT
+public:
+ QVButtonGroup( QWidget* parent=0, const char* name=0 );
+ QVButtonGroup( const QString &title, QWidget* parent=0, const char* name=0 );
+
+ ~QVButtonGroup();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QVButtonGroup( const QVButtonGroup & );
+ QVButtonGroup &operator=( const QVButtonGroup & );
+#endif
+};
+
+
+#endif // QT_NO_VBUTTONGROUP
+
+#endif // QVBUTTONGROUP_H
diff --git a/src/widgets/qvgroupbox.cpp b/src/widgets/qvgroupbox.cpp
new file mode 100644
index 0000000..6ef633b
--- /dev/null
+++ b/src/widgets/qvgroupbox.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Implementation of QVGroupBox class
+**
+** Created : 990602
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qvgroupbox.h"
+#ifndef QT_NO_VGROUPBOX
+
+/*!
+ \class QVGroupBox qvgroupbox.h
+ \brief The QVGroupBox widget organizes a group of widgets in a
+ vertical column.
+
+ \ingroup geomanagement
+ \ingroup appearance
+ \ingroup organizers
+
+ QVGroupBox is a convenience class that offers a thin layer on top of
+ QGroupBox. Think of it as a QVBox that offers a frame with a title.
+
+ \img qgroupboxes.png Group Boxes
+
+ \sa QHGroupBox
+*/
+
+/*!
+ Constructs a vertical group box with no title.
+
+ The \a parent and \a name arguments are passed on to the QWidget
+ constructor.
+*/
+QVGroupBox::QVGroupBox( QWidget *parent, const char *name )
+ : QGroupBox( 1, Horizontal /* sic! */, parent, name )
+{
+}
+
+/*!
+ Constructs a vertical group box with the title \a title.
+
+ The \a parent and \a name arguments are passed on to the QWidget
+ constructor.
+*/
+
+QVGroupBox::QVGroupBox( const QString &title, QWidget *parent,
+ const char *name )
+ : QGroupBox( 1, Horizontal /* sic! */, title, parent, name )
+{
+}
+
+/*!
+ Destroys the vertical group box, deleting its child widgets.
+*/
+QVGroupBox::~QVGroupBox()
+{
+}
+#endif
diff --git a/src/widgets/qvgroupbox.h b/src/widgets/qvgroupbox.h
new file mode 100644
index 0000000..ca9eb0a
--- /dev/null
+++ b/src/widgets/qvgroupbox.h
@@ -0,0 +1,68 @@
+/**********************************************************************
+**
+** Definition of QVGroupBox widget class
+**
+** Created : 990602
+**
+** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QVGROUPBOX_H
+#define QVGROUPBOX_H
+
+#ifndef QT_H
+#include "qgroupbox.h"
+#endif // QT_H
+
+#ifndef QT_NO_VGROUPBOX
+
+class Q_EXPORT QVGroupBox : public QGroupBox
+{
+ Q_OBJECT
+public:
+ QVGroupBox( QWidget* parent=0, const char* name=0 );
+ QVGroupBox( const QString &title, QWidget* parent=0, const char* name=0 );
+
+ ~QVGroupBox();
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QVGroupBox( const QVGroupBox & );
+ QVGroupBox &operator=( const QVGroupBox & );
+#endif
+};
+
+#endif // QT_NO_VGROUPBOX
+
+#endif // QVGROUPBOX_H
diff --git a/src/widgets/qwhatsthis.cpp b/src/widgets/qwhatsthis.cpp
new file mode 100644
index 0000000..c6e8f04
--- /dev/null
+++ b/src/widgets/qwhatsthis.cpp
@@ -0,0 +1,1001 @@
+/****************************************************************************
+**
+** Implementation of QWhatsThis class
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qwhatsthis.h"
+#ifndef QT_NO_WHATSTHIS
+#include "qapplication.h"
+#include "qpaintdevicemetrics.h"
+#include "qpixmap.h"
+#include "qpainter.h"
+#include "qtimer.h"
+#include "qptrdict.h"
+#include "qtoolbutton.h"
+#include "qshared.h"
+#include "qcursor.h"
+#include "qbitmap.h"
+#include "qtooltip.h"
+#include "qsimplerichtext.h"
+#include "qstylesheet.h"
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include "qaccessible.h"
+#endif
+#if defined(Q_WS_WIN)
+#include "qt_windows.h"
+#ifndef SPI_GETDROPSHADOW
+#define SPI_GETDROPSHADOW 0x1024
+#endif
+#endif
+
+/*!
+ \class QWhatsThis qwhatsthis.h
+ \brief The QWhatsThis class provides a simple description of any
+ widget, i.e. answering the question "What's this?".
+
+ \ingroup helpsystem
+ \mainclass
+
+ "What's this?" help is part of an application's online help system
+ that provides users with information about functionality, usage,
+ background etc., in various levels of detail from short tool tips
+ to full text browsing help windows.
+
+ QWhatsThis provides a single window with an explanatory text that
+ pops up when the user asks "What's this?". The default way to do
+ this is to focus the relevant widget and press Shift+F1. The help
+ text appears immediately; it goes away as soon as the user does
+ something else.
+
+ (Note that if there is an accelerator for Shift+F1, this mechanism
+ will not work.)
+
+ To add "What's this?" text to a widget you simply call
+ QWhatsThis::add() for the widget. For example, to assign text to a
+ menu item, call QMenuData::setWhatsThis(); for a global
+ accelerator key, call QAccel::setWhatsThis() and If you're using
+ actions, use QAction::setWhatsThis().
+
+ The text can be either rich text or plain text. If you specify a
+ rich text formatted string, it will be rendered using the default
+ stylesheet. This makes it possible to embed images. See
+ QStyleSheet::defaultSheet() for details.
+
+ \quotefile action/application.cpp
+ \skipto fileOpenText
+ \printuntil setWhatsThis
+
+ An alternative way to enter "What's this?" mode is to use the
+ ready-made tool bar tool button from
+ QWhatsThis::whatsThisButton(). By invoking this context help
+ button (in the picture below the first one from the right) the
+ user switches into "What's this?" mode. If they now click on a
+ widget the appropriate help text is shown. The mode is left when
+ help is given or when the user presses Esc.
+
+ \img whatsthis.png
+
+ If you are using QMainWindow you can also use the
+ QMainWindow::whatsThis() slot to invoke the mode from a menu item.
+
+ For more control you can create a dedicated QWhatsThis object for
+ a special widget. By subclassing and reimplementing
+ QWhatsThis::text() it is possible to have different help texts,
+ depending on the position of the mouse click. By reimplementing
+ QWhatsThis::clicked() it is possible to have hyperlinks inside the
+ help texts.
+
+ If you wish to control the "What's this?" behavior of a widget
+ manually see QWidget::customWhatsThis().
+
+ The What's This object can be removed using QWhatsThis::remove(),
+ although this is rarely necessary because it is automatically
+ removed when the widget is destroyed.
+
+ \sa QToolTip
+*/
+
+// a special button
+class QWhatsThisButton: public QToolButton
+{
+ Q_OBJECT
+
+public:
+ QWhatsThisButton( QWidget * parent, const char * name );
+ ~QWhatsThisButton();
+
+public slots:
+ void mouseReleased();
+
+};
+
+
+class QWhatsThat : public QWidget
+{
+ Q_OBJECT
+public:
+ QWhatsThat( QWidget* w, const QString& txt, QWidget* parent, const char* name );
+ ~QWhatsThat() ;
+
+public slots:
+ void hide();
+ inline void widgetDestroyed() { widget = 0; }
+
+protected:
+ void mousePressEvent( QMouseEvent* );
+ void mouseReleaseEvent( QMouseEvent* );
+ void mouseMoveEvent( QMouseEvent* );
+ void keyPressEvent( QKeyEvent* );
+ void paintEvent( QPaintEvent* );
+
+private:
+ QString text;
+#ifndef QT_NO_RICHTEXT
+ QSimpleRichText* doc;
+#endif
+ QString anchor;
+ bool pressed;
+ QWidget* widget;
+};
+
+
+class QWhatsThisPrivate: public QObject
+{
+ Q_OBJECT
+public:
+
+ // an item for storing texts
+ struct WhatsThisItem: public QShared
+ {
+ WhatsThisItem(): QShared() { whatsthis = 0; }
+ ~WhatsThisItem();
+ QString s;
+ QWhatsThis* whatsthis;
+ };
+
+ // the (these days pretty small) state machine
+ enum State { Inactive, Waiting };
+
+ QWhatsThisPrivate();
+ ~QWhatsThisPrivate();
+
+ bool eventFilter( QObject *, QEvent * );
+
+ WhatsThisItem* newItem( QWidget * widget );
+ void add( QWidget * widget, QWhatsThis* special );
+ void add( QWidget * widget, const QString& text );
+
+ // say it.
+ void say( QWidget *, const QString&, const QPoint& );
+
+ // setup and teardown
+ static void setUpWhatsThis();
+
+ void enterWhatsThisMode();
+ void leaveWhatsThisMode();
+
+ // variables
+ QWhatsThat * whatsThat;
+ QPtrDict<WhatsThisItem> * dict;
+ QPtrDict<QWidget> * tlw;
+ QPtrDict<QWhatsThisButton> * buttons;
+ State state;
+
+private slots:
+ void cleanupWidget()
+ {
+ const QObject* o = sender();
+ if ( o->isWidgetType() ) // sanity
+ QWhatsThis::remove((QWidget*)o);
+ }
+
+};
+
+// static, but static the less-typing way
+static QWhatsThisPrivate * wt = 0;
+
+// shadowWidth not const, for XP drop-shadow-fu turns it to 0
+static int shadowWidth = 6; // also used as '5' and '6' and even '8' below
+const int vMargin = 8;
+const int hMargin = 12;
+
+// Lets QPopupMenu destroy the QWhatsThat.
+void qWhatsThisBDH()
+{
+ if ( wt && wt->whatsThat )
+ wt->whatsThat->hide();
+}
+
+
+QWhatsThat::QWhatsThat( QWidget* w, const QString& txt, QWidget* parent, const char* name )
+ : QWidget( parent, name, WType_Popup ), text( txt ), pressed( FALSE ), widget( w )
+{
+
+ setBackgroundMode( NoBackground );
+ setPalette( QToolTip::palette() );
+ setMouseTracking( TRUE );
+#ifndef QT_NO_CURSOR
+ setCursor( arrowCursor );
+#endif
+
+ if ( widget )
+ connect( widget, SIGNAL( destroyed() ), this, SLOT( widgetDestroyed() ) );
+
+
+ QRect r;
+#ifndef QT_NO_RICHTEXT
+ doc = 0;
+ if ( QStyleSheet::mightBeRichText( text ) ) {
+ QFont f = QApplication::font( this );
+ doc = new QSimpleRichText( text, f );
+ doc->adjustSize();
+ r.setRect( 0, 0, doc->width(), doc->height() );
+ }
+ else
+#endif
+ {
+ int sw = QApplication::desktop()->width() / 3;
+ if ( sw < 200 )
+ sw = 200;
+ else if ( sw > 300 )
+ sw = 300;
+
+ r = fontMetrics().boundingRect( 0, 0, sw, 1000,
+ AlignAuto + AlignTop + WordBreak + ExpandTabs,
+ text );
+ }
+#if defined(Q_WS_WIN)
+ if ( (qWinVersion()&WV_NT_based) > WV_2000 ) {
+ BOOL shadow;
+ SystemParametersInfo( SPI_GETDROPSHADOW, 0, &shadow, 0 );
+ shadowWidth = shadow ? 0 : 6;
+ }
+#endif
+ resize( r.width() + 2*hMargin + shadowWidth, r.height() + 2*vMargin + shadowWidth );
+}
+
+QWhatsThat::~QWhatsThat()
+{
+ if ( wt && wt->whatsThat == this )
+ wt->whatsThat = 0;
+#ifndef QT_NO_RICHTEXT
+ if ( doc )
+ delete doc;
+#endif
+}
+
+void QWhatsThat::hide()
+{
+ QWidget::hide();
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpEnd );
+#endif
+}
+
+void QWhatsThat::mousePressEvent( QMouseEvent* e )
+{
+ pressed = TRUE;
+ if ( e->button() == LeftButton && rect().contains( e->pos() ) ) {
+#ifndef QT_NO_RICHTEXT
+ if ( doc )
+ anchor = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin) );
+#endif
+ return;
+ }
+ hide();
+}
+
+void QWhatsThat::mouseReleaseEvent( QMouseEvent* e )
+{
+ if ( !pressed )
+ return;
+#ifndef QT_NO_RICHTEXT
+ if ( e->button() == LeftButton && doc && rect().contains( e->pos() ) ) {
+ QString a = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin ) );
+ QString href;
+ if ( anchor == a )
+ href = a;
+ anchor = QString::null;
+ if ( widget && wt && wt->dict ) {
+ QWhatsThisPrivate::WhatsThisItem * i = wt->dict->find( widget );
+ if ( i && i->whatsthis && !i->whatsthis->clicked( href ) )
+ return;
+ }
+ }
+#endif
+ hide();
+}
+
+void QWhatsThat::mouseMoveEvent( QMouseEvent* e)
+{
+#ifndef QT_NO_RICHTEXT
+#ifndef QT_NO_CURSOR
+ if ( !doc )
+ return;
+ QString a = doc->anchorAt( e->pos() - QPoint( hMargin, vMargin ) );
+ if ( !a.isEmpty() )
+ setCursor( pointingHandCursor );
+ else
+ setCursor( arrowCursor );
+#endif
+#endif
+}
+
+
+void QWhatsThat::keyPressEvent( QKeyEvent* )
+{
+ hide();
+}
+
+
+
+void QWhatsThat::paintEvent( QPaintEvent* )
+{
+ bool drawShadow = TRUE;
+#if defined(Q_WS_WIN)
+ if ( (qWinVersion()&WV_NT_based) > WV_2000 ) {
+ BOOL shadow;
+ SystemParametersInfo( SPI_GETDROPSHADOW, 0, &shadow, 0 );
+ drawShadow = !shadow;
+ }
+#elif defined(Q_WS_MACX)
+ drawShadow = FALSE; //never draw it on OS X we get it for free
+#endif
+
+ QRect r = rect();
+ if ( drawShadow )
+ r.addCoords( 0, 0, -shadowWidth, -shadowWidth );
+ QPainter p( this);
+ p.setPen( colorGroup().foreground() );
+ p.drawRect( r );
+ p.setPen( colorGroup().mid() );
+ p.setBrush( colorGroup().brush( QColorGroup::Background ) );
+ int w = r.width();
+ int h = r.height();
+ p.drawRect( 1, 1, w-2, h-2 );
+ if ( drawShadow ) {
+ p.setPen( colorGroup().shadow() );
+ p.drawPoint( w + 5, 6 );
+ p.drawLine( w + 3, 6, w + 5, 8 );
+ p.drawLine( w + 1, 6, w + 5, 10 );
+ int i;
+ for( i=7; i < h; i += 2 )
+ p.drawLine( w, i, w + 5, i + 5 );
+ for( i = w - i + h; i > 6; i -= 2 )
+ p.drawLine( i, h, i + 5, h + 5 );
+ for( ; i > 0 ; i -= 2 )
+ p.drawLine( 6, h + 6 - i, i + 5, h + 5 );
+ }
+ p.setPen( colorGroup().foreground() );
+ r.addCoords( hMargin, vMargin, -hMargin, -vMargin );
+
+#ifndef QT_NO_RICHTEXT
+ if ( doc ) {
+ doc->draw( &p, r.x(), r.y(), r, colorGroup(), 0 );
+ }
+ else
+#endif
+ {
+ p.drawText( r, AlignAuto + AlignTop + WordBreak + ExpandTabs, text );
+ }
+}
+
+// the item
+QWhatsThisPrivate::WhatsThisItem::~WhatsThisItem()
+{
+ if ( count )
+ qFatal( "QWhatsThis: Internal error (%d)", count );
+ delete whatsthis;
+}
+
+
+static const char * const button_image[] = {
+"16 16 3 1",
+" c None",
+"o c #000000",
+"a c #000080",
+"o aaaaa ",
+"oo aaa aaa ",
+"ooo aaa aaa",
+"oooo aa aa",
+"ooooo aa aa",
+"oooooo a aaa",
+"ooooooo aaa ",
+"oooooooo aaa ",
+"ooooooooo aaa ",
+"ooooo aaa ",
+"oo ooo ",
+"o ooo aaa ",
+" ooo aaa ",
+" ooo ",
+" ooo ",
+" ooo "};
+
+// the button class
+QWhatsThisButton::QWhatsThisButton( QWidget * parent, const char * name )
+ : QToolButton( parent, name )
+{
+ QPixmap p( (const char**)button_image );
+ setPixmap( p );
+ setToggleButton( TRUE );
+ setAutoRaise( TRUE );
+ setFocusPolicy( NoFocus );
+ setTextLabel( tr( "What's this?" ) );
+ wt->buttons->insert( (void *)this, this );
+ connect( this, SIGNAL( released() ),
+ this, SLOT( mouseReleased() ) );
+}
+
+
+QWhatsThisButton::~QWhatsThisButton()
+{
+ if ( wt && wt->buttons )
+ wt->buttons->take( (void *)this );
+}
+
+
+void QWhatsThisButton::mouseReleased()
+{
+ if ( wt->state == QWhatsThisPrivate::Inactive && isOn() ) {
+ QWhatsThisPrivate::setUpWhatsThis();
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( whatsThisCursor, FALSE );
+#endif
+ wt->state = QWhatsThisPrivate::Waiting;
+ qApp->installEventFilter( wt );
+ }
+}
+
+static void qWhatsThisPrivateCleanup()
+{
+ if( wt ) {
+ delete wt;
+ wt = 0;
+ }
+}
+
+// the what's this manager class
+QWhatsThisPrivate::QWhatsThisPrivate()
+ : QObject( 0, "global what's this object" )
+{
+ whatsThat = 0;
+ dict = new QPtrDict<QWhatsThisPrivate::WhatsThisItem>;
+ tlw = new QPtrDict<QWidget>;
+ wt = this;
+ buttons = new QPtrDict<QWhatsThisButton>;
+ state = Inactive;
+}
+
+QWhatsThisPrivate::~QWhatsThisPrivate()
+{
+#ifndef QT_NO_CURSOR
+ if ( state == Waiting && qApp )
+ QApplication::restoreOverrideCursor();
+#endif
+ // the two straight-and-simple dicts
+ delete tlw;
+ delete buttons;
+
+ // then delete the complex one.
+ QPtrDictIterator<WhatsThisItem> it( *dict );
+ WhatsThisItem * i;
+ QWidget * w;
+ while( (i=it.current()) != 0 ) {
+ w = (QWidget *)it.currentKey();
+ ++it;
+ dict->take( w );
+ if ( i->deref() )
+ delete i;
+ }
+ delete dict;
+ if ( whatsThat && !whatsThat->parentWidget() ) {
+ delete whatsThat;
+ }
+ // and finally lose wt
+ wt = 0;
+}
+
+bool QWhatsThisPrivate::eventFilter( QObject * o, QEvent * e )
+{
+ switch( state ) {
+ case Waiting:
+ if ( e->type() == QEvent::MouseButtonPress && o->isWidgetType() ) {
+ QWidget * w = (QWidget *) o;
+ if ( ( (QMouseEvent*)e)->button() == RightButton )
+ return FALSE; // ignore RMB
+ if ( w->customWhatsThis() )
+ return FALSE;
+ QWhatsThisPrivate::WhatsThisItem * i = 0;
+ QMouseEvent* me = (QMouseEvent*) e;
+ QPoint p = me->pos();
+ while( w && !i ) {
+ i = dict->find( w );
+ if ( !i ) {
+ p += w->pos();
+ w = w->parentWidget( TRUE );
+ }
+ }
+ leaveWhatsThisMode();
+ if (!i ) {
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpEnd );
+#endif
+ return TRUE;
+ }
+ if ( i->whatsthis )
+ say( w, i->whatsthis->text( p ), me->globalPos() );
+ else
+ say( w, i->s, me->globalPos() );
+ return TRUE;
+ } else if ( e->type() == QEvent::MouseButtonRelease ) {
+ if ( ( (QMouseEvent*)e)->button() == RightButton )
+ return FALSE; // ignore RMB
+ return !o->isWidgetType() || !((QWidget*)o)->customWhatsThis();
+ } else if ( e->type() == QEvent::MouseMove ) {
+ return !o->isWidgetType() || !((QWidget*)o)->customWhatsThis();
+ } else if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent* kev = (QKeyEvent*)e;
+
+ if ( kev->key() == Qt::Key_Escape ) {
+ leaveWhatsThisMode();
+ return TRUE;
+ } else if ( o->isWidgetType() && ((QWidget*)o)->customWhatsThis() ) {
+ return FALSE;
+ } else if ( kev->key() == Key_Menu ||
+ ( kev->key() == Key_F10 &&
+ kev->state() == ShiftButton ) ) {
+ // we don't react to these keys, they are used for context menus
+ return FALSE;
+ } else if ( kev->state() == kev->stateAfter() &&
+ kev->key() != Key_Meta ) { // not a modifier key
+ leaveWhatsThisMode();
+ }
+ } else if ( e->type() == QEvent::MouseButtonDblClick ) {
+ return TRUE;
+ }
+ break;
+ case Inactive:
+ if ( e->type() == QEvent::Accel &&
+ ((QKeyEvent *)e)->key() == Key_F1 &&
+ o->isWidgetType() &&
+ ((QKeyEvent *)e)->state() == ShiftButton ) {
+ QWidget * w = ((QWidget *)o)->focusWidget();
+ if ( !w )
+ break;
+ QString s = QWhatsThis::textFor( w, QPoint(0,0), TRUE );
+ if ( !s.isNull() ) {
+ say ( w, s, w->mapToGlobal( w->rect().center() ) );
+ ((QKeyEvent *)e)->accept();
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+
+void QWhatsThisPrivate::setUpWhatsThis()
+{
+ if ( !wt ) {
+ wt = new QWhatsThisPrivate();
+
+ // It is necessary to use a post routine, because
+ // the destructor deletes pixmaps and other stuff that
+ // needs a working X connection under X11.
+ qAddPostRoutine( qWhatsThisPrivateCleanup );
+ }
+}
+
+
+void QWhatsThisPrivate::enterWhatsThisMode()
+{
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ContextHelpStart );
+#endif
+}
+
+
+void QWhatsThisPrivate::leaveWhatsThisMode()
+{
+ if ( state == Waiting ) {
+ QPtrDictIterator<QWhatsThisButton> it( *(wt->buttons) );
+ QWhatsThisButton * b;
+ while( (b=it.current()) != 0 ) {
+ ++it;
+ b->setOn( FALSE );
+ }
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ state = Inactive;
+ qApp->removeEventFilter( this );
+ }
+}
+
+
+
+void QWhatsThisPrivate::say( QWidget * widget, const QString &text, const QPoint& ppos)
+{
+ if ( text.isEmpty() )
+ return;
+ // make a fresh widget, and set it up
+ delete whatsThat;
+ whatsThat = new QWhatsThat(
+ widget, text,
+#if defined(Q_WS_X11)
+ QApplication::desktop()->screen( widget ?
+ widget->x11Screen() :
+ QCursor::x11Screen() ),
+#else
+ 0,
+#endif
+ "automatic what's this? widget" );
+
+
+ // okay, now to find a suitable location
+
+ int scr = ( widget ?
+ QApplication::desktop()->screenNumber( widget ) :
+#if defined(Q_WS_X11)
+ QCursor::x11Screen()
+#else
+ QApplication::desktop()->screenNumber( ppos )
+#endif // Q_WS_X11
+ );
+ QRect screen = QApplication::desktop()->screenGeometry( scr );
+
+ int x;
+ int w = whatsThat->width();
+ int h = whatsThat->height();
+ int sx = screen.x();
+ int sy = screen.y();
+
+ // first try locating the widget immediately above/below,
+ // with nice alignment if possible.
+ QPoint pos;
+ if ( widget )
+ pos = widget->mapToGlobal( QPoint( 0,0 ) );
+
+ if ( widget && w > widget->width() + 16 )
+ x = pos.x() + widget->width()/2 - w/2;
+ else
+ x = ppos.x() - w/2;
+
+ // squeeze it in if that would result in part of what's this
+ // being only partially visible
+ if ( x + w + shadowWidth > sx+screen.width() )
+ x = (widget? (QMIN(screen.width(),
+ pos.x() + widget->width())
+ ) : screen.width() )
+ - w;
+
+ if ( x < sx )
+ x = sx;
+
+ int y;
+ if ( widget && h > widget->height() + 16 ) {
+ y = pos.y() + widget->height() + 2; // below, two pixels spacing
+ // what's this is above or below, wherever there's most space
+ if ( y + h + 10 > sy+screen.height() )
+ y = pos.y() + 2 - shadowWidth - h; // above, overlap
+ }
+ y = ppos.y() + 2;
+
+ // squeeze it in if that would result in part of what's this
+ // being only partially visible
+ if ( y + h + shadowWidth > sy+screen.height() )
+ y = ( widget ? (QMIN(screen.height(),
+ pos.y() + widget->height())
+ ) : screen.height() )
+ - h;
+ if ( y < sy )
+ y = sy;
+
+ whatsThat->move( x, y );
+ whatsThat->show();
+}
+
+QWhatsThisPrivate::WhatsThisItem* QWhatsThisPrivate::newItem( QWidget * widget )
+{
+ WhatsThisItem * i = dict->find( (void *)widget );
+ if ( i )
+ QWhatsThis::remove( widget );
+ i = new WhatsThisItem;
+ dict->insert( (void *)widget, i );
+ QWidget * t = widget->topLevelWidget();
+ if ( !tlw->find( (void *)t ) ) {
+ tlw->insert( (void *)t, t );
+ t->installEventFilter( this );
+ }
+ connect( widget, SIGNAL(destroyed()), this, SLOT(cleanupWidget()) );
+ return i;
+}
+
+void QWhatsThisPrivate::add( QWidget * widget, QWhatsThis* special )
+{
+ newItem( widget )->whatsthis = special;
+}
+
+void QWhatsThisPrivate::add( QWidget * widget, const QString &text )
+{
+ newItem( widget )->s = text;
+}
+
+
+// and finally the What's This class itself
+
+/*!
+ Adds \a text as "What's this" help for \a widget. If the text is
+ rich text formatted (i.e. it contains markup) it will be rendered
+ with the default stylesheet QStyleSheet::defaultSheet().
+
+ The text is destroyed if the widget is later destroyed, so it need
+ not be explicitly removed.
+
+ \sa remove()
+*/
+void QWhatsThis::add( QWidget * widget, const QString &text )
+{
+ if ( text.isEmpty() )
+ return; // pointless
+ QWhatsThisPrivate::setUpWhatsThis();
+ wt->add(widget,text);
+}
+
+
+/*!
+ Removes the "What's this?" help associated with the \a widget.
+ This happens automatically if the widget is destroyed.
+
+ \sa add()
+*/
+void QWhatsThis::remove( QWidget * widget )
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ QWhatsThisPrivate::WhatsThisItem * i = wt->dict->find( (void *)widget );
+ if ( !i )
+ return;
+
+ wt->dict->take( (void *)widget );
+
+ i->deref();
+ if ( !i->count )
+ delete i;
+}
+
+
+/*!
+ Returns the what's this text for widget \a w or QString::null if
+ there is no "What's this?" help for the widget. \a pos contains
+ the mouse position; this is useful, for example, if you've
+ subclassed to make the text that is displayed position dependent.
+
+ If \a includeParents is TRUE, parent widgets are taken into
+ consideration as well when looking for what's this help text.
+
+ \sa add()
+*/
+QString QWhatsThis::textFor( QWidget * w, const QPoint& pos, bool includeParents )
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ QWhatsThisPrivate::WhatsThisItem * i = 0;
+ QPoint p = pos;
+ while( w && !i ) {
+ i = wt->dict->find( w );
+ if ( !includeParents )
+ break;
+ if ( !i ) {
+ p += w->pos();
+ w = w->parentWidget( TRUE );
+ }
+ }
+ if (!i)
+ return QString::null;
+ if ( i->whatsthis )
+ return i->whatsthis->text( p );
+ return i->s;
+}
+
+
+/*!
+ Creates a QToolButton preconfigured to enter "What's this?" mode
+ when clicked. You will often use this with a tool bar as \a
+ parent:
+ \code
+ (void) QWhatsThis::whatsThisButton( my_help_tool_bar );
+ \endcode
+*/
+QToolButton * QWhatsThis::whatsThisButton( QWidget * parent )
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ return new QWhatsThisButton( parent,
+ "automatic what's this? button" );
+}
+
+/*!
+ Constructs a dynamic "What's this?" object for \a widget. The
+ object is deleted when the \a widget is destroyed.
+
+ When the widget is queried by the user the text() function of this
+ QWhatsThis will be called to provide the appropriate text, rather
+ than using the text assigned by add().
+*/
+QWhatsThis::QWhatsThis( QWidget * widget)
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ wt->add(widget,this);
+}
+
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+QWhatsThis::~QWhatsThis()
+{
+}
+
+
+/*!
+ This virtual function returns the text for position \e p in the
+ widget that this "What's this?" object documents. If there is no
+ "What's this?" text for the position, QString::null is returned.
+
+ The default implementation returns QString::null.
+*/
+QString QWhatsThis::text( const QPoint & )
+{
+ return QString::null;
+}
+
+/*!
+ \fn bool QWhatsThis::clicked( const QString& href )
+
+ This virtual function is called when the user clicks inside the
+ "What's this?" window. \a href is the link the user clicked on, or
+ QString::null if there was no link.
+
+ If the function returns TRUE (the default), the "What's this?"
+ window is closed, otherwise it remains visible.
+
+ The default implementation ignores \a href and returns TRUE.
+*/
+bool QWhatsThis::clicked( const QString& )
+{
+ return TRUE;
+}
+
+
+/*!
+ Enters "What's this?" mode and returns immediately.
+
+ Qt will install a special cursor and take over mouse input until
+ the user clicks somewhere. It then shows any help available and
+ ends "What's this?" mode. Finally, Qt removes the special cursor
+ and help window and then restores ordinary event processing, at
+ which point the left mouse button is no longer pressed.
+
+ The user can also use the Esc key to leave "What's this?" mode.
+
+ \sa inWhatsThisMode(), leaveWhatsThisMode()
+*/
+
+void QWhatsThis::enterWhatsThisMode()
+{
+ QWhatsThisPrivate::setUpWhatsThis();
+ if ( wt->state == QWhatsThisPrivate::Inactive ) {
+ wt->enterWhatsThisMode();
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor( whatsThisCursor, FALSE );
+#endif
+ wt->state = QWhatsThisPrivate::Waiting;
+ qApp->installEventFilter( wt );
+ }
+}
+
+
+/*!
+ Returns TRUE if the application is in "What's this?" mode;
+ otherwise returns FALSE.
+
+ \sa enterWhatsThisMode(), leaveWhatsThisMode()
+*/
+bool QWhatsThis::inWhatsThisMode()
+{
+ if (!wt)
+ return FALSE;
+ return wt->state == QWhatsThisPrivate::Waiting;
+}
+
+
+/*!
+ Leaves "What's this?" question mode.
+
+ This function is used internally by widgets that support
+ QWidget::customWhatsThis(); applications do not usually call it.
+ An example of such a widget is QPopupMenu: menus still work
+ normally in "What's this?" mode but also provide help texts for
+ individual menu items.
+
+ If \a text is not QString::null, a "What's this?" help window is
+ displayed at the global screen position \a pos. If widget \a w is
+ not 0 and has its own dedicated QWhatsThis object, this object
+ will receive clicked() messages when the user clicks on hyperlinks
+ inside the help text.
+
+ \sa inWhatsThisMode(), enterWhatsThisMode(), QWhatsThis::clicked()
+*/
+void QWhatsThis::leaveWhatsThisMode( const QString& text, const QPoint& pos, QWidget* w )
+{
+ if ( !inWhatsThisMode() )
+ return;
+
+ wt->leaveWhatsThisMode();
+ if ( !text.isNull() )
+ wt->say( w, text, pos );
+}
+
+/*!
+ Display \a text in a help window at the global screen position \a
+ pos.
+
+ If widget \a w is not 0 and has its own dedicated QWhatsThis
+ object, this object will receive clicked() messages when the user
+ clicks on hyperlinks inside the help text.
+
+ \sa QWhatsThis::clicked()
+*/
+void QWhatsThis::display( const QString& text, const QPoint& pos, QWidget* w )
+{
+ if ( inWhatsThisMode() ) {
+ leaveWhatsThisMode( text, pos, w );
+ return;
+ }
+ QWhatsThisPrivate::setUpWhatsThis();
+ wt->say( w, text, pos );
+}
+
+/*!
+ Sets the font for all "What's this?" helps to \a font.
+*/
+void QWhatsThis::setFont( const QFont &font )
+{
+ QApplication::setFont( font, TRUE, "QWhatsThat" );
+}
+
+#include "qwhatsthis.moc"
+#endif
diff --git a/src/widgets/qwhatsthis.h b/src/widgets/qwhatsthis.h
new file mode 100644
index 0000000..6ad19d9
--- /dev/null
+++ b/src/widgets/qwhatsthis.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Definition of QWhatsThis class
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QWHATSTHIS_H
+#define QWHATSTHIS_H
+
+#ifndef QT_H
+#include "qobject.h"
+#endif // QT_H
+
+#ifndef QT_NO_WHATSTHIS
+
+#include "qcursor.h"
+
+class QToolButton;
+class QPopupMenu;
+class QStyleSheet;
+
+class Q_EXPORT QWhatsThis: public Qt
+{
+public:
+ QWhatsThis( QWidget *);
+ virtual ~QWhatsThis();
+
+ virtual QString text( const QPoint & );
+ virtual bool clicked( const QString& href );
+
+ // the common static functions
+ static void setFont( const QFont &font );
+
+ static void add( QWidget *, const QString &);
+ static void remove( QWidget * );
+ static QString textFor( QWidget *, const QPoint & pos = QPoint(), bool includeParents = FALSE );
+
+ static QToolButton * whatsThisButton( QWidget * parent );
+
+ static void enterWhatsThisMode();
+ static bool inWhatsThisMode();
+ static void leaveWhatsThisMode( const QString& = QString::null, const QPoint& pos = QCursor::pos(), QWidget* w = 0 );
+
+ static void display( const QString& text, const QPoint& pos = QCursor::pos(), QWidget* w = 0 );
+};
+
+#endif // QT_NO_WHATSTHIS
+
+#endif // QWHATSTHIS_H
diff --git a/src/widgets/qwidgetinterface_p.h b/src/widgets/qwidgetinterface_p.h
new file mode 100644
index 0000000..5a45ebc
--- /dev/null
+++ b/src/widgets/qwidgetinterface_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** ...
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QWIDGETINTERFACE_P_H
+#define QWIDGETINTERFACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+#ifndef QT_H
+#include <private/qcom_p.h>
+#include "qiconset.h"
+#endif // QT_H
+
+#ifndef QT_NO_WIDGETPLUGIN
+
+class QWidget;
+
+// {55184143-f18f-42c0-a8eb-71c01516019a}
+#ifndef IID_QWidgetFactory
+#define IID_QWidgetFactory QUuid( 0x55184143, 0xf18f, 0x42c0, 0xa8, 0xeb, 0x71, 0xc0, 0x15, 0x16, 0x1, 0x9a )
+#endif
+
+/*! To add custom widgets to the Qt Designer, implement that interface
+ in your custom widget plugin.
+
+ You also have to implement the function featureList() (\sa
+ QFeatureListInterface) and return there all widgets (names of it)
+ which this interface provides.
+*/
+
+struct QWidgetFactoryInterface : public QFeatureListInterface
+{
+public:
+
+ /*! In the implementation create and return the widget \a widget
+ here, use \a parent and \a name when creating the widget */
+ virtual QWidget* create( const QString &widget, QWidget* parent = 0, const char* name = 0 ) = 0;
+
+ /*! In the implementation return the name of the group of the
+ widget \a widget */
+ virtual QString group( const QString &widget ) const = 0;
+
+ /*! In the implementation return the iconset, which should be used
+ in the Qt Designer menubar and toolbar to represent the widget
+ \a widget */
+ virtual QIconSet iconSet( const QString &widget ) const = 0;
+
+ /*! In the implementation return the include file which is needed
+ for the widget \a widget in the generated code which uic
+ generates. */
+ virtual QString includeFile( const QString &widget ) const = 0;
+
+ /*! In the implementation return the text which should be
+ displayed as tooltip for the widget \a widget */
+ virtual QString toolTip( const QString &widget ) const = 0;
+
+ /*! In the implementation return the text which should be used for
+ what's this help for the widget \a widget. */
+ virtual QString whatsThis( const QString &widget ) const = 0;
+
+ /*! In the implementation return TRUE here, of the \a widget
+ should be able to contain other widget in the Qt Designer, else
+ FALSE. */
+ virtual bool isContainer( const QString &widget ) const = 0;
+};
+
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+// {15976628-e3c3-47f4-b525-d124a3caf30e}
+#ifndef IID_QWidgetContainer
+#define IID_QWidgetContainer QUuid( 0x15976628, 0xe3c3, 0x47f4, 0xb5, 0x25, 0xd1, 0x24, 0xa3, 0xca, 0xf3, 0x0e )
+#endif
+
+struct QWidgetContainerInterfacePrivate : public QUnknownInterface
+{
+public:
+ virtual QWidget *containerOfWidget( const QString &f, QWidget *container ) const = 0;
+ virtual bool isPassiveInteractor( const QString &f, QWidget *container ) const = 0;
+
+ virtual bool supportsPages( const QString &f ) const = 0;
+
+ virtual QWidget *addPage( const QString &f, QWidget *container,
+ const QString &name, int index ) const = 0;
+ virtual void insertPage( const QString &f, QWidget *container,
+ const QString &name, int index, QWidget *page ) const = 0;
+ virtual void removePage( const QString &f, QWidget *container, int index ) const = 0;
+ virtual void movePage( const QString &f, QWidget *container, int fromIndex, int toIndex ) const = 0;
+ virtual int count( const QString &key, QWidget *container ) const = 0;
+ virtual int currentIndex( const QString &key, QWidget *container ) const = 0;
+ virtual QString pageLabel( const QString &key, QWidget *container, int index ) const = 0;
+ virtual QWidget *page( const QString &key, QWidget *container, int index ) const = 0;
+ virtual void renamePage( const QString &key, QWidget *container,
+ int index, const QString &newName ) const = 0;
+ virtual QWidgetList pages( const QString &f, QWidget *container ) const = 0;
+ virtual QString createCode( const QString &f, const QString &container,
+ const QString &page, const QString &pageName ) const = 0;
+};
+
+#endif // QT_CONTAINER_CUSTOM_WIDGETS
+#endif // QT_NO_WIDGETPLUGIN
+#endif // QWIDGETINTERFACE_P_H
diff --git a/src/widgets/qwidgetplugin.cpp b/src/widgets/qwidgetplugin.cpp
new file mode 100644
index 0000000..77b633b
--- /dev/null
+++ b/src/widgets/qwidgetplugin.cpp
@@ -0,0 +1,729 @@
+/****************************************************************************
+**
+** Implementation of QWidgetPlugin class
+**
+** Created : 010920
+**
+** Copyright (C) 2001-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qwidgetplugin.h"
+
+#ifndef QT_NO_WIDGETPLUGIN
+#include "qwidgetinterface_p.h"
+#include "qobjectcleanuphandler.h"
+#include "qwidget.h"
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+#include "qwidgetlist.h"
+#endif
+
+/*!
+ \class QWidgetPlugin qwidgetplugin.h
+ \brief The QWidgetPlugin class provides an abstract base for custom QWidget plugins.
+
+ \ingroup plugins
+
+ The widget plugin is a simple plugin interface that makes it easy
+ to create custom widgets that can be included in forms using \link
+ designer-manual.book Qt Designer\endlink and used by applications.
+
+ Writing a widget plugin is achieved by subclassing this base
+ class, reimplementing the pure virtual functions keys(), create(),
+ group(), iconSet(), includeFile(), toolTip(), whatsThis() and
+ isContainer(), and exporting the class with the \c Q_EXPORT_PLUGIN
+ macro.
+
+ See the \link designer-manual.book Qt Designer manual's\endlink,
+ 'Creating Custom Widgets' section in the 'Creating Custom Widgets'
+ chapter, for a complete example of a QWidgetPlugin.
+
+ See also the \link plugins-howto.html Plugins
+ documentation\endlink and the \l{QWidgetFactory} class that is
+ supplied with \link designer-manual.book Qt Designer\endlink.
+*/
+
+class QWidgetPluginPrivate : public QWidgetFactoryInterface,
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+ public QWidgetContainerInterfacePrivate,
+#endif
+ private QLibraryInterface
+{
+public:
+ QWidgetPluginPrivate( QWidgetPlugin *p )
+ : plugin( p )
+ {
+ }
+
+ virtual ~QWidgetPluginPrivate();
+
+ QRESULT queryInterface( const QUuid &iid, QUnknownInterface **iface );
+ Q_REFCOUNT;
+
+ QStringList featureList() const;
+ QWidget *create( const QString &key, QWidget *parent, const char *name );
+ QString group( const QString &widget ) const;
+ QIconSet iconSet( const QString &widget ) const;
+ QString includeFile( const QString &widget ) const;
+ QString toolTip( const QString &widget ) const;
+ QString whatsThis( const QString &widget ) const;
+ bool isContainer( const QString &widget ) const;
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+ QWidget* containerOfWidget( const QString &key, QWidget *widget ) const;
+ bool isPassiveInteractor( const QString &key, QWidget *widget ) const;
+ bool supportsPages( const QString &key ) const;
+ QWidget *addPage( const QString &key, QWidget *container, const QString &name, int index ) const;
+ void insertPage( const QString &key, QWidget *container,
+ const QString &name, int index, QWidget *page ) const;
+ void Page( const QString &key, QWidget *container,
+ const QString &name, int index, QWidget *page ) const;
+ void removePage( const QString &key, QWidget *container, int index ) const;
+ void movePage( const QString &key, QWidget *container, int fromIndex, int toIndex ) const;
+ int count( const QString &key, QWidget *container ) const;
+ int currentIndex( const QString &key, QWidget *container ) const;
+ QString pageLabel( const QString &key, QWidget *container, int index ) const;
+ QWidget *page( const QString &key, QWidget *container, int index ) const;
+ void renamePage( const QString &key, QWidget *container, int index, const QString &newName ) const;
+ QWidgetList pages( const QString &key, QWidget *container ) const;
+ QString createCode( const QString &key, const QString &container,
+ const QString &page, const QString &pageName ) const;
+#endif // QT_CONTAINER_CUSTOM_WIDGETS
+ bool init();
+ void cleanup();
+ bool canUnload() const;
+
+private:
+ QWidgetPlugin *plugin;
+ QObjectCleanupHandler widgets;
+};
+
+QRESULT QWidgetPluginPrivate::queryInterface( const QUuid &iid, QUnknownInterface **iface )
+{
+ *iface = 0;
+
+ if ( iid == IID_QUnknown )
+ *iface = (QWidgetFactoryInterface*)this;
+ else if ( iid == IID_QFeatureList )
+ *iface = (QFeatureListInterface*)this;
+ else if ( iid == IID_QWidgetFactory )
+ *iface = (QWidgetFactoryInterface*)this;
+ else if ( iid == IID_QLibrary )
+ *iface = (QLibraryInterface*)this;
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+ else if ( iid == IID_QWidgetContainer )
+ *iface = (QWidgetContainerInterfacePrivate*)this;
+#endif
+ else
+ return QE_NOINTERFACE;
+
+ (*iface)->addRef();
+ return QS_OK;
+}
+
+/*!
+ \fn QStringList QWidgetPlugin::keys() const
+
+ Returns the list of widget keys this plugin supports.
+
+ These keys must be the class names of the custom widgets that are
+ implemented in the plugin.
+
+ \sa create()
+*/
+
+/*!
+ \fn QWidget *QWidgetPlugin::create( const QString &, QWidget *, const char * )
+
+ Creates and returns a QWidget object for the widget key \a key.
+ The widget key is the class name of the required widget. The \a
+ name and \a parent arguments are passed to the custom widget's
+ constructor.
+
+ \sa keys()
+*/
+
+QWidgetPluginPrivate::~QWidgetPluginPrivate()
+{
+ delete plugin;
+}
+
+QStringList QWidgetPluginPrivate::featureList() const
+{
+ return plugin->keys();
+}
+
+QWidget *QWidgetPluginPrivate::create( const QString &key, QWidget *parent, const char *name )
+{
+ QWidget *w = plugin->create( key, parent, name );
+ widgets.add( w );
+ return w;
+}
+
+QString QWidgetPluginPrivate::group( const QString &widget ) const
+{
+ return plugin->group( widget );
+}
+
+QIconSet QWidgetPluginPrivate::iconSet( const QString &widget ) const
+{
+ return plugin->iconSet( widget );
+}
+
+QString QWidgetPluginPrivate::includeFile( const QString &widget ) const
+{
+ return plugin->includeFile( widget );
+}
+
+QString QWidgetPluginPrivate::toolTip( const QString &widget ) const
+{
+ return plugin->toolTip( widget );
+}
+
+QString QWidgetPluginPrivate::whatsThis( const QString &widget ) const
+{
+ return plugin->whatsThis( widget );
+}
+
+bool QWidgetPluginPrivate::isContainer( const QString &widget ) const
+{
+ return plugin->isContainer( widget );
+}
+
+bool QWidgetPluginPrivate::init()
+{
+ return TRUE;
+}
+
+void QWidgetPluginPrivate::cleanup()
+{
+ widgets.clear();
+}
+
+bool QWidgetPluginPrivate::canUnload() const
+{
+ return widgets.isEmpty();
+}
+
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+QWidget* QWidgetPluginPrivate::containerOfWidget( const QString &key, QWidget *widget ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->containerOfWidget( key, widget );
+ return widget;
+}
+
+int QWidgetPluginPrivate::count( const QString &key, QWidget *container ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->count( key, container );
+ return 0;
+}
+
+int QWidgetPluginPrivate::currentIndex( const QString &key, QWidget *container ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->currentIndex( key, container );
+ return -1;
+}
+
+QString QWidgetPluginPrivate::pageLabel( const QString &key, QWidget *container, int index ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->pageLabel( key, container, index );
+ return QString::null;
+}
+
+QWidget *QWidgetPluginPrivate::page( const QString &key, QWidget *container, int index ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->page( key, container, index );
+ return 0;
+}
+
+bool QWidgetPluginPrivate::isPassiveInteractor( const QString &key, QWidget *widget ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->isPassiveInteractor( key, widget );
+ return FALSE;
+}
+
+bool QWidgetPluginPrivate::supportsPages( const QString &key ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->supportsPages( key );
+ return 0;
+}
+
+QWidget *QWidgetPluginPrivate::addPage( const QString &key, QWidget *container,
+ const QString &name, int index ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->addPage( key, container, name, index );
+ return 0;
+}
+
+void QWidgetPluginPrivate::insertPage( const QString &key, QWidget *container,
+ const QString &name, int index, QWidget *page ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ p->insertPage( key, container, name, index, page );
+}
+
+void QWidgetPluginPrivate::removePage( const QString &key, QWidget *container, int index ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ p->removePage( key, container, index );
+}
+
+void QWidgetPluginPrivate::movePage( const QString &key, QWidget *container,
+ int fromIndex, int toIndex ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ p->movePage( key, container, fromIndex, toIndex );
+}
+
+void QWidgetPluginPrivate::renamePage( const QString &key, QWidget *container,
+ int index, const QString &newName ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ p->renamePage( key, container, index, newName );
+}
+
+QWidgetList QWidgetPluginPrivate::pages( const QString &key, QWidget *container ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->pages( key, container );
+ return QWidgetList();
+}
+
+QString QWidgetPluginPrivate::createCode( const QString &key, const QString &container,
+ const QString &page, const QString &pageName ) const
+{
+ QWidgetContainerPlugin *p = (QWidgetContainerPlugin*)plugin->qt_cast( "QWidgetContainerPlugin" );
+ if ( p )
+ return p->createCode( key, container, page, pageName );
+ return QString::null;
+}
+#endif // QT_CONTAINER_CUSTOM_WIDGETS
+
+/*!
+ Constructs a widget plugin. This is invoked automatically by the
+ \c Q_EXPORT_PLUGIN macro.
+*/
+QWidgetPlugin::QWidgetPlugin()
+ : QGPlugin( (QWidgetFactoryInterface*)(d = new QWidgetPluginPrivate( this )) )
+{
+}
+
+/*!
+ Destroys the widget plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QWidgetPlugin::~QWidgetPlugin()
+{
+ // don't delete d, as this is deleted by d
+}
+
+/*!
+ Returns the group (toolbar name) that the custom widget of class
+ \a key should be part of when \e{Qt Designer} loads it.
+
+ The default implementation returns QString::null.
+*/
+QString QWidgetPlugin::group( const QString & ) const
+{
+ return QString::null;
+}
+
+/*!
+ Returns the iconset that \e{Qt Designer} should use to represent
+ the custom widget of class \a key in the toolbar.
+
+ The default implementation returns an null iconset.
+*/
+QIconSet QWidgetPlugin::iconSet( const QString & ) const
+{
+ return QIconSet();
+}
+
+/*!
+ Returns the name of the include file that \e{Qt Designer} and \c
+ uic should use to include the custom widget of class \a key in
+ generated code.
+
+ The default implementation returns QString::null.
+*/
+QString QWidgetPlugin::includeFile( const QString & ) const
+{
+ return QString::null;
+}
+
+/*!
+ Returns the text of the tooltip that \e{Qt Designer} should use
+ for the custom widget of class \a key's toolbar button.
+
+ The default implementation returns QString::null.
+*/
+QString QWidgetPlugin::toolTip( const QString & ) const
+{
+ return QString::null;
+}
+
+/*!
+ Returns the text of the whatsThis text that \e{Qt Designer} should
+ use when the user requests whatsThis help for the custom widget of
+ class \a key.
+
+ The default implementation returns QString::null.
+*/
+QString QWidgetPlugin::whatsThis( const QString & ) const
+{
+ return QString::null;
+}
+
+/*!
+ Returns TRUE if the custom widget of class \a key can contain
+ other widgets, e.g. like QFrame; otherwise returns FALSE.
+
+ The default implementation returns FALSE.
+*/
+bool QWidgetPlugin::isContainer( const QString & ) const
+{
+ return FALSE;
+}
+
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+
+/*!
+ \class QWidgetContainerPlugin qwidgetplugin.h
+ \brief The QWidgetContainerPlugin class provides an abstract base
+ for complex custom container QWidget plugins.
+
+ \internal
+
+ \ingroup plugins
+
+ The widget container plugin is a subclass of QWidgetPlugin and
+ extends the interface with functions necessary for supporting
+ complex container widgets via plugins. These container widgets are
+ widgets that have one or multiple sub widgets which act as the
+ widget's containers. If the widget has multiple container
+ subwidgets, they are referred to as "pages", and only one can be
+ active at a time. Examples of complex container widgets include:
+ QTabWidget, QWidgetStack and QToolBox.
+
+ Writing a complex container widget plugin is achieved by
+ subclassing this base class. First by reimplementing
+ QWidgetPlugin's pure virtual functions keys(), create(), group(),
+ iconSet(), includeFile(), toolTip(), whatsThis() and
+ isContainer(), and exporting the class with the \c Q_EXPORT_PLUGIN
+ macro. In addition containerOfWidget(), isPassiveInteractor() and
+ supportsPages() must be reimplemented. If the widget
+ supportsPages(), count(), currentIndex(), pageLabel(), page(),
+ pages() and createCode() must be implemented. If the widget
+ supportsPages() and you want to allow the containers pages to be
+ modified, you must also reimplement addPage(), insertPage(),
+ removePage(), movePage() and renamePage().
+
+ \sa QWidgetPlugin
+*/
+
+/*!
+ Constructs a complex container widget plugin. This is invoked
+ automatically by the \c Q_EXPORT_PLUGIN macro.
+*/
+
+QWidgetContainerPlugin::QWidgetContainerPlugin()
+ : QWidgetPlugin()
+{
+}
+
+/*!
+ Destroys the complex container widget plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+
+QWidgetContainerPlugin::~QWidgetContainerPlugin()
+{
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns the current \a container's custom widget. If the custom
+ widget is a tab widget, this function takes the \a container as
+ input and returns the widget's current page.
+
+ The default implementation returns \a container.
+*/
+
+QWidget* QWidgetContainerPlugin::containerOfWidget( const QString &,
+ QWidget *container ) const
+{
+ return container;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns the \a container custom widget's number of pages. If the
+ custom widget is a tab widget, this function returns the number of
+ tabs.
+
+ The default implementation returns 0.
+*/
+
+int QWidgetContainerPlugin::count( const QString &, QWidget * ) const
+{
+ return 0;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns the \a container custom widget's current page index. If
+ the custom widget is a tab widget, this function returns the
+ current tab's index.
+
+ The default implementation returns -1.
+*/
+
+int QWidgetContainerPlugin::currentIndex( const QString &, QWidget * ) const
+{
+ return -1;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns the \a container custom widget's label at position \a
+ index. If the custom widget is a tab widget, this function returns
+ the current tab's label.
+
+ The default implementation returns a null string.
+*/
+
+QString QWidgetContainerPlugin::pageLabel( const QString &, QWidget *, int ) const
+{
+ return QString::null;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns the \a container custom widget's page at position \a
+ index. If the custom widget is a tab widget, this function returns
+ the tab at index position \e index.
+
+
+ The default implementation returns 0.
+*/
+
+QWidget *QWidgetContainerPlugin::page( const QString &, QWidget *, int ) const
+{
+ return 0;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns TRUE if the \a container custom widget is a passive
+ interactor for class \e key; otherwise returns FALSE. The \a
+ container is a child widget of the actual custom widget.
+
+ Usually, when a custom widget is used in \e{Qt Designer}'s design
+ mode, no widget receives any mouse or key events, since \e{Qt
+ Designer} filters and processes them itself. If one or more
+ widgets of a custom widget still need to receive such events, for
+ example, because the widget needs to change pages, this function
+ must return TRUE for the widget. In such cases \e{Qt Designer}
+ will not filter out key and mouse events destined for the widget.
+
+ If the custom widget is a tab widget, the tab bar is the passive
+ interactor, since that's what the user will use to change pages.
+
+ The default implementation returns FALSE.
+*/
+
+bool QWidgetContainerPlugin::isPassiveInteractor( const QString &,
+ QWidget *container ) const
+{
+ Q_UNUSED( container )
+ return FALSE;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ Returns TRUE if the widget supports pages; otherwise returns
+ FALSE. If the custom widget is a tab widget this function should
+ return TRUE.
+
+ The default implementation returns FALSE.
+*/
+
+bool QWidgetContainerPlugin::supportsPages( const QString & ) const
+{
+ return FALSE;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function is called when a new page with the given \a name
+ should be added to the \a container custom widget at position \a
+ index.
+
+ The default implementation does nothing.
+*/
+
+QWidget* QWidgetContainerPlugin::addPage( const QString &, QWidget *,
+ const QString &, int ) const
+{
+ return 0;
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function is called when a new page, \a page, with the given
+ \a name should be added to the \a container custom widget at
+ position \a index.
+
+ The default implementation does nothing.
+*/
+
+void QWidgetContainerPlugin::insertPage( const QString &, QWidget *,
+ const QString &, int, QWidget * ) const
+{
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function is called when the page at position \a index should
+ be removed from the \a container custom widget.
+
+ The default implementation does nothing.
+*/
+
+void QWidgetContainerPlugin::removePage( const QString &, QWidget *, int ) const
+{
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function is called when the page at position \a fromIndex should
+ be moved to position \a toIndex in the \a container custom widget.
+
+ The default implementation does nothing.
+*/
+
+void QWidgetContainerPlugin::movePage( const QString &, QWidget *, int, int ) const
+{
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function is called when the page at position \a index should
+ be renamed (have its label changed) to \a newName in the \a
+ container custom widget.
+
+ The default implementation does nothing.
+*/
+
+void QWidgetContainerPlugin::renamePage( const QString &, QWidget *,
+ int, const QString & ) const
+{
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function should return a list of the \a container custom
+ widget's pages.
+*/
+
+QWidgetList QWidgetContainerPlugin::pages( const QString &, QWidget * ) const
+{
+ return QWidgetList();
+}
+
+/*!
+ Operates on the plugin's \a key class.
+
+ This function is called from \e{Qt Designer}'s User Interface
+ Compiler \c uic, when generating C++ code for inserting a page in
+ the \a container custom widget. The name of the page widget which
+ should be inserted at the end of the container is \a page, and the
+ label of the page should be \a pageName.
+
+ If the custom widget was a QTabWidget, the implementation of this
+ function should return:
+
+ \code
+ return widget + "->addTab( " + page + ", \"" + pageName + "\" )";
+ \endcode
+
+ Warning: If the code returned by this function contains invalid
+ C++ syntax, the generated \c uic code will not compile.
+*/
+
+QString QWidgetContainerPlugin::createCode( const QString &, const QString &,
+ const QString &, const QString & ) const
+{
+ return QString::null;
+}
+
+#endif // QT_CONTAINER_CUSTOM_WIDGETS
+
+#endif //QT_NO_WIDGETPLUGIN
diff --git a/src/widgets/qwidgetplugin.h b/src/widgets/qwidgetplugin.h
new file mode 100644
index 0000000..94e1ec7
--- /dev/null
+++ b/src/widgets/qwidgetplugin.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Definition of QWidgetPlugin class
+**
+** Created : 010920
+**
+** Copyright (C) 2001-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QWIDGETPLUGIN_H
+#define QWIDGETPLUGIN_H
+
+#ifndef QT_H
+#include "qgplugin.h"
+#include "qstringlist.h"
+#include "qiconset.h"
+#endif // QT_H
+#ifndef QT_NO_WIDGETPLUGIN
+
+#ifdef Q_WS_WIN
+#ifdef QT_PLUGIN
+#define QT_WIDGET_PLUGIN_EXPORT __declspec(dllexport)
+#else
+#define QT_WIDGET_PLUGIN_EXPORT __declspec(dllimport)
+#endif
+#else
+#define QT_WIDGET_PLUGIN_EXPORT
+#endif
+
+class QWidgetPluginPrivate;
+class QWidget;
+
+class Q_EXPORT QWidgetPlugin : public QGPlugin
+{
+ Q_OBJECT
+public:
+ QWidgetPlugin();
+ ~QWidgetPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QWidget *create( const QString &key, QWidget *parent = 0, const char *name = 0 ) = 0;
+
+ virtual QString group( const QString &key ) const;
+ virtual QIconSet iconSet( const QString &key ) const;
+ virtual QString includeFile( const QString &key ) const;
+ virtual QString toolTip( const QString &key ) const;
+ virtual QString whatsThis( const QString &key ) const;
+ virtual bool isContainer( const QString &key ) const;
+
+private:
+ QWidgetPluginPrivate *d;
+};
+
+#ifdef QT_CONTAINER_CUSTOM_WIDGETS
+
+class QWidgetContainerPluginPrivate;
+
+class Q_EXPORT QWidgetContainerPlugin : public QWidgetPlugin
+{
+
+public:
+ QWidgetContainerPlugin();
+ ~QWidgetContainerPlugin();
+
+ virtual QWidget* containerOfWidget( const QString &key, QWidget *container ) const;
+ virtual bool isPassiveInteractor( const QString &key, QWidget *container ) const;
+
+ virtual bool supportsPages( const QString &key ) const;
+
+ virtual QWidget *addPage( const QString &key, QWidget *container,
+ const QString &name, int index ) const;
+ virtual void insertPage( const QString &key, QWidget *container,
+ const QString &name, int index, QWidget *page ) const;
+ virtual void removePage( const QString &key, QWidget *container, int index ) const;
+ virtual void movePage( const QString &key, QWidget *container, int fromIndex, int toIndex ) const;
+ virtual int count( const QString &key, QWidget *container ) const;
+ virtual int currentIndex( const QString &key, QWidget *container ) const;
+ virtual QString pageLabel( const QString &key, QWidget *container, int index ) const;
+ virtual QWidget *page( const QString &key, QWidget *container, int index ) const;
+ virtual void renamePage( const QString &key, QWidget *container,
+ int index, const QString &newName ) const;
+ virtual QWidgetList pages( const QString &key, QWidget *container ) const;
+ virtual QString createCode( const QString &key, const QString &container,
+ const QString &page, const QString &pageName ) const;
+};
+
+#endif // QT_CONTAINER_CUSTOM_WIDGETS
+#endif // QT_NO_WIDGETPLUGIN
+#endif // QWIDGETPLUGIN_H
diff --git a/src/widgets/qwidgetresizehandler.cpp b/src/widgets/qwidgetresizehandler.cpp
new file mode 100644
index 0000000..44b414b
--- /dev/null
+++ b/src/widgets/qwidgetresizehandler.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Implementation of the QWidgetResizeHandler class
+**
+** Created : 001010
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the workspace module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qwidgetresizehandler_p.h"
+
+#ifndef QT_NO_RESIZEHANDLER
+#include "qframe.h"
+#include "qapplication.h"
+#include "qcursor.h"
+#include "qsizegrip.h"
+#if defined(Q_WS_WIN)
+#include "qt_windows.h"
+#endif
+
+#define RANGE 4
+
+static bool resizeHorizontalDirectionFixed = FALSE;
+static bool resizeVerticalDirectionFixed = FALSE;
+
+QWidgetResizeHandler::QWidgetResizeHandler( QWidget *parent, QWidget *cw, const char *name )
+ : QObject( parent, name ), widget( parent ), childWidget( cw ? cw : parent ),
+ extrahei( 0 ), buttonDown( FALSE ), moveResizeMode( FALSE ), sizeprotect( TRUE ), moving( TRUE )
+{
+ mode = Nowhere;
+ widget->setMouseTracking( TRUE );
+ QFrame *frame = ::qt_cast<QFrame*>(widget);
+ range = frame ? frame->frameWidth() : RANGE;
+ range = QMAX( RANGE, range );
+ activeForMove = activeForResize = TRUE;
+ qApp->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;
+}
+
+static QWidget *childOf( QWidget *w, QWidget *child )
+{
+ while ( child ) {
+ if ( child == w )
+ return child;
+ if ( child->isTopLevel() )
+ break;
+ child = child->parentWidget();
+ }
+ return 0;
+}
+
+bool QWidgetResizeHandler::eventFilter( QObject *o, QEvent *ee )
+{
+ if ( !isActive() || !o->isWidgetType() || !ee->spontaneous())
+ return FALSE;
+
+ if ( ee->type() != QEvent::MouseButtonPress &&
+ ee->type() != QEvent::MouseButtonRelease &&
+ ee->type() != QEvent::MouseMove &&
+ ee->type() != QEvent::KeyPress &&
+ ee->type() != QEvent::AccelOverride )
+ return FALSE;
+
+ QWidget *w = childOf( widget, (QWidget*)o );
+ if ( !w
+#ifndef QT_NO_SIZEGRIP
+ || ::qt_cast<QSizeGrip*>(o)
+#endif
+ || qApp->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() == LeftButton ) {
+ emit activate();
+ bool me = isMovingEnabled();
+ setMovingEnabled( me && o == widget );
+ mouseMoveEvent( e );
+ setMovingEnabled( me );
+ buttonDown = TRUE;
+ moveOffset = widget->mapFromGlobal( e->globalPos() );
+ invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
+ }
+ } break;
+ case QEvent::MouseButtonRelease:
+ if ( w->isMaximized() )
+ break;
+ if ( e->button() == LeftButton ) {
+ moveResizeMode = FALSE;
+ buttonDown = FALSE;
+ widget->releaseMouse();
+ widget->releaseKeyboard();
+ }
+ break;
+ case QEvent::MouseMove: {
+ if ( w->isMaximized() )
+ break;
+ bool me = isMovingEnabled();
+ setMovingEnabled( me && o == widget );
+ mouseMoveEvent( e );
+ setMovingEnabled( me );
+ if ( buttonDown && mode != Center )
+ return TRUE;
+ } break;
+ case QEvent::KeyPress:
+ keyPressEvent( (QKeyEvent*)e );
+ break;
+ case QEvent::AccelOverride:
+ 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 || ( e->state() & LeftButton ) == 0 ) ) {
+ 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
+ mode = Center;
+
+ if ( widget->isMinimized() || !isActive(Resize) )
+ mode = Center;
+#ifndef QT_NO_CURSOR
+ setMouseCursor( mode );
+#endif
+ return;
+ }
+
+ if ( buttonDown && !isMovingEnabled() && mode == Center && !moveResizeMode )
+ return;
+
+ if ( widget->testWState( WState_ConfigPending ) )
+ return;
+
+ QPoint globalPos = widget->parentWidget( TRUE ) ?
+ widget->parentWidget( TRUE )->mapFromGlobal( e->globalPos() ) : e->globalPos();
+ if ( widget->parentWidget( TRUE ) && !widget->parentWidget( TRUE )->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;
+
+ int fw = 0;
+ int mw = QMAX( childWidget->minimumSizeHint().width(),
+ childWidget->minimumWidth() );
+ int mh = QMAX( childWidget->minimumSizeHint().height(),
+ childWidget->minimumHeight() );
+ if ( childWidget != widget ) {
+ QFrame *frame = ::qt_cast<QFrame*>(widget);
+ if ( frame )
+ fw = frame->frameWidth();
+ mw += 2 * fw;
+ mh += 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) );
+ 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:
+ if ( isMovingEnabled() || moveResizeMode )
+ geom.moveTopLeft( pp );
+ break;
+ default:
+ break;
+ }
+
+ QSize maxsize( childWidget->maximumSize() );
+ if ( childWidget != widget )
+ maxsize += QSize( 2 * fw, 2 * fw + extrahei );
+
+ geom = QRect( geom.topLeft(),
+ geom.size().expandedTo( widget->minimumSize() )
+ .expandedTo( QSize(mw, mh) )
+ .boundedTo( maxsize ) );
+
+ if ( geom != widget->geometry() &&
+ ( widget->isTopLevel() || widget->parentWidget()->rect().intersects( geom ) ) ) {
+ if ( widget->isMinimized() )
+ widget->move( geom.topLeft() );
+ else
+ widget->setGeometry( geom );
+ }
+
+#if defined(Q_WS_WIN)
+ MSG msg;
+ QT_WA( {
+ while(PeekMessageW( &msg, widget->winId(), WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE ))
+ ;
+ } , {
+ while(PeekMessageA( &msg, widget->winId(), WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE ))
+ ;
+ } );
+#endif
+
+ QApplication::syncX();
+}
+
+void QWidgetResizeHandler::setMouseCursor( MousePosition m )
+{
+#ifndef QT_NO_CURSOR
+ switch ( m ) {
+ case TopLeft:
+ case BottomRight:
+ widget->setCursor( sizeFDiagCursor );
+ break;
+ case BottomLeft:
+ case TopRight:
+ widget->setCursor( sizeBDiagCursor );
+ break;
+ case Top:
+ case Bottom:
+ widget->setCursor( sizeVerCursor );
+ break;
+ case Left:
+ case Right:
+ widget->setCursor( sizeHorCursor );
+ break;
+ default:
+ widget->setCursor( arrowCursor );
+ break;
+ }
+#endif
+}
+
+void QWidgetResizeHandler::keyPressEvent( QKeyEvent * e )
+{
+ if ( !isMove() && !isResize() )
+ return;
+ bool is_control = e->state() & ControlButton;
+ int delta = is_control?1:8;
+ QPoint pos = QCursor::pos();
+ switch ( e->key() ) {
+ case 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 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 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 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 Key_Space:
+ case Key_Return:
+ case Key_Enter:
+ case Key_Escape:
+ moveResizeMode = FALSE;
+ widget->releaseMouse();
+ widget->releaseKeyboard();
+ buttonDown = FALSE;
+ break;
+ default:
+ return;
+ }
+ QCursor::setPos( pos );
+}
+
+
+void QWidgetResizeHandler::doResize()
+{
+ if ( !activeForResize )
+ return;
+
+ moveResizeMode = TRUE;
+ buttonDown = 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;
+ buttonDown = TRUE;
+ moveOffset = widget->mapFromGlobal( QCursor::pos() );
+ invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
+#ifndef QT_NO_CURSOR
+ widget->grabMouse( SizeAllCursor );
+#else
+ widget->grabMouse();
+#endif
+ widget->grabKeyboard();
+}
+
+#endif //QT_NO_RESIZEHANDLER
diff --git a/src/widgets/qwidgetresizehandler_p.h b/src/widgets/qwidgetresizehandler_p.h
new file mode 100644
index 0000000..3d3b6df
--- /dev/null
+++ b/src/widgets/qwidgetresizehandler_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Definition of the QWidgetResizeHandler class
+**
+** Created : 001010
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the workspace module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#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.
+//
+//
+
+#ifndef QT_H
+#include "qobject.h"
+#endif // QT_H
+#ifndef QT_NO_RESIZEHANDLER
+class QMouseEvent;
+class QKeyEvent;
+
+class Q_EXPORT QWidgetResizeHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Action {
+ Move = 0x01,
+ Resize = 0x02,
+ Any = Move|Resize
+ };
+
+ QWidgetResizeHandler( QWidget *parent, QWidget *cw = 0, const char *name = 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 ) { moving = b; }
+ bool isMovingEnabled() const { return moving; }
+
+ bool isButtonDown() const { return buttonDown; }
+
+ void setExtraHeight( int h ) { extrahei = h; }
+ void setSizeProtection( bool b ) { sizeprotect = b; }
+
+ void doResize();
+ void doMove();
+
+signals:
+ void activate();
+
+protected:
+ bool eventFilter( QObject *o, QEvent *e );
+ void mouseMoveEvent( QMouseEvent *e );
+ void keyPressEvent( QKeyEvent *e );
+
+private:
+ enum MousePosition {
+ Nowhere,
+ TopLeft, BottomRight, BottomLeft, TopRight,
+ Top, Bottom, Left, Right,
+ Center
+ };
+
+ QWidget *widget;
+ QWidget *childWidget;
+ QPoint moveOffset;
+ QPoint invertedMoveOffset;
+ MousePosition mode;
+ int extrahei;
+ int range;
+ uint buttonDown :1;
+ uint moveResizeMode :1;
+ uint activeForResize :1;
+ uint sizeprotect :1;
+ uint moving :1;
+ uint activeForMove :1;
+
+ void setMouseCursor( MousePosition m );
+ bool isMove() const {
+ return moveResizeMode && mode == Center;
+ }
+ bool isResize() const {
+ return moveResizeMode && !isMove();
+ }
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QWidgetResizeHandler( const QWidgetResizeHandler & );
+ QWidgetResizeHandler& operator=( const QWidgetResizeHandler & );
+#endif
+
+};
+
+#endif //QT_NO_RESIZEHANDLER
+#endif
diff --git a/src/widgets/qwidgetstack.cpp b/src/widgets/qwidgetstack.cpp
new file mode 100644
index 0000000..76dfc0b
--- /dev/null
+++ b/src/widgets/qwidgetstack.cpp
@@ -0,0 +1,610 @@
+/****************************************************************************
+**
+** Implementation of QWidgetStack class
+**
+** Created : 980128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qwidgetstack.h"
+#include "qlayout.h"
+#include "../kernel/qlayoutengine_p.h"
+#ifndef QT_NO_WIDGETSTACK
+
+#include "qobjectlist.h"
+#include "qfocusdata.h"
+#include "qbutton.h"
+#include "qbuttongroup.h"
+
+#include "qapplication.h"
+
+class QWidgetStackPrivate {
+public:
+ class Invisible: public QWidget
+ {
+ public:
+ Invisible( QWidgetStack * parent ): QWidget( parent, "qt_invisible_widgetstack" )
+ {
+ setBackgroundMode( NoBackground );
+ }
+ const char * className() const
+ {
+ return "QWidgetStackPrivate::Invisible";
+ }
+ };
+};
+
+
+#if (QT_VERSION-0 >= 0x040000)
+#if defined(Q_CC_GNU)
+#warning "Remove QWidgetStackEventFilter"
+#endif
+#endif
+class QWidgetStackEventFilter : public QObject
+{
+ /* For binary compatibility, since we cannot implement virtual
+ functions and rely on them being called. This is what we should
+ have
+
+ bool QWidgetStack::event( QEvent* e )
+ {
+ if ( e->type() == QEvent::LayoutHint )
+ updateGeometry(); // propgate layout hints to parent
+ return QFrame::event( e );
+ }
+ */
+public:
+
+ QWidgetStackEventFilter( QObject *parent = 0, const char * name = 0 )
+ : QObject( parent, name ) {}
+ bool eventFilter( QObject *o, QEvent * e ) {
+ if ( e->type() == QEvent::LayoutHint && o->isWidgetType() )
+ ((QWidget*)o)->updateGeometry();
+ return FALSE;
+ }
+};
+
+
+/*!
+ \class QWidgetStack
+ \brief The QWidgetStack class provides a stack of widgets of which
+ only the top widget is user-visible.
+
+ \ingroup organizers
+ \mainclass
+
+ The application programmer can move any widget to the top of the
+ stack at any time using raiseWidget(), and add or remove widgets
+ using addWidget() and removeWidget(). It is not sufficient to pass
+ the widget stack as parent to a widget which should be inserted into
+ the widgetstack.
+
+ visibleWidget() is the \e get equivalent of raiseWidget(); it
+ returns a pointer to the widget that is currently at the top of
+ the stack.
+
+ QWidgetStack also provides the ability to manipulate widgets
+ through application-specified integer IDs. You can also translate
+ from widget pointers to IDs using id() and from IDs to widget
+ pointers using widget(). These numeric IDs are unique (per
+ QWidgetStack, not globally), but QWidgetStack does not attach any
+ additional meaning to them.
+
+ The default widget stack is frameless, but you can use the usual
+ QFrame functions (such as setFrameStyle()) to add a frame.
+
+ QWidgetStack provides a signal, aboutToShow(), which is emitted
+ just before a managed widget is shown.
+
+ \sa QTabDialog QTabBar QFrame
+*/
+
+
+/*!
+ Constructs an empty widget stack.
+
+ The \a parent and \a name arguments are passed to the QFrame
+ constructor.
+*/
+
+QWidgetStack::QWidgetStack( QWidget * parent, const char *name )
+ : QFrame( parent, name )
+{
+ init();
+}
+
+/*!
+ Constructs an empty widget stack.
+
+ The \a parent, \a name and \a f arguments are passed to the QFrame
+ constructor.
+*/
+QWidgetStack::QWidgetStack( QWidget * parent, const char *name, WFlags f )
+ : QFrame( parent, name, f ) //## merge constructors in 4.0
+{
+ init();
+}
+
+void QWidgetStack::init()
+{
+ d = 0;
+ QWidgetStackEventFilter *ef = new QWidgetStackEventFilter( this );
+ installEventFilter( ef );
+ dict = new QIntDict<QWidget>;
+ focusWidgets = 0;
+ topWidget = 0;
+ invisible = new QWidgetStackPrivate::Invisible( this );
+ invisible->hide();
+}
+
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QWidgetStack::~QWidgetStack()
+{
+ delete focusWidgets;
+ delete d;
+ delete dict;
+}
+
+
+/*!
+ Adds widget \a w to this stack of widgets, with ID \a id.
+
+ If you pass an id \>= 0 this ID is used. If you pass an \a id of
+ -1 (the default), the widgets will be numbered automatically. If
+ you pass -2 a unique negative integer will be generated. No widget
+ has an ID of -1. Returns the ID or -1 on failure (e.g. \a w is 0).
+
+ If you pass an id that is already used, then a unique negative
+ integer will be generated to prevent two widgets having the same
+ id.
+
+ If \a w already exists in the stack the widget will be removed first.
+
+ If \a w is not a child of this QWidgetStack moves it using
+ reparent().
+*/
+
+int QWidgetStack::addWidget( QWidget * w, int id )
+{
+ static int nseq_no = -2;
+ static int pseq_no = 0;
+
+ if ( !w || w == invisible )
+ return -1;
+
+ // prevent duplicates
+ removeWidget( w );
+
+ if ( id >= 0 && dict->find( id ) )
+ id = -2;
+ if ( id < -1 )
+ id = nseq_no--;
+ else if ( id == -1 )
+ id = pseq_no++;
+ else
+ pseq_no = QMAX(pseq_no, id + 1);
+ // use id >= 0 as-is
+
+ dict->insert( id, w );
+
+ // preserve existing focus
+ QWidget * f = w->focusWidget();
+ while( f && f != w )
+ f = f->parentWidget();
+ if ( f ) {
+ if ( !focusWidgets )
+ focusWidgets = new QPtrDict<QWidget>( 17 );
+ focusWidgets->replace( w, w->focusWidget() );
+ }
+
+ w->hide();
+ if ( w->parent() != this )
+ w->reparent( this, contentsRect().topLeft(), FALSE );
+ w->setGeometry( contentsRect() );
+ updateGeometry();
+ return id;
+}
+
+
+/*!
+ Removes widget \a w from this stack of widgets. Does not delete \a
+ w. If \a w is the currently visible widget, no other widget is
+ substituted.
+
+ \sa visibleWidget() raiseWidget()
+*/
+
+void QWidgetStack::removeWidget( QWidget * w )
+{
+ if ( !w )
+ return;
+ int i = id( w );
+ if ( i != -1 )
+ dict->take( i );
+
+ if ( w == topWidget )
+ topWidget = 0;
+ if ( dict->isEmpty() )
+ invisible->hide(); // let background shine through again
+ updateGeometry();
+}
+
+
+/*!
+ Raises the widget with ID \a id to the top of the widget stack.
+
+ \sa visibleWidget()
+*/
+
+void QWidgetStack::raiseWidget( int id )
+{
+ if ( id == -1 )
+ return;
+ QWidget * w = dict->find( id );
+ if ( w )
+ raiseWidget( w );
+}
+
+static bool isChildOf( QWidget* child, QWidget *parent )
+{
+ const QObjectList *list = parent->children();
+ if ( !child || !list )
+ return FALSE;
+ QObjectListIt it(*list);
+ QObject *obj;
+ while ( (obj = it.current()) ) {
+ ++it;
+ if ( !obj->isWidgetType() || ((QWidget *)obj)->isTopLevel() )
+ continue;
+ QWidget *widget = (QWidget *)obj;
+ if ( widget == child || isChildOf( child, widget ) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*!
+ \overload
+
+ Raises widget \a w to the top of the widget stack.
+*/
+
+void QWidgetStack::raiseWidget( QWidget *w )
+{
+ if ( !w || w == invisible || w->parent() != this || w == topWidget )
+ return;
+
+ if ( id(w) == -1 )
+ addWidget( w );
+ if ( !isVisible() ) {
+ topWidget = w;
+ return;
+ }
+
+ if (w->maximumSize().width() < invisible->width()
+ || w->maximumSize().height() < invisible->height())
+ invisible->setBackgroundMode(backgroundMode());
+ else if (invisible->backgroundMode() != NoBackground)
+ invisible->setBackgroundMode(NoBackground);
+
+ if ( invisible->isHidden() ) {
+ invisible->setGeometry( contentsRect() );
+ invisible->lower();
+ invisible->show();
+ QApplication::sendPostedEvents( invisible, QEvent::ShowWindowRequest );
+ }
+
+ // try to move focus onto the incoming widget if focus
+ // was somewhere on the outgoing widget.
+ if ( topWidget ) {
+ QWidget * fw = focusWidget();
+ QWidget* p = fw;
+ while ( p && p != topWidget )
+ p = p->parentWidget();
+ if ( p == topWidget ) { // focus was on old page
+ if ( !focusWidgets )
+ focusWidgets = new QPtrDict<QWidget>( 17 );
+ focusWidgets->replace( topWidget, fw );
+ fw->clearFocus();
+ // look for the best focus widget we can find
+ // best == what we had (which may be deleted)
+ fw = focusWidgets->take( w );
+ if ( isChildOf( fw, w ) ) {
+ fw->setFocus();
+ } else {
+ // second best == first child widget in the focus chain
+ QFocusData *f = focusData();
+ QWidget* home = f->home();
+ QWidget *i = home;
+ do {
+ if ( ( ( i->focusPolicy() & TabFocus ) == TabFocus )
+ && !i->focusProxy() && i->isVisibleTo(w) && i->isEnabled() ) {
+ p = i;
+ while ( p && p != w )
+ p = p->parentWidget();
+ if ( p == w ) {
+ i->setFocus();
+ break;
+ }
+ }
+ i = f->next();
+ } while( i != home );
+ }
+ }
+ }
+
+ if ( isVisible() ) {
+ emit aboutToShow( w );
+ int i = id( w );
+ if ( i != -1 )
+ emit aboutToShow( i );
+ }
+
+ topWidget = w;
+
+ const QObjectList * c = children();
+ QObjectListIt it( *c );
+ QObject * o;
+
+ while( (o=it.current()) != 0 ) {
+ ++it;
+ if ( o->isWidgetType() && o != w && o != invisible )
+ ((QWidget *)o)->hide();
+ }
+
+ w->setGeometry( invisible->geometry() );
+ w->show();
+}
+
+/*!
+ \reimp
+*/
+
+void QWidgetStack::frameChanged()
+{
+ QFrame::frameChanged();
+ setChildGeometries();
+}
+
+
+/*!
+ \reimp
+*/
+
+void QWidgetStack::setFrameRect( const QRect & r )
+{
+ QFrame::setFrameRect( r );
+ setChildGeometries();
+}
+
+
+/*!
+ Fixes up the children's geometries.
+*/
+
+void QWidgetStack::setChildGeometries()
+{
+ invisible->setGeometry( contentsRect() );
+ if ( topWidget )
+ topWidget->setGeometry( invisible->geometry() );
+}
+
+
+/*!
+ \reimp
+*/
+void QWidgetStack::show()
+{
+ // Reimplemented in order to set the children's geometries
+ // appropriately and to pick the first widget as topWidget if no
+ // topwidget was defined
+ if ( !isVisible() && children() ) {
+ const QObjectList * c = children();
+ QObjectListIt it( *c );
+ QObject * o;
+
+ while( (o=it.current()) != 0 ) {
+ ++it;
+ if ( o->isWidgetType() ) {
+ if ( !topWidget && o != invisible )
+ topWidget = (QWidget*)o;
+ if ( o == topWidget )
+ ((QWidget *)o)->show();
+ else
+ ((QWidget *)o)->hide();
+ }
+ }
+ setChildGeometries();
+ }
+ QFrame::show();
+}
+
+
+/*!
+ Returns the widget with ID \a id. Returns 0 if this widget stack
+ does not manage a widget with ID \a id.
+
+ \sa id() addWidget()
+*/
+
+QWidget * QWidgetStack::widget( int id ) const
+{
+ return id != -1 ? dict->find( id ) : 0;
+}
+
+
+/*!
+ Returns the ID of the \a widget. Returns -1 if \a widget is 0 or
+ is not being managed by this widget stack.
+
+ \sa widget() addWidget()
+*/
+
+int QWidgetStack::id( QWidget * widget ) const
+{
+ if ( !widget )
+ return -1;
+
+ QIntDictIterator<QWidget> it( *dict );
+ while ( it.current() && it.current() != widget )
+ ++it;
+ return it.current() == widget ? it.currentKey() : -1;
+}
+
+
+/*!
+ Returns the currently visible widget (the one at the top of the
+ stack), or 0 if nothing is currently being shown.
+
+ \sa aboutToShow() id() raiseWidget()
+*/
+
+QWidget * QWidgetStack::visibleWidget() const
+{
+ return topWidget;
+}
+
+
+/*!
+ \fn void QWidgetStack::aboutToShow( int )
+
+ This signal is emitted just before a managed widget is shown if
+ that managed widget has an ID != -1. The argument is the numeric
+ ID of the widget.
+
+ If you call visibleWidget() in a slot connected to aboutToShow(),
+ the widget it returns is the one that is currently visible, not
+ the one that is about to be shown.
+*/
+
+
+/*!
+ \fn void QWidgetStack::aboutToShow( QWidget * )
+
+ \overload
+
+ This signal is emitted just before a managed widget is shown. The
+ argument is a pointer to the widget.
+
+ If you call visibleWidget() in a slot connected to aboutToShow(),
+ the widget returned is the one that is currently visible, not the
+ one that is about to be shown.
+*/
+
+
+/*!
+ \reimp
+*/
+
+void QWidgetStack::resizeEvent( QResizeEvent * e )
+{
+ QFrame::resizeEvent( e );
+ setChildGeometries();
+}
+
+
+/*!
+ \reimp
+*/
+
+QSize QWidgetStack::sizeHint() const
+{
+ constPolish();
+
+ QSize size( 0, 0 );
+
+ QIntDictIterator<QWidget> it( *dict );
+ QWidget *w;
+
+ while ( (w = it.current()) != 0 ) {
+ ++it;
+ QSize sh = w->sizeHint();
+ if ( w->sizePolicy().horData() == QSizePolicy::Ignored )
+ sh.rwidth() = 0;
+ if ( w->sizePolicy().verData() == QSizePolicy::Ignored )
+ sh.rheight() = 0;
+#ifndef QT_NO_LAYOUT
+ size = size.expandedTo( sh ).expandedTo( qSmartMinSize(w) );
+#endif
+ }
+ if ( size.isNull() )
+ size = QSize( 128, 64 );
+ size += QSize( 2*frameWidth(), 2*frameWidth() );
+ return size;
+}
+
+
+/*!
+ \reimp
+*/
+QSize QWidgetStack::minimumSizeHint() const
+{
+ constPolish();
+
+ QSize size( 0, 0 );
+
+ QIntDictIterator<QWidget> it( *dict );
+ QWidget *w;
+
+ while ( (w = it.current()) != 0 ) {
+ ++it;
+ QSize sh = w->minimumSizeHint();
+ if ( w->sizePolicy().horData() == QSizePolicy::Ignored )
+ sh.rwidth() = 0;
+ if ( w->sizePolicy().verData() == QSizePolicy::Ignored )
+ sh.rheight() = 0;
+#ifndef QT_NO_LAYOUT
+ size = size.expandedTo( sh ).expandedTo( w->minimumSize() );
+#endif
+ }
+ if ( size.isNull() )
+ size = QSize( 64, 32 );
+ size += QSize( 2*frameWidth(), 2*frameWidth() );
+ return size;
+}
+
+/*!
+ \reimp
+*/
+void QWidgetStack::childEvent( QChildEvent * e)
+{
+ if ( e->child()->isWidgetType() && e->removed() )
+ removeWidget( (QWidget*) e->child() );
+}
+#endif
diff --git a/src/widgets/qwidgetstack.h b/src/widgets/qwidgetstack.h
new file mode 100644
index 0000000..b87d668
--- /dev/null
+++ b/src/widgets/qwidgetstack.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Definition of QWidgetStack class
+**
+** Created : 980306
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#ifndef QWIDGETSTACK_H
+#define QWIDGETSTACK_H
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qintdict.h"
+#include "qptrdict.h"
+#endif // QT_H
+
+#ifndef QT_NO_WIDGETSTACK
+
+
+class QWidgetStackPrivate;
+
+
+class Q_EXPORT QWidgetStack: public QFrame
+{
+ Q_OBJECT
+public:
+ QWidgetStack( QWidget* parent=0, const char* name=0 );
+ QWidgetStack( QWidget* parent, const char* name, WFlags f);
+
+ ~QWidgetStack();
+
+ int addWidget( QWidget *, int = -1 );
+ void removeWidget( QWidget * );
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+ void show();
+
+ QWidget * widget( int ) const;
+ int id( QWidget * ) const;
+
+ QWidget * visibleWidget() const;
+
+ void setFrameRect( const QRect & );
+
+signals:
+ void aboutToShow( int );
+ void aboutToShow( QWidget * );
+
+public slots:
+ void raiseWidget( int );
+ void raiseWidget( QWidget * );
+
+protected:
+ void frameChanged();
+ void resizeEvent( QResizeEvent * );
+
+ virtual void setChildGeometries();
+ void childEvent( QChildEvent * );
+
+private:
+ void init();
+
+ QWidgetStackPrivate * d;
+ QIntDict<QWidget> * dict;
+ QPtrDict<QWidget> * focusWidgets;
+ QWidget * topWidget;
+ QWidget * invisible;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QWidgetStack( const QWidgetStack & );
+ QWidgetStack& operator=( const QWidgetStack & );
+#endif
+};
+
+#endif // QT_NO_WIDGETSTACK
+
+#endif // QWIDGETSTACK_H