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

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

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

File size: 42.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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 \note The button box takes ownership of the button.
1021
1022 \sa removeButton(), clear()
1023*/
1024void QDialogButtonBox::addButton(QAbstractButton *button, ButtonRole role)
1025{
1026 Q_D(QDialogButtonBox);
1027 if (role <= InvalidRole || role >= NRoles) {
1028 qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added");
1029 return;
1030 }
1031 removeButton(button);
1032 button->setParent(this);
1033 d->addButton(button, role);
1034}
1035
1036/*!
1037 Creates a push button with the given \a text, adds it to the button box for the
1038 specified \a role, and returns the corresponding push button. If \a role is
1039 invalid, no button is created, and zero is returned.
1040
1041 \sa removeButton(), clear()
1042*/
1043QPushButton *QDialogButtonBox::addButton(const QString &text, ButtonRole role)
1044{
1045 Q_D(QDialogButtonBox);
1046 if (role <= InvalidRole || role >= NRoles) {
1047 qWarning("QDialogButtonBox::addButton: Invalid ButtonRole, button not added");
1048 return 0;
1049 }
1050 QPushButton *button = new QPushButton(text, this);
1051 d->addButton(button, role);
1052 return button;
1053}
1054
1055/*!
1056 Adds a standard \a button to the button box if it is valid to do so, and returns
1057 a push button. If \a button is invalid, it is not added to the button box, and
1058 zero is returned.
1059
1060 \sa removeButton(), clear()
1061*/
1062QPushButton *QDialogButtonBox::addButton(StandardButton button)
1063{
1064 Q_D(QDialogButtonBox);
1065 return d->createButton(button);
1066}
1067
1068/*!
1069 \property QDialogButtonBox::standardButtons
1070 \brief collection of standard buttons in the button box
1071
1072 This property controls which standard buttons are used by the button box.
1073
1074 \sa addButton()
1075*/
1076void QDialogButtonBox::setStandardButtons(StandardButtons buttons)
1077{
1078 Q_D(QDialogButtonBox);
1079#ifdef QT_SOFTKEYS_ENABLED
1080 // Delete softkey actions since they have the buttons as parents
1081 qDeleteAll(d->softKeyActions.values());
1082 d->softKeyActions.clear();
1083#endif
1084 // Clear out all the old standard buttons, then recreate them.
1085 qDeleteAll(d->standardButtonHash.keys());
1086 d->standardButtonHash.clear();
1087
1088 d->createStandardButtons(buttons);
1089}
1090
1091QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
1092{
1093 Q_D(const QDialogButtonBox);
1094 StandardButtons standardButtons = NoButton;
1095 QHash<QPushButton *, StandardButton>::const_iterator it = d->standardButtonHash.constBegin();
1096 while (it != d->standardButtonHash.constEnd()) {
1097 standardButtons |= it.value();
1098 ++it;
1099 }
1100 return standardButtons;
1101}
1102
1103/*!
1104 Returns the QPushButton corresponding to the standard button \a which,
1105 or 0 if the standard button doesn't exist in this button box.
1106
1107 \sa standardButton(), standardButtons(), buttons()
1108*/
1109QPushButton *QDialogButtonBox::button(StandardButton which) const
1110{
1111 Q_D(const QDialogButtonBox);
1112 return d->standardButtonHash.key(which);
1113}
1114
1115/*!
1116 Returns the standard button enum value corresponding to the given \a button,
1117 or NoButton if the given \a button isn't a standard button.
1118
1119 \sa button(), buttons(), standardButtons()
1120*/
1121QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButton *button) const
1122{
1123 Q_D(const QDialogButtonBox);
1124 return d->standardButtonHash.value(static_cast<QPushButton *>(button));
1125}
1126
1127void QDialogButtonBoxPrivate::_q_handleButtonClicked()
1128{
1129 Q_Q(QDialogButtonBox);
1130 if (QAbstractButton *button = qobject_cast<QAbstractButton *>(q->sender())) {
1131 emit q->clicked(button);
1132
1133 switch (q->buttonRole(button)) {
1134 case AcceptRole:
1135 case YesRole:
1136 emit q->accepted();
1137 break;
1138 case RejectRole:
1139 case NoRole:
1140 emit q->rejected();
1141 break;
1142 case HelpRole:
1143 emit q->helpRequested();
1144 break;
1145 default:
1146 break;
1147 }
1148 }
1149}
1150
1151void QDialogButtonBoxPrivate::_q_handleButtonDestroyed()
1152{
1153 Q_Q(QDialogButtonBox);
1154 if (QObject *object = q->sender()) {
1155 QBoolBlocker skippy(internalRemove);
1156 q->removeButton(static_cast<QAbstractButton *>(object));
1157 }
1158}
1159
1160/*!
1161 \property QDialogButtonBox::centerButtons
1162 \brief whether the buttons in the button box are centered
1163
1164 By default, this property is false. This behavior is appopriate
1165 for most types of dialogs. A notable exception is message boxes
1166 on most platforms (e.g. Windows), where the button box is
1167 centered horizontally.
1168
1169 \sa QMessageBox
1170*/
1171void QDialogButtonBox::setCenterButtons(bool center)
1172{
1173 Q_D(QDialogButtonBox);
1174 if (d->center != center) {
1175 d->center = center;
1176 d->resetLayout();
1177 }
1178}
1179
1180bool QDialogButtonBox::centerButtons() const
1181{
1182 Q_D(const QDialogButtonBox);
1183 return d->center;
1184}
1185
1186/*!
1187 \reimp
1188*/
1189void QDialogButtonBox::changeEvent(QEvent *event)
1190{
1191 typedef QHash<QPushButton *, QDialogButtonBox::StandardButton> StandardButtonHash;
1192
1193 Q_D(QDialogButtonBox);
1194 switch (event->type()) {
1195 case QEvent::StyleChange: // Propagate style
1196 if (!d->standardButtonHash.empty()) {
1197 QStyle *newStyle = style();
1198 const StandardButtonHash::iterator end = d->standardButtonHash.end();
1199 for (StandardButtonHash::iterator it = d->standardButtonHash.begin(); it != end; ++it)
1200 it.key()->setStyle(newStyle);
1201 }
1202 // fallthrough intended
1203#ifdef Q_WS_MAC
1204 case QEvent::MacSizeChange:
1205#endif
1206 d->resetLayout();
1207 QWidget::changeEvent(event);
1208 break;
1209 default:
1210 QWidget::changeEvent(event);
1211 break;
1212 }
1213}
1214
1215/*!
1216 \reimp
1217*/
1218bool QDialogButtonBox::event(QEvent *event)
1219{
1220 Q_D(QDialogButtonBox);
1221 if (event->type() == QEvent::Show) {
1222 QList<QAbstractButton *> acceptRoleList = d->buttonLists[AcceptRole];
1223 QPushButton *firstAcceptButton = acceptRoleList.isEmpty() ? 0 : qobject_cast<QPushButton *>(acceptRoleList.at(0));
1224 bool hasDefault = false;
1225 QWidget *dialog = 0;
1226 QWidget *p = this;
1227 while (p && !p->isWindow()) {
1228 p = p->parentWidget();
1229 if ((dialog = qobject_cast<QDialog *>(p)))
1230 break;
1231 }
1232
1233 foreach (QPushButton *pb, qFindChildren<QPushButton *>(dialog ? dialog : this)) {
1234 if (pb->isDefault() && pb != firstAcceptButton) {
1235 hasDefault = true;
1236 break;
1237 }
1238 }
1239 if (!hasDefault && firstAcceptButton)
1240 firstAcceptButton->setDefault(true);
1241#ifdef QT_SOFTKEYS_ENABLED
1242 if (dialog)
1243 setFixedSize(0,0);
1244#endif
1245 }else if (event->type() == QEvent::LanguageChange) {
1246 d->retranslateStrings();
1247 }
1248#ifdef QT_SOFTKEYS_ENABLED
1249 else if (event->type() == QEvent::ParentChange) {
1250 QWidget *dialog = 0;
1251 QWidget *p = this;
1252 while (p && !p->isWindow()) {
1253 p = p->parentWidget();
1254 if ((dialog = qobject_cast<QDialog *>(p)))
1255 break;
1256 }
1257
1258 // If the parent changes, then move the softkeys
1259 for (QHash<QAbstractButton *, QAction *>::const_iterator it = d->softKeyActions.constBegin();
1260 it != d->softKeyActions.constEnd(); ++it) {
1261 QAction *current = it.value();
1262 QList<QWidget *> widgets = current->associatedWidgets();
1263 foreach (QWidget *w, widgets)
1264 w->removeAction(current);
1265 if (dialog)
1266 dialog->addAction(current);
1267 else
1268 addAction(current);
1269 }
1270 }
1271#endif
1272
1273 return QWidget::event(event);
1274}
1275
1276QT_END_NAMESPACE
1277
1278#include "moc_qdialogbuttonbox.cpp"
Note: See TracBrowser for help on using the repository browser.