1 /* This file is part of the KDE Libraries
2 * Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net)
3 * Additions 1999-2000 by Espen Sand (espen@kde.org)
4 * by Holger Freyther <freyther@kde.org>
5 * 2005-2009 by Olivier Goffart (ogoffart at kde.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "KoDialog.h"
24 #include "KoDialog_p.h"
25
26 #include <QApplication>
27 #include <QDesktopWidget>
28 #include <QDialogButtonBox>
29 #include <QHBoxLayout>
30 #include <QHideEvent>
31 #include <QPointer>
32 #include <QStyle>
33 #include <QTimer>
34 #include <QVBoxLayout>
35 #include <QWhatsThis>
36 #include <QDebug>
37 #include <QPushButton>
38
39 #include <kconfig.h>
40 #include <klocalizedstring.h>
41
42 #include <kseparator.h>
43 #include <kstandardguiitem.h>
44 #include <khelpclient.h>
45 #include <kurllabel.h>
46 #include <kwindowconfig.h>
47
setupLayout()48 void KoDialogPrivate::setupLayout()
49 {
50 Q_Q(KoDialog);
51 if (!dirty) {
52 QMetaObject::invokeMethod(q, "queuedLayoutUpdate", Qt::QueuedConnection);
53 dirty = true;
54 }
55 }
56
queuedLayoutUpdate()57 void KoDialogPrivate::queuedLayoutUpdate()
58 {
59 if (!dirty) {
60 return;
61 }
62
63 dirty = false;
64
65 Q_Q(KoDialog);
66
67 // Don't lose the focus widget when re-creating the layout.
68 // Testcase: KOrganizer's "Select Categories" dialog
69 QPointer<QWidget> focusWidget = mMainWidget ? mMainWidget->focusWidget() : 0;
70
71 if (q->layout() && q->layout() != mTopLayout) {
72 qWarning() << q->metaObject()->className() << "created with a layout; don't do that, KoDialog takes care of it, use mainWidget or setMainWidget instead";
73 delete q->layout();
74 }
75
76 delete mTopLayout;
77
78 if (mButtonOrientation == Qt::Horizontal) {
79 mTopLayout = new QVBoxLayout(q);
80 } else {
81 mTopLayout = new QHBoxLayout(q);
82 }
83
84 if (mUrlHelp) {
85 mTopLayout->addWidget(mUrlHelp, 0, Qt::AlignRight);
86 }
87
88 if (mMainWidget) {
89 mTopLayout->addWidget(mMainWidget, 10);
90 }
91
92 if (mDetailsWidget) {
93 mTopLayout->addWidget(mDetailsWidget);
94 }
95
96 if (mActionSeparator) {
97 mTopLayout->addWidget(mActionSeparator);
98 }
99
100 if (mButtonBox) {
101 mButtonBox->setOrientation(mButtonOrientation);
102 mTopLayout->addWidget(mButtonBox);
103 }
104
105 if (focusWidget) {
106 focusWidget->setFocus();
107 }
108 }
109
appendButton(KoDialog::ButtonCode key,const KGuiItem & item)110 void KoDialogPrivate::appendButton(KoDialog::ButtonCode key, const KGuiItem &item)
111 {
112 Q_Q(KoDialog);
113
114 QDialogButtonBox::ButtonRole role = QDialogButtonBox::InvalidRole;
115 switch (key) {
116 case KoDialog::Help:
117 case KoDialog::Details:
118 role = QDialogButtonBox::HelpRole;
119 break;
120 case KoDialog::Default:
121 case KoDialog::Reset:
122 role = QDialogButtonBox::ResetRole;
123 break;
124 case KoDialog::Ok:
125 role = QDialogButtonBox::AcceptRole;
126 break;
127 case KoDialog::Apply:
128 role = QDialogButtonBox::ApplyRole;
129 break;
130 case KoDialog::Try:
131 case KoDialog::Yes:
132 role = QDialogButtonBox::YesRole;
133 break;
134 case KoDialog::Close:
135 case KoDialog::Cancel:
136 role = QDialogButtonBox::RejectRole;
137 break;
138 case KoDialog::No:
139 role = QDialogButtonBox::NoRole;
140 break;
141 case KoDialog::User1:
142 case KoDialog::User2:
143 case KoDialog::User3:
144 role = QDialogButtonBox::ActionRole;
145 break;
146 default:
147 role = QDialogButtonBox::InvalidRole;
148 break;
149 }
150
151 if (role == QDialogButtonBox::InvalidRole) {
152 return;
153 }
154
155 QPushButton *button = new QPushButton;
156 KGuiItem::assign(button, item);
157 mButtonBox->addButton(button, role);
158
159 mButtonList.insert(key, button);
160
161 QObject::connect(button, &QPushButton::clicked, [this, key] { q_ptr->slotButtonClicked(key); });
162
163 if (key == mDefaultButton) {
164 // Now that it exists, set it as default
165 q->setDefaultButton(mDefaultButton);
166 }
167 }
168
init(KoDialog * q)169 void KoDialogPrivate::init(KoDialog *q)
170 {
171 q_ptr = q;
172
173 dirty = false;
174
175 q->setButtons(KoDialog::Ok | KoDialog::Cancel);
176 q->setDefaultButton(KoDialog::Ok);
177
178 q->setPlainCaption(qApp->applicationDisplayName()); // set appropriate initial window title for case it gets not set later
179 }
180
helpLinkClicked()181 void KoDialogPrivate::helpLinkClicked()
182 {
183 q_ptr->slotButtonClicked(KoDialog::Help);
184 }
185
KoDialog(QWidget * parent,Qt::WindowFlags flags)186 KoDialog::KoDialog(QWidget *parent, Qt::WindowFlags flags)
187 : QDialog(parent, flags)
188 , d_ptr(new KoDialogPrivate)
189 {
190 d_ptr->init(this);
191 }
192
KoDialog(KoDialogPrivate & dd,QWidget * parent,Qt::WindowFlags flags)193 KoDialog::KoDialog(KoDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags)
194 : QDialog(parent, flags)
195 , d_ptr(&dd)
196 {
197 d_ptr->init(this);
198 }
199
~KoDialog()200 KoDialog::~KoDialog()
201 {
202 delete d_ptr;
203 }
204
setButtons(ButtonCodes buttonMask)205 void KoDialog::setButtons(ButtonCodes buttonMask)
206 {
207 Q_D(KoDialog);
208 if (d->mButtonBox) {
209 d->mButtonList.clear();
210
211 delete d->mButtonBox;
212 d->mButtonBox = 0;
213 }
214
215 if (buttonMask & Cancel) {
216 buttonMask &= ~Close;
217 }
218
219 if (buttonMask & Apply) {
220 buttonMask &= ~Try;
221 }
222
223 if (buttonMask & Details) {
224 buttonMask &= ~Default;
225 }
226
227 if (buttonMask == None) {
228 d->setupLayout();
229 return; // When we want no button box
230 }
231
232 d->mEscapeButton = (buttonMask & Cancel) ? Cancel : Close;
233 d->mButtonBox = new QDialogButtonBox(this);
234
235 if (buttonMask & Help) {
236 d->appendButton(Help, KStandardGuiItem::help());
237 }
238 if (buttonMask & Default) {
239 d->appendButton(Default, KStandardGuiItem::defaults());
240 }
241 if (buttonMask & Reset) {
242 d->appendButton(Reset, KStandardGuiItem::reset());
243 }
244 if (buttonMask & User3) {
245 d->appendButton(User3, KGuiItem());
246 }
247 if (buttonMask & User2) {
248 d->appendButton(User2, KGuiItem());
249 }
250 if (buttonMask & User1) {
251 d->appendButton(User1, KGuiItem());
252 }
253 if (buttonMask & Ok) {
254 d->appendButton(Ok, KStandardGuiItem::ok());
255 }
256 if (buttonMask & Apply) {
257 d->appendButton(Apply, KStandardGuiItem::apply());
258 }
259 if (buttonMask & Try) {
260 d->appendButton(Try, KGuiItem(i18n("&Try")));
261 }
262 if (buttonMask & Cancel) {
263 d->appendButton(Cancel, KStandardGuiItem::cancel());
264 }
265 if (buttonMask & Close) {
266 d->appendButton(Close, KStandardGuiItem::close());
267 }
268 if (buttonMask & Yes) {
269 d->appendButton(Yes, KStandardGuiItem::yes());
270 }
271 if (buttonMask & No) {
272 d->appendButton(No, KStandardGuiItem::no());
273 }
274 if (buttonMask & Details) {
275 d->appendButton(Details, KGuiItem(QString(), "help-about"));
276 setDetailsWidgetVisible(false);
277 }
278
279 d->setupLayout();
280 }
281
setButtonsOrientation(Qt::Orientation orientation)282 void KoDialog::setButtonsOrientation(Qt::Orientation orientation)
283 {
284 Q_D(KoDialog);
285 if (d->mButtonOrientation != orientation) {
286 d->mButtonOrientation = orientation;
287
288 if (d->mActionSeparator) {
289 d->mActionSeparator->setOrientation(d->mButtonOrientation);
290 }
291
292 if (d->mButtonOrientation == Qt::Vertical) {
293 enableLinkedHelp(false); // 2000-06-18 Espen: No support for this yet.
294 }
295 }
296 }
297
setEscapeButton(ButtonCode id)298 void KoDialog::setEscapeButton(ButtonCode id)
299 {
300 d_func()->mEscapeButton = id;
301 }
302
setDefaultButton(ButtonCode newDefaultButton)303 void KoDialog::setDefaultButton(ButtonCode newDefaultButton)
304 {
305 Q_D(KoDialog);
306
307 if (newDefaultButton == None) {
308 newDefaultButton = NoDefault; // #148969
309 }
310
311 const KoDialog::ButtonCode oldDefault = defaultButton();
312
313 bool oldDefaultHadFocus = false;
314
315 if (oldDefault != NoDefault) {
316 QPushButton *old = button(oldDefault);
317 if (old) {
318 oldDefaultHadFocus = (focusWidget() == old);
319 old->setDefault(false);
320 }
321 }
322
323 if (newDefaultButton != NoDefault) {
324 QPushButton *b = button(newDefaultButton);
325 if (b) {
326 b->setDefault(true);
327 if (focusWidget() == 0 || oldDefaultHadFocus) {
328 // No widget had focus yet, or the old default button had
329 // -> ok to give focus to the new default button, so that it's
330 // really default (Enter triggers it).
331 // But we don't do this if the kdialog user gave focus to a
332 // specific widget in the dialog.
333 b->setFocus();
334 }
335 }
336 }
337 d->mDefaultButton = newDefaultButton;
338 Q_ASSERT(defaultButton() == newDefaultButton);
339 }
340
defaultButton() const341 KoDialog::ButtonCode KoDialog::defaultButton() const
342 {
343 Q_D(const KoDialog);
344 QHashIterator<int, QPushButton *> it(d->mButtonList);
345 while (it.hasNext()) {
346 it.next();
347 if (it.value()->isDefault()) {
348 return (ButtonCode)it.key();
349 }
350 }
351
352 return d->mDefaultButton;
353 }
354
setMainWidget(QWidget * widget)355 void KoDialog::setMainWidget(QWidget *widget)
356 {
357 Q_D(KoDialog);
358 if (d->mMainWidget == widget) {
359 return;
360 }
361 d->mMainWidget = widget;
362 if (d->mMainWidget && d->mMainWidget->layout()) {
363 // Avoid double-margin problem
364 d->mMainWidget->layout()->setMargin(0);
365 }
366 d->setupLayout();
367 }
368
mainWidget()369 QWidget *KoDialog::mainWidget()
370 {
371 Q_D(KoDialog);
372 if (!d->mMainWidget) {
373 setMainWidget(new QWidget(this));
374 }
375 return d->mMainWidget;
376 }
377
sizeHint() const378 QSize KoDialog::sizeHint() const
379 {
380 Q_D(const KoDialog);
381
382 if (!d->mMinSize.isEmpty()) {
383 return d->mMinSize.expandedTo(minimumSizeHint()) + d->mIncSize;
384 } else {
385 if (d->dirty) {
386 const_cast<KoDialogPrivate *>(d)->queuedLayoutUpdate();
387 }
388 return QDialog::sizeHint() + d->mIncSize;
389 }
390 }
391
minimumSizeHint() const392 QSize KoDialog::minimumSizeHint() const
393 {
394 Q_D(const KoDialog);
395
396 if (d->dirty) {
397 const_cast<KoDialogPrivate *>(d)->queuedLayoutUpdate();
398 }
399 return QDialog::minimumSizeHint() + d->mIncSize;
400 }
401
402 //
403 // Grab QDialogs keypresses if non-modal.
404 //
keyPressEvent(QKeyEvent * event)405 void KoDialog::keyPressEvent(QKeyEvent *event)
406 {
407 Q_D(KoDialog);
408 if (event->modifiers() == 0) {
409 if (event->key() == Qt::Key_F1) {
410 QPushButton *button = this->button(Help);
411
412 if (button) {
413 button->animateClick();
414 event->accept();
415 return;
416 }
417 }
418
419 if (event->key() == Qt::Key_Escape) {
420 QPushButton *button = this->button(d->mEscapeButton);
421
422 if (button) {
423 button->animateClick();
424 event->accept();
425 return;
426 }
427
428 }
429 } else if (event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier) {
430 QWhatsThis::enterWhatsThisMode();
431 event->accept();
432 return;
433 } else if (event->modifiers() == Qt::ControlModifier &&
434 (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) {
435 // accept the dialog when Ctrl-Return is pressed
436 QPushButton *button = this->button(Ok);
437
438 if (button) {
439 button->animateClick();
440 event->accept();
441 return;
442 }
443 }
444
445 QDialog::keyPressEvent(event);
446 }
447
marginHint()448 int KoDialog::marginHint()
449 {
450 return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin);
451 }
452
spacingHint()453 int KoDialog::spacingHint()
454 {
455 return QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
456 }
457
groupSpacingHint()458 int KoDialog::groupSpacingHint()
459 {
460 return QApplication::fontMetrics().lineSpacing();
461 }
462
makeStandardCaption(const QString & userCaption,QWidget * window,CaptionFlags flags)463 QString KoDialog::makeStandardCaption(const QString &userCaption,
464 QWidget *window,
465 CaptionFlags flags)
466 {
467 Q_UNUSED(window);
468 QString caption = qApp->applicationDisplayName();
469 QString captionString = userCaption.isEmpty() ? caption : userCaption;
470
471 // If the document is modified, add '[modified]'.
472 if (flags & ModifiedCaption) {
473 captionString += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]");
474 }
475
476 if (!userCaption.isEmpty()) {
477 // Add the application name if:
478 // User asked for it, it's not a duplication and the app name (caption()) is not empty
479 if (flags & AppNameCaption &&
480 !caption.isEmpty() &&
481 !userCaption.endsWith(caption)) {
482 // TODO: check to see if this is a transient/secondary window before trying to add the app name
483 // on platforms that need this
484 captionString += i18nc("Document/application separator in titlebar", " – ") + caption;
485 }
486 }
487
488 return captionString;
489 }
490
setCaption(const QString & _caption)491 void KoDialog::setCaption(const QString &_caption)
492 {
493 const QString caption = makeStandardCaption(_caption, this);
494 setPlainCaption(caption);
495 }
496
setCaption(const QString & caption,bool modified)497 void KoDialog::setCaption(const QString &caption, bool modified)
498 {
499 CaptionFlags flags = HIGCompliantCaption;
500
501 // ### Qt5 TODO: port to [*], see QWidget::setWindowFilePath
502 if (modified) {
503 flags |= ModifiedCaption;
504 }
505
506 setPlainCaption(makeStandardCaption(caption, this, flags));
507 }
508
setPlainCaption(const QString & caption)509 void KoDialog::setPlainCaption(const QString &caption)
510 {
511 if (QWidget *win = window()) {
512 win->setWindowTitle(caption);
513 }
514 }
515
resizeLayout(QWidget * widget,int margin,int spacing)516 void KoDialog::resizeLayout(QWidget *widget, int margin, int spacing) //static
517 {
518 if (widget->layout()) {
519 resizeLayout(widget->layout(), margin, spacing);
520 }
521
522 if (widget->children().count() > 0) {
523 const QList<QObject *> list = widget->children();
524 foreach (QObject *object, list) {
525 if (object->isWidgetType()) {
526 resizeLayout((QWidget *)object, margin, spacing);
527 }
528 }
529 }
530 }
531
resizeLayout(QLayout * layout,int margin,int spacing)532 void KoDialog::resizeLayout(QLayout *layout, int margin, int spacing) //static
533 {
534 QLayoutItem *child;
535 int pos = 0;
536
537 while ((child = layout->itemAt(pos))) {
538 if (child->layout()) {
539 resizeLayout(child->layout(), margin, spacing);
540 }
541
542 ++pos;
543 }
544
545 if (layout->layout()) {
546 layout->layout()->setMargin(margin);
547 layout->layout()->setSpacing(spacing);
548 }
549 }
550
screenRect(QWidget * widget,int screen)551 static QRect screenRect(QWidget *widget, int screen)
552 {
553 QDesktopWidget *desktop = QApplication::desktop();
554 KConfig gc("kdeglobals", KConfig::NoGlobals);
555 KConfigGroup cg(&gc, "Windows");
556 if (desktop->isVirtualDesktop() &&
557 cg.readEntry("XineramaEnabled", true) &&
558 cg.readEntry("XineramaPlacementEnabled", true)) {
559
560 if (screen < 0 || screen >= desktop->numScreens()) {
561 if (screen == -1) {
562 screen = desktop->primaryScreen();
563 } else if (screen == -3) {
564 screen = desktop->screenNumber(QCursor::pos());
565 } else {
566 screen = desktop->screenNumber(widget);
567 }
568 }
569
570 return desktop->availableGeometry(screen);
571 } else {
572 return desktop->geometry();
573 }
574 }
575
centerOnScreen(QWidget * widget,int screen)576 void KoDialog::centerOnScreen(QWidget *widget, int screen)
577 {
578 if (!widget) {
579 return;
580 }
581
582 QRect rect = screenRect(widget, screen);
583
584 widget->move(rect.center().x() - widget->width() / 2,
585 rect.center().y() - widget->height() / 2);
586 }
587
avoidArea(QWidget * widget,const QRect & area,int screen)588 bool KoDialog::avoidArea(QWidget *widget, const QRect &area, int screen)
589 {
590 if (!widget) {
591 return false;
592 }
593
594 QRect fg = widget->frameGeometry();
595 if (!fg.intersects(area)) {
596 return true; // nothing to do.
597 }
598
599 const QRect scr = screenRect(widget, screen);
600 QRect avoid(area); // let's add some margin
601 avoid.translate(-5, -5);
602 avoid.setRight(avoid.right() + 10);
603 avoid.setBottom(avoid.bottom() + 10);
604
605 if (qMax(fg.top(), avoid.top()) <= qMin(fg.bottom(), avoid.bottom())) {
606 // We need to move the widget up or down
607 int spaceAbove = qMax(0, avoid.top() - scr.top());
608 int spaceBelow = qMax(0, scr.bottom() - avoid.bottom());
609 if (spaceAbove > spaceBelow) // where's the biggest side?
610 if (fg.height() <= spaceAbove) { // big enough?
611 fg.setY(avoid.top() - fg.height());
612 } else {
613 return false;
614 }
615 else if (fg.height() <= spaceBelow) { // big enough?
616 fg.setY(avoid.bottom());
617 } else {
618 return false;
619 }
620 }
621
622 if (qMax(fg.left(), avoid.left()) <= qMin(fg.right(), avoid.right())) {
623 // We need to move the widget left or right
624 const int spaceLeft = qMax(0, avoid.left() - scr.left());
625 const int spaceRight = qMax(0, scr.right() - avoid.right());
626 if (spaceLeft > spaceRight) // where's the biggest side?
627 if (fg.width() <= spaceLeft) { // big enough?
628 fg.setX(avoid.left() - fg.width());
629 } else {
630 return false;
631 }
632 else if (fg.width() <= spaceRight) { // big enough?
633 fg.setX(avoid.right());
634 } else {
635 return false;
636 }
637 }
638
639 widget->move(fg.x(), fg.y());
640
641 return true;
642 }
643
showButtonSeparator(bool state)644 void KoDialog::showButtonSeparator(bool state)
645 {
646 Q_D(KoDialog);
647 if ((d->mActionSeparator != 0) == state) {
648 return;
649 }
650 if (state) {
651 if (d->mActionSeparator) {
652 return;
653 }
654
655 d->mActionSeparator = new KSeparator(this);
656 d->mActionSeparator->setOrientation(d->mButtonOrientation);
657 } else {
658 delete d->mActionSeparator;
659 d->mActionSeparator = 0;
660 }
661
662 d->setupLayout();
663 }
664
setInitialSize(const QSize & size)665 void KoDialog::setInitialSize(const QSize &size)
666 {
667 d_func()->mMinSize = size;
668 adjustSize();
669 }
670
incrementInitialSize(const QSize & size)671 void KoDialog::incrementInitialSize(const QSize &size)
672 {
673 d_func()->mIncSize = size;
674 adjustSize();
675 }
676
button(ButtonCode id) const677 QPushButton *KoDialog::button(ButtonCode id) const
678 {
679 Q_D(const KoDialog);
680 return d->mButtonList.value(id, 0);
681 }
682
enableButton(ButtonCode id,bool state)683 void KoDialog::enableButton(ButtonCode id, bool state)
684 {
685 QPushButton *button = this->button(id);
686 if (button) {
687 button->setEnabled(state);
688 }
689 }
690
isButtonEnabled(ButtonCode id) const691 bool KoDialog::isButtonEnabled(ButtonCode id) const
692 {
693 QPushButton *button = this->button(id);
694 if (button) {
695 return button->isEnabled();
696 }
697
698 return false;
699 }
700
enableButtonOk(bool state)701 void KoDialog::enableButtonOk(bool state)
702 {
703 enableButton(Ok, state);
704 }
705
enableButtonApply(bool state)706 void KoDialog::enableButtonApply(bool state)
707 {
708 enableButton(Apply, state);
709 }
710
enableButtonCancel(bool state)711 void KoDialog::enableButtonCancel(bool state)
712 {
713 enableButton(Cancel, state);
714 }
715
showButton(ButtonCode id,bool state)716 void KoDialog::showButton(ButtonCode id, bool state)
717 {
718 QPushButton *button = this->button(id);
719 if (button) {
720 state ? button->show() : button->hide();
721 }
722 }
723
setButtonGuiItem(ButtonCode id,const KGuiItem & item)724 void KoDialog::setButtonGuiItem(ButtonCode id, const KGuiItem &item)
725 {
726 QPushButton *button = this->button(id);
727 if (!button) {
728 return;
729 }
730
731 KGuiItem::assign(button, item);
732 }
733
setButtonText(ButtonCode id,const QString & text)734 void KoDialog::setButtonText(ButtonCode id, const QString &text)
735 {
736 Q_D(KoDialog);
737 if (!d->mSettingDetails && (id == Details)) {
738 d->mDetailsButtonText = text;
739 setDetailsWidgetVisible(d->mDetailsVisible);
740 return;
741 }
742
743 QPushButton *button = this->button(id);
744 if (button) {
745 button->setText(text);
746 }
747 }
748
buttonText(ButtonCode id) const749 QString KoDialog::buttonText(ButtonCode id) const
750 {
751 QPushButton *button = this->button(id);
752 if (button) {
753 return button->text();
754 } else {
755 return QString();
756 }
757 }
758
setButtonIcon(ButtonCode id,const QIcon & icon)759 void KoDialog::setButtonIcon(ButtonCode id, const QIcon &icon)
760 {
761 QPushButton *button = this->button(id);
762 if (button) {
763 button->setIcon(icon);
764 }
765 }
766
buttonIcon(ButtonCode id) const767 QIcon KoDialog::buttonIcon(ButtonCode id) const
768 {
769 QPushButton *button = this->button(id);
770 if (button) {
771 return button->icon();
772 } else {
773 return QIcon();
774 }
775 }
776
setButtonToolTip(ButtonCode id,const QString & text)777 void KoDialog::setButtonToolTip(ButtonCode id, const QString &text)
778 {
779 QPushButton *button = this->button(id);
780 if (button) {
781 if (text.isEmpty()) {
782 button->setToolTip(QString());
783 } else {
784 button->setToolTip(text);
785 }
786 }
787 }
788
buttonToolTip(ButtonCode id) const789 QString KoDialog::buttonToolTip(ButtonCode id) const
790 {
791 QPushButton *button = this->button(id);
792 if (button) {
793 return button->toolTip();
794 } else {
795 return QString();
796 }
797 }
798
setButtonWhatsThis(ButtonCode id,const QString & text)799 void KoDialog::setButtonWhatsThis(ButtonCode id, const QString &text)
800 {
801 QPushButton *button = this->button(id);
802 if (button) {
803 if (text.isEmpty()) {
804 button->setWhatsThis(QString());
805 } else {
806 button->setWhatsThis(text);
807 }
808 }
809 }
810
buttonWhatsThis(ButtonCode id) const811 QString KoDialog::buttonWhatsThis(ButtonCode id) const
812 {
813 QPushButton *button = this->button(id);
814 if (button) {
815 return button->whatsThis();
816 } else {
817 return QString();
818 }
819 }
820
setButtonFocus(ButtonCode id)821 void KoDialog::setButtonFocus(ButtonCode id)
822 {
823 QPushButton *button = this->button(id);
824 if (button) {
825 button->setFocus();
826 }
827 }
828
setDetailsWidget(QWidget * detailsWidget)829 void KoDialog::setDetailsWidget(QWidget *detailsWidget)
830 {
831 Q_D(KoDialog);
832 if (d->mDetailsWidget == detailsWidget) {
833 return;
834 }
835 delete d->mDetailsWidget;
836 d->mDetailsWidget = detailsWidget;
837
838 if (d->mDetailsWidget->parentWidget() != this) {
839 d->mDetailsWidget->setParent(this);
840 }
841
842 d->mDetailsWidget->hide();
843 d->setupLayout();
844
845 if (!d->mSettingDetails) {
846 setDetailsWidgetVisible(d->mDetailsVisible);
847 }
848 }
849
isDetailsWidgetVisible() const850 bool KoDialog::isDetailsWidgetVisible() const
851 {
852 return d_func()->mDetailsVisible;
853 }
854
setDetailsWidgetVisible(bool visible)855 void KoDialog::setDetailsWidgetVisible(bool visible)
856 {
857 Q_D(KoDialog);
858 if (d->mDetailsButtonText.isEmpty()) {
859 d->mDetailsButtonText = i18n("&Details");
860 }
861
862 d->mSettingDetails = true;
863 d->mDetailsVisible = visible;
864 if (d->mDetailsVisible) {
865 emit aboutToShowDetails();
866 setButtonText(Details, d->mDetailsButtonText + " <<");
867 if (d->mDetailsWidget) {
868 if (layout()) {
869 layout()->setEnabled(false);
870 }
871
872 d->mDetailsWidget->show();
873
874 adjustSize();
875
876 if (layout()) {
877 layout()->activate();
878 layout()->setEnabled(true);
879 }
880 }
881 } else {
882 setButtonText(Details, d->mDetailsButtonText + " >>");
883 if (d->mDetailsWidget) {
884 d->mDetailsWidget->hide();
885 }
886
887 if (layout()) {
888 layout()->activate();
889 adjustSize();
890 }
891
892 }
893
894 d->mSettingDetails = false;
895 }
896
delayedDestruct()897 void KoDialog::delayedDestruct()
898 {
899 if (isVisible()) {
900 hide();
901 }
902
903 deleteLater();
904 }
905
slotButtonClicked(int button)906 void KoDialog::slotButtonClicked(int button)
907 {
908 Q_D(KoDialog);
909 emit buttonClicked(static_cast<KoDialog::ButtonCode>(button));
910
911 switch (button) {
912 case Ok:
913 emit okClicked();
914 accept();
915 break;
916 case Apply:
917 emit applyClicked();
918 break;
919 case Try:
920 emit tryClicked();
921 break;
922 case User3:
923 emit user3Clicked();
924 break;
925 case User2:
926 emit user2Clicked();
927 break;
928 case User1:
929 emit user1Clicked();
930 break;
931 case Yes:
932 emit yesClicked();
933 done(Yes);
934 break;
935 case No:
936 emit noClicked();
937 done(No);
938 break;
939 case Cancel:
940 emit cancelClicked();
941 reject();
942 break;
943 case Close:
944 emit closeClicked();
945 done(Close); // KDE5: call reject() instead; more QDialog-like.
946 break;
947 case Help:
948 emit helpClicked();
949 if (!d->mAnchor.isEmpty() || !d->mHelpApp.isEmpty()) {
950 KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp);
951 }
952 break;
953 case Default:
954 emit defaultClicked();
955 break;
956 case Reset:
957 emit resetClicked();
958 break;
959 case Details:
960 setDetailsWidgetVisible(!d->mDetailsVisible);
961 break;
962 }
963
964 // If we're here from the closeEvent, and auto-delete is on, well, auto-delete now.
965 if (d->mDeferredDelete) {
966 d->mDeferredDelete = false;
967 delayedDestruct();
968 }
969 }
970
enableLinkedHelp(bool state)971 void KoDialog::enableLinkedHelp(bool state)
972 {
973 Q_D(KoDialog);
974 if ((d->mUrlHelp != 0) == state) {
975 return;
976 }
977 if (state) {
978 if (d->mUrlHelp) {
979 return;
980 }
981
982 d->mUrlHelp = new KUrlLabel(this);
983 d->mUrlHelp->setText(helpLinkText());
984 d->mUrlHelp->setFloatEnabled(true);
985 d->mUrlHelp->setUnderline(true);
986 d->mUrlHelp->setMinimumHeight(fontMetrics().height() + marginHint());
987 connect(d->mUrlHelp, SIGNAL(leftClickedUrl()), SLOT(helpLinkClicked()));
988
989 d->mUrlHelp->show();
990 } else {
991 delete d->mUrlHelp;
992 d->mUrlHelp = 0;
993 }
994
995 d->setupLayout();
996 }
997
setHelp(const QString & anchor,const QString & appname)998 void KoDialog::setHelp(const QString &anchor, const QString &appname)
999 {
1000 Q_D(KoDialog);
1001 d->mAnchor = anchor;
1002 d->mHelpApp = appname;
1003 }
1004
setHelpLinkText(const QString & text)1005 void KoDialog::setHelpLinkText(const QString &text)
1006 {
1007 Q_D(KoDialog);
1008 d->mHelpLinkText = text;
1009 if (d->mUrlHelp) {
1010 d->mUrlHelp->setText(helpLinkText());
1011 }
1012 }
1013
helpLinkText() const1014 QString KoDialog::helpLinkText() const
1015 {
1016 Q_D(const KoDialog);
1017 return (d->mHelpLinkText.isEmpty() ? i18n("Get help...") : d->mHelpLinkText);
1018 }
1019
updateGeometry()1020 void KoDialog::updateGeometry()
1021 {
1022 }
1023
hideEvent(QHideEvent * event)1024 void KoDialog::hideEvent(QHideEvent *event)
1025 {
1026 emit hidden();
1027
1028 if (!event->spontaneous()) {
1029 emit finished();
1030 }
1031 }
1032
closeEvent(QCloseEvent * event)1033 void KoDialog::closeEvent(QCloseEvent *event)
1034 {
1035 Q_D(KoDialog);
1036 QPushButton *button = this->button(d->mEscapeButton);
1037 if (button && !isHidden()) {
1038 button->animateClick();
1039
1040 if (testAttribute(Qt::WA_DeleteOnClose)) {
1041 // Don't let QWidget::close do a deferred delete just yet, wait for the click first
1042 d->mDeferredDelete = true;
1043 setAttribute(Qt::WA_DeleteOnClose, false);
1044 }
1045 } else {
1046 QDialog::closeEvent(event);
1047 }
1048 }
1049
1050 #include "moc_KoDialog.cpp"
1051