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