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