src/gui/widgets/qabstractbutton.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /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