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

Last change on this file since 642 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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