source: trunk/src/gui/widgets/qdialogbuttonbox.cpp@ 1166

Last change on this file since 1166 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 41.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtCore/qhash.h>
43#include <QtGui/qpushbutton.h>
44#include <QtGui/qstyle.h>
45#include <QtGui/qlayout.h>
46#include <QtGui/qdialog.h>
47#include <QtGui/qapplication.h>
48#include <QtGui/private/qwidget_p.h>
49#include <QtGui/qaction.h>
50
51#include "qdialogbuttonbox.h"
52
53#ifdef QT_SOFTKEYS_ENABLED
54#include <QtGui/qaction.h>
55#endif
56
57
58QT_BEGIN_NAMESPACE
59
60/*!
61 \class QDialogButtonBox
62 \since 4.2
63 \brief The QDialogButtonBox class is a widget that presents buttons in a
64 layout that is appropriate to the current widget style.
65
66 \ingroup dialog-classes
67
68
69 Dialogs and message boxes typically present buttons in a layout that
70 conforms to the interface guidelines for that platform. Invariably,
71 different platforms have different layouts for their dialogs.
72 QDialogButtonBox allows a developer to add buttons to it and will
73 automatically use the appropriate layout for the user's desktop
74 environment.
75
76 Most buttons for a dialog follow certain roles. Such roles include:
77
78 \list
79 \o Accepting or rejecting the dialog.
80 \o Asking for help.
81 \o Performing actions on the dialog itself (such as resetting fields or
82 applying changes).
83 \endlist
84
85 There can also be alternate ways of dismissing the dialog which may cause
86 destructive results.
87
88 Most dialogs have buttons that can almost be considered standard (e.g.
89 \gui OK and \gui Cancel buttons). It is sometimes convenient to create these
90 buttons in a standard way.
91
92 There are a couple ways of using QDialogButtonBox. One ways is to create
93 the buttons (or button texts) yourself and add them to the button box,
94 specifying their role.
95
96 \snippet examples/dialogs/extension/finddialog.cpp 1
97
98 Alternatively, QDialogButtonBox provides several standard buttons (e.g. OK, Cancel, Save)
99 that you can use. They exist as flags so you can OR them together in the constructor.
100
101 \snippet examples/dialogs/tabdialog/tabdialog.cpp 2
102
103 You can mix and match normal buttons and standard buttons.
104
105 Currently the buttons are laid out in the following way if the button box is horizontal:
106 \table
107 \row \o \inlineimage buttonbox-gnomelayout-horizontal.png GnomeLayout Horizontal
108 \o Button box laid out in horizontal GnomeLayout
109 \row \o \inlineimage buttonbox-kdelayout-horizontal.png KdeLayout Horizontal
110 \o Button box laid out in horizontal KdeLayout
111 \row \o \inlineimage buttonbox-maclayout-horizontal.png MacLayout Horizontal
112 \o Button box laid out in horizontal MacLayout
113 \row \o \inlineimage buttonbox-winlayout-horizontal.png WinLayout Horizontal
114 \o Button box laid out in horizontal WinLayout
115 \endtable
116
117 The buttons are laid out the following way if the button box is vertical:
118
119 \table
120 \row \o GnomeLayout
121 \o KdeLayout
122 \o MacLayout
123 \o WinLayout
124 \row \o \inlineimage buttonbox-gnomelayout-vertical.png GnomeLayout Vertical
125 \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical
126 \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical
127 \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical
128 \endtable
129
130 Additionally, button boxes that contain only buttons with ActionRole or
131 HelpRole can be considered modeless and have an alternate look on Mac OS X:
132
133 \table
134 \row \o modeless horizontal MacLayout
135 \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout
136 \endtable
137
138 When a button is clicked in the button box, the clicked() signal is emitted
139 for the actual button is that is pressed. For convenience, if the button
140 has an AcceptRole, RejectRole, or HelpRole, the accepted(), rejected(), or
141 helpRequested() signals are emitted respectively.
142
143 If you want a specific button to be default you need to call
144 QPushButton::setDefault() on it yourself. However, if there is no default
145 button set and to preserve which button is the default button across
146 platforms when using the QPushButton::autoDefault property, the first push
147 button with the accept role is made the default button when the
148 QDialogButtonBox is shown,
149
150 \sa QMessageBox, QPushButton, QDialog
151*/
152
153enum {
154 AcceptRole = QDialogButtonBox::AcceptRole,
155 RejectRole = QDialogButtonBox::RejectRole,
156 DestructiveRole = QDialogButtonBox::DestructiveRole,
157 ActionRole = QDialogButtonBox::ActionRole,
158 HelpRole = QDialogButtonBox::HelpRole,
159 YesRole = QDialogButtonBox::YesRole,
160 NoRole = QDialogButtonBox::NoRole,
161 ApplyRole = QDialogButtonBox::ApplyRole,
162 ResetRole = QDialogButtonBox::ResetRole,
163
164 AlternateRole = 0x10000000,
165 Stretch = 0x20000000,
166 EOL = 0x40000000,
167 Reverse = 0x80000000
168};
169
170static QDialogButtonBox::ButtonRole roleFor(QDialogButtonBox::StandardButton button)
171{
172 switch (button) {
173 case QDialogButtonBox::Ok:
174 case QDialogButtonBox::Save:
175 case QDialogButtonBox::Open:
176 case QDialogButtonBox::SaveAll:
177 case QDialogButtonBox::Retry:
178 case QDialogButtonBox::Ignore:
179 return QDialogButtonBox::AcceptRole;
180
181 case QDialogButtonBox::Cancel:
182 case QDialogButtonBox::Close:
183 case QDialogButtonBox::Abort:
184 return QDialogButtonBox::RejectRole;
185
186 case QDialogButtonBox::Discard:
187 return QDialogButtonBox::DestructiveRole;
188
189 case QDialogButtonBox::Help:
190 return QDialogButtonBox::HelpRole;
191
192 case QDialogButtonBox::Apply:
193 return QDialogButtonBox::ApplyRole;
194
195 case QDialogButtonBox::Yes:
196 case QDialogButtonBox::YesToAll:
197 return QDialogButtonBox::YesRole;
198
199 case QDialogButtonBox::No:
200 case QDialogButtonBox::NoToAll:
201 return QDialogButtonBox::NoRole;
202
203 case QDialogButtonBox::RestoreDefaults:
204 case QDialogButtonBox::Reset:
205 return QDialogButtonBox::ResetRole;
206
207 case QDialogButtonBox::NoButton: // NoButton means zero buttons, not "No" button
208 ;
209 }
210
211 return QDialogButtonBox::InvalidRole;
212}
213
214static const int layouts[2][5][14] =
215{
216 // Qt::Horizontal
217 {
218 // WinLayout
219 { ResetRole, Stretch, YesRole, AcceptRole, AlternateRole, DestructiveRole, NoRole, ActionRole, RejectRole, ApplyRole,
220 HelpRole, EOL, EOL, EOL },
221
222 // MacLayout
223 { HelpRole, ResetRole, ApplyRole, ActionRole, Stretch, DestructiveRole | Reverse,
224 AlternateRole | Reverse, RejectRole | Reverse, AcceptRole | Reverse, NoRole | Reverse, YesRole | Reverse, EOL, EOL },
225
226 // KdeLayout
227 { HelpRole, ResetRole, Stretch, YesRole, NoRole, ActionRole, AcceptRole, AlternateRole,
228 ApplyRole, DestructiveRole, RejectRole, EOL },
229
230 // GnomeLayout
231 { HelpRole, ResetRole, Stretch, ActionRole, ApplyRole | Reverse, DestructiveRole | Reverse,
232 AlternateRole | Reverse, RejectRole | Reverse, AcceptRole | Reverse, NoRole | Reverse, YesRole | Reverse, EOL },
233
234 // Mac modeless
235 { ResetRole, ApplyRole, ActionRole, Stretch, HelpRole, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL }
236 },
237
238 // Qt::Vertical
239 {
240 // WinLayout
241 { ActionRole, YesRole, AcceptRole, AlternateRole, DestructiveRole, NoRole, RejectRole, ApplyRole, ResetRole,
242 HelpRole, Stretch, EOL, EOL, EOL },
243
244 // MacLayout
245 { YesRole, NoRole, AcceptRole, RejectRole, AlternateRole, DestructiveRole, Stretch, ActionRole, ApplyRole,
246 ResetRole, HelpRole, EOL, EOL },
247
248 // KdeLayout
249 { AcceptRole, AlternateRole, ApplyRole, ActionRole, YesRole, NoRole, Stretch, ResetRole,
250 DestructiveRole, RejectRole, HelpRole, EOL },
251
252 // GnomeLayout
253 { YesRole, NoRole, AcceptRole, RejectRole, AlternateRole, DestructiveRole, ApplyRole, ActionRole, Stretch,
254 ResetRole, HelpRole, EOL, EOL, EOL },
255
256 // Mac modeless
257 { ActionRole, ApplyRole, ResetRole, Stretch, HelpRole, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL, EOL }
258 }
259};
260
261#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
262class QDialogButtonEnabledProxy : public QObject
263{
264public:
265 QDialogButtonEnabledProxy(QObject *parent, QWidget *src, QAction *trg) : QObject(parent), source(src), target(trg)
266 {
267 source->installEventFilter(this);
268 target->setEnabled(source->isEnabled());
269 }
270 ~QDialogButtonEnabledProxy()
271 {
272 source->removeEventFilter(this);
273 }
274 bool eventFilter(QObject *object, QEvent *event)
275 {
276 if (object == source && event->type() == QEvent::EnabledChange) {
277 target->setEnabled(source->isEnabled());
278 }
279 return false;
280 };
281private:
282 QWidget *source;
283 QAction *target;
284};
285#endif
286
287class QDialogButtonBoxPrivate : public QWidgetPrivate
288{
289 Q_DECLARE_PUBLIC(QDialogButtonBox)
290
291public:
292 QDialogButtonBoxPrivate(Qt::Orientation orient);
293
294 QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
295 QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
296#ifdef QT_SOFTKEYS_ENABLED
297 QHash<QAbstractButton *, QAction *> softKeyActions;
298#endif
299
300 Qt::Orientation orientation;
301 QDialogButtonBox::ButtonLayout layoutPolicy;
302 QBoxLayout *buttonLayout;
303 bool internalRemove;
304 bool center;
305
306 void createStandardButtons(QDialogButtonBox::StandardButtons buttons);
307
308 void layoutButtons();
309 void initLayout();
310 void resetLayout();
311 QPushButton *createButton(QDialogButtonBox::StandardButton button, bool doLayout = true);
312 void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, bool doLayout = true);
313 void _q_handleButtonDestroyed();
314 void _q_handleButtonClicked();
315 void addButtonsToLayout(const QList<QAbstractButton *> &buttonList, bool reverse);
316 void retranslateStrings();
317 const char *standardButtonText(QDialogButtonBox::StandardButton sbutton) const;
318#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
319 QAction *createSoftKey(QAbstractButton *button, QDialogButtonBox::ButtonRole role);
320#endif
321};
322
323QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
324 : orientation(orient), buttonLayout(0), internalRemove(false), center(false)
325{
326}
327
328void QDialogButtonBoxPrivate::initLayout()
329{
330 Q_Q(QDialogButtonBox);
331 layoutPolicy = QDialogButtonBox::ButtonLayout(q->style()->styleHint(QStyle::SH_DialogButtonLayout, 0, q));
332 bool createNewLayout = buttonLayout == 0
333 || (orientation == Qt::Horizontal && qobject_cast<QVBoxLayout *>(buttonLayout) != 0)
334 || (orientation == Qt::Vertical && qobject_cast<QHBoxLayout *>(buttonLayout) != 0);
335 if (createNewLayout) {
336 delete buttonLayout;
337 if (orientation == Qt::Horizontal)
338 buttonLayout = new QHBoxLayout(q);
339 else
340 buttonLayout = new QVBoxLayout(q);
341 }
342
343 int left, top, right, bottom;
344 setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem);
345 getLayoutItemMargins(&left, &top, &right, &bottom);
346 buttonLayout->setContentsMargins(-left, -top, -right, -bottom);
347
348 if (!q->testAttribute(Qt::WA_WState_OwnSizePolicy)) {
349 QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::ButtonBox);
350 if (orientation == Qt::Vertical)
351 sp.transpose();
352 q->setSizePolicy(sp);
353 q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
354 }
355
356 // ### move to a real init() function
357 q->setFocusPolicy(Qt::TabFocus);
358}
359
360void QDialogButtonBoxPrivate::resetLayout()
361{
362 //delete buttonLayout;
363 initLayout();
364 layoutButtons();
365}
366
367void QDialogButtonBoxPrivate::addButtonsToLayout(const QList<QAbstractButton *> &buttonList,
368 bool reverse)
369{
370 int start = reverse ? buttonList.count() - 1 : 0;
371 int end = reverse ? -1 : buttonList.count();
372 int step = reverse ? -1 : 1;
373
374 for (int i = start; i != end; i += step) {
375 QAbstractButton *button = buttonList.at(i);
376 buttonLayout->addWidget(button);
377 button->show();
378 }
379}
380
381void QDialogButtonBoxPrivate::layoutButtons()
382{
383 Q_Q(QDialogButtonBox);
384 const int MacGap = 36 - 8; // 8 is the default gap between a widget and a spacer item
385
386 for (int i = buttonLayout->count() - 1; i >= 0; --i) {
387 QLayoutItem *item = buttonLayout->takeAt(i);
388 if (QWidget *widget = item->widget())
389 widget->hide();
390 delete item;
391 }
392
393 int tmpPolicy = layoutPolicy;
394
395 static const int M = 5;
396 static const int ModalRoles[M] = { AcceptRole, RejectRole, DestructiveRole, YesRole, NoRole };
397 if (tmpPolicy == QDialogButtonBox::MacLayout) {
398 bool hasModalButton = false;
399 for (int i = 0; i < M; ++i) {
400 if (!buttonLists[ModalRoles[i]].isEmpty()) {
401 hasModalButton = true;
402 break;
403 }
404 }
405 if (!hasModalButton)
406 tmpPolicy = 4; // Mac modeless
407 }
408
409 const int *currentLayout = layouts[orientation == Qt::Vertical][tmpPolicy];
410
411 if (center)
412 buttonLayout->addStretch();
413
414 QList<QAbstractButton *> acceptRoleList = buttonLists[AcceptRole];
415
416 while (*currentLayout != EOL) {
417 int role = (*currentLayout & ~Reverse);
418 bool reverse = (*currentLayout & Reverse);
419
420 switch (role) {
421 case Stretch:
422 if (!center)
423 buttonLayout->addStretch();
424 break;
425 case AcceptRole: {
426 if (acceptRoleList.isEmpty())
427 break;
428 // Only the first one
429 QAbstractButton *button = acceptRoleList.first();
430 buttonLayout->addWidget(button);
431 button->show();
432 }
433 break;
434 case AlternateRole:
435 {
436 if (acceptRoleList.size() < 2)
437 break;
438 QList<QAbstractButton *> list = acceptRoleList;
439 list.removeFirst();
440 addButtonsToLayout(list, reverse);
441 }
442 break;
443 case DestructiveRole:
444 {
445 const QList<QAbstractButton *> &list = buttonLists[role];
446
447 /*
448 Mac: Insert a gap on the left of the destructive
449 buttons to ensure that they don't get too close to
450 the help and action buttons (but only if there are
451 some buttons to the left of the destructive buttons
452 (and the stretch, whence buttonLayout->count() > 1
453 and not 0)).
454 */
455 if (tmpPolicy == QDialogButtonBox::MacLayout
456 && !list.isEmpty() && buttonLayout->count() > 1)
457 buttonLayout->addSpacing(MacGap);
458
459 addButtonsToLayout(list, reverse);
460
461 /*
462 Insert a gap between the destructive buttons and the
463 accept and reject buttons.
464 */
465 if (tmpPolicy == QDialogButtonBox::MacLayout && !list.isEmpty())
466 buttonLayout->addSpacing(MacGap);
467 }
468 break;
469 case RejectRole:
470 case ActionRole:
471 case HelpRole:
472 case YesRole:
473 case NoRole:
474 case ApplyRole:
475 case ResetRole:
476 addButtonsToLayout(buttonLists[role], reverse);
477 }
478 ++currentLayout;
479 }
480
481 QWidget *lastWidget = 0;
482 q->setFocusProxy(0);
483 for (int i = 0; i < buttonLayout->count(); ++i) {
484 QLayoutItem *item = buttonLayout->itemAt(i);
485 if (QWidget *widget = item->widget()) {
486 if (lastWidget)
487 QWidget::setTabOrder(lastWidget, widget);
488 else
489 q->setFocusProxy(widget);
490 lastWidget = widget;
491 }
492 }
493
494 if (center)
495 buttonLayout->addStretch();
496}
497
498QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardButton sbutton,
499 bool doLayout)
500{
501 Q_Q(QDialogButtonBox);
502 const char *buttonText = 0;
503 int icon = 0;
504
505 switch (sbutton) {
506 case QDialogButtonBox::Ok:
507 icon = QStyle::SP_DialogOkButton;
508 break;
509 case QDialogButtonBox::Save:
510 icon = QStyle::SP_DialogSaveButton;
511 break;
512 case QDialogButtonBox::Open:
513 icon = QStyle::SP_DialogOpenButton;
514 break;
515 case QDialogButtonBox::Cancel:
516 icon = QStyle::SP_DialogCancelButton;
517 break;
518 case QDialogButtonBox::Close:
519 icon = QStyle::SP_DialogCloseButton;
520 break;
521 case QDialogButtonBox::Apply:
522 icon = QStyle::SP_DialogApplyButton;
523 break;
524 case QDialogButtonBox::Reset:
525 icon = QStyle::SP_DialogResetButton;
526 break;
527 case QDialogButtonBox::Help:
528 icon = QStyle::SP_DialogHelpButton;
529 break;
530 case QDialogButtonBox::Discard:
531 icon = QStyle::SP_DialogDiscardButton;
532 break;
533 case QDialogButtonBox::Yes:
534 icon = QStyle::SP_DialogYesButton;
535 break;
536 case QDialogButtonBox::No:
537 icon = QStyle::SP_DialogNoButton;
538 break;
539 case QDialogButtonBox::YesToAll:
540 case QDialogButtonBox::NoToAll:
541 case QDialogButtonBox::SaveAll:
542 case QDialogButtonBox::Abort:
543 case QDialogButtonBox::Retry:
544 case QDialogButtonBox::Ignore:
545 case QDialogButtonBox::RestoreDefaults:
546 break;
547 case QDialogButtonBox::NoButton:
548 return 0;
549 ;
550 }
551 buttonText = standardButtonText(sbutton);
552
553 QPushButton *button = new QPushButton(QDialogButtonBox::tr(buttonText), q);
554 QStyle *style = q->style();
555 if (style->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons, 0, q) && icon != 0)
556 button->setIcon(style->standardIcon(QStyle::StandardPixmap(icon), 0, q));
557 if (style != QApplication::style()) // Propagate style
558 button->setStyle(style);
559 standardButtonHash.insert(button, sbutton);
560 if (roleFor(sbutton) != QDialogButtonBox::InvalidRole) {
561 addButton(button, roleFor(sbutton), doLayout);
562 } else {
563 qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
564 }
565 return button;
566}
567
568void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
569 bool doLayout)
570{
571 Q_Q(QDialogButtonBox);
572 QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_handleButtonClicked()));
573 QObject::connect(button, SIGNAL(destroyed()), q, SLOT(_q_handleButtonDestroyed()));
574 buttonLists[role].append(button);
575#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
576 QAction *action = createSoftKey(button, role);
577 softKeyActions.insert(button, action);
578 new QDialogButtonEnabledProxy(action, button, action);
579#endif
580 if (doLayout)
581 layoutButtons();
582}
583
584#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
585QAction* QDialogButtonBoxPrivate::createSoftKey(QAbstractButton *button, QDialogButtonBox::ButtonRole role)
586{
587 Q_Q(QDialogButtonBox);
588 QAction::SoftKeyRole softkeyRole;
589
590 QAction *action = new QAction(button->text(), button);
591
592 switch (role) {
593 case ApplyRole:
594 case AcceptRole:
595 case YesRole:
596 case ActionRole:
597 case HelpRole:
598 softkeyRole = QAction::PositiveSoftKey;
599 break;
600 case RejectRole:
601 case DestructiveRole:
602 case NoRole:
603 case ResetRole:
604 softkeyRole = QAction::NegativeSoftKey;
605 break;
606 default:
607 break;
608 }
609 QObject::connect(action, SIGNAL(triggered()), button, SIGNAL(clicked()));
610 action->setSoftKeyRole(softkeyRole);
611
612
613 QWidget *dialog = 0;
614 QWidget *p = q;
615 while (p && !p->isWindow()) {
616 p = p->parentWidget();
617 if ((dialog = qobject_cast<QDialog *>(p)))
618 break;
619 }
620
621 if (dialog) {
622 dialog->addAction(action);
623 } else {
624 q->addAction(action);
625 }
626
627 return action;
628}
629#endif
630
631void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardButtons buttons)
632{
633 uint i = QDialogButtonBox::FirstButton;
634 while (i <= QDialogButtonBox::LastButton) {
635 if (i & buttons) {
636 createButton(QDialogButtonBox::StandardButton(i), false);
637 }
638 i = i << 1;
639 }
640 layoutButtons();
641}
642
643const char *QDialogButtonBoxPrivate::standardButtonText(QDialogButtonBox::StandardButton sbutton) const
644{
645 const char *buttonText = 0;
646 bool gnomeLayout = (layoutPolicy == QDialogButtonBox::GnomeLayout);
647 switch (sbutton) {
648 case QDialogButtonBox::Ok:
649 buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&OK") : QT_TRANSLATE_NOOP("QDialogButtonBox", "OK");
650 break;
651 case QDialogButtonBox::Save:
652 buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Save") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Save");
653 break;
654 case QDialogButtonBox::Open:
655 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Open");
656 break;
657 case QDialogButtonBox::Cancel:
658 buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Cancel") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Cancel");
659 break;
660 case QDialogButtonBox::Close:
661 buttonText = gnomeLayout ? QT_TRANSLATE_NOOP("QDialogButtonBox", "&Close") : QT_TRANSLATE_NOOP("QDialogButtonBox", "Close");
662 break;
663 case QDialogButtonBox::Apply:
664 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Apply");
665 break;
666 case QDialogButtonBox::Reset:
667 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Reset");
668 break;
669 case QDialogButtonBox::Help:
670 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Help");
671 break;
672 case QDialogButtonBox::Discard:
673 if (layoutPolicy == QDialogButtonBox::MacLayout)
674 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Don't Save");
675 else if (layoutPolicy == QDialogButtonBox::GnomeLayout)
676 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Close without Saving");
677 else
678 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Discard");
679 break;
680 case QDialogButtonBox::Yes:
681 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "&Yes");
682 break;
683 case QDialogButtonBox::YesToAll:
684 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Yes to &All");
685 break;
686 case QDialogButtonBox::No:
687 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "&No");
688 break;
689 case QDialogButtonBox::NoToAll:
690 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "N&o to All");
691 break;
692 case QDialogButtonBox::SaveAll:
693 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Save All");
694 break;
695 case QDialogButtonBox::Abort:
696 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Abort");
697 break;
698 case QDialogButtonBox::Retry:
699 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Retry");
700 break;
701 case QDialogButtonBox::Ignore:
702 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Ignore");
703 break;
704 case QDialogButtonBox::RestoreDefaults:
705 buttonText = QT_TRANSLATE_NOOP("QDialogButtonBox", "Restore Defaults");
706 break;
707 case QDialogButtonBox::NoButton:
708 ;
709 } // switch
710 return buttonText;
711}
712
713void QDialogButtonBoxPrivate::retranslateStrings()
714{
715 const char *buttonText = 0;
716 QHash<QPushButton *, QDialogButtonBox::StandardButton>::iterator it = standardButtonHash.begin();
717 while (it != standardButtonHash.end()) {
718 buttonText = standardButtonText(it.value());
719 if (buttonText) {
720 QPushButton *button = it.key();
721 button->setText(QDialogButtonBox::tr(buttonText));
722#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
723 QAction *action = softKeyActions.value(button, 0);
724 if (action)
725 action->setText(button->text());
726#endif
727 }
728 ++it;
729 }
730}
731
732/*!
733 Constructs an empty, horizontal button box with the given \a parent.
734
735 \sa orientation, addButton()
736*/
737QDialogButtonBox::QDialogButtonBox(QWidget *parent)
738 : QWidget(*new QDialogButtonBoxPrivate(Qt::Horizontal), parent, 0)
739{
740 d_func()->initLayout();
741}
742
743/*!
744 Constructs an empty button box with the given \a orientation and \a parent.
745
746 \sa orientation, addButton()
747*/
748QDialogButtonBox::QDialogButtonBox(Qt::Orientation orientation, QWidget *parent)
749 : QWidget(*new QDialogButtonBoxPrivate(orientation), parent, 0)
750{
751 d_func()->initLayout();
752}
753
754/*!
755 Constructs a button box with the given \a orientation and \a parent, containing
756 the standard buttons specified by \a buttons.
757
758 \sa orientation, addButton()
759*/
760QDialogButtonBox::QDialogButtonBox(StandardButtons buttons, Qt::Orientation orientation,
761 QWidget *parent)
762 : QWidget(*new QDialogButtonBoxPrivate(orientation), parent, 0)
763{
764 d_func()->initLayout();
765 d_func()->createStandardButtons(buttons);
766}
767
768/*!
769 Destroys the button box.
770*/
771QDialogButtonBox::~QDialogButtonBox()
772{
773}
774
775/*!
776 \enum QDialogButtonBox::ButtonRole
777 \enum QMessageBox::ButtonRole
778
779 This enum describes the roles that can be used to describe buttons in
780 the button box. Combinations of these roles are as flags used to
781 describe different aspects of their behavior.
782
783 \value InvalidRole The button is invalid.
784 \value AcceptRole Clicking the button causes the dialog to be accepted
785 (e.g. OK).
786 \value RejectRole Clicking the button causes the dialog to be rejected
787 (e.g. Cancel).
788 \value DestructiveRole Clicking the button causes a destructive change
789 (e.g. for Discarding Changes) and closes the dialog.
790 \value ActionRole Clicking the button causes changes to the elements within
791 the dialog.
792 \value HelpRole The button can be clicked to request help.
793 \value YesRole The button is a "Yes"-like button.
794 \value NoRole The button is a "No"-like button.
795 \value ApplyRole The button applies current changes.
796 \value ResetRole The button resets the dialog's fields to default values.
797
798 \omitvalue NRoles
799
800 \sa StandardButton
801*/
802
803/*!
804 \enum QDialogButtonBox::StandardButton
805
806 These enums describe flags for standard buttons. Each button has a
807 defined \l ButtonRole.
808
809 \value Ok An "OK" button defined with the \l AcceptRole.
810 \value Open A "Open" button defined with the \l AcceptRole.
811 \value Save A "Save" button defined with the \l AcceptRole.
812 \value Cancel A "Cancel" button defined with the \l RejectRole.
813 \value Close A "Close" button defined with the \l RejectRole.
814 \value Discard A "Discard" or "Don't Save" button, depending on the platform,
815 defined with the \l DestructiveRole.
816 \value Apply An "Apply" button defined with the \l ApplyRole.
817 \value Reset A "Reset" button defined with the \l ResetRole.
818 \value RestoreDefaults A "Restore Defaults" button defined with the \l ResetRole.
819 \value Help A "Help" button defined with the \l HelpRole.
820 \value SaveAll A "Save All" button defined with the \l AcceptRole.
821 \value Yes A "Yes" button defined with the \l YesRole.
822 \value YesToAll A "Yes to All" button defined with the \l YesRole.
823 \value No A "No" button defined with the \l NoRole.
824 \value NoToAll A "No to All" button defined with the \l NoRole.
825 \value Abort An "Abort" button defined with the \l RejectRole.
826 \value Retry A "Retry" button defined with the \l AcceptRole.
827 \value Ignore An "Ignore" button defined with the \l AcceptRole.
828
829 \value NoButton An invalid button.
830
831 \omitvalue FirstButton
832 \omitvalue LastButton
833
834 \sa ButtonRole, standardButtons
835*/
836
837/*!
838 \enum QDialogButtonBox::ButtonLayout
839
840 This enum describes the layout policy to be used when arranging the buttons
841 contained in the button box.
842
843 \value WinLayout Use a policy appropriate for applications on Windows.
844 \value MacLayout Use a policy appropriate for applications on Mac OS X.
845 \value KdeLayout Use a policy appropriate for applications on KDE.
846 \value GnomeLayout Use a policy appropriate for applications on GNOME.
847
848 The button layout is specified by the \l{style()}{current style}. However,
849 on the X11 platform, it may be influenced by the desktop environment.
850*/
851
852/*!
853 \fn void QDialogButtonBox::clicked(QAbstractButton *button)
854
855 This signal is emitted when a button inside the button box is clicked. The
856 specific button that was pressed is specified by \a button.
857
858 \sa accepted(), rejected(), helpRequested()
859*/
860
861/*!
862 \fn void QDialogButtonBox::accepted()
863
864 This signal is emitted when a button inside the button box is clicked, as long
865 as it was defined with the \l AcceptRole or \l YesRole.
866
867 \sa rejected(), clicked() helpRequested()
868*/
869
870/*!
871 \fn void QDialogButtonBox::rejected()
872
873 This signal is emitted when a button inside the button box is clicked, as long
874 as it was defined with the \l RejectRole or \l NoRole.
875
876 \sa accepted() helpRequested() clicked()
877*/
878
879/*!
880 \fn void QDialogButtonBox::helpRequested()
881
882 This signal is emitted when a button inside the button box is clicked, as long
883 as it was defined with the \l HelpRole.
884
885 \sa accepted() rejected() clicked()
886*/
887
888/*!
889 \property QDialogButtonBox::orientation
890 \brief the orientation of the button box
891
892 By default, the orientation is horizontal (i.e. the buttons are laid out
893 side by side). The possible orientations are Qt::Horizontal and
894 Qt::Vertical.
895*/
896Qt::Orientation QDialogButtonBox::orientation() const
897{
898 return d_func()->orientation;
899}
900
901void QDialogButtonBox::setOrientation(Qt::Orientation orientation)
902{
903 Q_D(QDialogButtonBox);
904 if (orientation == d->orientation)
905 return;
906
907 d->orientation = orientation;
908 d->resetLayout();
909}
910
911/*!
912 Clears the button box, deleting all buttons within it.
913
914 \sa removeButton(), addButton()
915*/
916void QDialogButtonBox::clear()
917{
918 Q_D(QDialogButtonBox);
919#ifdef QT_SOFTKEYS_ENABLED
920 // Delete softkey actions as they have the buttons as parents
921 qDeleteAll(d->softKeyActions.values());
922 d->softKeyActions.clear();
923#endif
924 // Remove the created standard buttons, they should be in the other lists, which will
925 // do the deletion
926 d->standardButtonHash.clear();
927 for (int i = 0; i < NRoles; ++i) {
928 QList<QAbstractButton *> &list = d->buttonLists[i];
929 while (list.count()) {
930 QAbstractButton *button = list.takeAt(0);
931 QObject::disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
932 delete button;
933 }
934 }
935}
936
937/*!
938 Returns a list of all the buttons that have been added to the button box.
939
940 \sa buttonRole(), addButton(), removeButton()
941*/
942QList<QAbstractButton *> QDialogButtonBox::buttons() const
943{
944 Q_D(const QDialogButtonBox);
945 QList<QAbstractButton *> finalList;
946 for (int i = 0; i < NRoles; ++i) {
947 const QList<QAbstractButton *> &list = d->buttonLists[i];
948 for (int j = 0; j < list.count(); ++j)
949 finalList.append(list.at(j));
950 }
951 return finalList;
952}
953
954/*!
955 Returns the button role for the specified \a button. This function returns
956 \l InvalidRole if \a button is 0 or has not been added to the button box.
957
958 \sa buttons(), addButton()
959*/
960QDialogButtonBox::ButtonRole QDialogButtonBox::buttonRole(QAbstractButton *button) const
961{
962 Q_D(const QDialogButtonBox);
963 for (int i = 0; i < NRoles; ++i) {
964 const QList<QAbstractButton *> &list = d->buttonLists[i];
965 for (int j = 0; j < list.count(); ++j) {
966 if (list.at(j) == button)
967 return ButtonRole(i);
968 }
969 }
970 return InvalidRole;
971}
972
973/*!
974 Removes \a button from the button box without deleting it and sets its parent to zero.
975
976 \sa clear(), buttons(), addButton()
977*/
978void QDialogButtonBox::removeButton(QAbstractButton *button)
979{
980 Q_D(QDialogButtonBox);
981
982 if (!button)
983 return;
984
985 // Remove it from the standard button hash first and then from the roles
986 if (QPushButton *pushButton = qobject_cast<QPushButton *>(button))
987 d->standardButtonHash.remove(pushButton);
988 for (int i = 0; i < NRoles; ++i) {
989 QList<QAbstractButton *> &list = d->buttonLists[i];
990 for (int j = 0; j < list.count(); ++j) {
991 if (list.at(j) == button) {
992 list.takeAt(j);
993 if (!d->internalRemove) {
994 disconnect(button, SIGNAL(clicked()), this, SLOT(_q_handleButtonClicked()));
995 disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
996 }
997 break;
998 }
999 }
1000 }
1001#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
1002 QAction *action = d->softKeyActions.value(button, 0);
1003 if (action) {
1004 d->softKeyActions.remove(button);
1005 delete action;
1006 }
1007#endif
1008 if (!d->internalRemove)
1009 button->setParent(0);
1010}
1011
1012/*!
1013 Adds the given \a button to the button box with the specified \a role.
1014 If the role is invalid, the button is not added.
1015
1016 If the button has already been added, it is removed and added again with the
1017 new role.
1018
1019 \note The button box takes ownership of the button.
1020
1021 \sa removeButton(), clear()
1022*/
1023void QDialogButtonBox::addButton(QAbstractButton *button, ButtonRole role)
1024{
1025 Q_D(QDialogButtonBox);
1026 if (role <= InvalidRole || role >= NRoles) {
1027 qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added");
1028 return;
1029 }
1030 removeButton(button);
1031 button->setParent(this);
1032 d->addButton(button, role);
1033}
1034
1035/*!
1036 Creates a push button with the given \a text, adds it to the button box for the
1037 specified \a role, and returns the corresponding push button. If \a role is
1038 invalid, no button is created, and zero is returned.
1039
1040 \sa removeButton(), clear()
1041*/
1042QPushButton *QDialogButtonBox::addButton(const QString &text, ButtonRole role)
1043{
1044 Q_D(QDialogButtonBox);
1045 if (role <= InvalidRole || role >= NRoles) {
1046 qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added");
1047 return 0;
1048 }
1049 QPushButton *button = new QPushButton(text, this);
1050 d->addButton(button, role);
1051 return button;
1052}
1053
1054/*!
1055 Adds a standard \a button to the button box if it is valid to do so, and returns
1056 a push button. If \a button is invalid, it is not added to the button box, and
1057 zero is returned.
1058
1059 \sa removeButton(), clear()
1060*/
1061QPushButton *QDialogButtonBox::addButton(StandardButton button)
1062{
1063 Q_D(QDialogButtonBox);
1064 return d->createButton(button);
1065}
1066
1067/*!
1068 \property QDialogButtonBox::standardButtons
1069 \brief collection of standard buttons in the button box
1070
1071 This property controls which standard buttons are used by the button box.
1072
1073 \sa addButton()
1074*/
1075void QDialogButtonBox::setStandardButtons(StandardButtons buttons)
1076{
1077 Q_D(QDialogButtonBox);
1078#ifdef QT_SOFTKEYS_ENABLED
1079 // Delete softkey actions since they have the buttons as parents
1080 qDeleteAll(d->softKeyActions.values());
1081 d->softKeyActions.clear();
1082#endif
1083 // Clear out all the old standard buttons, then recreate them.
1084 qDeleteAll(d->standardButtonHash.keys());
1085 d->standardButtonHash.clear();
1086
1087 d->createStandardButtons(buttons);
1088}
1089
1090QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
1091{
1092 Q_D(const QDialogButtonBox);
1093 StandardButtons standardButtons = NoButton;
1094 QHash<QPushButton *, StandardButton>::const_iterator it = d->standardButtonHash.constBegin();
1095 while (it != d->standardButtonHash.constEnd()) {
1096 standardButtons |= it.value();
1097 ++it;
1098 }
1099 return standardButtons;
1100}
1101
1102/*!
1103 Returns the QPushButton corresponding to the standard button \a which,
1104 or 0 if the standard button doesn't exist in this button box.
1105
1106 \sa standardButton(), standardButtons(), buttons()
1107*/
1108QPushButton *QDialogButtonBox::button(StandardButton which) const
1109{
1110 Q_D(const QDialogButtonBox);
1111 return d->standardButtonHash.key(which);
1112}
1113
1114/*!
1115 Returns the standard button enum value corresponding to the given \a button,
1116 or NoButton if the given \a button isn't a standard button.
1117
1118 \sa button(), buttons(), standardButtons()
1119*/
1120QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButton *button) const
1121{
1122 Q_D(const QDialogButtonBox);
1123 return d->standardButtonHash.value(static_cast<QPushButton *>(button));
1124}
1125
1126void QDialogButtonBoxPrivate::_q_handleButtonClicked()
1127{
1128 Q_Q(QDialogButtonBox);
1129 if (QAbstractButton *button = qobject_cast<QAbstractButton *>(q->sender())) {
1130 emit q->clicked(button);
1131
1132 switch (q->buttonRole(button)) {
1133 case AcceptRole:
1134 case YesRole:
1135 emit q->accepted();
1136 break;
1137 case RejectRole:
1138 case NoRole:
1139 emit q->rejected();
1140 break;
1141 case HelpRole:
1142 emit q->helpRequested();
1143 break;
1144 default:
1145 break;
1146 }
1147 }
1148}
1149
1150void QDialogButtonBoxPrivate::_q_handleButtonDestroyed()
1151{
1152 Q_Q(QDialogButtonBox);
1153 if (QObject *object = q->sender()) {
1154 QBoolBlocker skippy(internalRemove);
1155 q->removeButton(static_cast<QAbstractButton *>(object));
1156 }
1157}
1158
1159/*!
1160 \property QDialogButtonBox::centerButtons
1161 \brief whether the buttons in the button box are centered
1162
1163 By default, this property is false. This behavior is appopriate
1164 for most types of dialogs. A notable exception is message boxes
1165 on most platforms (e.g. Windows), where the button box is
1166 centered horizontally.
1167
1168 \sa QMessageBox
1169*/
1170void QDialogButtonBox::setCenterButtons(bool center)
1171{
1172 Q_D(QDialogButtonBox);
1173 if (d->center != center) {
1174 d->center = center;
1175 d->resetLayout();
1176 }
1177}
1178
1179bool QDialogButtonBox::centerButtons() const
1180{
1181 Q_D(const QDialogButtonBox);
1182 return d->center;
1183}
1184
1185/*!
1186 \reimp
1187*/
1188void QDialogButtonBox::changeEvent(QEvent *event)
1189{
1190 typedef QHash<QPushButton *, QDialogButtonBox::StandardButton> StandardButtonHash;
1191
1192 Q_D(QDialogButtonBox);
1193 switch (event->type()) {
1194 case QEvent::StyleChange: // Propagate style
1195 if (!d->standardButtonHash.empty()) {
1196 QStyle *newStyle = style();
1197 const StandardButtonHash::iterator end = d->standardButtonHash.end();
1198 for (StandardButtonHash::iterator it = d->standardButtonHash.begin(); it != end; ++it)
1199 it.key()->setStyle(newStyle);
1200 }
1201 // fallthrough intended
1202#ifdef Q_WS_MAC
1203 case QEvent::MacSizeChange:
1204#endif
1205 d->resetLayout();
1206 QWidget::changeEvent(event);
1207 break;
1208 default:
1209 QWidget::changeEvent(event);
1210 break;
1211 }
1212}
1213
1214/*!
1215 \reimp
1216*/
1217bool QDialogButtonBox::event(QEvent *event)
1218{
1219 Q_D(QDialogButtonBox);
1220 if (event->type() == QEvent::Show) {
1221 QList<QAbstractButton *> acceptRoleList = d->buttonLists[AcceptRole];
1222 QPushButton *firstAcceptButton = acceptRoleList.isEmpty() ? 0 : qobject_cast<QPushButton *>(acceptRoleList.at(0));
1223 bool hasDefault = false;
1224 QWidget *dialog = 0;
1225 QWidget *p = this;
1226 while (p && !p->isWindow()) {
1227 p = p->parentWidget();
1228 if ((dialog = qobject_cast<QDialog *>(p)))
1229 break;
1230 }
1231
1232 foreach (QPushButton *pb, qFindChildren<QPushButton *>(dialog ? dialog : this)) {
1233 if (pb->isDefault() && pb != firstAcceptButton) {
1234 hasDefault = true;
1235 break;
1236 }
1237 }
1238 if (!hasDefault && firstAcceptButton)
1239 firstAcceptButton->setDefault(true);
1240#ifdef QT_SOFTKEYS_ENABLED
1241 if (dialog)
1242 setFixedSize(0,0);
1243#endif
1244 }else if (event->type() == QEvent::LanguageChange) {
1245 d->retranslateStrings();
1246 }
1247#if defined(QT_SOFTKEYS_ENABLED) && !defined(QT_NO_ACTION)
1248 else if (event->type() == QEvent::ParentChange) {
1249 QWidget *dialog = 0;
1250 QWidget *p = this;
1251 while (p && !p->isWindow()) {
1252 p = p->parentWidget();
1253 if ((dialog = qobject_cast<QDialog *>(p)))
1254 break;
1255 }
1256
1257 // If the parent changes, then move the softkeys
1258 for (QHash<QAbstractButton *, QAction *>::const_iterator it = d->softKeyActions.constBegin();
1259 it != d->softKeyActions.constEnd(); ++it) {
1260 QAction *current = it.value();
1261 QList<QWidget *> widgets = current->associatedWidgets();
1262 foreach (QWidget *w, widgets)
1263 w->removeAction(current);
1264 if (dialog)
1265 dialog->addAction(current);
1266 else
1267 addAction(current);
1268 }
1269 }
1270#endif
1271
1272 return QWidget::event(event);
1273}
1274
1275QT_END_NAMESPACE
1276
1277#include "moc_qdialogbuttonbox.cpp"
Note: See TracBrowser for help on using the repository browser.