diff --git a/.gitignore b/.gitignore index d814e73cb9..71bc26627e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,33 @@ *.orig +*.rej __pycache__ *.egg-info *.trace build qtcreator-build *.kdev4 *~ .kateconfig CMakeLists.txt.user* .directory *.autosave *.swp .gdb_history .kdev_include_paths *.config *.creator *.creator.user *.files *.includes .DS_Store *.kate-swap .idea GTAGS GPATH GRTAGS GSYMS BROWSE *.kate-swp /po/ build_dir .flatpak-builder diff --git a/libs/ui/KisWelcomePageWidget.cpp b/libs/ui/KisWelcomePageWidget.cpp index 7a479abbe1..7ab6bcd89a 100644 --- a/libs/ui/KisWelcomePageWidget.cpp +++ b/libs/ui/KisWelcomePageWidget.cpp @@ -1,460 +1,456 @@ /* This file is part of the KDE project * Copyright (C) 2018 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisWelcomePageWidget.h" #include #include #include #include #include #include #include "kis_action_manager.h" #include "kactioncollection.h" #include "kis_action.h" #include "KConfigGroup" #include "KSharedConfig" #include #include #include "kis_icon_utils.h" #include "krita_utils.h" #include "KoStore.h" #include "kis_config.h" #include "KisDocument.h" #include #include #include KisWelcomePageWidget::KisWelcomePageWidget(QWidget *parent) : QWidget(parent) { setupUi(this); recentDocumentsListView->setDragEnabled(false); recentDocumentsListView->viewport()->setAutoFillBackground(false); recentDocumentsListView->setSpacing(2); // set up URLs that go to web browser manualLink->setTextFormat(Qt::RichText); manualLink->setTextInteractionFlags(Qt::TextBrowserInteraction); manualLink->setOpenExternalLinks(true); gettingStartedLink->setTextFormat(Qt::RichText); gettingStartedLink->setTextInteractionFlags(Qt::TextBrowserInteraction); gettingStartedLink->setOpenExternalLinks(true); supportKritaLink->setTextFormat(Qt::RichText); supportKritaLink->setTextInteractionFlags(Qt::TextBrowserInteraction); supportKritaLink->setOpenExternalLinks(true); userCommunityLink->setTextFormat(Qt::RichText); userCommunityLink->setTextInteractionFlags(Qt::TextBrowserInteraction); userCommunityLink->setOpenExternalLinks(true); kritaWebsiteLink->setTextFormat(Qt::RichText); kritaWebsiteLink->setTextInteractionFlags(Qt::TextBrowserInteraction); kritaWebsiteLink->setOpenExternalLinks(true); sourceCodeLink->setTextFormat(Qt::RichText); sourceCodeLink->setTextInteractionFlags(Qt::TextBrowserInteraction); sourceCodeLink->setOpenExternalLinks(true); poweredByKDELink->setTextFormat(Qt::RichText); poweredByKDELink->setTextInteractionFlags(Qt::TextBrowserInteraction); poweredByKDELink->setOpenExternalLinks(true); kdeIcon->setIconSize(QSize(20, 20)); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); versionNotificationLabel->setTextFormat(Qt::RichText); versionNotificationLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); versionNotificationLabel->setOpenExternalLinks(true); connect(chkShowNews, SIGNAL(toggled(bool)), newsWidget, SLOT(toggleNews(bool))); connect(newsWidget, SIGNAL(newsDataChanged()), this, SLOT(slotUpdateVersionMessage())); #ifdef Q_OS_ANDROID // checking this widgets crashes the app, so it is better for it to be hidden for now newsWidget->hide(); helpTitleLabel_2->hide(); chkShowNews->hide(); #endif // configure the News area KisConfig cfg(true); bool m_getNews = cfg.readEntry("FetchNews", false); chkShowNews->setChecked(m_getNews); setAcceptDrops(true); } KisWelcomePageWidget::~KisWelcomePageWidget() { } void KisWelcomePageWidget::setMainWindow(KisMainWindow* mainWin) { if (mainWin) { m_mainWindow = mainWin; // set the shortcut links from actions (only if a shortcut exists) if ( mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() != "") { newFileLinkShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() + QString(")")); } if (mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() != "") { openFileShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() + QString(")")); } connect(recentDocumentsListView, SIGNAL(clicked(QModelIndex)), this, SLOT(recentDocumentClicked(QModelIndex))); // we need the view manager to actually call actions, so don't create the connections // until after the view manager is set connect(newFileLink, SIGNAL(clicked(bool)), this, SLOT(slotNewFileClicked())); connect(openFileLink, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileClicked())); connect(clearRecentFilesLink, SIGNAL(clicked(bool)), mainWin, SLOT(clearRecentFiles())); slotUpdateThemeColors(); // allows RSS news items to apply analytics tracking. newsWidget->setAnalyticsTracking("?" + analyticsString); } } -bool KisWelcomePageWidget::isDevelopmentBuild() -{ - // dev builds contain GIT hash in it and the word git - // stable versions do not contain this - return qApp->applicationVersion().contains("git"); -} void KisWelcomePageWidget::showDropAreaIndicator(bool show) { if (!show) { QString dropFrameStyle = "QFrame#dropAreaIndicator { border: 0px }"; dropFrameBorder->setStyleSheet(dropFrameStyle); } else { QColor textColor = qApp->palette().color(QPalette::Text); QColor backgroundColor = qApp->palette().color(QPalette::Background); QColor blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); // QColor.name() turns it into a hex/web format QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 2px dotted ").append(blendedColor.name()).append(" }") ; dropFrameBorder->setStyleSheet(dropFrameStyle); } } void KisWelcomePageWidget::slotUpdateThemeColors() { textColor = qApp->palette().color(QPalette::Text); backgroundColor = qApp->palette().color(QPalette::Background); // make the welcome screen labels a subtle color so it doesn't clash with the main UI elements blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); blendedStyle = QString("color: ").append(blendedColor.name()); // what labels to change the color... startTitleLabel->setStyleSheet(blendedStyle); recentDocumentsLabel->setStyleSheet(blendedStyle); helpTitleLabel->setStyleSheet(blendedStyle); newFileLinkShortcut->setStyleSheet(blendedStyle); openFileShortcut->setStyleSheet(blendedStyle); clearRecentFilesLink->setStyleSheet(blendedStyle); recentDocumentsListView->setStyleSheet(blendedStyle); newFileLink->setStyleSheet(blendedStyle); openFileLink->setStyleSheet(blendedStyle); // giving the drag area messaging a dotted border QString dottedBorderStyle = QString("border: 2px dotted ").append(blendedColor.name()).append("; color:").append(blendedColor.name()).append( ";"); dragImageHereLabel->setStyleSheet(dottedBorderStyle); // make drop area QFrame have a dotted line dropFrameBorder->setObjectName("dropAreaIndicator"); QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 4px dotted ").append(blendedColor.name()).append("}"); dropFrameBorder->setStyleSheet(dropFrameStyle); // only show drop area when we have a document over the empty area showDropAreaIndicator(false); // add icons for new and open settings to make them stand out a bit more openFileLink->setIconSize(QSize(30, 30)); newFileLink->setIconSize(QSize(30, 30)); openFileLink->setIcon(KisIconUtils::loadIcon("document-open")); newFileLink->setIcon(KisIconUtils::loadIcon("document-new")); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); // HTML links seem to be a bit more stubborn with theme changes... setting inline styles to help with color change userCommunityLink->setText(QString("") .append(i18n("User Community")).append("")); gettingStartedLink->setText(QString("") .append(i18n("Getting Started")).append("")); manualLink->setText(QString("") .append(i18n("User Manual")).append("")); supportKritaLink->setText(QString("") .append(i18n("Support Krita")).append("")); kritaWebsiteLink->setText(QString("") .append(i18n("Krita Website")).append("")); sourceCodeLink->setText(QString("") .append(i18n("Source Code")).append("")); poweredByKDELink->setText(QString("") .append(i18n("Powered by KDE")).append("")); slotUpdateVersionMessage(); // text set from RSS feed // re-populate recent files since they might have themed icons populateRecentDocuments(); } void KisWelcomePageWidget::populateRecentDocuments() { m_recentFilesModel.clear(); // clear existing data before it gets re-populated // grab recent files data int numRecentFiles = m_mainWindow->recentFilesUrls().length() > 5 ? 5 : m_mainWindow->recentFilesUrls().length(); // grab at most 5 for (int i = 0; i < numRecentFiles; i++ ) { QStandardItem *recentItem = new QStandardItem(1,2); // 1 row, 1 column recentItem->setIcon(KisIconUtils::loadIcon("document-export")); QString recentFileUrlPath = m_mainWindow->recentFilesUrls().at(i).toLocalFile(); QString fileName = recentFileUrlPath.split("/").last(); QList brokenUrls; if (m_thumbnailMap.contains(recentFileUrlPath)) { recentItem->setIcon(m_thumbnailMap[recentFileUrlPath]); } else { QFileInfo fi(recentFileUrlPath); if (fi.exists()) { if (fi.suffix() == "ora" || fi.suffix() == "kra") { QScopedPointer store(KoStore::createStore(recentFileUrlPath, KoStore::Read)); if (store) { QString thumbnailpath; if (store->hasFile(QString("Thumbnails/thumbnail.png"))){ thumbnailpath = QString("Thumbnails/thumbnail.png"); } else if (store->hasFile(QString("preview.png"))) { thumbnailpath = QString("preview.png"); } if (!thumbnailpath.isEmpty()) { if (store->open(thumbnailpath)) { QByteArray bytes = store->read(store->size()); store->close(); QImage img; img.loadFromData(bytes); img.setDevicePixelRatio(devicePixelRatioF()); recentItem->setIcon(QIcon(QPixmap::fromImage(img))); } } } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } else if (fi.suffix() == "tiff" || fi.suffix() == "tif") { // Workaround for a bug in Qt tiff QImageIO plugin QScopedPointer doc; doc.reset(KisPart::instance()->createDocument()); doc->setFileBatchMode(true); bool r = doc->openUrl(QUrl::fromLocalFile(recentFileUrlPath), KisDocument::DontAddToRecent); if (r) { KisPaintDeviceSP projection = doc->image()->projection(); recentItem->setIcon(QIcon(QPixmap::fromImage(projection->createThumbnail(48, 48, projection->exactBounds())))); } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } else { QImage img; img.setDevicePixelRatio(devicePixelRatioF()); img.load(recentFileUrlPath); if (!img.isNull()) { recentItem->setIcon(QIcon(QPixmap::fromImage(img.scaledToWidth(48)))); } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } if (brokenUrls.size() > 0 && brokenUrls.last().toLocalFile() != recentFileUrlPath) { m_thumbnailMap[recentFileUrlPath] = recentItem->icon(); } } } Q_FOREACH(const QUrl &url, brokenUrls) { m_mainWindow->removeRecentUrl(url); } // set the recent object with the data if (brokenUrls.isEmpty() || brokenUrls.last().toLocalFile() != recentFileUrlPath) { recentItem->setText(fileName); // what to display for the item recentItem->setToolTip(recentFileUrlPath); m_recentFilesModel.appendRow(recentItem); } } // hide clear and Recent files title if there are none bool hasRecentFiles = m_mainWindow->recentFilesUrls().length() > 0; recentDocumentsLabel->setVisible(hasRecentFiles); clearRecentFilesLink->setVisible(hasRecentFiles); recentDocumentsListView->setIconSize(QSize(48, 48)); recentDocumentsListView->setModel(&m_recentFilesModel); } void KisWelcomePageWidget::slotUpdateVersionMessage() { alertIcon->setIcon(KisIconUtils::loadIcon("warning")); alertIcon->setVisible(false); - // find out if we need an update...or if this is a development version - if (isDevelopmentBuild()) { + // find out if we need an update...or if this is a development version: + // dev builds contain GIT hash in it and the word git + // stable versions do not contain this. + if (qApp->applicationVersion().contains("git")) { // Development build QString versionLabelText = QString("") .append(i18n("DEV BUILD")).append(""); versionNotificationLabel->setText(versionLabelText); alertIcon->setVisible(true); versionNotificationLabel->setVisible(true); } else if (newsWidget->hasUpdateAvailable()) { // build URL for label QString versionLabelText = QString("versionLink() + "?" + analyticsString + "version-update" + "\">") .append(i18n("New Version Available!")).append(""); versionNotificationLabel->setVisible(true); versionNotificationLabel->setText(versionLabelText); alertIcon->setVisible(true); } else { // no message needed... exit versionNotificationLabel->setVisible(false); return; } if (!blendedStyle.isNull()) { versionNotificationLabel->setStyleSheet(blendedStyle); } } void KisWelcomePageWidget::dragEnterEvent(QDragEnterEvent *event) { //qDebug() << "dragEnterEvent formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(true); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dropEvent(QDropEvent *event) { //qDebug() << "KisWelcomePageWidget::dropEvent() formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(false); if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { if (url.toLocalFile().endsWith(".bundle")) { bool r = m_mainWindow->installBundle(url.toLocalFile()); if (!r) { qWarning() << "Could not install bundle" << url.toLocalFile(); } } else { m_mainWindow->openDocument(url, KisMainWindow::None); } } } } void KisWelcomePageWidget::dragMoveEvent(QDragMoveEvent *event) { //qDebug() << "dragMoveEvent"; m_mainWindow->dragMoveEvent(event); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dragLeaveEvent(QDragLeaveEvent */*event*/) { //qDebug() << "dragLeaveEvent"; showDropAreaIndicator(false); m_mainWindow->dragLeave(); } void KisWelcomePageWidget::recentDocumentClicked(QModelIndex index) { QString fileUrl = index.data(Qt::ToolTipRole).toString(); m_mainWindow->openDocument(QUrl::fromLocalFile(fileUrl), KisMainWindow::None ); } void KisWelcomePageWidget::slotNewFileClicked() { m_mainWindow->slotFileNew(); } void KisWelcomePageWidget::slotOpenFileClicked() { m_mainWindow->slotFileOpen(); } diff --git a/libs/ui/KisWelcomePageWidget.h b/libs/ui/KisWelcomePageWidget.h index 7756fcd5ae..51a4fafa62 100644 --- a/libs/ui/KisWelcomePageWidget.h +++ b/libs/ui/KisWelcomePageWidget.h @@ -1,95 +1,93 @@ /* This file is part of the KDE project * Copyright (C) 2018 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISWELCOMEPAGEWIDGET_H #define KISWELCOMEPAGEWIDGET_H #include "kritaui_export.h" #include "KisViewManager.h" #include "KisMainWindow.h" #include #include "ui_KisWelcomePage.h" #include /// A widget for displaying if no documents are open. This will display in the MDI area class KRITAUI_EXPORT KisWelcomePageWidget : public QWidget, public Ui::KisWelcomePage { Q_OBJECT public: explicit KisWelcomePageWidget(QWidget *parent); ~KisWelcomePageWidget() override; void setMainWindow(KisMainWindow* m_mainWindow); - bool isDevelopmentBuild(); - public Q_SLOTS: /// if a document is placed over this area, a dotted line will appear as an indicator /// that it is a droppable area. KisMainwindow is what triggers this void showDropAreaIndicator(bool show); void slotUpdateThemeColors(); /// this could be called multiple times. If a recent document doesn't /// have a preview, an icon is used that needs to be updated void populateRecentDocuments(); void slotUpdateVersionMessage(); protected: // QWidget overrides void dragEnterEvent(QDragEnterEvent * event) override; void dropEvent(QDropEvent * event) override; void dragMoveEvent(QDragMoveEvent * event) override; void dragLeaveEvent(QDragLeaveEvent * event) override; private: KisMainWindow *m_mainWindow; QStandardItemModel m_recentFilesModel; QMap m_thumbnailMap; /// help us see how many people are clicking startup screen links /// you can see the results in Matomo (stats.kde.org) /// this will be listed in the "Acquisition" section of Matomo /// just append some text to this to associate it with an event/page const QString analyticsString = "pk_campaign=startup-sceen&pk_kwd="; // keeping track of link colors with theme change QColor textColor; QColor backgroundColor; QColor blendedColor; QString blendedStyle; private Q_SLOTS: void slotNewFileClicked(); void slotOpenFileClicked(); void recentDocumentClicked(QModelIndex index); }; #endif // KISWELCOMEPAGEWIDGET_H diff --git a/libs/widgets/KoDialog.cpp b/libs/widgets/KoDialog.cpp index bca841903c..de98f3e7b3 100644 --- a/libs/widgets/KoDialog.cpp +++ b/libs/widgets/KoDialog.cpp @@ -1,1053 +1,957 @@ /* This file is part of the KDE Libraries * Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net) * Additions 1999-2000 by Espen Sand (espen@kde.org) * by Holger Freyther * 2005-2009 by Olivier Goffart (ogoffart at kde.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoDialog.h" #include "KoDialog_p.h" #include -#include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void KoDialogPrivate::setupLayout() { Q_Q(KoDialog); if (!dirty) { QMetaObject::invokeMethod(q, "queuedLayoutUpdate", Qt::QueuedConnection); dirty = true; } } void KoDialogPrivate::queuedLayoutUpdate() { if (!dirty) { return; } dirty = false; Q_Q(KoDialog); // Don't lose the focus widget when re-creating the layout. // Testcase: KOrganizer's "Select Categories" dialog QPointer focusWidget = mMainWidget ? mMainWidget->focusWidget() : 0; if (q->layout() && q->layout() != mTopLayout) { qWarning() << q->metaObject()->className() << "created with a layout; don't do that, KoDialog takes care of it, use mainWidget or setMainWidget instead"; delete q->layout(); } delete mTopLayout; if (mButtonOrientation == Qt::Horizontal) { mTopLayout = new QVBoxLayout(q); } else { mTopLayout = new QHBoxLayout(q); } if (mUrlHelp) { mTopLayout->addWidget(mUrlHelp, 0, Qt::AlignRight); } if (mMainWidget) { mTopLayout->addWidget(mMainWidget, 10); } if (mDetailsWidget) { mTopLayout->addWidget(mDetailsWidget); } if (mActionSeparator) { mTopLayout->addWidget(mActionSeparator); } if (mButtonBox) { mButtonBox->setOrientation(mButtonOrientation); mTopLayout->addWidget(mButtonBox); } if (focusWidget) { focusWidget->setFocus(); } } void KoDialogPrivate::appendButton(KoDialog::ButtonCode key, const KGuiItem &item) { Q_Q(KoDialog); QDialogButtonBox::ButtonRole role = QDialogButtonBox::InvalidRole; switch (key) { case KoDialog::Help: case KoDialog::Details: role = QDialogButtonBox::HelpRole; break; case KoDialog::Default: case KoDialog::Reset: role = QDialogButtonBox::ResetRole; break; case KoDialog::Ok: role = QDialogButtonBox::AcceptRole; break; case KoDialog::Apply: role = QDialogButtonBox::ApplyRole; break; case KoDialog::Try: case KoDialog::Yes: role = QDialogButtonBox::YesRole; break; case KoDialog::Close: case KoDialog::Cancel: role = QDialogButtonBox::RejectRole; break; case KoDialog::No: role = QDialogButtonBox::NoRole; break; case KoDialog::User1: case KoDialog::User2: case KoDialog::User3: role = QDialogButtonBox::ActionRole; break; default: role = QDialogButtonBox::InvalidRole; break; } if (role == QDialogButtonBox::InvalidRole) { return; } QPushButton *button = new QPushButton; KGuiItem::assign(button, item); mButtonBox->addButton(button, role); mButtonList.insert(key, button); QObject::connect(button, &QPushButton::clicked, [=] { q->slotButtonClicked(key); }); if (key == mDefaultButton) { // Now that it exists, set it as default q->setDefaultButton(mDefaultButton); } } void KoDialogPrivate::init(KoDialog *q) { q_ptr = q; dirty = false; q->setButtons(KoDialog::Ok | KoDialog::Cancel); q->setDefaultButton(KoDialog::Ok); q->setPlainCaption(qApp->applicationDisplayName()); // set appropriate initial window title for case it gets not set later } void KoDialogPrivate::helpLinkClicked() { q_ptr->slotButtonClicked(KoDialog::Help); } KoDialog::KoDialog(QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags) , d_ptr(new KoDialogPrivate) { d_ptr->init(this); } KoDialog::KoDialog(KoDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags) , d_ptr(&dd) { d_ptr->init(this); } KoDialog::~KoDialog() { delete d_ptr; } void KoDialog::setButtons(ButtonCodes buttonMask) { Q_D(KoDialog); if (d->mButtonBox) { d->mButtonList.clear(); delete d->mButtonBox; d->mButtonBox = 0; } if (buttonMask & Cancel) { buttonMask &= ~Close; } if (buttonMask & Apply) { buttonMask &= ~Try; } if (buttonMask & Details) { buttonMask &= ~Default; } if (buttonMask == None) { d->setupLayout(); return; // When we want no button box } d->mEscapeButton = (buttonMask & Cancel) ? Cancel : Close; d->mButtonBox = new QDialogButtonBox(this); if (buttonMask & Help) { d->appendButton(Help, KStandardGuiItem::help()); } if (buttonMask & Default) { d->appendButton(Default, KStandardGuiItem::defaults()); } if (buttonMask & Reset) { d->appendButton(Reset, KStandardGuiItem::reset()); } if (buttonMask & User3) { d->appendButton(User3, KGuiItem()); } if (buttonMask & User2) { d->appendButton(User2, KGuiItem()); } if (buttonMask & User1) { d->appendButton(User1, KGuiItem()); } if (buttonMask & Ok) { d->appendButton(Ok, KStandardGuiItem::ok()); } if (buttonMask & Apply) { d->appendButton(Apply, KStandardGuiItem::apply()); } if (buttonMask & Try) { d->appendButton(Try, KGuiItem(i18n("&Try"))); } if (buttonMask & Cancel) { d->appendButton(Cancel, KStandardGuiItem::cancel()); } if (buttonMask & Close) { d->appendButton(Close, KStandardGuiItem::close()); } if (buttonMask & Yes) { d->appendButton(Yes, KStandardGuiItem::yes()); } if (buttonMask & No) { d->appendButton(No, KStandardGuiItem::no()); } if (buttonMask & Details) { d->appendButton(Details, KGuiItem(QString(), "help-about")); setDetailsWidgetVisible(false); } d->setupLayout(); } void KoDialog::setButtonsOrientation(Qt::Orientation orientation) { Q_D(KoDialog); if (d->mButtonOrientation != orientation) { d->mButtonOrientation = orientation; if (d->mActionSeparator) { d->mActionSeparator->setOrientation(d->mButtonOrientation); } if (d->mButtonOrientation == Qt::Vertical) { enableLinkedHelp(false); // 2000-06-18 Espen: No support for this yet. } } } void KoDialog::setEscapeButton(ButtonCode id) { d_func()->mEscapeButton = id; } void KoDialog::setDefaultButton(ButtonCode newDefaultButton) { Q_D(KoDialog); if (newDefaultButton == None) { newDefaultButton = NoDefault; // #148969 } const KoDialog::ButtonCode oldDefault = defaultButton(); bool oldDefaultHadFocus = false; if (oldDefault != NoDefault) { QPushButton *old = button(oldDefault); if (old) { oldDefaultHadFocus = (focusWidget() == old); old->setDefault(false); } } if (newDefaultButton != NoDefault) { QPushButton *b = button(newDefaultButton); if (b) { b->setDefault(true); if (focusWidget() == 0 || oldDefaultHadFocus) { // No widget had focus yet, or the old default button had // -> ok to give focus to the new default button, so that it's // really default (Enter triggers it). // But we don't do this if the kdialog user gave focus to a // specific widget in the dialog. b->setFocus(); } } } d->mDefaultButton = newDefaultButton; Q_ASSERT(defaultButton() == newDefaultButton); } KoDialog::ButtonCode KoDialog::defaultButton() const { Q_D(const KoDialog); QHashIterator it(d->mButtonList); while (it.hasNext()) { it.next(); if (it.value()->isDefault()) { return (ButtonCode)it.key(); } } return d->mDefaultButton; } void KoDialog::setMainWidget(QWidget *widget) { Q_D(KoDialog); if (d->mMainWidget == widget) { return; } d->mMainWidget = widget; if (d->mMainWidget && d->mMainWidget->layout()) { // Avoid double-margin problem d->mMainWidget->layout()->setMargin(0); } d->setupLayout(); } QWidget *KoDialog::mainWidget() { Q_D(KoDialog); if (!d->mMainWidget) { setMainWidget(new QWidget(this)); } return d->mMainWidget; } QSize KoDialog::sizeHint() const { Q_D(const KoDialog); if (!d->mMinSize.isEmpty()) { return d->mMinSize.expandedTo(minimumSizeHint()) + d->mIncSize; } else { if (d->dirty) { const_cast(d)->queuedLayoutUpdate(); } return QDialog::sizeHint() + d->mIncSize; } } QSize KoDialog::minimumSizeHint() const { Q_D(const KoDialog); if (d->dirty) { const_cast(d)->queuedLayoutUpdate(); } return QDialog::minimumSizeHint() + d->mIncSize; } // // Grab QDialogs keypresses if non-modal. // void KoDialog::keyPressEvent(QKeyEvent *event) { Q_D(KoDialog); if (event->modifiers() == 0) { if (event->key() == Qt::Key_F1) { QPushButton *button = this->button(Help); if (button) { button->animateClick(); event->accept(); return; } } if (event->key() == Qt::Key_Escape) { QPushButton *button = this->button(d->mEscapeButton); if (button) { button->animateClick(); event->accept(); return; } } } else if (event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier) { QWhatsThis::enterWhatsThisMode(); event->accept(); return; } else if (event->modifiers() == Qt::ControlModifier && (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) { // accept the dialog when Ctrl-Return is pressed QPushButton *button = this->button(Ok); if (button) { button->animateClick(); event->accept(); return; } } QDialog::keyPressEvent(event); } int KoDialog::marginHint() { return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin); } int KoDialog::spacingHint() { return QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); } int KoDialog::groupSpacingHint() { return QApplication::fontMetrics().lineSpacing(); } QString KoDialog::makeStandardCaption(const QString &userCaption, QWidget *window, CaptionFlags flags) { Q_UNUSED(window); QString caption = qApp->applicationDisplayName(); QString captionString = userCaption.isEmpty() ? caption : userCaption; // If the document is modified, add '[modified]'. if (flags & ModifiedCaption) { captionString += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]"); } if (!userCaption.isEmpty()) { // Add the application name if: // User asked for it, it's not a duplication and the app name (caption()) is not empty if (flags & AppNameCaption && !caption.isEmpty() && !userCaption.endsWith(caption)) { // TODO: check to see if this is a transient/secondary window before trying to add the app name // on platforms that need this captionString += i18nc("Document/application separator in titlebar", " – ") + caption; } } return captionString; } void KoDialog::setCaption(const QString &_caption) { const QString caption = makeStandardCaption(_caption, this); setPlainCaption(caption); } void KoDialog::setCaption(const QString &caption, bool modified) { CaptionFlags flags = HIGCompliantCaption; // ### Qt5 TODO: port to [*], see QWidget::setWindowFilePath if (modified) { flags |= ModifiedCaption; } setPlainCaption(makeStandardCaption(caption, this, flags)); } void KoDialog::setPlainCaption(const QString &caption) { if (QWidget *win = window()) { win->setWindowTitle(caption); } } void KoDialog::resizeLayout(QWidget *widget, int margin, int spacing) //static { if (widget->layout()) { resizeLayout(widget->layout(), margin, spacing); } if (widget->children().count() > 0) { const QList list = widget->children(); foreach (QObject *object, list) { if (object->isWidgetType()) { resizeLayout((QWidget *)object, margin, spacing); } } } } void KoDialog::resizeLayout(QLayout *layout, int margin, int spacing) //static { QLayoutItem *child; int pos = 0; while ((child = layout->itemAt(pos))) { if (child->layout()) { resizeLayout(child->layout(), margin, spacing); } ++pos; } if (layout->layout()) { layout->layout()->setMargin(margin); layout->layout()->setSpacing(spacing); } } -static QRect screenRect(QWidget *widget, int screen) -{ - QDesktopWidget *desktop = QApplication::desktop(); - KConfig gc("kdeglobals", KConfig::NoGlobals); - auto screens = QGuiApplication::screens(); - KConfigGroup cg(&gc, "Windows"); - if (QApplication::primaryScreen()->virtualSiblings().count() && - cg.readEntry("XineramaEnabled", true) && - cg.readEntry("XineramaPlacementEnabled", true)) { - - if (screen < 0 || screen >= screens.count()) { - if (screen == -1) { - return QGuiApplication::primaryScreen()->availableVirtualGeometry(); - } else if (screen == -3) { - return QGuiApplication::screenAt(QCursor::pos())->availableVirtualGeometry(); - } else { - screen = desktop->screenNumber(widget); - } - } - - return QGuiApplication::screens().at(screen)->availableVirtualGeometry(); - } else { - return desktop->geometry(); - } -} - -void KoDialog::centerOnScreen(QWidget *widget, int screen) -{ - if (!widget) { - return; - } - - QRect rect = screenRect(widget, screen); - - widget->move(rect.center().x() - widget->width() / 2, - rect.center().y() - widget->height() / 2); -} - -bool KoDialog::avoidArea(QWidget *widget, const QRect &area, int screen) -{ - if (!widget) { - return false; - } - - QRect fg = widget->frameGeometry(); - if (!fg.intersects(area)) { - return true; // nothing to do. - } - - const QRect scr = screenRect(widget, screen); - QRect avoid(area); // let's add some margin - avoid.translate(-5, -5); - avoid.setRight(avoid.right() + 10); - avoid.setBottom(avoid.bottom() + 10); - - if (qMax(fg.top(), avoid.top()) <= qMin(fg.bottom(), avoid.bottom())) { - // We need to move the widget up or down - int spaceAbove = qMax(0, avoid.top() - scr.top()); - int spaceBelow = qMax(0, scr.bottom() - avoid.bottom()); - if (spaceAbove > spaceBelow) // where's the biggest side? - if (fg.height() <= spaceAbove) { // big enough? - fg.setY(avoid.top() - fg.height()); - } else { - return false; - } - else if (fg.height() <= spaceBelow) { // big enough? - fg.setY(avoid.bottom()); - } else { - return false; - } - } - - if (qMax(fg.left(), avoid.left()) <= qMin(fg.right(), avoid.right())) { - // We need to move the widget left or right - const int spaceLeft = qMax(0, avoid.left() - scr.left()); - const int spaceRight = qMax(0, scr.right() - avoid.right()); - if (spaceLeft > spaceRight) // where's the biggest side? - if (fg.width() <= spaceLeft) { // big enough? - fg.setX(avoid.left() - fg.width()); - } else { - return false; - } - else if (fg.width() <= spaceRight) { // big enough? - fg.setX(avoid.right()); - } else { - return false; - } - } - - widget->move(fg.x(), fg.y()); - - return true; -} - void KoDialog::showButtonSeparator(bool state) { Q_D(KoDialog); if ((d->mActionSeparator != 0) == state) { return; } if (state) { if (d->mActionSeparator) { return; } d->mActionSeparator = new KSeparator(this); d->mActionSeparator->setOrientation(d->mButtonOrientation); } else { delete d->mActionSeparator; d->mActionSeparator = 0; } d->setupLayout(); } void KoDialog::setInitialSize(const QSize &size) { d_func()->mMinSize = size; adjustSize(); } void KoDialog::incrementInitialSize(const QSize &size) { d_func()->mIncSize = size; adjustSize(); } QPushButton *KoDialog::button(ButtonCode id) const { Q_D(const KoDialog); return d->mButtonList.value(id, 0); } void KoDialog::enableButton(ButtonCode id, bool state) { QPushButton *button = this->button(id); if (button) { button->setEnabled(state); } } bool KoDialog::isButtonEnabled(ButtonCode id) const { QPushButton *button = this->button(id); if (button) { return button->isEnabled(); } return false; } void KoDialog::enableButtonOk(bool state) { enableButton(Ok, state); } void KoDialog::enableButtonApply(bool state) { enableButton(Apply, state); } void KoDialog::enableButtonCancel(bool state) { enableButton(Cancel, state); } void KoDialog::showButton(ButtonCode id, bool state) { QPushButton *button = this->button(id); if (button) { state ? button->show() : button->hide(); } } void KoDialog::setButtonGuiItem(ButtonCode id, const KGuiItem &item) { QPushButton *button = this->button(id); if (!button) { return; } KGuiItem::assign(button, item); } void KoDialog::setButtonText(ButtonCode id, const QString &text) { Q_D(KoDialog); if (!d->mSettingDetails && (id == Details)) { d->mDetailsButtonText = text; setDetailsWidgetVisible(d->mDetailsVisible); return; } QPushButton *button = this->button(id); if (button) { button->setText(text); } } QString KoDialog::buttonText(ButtonCode id) const { QPushButton *button = this->button(id); if (button) { return button->text(); } else { return QString(); } } void KoDialog::setButtonIcon(ButtonCode id, const QIcon &icon) { QPushButton *button = this->button(id); if (button) { button->setIcon(icon); } } QIcon KoDialog::buttonIcon(ButtonCode id) const { QPushButton *button = this->button(id); if (button) { return button->icon(); } else { return QIcon(); } } void KoDialog::setButtonToolTip(ButtonCode id, const QString &text) { QPushButton *button = this->button(id); if (button) { if (text.isEmpty()) { button->setToolTip(QString()); } else { button->setToolTip(text); } } } QString KoDialog::buttonToolTip(ButtonCode id) const { QPushButton *button = this->button(id); if (button) { return button->toolTip(); } else { return QString(); } } void KoDialog::setButtonWhatsThis(ButtonCode id, const QString &text) { QPushButton *button = this->button(id); if (button) { if (text.isEmpty()) { button->setWhatsThis(QString()); } else { button->setWhatsThis(text); } } } QString KoDialog::buttonWhatsThis(ButtonCode id) const { QPushButton *button = this->button(id); if (button) { return button->whatsThis(); } else { return QString(); } } void KoDialog::setButtonFocus(ButtonCode id) { QPushButton *button = this->button(id); if (button) { button->setFocus(); } } void KoDialog::setDetailsWidget(QWidget *detailsWidget) { Q_D(KoDialog); if (d->mDetailsWidget == detailsWidget) { return; } delete d->mDetailsWidget; d->mDetailsWidget = detailsWidget; if (d->mDetailsWidget->parentWidget() != this) { d->mDetailsWidget->setParent(this); } d->mDetailsWidget->hide(); d->setupLayout(); if (!d->mSettingDetails) { setDetailsWidgetVisible(d->mDetailsVisible); } } bool KoDialog::isDetailsWidgetVisible() const { return d_func()->mDetailsVisible; } void KoDialog::setDetailsWidgetVisible(bool visible) { Q_D(KoDialog); if (d->mDetailsButtonText.isEmpty()) { d->mDetailsButtonText = i18n("&Details"); } d->mSettingDetails = true; d->mDetailsVisible = visible; if (d->mDetailsVisible) { emit aboutToShowDetails(); setButtonText(Details, d->mDetailsButtonText + " <<"); if (d->mDetailsWidget) { if (layout()) { layout()->setEnabled(false); } d->mDetailsWidget->show(); adjustSize(); if (layout()) { layout()->activate(); layout()->setEnabled(true); } } } else { setButtonText(Details, d->mDetailsButtonText + " >>"); if (d->mDetailsWidget) { d->mDetailsWidget->hide(); } if (layout()) { layout()->activate(); adjustSize(); } } d->mSettingDetails = false; } void KoDialog::delayedDestruct() { if (isVisible()) { hide(); } deleteLater(); } void KoDialog::slotButtonClicked(int button) { Q_D(KoDialog); emit buttonClicked(static_cast(button)); switch (button) { case Ok: emit okClicked(); accept(); break; case Apply: emit applyClicked(); break; case Try: emit tryClicked(); break; case User3: emit user3Clicked(); break; case User2: emit user2Clicked(); break; case User1: emit user1Clicked(); break; case Yes: emit yesClicked(); done(Yes); break; case No: emit noClicked(); done(No); break; case Cancel: emit cancelClicked(); reject(); break; case Close: emit closeClicked(); done(Close); // KDE5: call reject() instead; more QDialog-like. break; case Help: emit helpClicked(); if (!d->mAnchor.isEmpty() || !d->mHelpApp.isEmpty()) { KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp); } break; case Default: emit defaultClicked(); break; case Reset: emit resetClicked(); break; case Details: setDetailsWidgetVisible(!d->mDetailsVisible); break; } // If we're here from the closeEvent, and auto-delete is on, well, auto-delete now. if (d->mDeferredDelete) { d->mDeferredDelete = false; delayedDestruct(); } } void KoDialog::enableLinkedHelp(bool state) { Q_D(KoDialog); if ((d->mUrlHelp != 0) == state) { return; } if (state) { if (d->mUrlHelp) { return; } d->mUrlHelp = new KUrlLabel(this); d->mUrlHelp->setText(helpLinkText()); d->mUrlHelp->setFloatEnabled(true); d->mUrlHelp->setUnderline(true); d->mUrlHelp->setMinimumHeight(fontMetrics().height() + marginHint()); connect(d->mUrlHelp, SIGNAL(leftClickedUrl()), SLOT(helpLinkClicked())); d->mUrlHelp->show(); } else { delete d->mUrlHelp; d->mUrlHelp = 0; } d->setupLayout(); } void KoDialog::setHelp(const QString &anchor, const QString &appname) { Q_D(KoDialog); d->mAnchor = anchor; d->mHelpApp = appname; } void KoDialog::setHelpLinkText(const QString &text) { Q_D(KoDialog); d->mHelpLinkText = text; if (d->mUrlHelp) { d->mUrlHelp->setText(helpLinkText()); } } QString KoDialog::helpLinkText() const { Q_D(const KoDialog); return (d->mHelpLinkText.isEmpty() ? i18n("Get help...") : d->mHelpLinkText); } void KoDialog::updateGeometry() { } void KoDialog::hideEvent(QHideEvent *event) { emit hidden(); if (!event->spontaneous()) { emit finished(); } } void KoDialog::closeEvent(QCloseEvent *event) { Q_D(KoDialog); QPushButton *button = this->button(d->mEscapeButton); if (button && !isHidden()) { button->animateClick(); if (testAttribute(Qt::WA_DeleteOnClose)) { // Don't let QWidget::close do a deferred delete just yet, wait for the click first d->mDeferredDelete = true; setAttribute(Qt::WA_DeleteOnClose, false); } } else { QDialog::closeEvent(event); } } #include "moc_KoDialog.cpp" diff --git a/libs/widgets/KoDialog.h b/libs/widgets/KoDialog.h index 315b0a970e..9bac7e5043 100644 --- a/libs/widgets/KoDialog.h +++ b/libs/widgets/KoDialog.h @@ -1,836 +1,815 @@ /* This file is part of the KDE Librariesfsignals * Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net) * Additions 1999-2000 by Espen Sand (espen@kde.org) * and Holger Freyther * 2005-2009 Olivier Goffart * 2006 Tobias Koenig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KODIALOG_H #define KODIALOG_H class QPushButton; class QMenu; class KoDialogPrivate; #include #include #include #include /** * @short A dialog base class with standard buttons and predefined layouts. * * Provides basic functionality needed by nearly all dialogs. * * It offers the standard action buttons you'd expect to find in a * dialog as well as the capability to define at most three configurable * buttons. You can define a main widget that contains your specific * dialog layout * * The class takes care of the geometry management. You only need to define * a minimum size for the widget you want to use as the main widget. * * By default, the dialog is non-modal. * * Standard buttons (action buttons):\n * * You select which buttons should be displayed, but you do not choose the * order in which they are displayed. This ensures a standard interface in * KDE. The button order can be changed, but this ability is only available * for a central KDE control tool. The following buttons are available: * OK, Cancel/Close, Apply/Try, Default, Help and three user definable * buttons: User1, User2 and User3. You must specify the text of the UserN * buttons. Each button emit a signal, so you can choose to connect that signal. * * The default action of the Help button will open the help system if you have * provided a path to the help text. * The default action of Ok and Cancel will run QDialog::accept() and QDialog::reject(), * which you can override by reimplementing slotButtonClicked(). The default * action of the Close button will close the dialog. * * Note that the KoDialog will animate a button press * when the user presses Escape. The button that is enabled is either Cancel, * Close or the button that is defined by setEscapeButton(). * Your custom dialog code should reimplement the keyPressEvent and * animate the cancel button so that the dialog behaves like regular * dialogs. * * Layout:\n * * The dialog consists of a help area on top (becomes visible if you define * a help path and use enableLinkedHelp()), the main area which is * the built-in dialog face or your own widget in the middle and by default * a button box at the bottom. The button box can also be placed at the * right edge (to the right of the main widget). Use * setButtonsOrientation() to control this behavior. A separator * can be placed above the button box (or to the left when the button box * is at the right edge). * * Standard compliance:\n * * The marginHint() and spacingHint() sizes shall be used * whenever you lay out the interior of a dialog. One special note. If * you make your own action buttons (OK, Cancel etc), the space * between the buttons shall be spacingHint(), whereas the space * above, below, to the right and to the left shall be marginHint(). * If you add a separator line above the buttons, there shall be a * marginHint() between the buttons and the separator and a * marginHint() above the separator as well. * * Example:\n * * \code * KoDialog *dialog = new KoDialog( this ); * dialog->setCaption( "My title" ); * dialog->setButtons( KoDialog::Ok | KoDialog::Cancel | KoDialog::Apply ); * * FooWidget *widget = new FooWidget( dialog ); * dialog->setMainWidget( widget ); * connect( dialog, SIGNAL( applyClicked() ), widget, SLOT( save() ) ); * connect( dialog, SIGNAL( okClicked() ), widget, SLOT( save() ) ); * connect( widget, SIGNAL( changed( bool ) ), dialog, SLOT( enableButtonApply( bool ) ) ); * * dialog->enableButtonApply( false ); * dialog->show(); * \endcode * * \image html kdialog.png "KDE Dialog example" * * This class can be used in many ways. Note that most KDE ui widgets * and many of KDE core applications use the KoDialog so for more * inspiration you should study the code for these. * * * @see KPageDialog * @author Thomas Tanghus * @author Espen Sand * @author Mirko Boehm * @author Olivier Goffart * @author Tobias Koenig */ class KRITAWIDGETS_EXPORT KoDialog : public QDialog //krazy:exclude=qclasses { Q_OBJECT Q_ENUMS(ButtonCode) Q_DECLARE_PRIVATE(KoDialog) public: enum ButtonCode { None = 0x00000000, Help = 0x00000001, ///< Show Help button. (this button will run the help set with setHelp) Default = 0x00000002, ///< Show Default button. Ok = 0x00000004, ///< Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted) Apply = 0x00000008, ///< Show Apply button. Try = 0x00000010, ///< Show Try button. Cancel = 0x00000020, ///< Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected) Close = 0x00000040, ///< Show Close-button. (this button closes the dialog) No = 0x00000080, ///< Show No button. (this button closes the dialog and sets the result to KoDialog::No) Yes = 0x00000100, ///< Show Yes button. (this button closes the dialog and sets the result to KoDialog::Yes) Reset = 0x00000200, ///< Show Reset button Details = 0x00000400, ///< Show Details button. (this button will show the detail widget set with setDetailsWidget) User1 = 0x00001000, ///< Show User defined button 1. User2 = 0x00002000, ///< Show User defined button 2. User3 = 0x00004000, ///< Show User defined button 3. NoDefault = 0x00008000 ///< Used when specifying a default button; indicates that no button should be marked by default. }; // TODO KDE5: remove NoDefault and use the value None instead Q_DECLARE_FLAGS(ButtonCodes, ButtonCode) enum ButtonPopupMode { InstantPopup = 0, DelayedPopup = 1 }; Q_DECLARE_FLAGS(ButtonPopupModes, ButtonPopupMode) public: /** * Creates a dialog. * * @param parent The parent of the dialog. * @param flags The widget flags passed to the QDialog constructor */ explicit KoDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0); /** * Destroys the dialog. */ ~KoDialog() override; /** * Creates (or recreates) the button box and all the buttons in it. * * Note that some combinations are not possible. That means, you can't * have the following pairs of buttons in a dialog: * - Default and Details * - Cancel and Close * - Ok and Try * * This will reset all default KGuiItem of all button. * * @param buttonMask Specifies what buttons will be made. * * @deprecated Since 5.0 use QDialogButtonBox */ void setButtons(ButtonCodes buttonMask); /** * Sets the orientation of the button box. * * It can be @p Vertical or @p Horizontal. If @p Horizontal * (default), the button box is positioned at the bottom of the * dialog. If @p Vertical it will be placed at the right edge of the * dialog. * * @param orientation The button box orientation. */ void setButtonsOrientation(Qt::Orientation orientation); /** * Sets the button that will be activated when the Escape key * is pressed. * * By default, the Escape key is mapped to either the Cancel or the Close button * if one of these buttons are defined. The user expects that Escape will * cancel an operation so use this function with caution. * * @param id The button code. */ void setEscapeButton(ButtonCode id); /** * Sets the button that will be activated when the Enter key * is pressed. * * By default, this is the Ok button if it is present * * @param id The button code. */ void setDefaultButton(ButtonCode id); /** * Returns the button code of the default button, * or NoDefault if there is no default button. */ ButtonCode defaultButton() const; /** * Hide or display the a separator line drawn between the action * buttons an the main widget. */ void showButtonSeparator(bool state); /** * Hide or display a general action button. * * Only buttons that have * been created in the constructor can be displayed. This method will * not create a new button. * * @param id Button identifier. * @param state true display the button(s). */ void showButton(ButtonCode id, bool state); /** * Sets the text of any button. * * @param id The button identifier. * @param text Button text. */ void setButtonText(ButtonCode id, const QString &text); /** * Returns the text of any button. */ QString buttonText(ButtonCode id) const; /** * Sets the icon of any button. * * @param id The button identifier. * @param icon Button icon. */ void setButtonIcon(ButtonCode id, const QIcon &icon); /** * Returns the icon of any button. */ QIcon buttonIcon(ButtonCode id) const; /** * Sets the tooltip text of any button. * * @param id The button identifier. * @param text Button text. */ void setButtonToolTip(ButtonCode id, const QString &text); /** * Returns the tooltip of any button. */ QString buttonToolTip(ButtonCode id) const; /** * Sets the "What's this?" text of any button. * * @param id The button identifier. * @param text Button text. */ void setButtonWhatsThis(ButtonCode id, const QString &text); /** * Returns the "What's this?" text of any button. */ QString buttonWhatsThis(ButtonCode id) const; /** * Sets the KGuiItem directly for the button instead of using 3 methods to * set the text, tooltip and whatsthis strings. This also allows to set an * icon for the button which is otherwise not possible for the extra * buttons beside Ok, Cancel and Apply. * * @param id The button identifier. * @param item The KGuiItem for the button. */ void setButtonGuiItem(ButtonCode id, const KGuiItem &item); /** * Sets the focus to the button of the passed @p id. */ void setButtonFocus(ButtonCode id); /** * Convenience method. Sets the initial dialog size. * * This method should only be called right before show() or exec(). * The initial size will be ignored if smaller than * the dialog's minimum size. * * @param size Startup size. */ void setInitialSize(const QSize &size); /** * Convenience method. Add a size to the default minimum size of a * dialog. * * This method should only be called right before show() or exec(). * * @param size Size added to minimum size. */ void incrementInitialSize(const QSize &size); /** * Returns the help link text. * * If no text has been defined, * "Get help..." (internationalized) is returned. * * @return The help link text. * * @see enableLinkedHelp() * @see setHelpLinkText() * @see setHelp() */ QString helpLinkText() const; /** * Returns whether any button is enabled. */ bool isButtonEnabled(ButtonCode id) const; /** * Returns the button that corresponds to the @p id. * * Normally you should not use this function. * @em Never delete the object returned by this function. * See also enableButton(), showButton(), setButtonGuiItem(). * * @param id Identifier of the button. * @return The button or 0 if the button does not exist. */ QPushButton *button(ButtonCode id) const; /** * Returns the number of pixels that should be used between a * dialog edge and the outermost widget(s) according to the KDE standard. * * @deprecated Use the style's pixelMetric() function to query individual margins. * Different platforms may use different values for the four margins. */ static int marginHint(); /** * Returns the number of pixels that should be used between * widgets inside a dialog according to the KDE standard. * * @deprecated Use the style's layoutSpacing() function to query individual spacings. * Different platforms may use different values depending on widget types and pairs. */ static int spacingHint(); /** * Returns the number of pixels that should be used to visually * separate groups of related options in a dialog according to * the KDE standard. * @since 4.2 */ static int groupSpacingHint(); /** * @enum CaptionFlag * Used to specify how to construct a window caption * * @var NoCaptionFlags Indicates that the method has no caption flags. * @var AppNameCaption Indicates that the method shall include * the application name when making the caption string. * @var ModifiedCaption Causes a 'modified' sign will be included in the * returned string. This is useful when indicating that a file is * modified, i.e., it contains data that has not been saved. * @var HIGCompliantCaption The base minimum flags required to align a * caption with the KDE Human Interface Guidelines */ enum CaptionFlag { NoCaptionFlags = 0, AppNameCaption = 1, ModifiedCaption = 2, HIGCompliantCaption = AppNameCaption }; Q_DECLARE_FLAGS(CaptionFlags, CaptionFlag) /** * Builds a caption that contains the application name along with the * userCaption using a standard layout. * * To make a compliant caption for your window, simply do: * @p setWindowTitle(KoDialog::makeStandardCaption(yourCaption)); * * To ensure that the caption is appropriate to the desktop in which the * application is running, pass in a pointer to the window the caption will * be applied to. * * If using a KoDialog or KMainWindow subclass, call setCaption instead and * an appropriate standard caption will be created for you * * @param userCaption The caption string you want to display in the * window caption area. Do not include the application name! * @param window a pointer to the window this application will apply to * @param flags * @return the created caption */ static QString makeStandardCaption(const QString &userCaption, QWidget *window = 0, CaptionFlags flags = HIGCompliantCaption); /** * Resize every layout manager used in @p widget and its nested children. * * @param widget The widget used. * @param margin The new layout margin. * @param spacing The new layout spacing. * * @deprecated Use QLayout functions where necessary. Setting margin and spacing * values recursively for all children prevents QLayout from creating platform native * layouts. */ static void resizeLayout(QWidget *widget, int margin, int spacing); /** * Resize every layout associated with @p lay and its children. * * @param lay layout to be resized * @param margin The new layout margin * @param spacing The new layout spacing * * @deprecated Use QLayout functions where necessary. Setting margin and spacing * values recursively for all children prevents QLayout from creating platform native * layouts. */ static void resizeLayout(QLayout *lay, int margin, int spacing); - /** - * Centers @p widget on the desktop, taking multi-head setups into - * account. If @p screen is -1, @p widget will be centered on its - * current screen (if it was shown already) or on the primary screen. - * If @p screen is -3, @p widget will be centered on the screen that - * currently contains the mouse pointer. - * @p screen will be ignored if a merged display (like Xinerama) is not - * in use, or merged display placement is not enabled in kdeglobals. - */ - static void centerOnScreen(QWidget *widget, int screen = -1); - - /** - * Places @p widget so that it doesn't cover a certain @p area of the screen. - * This is typically used by the "find dialog" so that the match it finds can - * be read. - * For @p screen, see centerOnScreen - * @return true on success (widget doesn't cover area anymore, or never did), - * false on failure (not enough space found) - */ - static bool avoidArea(QWidget *widget, const QRect &area, int screen = -1); - /** * Sets the main widget of the dialog. */ void setMainWidget(QWidget *widget); /** * @return The current main widget. Will create a QWidget as the mainWidget * if none was set before. This way you can write * \code * ui.setupUi(mainWidget()); * \endcode * when using designer. */ QWidget *mainWidget(); /** * Reimplemented from QDialog. */ QSize sizeHint() const override; /** * Reimplemented from QDialog. */ QSize minimumSizeHint() const override; public Q_SLOTS: /** * Make a KDE compliant caption. * * @param caption Your caption. Do @p not include the application name * in this string. It will be added automatically according to the KDE * standard. * * @deprecated Since 5.0 use QWidget::setWindowTitle */ virtual void setCaption(const QString &caption); /** * Makes a KDE compliant caption. * * @param caption Your caption. @em Do @em not include the application name * in this string. It will be added automatically according to the KDE * standard. * @param modified Specify whether the document is modified. This displays * an additional sign in the title bar, usually "**". * * @deprecated Since 5.0 use QWidget::setWindowTitle and QWidget::setWindowModified. */ virtual void setCaption(const QString &caption, bool modified); /** * Make a plain caption without any modifications. * * @param caption Your caption. This is the string that will be * displayed in the window title. */ virtual void setPlainCaption(const QString &caption); /** * Enable or disable (gray out) a general action button. * * @param id Button identifier. * @param state @p true enables the button(s). */ void enableButton(ButtonCode id, bool state); /** * Enable or disable (gray out) the OK button. * * @param state @p true enables the button. */ void enableButtonOk(bool state); /** * Enable or disable (gray out) the Apply button. * * @param state true enables the button. */ void enableButtonApply(bool state); /** * Enable or disable (gray out) the Cancel button. * * @param state true enables the button. */ void enableButtonCancel(bool state); /** * Display or hide the help link area on the top of the dialog. * * @param state @p true will display the area. * * @see helpLinkText() * @see setHelpLinkText() * @see setHelp() */ void enableLinkedHelp(bool state); /** * Sets the text that is shown as the linked text. * * If text is empty, * the text "Get help..." (internationalized) is used instead. * * @param text The link text. * * @see helpLinkText() * @see enableLinkedHelp() * @see setHelp() */ void setHelpLinkText(const QString &text); /** * Sets the help path and topic. * * @param anchor Defined anchor in your docbook sources * @param appname Defines the appname the help belongs to * If empty it's the current one * * @note The help button works differently for the class * KCMultiDialog, so it does not make sense to call this * function for Dialogs of that type. See * KCMultiDialog::slotHelp() for more information. */ void setHelp(const QString &anchor, const QString &appname = QString()); /** * Returns the status of the Details button. */ bool isDetailsWidgetVisible() const; /** * Sets the status of the Details button. */ void setDetailsWidgetVisible(bool visible); /** * Sets the widget that gets shown when "Details" is enabled. * * The dialog takes over ownership of the widget. * Any previously set widget gets deleted. */ void setDetailsWidget(QWidget *detailsWidget); /** * Destruct the dialog delayed. * * You can call this function from slots like closeClicked() and hidden(). * You should not use the dialog any more after calling this function. * @deprecated use hide()+deleteLater() */ void delayedDestruct(); Q_SIGNALS: /** * Emitted when the margin size and/or spacing size * have changed. * * Use marginHint() and spacingHint() in your slot * to get the new values. * * @deprecated This signal is not emitted. Listen to QEvent::StyleChange events instead. */ void layoutHintChanged(); /** * The Help button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void helpClicked(); /** * The Default button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void defaultClicked(); /** * The Reset button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void resetClicked(); /** * The User3 button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void user3Clicked(); /** * The User2 button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void user2Clicked(); /** * The User1 button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void user1Clicked(); /** * The Apply button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void applyClicked(); /** * The Try button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void tryClicked(); /** * The OK button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void okClicked(); /** * The Yes button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void yesClicked(); /** * The No button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void noClicked(); /** * The Cancel button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void cancelClicked(); /** * The Close button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void closeClicked(); /** * A button has been pressed. This signal is only emitted if * slotButtonClicked() is not replaced * @param button is the code of the pressed button. */ void buttonClicked(KoDialog::ButtonCode button); /** * The dialog is about to be hidden. * * A dialog is hidden after a user clicks a button that ends * the dialog or when the user switches to another desktop or * minimizes the dialog. */ void hidden(); /** * The dialog has finished. * * A dialog emits finished after a user clicks a button that ends * the dialog. * * This signal is also emitted when you call hide() * * If you have stored a pointer to the * dialog do @em not try to delete the pointer in the slot that is * connected to this signal. * * You should use deleteLater() instead. */ void finished(); /** * The detailsWidget is about to get shown. This is your last chance * to call setDetailsWidget if you haven't done so yet. */ void aboutToShowDetails(); protected: /** * Emits the #hidden signal. You can connect to that signal to * detect when a dialog has been closed. */ void hideEvent(QHideEvent *) override; /** * Detects when a dialog is being closed from the window manager * controls. If the Cancel or Close button is present then the button * is activated. Otherwise standard QDialog behavior * will take place. */ void closeEvent(QCloseEvent *e) override; /** * @internal */ void keyPressEvent(QKeyEvent *) override; protected Q_SLOTS: /** * Activated when the button @p button is clicked * * Sample that shows how to catch and handle button clicks within * an own dialog; * @code * class MyDialog : public KoDialog { * protected Q_SLOTS: * virtual void slotButtonClicked(int button) { * if (button == KoDialog::Ok) * accept(); * else * KoDialog::slotButtonClicked(button); * } * } * @endcode * * @param button is the type @a KoDialog::ButtonCode * * @deprecated since 5.0 use QDialogButtonBox and connect to the clicked signal */ virtual void slotButtonClicked(int button); /** * Updates the margins and spacings. * * @deprecated KoDialog respects the style's margins and spacings automatically. Calling * this function has no effect. */ void updateGeometry(); private: KoDialog(KoDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags = 0); KoDialogPrivate *const d_ptr; private: Q_DISABLE_COPY(KoDialog) Q_PRIVATE_SLOT(d_ptr, void queuedLayoutUpdate()) Q_PRIVATE_SLOT(d_ptr, void helpLinkClicked()) }; Q_DECLARE_OPERATORS_FOR_FLAGS(KoDialog::ButtonCodes) Q_DECLARE_OPERATORS_FOR_FLAGS(KoDialog::CaptionFlags) #endif // KODIALOG_H