--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/widgets/qabstractbutton.cpp Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1467 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractbutton.h"
+#include "qabstractitemview.h"
+#include "qbuttongroup.h"
+#include "qabstractbutton_p.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qaction.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define AUTO_REPEAT_DELAY 300
+#define AUTO_REPEAT_INTERVAL 100
+
+extern bool qt_tab_all_widgets;
+
+/*!
+ \class QAbstractButton
+
+ \brief The QAbstractButton class is the abstract base class of
+ button widgets, providing functionality common to buttons.
+
+ \ingroup abstractwidgets
+
+ This class implements an \e abstract button.
+ Subclasses of this class handle user actions, and specify how the button
+ is drawn.
+
+ QAbstractButton provides support for both push buttons and checkable
+ (toggle) buttons. Checkable buttons are implemented in the QRadioButton
+ and QCheckBox classes. Push buttons are implemented in the
+ QPushButton and QToolButton classes; these also provide toggle
+ behavior if required.
+
+ Any button can display a label containing text and an icon. setText()
+ sets the text; setIcon() sets the icon. If a button is disabled, its label
+ is changed to give the button a "disabled" appearance.
+
+ If the button is a text button with a string containing an
+ ampersand ('&'), QAbstractButton automatically creates a shortcut
+ key. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 0
+
+ The \key Alt+C shortcut is assigned to the button, i.e., when the
+ user presses \key Alt+C the button will call animateClick(). See
+ the \l {QShortcut#mnemonic}{QShortcut} documentation for details
+ (to display an actual ampersand, use '&&').
+
+ You can also set a custom shortcut key using the setShortcut()
+ function. This is useful mostly for buttons that do not have any
+ text, because they have no automatic shortcut.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 1
+
+ All of the buttons provided by Qt (QPushButton, QToolButton,
+ QCheckBox, and QRadioButton) can display both \l text and \l{icon}{icons}.
+
+ A button can be made the default button in a dialog are provided by
+ QPushButton::setDefault() and QPushButton::setAutoDefault().
+
+ QAbstractButton provides most of the states used for buttons:
+
+ \list
+
+ \o isDown() indicates whether the button is \e pressed down.
+
+ \o isChecked() indicates whether the button is \e checked. Only
+ checkable buttons can be checked and unchecked (see below).
+
+ \o isEnabled() indicates whether the button can be pressed by the
+ user.
+
+ \o setAutoRepeat() sets whether the button will auto-repeat if the
+ user holds it down. \l autoRepeatDelay and \l autoRepeatInterval
+ define how auto-repetition is done.
+
+ \o setCheckable() sets whether the button is a toggle button or not.
+
+ \endlist
+
+ The difference between isDown() and isChecked() is as follows.
+ When the user clicks a toggle button to check it, the button is first
+ \e pressed then released into the \e checked state. When the user
+ clicks it again (to uncheck it), the button moves first to the
+ \e pressed state, then to the \e unchecked state (isChecked() and
+ isDown() are both false).
+
+ QAbstractButton provides four signals:
+
+ \list 1
+
+ \o pressed() is emitted when the left mouse button is pressed while
+ the mouse cursor is inside the button.
+
+ \o released() is emitted when the left mouse button is released.
+
+ \o clicked() is emitted when the button is first pressed and then
+ released, when the shortcut key is typed, or when click() or
+ animateClick() is called.
+
+ \o toggled() is emitted when the state of a toggle button changes.
+
+ \endlist
+
+ To subclass QAbstractButton, you must reimplement at least
+ paintEvent() to draw the button's outline and its text or pixmap. It
+ is generally advisable to reimplement sizeHint() as well, and
+ sometimes hitButton() (to determine whether a button press is within
+ the button). For buttons with more than two states (like tri-state
+ buttons), you will also have to reimplement checkStateSet() and
+ nextCheckState().
+
+ \sa QButtonGroup
+*/
+
+QAbstractButtonPrivate::QAbstractButtonPrivate(QSizePolicy::ControlType type)
+ :
+#ifndef QT_NO_SHORTCUT
+ shortcutId(0),
+#endif
+ checkable(false), checked(false), autoRepeat(false), autoExclusive(false),
+ down(false), blockRefresh(false),
+#ifndef QT_NO_BUTTONGROUP
+ group(0),
+#endif
+ autoRepeatDelay(AUTO_REPEAT_DELAY),
+ autoRepeatInterval(AUTO_REPEAT_INTERVAL),
+ controlType(type)
+{}
+
+#ifndef QT_NO_BUTTONGROUP
+
+class QButtonGroupPrivate: public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QButtonGroup)
+
+public:
+ QButtonGroupPrivate():exclusive(true){}
+ QList<QAbstractButton *> buttonList;
+ QPointer<QAbstractButton> checkedButton;
+ void detectCheckedButton();
+ void notifyChecked(QAbstractButton *button);
+ bool exclusive;
+ QMap<QAbstractButton*, int> mapping;
+};
+
+QButtonGroup::QButtonGroup(QObject *parent)
+ : QObject(*new QButtonGroupPrivate, parent)
+{
+}
+
+QButtonGroup::~QButtonGroup()
+{
+ Q_D(QButtonGroup);
+ for (int i = 0; i < d->buttonList.count(); ++i)
+ d->buttonList.at(i)->d_func()->group = 0;
+}
+
+
+bool QButtonGroup::exclusive() const
+{
+ Q_D(const QButtonGroup);
+ return d->exclusive;
+}
+
+void QButtonGroup::setExclusive(bool exclusive)
+{
+ Q_D(QButtonGroup);
+ d->exclusive = exclusive;
+}
+
+
+// TODO: Qt 5: Merge with addButton(QAbstractButton *button, int id)
+void QButtonGroup::addButton(QAbstractButton *button)
+{
+ addButton(button, -1);
+}
+
+void QButtonGroup::addButton(QAbstractButton *button, int id)
+{
+ Q_D(QButtonGroup);
+ if (QButtonGroup *previous = button->d_func()->group)
+ previous->removeButton(button);
+ button->d_func()->group = this;
+ d->buttonList.append(button);
+ if (id == -1) {
+ QList<int> ids = d->mapping.values();
+ if (ids.isEmpty())
+ d->mapping[button] = -2;
+ else {
+ qSort(ids);
+ d->mapping[button] = ids.first()-1;
+ }
+ } else {
+ d->mapping[button] = id;
+ }
+
+ if (d->exclusive && button->isChecked())
+ button->d_func()->notifyChecked();
+}
+
+void QButtonGroup::removeButton(QAbstractButton *button)
+{
+ Q_D(QButtonGroup);
+ if (d->checkedButton == button) {
+ d->detectCheckedButton();
+ }
+ if (button->d_func()->group == this) {
+ button->d_func()->group = 0;
+ d->buttonList.removeAll(button);
+ d->mapping.remove(button);
+ }
+}
+
+QList<QAbstractButton*> QButtonGroup::buttons() const
+{
+ Q_D(const QButtonGroup);
+ return d->buttonList;
+}
+
+QAbstractButton *QButtonGroup::checkedButton() const
+{
+ Q_D(const QButtonGroup);
+ return d->checkedButton;
+}
+
+QAbstractButton *QButtonGroup::button(int id) const
+{
+ Q_D(const QButtonGroup);
+ return d->mapping.key(id);
+}
+
+void QButtonGroup::setId(QAbstractButton *button, int id)
+{
+ Q_D(QButtonGroup);
+ if (button && id != -1)
+ d->mapping[button] = id;
+}
+
+int QButtonGroup::id(QAbstractButton *button) const
+{
+ Q_D(const QButtonGroup);
+ return d->mapping.value(button, -1);
+}
+
+int QButtonGroup::checkedId() const
+{
+ Q_D(const QButtonGroup);
+ return d->mapping.value(d->checkedButton, -1);
+}
+
+// detect a checked button other than the current one
+void QButtonGroupPrivate::detectCheckedButton()
+{
+ QAbstractButton *previous = checkedButton;
+ checkedButton = 0;
+ if (exclusive)
+ return;
+ for (int i = 0; i < buttonList.count(); i++) {
+ if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) {
+ checkedButton = buttonList.at(i);
+ return;
+ }
+ }
+}
+
+#endif // QT_NO_BUTTONGROUP
+
+QList<QAbstractButton *>QAbstractButtonPrivate::queryButtonList() const
+{
+#ifndef QT_NO_BUTTONGROUP
+ if (group)
+ return group->d_func()->buttonList;
+#endif
+
+ QList<QAbstractButton*>candidates = qFindChildren<QAbstractButton *>(parent);
+ if (autoExclusive) {
+ for (int i = candidates.count() - 1; i >= 0; --i) {
+ QAbstractButton *candidate = candidates.at(i);
+ if (!candidate->autoExclusive()
+#ifndef QT_NO_BUTTONGROUP
+ || candidate->group()
+#endif
+ )
+ candidates.removeAt(i);
+ }
+ }
+ return candidates;
+}
+
+QAbstractButton *QAbstractButtonPrivate::queryCheckedButton() const
+{
+#ifndef QT_NO_BUTTONGROUP
+ if (group)
+ return group->d_func()->checkedButton;
+#endif
+
+ Q_Q(const QAbstractButton);
+ QList<QAbstractButton *> buttonList = queryButtonList();
+ if (!autoExclusive || buttonList.count() == 1) // no group
+ return 0;
+
+ for (int i = 0; i < buttonList.count(); ++i) {
+ QAbstractButton *b = buttonList.at(i);
+ if (b->d_func()->checked && b != q)
+ return b;
+ }
+ return checked ? const_cast<QAbstractButton *>(q) : 0;
+}
+
+void QAbstractButtonPrivate::notifyChecked()
+{
+#ifndef QT_NO_BUTTONGROUP
+ Q_Q(QAbstractButton);
+ if (group) {
+ QAbstractButton *previous = group->d_func()->checkedButton;
+ group->d_func()->checkedButton = q;
+ if (group->d_func()->exclusive && previous && previous != q)
+ previous->nextCheckState();
+ } else
+#endif
+ if (autoExclusive) {
+ if (QAbstractButton *b = queryCheckedButton())
+ b->setChecked(false);
+ }
+}
+
+void QAbstractButtonPrivate::moveFocus(int key)
+{
+ QList<QAbstractButton *> buttonList = queryButtonList();;
+#ifndef QT_NO_BUTTONGROUP
+ bool exclusive = group ? group->d_func()->exclusive : autoExclusive;
+#else
+ bool exclusive = autoExclusive;
+#endif
+ QWidget *f = QApplication::focusWidget();
+ QAbstractButton *fb = qobject_cast<QAbstractButton *>(f);
+ if (!fb || !buttonList.contains(fb))
+ return;
+
+ QAbstractButton *candidate = 0;
+ int bestScore = -1;
+ QRect target = f->rect().translated(f->mapToGlobal(QPoint(0,0)));
+ QPoint goal = target.center();
+ uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
+
+ for (int i = 0; i < buttonList.count(); ++i) {
+ QAbstractButton *button = buttonList.at(i);
+ if (button != f && button->window() == f->window() && button->isEnabled() && !button->isHidden() &&
+ (autoExclusive || (button->focusPolicy() & focus_flag) == focus_flag)) {
+ QRect buttonRect = button->rect().translated(button->mapToGlobal(QPoint(0,0)));
+ QPoint p = buttonRect.center();
+
+ //Priority to widgets that overlap on the same coordinate.
+ //In that case, the distance in the direction will be used as significant score,
+ //take also in account orthogonal distance in case two widget are in the same distance.
+ int score;
+ if ((buttonRect.x() < target.right() && target.x() < buttonRect.right())
+ && (key == Qt::Key_Up || key == Qt::Key_Down)) {
+ //one item's is at the vertical of the other
+ score = (qAbs(p.y() - goal.y()) << 16) + qAbs(p.x() - goal.x());
+ } else if ((buttonRect.y() < target.bottom() && target.y() < buttonRect.bottom())
+ && (key == Qt::Key_Left || key == Qt::Key_Right) ) {
+ //one item's is at the horizontal of the other
+ score = (qAbs(p.x() - goal.x()) << 16) + qAbs(p.y() - goal.y());
+ } else {
+ score = (1 << 30) + (p.y() - goal.y()) * (p.y() - goal.y()) + (p.x() - goal.x()) * (p.x() - goal.x());
+ }
+
+ if (score > bestScore && candidate)
+ continue;
+
+ switch(key) {
+ case Qt::Key_Up:
+ if (p.y() < goal.y()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ case Qt::Key_Down:
+ if (p.y() > goal.y()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ case Qt::Key_Left:
+ if (p.x() < goal.x()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ case Qt::Key_Right:
+ if (p.x() > goal.x()) {
+ candidate = button;
+ bestScore = score;
+ }
+ break;
+ }
+ }
+ }
+
+ if (exclusive
+#ifdef QT_KEYPAD_NAVIGATION
+ && !QApplication::keypadNavigationEnabled()
+#endif
+ && candidate
+ && fb->d_func()->checked
+ && candidate->d_func()->checkable)
+ candidate->click();
+
+ if (candidate) {
+ if (key == Qt::Key_Up || key == Qt::Key_Left)
+ candidate->setFocus(Qt::BacktabFocusReason);
+ else
+ candidate->setFocus(Qt::TabFocusReason);
+ }
+}
+
+void QAbstractButtonPrivate::fixFocusPolicy()
+{
+ Q_Q(QAbstractButton);
+#ifndef QT_NO_BUTTONGROUP
+ if (!group && !autoExclusive)
+#else
+ if (!autoExclusive)
+#endif
+ return;
+
+ QList<QAbstractButton *> buttonList = queryButtonList();
+ for (int i = 0; i < buttonList.count(); ++i) {
+ QAbstractButton *b = buttonList.at(i);
+ if (!b->isCheckable())
+ continue;
+ b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable())
+ ? (b->focusPolicy() | Qt::TabFocus)
+ : (b->focusPolicy() & ~Qt::TabFocus)));
+ }
+}
+
+void QAbstractButtonPrivate::init()
+{
+ Q_Q(QAbstractButton);
+
+ q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
+ q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType));
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ q->setForegroundRole(QPalette::ButtonText);
+ q->setBackgroundRole(QPalette::Button);
+}
+
+void QAbstractButtonPrivate::refresh()
+{
+ Q_Q(QAbstractButton);
+
+ if (blockRefresh)
+ return;
+ q->update();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(q, 0, QAccessible::StateChanged);
+#endif
+}
+
+void QAbstractButtonPrivate::click()
+{
+ Q_Q(QAbstractButton);
+
+ down = false;
+ blockRefresh = true;
+ bool changeState = true;
+ if (checked && queryCheckedButton() == q) {
+ // the checked button of an exclusive or autoexclusive group cannot be unchecked
+#ifndef QT_NO_BUTTONGROUP
+ if (group ? group->d_func()->exclusive : autoExclusive)
+#else
+ if (autoExclusive)
+#endif
+ changeState = false;
+ }
+
+ QPointer<QAbstractButton> guard(q);
+ if (changeState) {
+ q->nextCheckState();
+ if (!guard)
+ return;
+ }
+ blockRefresh = false;
+ refresh();
+ q->repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ if (guard)
+ emitReleased();
+ if (guard)
+ emitClicked();
+}
+
+void QAbstractButtonPrivate::emitClicked()
+{
+ Q_Q(QAbstractButton);
+ QPointer<QAbstractButton> guard(q);
+ emit q->clicked(checked);
+#ifndef QT_NO_BUTTONGROUP
+ if (guard && group) {
+ emit group->buttonClicked(group->id(q));
+ if (guard && group)
+ emit group->buttonClicked(q);
+ }
+#endif
+}
+
+void QAbstractButtonPrivate::emitPressed()
+{
+ Q_Q(QAbstractButton);
+ QPointer<QAbstractButton> guard(q);
+ emit q->pressed();
+#ifndef QT_NO_BUTTONGROUP
+ if (guard && group) {
+ emit group->buttonPressed(group->id(q));
+ if (guard && group)
+ emit group->buttonPressed(q);
+ }
+#endif
+}
+
+void QAbstractButtonPrivate::emitReleased()
+{
+ Q_Q(QAbstractButton);
+ QPointer<QAbstractButton> guard(q);
+ emit q->released();
+#ifndef QT_NO_BUTTONGROUP
+ if (guard && group) {
+ emit group->buttonReleased(group->id(q));
+ if (guard && group)
+ emit group->buttonReleased(q);
+ }
+#endif
+}
+
+/*!
+ Constructs an abstract button with a \a parent.
+*/
+QAbstractButton::QAbstractButton(QWidget *parent)
+ : QWidget(*new QAbstractButtonPrivate, parent, 0)
+{
+ Q_D(QAbstractButton);
+ d->init();
+}
+
+/*!
+ Destroys the button.
+ */
+ QAbstractButton::~QAbstractButton()
+{
+#ifndef QT_NO_BUTTONGROUP
+ Q_D(QAbstractButton);
+ if (d->group)
+ d->group->removeButton(this);
+#endif
+}
+
+
+/*! \internal
+ */
+QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent)
+ : QWidget(dd, parent, 0)
+{
+ Q_D(QAbstractButton);
+ d->init();
+}
+
+/*!
+\property QAbstractButton::text
+\brief the text shown on the button
+
+If the button has no text, the text() function will return a an empty
+string.
+
+If the text contains an ampersand character ('&'), a shortcut is
+automatically created for it. The character that follows the '&' will
+be used as the shortcut key. Any previous shortcut will be
+overwritten, or cleared if no shortcut is defined by the text. See the
+\l {QShortcut#mnemonic}{QShortcut} documentation for details (to
+display an actual ampersand, use '&&').
+
+There is no default text.
+*/
+
+void QAbstractButton::setText(const QString &text)
+{
+ Q_D(QAbstractButton);
+ if (d->text == text)
+ return;
+ d->text = text;
+#ifndef QT_NO_SHORTCUT
+ QKeySequence newMnemonic = QKeySequence::mnemonic(text);
+ setShortcut(newMnemonic);
+#endif
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
+#endif
+}
+
+QString QAbstractButton::text() const
+{
+ Q_D(const QAbstractButton);
+ return d->text;
+}
+
+
+/*!
+ \property QAbstractButton::icon
+ \brief the icon shown on the button
+
+ The icon's default size is defined by the GUI style, but can be
+ adjusted by setting the \l iconSize property.
+*/
+void QAbstractButton::setIcon(const QIcon &icon)
+{
+ Q_D(QAbstractButton);
+ d->icon = icon;
+ d->sizeHint = QSize();
+ update();
+ updateGeometry();
+}
+
+QIcon QAbstractButton::icon() const
+{
+ Q_D(const QAbstractButton);
+ return d->icon;
+}
+
+#ifndef QT_NO_SHORTCUT
+/*!
+\property QAbstractButton::shortcut
+\brief the mnemonic associated with the button
+*/
+
+void QAbstractButton::setShortcut(const QKeySequence &key)
+{
+ Q_D(QAbstractButton);
+ if (d->shortcutId != 0)
+ releaseShortcut(d->shortcutId);
+ d->shortcut = key;
+ d->shortcutId = grabShortcut(key);
+}
+
+QKeySequence QAbstractButton::shortcut() const
+{
+ Q_D(const QAbstractButton);
+ return d->shortcut;
+}
+#endif // QT_NO_SHORTCUT
+
+/*!
+\property QAbstractButton::checkable
+\brief whether the button is checkable
+
+By default, the button is not checkable.
+
+\sa checked
+*/
+void QAbstractButton::setCheckable(bool checkable)
+{
+ Q_D(QAbstractButton);
+ if (d->checkable == checkable)
+ return;
+
+ d->checkable = checkable;
+ d->checked = false;
+}
+
+bool QAbstractButton::isCheckable() const
+{
+ Q_D(const QAbstractButton);
+ return d->checkable;
+}
+
+/*!
+\property QAbstractButton::checked
+\brief whether the button is checked
+
+Only checkable buttons can be checked. By default, the button is unchecked.
+
+\sa checkable
+*/
+void QAbstractButton::setChecked(bool checked)
+{
+ Q_D(QAbstractButton);
+ if (!d->checkable || d->checked == checked) {
+ if (!d->blockRefresh)
+ checkStateSet();
+ return;
+ }
+
+ if (!checked && d->queryCheckedButton() == this) {
+ // the checked button of an exclusive or autoexclusive group cannot be unchecked
+#ifndef QT_NO_BUTTONGROUP
+ if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
+ return;
+ if (d->group)
+ d->group->d_func()->detectCheckedButton();
+#else
+ if (d->autoExclusive)
+ return;
+#endif
+ }
+
+ QPointer<QAbstractButton> guard(this);
+
+ d->checked = checked;
+ if (!d->blockRefresh)
+ checkStateSet();
+ d->refresh();
+
+ if (guard && checked)
+ d->notifyChecked();
+ if (guard)
+ emit toggled(checked);
+}
+
+bool QAbstractButton::isChecked() const
+{
+ Q_D(const QAbstractButton);
+ return d->checked;
+}
+
+/*!
+ \property QAbstractButton::down
+ \brief whether the button is pressed down
+
+ If this property is true, the button is pressed down. The signals
+ pressed() and clicked() are not emitted if you set this property
+ to true. The default is false.
+*/
+
+void QAbstractButton::setDown(bool down)
+{
+ Q_D(QAbstractButton);
+ if (d->down == down)
+ return;
+ d->down = down;
+ d->refresh();
+ if (d->autoRepeat && d->down)
+ d->repeatTimer.start(d->autoRepeatDelay, this);
+ else
+ d->repeatTimer.stop();
+}
+
+bool QAbstractButton::isDown() const
+{
+ Q_D(const QAbstractButton);
+ return d->down;
+}
+
+/*!
+\property QAbstractButton::autoRepeat
+\brief whether autoRepeat is enabled
+
+If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at
+regular intervals when the button is down. autoRepeat is off by default.
+The initial delay and the repetition interval are defined in milliseconds by \l
+autoRepeatDelay and \l autoRepeatInterval.
+
+Note: If a button is pressed down by a shortcut key, then auto-repeat is enabled and timed by the
+system and not by this class. The pressed(), released(), and clicked() signals will be emitted
+like in the normal case.
+*/
+
+void QAbstractButton::setAutoRepeat(bool autoRepeat)
+{
+ Q_D(QAbstractButton);
+ if (d->autoRepeat == autoRepeat)
+ return;
+ d->autoRepeat = autoRepeat;
+ if (d->autoRepeat && d->down)
+ d->repeatTimer.start(d->autoRepeatDelay, this);
+ else
+ d->repeatTimer.stop();
+}
+
+bool QAbstractButton::autoRepeat() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoRepeat;
+}
+
+/*!
+ \property QAbstractButton::autoRepeatDelay
+ \brief the initial delay of auto-repetition
+ \since 4.2
+
+ If \l autoRepeat is enabled, then autoRepeatDelay defines the initial
+ delay in milliseconds before auto-repetition kicks in.
+
+ \sa autoRepeat, autoRepeatInterval
+*/
+
+void QAbstractButton::setAutoRepeatDelay(int autoRepeatDelay)
+{
+ Q_D(QAbstractButton);
+ d->autoRepeatDelay = autoRepeatDelay;
+}
+
+int QAbstractButton::autoRepeatDelay() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoRepeatDelay;
+}
+
+/*!
+ \property QAbstractButton::autoRepeatInterval
+ \brief the interval of auto-repetition
+ \since 4.2
+
+ If \l autoRepeat is enabled, then autoRepeatInterval defines the
+ length of the auto-repetition interval in millisecons.
+
+ \sa autoRepeat, autoRepeatDelay
+*/
+
+void QAbstractButton::setAutoRepeatInterval(int autoRepeatInterval)
+{
+ Q_D(QAbstractButton);
+ d->autoRepeatInterval = autoRepeatInterval;
+}
+
+int QAbstractButton::autoRepeatInterval() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoRepeatInterval;
+}
+
+
+
+/*!
+\property QAbstractButton::autoExclusive
+\brief whether auto-exclusivity is enabled
+
+If auto-exclusivity is enabled, checkable buttons that belong to the
+same parent widget behave as if they were part of the same
+exclusive button group. In an exclusive button group, only one button
+can be checked at any time; checking another button automatically
+unchecks the previously checked one.
+
+The property has no effect on buttons that belong to a button
+group.
+
+autoExclusive is off by default, except for radio buttons.
+
+\sa QRadioButton
+*/
+void QAbstractButton::setAutoExclusive(bool autoExclusive)
+{
+ Q_D(QAbstractButton);
+ d->autoExclusive = autoExclusive;
+}
+
+bool QAbstractButton::autoExclusive() const
+{
+ Q_D(const QAbstractButton);
+ return d->autoExclusive;
+}
+
+#ifndef QT_NO_BUTTONGROUP
+/*!
+ Returns the group that this button belongs to.
+
+ If the button is not a member of any QButtonGroup, this function
+ returns 0.
+
+ \sa QButtonGroup
+*/
+QButtonGroup *QAbstractButton::group() const
+{
+ Q_D(const QAbstractButton);
+ return d->group;
+}
+#endif // QT_NO_BUTTONGROUP
+
+/*!
+Performs an animated click: the button is pressed immediately, and
+released \a msec milliseconds later (the default is 100 ms).
+
+Calling this function again before the button was released will reset
+the release timer.
+
+All signals associated with a click are emitted as appropriate.
+
+This function does nothing if the button is \link setEnabled()
+disabled. \endlink
+
+\sa click()
+*/
+void QAbstractButton::animateClick(int msec)
+{
+ if (!isEnabled())
+ return;
+ Q_D(QAbstractButton);
+ if (d->checkable && focusPolicy() & Qt::ClickFocus)
+ setFocus();
+ setDown(true);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ if (!d->animateTimer.isActive())
+ d->emitPressed();
+ d->animateTimer.start(msec, this);
+}
+
+/*!
+Performs a click.
+
+All the usual signals associated with a click are emitted as
+appropriate. If the button is checkable, the state of the button is
+toggled.
+
+This function does nothing if the button is \link setEnabled()
+disabled. \endlink
+
+\sa animateClick()
+ */
+void QAbstractButton::click()
+{
+ if (!isEnabled())
+ return;
+ Q_D(QAbstractButton);
+ QPointer<QAbstractButton> guard(this);
+ d->down = true;
+ d->emitPressed();
+ if (guard) {
+ d->down = false;
+ nextCheckState();
+ if (guard)
+ d->emitReleased();
+ if (guard)
+ d->emitClicked();
+ }
+}
+
+/*! \fn void QAbstractButton::toggle()
+
+ Toggles the state of a checkable button.
+
+ \sa checked
+*/
+void QAbstractButton::toggle()
+{
+ Q_D(QAbstractButton);
+ setChecked(!d->checked);
+}
+
+
+/*! This virtual handler is called when setChecked() was called,
+unless it was called from within nextCheckState(). It allows
+subclasses to reset their intermediate button states.
+
+\sa nextCheckState()
+ */
+void QAbstractButton::checkStateSet()
+{
+}
+
+/*! This virtual handler is called when a button is clicked. The
+default implementation calls setChecked(!isChecked()) if the button
+isCheckable(). It allows subclasses to implement intermediate button
+states.
+
+\sa checkStateSet()
+*/
+void QAbstractButton::nextCheckState()
+{
+ if (isCheckable())
+ setChecked(!isChecked());
+}
+
+/*!
+Returns true if \a pos is inside the clickable button rectangle;
+otherwise returns false.
+
+By default, the clickable area is the entire widget. Subclasses
+may reimplement this function to provide support for clickable
+areas of different shapes and sizes.
+*/
+bool QAbstractButton::hitButton(const QPoint &pos) const
+{
+ return rect().contains(pos);
+}
+
+/*! \reimp */
+bool QAbstractButton::event(QEvent *e)
+{
+ // as opposed to other widgets, disabled buttons accept mouse
+ // events. This avoids surprising click-through scenarios
+ if (!isEnabled()) {
+ switch(e->type()) {
+ case QEvent::TabletPress:
+ case QEvent::TabletRelease:
+ case QEvent::TabletMove:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ case QEvent::HoverMove:
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::ContextMenu:
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::Wheel:
+#endif
+ return true;
+ default:
+ break;
+ }
+ }
+
+#ifndef QT_NO_SHORTCUT
+ if (e->type() == QEvent::Shortcut) {
+ Q_D(QAbstractButton);
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ if (d->shortcutId != se->shortcutId())
+ return false;
+ if (!se->isAmbiguous()) {
+ if (!d->animateTimer.isActive())
+ animateClick();
+ } else {
+ if (focusPolicy() != Qt::NoFocus)
+ setFocus(Qt::ShortcutFocusReason);
+ window()->setAttribute(Qt::WA_KeyboardFocusChange);
+ }
+ return true;
+ }
+#endif
+ return QWidget::event(e);
+}
+
+/*! \reimp */
+void QAbstractButton::mousePressEvent(QMouseEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->button() != Qt::LeftButton) {
+ e->ignore();
+ return;
+ }
+ if (hitButton(e->pos())) {
+ setDown(true);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ d->emitPressed();
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->button() != Qt::LeftButton) {
+ e->ignore();
+ return;
+ }
+
+ if (!d->down) {
+ e->ignore();
+ return;
+ }
+
+ if (hitButton(e->pos())) {
+ d->repeatTimer.stop();
+ d->click();
+ e->accept();
+ } else {
+ setDown(false);
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (!(e->buttons() & Qt::LeftButton)) {
+ e->ignore();
+ return;
+ }
+
+ if (hitButton(e->pos()) != d->down) {
+ setDown(!d->down);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ if (d->down)
+ d->emitPressed();
+ else
+ d->emitReleased();
+ e->accept();
+ } else if (!hitButton(e->pos())) {
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QAbstractButton);
+ bool next = true;
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ e->ignore();
+ break;
+ case Qt::Key_Select:
+ case Qt::Key_Space:
+ if (!e->isAutoRepeat()) {
+ setDown(true);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ d->emitPressed();
+ }
+ break;
+ case Qt::Key_Up:
+ case Qt::Key_Left:
+ next = false;
+ // fall through
+ case Qt::Key_Right:
+ case Qt::Key_Down:
+#ifdef QT_KEYPAD_NAVIGATION
+ if ((QApplication::keypadNavigationEnabled()
+ && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))
+ || (!QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
+ || (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down))) {
+ e->ignore();
+ return;
+ }
+#endif
+ QWidget *pw;
+ if (d->autoExclusive
+#ifndef QT_NO_BUTTONGROUP
+ || d->group
+#endif
+#ifndef QT_NO_ITEMVIEWS
+ || ((pw = parentWidget()) && qobject_cast<QAbstractItemView *>(pw->parentWidget()))
+#endif
+ ) {
+ // ### Using qobject_cast to check if the parent is a viewport of
+ // QAbstractItemView is a crude hack, and should be revisited and
+ // cleaned up when fixing task 194373. It's here to ensure that we
+ // keep compatibility outside QAbstractItemView.
+ d->moveFocus(e->key());
+ if (hasFocus()) // nothing happend, propagate
+ e->ignore();
+ } else {
+ focusNextPrevChild(next);
+ }
+ break;
+ case Qt::Key_Escape:
+ if (d->down) {
+ setDown(false);
+ repaint(); //flush paint event before invoking potentially expensive operation
+ QApplication::flush();
+ d->emitReleased();
+ break;
+ }
+ // fall through
+ default:
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::keyReleaseEvent(QKeyEvent *e)
+{
+ Q_D(QAbstractButton);
+
+ if (!e->isAutoRepeat())
+ d->repeatTimer.stop();
+
+ switch (e->key()) {
+ case Qt::Key_Select:
+ case Qt::Key_Space:
+ if (!e->isAutoRepeat() && d->down)
+ d->click();
+ break;
+ default:
+ e->ignore();
+ }
+}
+
+/*!\reimp
+ */
+void QAbstractButton::timerEvent(QTimerEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->timerId() == d->repeatTimer.timerId()) {
+ d->repeatTimer.start(d->autoRepeatInterval, this);
+ if (d->down) {
+ QPointer<QAbstractButton> guard(this);
+ nextCheckState();
+ if (guard)
+ d->emitReleased();
+ if (guard)
+ d->emitClicked();
+ if (guard)
+ d->emitPressed();
+ }
+ } else if (e->timerId() == d->animateTimer.timerId()) {
+ d->animateTimer.stop();
+ d->click();
+ }
+}
+
+/*! \reimp */
+void QAbstractButton::focusInEvent(QFocusEvent *e)
+{
+ Q_D(QAbstractButton);
+#ifdef QT_KEYPAD_NAVIGATION
+ if (!QApplication::keypadNavigationEnabled())
+#endif
+ d->fixFocusPolicy();
+ QWidget::focusInEvent(e);
+}
+
+/*! \reimp */
+void QAbstractButton::focusOutEvent(QFocusEvent *e)
+{
+ Q_D(QAbstractButton);
+ if (e->reason() != Qt::PopupFocusReason)
+ d->down = false;
+ QWidget::focusOutEvent(e);
+}
+
+/*! \reimp */
+void QAbstractButton::changeEvent(QEvent *e)
+{
+ Q_D(QAbstractButton);
+ switch (e->type()) {
+ case QEvent::EnabledChange:
+ if (!isEnabled())
+ setDown(false);
+ break;
+ default:
+ d->sizeHint = QSize();
+ break;
+ }
+ QWidget::changeEvent(e);
+}
+
+/*!
+ \fn void QAbstractButton::paintEvent(QPaintEvent *e)
+ \reimp
+*/
+
+/*!
+ \fn void QAbstractButton::pressed()
+
+ This signal is emitted when the button is pressed down.
+
+ \sa released(), clicked()
+*/
+
+/*!
+ \fn void QAbstractButton::released()
+
+ This signal is emitted when the button is released.
+
+ \sa pressed(), clicked(), toggled()
+*/
+
+/*!
+\fn void QAbstractButton::clicked(bool checked)
+
+This signal is emitted when the button is activated (i.e. pressed down
+then released while the mouse cursor is inside the button), when the
+shortcut key is typed, or when click() or animateClick() is called.
+Notably, this signal is \e not emitted if you call setDown(),
+setChecked() or toggle().
+
+If the button is checkable, \a checked is true if the button is
+checked, or false if the button is unchecked.
+
+\sa pressed(), released(), toggled()
+*/
+
+/*!
+\fn void QAbstractButton::toggled(bool checked)
+
+This signal is emitted whenever a checkable button changes its state.
+\a checked is true if the button is checked, or false if the button is
+unchecked.
+
+This may be the result of a user action, click() slot activation,
+or because setChecked() was called.
+
+The states of buttons in exclusive button groups are updated before this
+signal is emitted. This means that slots can act on either the "off"
+signal or the "on" signal emitted by the buttons in the group whose
+states have changed.
+
+For example, a slot that reacts to signals emitted by newly checked
+buttons but which ignores signals from buttons that have been unchecked
+can be implemented using the following pattern:
+
+\snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 2
+
+Button groups can be created using the QButtonGroup class, and
+updates to the button states monitored with the
+\l{QButtonGroup::buttonClicked()} signal.
+
+\sa checked, clicked()
+*/
+
+/*!
+ \property QAbstractButton::iconSize
+ \brief the icon size used for this button.
+
+ The default size is defined by the GUI style. This is a maximum
+ size for the icons. Smaller icons will not be scaled up.
+*/
+
+QSize QAbstractButton::iconSize() const
+{
+ Q_D(const QAbstractButton);
+ if (d->iconSize.isValid())
+ return d->iconSize;
+ int e = style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, this);
+ return QSize(e, e);
+}
+
+void QAbstractButton::setIconSize(const QSize &size)
+{
+ Q_D(QAbstractButton);
+ if (d->iconSize == size)
+ return;
+
+ d->iconSize = size;
+ d->sizeHint = QSize();
+ updateGeometry();
+ if (isVisible()) {
+ update();
+ }
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ Use icon() instead.
+*/
+QIcon *QAbstractButton::iconSet() const
+{
+ Q_D(const QAbstractButton);
+ if (!d->icon.isNull())
+ return const_cast<QIcon *>(&d->icon);
+ return 0;
+}
+
+/*!
+ Use QAbstractButton(QWidget *) instead.
+
+ Call setObjectName() if you want to specify an object name, and
+ setParent() if you want to set the window flags.
+*/
+QAbstractButton::QAbstractButton(QWidget *parent, const char *name, Qt::WindowFlags f)
+ : QWidget(*new QAbstractButtonPrivate, parent, f)
+{
+ Q_D(QAbstractButton);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*! \fn bool QAbstractButton::isOn() const
+
+ Use isChecked() instead.
+*/
+
+/*!
+ \fn QPixmap *QAbstractButton::pixmap() const
+
+ This compatibility function always returns 0.
+
+ Use icon() instead.
+*/
+
+/*! \fn void QAbstractButton::setPixmap(const QPixmap &p)
+
+ Use setIcon() instead.
+*/
+
+/*! \fn void QAbstractButton::setIconSet(const QIcon &icon)
+
+ Use setIcon() instead.
+*/
+
+/*! \fn void QAbstractButton::setOn(bool b)
+
+ Use setChecked() instead.
+*/
+
+/*! \fn bool QAbstractButton::isToggleButton() const
+
+ Use isCheckable() instead.
+*/
+
+/*!
+ \fn void QAbstractButton::setToggleButton(bool b)
+
+ Use setCheckable() instead.
+*/
+
+/*! \fn void QAbstractButton::setAccel(const QKeySequence &key)
+
+ Use setShortcut() instead.
+*/
+
+/*! \fn QKeySequence QAbstractButton::accel() const
+
+ Use shortcut() instead.
+*/
+#endif
+
+QT_END_NAMESPACE