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