Git commit 7cda7c95d5bfa93f34c5a52df17480c248a8367c by Christoph Roick. Committed on 30/06/2017 at 21:57. Pushed by croick into branch 'master'. Fix crashy dialogs (found by krazy and by hand) Summary: - use a wrapper class which simplifies the use of QPointer for the creation of local QDialogs - some false positives are marked - some dialogs not identified by krazy have the main window as parent, they may still cause a crash, when the program is killed Test Plan: Before: - open "About KDevelop Platform" dialog - "killall kdevelop" -> kdevelop closes (as intended), but with crash After: - open same dialog - "killall kdevelop" -> kdevelop silently quits Reviewers: #kdevelop, apol Reviewed By: #kdevelop, apol Subscribers: apol, anthonyfieroni, kdevelop-devel Differential Revision: https://phabricator.kde.org/D6308 M +1 -2 language/codegen/basicrefactoring.cpp M +5 -4 plugins/appwizard/appwizardplugin.cpp M +11 -8 plugins/appwizard/projectselectionpage.cpp M +6 -6 plugins/externalscript/externalscriptview.cpp M +4 -4 plugins/filetemplates/templateclassassistant.cpp M +6 -5 plugins/filetemplates/templateselectionpage.cpp M +1 -1 plugins/git/gitplugin.cpp M +2 -2 plugins/subversion/kdevsvnplugin.cpp M +6 -5 plugins/subversion/svnjobbase.cpp M +3 -3 shell/documentcontroller.cpp M +15 -13 shell/environmentconfigurebutton.cpp M +4 -2 shell/loadedpluginsdialog.cpp M +5 -4 shell/mainwindow_actions.cpp M +21 -17 shell/projectcontroller.cpp M +1 -1 shell/sessioncontroller.cpp M +16 -14 shell/settings/environmentwidget.cpp M +4 -3 shell/settings/sourceformattersettings.cpp M +15 -11 shell/settings/templatepage.cpp M +2 -2 shell/uicontroller.cpp A +86 -0 util/scopeddialog.h [License: GPL (v2+)] M +4 -3 vcs/dvcs/dvcsplugin.cpp M +2 -1 vcs/vcspluginhelper.cpp https://commits.kde.org/kdevplatform/7cda7c95d5bfa93f34c5a52df17480c248a836= 7c diff --git a/language/codegen/basicrefactoring.cpp b/language/codegen/basic= refactoring.cpp index f666b2444..68dc459e3 100644 --- a/language/codegen/basicrefactoring.cpp +++ b/language/codegen/basicrefactoring.cpp @@ -309,8 +309,7 @@ BasicRefactoring::NameAndCollector BasicRefactoring::ne= wNameForDeclaration(const const auto text =3D renameDialog.edit->text().trimmed(); RefactoringProgressDialog refactoringProgress(i18n("Renaming \"%1\" to= \"%2\"", declarationName, text), collector.data()); if (!collector->isReady()) { - refactoringProgress.exec(); - if (refactoringProgress.result() !=3D QDialog::Accepted) { + if (refactoringProgress.exec() !=3D QDialog::Accepted) { // krazy:= exclude=3Dcrashy return {}; } } diff --git a/plugins/appwizard/appwizardplugin.cpp b/plugins/appwizard/appw= izardplugin.cpp index f0e6eb107..50a5f82ce 100644 --- 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 @@ void AppWizardPlugin::slotNewProject() { model()->refresh(); = - AppWizardDialog dlg(core()->pluginController(), m_templatesModel); + ScopedDialog dlg(core()->pluginController(), m_templa= tesModel); = - if (dlg.exec() =3D=3D QDialog::Accepted) + if (dlg->exec() =3D=3D QDialog::Accepted) { - QString project =3D createProject( dlg.appInfo() ); + QString project =3D createProject( dlg->appInfo() ); if (!project.isEmpty()) { core()->projectController()->openProject(QUrl::fromLocalFile(p= roject)); = - KConfig templateConfig(dlg.appInfo().appTemplate); + KConfig templateConfig(dlg->appInfo().appTemplate); KConfigGroup general(&templateConfig, "General"); const QStringList fileArgs =3D general.readEntry("ShowFilesAft= erGeneration").split(QLatin1Char(','), QString::SkipEmptyParts); for (const auto& fileArg : fileArgs) { diff --git a/plugins/appwizard/projectselectionpage.cpp b/plugins/appwizard= /projectselectionpage.cpp index d7862e0ee..d4ec5e7cd 100644 --- 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 @@ void ProjectSelectionPage::loadFileClicked() 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 Fi= le")); + 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 =3D m_templatesModel->loadTemplateFile(fileNam= e); QModelIndexList indexes =3D m_templatesModel->templateIndexes(dest= ination); if (indexes.size() > 2) @@ -326,10 +327,12 @@ void ProjectSelectionPage::loadFileClicked() = void ProjectSelectionPage::moreTemplatesClicked() { - KNS3::DownloadDialog dialog(QStringLiteral("kdevappwizard.knsrc"), thi= s); - dialog.exec(); + ScopedDialog dialog(QStringLiteral("kdevappwizar= d.knsrc"), this); = - auto entries =3D dialog.changedEntries(); + if (!dialog->exec()) + return; + + auto entries =3D dialog->changedEntries(); if (entries.isEmpty()) { return; } diff --git a/plugins/externalscript/externalscriptview.cpp b/plugins/extern= alscript/externalscriptview.cpp index 22b78bf7e..ad34c4966 100644 --- a/plugins/externalscript/externalscriptview.cpp +++ b/plugins/externalscript/externalscriptview.cpp @@ -32,6 +32,8 @@ #include #include = +#include + = ExternalScriptView::ExternalScriptView( ExternalScriptPlugin* plugin, QWid= get* parent ) : QWidget( parent ), m_plugin( plugin ) @@ -135,9 +137,8 @@ bool ExternalScriptView::eventFilter( QObject* obj, QEv= ent* e ) void ExternalScriptView::addScript() { ExternalScriptItem* item =3D new ExternalScriptItem; - EditExternalScript dlg( item, this ); - int ret =3D dlg.exec(); - if ( ret =3D=3D QDialog::Accepted) { + KDevelop::ScopedDialog dlg( item, this ); + if ( dlg->exec() =3D=3D QDialog::Accepted) { m_plugin->model()->appendRow( item ); } else { delete item; @@ -170,9 +171,8 @@ void ExternalScriptView::editScript() return; } = - EditExternalScript dlg( item, this ); - int ret =3D dlg.exec(); - if (ret =3D=3D QDialog::Accepted) { + KDevelop::ScopedDialog dlg( item, this ); + if (dlg->exec() =3D=3D QDialog::Accepted) { item->save(); } } diff --git a/plugins/filetemplates/templateclassassistant.cpp b/plugins/fil= etemplates/templateclassassistant.cpp index b9cf29005..da4237b5e 100644 --- a/plugins/filetemplates/templateclassassistant.cpp +++ b/plugins/filetemplates/templateclassassistant.cpp @@ -45,12 +45,12 @@ #include #include #include +#include = #include #include #include #include -#include #include #include = @@ -198,7 +198,7 @@ void TemplateClassAssistantPrivate::addFilesToTarget (c= onst QHash< QString, QUrl else if (targets.size() > 1) { // More than one candidate target, show the chooser dialog - QPointer d =3D new QDialog; + ScopedDialog d; = auto mainLayout =3D new QVBoxLayout(d); mainLayout->addWidget(new QLabel(i18n("Choose one target to add th= e file or cancel if you do not want to do so."))); @@ -215,8 +215,8 @@ void TemplateClassAssistantPrivate::addFilesToTarget (c= onst QHash< QString, QUrl QPushButton *okButton =3D buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - d->connect(buttonBox, &QDialogButtonBox::accepted, d.data(), &QDia= log::accept); - d->connect(buttonBox, &QDialogButtonBox::rejected, d.data(), &QDia= log::reject); + d->connect(buttonBox, &QDialogButtonBox::accepted, d, &QDialog::ac= cept); + d->connect(buttonBox, &QDialogButtonBox::rejected, d, &QDialog::re= ject); mainLayout->addWidget(buttonBox); = if(d->exec() =3D=3D QDialog::Accepted) diff --git a/plugins/filetemplates/templateselectionpage.cpp b/plugins/file= templates/templateselectionpage.cpp index 7f731c4cd..ae728ed36 100644 --- 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 @@ void TemplateSelectionPagePrivate::loadFileClicked() 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 =3D model->loadTemplateFile(fileName); QModelIndexList indexes =3D model->templateIndexes(destination); diff --git a/plugins/git/gitplugin.cpp b/plugins/git/gitplugin.cpp index bc926bf51..f403d1ab9 100644 --- a/plugins/git/gitplugin.cpp +++ b/plugins/git/gitplugin.cpp @@ -516,7 +516,7 @@ void GitPlugin::addNotVersionedFiles(const QDir& dir, c= onst QList& files) = if(!toadd.isEmpty()) { VcsJob* job =3D add(toadd); - job->exec(); + job->exec(); // krazy:exclude=3Dcrashy } } = diff --git a/plugins/subversion/kdevsvnplugin.cpp b/plugins/subversion/kdev= svnplugin.cpp index e2016856d..d39674f39 100644 --- a/plugins/subversion/kdevsvnplugin.cpp +++ b/plugins/subversion/kdevsvnplugin.cpp @@ -404,7 +404,7 @@ void KDevSvnPlugin::ctxCopy() dlg.urlRequester()->setMode(KFile::Directory | KFile::LocalOnl= y); } = - if (dlg.exec() =3D=3D QDialog::Accepted) { + if (dlg.exec() =3D=3D QDialog::Accepted) { // krazy:exclude=3Dcras= hy KDevelop::ICore::self()->runController()->registerJob(copy(sou= rce, dlg.selectedUrl())); } } else { @@ -440,7 +440,7 @@ void KDevSvnPlugin::ctxMove() dlg.urlRequester()->setMode(KFile::Directory | KFile::LocalOnl= y); } = - if (dlg.exec() =3D=3D QDialog::Accepted) { + if (dlg.exec() =3D=3D QDialog::Accepted) { // krazy:exclude=3Dcras= hy KDevelop::ICore::self()->runController()->registerJob(move(sou= rce, dlg.selectedUrl())); } } else { diff --git a/plugins/subversion/svnjobbase.cpp b/plugins/subversion/svnjobb= ase.cpp index c04df5e6f..0b7e4eeea 100644 --- a/plugins/subversion/svnjobbase.cpp +++ b/plugins/subversion/svnjobbase.cpp @@ -68,11 +68,12 @@ void SvnJobBase::askForLogin( const QString& realm ) qCDebug(PLUGIN_SVN) << "login"; KPasswordDialog dlg( nullptr, KPasswordDialog::ShowUsernameLine | KPas= swordDialog::ShowKeepPassword ); dlg.setPrompt( i18n("Enter Login for: %1", realm ) ); - dlg.exec(); - internalJob()->m_login_username =3D dlg.username(); - internalJob()->m_login_password =3D dlg.password(); - internalJob()->m_maySave =3D dlg.keepPassword(); - internalJob()->m_guiSemaphore.release( 1 ); + if (dlg.exec()) { // krazy:exclude=3Dcrashy + internalJob()->m_login_username =3D dlg.username(); + internalJob()->m_login_password =3D dlg.password(); + internalJob()->m_maySave =3D 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 index e4d656fde..724a51499 100644 --- a/shell/documentcontroller.cpp +++ b/shell/documentcontroller.cpp @@ -54,6 +54,7 @@ Boston, MA 02110-1301, USA. #include #include #include +#include #include = #include "core.h" @@ -813,9 +814,8 @@ bool KDevelop::DocumentController::saveSomeDocuments(co= nst QList< IDocument * > QList checkSave =3D modifiedDocuments(list); = if (!checkSave.isEmpty()) { - KSaveSelectDialog dialog(checkSave, qApp->activeWindow()); - if (dialog.exec() =3D=3D QDialog::Rejected) - return false; + ScopedDialog dialog(checkSave, qApp->active= Window()); + return dialog->exec(); } } = diff --git a/shell/environmentconfigurebutton.cpp b/shell/environmentconfig= urebutton.cpp index f48287421..f7f7221d9 100644 --- a/shell/environmentconfigurebutton.cpp +++ b/shell/environmentconfigurebutton.cpp @@ -29,6 +29,8 @@ #include #include = +#include + #include = namespace KDevelop { @@ -43,31 +45,31 @@ public: = void showDialog() { - QDialog dlg(qApp->activeWindow()); + ScopedDialog dlg(qApp->activeWindow()); QString selected; if (selectionWidget) { selected =3D selectionWidget->effectiveProfileName(); } = - EnvironmentPreferences prefs(selected, q); + auto prefs =3D new EnvironmentPreferences(selected, q); = // TODO: This should be implicit when constructing EnvironmentPref= erences - prefs.initConfigManager(); - prefs.reset(); + prefs->initConfigManager(); + prefs->reset(); = auto buttonBox =3D new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QObject::connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QD= ialog::accept); - QObject::connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QD= ialog::reject); + QObject::connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDi= alog::accept); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDi= alog::reject); auto layout =3D 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() =3D=3D QDialog::Accepted) { - prefs.apply(); + dlg->setLayout(layout); + dlg->setWindowTitle(prefs->fullName()); + dlg->setWindowIcon(prefs->icon()); + dlg->resize(800, 600); + if (dlg->exec() =3D=3D QDialog::Accepted) { + prefs->apply(); emit q->environmentConfigured(); } } diff --git a/shell/loadedpluginsdialog.cpp b/shell/loadedpluginsdialog.cpp index ed13541e4..3b5916c8a 100644 --- 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 @@ private Q_SLOTS: if (p) { KAboutData aboutData =3D KAboutData::fromPluginMetaData(plugin= Info(p)); if (!aboutData.componentName().isEmpty()) { // Be sure the abo= ut data is not completely empty - KAboutApplicationDialog aboutPlugin(aboutData, itemView()); - aboutPlugin.exec(); + KDevelop::ScopedDialog aboutPlugi= n(aboutData, itemView()); + aboutPlugin->exec(); return; } } diff --git a/shell/mainwindow_actions.cpp b/shell/mainwindow_actions.cpp index 7bc17b29e..8b75f7417 100644 --- a/shell/mainwindow_actions.cpp +++ b/shell/mainwindow_actions.cpp @@ -40,6 +40,7 @@ Boston, MA 02110-1301, USA. #include "loadedpluginsdialog.h" = #include +#include = namespace KDevelop { = @@ -206,14 +207,14 @@ void MainWindowPrivate::configureNotifications() = 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 index c0927d348..7e94e02bf 100644 --- a/shell/projectcontroller.cpp +++ b/shell/projectcontroller.cpp @@ -29,6 +29,7 @@ Boston, MA 02110-1301, USA. #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ Boston, MA 02110-1301, USA. #include #include #include +#include #include #include = @@ -419,13 +421,15 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(= bool fetch, const QUrl& sta const QUrl& repoUrl, = IPlugin* vcsOrProviderPlugin) { Q_ASSERT(d); - OpenProjectDialog dlg(fetch, startUrl, repoUrl, vcsOrProviderPlugin, C= ore::self()->uiController()->activeMainWindow()); - if(dlg.exec() =3D=3D QDialog::Rejected) + ScopedDialog dlg(fetch, startUrl, repoUrl, vcsOrPro= viderPlugin, + Core::self()->uiController()->act= iveMainWindow()); + if(dlg->exec() =3D=3D QDialog::Rejected) { return QUrl(); + } = - QUrl projectFileUrl =3D dlg.projectFileUrl(); - qCDebug(SHELL) << "selected project:" << projectFileUrl << dlg.project= Name() << dlg.projectManager(); - if ( dlg.projectManager() =3D=3D QLatin1String("") ) { + QUrl projectFileUrl =3D dlg->projectFileUrl(); + qCDebug(SHELL) << "selected project:" << projectFileUrl << dlg->projec= tName() << dlg->projectManager(); + if ( dlg->projectManager() =3D=3D QLatin1String("") ) { return projectFileUrl; } = @@ -435,11 +439,11 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(= bool fetch, const QUrl& sta { // check whether config is equal bool shouldAsk =3D true; - if( projectFileUrl =3D=3D dlg.selectedUrl() ) + if( projectFileUrl =3D=3D dlg->selectedUrl() ) { if( projectFileUrl.isLocalFile() ) { - shouldAsk =3D !equalProjectFile( projectFileUrl.toLocalFil= e(), &dlg ); + shouldAsk =3D !equalProjectFile( projectFileUrl.toLocalFil= e(), dlg ); } else { shouldAsk =3D false; = @@ -448,7 +452,7 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(bo= ol fetch, const QUrl& sta auto downloadJob =3D KIO::file_copy(projectFileUrl, QU= rl::fromLocalFile(tmpFile.fileName())); KJobWidgets::setWindow(downloadJob, qApp->activeWindow= ()); if (downloadJob->exec()) { - shouldAsk =3D !equalProjectFile(tmpFile.fileName()= , &dlg); + shouldAsk =3D !equalProjectFile(tmpFile.fileName()= , dlg); } } } @@ -483,12 +487,13 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(= bool fetch, const QUrl& sta } = if (writeProjectConfigToFile) { - if (!writeProjectSettingsToConfigFile(projectFileUrl, &dlg)) { + if (!writeProjectSettingsToConfigFile(projectFileUrl, dlg)) { KMessageBox::error(d->m_core->uiControllerInternal()->defaultM= ainWindow(), i18n("Unable to create configuration file %1", projectFile= Url.url())); return QUrl(); } } + return projectFileUrl; } = @@ -785,10 +790,10 @@ void ProjectController::openProject( const QUrl &proj= ectFile ) } = if ( ! existingSessions.isEmpty() ) { - QDialog dialog(Core::self()->uiControllerInternal()->activeMainWin= dow()); - dialog.setWindowTitle(i18n("Project Already Open")); + ScopedDialog dialog(Core::self()->uiControllerInternal()-= >activeMainWindow()); + dialog->setWindowTitle(i18n("Project Already Open")); = - auto mainLayout =3D new QVBoxLayout(&dialog); + auto mainLayout =3D new QVBoxLayout(dialog); mainLayout->addWidget(new QLabel(i18n("The project you're trying t= o open is already open in at least one " "other session.
Wh= at do you want to do?"))); QGroupBox sessions; @@ -808,12 +813,11 @@ void ProjectController::openProject( const QUrl &proj= ectFile ) auto okButton =3D 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 =3D dialog.exec(); - if (!success) + if (!dialog->exec()) return; = foreach ( const QObject* obj, sessions.children() ) { @@ -1158,7 +1162,7 @@ void ProjectController::commitCurrentProject() bool ret =3D showVcsDiff(patchSource); = if(!ret) { - VcsCommitDialog *commitDialog =3D new VcsCommitDialog(patc= hSource); + ScopedDialog commitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); } diff --git a/shell/sessioncontroller.cpp b/shell/sessioncontroller.cpp index 137aa7e05..bceb0177a 100644 --- a/shell/sessioncontroller.cpp +++ b/shell/sessioncontroller.cpp @@ -614,7 +614,7 @@ QString SessionController::showSessionChooserDialog(QSt= ring headerText, bool onl ///@todo We need a way to get a proper size-hint from the view, but un= fortunately, that only seems possible after the view was shown. dialog.resize(QSize(900, 600)); = - if(dialog.exec() !=3D QDialog::Accepted) + if(dialog.exec() !=3D QDialog::Accepted) // krazy:exclude=3Dcrashy { return QString(); } diff --git a/shell/settings/environmentwidget.cpp b/shell/settings/environm= entwidget.cpp index df43dcb76..b09624087 100644 --- a/shell/settings/environmentwidget.cpp +++ b/shell/settings/environmentwidget.cpp @@ -33,6 +33,8 @@ Boston, MA 02110-1301, USA. #include #include = +#include + #include = #include "environmentprofilelistmodel.h" @@ -176,10 +178,10 @@ void EnvironmentWidget::defaults( KConfig* config ) = 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 =3D new QVBoxLayout(&dialog); + QVBoxLayout *layout =3D new QVBoxLayout(dialog); = auto editLayout =3D new QHBoxLayout; = @@ -193,11 +195,11 @@ QString EnvironmentWidget::askNewProfileName(const QS= tring& defaultName) auto okButton =3D buttonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(false); okButton->setDefault(true); - dialog.connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDial= og::accept); - dialog.connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDial= og::reject); + dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDial= og::accept); + dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDial= og::reject); layout->addWidget(buttonBox); = - auto validator =3D new ProfileNameValidator(m_environmentProfileListMo= del, &dialog); + auto validator =3D new ProfileNameValidator(m_environmentProfileListMo= del, dialog); connect(edit, &QLineEdit::textChanged, validator, [validator, okButton= ](const QString& text) { int pos; QString t(text); @@ -208,7 +210,7 @@ QString EnvironmentWidget::askNewProfileName(const QStr= ing& defaultName) edit->setText(defaultName); edit->selectAll(); = - if (dialog.exec() !=3D QDialog::Accepted) { + if (dialog->exec() !=3D QDialog::Accepted) { return {}; } = @@ -239,10 +241,10 @@ void EnvironmentWidget::onVariableInserted(int column= , const QVariant& value) = void EnvironmentWidget::batchModeEditButtonClicked() { - QDialog dialog(this); - dialog.setWindowTitle( i18n( "Batch Edit Mode" ) ); + ScopedDialog dialog(this); + dialog->setWindowTitle( i18n( "Batch Edit Mode" ) ); = - QVBoxLayout *layout =3D new QVBoxLayout(&dialog); + QVBoxLayout *layout =3D new QVBoxLayout(dialog); = auto edit =3D new QPlainTextEdit; edit->setPlaceholderText(QStringLiteral("VARIABLE1=3DVALUE1\nVARIABLE2= =3DVALUE2")); @@ -259,13 +261,13 @@ void EnvironmentWidget::batchModeEditButtonClicked() auto okButton =3D buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - dialog.connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDial= og::accept); - dialog.connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDial= og::reject); + dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDial= og::accept); + dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDial= og::reject); layout->addWidget(buttonBox); = - dialog.resize(600, 400); + dialog->resize(600, 400); = - if ( dialog.exec() !=3D QDialog::Accepted ) { + if ( dialog->exec() !=3D QDialog::Accepted ) { return; } = diff --git a/shell/settings/sourceformattersettings.cpp b/shell/settings/so= urceformattersettings.cpp index 19e036ea7..491a6a91d 100644 --- a/shell/settings/sourceformattersettings.cpp +++ b/shell/settings/sourceformattersettings.cpp @@ -38,6 +38,7 @@ Boston, MA 02110-1301, USA. #include #include #include +#include = #include "editstyledialog.h" #include "debug.h" @@ -401,10 +402,10 @@ void SourceFormatterSettings::editStyle() = QMimeType mimetype =3D l.mimetypes.first(); if( QScopedPointer(fmt->formatter->editStyleWidget( mimetype = )) ) { - EditStyleDialog dlg( fmt->formatter, mimetype, *l.selectedStyle, t= his ); - if( dlg.exec() =3D=3D QDialog::Accepted ) + KDevelop::ScopedDialog dlg(fmt->formatter, mimety= pe, *l.selectedStyle, this); + if( dlg->exec() =3D=3D 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 index 64a566c5c..f7ce0883b 100644 --- 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,14 +71,14 @@ TemplatePage::~TemplatePage() = 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); } = @@ -86,10 +87,13 @@ void TemplatePage::loadFromFile() = void TemplatePage::getMoreTemplates() { - KNS3::DownloadDialog dialog(m_provider->knsConfigurationFile(), this); - dialog.exec(); + KDevelop::ScopedDialog dialog(m_provider->knsCon= figurationFile(), this); + + if (!dialog->exec()) { + return; + } = - if (!dialog.changedEntries().isEmpty()) + if (!dialog->changedEntries().isEmpty()) { m_provider->reload(); } @@ -97,8 +101,8 @@ void TemplatePage::getMoreTemplates() = void TemplatePage::shareTemplates() { - KNS3::UploadDialog dialog(m_provider->knsConfigurationFile(), this); - dialog.exec(); + KDevelop::ScopedDialog dialog(m_provider->knsConfi= gurationFile(), this); + dialog->exec(); } = void TemplatePage::currentIndexChanged(const QModelIndex& index) diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp index 645598801..76a60f799 100644 --- 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 @@ void UiController::selectNewToolViewToAdd(MainWindow *m= w) if (!mw || !mw->area()) return; = - QDialog *dia =3D new QDialog(mw); + ScopedDialog dia(mw); dia->setWindowTitle(i18n("Select Tool View to Add")); = auto mainLayout =3D new QVBoxLayout(dia); @@ -474,7 +475,6 @@ void UiController::selectNewToolViewToAdd(MainWindow *m= w) addNewToolView(mw, item); } } - delete dia; } = void UiController::addNewToolView(MainWindow *mw, QListWidgetItem* item) diff --git a/util/scopeddialog.h b/util/scopeddialog.h new file mode 100644 index 000000000..7c0cfd5f0 --- /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 c= alling + * function they get intentionally deleted again, which will lead to a cra= sh. This + * can be circumvented by using a QPointer which keeps track of the QDialo= gs 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(arg= s...)) { + } + /// 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 index d1be44f40..85d34387b 100644 --- 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 @@ void DistributedVersionControlPlugin::ctxBranchManager() = ICore::self()->documentController()->saveAllDocuments(); = - BranchManager branchManager(stripPathToDir(ctxUrlList.front().toLocalF= ile()), - this, core()->uiController()->activeMainWi= ndow()); - branchManager.exec(); + ScopedDialog branchManager(stripPathToDir(ctxUrlList.fr= ont().toLocalFile()), + this, core()->uiController(= )->activeMainWindow()); + branchManager->exec(); } = } diff --git a/vcs/vcspluginhelper.cpp b/vcs/vcspluginhelper.cpp index 19810b4d0..9778cd5a3 100644 --- a/vcs/vcspluginhelper.cpp +++ b/vcs/vcspluginhelper.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -457,7 +458,7 @@ void VcsPluginHelper::commit() bool ret =3D showVcsDiff(patchSource); = if(!ret) { - VcsCommitDialog *commitDialog =3D new VcsCommitDialog(patchSource); + ScopedDialog commitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); }