[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdevplatform] /: Fix crashy dialogs (found by krazy and by hand)
From:       Christoph Roick <null () kde ! org>
Date:       2017-06-30 21:58:42
Message-ID: E1dR3w2-0003Fw-Ek () code ! kde ! org
[Download RAW message or body]

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/7cda7c95d5bfa93f34c5a52df17480c248a8367c

diff --git a/language/codegen/basicrefactoring.cpp \
b/language/codegen/basicrefactoring.cpp index f666b2444..68dc459e3 100644
--- a/language/codegen/basicrefactoring.cpp
+++ b/language/codegen/basicrefactoring.cpp
@@ -309,8 +309,7 @@ BasicRefactoring::NameAndCollector \
BasicRefactoring::newNameForDeclaration(const  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 index f0e6eb107..50a5f82ce 100644
--- a/plugins/appwizard/appwizardplugin.cpp
+++ b/plugins/appwizard/appwizardplugin.cpp
@@ -46,6 +46,7 @@
 #include <interfaces/idocumentcontroller.h>
 #include <interfaces/context.h>
 #include <interfaces/contextmenuextension.h>
+#include <util/scopeddialog.h>
 #include <vcs/vcsjob.h>
 #include <vcs/interfaces/icentralizedversioncontrol.h>
 #include <vcs/interfaces/idistributedversioncontrol.h>
@@ -84,16 +85,16 @@ void AppWizardPlugin::slotNewProject()
 {
     model()->refresh();
 
-    AppWizardDialog dlg(core()->pluginController(), m_templatesModel);
+    ScopedDialog<AppWizardDialog> 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 index d7862e0ee..d4ec5e7cd 100644
--- a/plugins/appwizard/projectselectionpage.cpp
+++ b/plugins/appwizard/projectselectionpage.cpp
@@ -26,6 +26,7 @@
 #include <language/codegen/templatepreviewicon.h>
 
 #include <util/multilevellistview.h>
+#include <util/scopeddialog.h>
 
 #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<QFileDialog> 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::loadFileClicked()
 
 void ProjectSelectionPage::moreTemplatesClicked()
 {
-    KNS3::DownloadDialog dialog(QStringLiteral("kdevappwizard.knsrc"), this);
-    dialog.exec();
+    ScopedDialog<KNS3::DownloadDialog> 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 index 22b78bf7e..ad34c4966 100644
--- a/plugins/externalscript/externalscriptview.cpp
+++ b/plugins/externalscript/externalscriptview.cpp
@@ -32,6 +32,8 @@
 #include <KLocalizedString>
 #include <KMessageBox>
 
+#include <util/scopeddialog.h>
+
 
 ExternalScriptView::ExternalScriptView( ExternalScriptPlugin* plugin, QWidget* \
parent )  : QWidget( parent ), m_plugin( plugin )
@@ -135,9 +137,8 @@ bool ExternalScriptView::eventFilter( QObject* obj, QEvent* e )
 void ExternalScriptView::addScript()
 {
   ExternalScriptItem* item = new ExternalScriptItem;
-  EditExternalScript dlg( item, this );
-  int ret = dlg.exec();
-  if ( ret == QDialog::Accepted) {
+  KDevelop::ScopedDialog<EditExternalScript> dlg( item, this );
+  if ( dlg->exec() == QDialog::Accepted) {
     m_plugin->model()->appendRow( item );
   } else {
     delete item;
@@ -170,9 +171,8 @@ void ExternalScriptView::editScript()
     return;
   }
 
-  EditExternalScript dlg( item, this );
-  int ret = dlg.exec();
-  if (ret == QDialog::Accepted) {
+  KDevelop::ScopedDialog<EditExternalScript> dlg( item, this );
+  if (dlg->exec() == QDialog::Accepted) {
     item->save();
   }
 }
diff --git a/plugins/filetemplates/templateclassassistant.cpp \
b/plugins/filetemplates/templateclassassistant.cpp index b9cf29005..da4237b5e 100644
--- a/plugins/filetemplates/templateclassassistant.cpp
+++ b/plugins/filetemplates/templateclassassistant.cpp
@@ -45,12 +45,12 @@
 #include <project/projectmodel.h>
 #include <project/interfaces/iprojectfilemanager.h>
 #include <project/interfaces/ibuildsystemmanager.h>
+#include <util/scopeddialog.h>
 
 #include <QDialog>
 #include <QDialogButtonBox>
 #include <QLabel>
 #include <QListWidget>
-#include <QPointer>
 #include <QPushButton>
 #include <QVBoxLayout>
 
@@ -198,7 +198,7 @@ void TemplateClassAssistantPrivate::addFilesToTarget (const \
QHash< QString, QUrl  else if (targets.size() > 1)
     {
         // More than one candidate target, show the chooser dialog
-        QPointer<QDialog> d = new QDialog;
+        ScopedDialog<QDialog> d;
 
         auto mainLayout = new QVBoxLayout(d);
         mainLayout->addWidget(new QLabel(i18n("Choose one target to add the file or \
cancel if you do not want to do so."))); @@ -215,8 +215,8 @@ void \
TemplateClassAssistantPrivate::addFilesToTarget (const QHash< QString, QUrl  \
QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);  \
okButton->setDefault(true);  okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
-        d->connect(buttonBox, &QDialogButtonBox::accepted, d.data(), \
                &QDialog::accept);
-        d->connect(buttonBox, &QDialogButtonBox::rejected, d.data(), \
&QDialog::reject); +        d->connect(buttonBox, &QDialogButtonBox::accepted, d, \
&QDialog::accept); +        d->connect(buttonBox, &QDialogButtonBox::rejected, d, \
&QDialog::reject);  mainLayout->addWidget(buttonBox);
 
         if(d->exec() == QDialog::Accepted)
diff --git a/plugins/filetemplates/templateselectionpage.cpp \
b/plugins/filetemplates/templateselectionpage.cpp index 7f731c4cd..ae728ed36 100644
--- a/plugins/filetemplates/templateselectionpage.cpp
+++ b/plugins/filetemplates/templateselectionpage.cpp
@@ -32,6 +32,7 @@
 #include <interfaces/iproject.h>
 #include <interfaces/iprojectcontroller.h>
 #include <interfaces/isession.h>
+#include <util/scopeddialog.h>
 
 #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<QFileDialog> 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
index bc926bf51..f403d1ab9 100644
--- a/plugins/git/gitplugin.cpp
+++ b/plugins/git/gitplugin.cpp
@@ -516,7 +516,7 @@ void GitPlugin::addNotVersionedFiles(const QDir& dir, const \
QList<QUrl>& files)  
     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 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::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 @@ void KDevSvnPlugin::ctxMove()
             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
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 | \
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
index e4d656fde..724a51499 100644
--- a/shell/documentcontroller.cpp
+++ b/shell/documentcontroller.cpp
@@ -54,6 +54,7 @@ Boston, MA 02110-1301, USA.
 #include <interfaces/iselectioncontroller.h>
 #include <interfaces/context.h>
 #include <project/projectmodel.h>
+#include <util/scopeddialog.h>
 #include <util/path.h>
 
 #include "core.h"
@@ -813,9 +814,8 @@ bool KDevelop::DocumentController::saveSomeDocuments(const QList< \
IDocument * >  QList<IDocument*> checkSave = modifiedDocuments(list);
 
         if (!checkSave.isEmpty()) {
-            KSaveSelectDialog dialog(checkSave, qApp->activeWindow());
-            if (dialog.exec() == QDialog::Rejected)
-                return false;
+            ScopedDialog<KSaveSelectDialog> dialog(checkSave, qApp->activeWindow());
+            return dialog->exec();
         }
     }
 
diff --git a/shell/environmentconfigurebutton.cpp \
b/shell/environmentconfigurebutton.cpp index f48287421..f7f7221d9 100644
--- a/shell/environmentconfigurebutton.cpp
+++ b/shell/environmentconfigurebutton.cpp
@@ -29,6 +29,8 @@
 #include <QIcon>
 #include <QVBoxLayout>
 
+#include <util/scopeddialog.h>
+
 #include <KLocalizedString>
 
 namespace KDevelop {
@@ -43,31 +45,31 @@ public:
 
     void showDialog()
     {
-        QDialog dlg(qApp->activeWindow());
+        ScopedDialog<QDialog> 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
index ed13541e4..3b5916c8a 100644
--- a/shell/loadedpluginsdialog.cpp
+++ b/shell/loadedpluginsdialog.cpp
@@ -34,6 +34,8 @@
 #include <KTitleWidget>
 #include <KWidgetItemDelegate>
 
+#include <util/scopeddialog.h>
+
 #include "core.h"
 #include "plugincontroller.h"
 
@@ -240,8 +242,8 @@ private Q_SLOTS:
         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<KAboutApplicationDialog> \
aboutPlugin(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 <interfaces/itoolviewactionlistener.h>
+#include <util/scopeddialog.h>
 
 namespace KDevelop {
 
@@ -206,14 +207,14 @@ void MainWindowPrivate::configureNotifications()
 
 void MainWindowPrivate::showAboutPlatform()
 {
-    KAboutApplicationDialog dlg(Core::self()->aboutData(), m_mainWindow );
-    dlg.exec();
+    ScopedDialog<KAboutApplicationDialog> dlg(Core::self()->aboutData(), \
m_mainWindow ); +    dlg->exec();
 }
 
 void MainWindowPrivate::showLoadedPlugins()
 {
-    LoadedPluginsDialog dlg(m_mainWindow);
-    dlg.exec();
+    ScopedDialog<LoadedPluginsDialog> 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 <QLabel>
 #include <QList>
 #include <QMap>
+#include <QPointer>
 #include <QPushButton>
 #include <QRadioButton>
 #include <QSet>
@@ -63,6 +64,7 @@ Boston, MA 02110-1301, USA.
 #include <projectconfigpage.h>
 #include <language/backgroundparser/parseprojectjob.h>
 #include <interfaces/iruncontroller.h>
+#include <util/scopeddialog.h>
 #include <vcs/widgets/vcsdiffpatchsources.h>
 #include <vcs/widgets/vcscommitdialog.h>
 
@@ -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, \
                Core::self()->uiController()->activeMainWindow());
-    if(dlg.exec() == QDialog::Rejected)
+    ScopedDialog<OpenProjectDialog> 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("<built-in>") ) {
+    QUrl projectFileUrl = dlg->projectFileUrl();
+    qCDebug(SHELL) << "selected project:" << projectFileUrl << dlg->projectName() << \
dlg->projectManager(); +    if ( dlg->projectManager() == QLatin1String("<built-in>") \
) {  return projectFileUrl;
     }
 
@@ -435,11 +439,11 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(bool \
fetch, const QUrl& sta  {
         // 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;
 
@@ -448,7 +452,7 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(bool fetch, \
                const QUrl& sta
                     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 @@ QUrl ProjectDialogProvider::askProjectConfigLocation(bool \
fetch, const QUrl& sta  }
 
     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 @@ void ProjectController::openProject( const QUrl &projectFile )
     }
 
     if ( ! existingSessions.isEmpty() ) {
-        QDialog dialog(Core::self()->uiControllerInternal()->activeMainWindow());
-        dialog.setWindowTitle(i18n("Project Already Open"));
+        ScopedDialog<QDialog> \
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.<br>What do you \
want to do?")));  QGroupBox sessions;
@@ -808,12 +813,11 @@ void ProjectController::openProject( const QUrl &projectFile )
         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 @@ void ProjectController::commitCurrentProject()
             bool ret = showVcsDiff(patchSource);
 
             if(!ret) {
-                VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource);
+                ScopedDialog<VcsCommitDialog> 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(QString \
                headerText, bool onl
     ///@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 index df43dcb76..b09624087 100644
--- a/shell/settings/environmentwidget.cpp
+++ b/shell/settings/environmentwidget.cpp
@@ -33,6 +33,8 @@ Boston, MA 02110-1301, USA.
 #include <QHBoxLayout>
 #include <QValidator>
 
+#include <util/scopeddialog.h>
+
 #include <KLocalizedString>
 
 #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<QDialog> 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 @@ QString EnvironmentWidget::askNewProfileName(const QString& \
defaultName)  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 @@ QString EnvironmentWidget::askNewProfileName(const QString& \
defaultName)  edit->setText(defaultName);
     edit->selectAll();
 
-    if (dialog.exec() != QDialog::Accepted) {
+    if (dialog->exec() != 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<QDialog> 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 @@ void EnvironmentWidget::batchModeEditButtonClicked()
     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 index 19e036ea7..491a6a91d 100644
--- a/shell/settings/sourceformattersettings.cpp
+++ b/shell/settings/sourceformattersettings.cpp
@@ -38,6 +38,7 @@ Boston, MA 02110-1301, USA.
 #include <shell/core.h>
 #include <shell/plugincontroller.h>
 #include <shell/languagecontroller.h>
+#include <util/scopeddialog.h>
 
 #include "editstyledialog.h"
 #include "debug.h"
@@ -401,10 +402,10 @@ void SourceFormatterSettings::editStyle()
 
     QMimeType mimetype = l.mimetypes.first();
     if( QScopedPointer<QObject>(fmt->formatter->editStyleWidget( mimetype )) ) {
-        EditStyleDialog dlg( fmt->formatter, mimetype, *l.selectedStyle, this );
-        if( dlg.exec() == QDialog::Accepted )
+        KDevelop::ScopedDialog<EditStyleDialog> 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
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 <QFileDialog>
 
 #include <interfaces/itemplateprovider.h>
 #include <language/codegen/templatesmodel.h>
@@ -32,7 +33,7 @@
 #include <KZip>
 #include <KTar>
 
-#include <QFileDialog>
+#include <util/scopeddialog.h>
 
 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<QFileDialog> 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<KNS3::DownloadDialog> \
dialog(m_provider->knsConfigurationFile(), 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<KNS3::UploadDialog> \
dialog(m_provider->knsConfigurationFile(), 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 <sublime/holdupdates.h>
 
 #include <interfaces/itoolviewactionlistener.h>
+#include <util/scopeddialog.h>
 
 #include "core.h"
 #include "configpage.h"
@@ -434,7 +435,7 @@ void UiController::selectNewToolViewToAdd(MainWindow *mw)
     if (!mw || !mw->area())
         return;
 
-    QDialog *dia = new QDialog(mw);
+    ScopedDialog<QDialog> dia(mw);
     dia->setWindowTitle(i18n("Select Tool View to Add"));
 
     auto mainLayout = new QVBoxLayout(dia);
@@ -474,7 +475,6 @@ void UiController::selectNewToolViewToAdd(MainWindow *mw)
             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 <chrisito@gmx.de>
+ *
+ * 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 <QPointer>
+
+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
+ * <a href="https://blogs.kde.org/2009/03/26/how-crash-almost-every-qtkde-application-and-how-fix-it-0">blog \
entry</a> + * 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<QFileDialog> dlg(this);
+   if (dlg->exec())
+       return;
+  \endcode
+  without need to manually clean up afterwards.
+ */
+template<typename DialogType>
+class ScopedDialog {
+    public:
+        /// Construct the dialog with any set of allowed arguments
+        /// for the construction of DialogType
+        template<typename ... Arguments>
+        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<DialogType> 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 <interfaces/context.h>
 #include <interfaces/contextmenuextension.h>
 #include <interfaces/idocumentcontroller.h>
+#include <util/scopeddialog.h>
 
 #include "dvcsjob.h"
 #include "ui/dvcsimportmetadatawidget.h"
@@ -128,9 +129,9 @@ void DistributedVersionControlPlugin::ctxBranchManager()
     
     ICore::self()->documentController()->saveAllDocuments();
 
-    BranchManager branchManager(stripPathToDir(ctxUrlList.front().toLocalFile()),
-                                this, core()->uiController()->activeMainWindow());
-    branchManager.exec();
+    ScopedDialog<BranchManager> \
branchManager(stripPathToDir(ctxUrlList.front().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 <interfaces/isession.h>
 #include <interfaces/iuicontroller.h>
 #include <util/path.h>
+#include <util/scopeddialog.h>
 #include <vcs/interfaces/ibasicversioncontrol.h>
 #include <vcs/models/vcsannotationmodel.h>
 #include <vcs/widgets/vcseventwidget.h>
@@ -457,7 +458,7 @@ void VcsPluginHelper::commit()
     bool ret = showVcsDiff(patchSource);
 
     if(!ret) {
-        VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource);
+        ScopedDialog<VcsCommitDialog> commitDialog(patchSource);
         commitDialog->setCommitCandidates(patchSource->infos());
         commitDialog->exec();
     }


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic