a398cc156795de0184197fb1bf5f74356e631aea
[profile/ivi/qtbase.git] / src / widgets / widgets / qabstractbutton.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qabstractbutton.h"
43 #include "qabstractitemview.h"
44 #include "qbuttongroup.h"
45 #include "qabstractbutton_p.h"
46 #include "qevent.h"
47 #include "qpainter.h"
48 #include "qapplication.h"
49 #include "qstyle.h"
50 #include "qaction.h"
51 #ifndef QT_NO_ACCESSIBILITY
52 #include "qaccessible.h"
53 #endif
54
55 QT_BEGIN_NAMESPACE
56
57 #define AUTO_REPEAT_DELAY  300
58 #define AUTO_REPEAT_INTERVAL 100
59
60 Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets;
61
62 /*!
63     \class QAbstractButton
64
65     \brief The QAbstractButton class is the abstract base class of
66     button widgets, providing functionality common to buttons.
67
68     \ingroup abstractwidgets
69     \inmodule QtWidgets
70
71     This class implements an \e abstract button.
72     Subclasses of this class handle user actions, and specify how the button
73     is drawn.
74
75     QAbstractButton provides support for both push buttons and checkable
76     (toggle) buttons. Checkable buttons are implemented in the QRadioButton
77     and QCheckBox classes. Push buttons are implemented in the
78     QPushButton and QToolButton classes; these also provide toggle
79     behavior if required.
80
81     Any button can display a label containing text and an icon. setText()
82     sets the text; setIcon() sets the icon. If a button is disabled, its label
83     is changed to give the button a "disabled" appearance.
84
85     If the button is a text button with a string containing an
86     ampersand ('&'), QAbstractButton automatically creates a shortcut
87     key. For example:
88
89     \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 0
90
91     The \key Alt+C shortcut is assigned to the button, i.e., when the
92     user presses \key Alt+C the button will call animateClick(). See
93     the \l {QShortcut#mnemonic}{QShortcut} documentation for details
94     (to display an actual ampersand, use '&&').
95
96     You can also set a custom shortcut key using the setShortcut()
97     function. This is useful mostly for buttons that do not have any
98     text, because they have no automatic shortcut.
99
100     \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 1
101
102     All of the buttons provided by Qt (QPushButton, QToolButton,
103     QCheckBox, and QRadioButton) can display both \l text and \l{icon}{icons}.
104
105     A button can be made the default button in a dialog are provided by
106     QPushButton::setDefault() and QPushButton::setAutoDefault().
107
108     QAbstractButton provides most of the states used for buttons:
109
110     \list
111
112     \o isDown() indicates whether the button is \e pressed down.
113
114     \o isChecked() indicates whether the button is \e checked.  Only
115     checkable buttons can be checked and unchecked (see below).
116
117     \o isEnabled() indicates whether the button can be pressed by the
118     user.
119
120     \o setAutoRepeat() sets whether the button will auto-repeat if the
121     user holds it down. \l autoRepeatDelay and \l autoRepeatInterval
122     define how auto-repetition is done.
123
124     \o setCheckable() sets whether the button is a toggle button or not.
125
126     \endlist
127
128     The difference between isDown() and isChecked() is as follows.
129     When the user clicks a toggle button to check it, the button is first
130     \e pressed then released into the \e checked state. When the user
131     clicks it again (to uncheck it), the button moves first to the
132     \e pressed state, then to the \e unchecked state (isChecked() and
133     isDown() are both false).
134
135     QAbstractButton provides four signals:
136
137     \list 1
138
139     \o pressed() is emitted when the left mouse button is pressed while
140     the mouse cursor is inside the button.
141
142     \o released() is emitted when the left mouse button is released.
143
144     \o clicked() is emitted when the button is first pressed and then
145     released, when the shortcut key is typed, or when click() or
146     animateClick() is called.
147
148     \o toggled() is emitted when the state of a toggle button changes.
149
150     \endlist
151
152     To subclass QAbstractButton, you must reimplement at least
153     paintEvent() to draw the button's outline and its text or pixmap. It
154     is generally advisable to reimplement sizeHint() as well, and
155     sometimes hitButton() (to determine whether a button press is within
156     the button). For buttons with more than two states (like tri-state
157     buttons), you will also have to reimplement checkStateSet() and
158     nextCheckState().
159
160     \sa QButtonGroup
161 */
162
163 QAbstractButtonPrivate::QAbstractButtonPrivate(QSizePolicy::ControlType type)
164     :
165 #ifndef QT_NO_SHORTCUT
166     shortcutId(0),
167 #endif
168     checkable(false), checked(false), autoRepeat(false), autoExclusive(false),
169     down(false), blockRefresh(false), pressed(false),
170 #ifndef QT_NO_BUTTONGROUP
171     group(0),
172 #endif
173     autoRepeatDelay(AUTO_REPEAT_DELAY),
174     autoRepeatInterval(AUTO_REPEAT_INTERVAL),
175     controlType(type)
176 {}
177
178 #ifndef QT_NO_BUTTONGROUP
179
180 class QButtonGroupPrivate: public QObjectPrivate
181 {
182     Q_DECLARE_PUBLIC(QButtonGroup)
183
184 public:
185     QButtonGroupPrivate():exclusive(true){}
186     QList<QAbstractButton *> buttonList;
187     QPointer<QAbstractButton> checkedButton;
188     void detectCheckedButton();
189     void notifyChecked(QAbstractButton *button);
190     bool exclusive;
191     QMap<QAbstractButton*, int> mapping;
192 };
193
194 QButtonGroup::QButtonGroup(QObject *parent)
195     : QObject(*new QButtonGroupPrivate, parent)
196 {
197 }
198
199 QButtonGroup::~QButtonGroup()
200 {
201     Q_D(QButtonGroup);
202     for (int i = 0; i < d->buttonList.count(); ++i)
203         d->buttonList.at(i)->d_func()->group = 0;
204 }
205
206
207 bool QButtonGroup::exclusive() const
208 {
209     Q_D(const QButtonGroup);
210     return d->exclusive;
211 }
212
213 void QButtonGroup::setExclusive(bool exclusive)
214 {
215     Q_D(QButtonGroup);
216     d->exclusive = exclusive;
217 }
218
219
220 // TODO: Qt 5: Merge with addButton(QAbstractButton *button, int id)
221 void QButtonGroup::addButton(QAbstractButton *button)
222 {
223     addButton(button, -1);
224 }
225
226 void QButtonGroup::addButton(QAbstractButton *button, int id)
227 {
228     Q_D(QButtonGroup);
229     if (QButtonGroup *previous = button->d_func()->group)
230         previous->removeButton(button);
231     button->d_func()->group = this;
232     d->buttonList.append(button);
233     if (id == -1) {
234         QList<int> ids = d->mapping.values();
235         if (ids.isEmpty())
236            d->mapping[button] = -2;
237         else {
238             qSort(ids);
239             d->mapping[button] = ids.first()-1;
240         }
241     } else {
242         d->mapping[button] = id;
243     }
244
245     if (d->exclusive && button->isChecked())
246         button->d_func()->notifyChecked();
247 }
248
249 void QButtonGroup::removeButton(QAbstractButton *button)
250 {
251     Q_D(QButtonGroup);
252     if (d->checkedButton == button) {
253         d->detectCheckedButton();
254     }
255     if (button->d_func()->group == this) {
256         button->d_func()->group = 0;
257         d->buttonList.removeAll(button);
258         d->mapping.remove(button);
259     }
260 }
261
262 QList<QAbstractButton*> QButtonGroup::buttons() const
263 {
264     Q_D(const QButtonGroup);
265     return d->buttonList;
266 }
267
268 QAbstractButton *QButtonGroup::checkedButton() const
269 {
270     Q_D(const QButtonGroup);
271     return d->checkedButton;
272 }
273
274 QAbstractButton *QButtonGroup::button(int id) const
275 {
276     Q_D(const QButtonGroup);
277     return d->mapping.key(id);
278 }
279
280 void QButtonGroup::setId(QAbstractButton *button, int id)
281 {
282     Q_D(QButtonGroup);
283     if (button && id != -1)
284         d->mapping[button] = id;
285 }
286
287 int QButtonGroup::id(QAbstractButton *button) const
288 {
289     Q_D(const QButtonGroup);
290     return d->mapping.value(button, -1);
291 }
292
293 int QButtonGroup::checkedId() const
294 {
295     Q_D(const QButtonGroup);
296     return d->mapping.value(d->checkedButton, -1);
297 }
298
299 // detect a checked button other than the current one
300 void QButtonGroupPrivate::detectCheckedButton()
301 {
302     QAbstractButton *previous = checkedButton;
303     checkedButton = 0;
304     if (exclusive)
305         return;
306     for (int i = 0; i < buttonList.count(); i++) {
307         if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) {
308             checkedButton = buttonList.at(i);
309             return;
310         }
311     }
312 }
313
314 #endif // QT_NO_BUTTONGROUP
315
316 QList<QAbstractButton *>QAbstractButtonPrivate::queryButtonList() const
317 {
318 #ifndef QT_NO_BUTTONGROUP
319     if (group)
320         return group->d_func()->buttonList;
321 #endif
322
323     QList<QAbstractButton*>candidates = parent->findChildren<QAbstractButton *>();
324     if (autoExclusive) {
325         for (int i = candidates.count() - 1; i >= 0; --i) {
326             QAbstractButton *candidate = candidates.at(i);
327             if (!candidate->autoExclusive()
328 #ifndef QT_NO_BUTTONGROUP
329                 || candidate->group()
330 #endif
331                 )
332                 candidates.removeAt(i);
333         }
334     }
335     return candidates;
336 }
337
338 QAbstractButton *QAbstractButtonPrivate::queryCheckedButton() const
339 {
340 #ifndef QT_NO_BUTTONGROUP
341     if (group)
342         return group->d_func()->checkedButton;
343 #endif
344
345     Q_Q(const QAbstractButton);
346     QList<QAbstractButton *> buttonList = queryButtonList();
347     if (!autoExclusive || buttonList.count() == 1) // no group
348         return 0;
349
350     for (int i = 0; i < buttonList.count(); ++i) {
351         QAbstractButton *b = buttonList.at(i);
352         if (b->d_func()->checked && b != q)
353             return b;
354     }
355     return checked  ? const_cast<QAbstractButton *>(q) : 0;
356 }
357
358 void QAbstractButtonPrivate::notifyChecked()
359 {
360 #ifndef QT_NO_BUTTONGROUP
361     Q_Q(QAbstractButton);
362     if (group) {
363         QAbstractButton *previous = group->d_func()->checkedButton;
364         group->d_func()->checkedButton = q;
365         if (group->d_func()->exclusive && previous && previous != q)
366             previous->nextCheckState();
367     } else
368 #endif
369     if (autoExclusive) {
370         if (QAbstractButton *b = queryCheckedButton())
371             b->setChecked(false);
372     }
373 }
374
375 void QAbstractButtonPrivate::moveFocus(int key)
376 {
377     QList<QAbstractButton *> buttonList = queryButtonList();;
378 #ifndef QT_NO_BUTTONGROUP
379     bool exclusive = group ? group->d_func()->exclusive : autoExclusive;
380 #else
381     bool exclusive = autoExclusive;
382 #endif
383     QWidget *f = QApplication::focusWidget();
384     QAbstractButton *fb = qobject_cast<QAbstractButton *>(f);
385     if (!fb || !buttonList.contains(fb))
386         return;
387     
388     QAbstractButton *candidate = 0;
389     int bestScore = -1;
390     QRect target = f->rect().translated(f->mapToGlobal(QPoint(0,0)));
391     QPoint goal = target.center();
392     uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
393
394     for (int i = 0; i < buttonList.count(); ++i) {
395         QAbstractButton *button = buttonList.at(i);
396         if (button != f && button->window() == f->window() && button->isEnabled() && !button->isHidden() &&
397             (autoExclusive || (button->focusPolicy() & focus_flag) == focus_flag)) {
398             QRect buttonRect = button->rect().translated(button->mapToGlobal(QPoint(0,0)));
399             QPoint p = buttonRect.center();
400
401             //Priority to widgets that overlap on the same coordinate.
402             //In that case, the distance in the direction will be used as significant score,
403             //take also in account orthogonal distance in case two widget are in the same distance.
404             int score;
405             if ((buttonRect.x() < target.right() && target.x() < buttonRect.right())
406                   && (key == Qt::Key_Up || key == Qt::Key_Down)) {
407                 //one item's is at the vertical of the other
408                 score = (qAbs(p.y() - goal.y()) << 16) + qAbs(p.x() - goal.x());
409             } else if ((buttonRect.y() < target.bottom() && target.y() < buttonRect.bottom())
410                         && (key == Qt::Key_Left || key == Qt::Key_Right) ) {
411                 //one item's is at the horizontal of the other
412                 score = (qAbs(p.x() - goal.x()) << 16) + qAbs(p.y() - goal.y());
413             } else {
414                 score = (1 << 30) + (p.y() - goal.y()) * (p.y() - goal.y()) + (p.x() - goal.x()) * (p.x() - goal.x());
415             }
416
417             if (score > bestScore && candidate)
418                 continue;
419
420             switch(key) {
421             case Qt::Key_Up:
422                 if (p.y() < goal.y()) {
423                     candidate = button;
424                     bestScore = score;
425                 }
426                 break;
427             case Qt::Key_Down:
428                 if (p.y() > goal.y()) {
429                     candidate = button;
430                     bestScore = score;
431                 }
432                 break;
433             case Qt::Key_Left:
434                 if (p.x() < goal.x()) {
435                     candidate = button;
436                     bestScore = score;
437                 }
438                 break;
439             case Qt::Key_Right:
440                 if (p.x() > goal.x()) {
441                     candidate = button;
442                     bestScore = score;
443                 }
444                 break;
445             }
446         }
447     }
448
449     if (exclusive
450 #ifdef QT_KEYPAD_NAVIGATION
451         && !QApplication::keypadNavigationEnabled()
452 #endif
453         && candidate
454         && fb->d_func()->checked
455         && candidate->d_func()->checkable)
456         candidate->click();
457
458     if (candidate) {
459         if (key == Qt::Key_Up || key == Qt::Key_Left)
460             candidate->setFocus(Qt::BacktabFocusReason);
461         else
462             candidate->setFocus(Qt::TabFocusReason);
463     }
464 }
465
466 void QAbstractButtonPrivate::fixFocusPolicy()
467 {
468     Q_Q(QAbstractButton);
469 #ifndef QT_NO_BUTTONGROUP
470     if (!group && !autoExclusive)
471 #else
472     if (!autoExclusive)
473 #endif
474         return;
475
476     QList<QAbstractButton *> buttonList = queryButtonList();
477     for (int i = 0; i < buttonList.count(); ++i) {
478         QAbstractButton *b = buttonList.at(i);
479         if (!b->isCheckable())
480             continue;
481         b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable())
482                                          ? (b->focusPolicy() | Qt::TabFocus)
483                                          :  (b->focusPolicy() & ~Qt::TabFocus)));
484     }
485 }
486
487 void QAbstractButtonPrivate::init()
488 {
489     Q_Q(QAbstractButton);
490
491     q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
492     q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType));
493     q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
494     q->setForegroundRole(QPalette::ButtonText);
495     q->setBackgroundRole(QPalette::Button);
496 }
497
498 void QAbstractButtonPrivate::refresh()
499 {
500     Q_Q(QAbstractButton);
501
502     if (blockRefresh)
503         return;
504     q->update();
505 #ifndef QT_NO_ACCESSIBILITY
506     QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::StateChanged, q, 0));
507 #endif
508 }
509
510 void QAbstractButtonPrivate::click()
511 {
512     Q_Q(QAbstractButton);
513
514     down = false;
515     blockRefresh = true;
516     bool changeState = true;
517     if (checked && queryCheckedButton() == q) {
518         // the checked button of an exclusive or autoexclusive group cannot be unchecked
519 #ifndef QT_NO_BUTTONGROUP
520         if (group ? group->d_func()->exclusive : autoExclusive)
521 #else
522         if (autoExclusive)
523 #endif
524             changeState = false;
525     }
526
527     QPointer<QAbstractButton> guard(q);
528     if (changeState) {
529         q->nextCheckState();
530         if (!guard)
531             return;
532     }
533     blockRefresh = false;
534     refresh();
535     q->repaint(); //flush paint event before invoking potentially expensive operation
536     QApplication::flush();
537     if (guard)
538         emitReleased();
539     if (guard)
540         emitClicked();
541 }
542
543 void QAbstractButtonPrivate::emitClicked()
544 {
545     Q_Q(QAbstractButton);
546     QPointer<QAbstractButton> guard(q);
547     emit q->clicked(checked);
548 #ifndef QT_NO_BUTTONGROUP
549     if (guard && group) {
550         emit group->buttonClicked(group->id(q));
551         if (guard && group)
552             emit group->buttonClicked(q);
553     }
554 #endif
555 }
556
557 void QAbstractButtonPrivate::emitPressed()
558 {
559     Q_Q(QAbstractButton);
560     QPointer<QAbstractButton> guard(q);
561     emit q->pressed();
562 #ifndef QT_NO_BUTTONGROUP
563     if (guard && group) {
564         emit group->buttonPressed(group->id(q));
565         if (guard && group)
566             emit group->buttonPressed(q);
567     }
568 #endif
569 }
570
571 void QAbstractButtonPrivate::emitReleased()
572 {
573     Q_Q(QAbstractButton);
574     QPointer<QAbstractButton> guard(q);
575     emit q->released();
576 #ifndef QT_NO_BUTTONGROUP
577     if (guard && group) {
578         emit group->buttonReleased(group->id(q));
579         if (guard && group)
580             emit group->buttonReleased(q);
581     }
582 #endif
583 }
584
585 /*!
586     Constructs an abstract button with a \a parent.
587 */
588 QAbstractButton::QAbstractButton(QWidget *parent)
589     : QWidget(*new QAbstractButtonPrivate, parent, 0)
590 {
591     Q_D(QAbstractButton);
592     d->init();
593 }
594
595 /*!
596     Destroys the button.
597  */
598  QAbstractButton::~QAbstractButton()
599 {
600 #ifndef QT_NO_BUTTONGROUP
601     Q_D(QAbstractButton);
602     if (d->group)
603         d->group->removeButton(this);
604 #endif
605 }
606
607
608 /*! \internal
609  */
610 QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent)
611     : QWidget(dd, parent, 0)
612 {
613     Q_D(QAbstractButton);
614     d->init();
615 }
616
617 /*!
618 \property QAbstractButton::text
619 \brief the text shown on the button
620
621 If the button has no text, the text() function will return a an empty
622 string.
623
624 If the text contains an ampersand character ('&'), a shortcut is
625 automatically created for it. The character that follows the '&' will
626 be used as the shortcut key. Any previous shortcut will be
627 overwritten, or cleared if no shortcut is defined by the text. See the
628 \l {QShortcut#mnemonic}{QShortcut} documentation for details (to
629 display an actual ampersand, use '&&').
630
631 There is no default text.
632 */
633
634 void QAbstractButton::setText(const QString &text)
635 {
636     Q_D(QAbstractButton);
637     if (d->text == text)
638         return;
639     d->text = text;
640 #ifndef QT_NO_SHORTCUT
641     QKeySequence newMnemonic = QKeySequence::mnemonic(text);
642     setShortcut(newMnemonic);
643 #endif
644     d->sizeHint = QSize();
645     update();
646     updateGeometry();
647 #ifndef QT_NO_ACCESSIBILITY
648     QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::NameChanged, this, 0));
649 #endif
650 }
651
652 QString QAbstractButton::text() const
653 {
654     Q_D(const QAbstractButton);
655     return d->text;
656 }
657
658
659 /*!
660   \property QAbstractButton::icon
661   \brief the icon shown on the button
662
663   The icon's default size is defined by the GUI style, but can be
664   adjusted by setting the \l iconSize property.
665 */
666 void QAbstractButton::setIcon(const QIcon &icon)
667 {
668     Q_D(QAbstractButton);
669     d->icon = icon;
670     d->sizeHint = QSize();
671     update();
672     updateGeometry();
673 }
674
675 QIcon QAbstractButton::icon() const
676 {
677     Q_D(const QAbstractButton);
678     return d->icon;
679 }
680
681 #ifndef QT_NO_SHORTCUT
682 /*!
683 \property QAbstractButton::shortcut
684 \brief the mnemonic associated with the button
685 */
686
687 void QAbstractButton::setShortcut(const QKeySequence &key)
688 {
689     Q_D(QAbstractButton);
690     if (d->shortcutId != 0)
691         releaseShortcut(d->shortcutId);
692     d->shortcut = key;
693     d->shortcutId = grabShortcut(key);
694 }
695
696 QKeySequence QAbstractButton::shortcut() const
697 {
698     Q_D(const QAbstractButton);
699     return d->shortcut;
700 }
701 #endif // QT_NO_SHORTCUT
702
703 /*!
704 \property QAbstractButton::checkable
705 \brief whether the button is checkable
706
707 By default, the button is not checkable.
708
709 \sa checked
710 */
711 void QAbstractButton::setCheckable(bool checkable)
712 {
713     Q_D(QAbstractButton);
714     if (d->checkable == checkable)
715         return;
716
717     d->checkable = checkable;
718     d->checked = false;
719 }
720
721 bool QAbstractButton::isCheckable() const
722 {
723     Q_D(const QAbstractButton);
724     return d->checkable;
725 }
726
727 /*!
728 \property QAbstractButton::checked
729 \brief whether the button is checked
730
731 Only checkable buttons can be checked. By default, the button is unchecked.
732
733 \sa checkable
734 */
735 void QAbstractButton::setChecked(bool checked)
736 {
737     Q_D(QAbstractButton);
738     if (!d->checkable || d->checked == checked) {
739         if (!d->blockRefresh)
740             checkStateSet();
741         return;
742     }
743
744     if (!checked && d->queryCheckedButton() == this) {
745         // the checked button of an exclusive or autoexclusive group cannot be  unchecked
746 #ifndef QT_NO_BUTTONGROUP
747         if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
748             return;
749         if (d->group)
750             d->group->d_func()->detectCheckedButton();
751 #else
752         if (d->autoExclusive)
753             return;
754 #endif
755     }
756
757     QPointer<QAbstractButton> guard(this);
758
759     d->checked = checked;
760     if (!d->blockRefresh)
761         checkStateSet();
762     d->refresh();
763
764     if (guard && checked)
765         d->notifyChecked();
766     if (guard)
767         emit toggled(checked);
768 }
769
770 bool QAbstractButton::isChecked() const
771 {
772     Q_D(const QAbstractButton);
773     return d->checked;
774 }
775
776 /*!
777   \property QAbstractButton::down
778   \brief whether the button is pressed down
779
780   If this property is true, the button is pressed down. The signals
781   pressed() and clicked() are not emitted if you set this property
782   to true. The default is false.
783 */
784
785 void QAbstractButton::setDown(bool down)
786 {
787     Q_D(QAbstractButton);
788     if (d->down == down)
789         return;
790     d->down = down;
791     d->refresh();
792     if (d->autoRepeat && d->down)
793         d->repeatTimer.start(d->autoRepeatDelay, this);
794     else
795         d->repeatTimer.stop();
796 }
797
798 bool QAbstractButton::isDown() const
799 {
800     Q_D(const QAbstractButton);
801     return d->down;
802 }
803
804 /*!
805 \property QAbstractButton::autoRepeat
806 \brief whether autoRepeat is enabled
807
808 If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at
809 regular intervals when the button is down. autoRepeat is off by default.
810 The initial delay and the repetition interval are defined in milliseconds by \l
811 autoRepeatDelay and \l autoRepeatInterval.
812
813 Note: If a button is pressed down by a shortcut key, then auto-repeat is enabled and timed by the
814 system and not by this class. The pressed(), released(), and clicked() signals will be emitted
815 like in the normal case.
816 */
817
818 void QAbstractButton::setAutoRepeat(bool autoRepeat)
819 {
820     Q_D(QAbstractButton);
821     if (d->autoRepeat == autoRepeat)
822         return;
823     d->autoRepeat = autoRepeat;
824     if (d->autoRepeat && d->down)
825         d->repeatTimer.start(d->autoRepeatDelay, this);
826     else
827         d->repeatTimer.stop();
828 }
829
830 bool QAbstractButton::autoRepeat() const
831 {
832     Q_D(const QAbstractButton);
833     return d->autoRepeat;
834 }
835
836 /*!
837     \property QAbstractButton::autoRepeatDelay
838     \brief the initial delay of auto-repetition
839     \since 4.2
840
841     If \l autoRepeat is enabled, then autoRepeatDelay defines the initial
842     delay in milliseconds before auto-repetition kicks in.
843
844     \sa autoRepeat, autoRepeatInterval
845 */
846
847 void QAbstractButton::setAutoRepeatDelay(int autoRepeatDelay)
848 {
849     Q_D(QAbstractButton);
850     d->autoRepeatDelay = autoRepeatDelay;
851 }
852
853 int QAbstractButton::autoRepeatDelay() const
854 {
855     Q_D(const QAbstractButton);
856     return d->autoRepeatDelay;
857 }
858
859 /*!
860     \property QAbstractButton::autoRepeatInterval
861     \brief the interval of auto-repetition
862     \since 4.2
863
864     If \l autoRepeat is enabled, then autoRepeatInterval defines the
865     length of the auto-repetition interval in millisecons.
866
867     \sa autoRepeat, autoRepeatDelay
868 */
869
870 void QAbstractButton::setAutoRepeatInterval(int autoRepeatInterval)
871 {
872     Q_D(QAbstractButton);
873     d->autoRepeatInterval = autoRepeatInterval;
874 }
875
876 int QAbstractButton::autoRepeatInterval() const
877 {
878     Q_D(const QAbstractButton);
879     return d->autoRepeatInterval;
880 }
881
882
883
884 /*!
885 \property QAbstractButton::autoExclusive
886 \brief whether auto-exclusivity is enabled
887
888 If auto-exclusivity is enabled, checkable buttons that belong to the
889 same parent widget behave as if they were part of the same
890 exclusive button group. In an exclusive button group, only one button
891 can be checked at any time; checking another button automatically
892 unchecks the previously checked one.
893
894 The property has no effect on buttons that belong to a button
895 group.
896
897 autoExclusive is off by default, except for radio buttons.
898
899 \sa QRadioButton
900 */
901 void QAbstractButton::setAutoExclusive(bool autoExclusive)
902 {
903     Q_D(QAbstractButton);
904     d->autoExclusive = autoExclusive;
905 }
906
907 bool QAbstractButton::autoExclusive() const
908 {
909     Q_D(const QAbstractButton);
910     return d->autoExclusive;
911 }
912
913 #ifndef QT_NO_BUTTONGROUP
914 /*!
915   Returns the group that this button belongs to.
916
917   If the button is not a member of any QButtonGroup, this function
918   returns 0.
919
920   \sa QButtonGroup
921 */
922 QButtonGroup *QAbstractButton::group() const
923 {
924     Q_D(const QAbstractButton);
925     return d->group;
926 }
927 #endif // QT_NO_BUTTONGROUP
928
929 /*!
930 Performs an animated click: the button is pressed immediately, and
931 released \a msec milliseconds later (the default is 100 ms).
932
933 Calling this function again before the button was released will reset
934 the release timer.
935
936 All signals associated with a click are emitted as appropriate.
937
938 This function does nothing if the button is \link setEnabled()
939 disabled. \endlink
940
941 \sa click()
942 */
943 void QAbstractButton::animateClick(int msec)
944 {
945     if (!isEnabled())
946         return;
947     Q_D(QAbstractButton);
948     if (d->checkable && focusPolicy() & Qt::ClickFocus)
949         setFocus();
950     setDown(true);
951     repaint(); //flush paint event before invoking potentially expensive operation
952     QApplication::flush();
953     if (!d->animateTimer.isActive())
954         d->emitPressed();
955     d->animateTimer.start(msec, this);
956 }
957
958 /*!
959 Performs a click.
960
961 All the usual signals associated with a click are emitted as
962 appropriate. If the button is checkable, the state of the button is
963 toggled.
964
965 This function does nothing if the button is \link setEnabled()
966 disabled. \endlink
967
968 \sa animateClick()
969  */
970 void QAbstractButton::click()
971 {
972     if (!isEnabled())
973         return;
974     Q_D(QAbstractButton);
975     QPointer<QAbstractButton> guard(this);
976     d->down = true;
977     d->emitPressed();
978     if (guard) {
979         d->down = false;
980         nextCheckState();
981         if (guard)
982             d->emitReleased();
983         if (guard)
984             d->emitClicked();
985     }
986 }
987
988 /*! \fn void QAbstractButton::toggle()
989
990     Toggles the state of a checkable button.
991
992      \sa checked
993 */
994 void QAbstractButton::toggle()
995 {
996     Q_D(QAbstractButton);
997     setChecked(!d->checked);
998 }
999
1000
1001 /*! This virtual handler is called when setChecked() was called,
1002 unless it was called from within nextCheckState(). It allows
1003 subclasses to reset their intermediate button states.
1004
1005 \sa nextCheckState()
1006  */
1007 void QAbstractButton::checkStateSet()
1008 {
1009 }
1010
1011 /*! This virtual handler is called when a button is clicked. The
1012 default implementation calls setChecked(!isChecked()) if the button
1013 isCheckable().  It allows subclasses to implement intermediate button
1014 states.
1015
1016 \sa checkStateSet()
1017 */
1018 void QAbstractButton::nextCheckState()
1019 {
1020     if (isCheckable())
1021         setChecked(!isChecked());
1022 }
1023
1024 /*!
1025 Returns true if \a pos is inside the clickable button rectangle;
1026 otherwise returns false.
1027
1028 By default, the clickable area is the entire widget. Subclasses
1029 may reimplement this function to provide support for clickable
1030 areas of different shapes and sizes.
1031 */
1032 bool QAbstractButton::hitButton(const QPoint &pos) const
1033 {
1034     return rect().contains(pos);
1035 }
1036
1037 /*! \reimp */
1038 bool QAbstractButton::event(QEvent *e)
1039 {
1040     // as opposed to other widgets, disabled buttons accept mouse
1041     // events. This avoids surprising click-through scenarios
1042     if (!isEnabled()) {
1043         switch(e->type()) {
1044         case QEvent::TabletPress:
1045         case QEvent::TabletRelease:
1046         case QEvent::TabletMove:
1047         case QEvent::MouseButtonPress:
1048         case QEvent::MouseButtonRelease:
1049         case QEvent::MouseButtonDblClick:
1050         case QEvent::MouseMove:
1051         case QEvent::HoverMove:
1052         case QEvent::HoverEnter:
1053         case QEvent::HoverLeave:
1054         case QEvent::ContextMenu:
1055 #ifndef QT_NO_WHEELEVENT
1056         case QEvent::Wheel:
1057 #endif
1058             return true;
1059         default:
1060             break;
1061         }
1062     }
1063
1064 #ifndef QT_NO_SHORTCUT
1065     if (e->type() == QEvent::Shortcut) {
1066         Q_D(QAbstractButton);
1067         QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1068         if (d->shortcutId != se->shortcutId())
1069             return false;
1070         if (!se->isAmbiguous()) {
1071             if (!d->animateTimer.isActive())
1072                 animateClick();
1073         } else {
1074             if (focusPolicy() != Qt::NoFocus)
1075                 setFocus(Qt::ShortcutFocusReason);
1076             window()->setAttribute(Qt::WA_KeyboardFocusChange);
1077         }
1078         return true;
1079     }
1080 #endif
1081     return QWidget::event(e);
1082 }
1083
1084 /*! \reimp */
1085 void QAbstractButton::mousePressEvent(QMouseEvent *e)
1086 {
1087     Q_D(QAbstractButton);
1088     if (e->button() != Qt::LeftButton) {
1089         e->ignore();
1090         return;
1091     }
1092     if (hitButton(e->pos())) {
1093         setDown(true);
1094         d->pressed = true;
1095         repaint(); //flush paint event before invoking potentially expensive operation
1096         QApplication::flush();
1097         d->emitPressed();
1098         e->accept();
1099     } else {
1100         e->ignore();
1101     }
1102 }
1103
1104 /*! \reimp */
1105 void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
1106 {
1107     Q_D(QAbstractButton);
1108     d->pressed = false;
1109
1110     if (e->button() != Qt::LeftButton) {
1111         e->ignore();
1112         return;
1113     }
1114
1115     if (!d->down) {
1116         e->ignore();
1117         return;
1118     }
1119
1120     if (hitButton(e->pos())) {
1121         d->repeatTimer.stop();
1122         d->click();
1123         e->accept();
1124     } else {
1125         setDown(false);
1126         e->ignore();
1127     }
1128 }
1129
1130 /*! \reimp */
1131 void QAbstractButton::mouseMoveEvent(QMouseEvent *e)
1132 {
1133     Q_D(QAbstractButton);
1134     if (!(e->buttons() & Qt::LeftButton) || !d->pressed) {
1135         e->ignore();
1136         return;
1137     }
1138
1139     if (hitButton(e->pos()) != d->down) {
1140         setDown(!d->down);
1141         repaint(); //flush paint event before invoking potentially expensive operation
1142         QApplication::flush();
1143         if (d->down)
1144             d->emitPressed();
1145         else
1146             d->emitReleased();
1147         e->accept();
1148     } else if (!hitButton(e->pos())) {
1149         e->ignore();
1150     }
1151 }
1152
1153 /*! \reimp */
1154 void QAbstractButton::keyPressEvent(QKeyEvent *e)
1155 {
1156     Q_D(QAbstractButton);
1157     bool next = true;
1158     switch (e->key()) {
1159     case Qt::Key_Enter:
1160     case Qt::Key_Return:
1161         e->ignore();
1162         break;
1163     case Qt::Key_Select:
1164     case Qt::Key_Space:
1165         if (!e->isAutoRepeat()) {
1166             setDown(true);
1167             repaint(); //flush paint event before invoking potentially expensive operation
1168             QApplication::flush();
1169             d->emitPressed();
1170         }
1171         break;
1172     case Qt::Key_Up:
1173     case Qt::Key_Left:
1174         next = false;
1175         // fall through
1176     case Qt::Key_Right:
1177     case Qt::Key_Down:
1178 #ifdef QT_KEYPAD_NAVIGATION
1179         if ((QApplication::keypadNavigationEnabled()
1180                 && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))
1181                 || (!QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
1182                 || (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down))) {
1183             e->ignore();
1184             return;
1185         }
1186 #endif
1187         QWidget *pw;
1188         if (d->autoExclusive
1189 #ifndef QT_NO_BUTTONGROUP
1190         || d->group
1191 #endif
1192 #ifndef QT_NO_ITEMVIEWS
1193         || ((pw = parentWidget()) && qobject_cast<QAbstractItemView *>(pw->parentWidget()))
1194 #endif
1195         ) {
1196             // ### Using qobject_cast to check if the parent is a viewport of
1197             // QAbstractItemView is a crude hack, and should be revisited and
1198             // cleaned up when fixing task 194373. It's here to ensure that we
1199             // keep compatibility outside QAbstractItemView.
1200             d->moveFocus(e->key());
1201             if (hasFocus()) // nothing happend, propagate
1202                 e->ignore();
1203         } else {
1204             focusNextPrevChild(next);
1205         }
1206         break;
1207     case Qt::Key_Escape:
1208         if (d->down) {
1209             setDown(false);
1210             repaint(); //flush paint event before invoking potentially expensive operation
1211             QApplication::flush();
1212             d->emitReleased();
1213             break;
1214         }
1215         // fall through
1216     default:
1217         e->ignore();
1218     }
1219 }
1220
1221 /*! \reimp */
1222 void QAbstractButton::keyReleaseEvent(QKeyEvent *e)
1223 {
1224     Q_D(QAbstractButton);
1225
1226     if (!e->isAutoRepeat())
1227         d->repeatTimer.stop();
1228
1229     switch (e->key()) {
1230     case Qt::Key_Select:
1231     case Qt::Key_Space:
1232         if (!e->isAutoRepeat() && d->down)
1233             d->click();
1234         break;
1235     default:
1236         e->ignore();
1237     }
1238 }
1239
1240 /*!\reimp
1241  */
1242 void QAbstractButton::timerEvent(QTimerEvent *e)
1243 {
1244     Q_D(QAbstractButton);
1245     if (e->timerId() == d->repeatTimer.timerId()) {
1246         d->repeatTimer.start(d->autoRepeatInterval, this);
1247         if (d->down) {
1248             QPointer<QAbstractButton> guard(this);
1249             nextCheckState();
1250             if (guard)
1251                 d->emitReleased();
1252             if (guard)
1253                 d->emitClicked();
1254             if (guard)
1255                 d->emitPressed();
1256         }
1257     } else if (e->timerId() == d->animateTimer.timerId()) {
1258         d->animateTimer.stop();
1259         d->click();
1260     }
1261 }
1262
1263 /*! \reimp */
1264 void QAbstractButton::focusInEvent(QFocusEvent *e)
1265 {
1266     Q_D(QAbstractButton);
1267 #ifdef QT_KEYPAD_NAVIGATION
1268     if (!QApplication::keypadNavigationEnabled())
1269 #endif
1270     d->fixFocusPolicy();
1271     QWidget::focusInEvent(e);
1272 }
1273
1274 /*! \reimp */
1275 void QAbstractButton::focusOutEvent(QFocusEvent *e)
1276 {
1277     Q_D(QAbstractButton);
1278     if (e->reason() != Qt::PopupFocusReason)
1279         d->down = false;
1280     QWidget::focusOutEvent(e);
1281 }
1282
1283 /*! \reimp */
1284 void QAbstractButton::changeEvent(QEvent *e)
1285 {
1286     Q_D(QAbstractButton);
1287     switch (e->type()) {
1288     case QEvent::EnabledChange:
1289         if (!isEnabled())
1290             setDown(false);
1291         break;
1292     default:
1293         d->sizeHint = QSize();
1294         break;
1295     }
1296     QWidget::changeEvent(e);
1297 }
1298
1299 /*!
1300     \fn void QAbstractButton::paintEvent(QPaintEvent *e)
1301     \reimp
1302 */
1303
1304 /*!
1305     \fn void QAbstractButton::pressed()
1306
1307     This signal is emitted when the button is pressed down.
1308
1309     \sa released(), clicked()
1310 */
1311
1312 /*!
1313     \fn void QAbstractButton::released()
1314
1315     This signal is emitted when the button is released.
1316
1317     \sa pressed(), clicked(), toggled()
1318 */
1319
1320 /*!
1321 \fn void QAbstractButton::clicked(bool checked)
1322
1323 This signal is emitted when the button is activated (i.e. pressed down
1324 then released while the mouse cursor is inside the button), when the
1325 shortcut key is typed, or when click() or animateClick() is called.
1326 Notably, this signal is \e not emitted if you call setDown(),
1327 setChecked() or toggle().
1328
1329 If the button is checkable, \a checked is true if the button is
1330 checked, or false if the button is unchecked.
1331
1332 \sa pressed(), released(), toggled()
1333 */
1334
1335 /*!
1336 \fn void QAbstractButton::toggled(bool checked)
1337
1338 This signal is emitted whenever a checkable button changes its state.
1339 \a checked is true if the button is checked, or false if the button is
1340 unchecked.
1341
1342 This may be the result of a user action, click() slot activation,
1343 or because setChecked() was called.
1344
1345 The states of buttons in exclusive button groups are updated before this
1346 signal is emitted. This means that slots can act on either the "off"
1347 signal or the "on" signal emitted by the buttons in the group whose
1348 states have changed.
1349
1350 For example, a slot that reacts to signals emitted by newly checked
1351 buttons but which ignores signals from buttons that have been unchecked
1352 can be implemented using the following pattern:
1353
1354 \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 2
1355
1356 Button groups can be created using the QButtonGroup class, and
1357 updates to the button states monitored with the
1358 \l{QButtonGroup::buttonClicked()} signal.
1359
1360 \sa checked, clicked()
1361 */
1362
1363 /*!
1364     \property QAbstractButton::iconSize
1365     \brief the icon size used for this button.
1366
1367     The default size is defined by the GUI style. This is a maximum
1368     size for the icons. Smaller icons will not be scaled up.
1369 */
1370
1371 QSize QAbstractButton::iconSize() const
1372 {
1373     Q_D(const QAbstractButton);
1374     if (d->iconSize.isValid())
1375         return d->iconSize;
1376     int e = style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, this);
1377     return QSize(e, e);
1378 }
1379
1380 void QAbstractButton::setIconSize(const QSize &size)
1381 {
1382     Q_D(QAbstractButton);
1383     if (d->iconSize == size)
1384         return;
1385
1386     d->iconSize = size;
1387     d->sizeHint = QSize();
1388     updateGeometry();
1389     if (isVisible()) {
1390         update();
1391     }
1392 }
1393
1394
1395
1396 QT_END_NAMESPACE