source: trunk/src/gui/widgets/qabstractbutton.cpp@ 112

Last change on this file since 112 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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