diff --git a/language/codegen/basicrefactoring.cpp b/language/codegen/basicrefactoring.cpp --- a/language/codegen/basicrefactoring.cpp +++ b/language/codegen/basicrefactoring.cpp @@ -309,8 +309,7 @@ const auto text = renameDialog.edit->text().trimmed(); RefactoringProgressDialog refactoringProgress(i18n("Renaming \"%1\" to \"%2\"", declarationName, text), collector.data()); if (!collector->isReady()) { - refactoringProgress.exec(); - if (refactoringProgress.result() != QDialog::Accepted) { + if (refactoringProgress.exec() != QDialog::Accepted) { // krazy:exclude=crashy return {}; } } diff --git a/plugins/appwizard/appwizardplugin.cpp b/plugins/appwizard/appwizardplugin.cpp --- a/plugins/appwizard/appwizardplugin.cpp +++ b/plugins/appwizard/appwizardplugin.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -84,16 +85,16 @@ { model()->refresh(); - AppWizardDialog dlg(core()->pluginController(), m_templatesModel); + ScopedDialog dlg(core()->pluginController(), m_templatesModel); - if (dlg.exec() == QDialog::Accepted) + if (dlg->exec() == QDialog::Accepted) { - QString project = createProject( dlg.appInfo() ); + QString project = createProject( dlg->appInfo() ); if (!project.isEmpty()) { core()->projectController()->openProject(QUrl::fromLocalFile(project)); - KConfig templateConfig(dlg.appInfo().appTemplate); + KConfig templateConfig(dlg->appInfo().appTemplate); KConfigGroup general(&templateConfig, "General"); const QStringList fileArgs = general.readEntry("ShowFilesAfterGeneration").split(QLatin1Char(','), QString::SkipEmptyParts); for (const auto& fileArg : fileArgs) { diff --git a/plugins/appwizard/projectselectionpage.cpp b/plugins/appwizard/projectselectionpage.cpp --- a/plugins/appwizard/projectselectionpage.cpp +++ b/plugins/appwizard/projectselectionpage.cpp @@ -26,6 +26,7 @@ #include #include +#include #include "ui_projectselectionpage.h" #include "projecttemplatesmodel.h" @@ -305,15 +306,15 @@ QStringLiteral("application/x-bzip-compressed-tar"), QStringLiteral("application/zip") }; - QFileDialog fileDialog(this, i18n("Load Template From File")); - fileDialog.setMimeTypeFilters(supportedMimeTypes); - fileDialog.setFileMode(QFileDialog::ExistingFiles); + ScopedDialog fileDialog(this, i18n("Load Template From File")); + fileDialog->setMimeTypeFilters(supportedMimeTypes); + fileDialog->setFileMode(QFileDialog::ExistingFiles); - if (!fileDialog.exec()) { + if (!fileDialog->exec()) { return; } - for (const auto& fileName : fileDialog.selectedFiles()) { + for (const auto& fileName : fileDialog->selectedFiles()) { QString destination = m_templatesModel->loadTemplateFile(fileName); QModelIndexList indexes = m_templatesModel->templateIndexes(destination); if (indexes.size() > 2) @@ -326,10 +327,12 @@ void ProjectSelectionPage::moreTemplatesClicked() { - KNS3::DownloadDialog dialog(QStringLiteral("kdevappwizard.knsrc"), this); - dialog.exec(); + ScopedDialog dialog(QStringLiteral("kdevappwizard.knsrc"), this); - auto entries = dialog.changedEntries(); + if (!dialog->exec()) + return; + + auto entries = dialog->changedEntries(); if (entries.isEmpty()) { return; } diff --git a/plugins/externalscript/externalscriptview.cpp b/plugins/externalscript/externalscriptview.cpp --- a/plugins/externalscript/externalscriptview.cpp +++ b/plugins/externalscript/externalscriptview.cpp @@ -32,6 +32,8 @@ #include #include +#include + ExternalScriptView::ExternalScriptView( ExternalScriptPlugin* plugin, QWidget* parent ) : QWidget( parent ), m_plugin( plugin ) @@ -135,9 +137,8 @@ void ExternalScriptView::addScript() { ExternalScriptItem* item = new ExternalScriptItem; - EditExternalScript dlg( item, this ); - int ret = dlg.exec(); - if ( ret == QDialog::Accepted) { + KDevelop::ScopedDialog dlg( item, this ); + if ( dlg->exec() == QDialog::Accepted) { m_plugin->model()->appendRow( item ); } else { delete item; @@ -170,9 +171,8 @@ return; } - EditExternalScript dlg( item, this ); - int ret = dlg.exec(); - if (ret == QDialog::Accepted) { + KDevelop::ScopedDialog dlg( item, this ); + if (dlg->exec() == QDialog::Accepted) { item->save(); } } diff --git a/plugins/filetemplates/templateselectionpage.cpp b/plugins/filetemplates/templateselectionpage.cpp --- a/plugins/filetemplates/templateselectionpage.cpp +++ b/plugins/filetemplates/templateselectionpage.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "ui_templateselection.h" @@ -159,16 +160,16 @@ QStringLiteral("application/x-bzip-compressed-tar"), QStringLiteral("application/zip") }; - QFileDialog dlg(page); - dlg.setMimeTypeFilters(filters); - dlg.setFileMode(QFileDialog::ExistingFiles); + ScopedDialog dlg(page); + dlg->setMimeTypeFilters(filters); + dlg->setFileMode(QFileDialog::ExistingFiles); - if (!dlg.exec()) + if (!dlg->exec()) { return; } - foreach(const QString& fileName, dlg.selectedFiles()) + foreach(const QString& fileName, dlg->selectedFiles()) { QString destination = model->loadTemplateFile(fileName); QModelIndexList indexes = model->templateIndexes(destination); diff --git a/plugins/git/gitplugin.cpp b/plugins/git/gitplugin.cpp --- a/plugins/git/gitplugin.cpp +++ b/plugins/git/gitplugin.cpp @@ -516,7 +516,7 @@ if(!toadd.isEmpty()) { VcsJob* job = add(toadd); - job->exec(); + job->exec(); // krazy:exclude=crashy } } diff --git a/plugins/subversion/kdevsvnplugin.cpp b/plugins/subversion/kdevsvnplugin.cpp --- a/plugins/subversion/kdevsvnplugin.cpp +++ b/plugins/subversion/kdevsvnplugin.cpp @@ -404,7 +404,7 @@ dlg.urlRequester()->setMode(KFile::Directory | KFile::LocalOnly); } - if (dlg.exec() == QDialog::Accepted) { + if (dlg.exec() == QDialog::Accepted) { // krazy:exclude=crashy KDevelop::ICore::self()->runController()->registerJob(copy(source, dlg.selectedUrl())); } } else { @@ -440,7 +440,7 @@ dlg.urlRequester()->setMode(KFile::Directory | KFile::LocalOnly); } - if (dlg.exec() == QDialog::Accepted) { + if (dlg.exec() == QDialog::Accepted) { // krazy:exclude=crashy KDevelop::ICore::self()->runController()->registerJob(move(source, dlg.selectedUrl())); } } else { diff --git a/plugins/subversion/svnjobbase.cpp b/plugins/subversion/svnjobbase.cpp --- a/plugins/subversion/svnjobbase.cpp +++ b/plugins/subversion/svnjobbase.cpp @@ -68,11 +68,12 @@ qCDebug(PLUGIN_SVN) << "login"; KPasswordDialog dlg( nullptr, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword ); dlg.setPrompt( i18n("Enter Login for: %1", realm ) ); - dlg.exec(); - internalJob()->m_login_username = dlg.username(); - internalJob()->m_login_password = dlg.password(); - internalJob()->m_maySave = dlg.keepPassword(); - internalJob()->m_guiSemaphore.release( 1 ); + if (dlg.exec()) { // krazy:exclude=crashy + internalJob()->m_login_username = dlg.username(); + internalJob()->m_login_password = dlg.password(); + internalJob()->m_maySave = dlg.keepPassword(); + internalJob()->m_guiSemaphore.release( 1 ); + } } void SvnJobBase::showNotification( const QString& path, const QString& msg ) diff --git a/shell/documentcontroller.cpp b/shell/documentcontroller.cpp --- a/shell/documentcontroller.cpp +++ b/shell/documentcontroller.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include "core.h" @@ -813,9 +814,8 @@ QList checkSave = modifiedDocuments(list); if (!checkSave.isEmpty()) { - KSaveSelectDialog dialog(checkSave, qApp->activeWindow()); - if (dialog.exec() == QDialog::Rejected) - return false; + ScopedDialog dialog(checkSave, qApp->activeWindow()); + return dialog->exec(); } } diff --git a/shell/environmentconfigurebutton.cpp b/shell/environmentconfigurebutton.cpp --- a/shell/environmentconfigurebutton.cpp +++ b/shell/environmentconfigurebutton.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include namespace KDevelop { @@ -43,31 +45,31 @@ void showDialog() { - QDialog dlg(qApp->activeWindow()); + ScopedDialog dlg(qApp->activeWindow()); QString selected; if (selectionWidget) { selected = selectionWidget->effectiveProfileName(); } - EnvironmentPreferences prefs(selected, q); + auto prefs = new EnvironmentPreferences(selected, q); // TODO: This should be implicit when constructing EnvironmentPreferences - prefs.initConfigManager(); - prefs.reset(); + prefs->initConfigManager(); + prefs->reset(); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QObject::connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept); - QObject::connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); + QObject::connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject); auto layout = new QVBoxLayout; - layout->addWidget(&prefs); + layout->addWidget(prefs); layout->addWidget(buttonBox); - dlg.setLayout(layout); - dlg.setWindowTitle(prefs.fullName()); - dlg.setWindowIcon(prefs.icon()); - dlg.resize(800, 600); - if (dlg.exec() == QDialog::Accepted) { - prefs.apply(); + dlg->setLayout(layout); + dlg->setWindowTitle(prefs->fullName()); + dlg->setWindowIcon(prefs->icon()); + dlg->resize(800, 600); + if (dlg->exec() == QDialog::Accepted) { + prefs->apply(); emit q->environmentConfigured(); } } diff --git a/shell/loadedpluginsdialog.cpp b/shell/loadedpluginsdialog.cpp --- a/shell/loadedpluginsdialog.cpp +++ b/shell/loadedpluginsdialog.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include "core.h" #include "plugincontroller.h" @@ -240,8 +242,8 @@ if (p) { KAboutData aboutData = KAboutData::fromPluginMetaData(pluginInfo(p)); if (!aboutData.componentName().isEmpty()) { // Be sure the about data is not completely empty - KAboutApplicationDialog aboutPlugin(aboutData, itemView()); - aboutPlugin.exec(); + KDevelop::ScopedDialog aboutPlugin(aboutData, itemView()); + aboutPlugin->exec(); return; } } diff --git a/shell/mainwindow_actions.cpp b/shell/mainwindow_actions.cpp --- a/shell/mainwindow_actions.cpp +++ b/shell/mainwindow_actions.cpp @@ -40,6 +40,7 @@ #include "loadedpluginsdialog.h" #include +#include namespace KDevelop { @@ -206,14 +207,14 @@ void MainWindowPrivate::showAboutPlatform() { - KAboutApplicationDialog dlg(Core::self()->aboutData(), m_mainWindow ); - dlg.exec(); + ScopedDialog dlg(Core::self()->aboutData(), m_mainWindow ); + dlg->exec(); } void MainWindowPrivate::showLoadedPlugins() { - LoadedPluginsDialog dlg(m_mainWindow); - dlg.exec(); + ScopedDialog dlg(m_mainWindow); + dlg->exec(); } void MainWindowPrivate::contextMenuFileNew() diff --git a/shell/projectcontroller.cpp b/shell/projectcontroller.cpp --- a/shell/projectcontroller.cpp +++ b/shell/projectcontroller.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include #include #include +#include #include #include @@ -419,13 +421,15 @@ const QUrl& repoUrl, IPlugin* vcsOrProviderPlugin) { Q_ASSERT(d); - OpenProjectDialog dlg(fetch, startUrl, repoUrl, vcsOrProviderPlugin, Core::self()->uiController()->activeMainWindow()); - if(dlg.exec() == QDialog::Rejected) + ScopedDialog dlg(fetch, startUrl, repoUrl, vcsOrProviderPlugin, + Core::self()->uiController()->activeMainWindow()); + if(dlg->exec() == QDialog::Rejected) { return QUrl(); + } - QUrl projectFileUrl = dlg.projectFileUrl(); - qCDebug(SHELL) << "selected project:" << projectFileUrl << dlg.projectName() << dlg.projectManager(); - if ( dlg.projectManager() == QLatin1String("") ) { + QUrl projectFileUrl = dlg->projectFileUrl(); + qCDebug(SHELL) << "selected project:" << projectFileUrl << dlg->projectName() << dlg->projectManager(); + if ( dlg->projectManager() == QLatin1String("") ) { return projectFileUrl; } @@ -435,20 +439,20 @@ { // check whether config is equal bool shouldAsk = true; - if( projectFileUrl == dlg.selectedUrl() ) + if( projectFileUrl == dlg->selectedUrl() ) { if( projectFileUrl.isLocalFile() ) { - shouldAsk = !equalProjectFile( projectFileUrl.toLocalFile(), &dlg ); + shouldAsk = !equalProjectFile( projectFileUrl.toLocalFile(), dlg ); } else { shouldAsk = false; QTemporaryFile tmpFile; if (tmpFile.open()) { auto downloadJob = KIO::file_copy(projectFileUrl, QUrl::fromLocalFile(tmpFile.fileName())); KJobWidgets::setWindow(downloadJob, qApp->activeWindow()); if (downloadJob->exec()) { - shouldAsk = !equalProjectFile(tmpFile.fileName(), &dlg); + shouldAsk = !equalProjectFile(tmpFile.fileName(), dlg); } } } @@ -483,12 +487,13 @@ } if (writeProjectConfigToFile) { - if (!writeProjectSettingsToConfigFile(projectFileUrl, &dlg)) { + if (!writeProjectSettingsToConfigFile(projectFileUrl, dlg)) { KMessageBox::error(d->m_core->uiControllerInternal()->defaultMainWindow(), i18n("Unable to create configuration file %1", projectFileUrl.url())); return QUrl(); } } + return projectFileUrl; } @@ -785,10 +790,10 @@ } if ( ! existingSessions.isEmpty() ) { - QDialog dialog(Core::self()->uiControllerInternal()->activeMainWindow()); - dialog.setWindowTitle(i18n("Project Already Open")); + ScopedDialog dialog(Core::self()->uiControllerInternal()->activeMainWindow()); + dialog->setWindowTitle(i18n("Project Already Open")); - auto mainLayout = new QVBoxLayout(&dialog); + auto mainLayout = new QVBoxLayout(dialog); mainLayout->addWidget(new QLabel(i18n("The project you're trying to open is already open in at least one " "other session.
What do you want to do?"))); QGroupBox sessions; @@ -808,12 +813,11 @@ auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); mainLayout->addWidget(buttonBox); - bool success = dialog.exec(); - if (!success) + if (!dialog->exec()) return; foreach ( const QObject* obj, sessions.children() ) { @@ -1158,7 +1162,7 @@ bool ret = showVcsDiff(patchSource); if(!ret) { - VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource); + ScopedDialog commitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); } diff --git a/shell/sessioncontroller.cpp b/shell/sessioncontroller.cpp --- a/shell/sessioncontroller.cpp +++ b/shell/sessioncontroller.cpp @@ -614,7 +614,7 @@ ///@todo We need a way to get a proper size-hint from the view, but unfortunately, that only seems possible after the view was shown. dialog.resize(QSize(900, 600)); - if(dialog.exec() != QDialog::Accepted) + if(dialog.exec() != QDialog::Accepted) // krazy:exclude=crashy { return QString(); } diff --git a/shell/settings/environmentwidget.cpp b/shell/settings/environmentwidget.cpp --- a/shell/settings/environmentwidget.cpp +++ b/shell/settings/environmentwidget.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include #include "environmentprofilelistmodel.h" @@ -176,10 +178,10 @@ QString EnvironmentWidget::askNewProfileName(const QString& defaultName) { - QDialog dialog(this); - dialog.setWindowTitle(i18n("Enter Name of New Environment Profile")); + ScopedDialog dialog(this); + dialog->setWindowTitle(i18n("Enter Name of New Environment Profile")); - QVBoxLayout *layout = new QVBoxLayout(&dialog); + QVBoxLayout *layout = new QVBoxLayout(dialog); auto editLayout = new QHBoxLayout; @@ -193,11 +195,11 @@ auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(false); okButton->setDefault(true); - dialog.connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); - dialog.connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); layout->addWidget(buttonBox); - auto validator = new ProfileNameValidator(m_environmentProfileListModel, &dialog); + auto validator = new ProfileNameValidator(m_environmentProfileListModel, dialog); connect(edit, &QLineEdit::textChanged, validator, [validator, okButton](const QString& text) { int pos; QString t(text); @@ -208,7 +210,7 @@ edit->setText(defaultName); edit->selectAll(); - if (dialog.exec() != QDialog::Accepted) { + if (dialog->exec() != QDialog::Accepted) { return {}; } @@ -239,10 +241,10 @@ void EnvironmentWidget::batchModeEditButtonClicked() { - QDialog dialog(this); - dialog.setWindowTitle( i18n( "Batch Edit Mode" ) ); + ScopedDialog dialog(this); + dialog->setWindowTitle( i18n( "Batch Edit Mode" ) ); - QVBoxLayout *layout = new QVBoxLayout(&dialog); + QVBoxLayout *layout = new QVBoxLayout(dialog); auto edit = new QPlainTextEdit; edit->setPlaceholderText(QStringLiteral("VARIABLE1=VALUE1\nVARIABLE2=VALUE2")); @@ -259,13 +261,13 @@ auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - dialog.connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); - dialog.connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); layout->addWidget(buttonBox); - dialog.resize(600, 400); + dialog->resize(600, 400); - if ( dialog.exec() != QDialog::Accepted ) { + if ( dialog->exec() != QDialog::Accepted ) { return; } diff --git a/shell/settings/sourceformattersettings.cpp b/shell/settings/sourceformattersettings.cpp --- a/shell/settings/sourceformattersettings.cpp +++ b/shell/settings/sourceformattersettings.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "editstyledialog.h" #include "debug.h" @@ -401,10 +402,10 @@ QMimeType mimetype = l.mimetypes.first(); if( QScopedPointer(fmt->formatter->editStyleWidget( mimetype )) ) { - EditStyleDialog dlg( fmt->formatter, mimetype, *l.selectedStyle, this ); - if( dlg.exec() == QDialog::Accepted ) + KDevelop::ScopedDialog dlg(fmt->formatter, mimetype, *l.selectedStyle, this); + if( dlg->exec() == QDialog::Accepted ) { - l.selectedStyle->setContent(dlg.content()); + l.selectedStyle->setContent(dlg->content()); } updatePreview(); emit changed(); diff --git a/shell/settings/templatepage.cpp b/shell/settings/templatepage.cpp --- a/shell/settings/templatepage.cpp +++ b/shell/settings/templatepage.cpp @@ -22,6 +22,7 @@ #include "ui_templatepage.h" #include "qtcompat_p.h" +#include #include #include @@ -32,7 +33,7 @@ #include #include -#include +#include TemplatePage::TemplatePage (KDevelop::ITemplateProvider* provider, QWidget* parent) : QWidget (parent), m_provider(provider) @@ -70,35 +71,38 @@ void TemplatePage::loadFromFile() { - QFileDialog fileDialog(this); - fileDialog.setMimeTypeFilters(m_provider->supportedMimeTypes()); - fileDialog.setFileMode(QFileDialog::ExistingFiles); - if (!fileDialog.exec()) { + KDevelop::ScopedDialog fileDialog(this); + fileDialog->setMimeTypeFilters(m_provider->supportedMimeTypes()); + fileDialog->setFileMode(QFileDialog::ExistingFiles); + if (!fileDialog->exec()) { return; } - for (const auto& file : fileDialog.selectedFiles()) { + for (const auto& file : fileDialog->selectedFiles()) { m_provider->loadTemplate(file); } m_provider->reload(); } void TemplatePage::getMoreTemplates() { - KNS3::DownloadDialog dialog(m_provider->knsConfigurationFile(), this); - dialog.exec(); + KDevelop::ScopedDialog dialog(m_provider->knsConfigurationFile(), this); + + if (!dialog->exec()) { + return; + } - if (!dialog.changedEntries().isEmpty()) + if (!dialog->changedEntries().isEmpty()) { m_provider->reload(); } } void TemplatePage::shareTemplates() { - KNS3::UploadDialog dialog(m_provider->knsConfigurationFile(), this); - dialog.exec(); + KDevelop::ScopedDialog dialog(m_provider->knsConfigurationFile(), this); + dialog->exec(); } void TemplatePage::currentIndexChanged(const QModelIndex& index) diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp --- a/shell/uicontroller.cpp +++ b/shell/uicontroller.cpp @@ -36,6 +36,7 @@ #include #include +#include #include "core.h" #include "configpage.h" @@ -434,7 +435,7 @@ if (!mw || !mw->area()) return; - QDialog *dia = new QDialog(mw); + ScopedDialog dia(mw); dia->setWindowTitle(i18n("Select Tool View to Add")); auto mainLayout = new QVBoxLayout(dia); @@ -474,7 +475,6 @@ addNewToolView(mw, item); } } - delete dia; } void UiController::addNewToolView(MainWindow *mw, QListWidgetItem* item) diff --git a/util/dialogwrapper.h b/util/dialogwrapper.h new file mode 100644 --- /dev/null +++ b/util/dialogwrapper.h @@ -0,0 +1,86 @@ +/* This file is part of KDevelop + * + * Copyright 2017 Christoph Roick + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef KDEVPLATFORM_DIALOGWRAPPER_H +#define KDEVPLATFORM_DIALOGWRAPPER_H + +#include +#include "utilexport.h" + +namespace KDevelop { + +/** + * Wrapper class for QDialogs which should not be instantiated on stack. + * + * Parents of QDialogs may be unintentionally deleted during the execution of the + * dialog and automatically delete their children. When returning to the calling + * function they get intentionally deleted again, which will lead to a crash. This + * can be circumvented by using a QPointer which keeps track of the QDialogs validity. + * See this + * blog entry for explanation. The DialogWrapper utility allows using the dialog like a + * common pointer. + * + * Instead of + * \code + QFileDialog dlg(this); + if (dlg.exec()) + return; + \endcode + simply use + * \code + DialogWrapper dlg(this); + if (dlg->exec()) + return; + \endcode + without need to manually clean up afterwards. + */ +template +class KDEVPLATFORMUTIL_EXPORT DialogWrapper { + public: + /// Construct the dialog with any set of allowed arguments + /// for the construction of DialogType + template + explicit DialogWrapper(Arguments ... args) : ptr(new DialogType(args...)) { + } + /// Automatically deletes the dialog if it is still present + ~DialogWrapper() { + delete ptr; + } + + /// Access members of the dialog + DialogType* operator->() const { + return ptr; + } + /// Access the dialog + DialogType & operator*() const { + return *ptr; + } + /// Return the corresponding pointer + operator DialogType*() const { + return ptr; + } + + private: + QPointer ptr; +}; + +} + +#endif // KDEVPLATFORM_DIALOGWRAPPER_H diff --git a/util/scopeddialog.h b/util/scopeddialog.h new file mode 100644 --- /dev/null +++ b/util/scopeddialog.h @@ -0,0 +1,86 @@ +/* This file is part of KDevelop + * + * Copyright 2017 Christoph Roick + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef KDEVPLATFORM_SCOPEDDIALOG_H +#define KDEVPLATFORM_SCOPEDDIALOG_H + +#include + +namespace KDevelop { + +/** + * Wrapper class for QDialogs which should not be instantiated on stack. + * + * Parents of QDialogs may be unintentionally deleted during the execution of the + * dialog and automatically delete their children. When returning to the calling + * function they get intentionally deleted again, which will lead to a crash. This + * can be circumvented by using a QPointer which keeps track of the QDialogs validity. + * See this + * blog entry + * for explanation. The ScopedDialog utility allows using the dialog like a + * common pointer. + * + * Instead of + * \code + QFileDialog dlg(this); + if (dlg.exec()) + return; + \endcode + simply use + * \code + ScopedDialog dlg(this); + if (dlg->exec()) + return; + \endcode + without need to manually clean up afterwards. + */ +template +class ScopedDialog { + public: + /// Construct the dialog with any set of allowed arguments + /// for the construction of DialogType + template + explicit ScopedDialog(Arguments ... args) : ptr(new DialogType(args...)) { + } + /// Automatically deletes the dialog if it is still present + ~ScopedDialog() { + delete ptr; + } + + /// Access members of the dialog + DialogType* operator->() const { + return ptr; + } + /// Access the dialog + DialogType & operator*() const { + return *ptr; + } + /// Return the corresponding pointer + operator DialogType*() const { + return ptr; + } + + private: + QPointer ptr; +}; + +} + +#endif // KDEVPLATFORM_SCOPEDDIALOG_H diff --git a/vcs/dvcs/dvcsplugin.cpp b/vcs/dvcs/dvcsplugin.cpp --- a/vcs/dvcs/dvcsplugin.cpp +++ b/vcs/dvcs/dvcsplugin.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include "dvcsjob.h" #include "ui/dvcsimportmetadatawidget.h" @@ -128,9 +129,9 @@ ICore::self()->documentController()->saveAllDocuments(); - BranchManager branchManager(stripPathToDir(ctxUrlList.front().toLocalFile()), - this, core()->uiController()->activeMainWindow()); - branchManager.exec(); + ScopedDialog branchManager(stripPathToDir(ctxUrlList.front().toLocalFile()), + this, core()->uiController()->activeMainWindow()); + branchManager->exec(); } } diff --git a/vcs/vcspluginhelper.cpp b/vcs/vcspluginhelper.cpp --- a/vcs/vcspluginhelper.cpp +++ b/vcs/vcspluginhelper.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -457,7 +458,7 @@ bool ret = showVcsDiff(patchSource); if(!ret) { - VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource); + ScopedDialog commitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); }