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

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

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

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