File indexing completed on 2024-05-12 16:02:08
0001 /* This file is part of the KDE Libraries 0002 * SPDX-FileCopyrightText: 1998 Thomas Tanghus (tanghus@earthling.net) 0003 * SPDX-FileCopyrightText: 1999-2000 Espen Sand (espen@kde.org) 0004 * SPDX-FileCopyrightText: 1999-2000 Holger Freyther <freyther@kde.org> 0005 * SPDX-FileCopyrightText: 2005-2009 Olivier Goffart (ogoffart at kde.org) 0006 * 0007 * SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "KoDialog.h" 0011 #include "KoDialog_p.h" 0012 0013 #include <QWindow> 0014 #include <QApplication> 0015 #include <QGuiApplication> 0016 #include <QDialogButtonBox> 0017 #include <QHBoxLayout> 0018 #include <QHideEvent> 0019 #include <QPointer> 0020 #include <QStyle> 0021 #include <QTimer> 0022 #include <QVBoxLayout> 0023 #include <QWhatsThis> 0024 #include <QDebug> 0025 #include <QPushButton> 0026 #include <QDesktopWidget> 0027 #include <QTimer> 0028 0029 #include <kconfig.h> 0030 #include <klocalizedstring.h> 0031 0032 #include <kseparator.h> 0033 #include <kstandardguiitem.h> 0034 #include <khelpclient.h> 0035 #include <kurllabel.h> 0036 #include <kwindowconfig.h> 0037 0038 void KoDialogPrivate::setupLayout() 0039 { 0040 Q_Q(KoDialog); 0041 if (!dirty) { 0042 QMetaObject::invokeMethod(q, "queuedLayoutUpdate", Qt::QueuedConnection); 0043 dirty = true; 0044 } 0045 } 0046 0047 void KoDialogPrivate::queuedLayoutUpdate() 0048 { 0049 if (!dirty) { 0050 return; 0051 } 0052 0053 dirty = false; 0054 0055 Q_Q(KoDialog); 0056 0057 // Don't lose the focus widget when re-creating the layout. 0058 // Testcase: KOrganizer's "Select Categories" dialog 0059 QPointer<QWidget> focusWidget = mMainWidget ? mMainWidget->focusWidget() : 0; 0060 0061 if (q->layout() && q->layout() != mTopLayout) { 0062 qWarning() << q->metaObject()->className() << "created with a layout; don't do that, KoDialog takes care of it, use mainWidget or setMainWidget instead"; 0063 delete q->layout(); 0064 } 0065 0066 delete mTopLayout; 0067 0068 if (mButtonOrientation == Qt::Horizontal) { 0069 mTopLayout = new QVBoxLayout(q); 0070 } else { 0071 mTopLayout = new QHBoxLayout(q); 0072 } 0073 0074 if (mUrlHelp) { 0075 mTopLayout->addWidget(mUrlHelp, 0, Qt::AlignRight); 0076 } 0077 0078 if (mMainWidget) { 0079 mTopLayout->addWidget(mMainWidget, 10); 0080 } 0081 0082 if (mDetailsWidget) { 0083 mTopLayout->addWidget(mDetailsWidget); 0084 } 0085 0086 if (mActionSeparator) { 0087 mTopLayout->addWidget(mActionSeparator); 0088 } 0089 0090 if (mButtonBox) { 0091 mButtonBox->setOrientation(mButtonOrientation); 0092 mTopLayout->addWidget(mButtonBox); 0093 } 0094 0095 if (focusWidget) { 0096 focusWidget->setFocus(); 0097 } 0098 } 0099 0100 void KoDialogPrivate::appendButton(KoDialog::ButtonCode key, const KGuiItem &item) 0101 { 0102 Q_Q(KoDialog); 0103 0104 QDialogButtonBox::ButtonRole role = QDialogButtonBox::InvalidRole; 0105 switch (key) { 0106 case KoDialog::Help: 0107 case KoDialog::Details: 0108 role = QDialogButtonBox::HelpRole; 0109 break; 0110 case KoDialog::Default: 0111 case KoDialog::Reset: 0112 role = QDialogButtonBox::ResetRole; 0113 break; 0114 case KoDialog::Ok: 0115 role = QDialogButtonBox::AcceptRole; 0116 break; 0117 case KoDialog::Apply: 0118 role = QDialogButtonBox::ApplyRole; 0119 break; 0120 case KoDialog::Try: 0121 case KoDialog::Yes: 0122 role = QDialogButtonBox::YesRole; 0123 break; 0124 case KoDialog::Close: 0125 case KoDialog::Cancel: 0126 role = QDialogButtonBox::RejectRole; 0127 break; 0128 case KoDialog::No: 0129 role = QDialogButtonBox::NoRole; 0130 break; 0131 case KoDialog::User1: 0132 case KoDialog::User2: 0133 case KoDialog::User3: 0134 role = QDialogButtonBox::ActionRole; 0135 break; 0136 default: 0137 role = QDialogButtonBox::InvalidRole; 0138 break; 0139 } 0140 0141 if (role == QDialogButtonBox::InvalidRole) { 0142 return; 0143 } 0144 0145 QPushButton *button = new QPushButton; 0146 KGuiItem::assign(button, item); 0147 mButtonBox->addButton(button, role); 0148 0149 mButtonList.insert(key, button); 0150 0151 QObject::connect(button, &QPushButton::clicked, [=] { q->slotButtonClicked(key); }); 0152 0153 if (key == mDefaultButton) { 0154 // Now that it exists, set it as default 0155 q->setDefaultButton(mDefaultButton); 0156 } 0157 } 0158 0159 void KoDialogPrivate::init(KoDialog *q) 0160 { 0161 q_ptr = q; 0162 0163 dirty = false; 0164 0165 q->setButtons(KoDialog::Ok | KoDialog::Cancel); 0166 q->setDefaultButton(KoDialog::Ok); 0167 0168 q->setPlainCaption(qApp->applicationDisplayName()); // set appropriate initial window title for case it gets not set later 0169 } 0170 0171 void KoDialogPrivate::helpLinkClicked() 0172 { 0173 q_ptr->slotButtonClicked(KoDialog::Help); 0174 } 0175 0176 KoDialog::KoDialog(QWidget *parent, Qt::WindowFlags flags) 0177 : QDialog(parent ? parent : qApp->activeWindow(), flags) 0178 , d_ptr(new KoDialogPrivate) 0179 { 0180 d_ptr->init(this); 0181 } 0182 0183 KoDialog::KoDialog(KoDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags) 0184 : QDialog(parent ? parent : qApp->activeWindow(), flags) 0185 , d_ptr(&dd) 0186 { 0187 d_ptr->init(this); 0188 } 0189 0190 KoDialog::~KoDialog() 0191 { 0192 delete d_ptr; 0193 } 0194 0195 void KoDialog::setButtons(ButtonCodes buttonMask) 0196 { 0197 Q_D(KoDialog); 0198 if (d->mButtonBox) { 0199 d->mButtonList.clear(); 0200 0201 delete d->mButtonBox; 0202 d->mButtonBox = 0; 0203 } 0204 0205 if (buttonMask & Cancel) { 0206 buttonMask &= ~Close; 0207 } 0208 0209 if (buttonMask & Apply) { 0210 buttonMask &= ~Try; 0211 } 0212 0213 if (buttonMask & Details) { 0214 buttonMask &= ~Default; 0215 } 0216 0217 if (buttonMask == None) { 0218 d->setupLayout(); 0219 return; // When we want no button box 0220 } 0221 0222 d->mEscapeButton = (buttonMask & Cancel) ? Cancel : Close; 0223 d->mButtonBox = new QDialogButtonBox(this); 0224 0225 if (buttonMask & Help) { 0226 d->appendButton(Help, KStandardGuiItem::help()); 0227 } 0228 if (buttonMask & Default) { 0229 d->appendButton(Default, KStandardGuiItem::defaults()); 0230 } 0231 if (buttonMask & Reset) { 0232 d->appendButton(Reset, KStandardGuiItem::reset()); 0233 } 0234 if (buttonMask & User3) { 0235 d->appendButton(User3, KGuiItem()); 0236 } 0237 if (buttonMask & User2) { 0238 d->appendButton(User2, KGuiItem()); 0239 } 0240 if (buttonMask & User1) { 0241 d->appendButton(User1, KGuiItem()); 0242 } 0243 if (buttonMask & Ok) { 0244 d->appendButton(Ok, KStandardGuiItem::ok()); 0245 } 0246 if (buttonMask & Apply) { 0247 d->appendButton(Apply, KStandardGuiItem::apply()); 0248 } 0249 if (buttonMask & Try) { 0250 d->appendButton(Try, KGuiItem(i18n("&Try"))); 0251 } 0252 if (buttonMask & Cancel) { 0253 d->appendButton(Cancel, KStandardGuiItem::cancel()); 0254 } 0255 if (buttonMask & Close) { 0256 d->appendButton(Close, KStandardGuiItem::close()); 0257 } 0258 if (buttonMask & Yes) { 0259 d->appendButton(Yes, KStandardGuiItem::yes()); 0260 } 0261 if (buttonMask & No) { 0262 d->appendButton(No, KStandardGuiItem::no()); 0263 } 0264 if (buttonMask & Details) { 0265 d->appendButton(Details, KGuiItem(QString(), "help-about")); 0266 setDetailsWidgetVisible(false); 0267 } 0268 0269 d->setupLayout(); 0270 } 0271 0272 void KoDialog::setButtonsOrientation(Qt::Orientation orientation) 0273 { 0274 Q_D(KoDialog); 0275 if (d->mButtonOrientation != orientation) { 0276 d->mButtonOrientation = orientation; 0277 0278 if (d->mActionSeparator) { 0279 d->mActionSeparator->setOrientation(d->mButtonOrientation); 0280 } 0281 0282 if (d->mButtonOrientation == Qt::Vertical) { 0283 enableLinkedHelp(false); // 2000-06-18 Espen: No support for this yet. 0284 } 0285 } 0286 } 0287 0288 void KoDialog::setEscapeButton(ButtonCode id) 0289 { 0290 d_func()->mEscapeButton = id; 0291 } 0292 0293 void KoDialog::setDefaultButton(ButtonCode newDefaultButton) 0294 { 0295 Q_D(KoDialog); 0296 0297 if (newDefaultButton == None) { 0298 newDefaultButton = NoDefault; // #148969 0299 } 0300 0301 const KoDialog::ButtonCode oldDefault = defaultButton(); 0302 0303 bool oldDefaultHadFocus = false; 0304 0305 if (oldDefault != NoDefault) { 0306 QPushButton *old = button(oldDefault); 0307 if (old) { 0308 oldDefaultHadFocus = (focusWidget() == old); 0309 old->setDefault(false); 0310 } 0311 } 0312 0313 if (newDefaultButton != NoDefault) { 0314 QPushButton *b = button(newDefaultButton); 0315 if (b) { 0316 b->setDefault(true); 0317 if (focusWidget() == 0 || oldDefaultHadFocus) { 0318 // No widget had focus yet, or the old default button had 0319 // -> ok to give focus to the new default button, so that it's 0320 // really default (Enter triggers it). 0321 // But we don't do this if the kdialog user gave focus to a 0322 // specific widget in the dialog. 0323 b->setFocus(); 0324 } 0325 } 0326 } 0327 d->mDefaultButton = newDefaultButton; 0328 Q_ASSERT(defaultButton() == newDefaultButton); 0329 } 0330 0331 KoDialog::ButtonCode KoDialog::defaultButton() const 0332 { 0333 Q_D(const KoDialog); 0334 QHashIterator<int, QPushButton *> it(d->mButtonList); 0335 while (it.hasNext()) { 0336 it.next(); 0337 if (it.value()->isDefault()) { 0338 return (ButtonCode)it.key(); 0339 } 0340 } 0341 0342 return d->mDefaultButton; 0343 } 0344 0345 void KoDialog::setMainWidget(QWidget *widget) 0346 { 0347 Q_D(KoDialog); 0348 if (d->mMainWidget == widget) { 0349 return; 0350 } 0351 d->mMainWidget = widget; 0352 if (d->mMainWidget && d->mMainWidget->layout()) { 0353 // Avoid double-margin problem 0354 d->mMainWidget->layout()->setMargin(0); 0355 } 0356 d->setupLayout(); 0357 } 0358 0359 QWidget *KoDialog::mainWidget() 0360 { 0361 Q_D(KoDialog); 0362 if (!d->mMainWidget) { 0363 setMainWidget(new QWidget(this)); 0364 } 0365 return d->mMainWidget; 0366 } 0367 0368 QSize KoDialog::sizeHint() const 0369 { 0370 Q_D(const KoDialog); 0371 0372 if (!d->mMinSize.isEmpty()) { 0373 return d->mMinSize.expandedTo(minimumSizeHint()) + d->mIncSize; 0374 } else { 0375 if (d->dirty) { 0376 const_cast<KoDialogPrivate *>(d)->queuedLayoutUpdate(); 0377 } 0378 return QDialog::sizeHint() + d->mIncSize; 0379 } 0380 } 0381 0382 QSize KoDialog::minimumSizeHint() const 0383 { 0384 Q_D(const KoDialog); 0385 0386 if (d->dirty) { 0387 const_cast<KoDialogPrivate *>(d)->queuedLayoutUpdate(); 0388 } 0389 return QDialog::minimumSizeHint() + d->mIncSize; 0390 } 0391 0392 // 0393 // Grab QDialogs keypresses if non-modal. 0394 // 0395 void KoDialog::keyPressEvent(QKeyEvent *event) 0396 { 0397 Q_D(KoDialog); 0398 if (event->modifiers() == 0) { 0399 if (event->key() == Qt::Key_F1) { 0400 QPushButton *button = this->button(Help); 0401 0402 if (button) { 0403 button->animateClick(); 0404 event->accept(); 0405 return; 0406 } 0407 } 0408 0409 if (event->key() == Qt::Key_Escape) { 0410 QPushButton *button = this->button(d->mEscapeButton); 0411 0412 if (button) { 0413 button->animateClick(); 0414 event->accept(); 0415 return; 0416 } 0417 0418 } 0419 } else if (event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier) { 0420 QWhatsThis::enterWhatsThisMode(); 0421 event->accept(); 0422 return; 0423 } else if (event->modifiers() == Qt::ControlModifier && 0424 (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) { 0425 // accept the dialog when Ctrl-Return is pressed 0426 QPushButton *button = this->button(Ok); 0427 0428 if (button) { 0429 button->animateClick(); 0430 event->accept(); 0431 return; 0432 } 0433 } 0434 0435 QDialog::keyPressEvent(event); 0436 } 0437 0438 void KoDialog::showEvent(QShowEvent *e) 0439 { 0440 QDialog::showEvent(e); 0441 QTimer::singleShot(5, this, SLOT(adjustPosition())); 0442 } 0443 0444 int KoDialog::marginHint() 0445 { 0446 return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin); 0447 } 0448 0449 int KoDialog::spacingHint() 0450 { 0451 return QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); 0452 } 0453 0454 int KoDialog::groupSpacingHint() 0455 { 0456 return QApplication::fontMetrics().lineSpacing(); 0457 } 0458 0459 QString KoDialog::makeStandardCaption(const QString &userCaption, 0460 QWidget *window, 0461 CaptionFlags flags) 0462 { 0463 Q_UNUSED(window); 0464 QString caption = qApp->applicationDisplayName(); 0465 QString captionString = userCaption.isEmpty() ? caption : userCaption; 0466 0467 // If the document is modified, add '[modified]'. 0468 if (flags & ModifiedCaption) { 0469 captionString += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]"); 0470 } 0471 0472 if (!userCaption.isEmpty()) { 0473 // Add the application name if: 0474 // User asked for it, it's not a duplication and the app name (caption()) is not empty 0475 if (flags & AppNameCaption && 0476 !caption.isEmpty() && 0477 !userCaption.endsWith(caption)) { 0478 // TODO: check to see if this is a transient/secondary window before trying to add the app name 0479 // on platforms that need this 0480 captionString += i18nc("Document/application separator in titlebar", " – ") + caption; 0481 } 0482 } 0483 0484 return captionString; 0485 } 0486 0487 void KoDialog::setCaption(const QString &_caption) 0488 { 0489 const QString caption = makeStandardCaption(_caption, this); 0490 setPlainCaption(caption); 0491 } 0492 0493 void KoDialog::setCaption(const QString &caption, bool modified) 0494 { 0495 CaptionFlags flags = HIGCompliantCaption; 0496 0497 // ### Qt5 TODO: port to [*], see QWidget::setWindowFilePath 0498 if (modified) { 0499 flags |= ModifiedCaption; 0500 } 0501 0502 setPlainCaption(makeStandardCaption(caption, this, flags)); 0503 } 0504 0505 void KoDialog::setPlainCaption(const QString &caption) 0506 { 0507 if (QWidget *win = window()) { 0508 win->setWindowTitle(caption); 0509 } 0510 } 0511 0512 void KoDialog::resizeLayout(QWidget *widget, int margin, int spacing) //static 0513 { 0514 if (widget->layout()) { 0515 resizeLayout(widget->layout(), margin, spacing); 0516 } 0517 0518 if (widget->children().count() > 0) { 0519 const QList<QObject *> list = widget->children(); 0520 foreach (QObject *object, list) { 0521 if (object->isWidgetType()) { 0522 resizeLayout((QWidget *)object, margin, spacing); 0523 } 0524 } 0525 } 0526 } 0527 0528 void KoDialog::resizeLayout(QLayout *layout, int margin, int spacing) //static 0529 { 0530 QLayoutItem *child; 0531 int pos = 0; 0532 0533 while ((child = layout->itemAt(pos))) { 0534 if (child->layout()) { 0535 resizeLayout(child->layout(), margin, spacing); 0536 } 0537 0538 ++pos; 0539 } 0540 0541 if (layout->layout()) { 0542 layout->layout()->setMargin(margin); 0543 layout->layout()->setSpacing(spacing); 0544 } 0545 } 0546 0547 void KoDialog::showButtonSeparator(bool state) 0548 { 0549 Q_D(KoDialog); 0550 if ((d->mActionSeparator != 0) == state) { 0551 return; 0552 } 0553 if (state) { 0554 if (d->mActionSeparator) { 0555 return; 0556 } 0557 0558 d->mActionSeparator = new KSeparator(this); 0559 d->mActionSeparator->setOrientation(d->mButtonOrientation); 0560 } else { 0561 delete d->mActionSeparator; 0562 d->mActionSeparator = 0; 0563 } 0564 0565 d->setupLayout(); 0566 } 0567 0568 void KoDialog::setInitialSize(const QSize &size) 0569 { 0570 d_func()->mMinSize = size; 0571 adjustSize(); 0572 } 0573 0574 void KoDialog::incrementInitialSize(const QSize &size) 0575 { 0576 d_func()->mIncSize = size; 0577 adjustSize(); 0578 } 0579 0580 QPushButton *KoDialog::button(ButtonCode id) const 0581 { 0582 Q_D(const KoDialog); 0583 return d->mButtonList.value(id, 0); 0584 } 0585 0586 void KoDialog::enableButton(ButtonCode id, bool state) 0587 { 0588 QPushButton *button = this->button(id); 0589 if (button) { 0590 button->setEnabled(state); 0591 } 0592 } 0593 0594 bool KoDialog::isButtonEnabled(ButtonCode id) const 0595 { 0596 QPushButton *button = this->button(id); 0597 if (button) { 0598 return button->isEnabled(); 0599 } 0600 0601 return false; 0602 } 0603 0604 void KoDialog::enableButtonOk(bool state) 0605 { 0606 enableButton(Ok, state); 0607 } 0608 0609 void KoDialog::enableButtonApply(bool state) 0610 { 0611 enableButton(Apply, state); 0612 } 0613 0614 void KoDialog::enableButtonCancel(bool state) 0615 { 0616 enableButton(Cancel, state); 0617 } 0618 0619 void KoDialog::showButton(ButtonCode id, bool state) 0620 { 0621 QPushButton *button = this->button(id); 0622 if (button) { 0623 state ? button->show() : button->hide(); 0624 } 0625 } 0626 0627 void KoDialog::setButtonGuiItem(ButtonCode id, const KGuiItem &item) 0628 { 0629 QPushButton *button = this->button(id); 0630 if (!button) { 0631 return; 0632 } 0633 0634 KGuiItem::assign(button, item); 0635 } 0636 0637 void KoDialog::setButtonText(ButtonCode id, const QString &text) 0638 { 0639 Q_D(KoDialog); 0640 if (!d->mSettingDetails && (id == Details)) { 0641 d->mDetailsButtonText = text; 0642 setDetailsWidgetVisible(d->mDetailsVisible); 0643 return; 0644 } 0645 0646 QPushButton *button = this->button(id); 0647 if (button) { 0648 button->setText(text); 0649 } 0650 } 0651 0652 QString KoDialog::buttonText(ButtonCode id) const 0653 { 0654 QPushButton *button = this->button(id); 0655 if (button) { 0656 return button->text(); 0657 } else { 0658 return QString(); 0659 } 0660 } 0661 0662 void KoDialog::setButtonIcon(ButtonCode id, const QIcon &icon) 0663 { 0664 QPushButton *button = this->button(id); 0665 if (button) { 0666 button->setIcon(icon); 0667 } 0668 } 0669 0670 QIcon KoDialog::buttonIcon(ButtonCode id) const 0671 { 0672 QPushButton *button = this->button(id); 0673 if (button) { 0674 return button->icon(); 0675 } else { 0676 return QIcon(); 0677 } 0678 } 0679 0680 void KoDialog::setButtonToolTip(ButtonCode id, const QString &text) 0681 { 0682 QPushButton *button = this->button(id); 0683 if (button) { 0684 if (text.isEmpty()) { 0685 button->setToolTip(QString()); 0686 } else { 0687 button->setToolTip(text); 0688 } 0689 } 0690 } 0691 0692 QString KoDialog::buttonToolTip(ButtonCode id) const 0693 { 0694 QPushButton *button = this->button(id); 0695 if (button) { 0696 return button->toolTip(); 0697 } else { 0698 return QString(); 0699 } 0700 } 0701 0702 void KoDialog::setButtonWhatsThis(ButtonCode id, const QString &text) 0703 { 0704 QPushButton *button = this->button(id); 0705 if (button) { 0706 if (text.isEmpty()) { 0707 button->setWhatsThis(QString()); 0708 } else { 0709 button->setWhatsThis(text); 0710 } 0711 } 0712 } 0713 0714 QString KoDialog::buttonWhatsThis(ButtonCode id) const 0715 { 0716 QPushButton *button = this->button(id); 0717 if (button) { 0718 return button->whatsThis(); 0719 } else { 0720 return QString(); 0721 } 0722 } 0723 0724 void KoDialog::setButtonFocus(ButtonCode id) 0725 { 0726 QPushButton *button = this->button(id); 0727 if (button) { 0728 button->setFocus(); 0729 } 0730 } 0731 0732 void KoDialog::setDetailsWidget(QWidget *detailsWidget) 0733 { 0734 Q_D(KoDialog); 0735 if (d->mDetailsWidget == detailsWidget) { 0736 return; 0737 } 0738 delete d->mDetailsWidget; 0739 d->mDetailsWidget = detailsWidget; 0740 0741 if (d->mDetailsWidget->parentWidget() != this) { 0742 d->mDetailsWidget->setParent(this); 0743 } 0744 0745 d->mDetailsWidget->hide(); 0746 d->setupLayout(); 0747 0748 if (!d->mSettingDetails) { 0749 setDetailsWidgetVisible(d->mDetailsVisible); 0750 } 0751 } 0752 0753 bool KoDialog::isDetailsWidgetVisible() const 0754 { 0755 return d_func()->mDetailsVisible; 0756 } 0757 0758 void KoDialog::setDetailsWidgetVisible(bool visible) 0759 { 0760 Q_D(KoDialog); 0761 if (d->mDetailsButtonText.isEmpty()) { 0762 d->mDetailsButtonText = i18n("&Details"); 0763 } 0764 0765 d->mSettingDetails = true; 0766 d->mDetailsVisible = visible; 0767 if (d->mDetailsVisible) { 0768 emit aboutToShowDetails(); 0769 setButtonText(Details, d->mDetailsButtonText + " <<"); 0770 if (d->mDetailsWidget) { 0771 if (layout()) { 0772 layout()->setEnabled(false); 0773 } 0774 0775 d->mDetailsWidget->show(); 0776 0777 adjustSize(); 0778 0779 if (layout()) { 0780 layout()->activate(); 0781 layout()->setEnabled(true); 0782 } 0783 } 0784 } else { 0785 setButtonText(Details, d->mDetailsButtonText + " >>"); 0786 if (d->mDetailsWidget) { 0787 d->mDetailsWidget->hide(); 0788 } 0789 0790 if (layout()) { 0791 layout()->activate(); 0792 adjustSize(); 0793 } 0794 0795 } 0796 0797 d->mSettingDetails = false; 0798 } 0799 0800 void KoDialog::delayedDestruct() 0801 { 0802 if (isVisible()) { 0803 hide(); 0804 } 0805 0806 deleteLater(); 0807 } 0808 0809 void KoDialog::slotButtonClicked(int button) 0810 { 0811 Q_D(KoDialog); 0812 emit buttonClicked(static_cast<KoDialog::ButtonCode>(button)); 0813 0814 switch (button) { 0815 case Ok: 0816 emit okClicked(); 0817 accept(); 0818 break; 0819 case Apply: 0820 emit applyClicked(); 0821 break; 0822 case Try: 0823 emit tryClicked(); 0824 break; 0825 case User3: 0826 emit user3Clicked(); 0827 break; 0828 case User2: 0829 emit user2Clicked(); 0830 break; 0831 case User1: 0832 emit user1Clicked(); 0833 break; 0834 case Yes: 0835 emit yesClicked(); 0836 done(Yes); 0837 break; 0838 case No: 0839 emit noClicked(); 0840 done(No); 0841 break; 0842 case Cancel: 0843 emit cancelClicked(); 0844 reject(); 0845 break; 0846 case Close: 0847 emit closeClicked(); 0848 done(Close); // KDE5: call reject() instead; more QDialog-like. 0849 break; 0850 case Help: 0851 emit helpClicked(); 0852 if (!d->mAnchor.isEmpty() || !d->mHelpApp.isEmpty()) { 0853 KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp); 0854 } 0855 break; 0856 case Default: 0857 emit defaultClicked(); 0858 break; 0859 case Reset: 0860 emit resetClicked(); 0861 break; 0862 case Details: 0863 setDetailsWidgetVisible(!d->mDetailsVisible); 0864 break; 0865 } 0866 0867 // If we're here from the closeEvent, and auto-delete is on, well, auto-delete now. 0868 if (d->mDeferredDelete) { 0869 d->mDeferredDelete = false; 0870 delayedDestruct(); 0871 } 0872 } 0873 0874 void KoDialog::enableLinkedHelp(bool state) 0875 { 0876 Q_D(KoDialog); 0877 if ((d->mUrlHelp != 0) == state) { 0878 return; 0879 } 0880 if (state) { 0881 if (d->mUrlHelp) { 0882 return; 0883 } 0884 0885 d->mUrlHelp = new KUrlLabel(this); 0886 d->mUrlHelp->setText(helpLinkText()); 0887 d->mUrlHelp->setFloatEnabled(true); 0888 d->mUrlHelp->setUnderline(true); 0889 d->mUrlHelp->setMinimumHeight(fontMetrics().height() + marginHint()); 0890 connect(d->mUrlHelp, SIGNAL(leftClickedUrl()), SLOT(helpLinkClicked())); 0891 0892 d->mUrlHelp->show(); 0893 } else { 0894 delete d->mUrlHelp; 0895 d->mUrlHelp = 0; 0896 } 0897 0898 d->setupLayout(); 0899 } 0900 0901 void KoDialog::setHelp(const QString &anchor, const QString &appname) 0902 { 0903 Q_D(KoDialog); 0904 d->mAnchor = anchor; 0905 d->mHelpApp = appname; 0906 } 0907 0908 void KoDialog::setHelpLinkText(const QString &text) 0909 { 0910 Q_D(KoDialog); 0911 d->mHelpLinkText = text; 0912 if (d->mUrlHelp) { 0913 d->mUrlHelp->setText(helpLinkText()); 0914 } 0915 } 0916 0917 QString KoDialog::helpLinkText() const 0918 { 0919 Q_D(const KoDialog); 0920 return (d->mHelpLinkText.isEmpty() ? i18n("Get help...") : d->mHelpLinkText); 0921 } 0922 0923 void KoDialog::hideEvent(QHideEvent *event) 0924 { 0925 emit hidden(); 0926 0927 if (!event->spontaneous()) { 0928 emit finished(); 0929 } 0930 } 0931 0932 void KoDialog::closeEvent(QCloseEvent *event) 0933 { 0934 Q_D(KoDialog); 0935 QPushButton *button = this->button(d->mEscapeButton); 0936 if (button && !isHidden()) { 0937 button->animateClick(); 0938 0939 if (testAttribute(Qt::WA_DeleteOnClose)) { 0940 // Don't let QWidget::close do a deferred delete just yet, wait for the click first 0941 d->mDeferredDelete = true; 0942 setAttribute(Qt::WA_DeleteOnClose, false); 0943 } 0944 } else { 0945 QDialog::closeEvent(event); 0946 } 0947 } 0948 0949 void KoDialog::adjustPosition() 0950 { 0951 QWidget *w = parentWidget(); 0952 0953 QPoint p(0, 0); 0954 int extraw = 0, extrah = 0, scrn = 0; 0955 if (w) 0956 w = w->window(); 0957 QRect desk; 0958 if (w) { 0959 scrn = qApp->desktop()->screenNumber(w); 0960 } else if (qApp->desktop()->isVirtualDesktop()) { 0961 scrn = qApp->desktop()->screenNumber(QCursor::pos()); 0962 } else { 0963 scrn = qApp->desktop()->screenNumber(this); 0964 } 0965 desk = qApp->desktop()->availableGeometry(scrn); 0966 0967 QWidgetList list = QApplication::topLevelWidgets(); 0968 for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) { 0969 QWidget * current = list.at(i); 0970 if (current->isVisible()) { 0971 int framew = current->geometry().x() - current->x(); 0972 int frameh = current->geometry().y() - current->y(); 0973 0974 extraw = qMax(extraw, framew); 0975 extrah = qMax(extrah, frameh); 0976 } 0977 } 0978 0979 // sanity check for decoration frames. With embedding, we 0980 // might get extraordinary values 0981 if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) { 0982 extrah = 40; 0983 extraw = 10; 0984 } 0985 0986 0987 if (w) { 0988 // Use pos() if the widget is embedded into a native window 0989 QPoint pp; 0990 if (w->windowHandle() && w->windowHandle()->property("_q_embedded_native_parent_handle").value<WId>()) 0991 pp = w->pos(); 0992 else 0993 pp = w->mapToGlobal(QPoint(0,0)); 0994 p = QPoint(pp.x() + w->width()/2, 0995 pp.y() + w->height()/ 2); 0996 } else { 0997 // p = middle of the desktop 0998 p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2); 0999 } 1000 1001 // p = origin of this 1002 p = QPoint(p.x()-width()/2 - extraw, 1003 p.y()-height()/2 - extrah); 1004 1005 1006 if (p.x() + extraw + width() > desk.x() + desk.width()) 1007 p.setX(desk.x() + desk.width() - width() - extraw); 1008 if (p.x() < desk.x()) 1009 p.setX(desk.x()); 1010 1011 if (p.y() + extrah + height() > desk.y() + desk.height()) 1012 p.setY(desk.y() + desk.height() - height() - extrah); 1013 if (p.y() < desk.y()) 1014 p.setY(desk.y()); 1015 1016 // QTBUG-52735: Manually set the correct target screen since scaling in a 1017 // subsequent call to QWindow::resize() may otherwise use the wrong factor 1018 // if the screen changed notification is still in an event queue. 1019 if (scrn >= 0) { 1020 if (QWindow *window = windowHandle()) 1021 window->setScreen(QGuiApplication::screens().at(scrn)); 1022 } 1023 setGeometry(p.x(), p.y(), width(), height()); 1024 } 1025 1026 1027 1028 #include "moc_KoDialog.cpp"