summaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/appmanager/project/appmanagerproject.cpp4
-rw-r--r--src/plugins/appmanager/project/appmanagerprojectnode.cpp6
-rw-r--r--src/plugins/autotoolsprojectmanager/autotoolsproject.cpp5
-rw-r--r--src/plugins/bazaar/bazaarclient.cpp32
-rw-r--r--src/plugins/bazaar/bazaarclient.h1
-rw-r--r--src/plugins/bazaar/bazaarcontrol.cpp5
-rw-r--r--src/plugins/bazaar/bazaarcontrol.h28
-rw-r--r--src/plugins/clangcodemodel/clangcodemodel.pro5
-rw-r--r--src/plugins/clangrefactoring/clangrefactoring.pro3
-rw-r--r--src/plugins/classview/classviewparser.cpp8
-rw-r--r--src/plugins/clearcase/clearcasecontrol.cpp6
-rw-r--r--src/plugins/clearcase/clearcasecontrol.h36
-rw-r--r--src/plugins/clearcase/clearcaseplugin.cpp1
-rw-r--r--src/plugins/cmakeprojectmanager/builddirmanager.cpp899
-rw-r--r--src/plugins/cmakeprojectmanager/builddirmanager.h66
-rw-r--r--src/plugins/cmakeprojectmanager/builddirreader.cpp98
-rw-r--r--src/plugins/cmakeprojectmanager/builddirreader.h119
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp11
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h4
-rw-r--r--src/plugins/cmakeprojectmanager/cmakecbpparser.cpp163
-rw-r--r--src/plugins/cmakeprojectmanager/cmakecbpparser.h11
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp49
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeconfigitem.h6
-rw-r--r--src/plugins/cmakeprojectmanager/cmakekitinformation.cpp2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.cpp9
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.h14
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeproject.qrc2
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectconstants.h3
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro14
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs12
-rw-r--r--src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp7
-rw-r--r--src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp13
-rw-r--r--src/plugins/cmakeprojectmanager/cmakerunconfiguration.h4
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.cpp6
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.h4
-rw-r--r--src/plugins/cmakeprojectmanager/images/fileoverlay_cmake.pngbin0 -> 419 bytes
-rw-r--r--src/plugins/cmakeprojectmanager/images/fileoverlay_cmake@2x.pngbin0 -> 947 bytes
-rw-r--r--src/plugins/cmakeprojectmanager/servermode.cpp456
-rw-r--r--src/plugins/cmakeprojectmanager/servermode.h118
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.cpp452
-rw-r--r--src/plugins/cmakeprojectmanager/servermodereader.h141
-rw-r--r--src/plugins/cmakeprojectmanager/tealeafreader.cpp716
-rw-r--r--src/plugins/cmakeprojectmanager/tealeafreader.h94
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp1
-rw-r--r--src/plugins/coreplugin/coreplugin.h3
-rw-r--r--src/plugins/coreplugin/coreplugin.pro3
-rw-r--r--src/plugins/coreplugin/coreplugin.qbs1
-rw-r--r--src/plugins/coreplugin/fileiconprovider.cpp52
-rw-r--r--src/plugins/coreplugin/fileiconprovider.h7
-rw-r--r--src/plugins/coreplugin/find/findplugin.cpp5
-rw-r--r--src/plugins/coreplugin/find/ifindfilter.cpp6
-rw-r--r--src/plugins/coreplugin/iversioncontrol.h14
-rw-r--r--src/plugins/coreplugin/reaper.cpp146
-rw-r--r--src/plugins/coreplugin/reaper.h (renamed from src/plugins/cmakeprojectmanager/cmakefile.h)24
-rw-r--r--src/plugins/coreplugin/reaper_p.h (renamed from src/plugins/cmakeprojectmanager/cmakefile.cpp)64
-rw-r--r--src/plugins/cvs/cvsclient.cpp19
-rw-r--r--src/plugins/cvs/cvscontrol.cpp7
-rw-r--r--src/plugins/cvs/cvscontrol.h32
-rw-r--r--src/plugins/cvs/cvsplugin.cpp1
-rw-r--r--src/plugins/debugger/debuggerengine.cpp2
-rw-r--r--src/plugins/designer/resourcehandler.cpp2
-rw-r--r--src/plugins/genericprojectmanager/genericproject.cpp10
-rw-r--r--src/plugins/git/gitclient.cpp73
-rw-r--r--src/plugins/git/gitclient.h1
-rw-r--r--src/plugins/git/gitsettings.cpp2
-rw-r--r--src/plugins/git/gitsettings.h1
-rw-r--r--src/plugins/git/gitversioncontrol.cpp8
-rw-r--r--src/plugins/git/gitversioncontrol.h32
-rw-r--r--src/plugins/mercurial/mercurialclient.cpp19
-rw-r--r--src/plugins/mercurial/mercurialclient.h1
-rw-r--r--src/plugins/mercurial/mercurialcontrol.cpp5
-rw-r--r--src/plugins/mercurial/mercurialcontrol.h28
-rw-r--r--src/plugins/modeleditor/componentviewcontroller.cpp4
-rw-r--r--src/plugins/modeleditor/modelindexer.cpp2
-rw-r--r--src/plugins/modeleditor/pxnodecontroller.cpp14
-rw-r--r--src/plugins/modeleditor/pxnodeutilities.cpp10
-rw-r--r--src/plugins/nim/project/nimbuildconfigurationfactory.cpp4
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.cpp11
-rw-r--r--src/plugins/nim/project/nimcompilerbuildstep.h2
-rw-r--r--src/plugins/nim/project/nimproject.cpp68
-rw-r--r--src/plugins/nim/project/nimproject.h11
-rw-r--r--src/plugins/nim/project/nimprojectnode.cpp6
-rw-r--r--src/plugins/perforce/perforceplugin.cpp22
-rw-r--r--src/plugins/perforce/perforceversioncontrol.cpp6
-rw-r--r--src/plugins/perforce/perforceversioncontrol.h33
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp2
-rw-r--r--src/plugins/projectexplorer/kitmanager.h2
-rw-r--r--src/plugins/projectexplorer/project.h1
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp56
-rw-r--r--src/plugins/projectexplorer/projectmodels.cpp138
-rw-r--r--src/plugins/projectexplorer/projectnodes.cpp410
-rw-r--r--src/plugins/projectexplorer/projectnodes.h144
-rw-r--r--src/plugins/projectexplorer/projecttree.cpp14
-rw-r--r--src/plugins/projectexplorer/projecttreewidget.cpp2
-rw-r--r--src/plugins/projectexplorer/projectwizardpage.cpp6
-rw-r--r--src/plugins/projectexplorer/session.cpp2
-rw-r--r--src/plugins/pythoneditor/pythoneditorplugin.cpp2
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodes.cpp69
-rw-r--r--src/plugins/qbsprojectmanager/qbsnodes.h2
-rw-r--r--src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp14
-rw-r--r--src/plugins/qmakeprojectmanager/profileeditor.cpp6
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodes.cpp98
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeproject.cpp26
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp6
-rw-r--r--src/plugins/qmldesigner/components/integration/componentaction.cpp2
-rw-r--r--src/plugins/qmldesigner/components/integration/componentaction.h2
-rw-r--r--src/plugins/qmldesigner/components/integration/componentview.cpp1
-rw-r--r--src/plugins/qmldesigner/documentmanager.cpp18
-rw-r--r--src/plugins/qmljseditor/qmljseditingsettingspage.cpp194
-rw-r--r--src/plugins/qmljseditor/qmljseditingsettingspage.h (renamed from src/plugins/qmljseditor/quicktoolbarsettingspage.h)54
-rw-r--r--src/plugins/qmljseditor/qmljseditingsettingspage.ui (renamed from src/plugins/qmljseditor/quicktoolbarsettingspage.ui)57
-rw-r--r--src/plugins/qmljseditor/qmljseditor.pro6
-rw-r--r--src/plugins/qmljseditor/qmljseditor.qbs6
-rw-r--r--src/plugins/qmljseditor/qmljseditorconstants.h3
-rw-r--r--src/plugins/qmljseditor/qmljseditorplugin.cpp56
-rw-r--r--src/plugins/qmljseditor/qmljseditorplugin.h2
-rw-r--r--src/plugins/qmljseditor/quicktoolbar.cpp20
-rw-r--r--src/plugins/qmljseditor/quicktoolbarsettingspage.cpp133
-rw-r--r--src/plugins/qmljstools/qmljstools.pro2
-rw-r--r--src/plugins/qmlprofiler/debugmessagesmodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/debugmessagesmodel.h2
-rw-r--r--src/plugins/qmlprofiler/inputeventsmodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/inputeventsmodel.h2
-rw-r--r--src/plugins/qmlprofiler/memoryusagemodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/memoryusagemodel.h2
-rw-r--r--src/plugins/qmlprofiler/pixmapcachemodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/pixmapcachemodel.h2
-rw-r--r--src/plugins/qmlprofiler/qmlevent.cpp12
-rw-r--r--src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/qmlprofileranimationsmodel.h2
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp9
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerdatamodel.h1
-rw-r--r--src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp4
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerrangemodel.h2
-rw-r--r--src/plugins/qmlprofiler/qmlprofilertracefile.cpp17
-rw-r--r--src/plugins/qmlprofiler/qmlprofilertracefile.h2
-rw-r--r--src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp2
-rw-r--r--src/plugins/qmlprofiler/scenegraphtimelinemodel.h2
-rw-r--r--src/plugins/qmlprofiler/tests/debugmessagesmodel_test.cpp2
-rw-r--r--src/plugins/qmlprofiler/tests/inputeventsmodel_test.cpp8
-rw-r--r--src/plugins/qmlprofiler/tests/memoryusagemodel_test.cpp6
-rw-r--r--src/plugins/qmlprofiler/tests/pixmapcachemodel_test.cpp12
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectnodes.cpp8
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp18
-rw-r--r--src/plugins/qtsupport/qscxmlcgenerator.cpp2
-rw-r--r--src/plugins/qtsupport/uicgenerator.cpp2
-rw-r--r--src/plugins/resourceeditor/resourcenode.cpp22
-rw-r--r--src/plugins/subversion/subversionclient.cpp12
-rw-r--r--src/plugins/subversion/subversioncontrol.cpp5
-rw-r--r--src/plugins/subversion/subversioncontrol.h27
-rw-r--r--src/plugins/subversion/subversionplugin.cpp11
-rw-r--r--src/plugins/subversion/subversionplugin.h2
-rw-r--r--src/plugins/texteditor/texteditor.cpp129
-rw-r--r--src/plugins/texteditor/texteditor.h3
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.cpp12
-rw-r--r--src/plugins/texteditor/texteditorconstants.h2
-rw-r--r--src/plugins/todo/todoitemsprovider.cpp2
-rw-r--r--src/plugins/vcsbase/vcsbase.pro4
-rw-r--r--src/plugins/vcsbase/vcsbase.qbs4
-rw-r--r--src/plugins/vcsbase/vcsbaseclient.cpp67
-rw-r--r--src/plugins/vcsbase/vcsbaseclient.h9
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.cpp18
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.h6
-rw-r--r--src/plugins/vcsbase/vcsbaseeditorconfig.cpp (renamed from src/plugins/vcsbase/vcsbaseeditorparameterwidget.cpp)131
-rw-r--r--src/plugins/vcsbase/vcsbaseeditorconfig.h (renamed from src/plugins/vcsbase/vcsbaseeditorparameterwidget.h)32
167 files changed, 4520 insertions, 2062 deletions
diff --git a/src/plugins/appmanager/project/appmanagerproject.cpp b/src/plugins/appmanager/project/appmanagerproject.cpp
index d0ea2824d4..d67ad4731f 100644
--- a/src/plugins/appmanager/project/appmanagerproject.cpp
+++ b/src/plugins/appmanager/project/appmanagerproject.cpp
@@ -156,7 +156,7 @@ void AppManagerProject::addNodes(const QSet<QString> &nodes)
path = QDir(projectDirectory().toString()).relativeFilePath(node).split(QDir::separator());
path.pop_back();
FolderNode *folder = findFolderFor(path);
- auto fileNode = new FileNode(FileName::fromString(node), SourceType, false);
+ auto fileNode = new FileNode(FileName::fromString(node), FileType::Source, false);
folder->addFileNodes({fileNode});
}
}
@@ -205,7 +205,7 @@ FolderNode *AppManagerProject::findFolderFor(const QStringList &path)
// Folder not found. Add it
QString newFolderPath = QDir::cleanPath(currentPath + QDir::separator() + part);
auto newFolder = new FolderNode(FileName::fromString(newFolderPath),
- FolderNodeType,
+ NodeType::Folder,
part);
folder->addFolderNodes({newFolder});
folder = newFolder;
diff --git a/src/plugins/appmanager/project/appmanagerprojectnode.cpp b/src/plugins/appmanager/project/appmanagerprojectnode.cpp
index 8c4bafe074..8955188b75 100644
--- a/src/plugins/appmanager/project/appmanagerprojectnode.cpp
+++ b/src/plugins/appmanager/project/appmanagerprojectnode.cpp
@@ -47,10 +47,10 @@ QList<ProjectAction> AppManagerProjectNode::supportedActions(Node *node) const
ProjectAction::RemoveFile
};
switch (node->nodeType()) {
- case FileNodeType:
+ case NodeType::File:
return fileActions;
- case FolderNodeType:
- case ProjectNodeType:
+ case NodeType::Folder:
+ case NodeType::Project:
return folderActions;
default:
return ProjectNode::supportedActions(node);
diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
index d07d355234..c37d144438 100644
--- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
+++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp
@@ -222,8 +222,9 @@ void AutotoolsProject::makefileParsingFinished()
QList<FileNode *> fileNodes = Utils::transform(files, [dir](const QString &f) {
const Utils::FileName path = Utils::FileName::fromString(dir.absoluteFilePath(f));
return new FileNode(path,
- (f == QLatin1String("Makefile.am") || f == QLatin1String("configure.ac"))
- ? ProjectFileType : ResourceType, false);
+ (f == QLatin1String("Makefile.am") ||
+ f == QLatin1String("configure.ac")) ? FileType::Project : FileType::Resource,
+ false);
});
rootProjectNode()->buildTree(fileNodes);
diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp
index 991f994741..b2bdac3288 100644
--- a/src/plugins/bazaar/bazaarclient.cpp
+++ b/src/plugins/bazaar/bazaarclient.cpp
@@ -30,7 +30,9 @@
#include <vcsbase/vcsbaseplugin.h>
#include <vcsbase/vcsoutputwindow.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
+
+#include <utils/hostosinfo.h>
#include <QDir>
#include <QFileInfo>
@@ -44,12 +46,12 @@ namespace Bazaar {
namespace Internal {
// Parameter widget controlling whitespace diff mode, associated with a parameter
-class BazaarDiffParameterWidget : public VcsBaseEditorParameterWidget
+class BazaarDiffConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- BazaarDiffParameterWidget(VcsBaseClientSettings &settings, QWidget *parent = 0) :
- VcsBaseEditorParameterWidget(parent)
+ BazaarDiffConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar)
{
mapSetting(addToggleButton(QLatin1String("-w"), tr("Ignore Whitespace")),
settings.boolPointer(BazaarSettings::diffIgnoreWhiteSpaceKey));
@@ -61,7 +63,7 @@ public:
{
QStringList args;
// Bazaar wants "--diff-options=-w -B.."
- const QStringList formatArguments = VcsBaseEditorParameterWidget::arguments();
+ const QStringList formatArguments = VcsBaseEditorConfig::arguments();
if (!formatArguments.isEmpty()) {
const QString a = QLatin1String("--diff-options=")
+ formatArguments.join(QString(QLatin1Char(' ')));
@@ -71,12 +73,12 @@ public:
}
};
-class BazaarLogParameterWidget : public VcsBaseEditorParameterWidget
+class BazaarLogConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- BazaarLogParameterWidget(VcsBaseClientSettings &settings, QWidget *parent = 0) :
- VcsBaseEditorParameterWidget(parent)
+ BazaarLogConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar)
{
mapSetting(addToggleButton(QLatin1String("--verbose"), tr("Verbose"),
tr("Show files changed in each revision.")),
@@ -100,8 +102,12 @@ public:
BazaarClient::BazaarClient() : VcsBaseClient(new BazaarSettings)
{
- setDiffParameterWidgetCreator([this] { return new BazaarDiffParameterWidget(settings()); });
- setLogParameterWidgetCreator([this] { return new BazaarLogParameterWidget(settings()); });
+ setDiffConfigCreator([this](QToolBar *toolBar) {
+ return new BazaarDiffConfig(settings(), toolBar);
+ });
+ setLogConfigCreator([this](QToolBar *toolBar) {
+ return new BazaarLogConfig(settings(), toolBar);
+ });
}
bool BazaarClient::synchronousSetUserId()
@@ -171,6 +177,12 @@ VcsBaseEditorWidget *BazaarClient::annotate(
QStringList(extraOptions) << QLatin1String("--long"));
}
+bool BazaarClient::isVcsDirectory(const FileName &fileName) const
+{
+ return fileName.toFileInfo().isDir()
+ && !fileName.fileName().compare(Constants::BAZAARREPO, HostOsInfo::fileNameCaseSensitivity());
+}
+
QString BazaarClient::findTopLevelForFile(const QFileInfo &file) const
{
const QString repositoryCheckFile =
diff --git a/src/plugins/bazaar/bazaarclient.h b/src/plugins/bazaar/bazaarclient.h
index c4293366a2..96f6a97a80 100644
--- a/src/plugins/bazaar/bazaarclient.h
+++ b/src/plugins/bazaar/bazaarclient.h
@@ -52,6 +52,7 @@ public:
VcsBase::VcsBaseEditorWidget *annotate(
const QString &workingDir, const QString &file, const QString &revision = QString(),
int lineNumber = -1, const QStringList &extraOptions = QStringList());
+ bool isVcsDirectory(const Utils::FileName &fileName) const;
QString findTopLevelForFile(const QFileInfo &file) const;
bool managesFile(const QString &workingDirectory, const QString &fileName) const;
diff --git a/src/plugins/bazaar/bazaarcontrol.cpp b/src/plugins/bazaar/bazaarcontrol.cpp
index 35269f622c..3db806cf0c 100644
--- a/src/plugins/bazaar/bazaarcontrol.cpp
+++ b/src/plugins/bazaar/bazaarcontrol.cpp
@@ -52,6 +52,11 @@ Core::Id BazaarControl::id() const
return Core::Id(VcsBase::Constants::VCS_ID_BAZAAR);
}
+bool BazaarControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ return m_bazaarClient->isVcsDirectory(fileName);
+}
+
bool BazaarControl::managesDirectory(const QString &directory, QString *topLevel) const
{
QFileInfo dir(directory);
diff --git a/src/plugins/bazaar/bazaarcontrol.h b/src/plugins/bazaar/bazaarcontrol.h
index 3b0be48097..020e15d37b 100644
--- a/src/plugins/bazaar/bazaarcontrol.h
+++ b/src/plugins/bazaar/bazaarcontrol.h
@@ -45,24 +45,26 @@ class BazaarControl: public Core::IVersionControl
public:
explicit BazaarControl(BazaarClient *bazaarClient);
- QString displayName() const override;
- Core::Id id() const override;
+ QString displayName() const final;
+ Core::Id id() const final;
- bool managesDirectory(const QString &filename, QString *topLevel = 0) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
- bool isConfigured() const override;
- bool supportsOperation(Operation operation) const override;
- bool vcsOpen(const QString &fileName) override;
- bool vcsAdd(const QString &filename) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
- bool vcsAnnotate(const QString &file, int line) override;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
+
+ bool managesDirectory(const QString &filename, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ bool vcsOpen(const QString &fileName) final;
+ bool vcsAdd(const QString &filename) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
+ bool vcsAnnotate(const QString &file, int line) final;
Core::ShellCommand *createInitialCheckoutCommand(const QString &url,
const Utils::FileName &baseDirectory,
const QString &localName,
- const QStringList &extraArgs) override;
+ const QStringList &extraArgs) final;
// To be connected to the VCSTask's success signal to emit the repository/
// files changed signals according to the variant's type:
diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro
index 0d9b5ee96b..3ab1502d46 100644
--- a/src/plugins/clangcodemodel/clangcodemodel.pro
+++ b/src/plugins/clangcodemodel/clangcodemodel.pro
@@ -1,10 +1,7 @@
include(../../qtcreatorplugin.pri)
include(../../shared/clang/clang_installation.pri)
-# The following defines are used to determine the clang include path for intrinsics.
-DEFINES += CLANG_VERSION=\\\"$${LLVM_VERSION}\\\"
-CLANG_RESOURCE_DIR=$$clean_path($${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/include)
-DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${CLANG_RESOURCE_DIR}\\\"\""
+include(../../shared/clang/clang_defines.pri)
SOURCES += \
clangactivationsequencecontextprocessor.cpp \
diff --git a/src/plugins/clangrefactoring/clangrefactoring.pro b/src/plugins/clangrefactoring/clangrefactoring.pro
index 3716c86b93..b811f181a7 100644
--- a/src/plugins/clangrefactoring/clangrefactoring.pro
+++ b/src/plugins/clangrefactoring/clangrefactoring.pro
@@ -2,8 +2,7 @@ include(../../qtcreatorplugin.pri)
include(clangrefactoring-source.pri)
include(../../shared/clang/clang_installation.pri)
-DEFINES += CLANG_VERSION=\\\"$${LLVM_VERSION}\\\"
-DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/include\\\"\""
+include(../../shared/clang/clang_defines.pri)
HEADERS += \
$$PWD/clangrefactoringplugin.h
diff --git a/src/plugins/classview/classviewparser.cpp b/src/plugins/classview/classviewparser.cpp
index 4ab5d83750..7e4e4de283 100644
--- a/src/plugins/classview/classviewparser.cpp
+++ b/src/plugins/classview/classviewparser.cpp
@@ -718,7 +718,7 @@ QStringList Parser::projectNodeFileList(const FolderNode *node) const
return list;
QList<FileNode *> fileNodes = node->fileNodes();
- QList<FolderNode *> subFolderNodes = node->subFolderNodes();
+ QList<FolderNode *> subFolderNodes = node->folderNodes();
foreach (const FileNode *file, fileNodes) {
if (file->isGenerated())
@@ -728,7 +728,7 @@ QStringList Parser::projectNodeFileList(const FolderNode *node) const
}
foreach (const FolderNode *folder, subFolderNodes) {
- if (folder->nodeType() != FolderNodeType && folder->nodeType() != VirtualFolderNodeType)
+ if (folder->nodeType() != NodeType::Folder && folder->nodeType() != NodeType::VirtualFolder)
continue;
list << projectNodeFileList(folder);
}
@@ -768,7 +768,7 @@ QStringList Parser::addProjectNode(const ParserTreeItem::Ptr &item, const Projec
}
// subnodes
- QList<ProjectNode *> projectNodes = node->subProjectNodes();
+ QList<ProjectNode *> projectNodes = node->projectNodes();
foreach (const ProjectNode *project, projectNodes) {
ParserTreeItem::Ptr itemPrj(new ParserTreeItem());
@@ -804,7 +804,7 @@ QStringList Parser::getAllFiles(const ProjectNode *node)
d->cachedPrjFileLists[nodePath] = fileList;
}
// subnodes
- QList<ProjectNode *> projectNodes = node->subProjectNodes();
+ QList<ProjectNode *> projectNodes = node->projectNodes();
foreach (const ProjectNode *project, projectNodes)
fileList += getAllFiles(project);
diff --git a/src/plugins/clearcase/clearcasecontrol.cpp b/src/plugins/clearcase/clearcasecontrol.cpp
index 5c358082df..ef18e6d62d 100644
--- a/src/plugins/clearcase/clearcasecontrol.cpp
+++ b/src/plugins/clearcase/clearcasecontrol.cpp
@@ -49,6 +49,12 @@ Core::Id ClearCaseControl::id() const
return Constants::VCS_ID_CLEARCASE;
}
+bool ClearCaseControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ Q_UNUSED(fileName);
+ return false; // ClearCase has no files/directories littering the sources
+}
+
bool ClearCaseControl::isConfigured() const
{
#ifdef WITH_TESTS
diff --git a/src/plugins/clearcase/clearcasecontrol.h b/src/plugins/clearcase/clearcasecontrol.h
index fbcee6b88c..07648d4836 100644
--- a/src/plugins/clearcase/clearcasecontrol.h
+++ b/src/plugins/clearcase/clearcasecontrol.h
@@ -39,28 +39,30 @@ class ClearCaseControl : public Core::IVersionControl
Q_OBJECT
public:
explicit ClearCaseControl(ClearCasePlugin *plugin);
- QString displayName() const override;
- Core::Id id() const override;
+ QString displayName() const final;
+ Core::Id id() const final;
- bool managesDirectory(const QString &directory, QString *topLevel = 0) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
- bool isConfigured() const override;
+ bool managesDirectory(const QString &directory, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
- bool supportsOperation(Operation operation) const override;
- OpenSupportMode openSupportMode(const QString &fileName) const override;
- bool vcsOpen(const QString &fileName) override;
- SettingsFlags settingsFlags() const override;
- bool vcsAdd(const QString &fileName) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
+ bool isConfigured() const final;
- bool vcsAnnotate(const QString &file, int line) override;
+ bool supportsOperation(Operation operation) const final;
+ OpenSupportMode openSupportMode(const QString &fileName) const final;
+ bool vcsOpen(const QString &fileName) final;
+ SettingsFlags settingsFlags() const final;
+ bool vcsAdd(const QString &fileName) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
- QString vcsOpenText() const override;
- QString vcsMakeWritableText() const override;
- QString vcsTopic(const QString &directory) override;
+ bool vcsAnnotate(const QString &file, int line) final;
+
+ QString vcsOpenText() const final;
+ QString vcsMakeWritableText() const final;
+ QString vcsTopic(const QString &directory) final;
void emitRepositoryChanged(const QString &);
void emitFilesChanged(const QStringList &);
diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp
index 2351e6bbb2..ee1f1779bb 100644
--- a/src/plugins/clearcase/clearcaseplugin.cpp
+++ b/src/plugins/clearcase/clearcaseplugin.cpp
@@ -64,7 +64,6 @@
#include <vcsbase/basevcseditorfactory.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseeditor.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <vcsbase/vcsoutputwindow.h>
#include <vcsbase/vcsbasesubmiteditor.h>
diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp
index 3bc0ab684e..5c5314b31d 100644
--- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp
@@ -27,6 +27,7 @@
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include "cmakeparser.h"
+#include "cmakeprojectconstants.h"
#include "cmakeprojectmanager.h"
#include "cmakeprojectnodes.h"
#include "cmaketool.h"
@@ -36,6 +37,7 @@
#include <coreplugin/messagemanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
+#include <cpptools/cpptoolsconstants.h>
#include <cpptools/projectpartbuilder.h>
#include <projectexplorer/headerpath.h>
#include <projectexplorer/kit.h>
@@ -49,8 +51,10 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
+#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
+#include <utils/runextensions.h>
#include <utils/synchronousprocess.h>
#include <QDateTime>
@@ -63,43 +67,9 @@
using namespace ProjectExplorer;
-// --------------------------------------------------------------------
-// Helper:
-// --------------------------------------------------------------------
-
namespace CMakeProjectManager {
namespace Internal {
-static QStringList toArguments(const CMakeConfig &config, const Kit *k) {
- return Utils::transform(config, [k](const CMakeConfigItem &i) -> QString {
- QString a = QString::fromLatin1("-D");
- a.append(QString::fromUtf8(i.key));
- switch (i.type) {
- case CMakeConfigItem::FILEPATH:
- a.append(QLatin1String(":FILEPATH="));
- break;
- case CMakeConfigItem::PATH:
- a.append(QLatin1String(":PATH="));
- break;
- case CMakeConfigItem::BOOL:
- a.append(QLatin1String(":BOOL="));
- break;
- case CMakeConfigItem::STRING:
- a.append(QLatin1String(":STRING="));
- break;
- case CMakeConfigItem::INTERNAL:
- a.append(QLatin1String(":INTERNAL="));
- break;
- case CMakeConfigItem::STATIC:
- a.append(QLatin1String(":STATIC="));
- break;
- }
- a.append(i.expandedValue(k));
-
- return a;
- });
-}
-
// --------------------------------------------------------------------
// BuildDirManager:
// --------------------------------------------------------------------
@@ -108,65 +78,158 @@ BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) :
m_buildConfiguration(bc)
{
QTC_ASSERT(bc, return);
- m_projectName = sourceDirectory().fileName();
m_reparseTimer.setSingleShot(true);
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::parse);
- connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave,
- this, &BuildDirManager::handleDocumentSaves);
+
+ connect(&m_futureWatcher, &QFutureWatcher<QList<FileNode *>>::finished,
+ this, &BuildDirManager::emitDataAvailable);
}
-BuildDirManager::~BuildDirManager()
+BuildDirManager::~BuildDirManager() = default;
+
+const Utils::FileName BuildDirManager::workDirectory() const
{
- stopProcess();
- resetData();
- qDeleteAll(m_watchedFiles);
- delete m_tempDir;
+ const Utils::FileName bdir = m_buildConfiguration->buildDirectory();
+ if (bdir.exists())
+ return bdir;
+ if (!m_tempDir) {
+ const QString path = QDir::tempPath() + QLatin1String("/qtc-cmake-XXXXXX");
+ m_tempDir.reset(new QTemporaryDir(path));
+ if (!m_tempDir->isValid())
+ emit errorOccured(tr("Failed to create temporary directory using template \"%1\".").arg(path));
+ }
+ return Utils::FileName::fromString(m_tempDir->path());
}
-const Kit *BuildDirManager::kit() const
+void BuildDirManager::emitDataAvailable()
{
- return m_buildConfiguration->target()->kit();
+ if (!isParsing() && m_futureWatcher.isFinished())
+ emit dataAvailable();
}
-const Utils::FileName BuildDirManager::buildDirectory() const
+void BuildDirManager::updateReaderType(std::function<void()> todo)
{
- return m_buildConfiguration->buildDirectory();
+ BuildDirReader::Parameters p(m_buildConfiguration);
+ p.buildDirectory = workDirectory();
+
+ if (!m_reader || !m_reader->isCompatible(p)) {
+ m_reader.reset(BuildDirReader::createReader(p));
+ connect(m_reader.get(), &BuildDirReader::configurationStarted,
+ this, &BuildDirManager::configurationStarted);
+ connect(m_reader.get(), &BuildDirReader::dataAvailable,
+ this, &BuildDirManager::emitDataAvailable);
+ connect(m_reader.get(), &BuildDirReader::errorOccured,
+ this, &BuildDirManager::errorOccured);
+ connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty);
+ }
+ m_reader->setParameters(p);
+
+ if (m_reader->isReady())
+ todo();
+ else
+ connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo);
}
-const Utils::FileName BuildDirManager::workDirectory() const
+void BuildDirManager::updateReaderData()
{
- const Utils::FileName bdir = buildDirectory();
- if (bdir.exists())
- return bdir;
- if (m_tempDir)
- return Utils::FileName::fromString(m_tempDir->path());
- return bdir;
+ BuildDirReader::Parameters p(m_buildConfiguration);
+ p.buildDirectory = workDirectory();
+
+ m_reader->setParameters(p);
}
-const Utils::FileName BuildDirManager::sourceDirectory() const
+void BuildDirManager::parseOnceReaderReady(bool force)
{
- return m_buildConfiguration->target()->project()->projectDirectory();
+ m_futureInterface.reset(new QFutureInterface<QList<ProjectExplorer::FileNode *>>());
+ m_futureWatcher.setFuture(m_futureInterface->future());
+
+ Core::ProgressManager::addTask(m_futureInterface->future(), "Scan CMake project tree", "CMake.Scan.Tree");
+ Utils::runAsync([this]() { BuildDirManager::asyncScanForFiles(*m_futureInterface); });
+
+ checkConfiguration();
+ m_reader->stop();
+ m_reader->parse(force);
}
-const CMakeConfig BuildDirManager::intendedConfiguration() const
+void BuildDirManager::maybeForceReparseOnceReaderReady()
{
- return m_buildConfiguration->cmakeConfiguration();
+ checkConfiguration();
+
+ const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
+ const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
+ const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";
+
+ const QByteArrayList criticalKeys
+ = QByteArrayList() << GENERATOR_KEY << CMAKE_COMMAND_KEY;
+
+ const CMakeConfig currentConfig = parsedConfiguration();
+
+ Kit *k = m_buildConfiguration->target()->kit();
+ const CMakeTool *tool = CMakeKitInformation::cmakeTool(k);
+ QTC_ASSERT(tool, return); // No cmake... we should not have ended up here in the first place
+ const QString extraKitGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
+ const QString mainKitGenerator = CMakeGeneratorKitInformation::generator(k);
+ CMakeConfig targetConfig = m_buildConfiguration->cmakeConfiguration();
+ targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL,
+ QByteArray(), mainKitGenerator.toUtf8()));
+ if (!extraKitGenerator.isEmpty())
+ targetConfig.append(CMakeConfigItem(EXTRA_GENERATOR_KEY, CMakeConfigItem::INTERNAL,
+ QByteArray(), extraKitGenerator.toUtf8()));
+ targetConfig.append(CMakeConfigItem(CMAKE_COMMAND_KEY, CMakeConfigItem::INTERNAL,
+ QByteArray(), tool->cmakeExecutable().toUserOutput().toUtf8()));
+ Utils::sort(targetConfig, CMakeConfigItem::sortOperator());
+
+ bool mustReparse = false;
+ auto ccit = currentConfig.constBegin();
+ auto kcit = targetConfig.constBegin();
+
+ while (ccit != currentConfig.constEnd() && kcit != targetConfig.constEnd()) {
+ if (ccit->key == kcit->key) {
+ if (ccit->value != kcit->value) {
+ if (criticalKeys.contains(kcit->key)) {
+ clearCache();
+ return;
+ }
+ mustReparse = true;
+ }
+ ++ccit;
+ ++kcit;
+ } else {
+ if (ccit->key < kcit->key) {
+ ++ccit;
+ } else {
+ ++kcit;
+ mustReparse = true;
+ }
+ }
+ }
+
+ // If we have keys that do not exist yet, then reparse.
+ //
+ // The critical keys *must* be set in cmake configuration, so those were already
+ // handled above.
+ if (mustReparse || kcit != targetConfig.constEnd())
+ parseOnceReaderReady(true);
}
bool BuildDirManager::isParsing() const
{
- if (m_cmakeProcess)
- return m_cmakeProcess->state() != QProcess::NotRunning;
- return false;
+ return m_reader && m_reader->isParsing();
}
-void BuildDirManager::cmakeFilesChanged()
+void BuildDirManager::becameDirty()
{
if (isParsing())
return;
+ Target *t = m_buildConfiguration->target()->project()->activeTarget();
+ BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
+
+ if (bc != m_buildConfiguration)
+ return;
+
const CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
if (!tool->isAutoRun())
return;
@@ -174,28 +237,70 @@ void BuildDirManager::cmakeFilesChanged()
m_reparseTimer.start(1000);
}
+void BuildDirManager::asyncScanForFiles(QFutureInterface<QList<FileNode *> > &fi)
+{
+ fi.reportStarted();
+ Utils::MimeDatabase mdb;
+
+ QList<FileNode *> nodes
+ = FileNode::scanForFiles(m_buildConfiguration->target()->project()->projectDirectory(),
+ [&mdb](const Utils::FileName &fn) -> FileNode * {
+ QTC_ASSERT(!fn.isEmpty(), return nullptr);
+ const Utils::MimeType mimeType = mdb.mimeTypeForFile(fn.toString());
+ FileType type = FileType::Unknown;
+ if (mimeType.isValid()) {
+ const QString mt = mimeType.name();
+ if (mt == CppTools::Constants::C_SOURCE_MIMETYPE
+ || mt == CppTools::Constants::CPP_SOURCE_MIMETYPE
+ || mt == CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE
+ || mt == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE
+ || mt == CppTools::Constants::QDOC_MIMETYPE
+ || mt == CppTools::Constants::MOC_MIMETYPE)
+ type = FileType::Source;
+ else if (mt == CppTools::Constants::C_HEADER_MIMETYPE
+ || mt == CppTools::Constants::CPP_HEADER_MIMETYPE)
+ type = FileType::Header;
+ else if (mt == ProjectExplorer::Constants::FORM_MIMETYPE)
+ type = FileType::Form;
+ else if (mt == ProjectExplorer::Constants::RESOURCE_MIMETYPE)
+ type = FileType::Resource;
+ else if (mt == ProjectExplorer::Constants::SCXML_MIMETYPE)
+ type = FileType::StateChart;
+ else if (mt == CMakeProjectManager::Constants::CMAKEPROJECTMIMETYPE
+ || mt == CMakeProjectManager::Constants::CMAKEMIMETYPE)
+ type = FileType::Project;
+ else if (mt == ProjectExplorer::Constants::QML_MIMETYPE)
+ type = FileType::QML;
+ }
+ return new FileNode(fn, type, false);
+ },
+ &fi);
+ fi.setProgressValue(m_futureInterface->progressMaximum());
+ fi.reportResult(nodes);
+ fi.reportFinished();
+}
+
void BuildDirManager::forceReparse()
{
if (m_buildConfiguration->target()->activeBuildConfiguration() != m_buildConfiguration)
return;
- stopProcess();
-
- CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
+ CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
QTC_ASSERT(tool, return);
- startCMake(tool, CMakeGeneratorKitInformation::generatorArguments(kit()), intendedConfiguration());
+ m_reader.reset(); // Force reparse by forcing in a new reader
+ updateReaderType([this]() { parseOnceReaderReady(true); });
}
void BuildDirManager::resetData()
{
- m_hasData = false;
+ if (m_reader)
+ m_reader->resetData();
m_cmakeCache.clear();
- m_projectName.clear();
- m_buildTargets.clear();
- qDeleteAll(m_files);
- m_files.clear();
+ m_futureInterface.reset();
+
+ m_reader.reset(nullptr);
}
bool BuildDirManager::updateCMakeStateBeforeBuild()
@@ -208,115 +313,54 @@ bool BuildDirManager::persistCMakeState()
if (!m_tempDir)
return false;
- QDir dir(buildDirectory().toString());
- dir.mkpath(buildDirectory().toString());
+ const QString buildDir = m_buildConfiguration->buildDirectory().toString();
+ QDir dir(buildDir);
+ dir.mkpath(buildDir);
- delete m_tempDir;
- m_tempDir = nullptr;
+ m_tempDir.reset(nullptr);
- resetData();
QTimer::singleShot(0, this, &BuildDirManager::parse); // make sure signals only happen afterwards!
return true;
}
void BuildDirManager::generateProjectTree(CMakeProjectNode *root)
{
- root->setDisplayName(m_projectName);
-
- // Delete no longer necessary file watcher:
- const QSet<Utils::FileName> currentWatched
- = Utils::transform(m_watchedFiles, [](CMakeFile *cmf) { return cmf->filePath(); });
- const QSet<Utils::FileName> toWatch = m_cmakeFiles;
- QSet<Utils::FileName> toDelete = currentWatched;
- toDelete.subtract(toWatch);
- m_watchedFiles = Utils::filtered(m_watchedFiles, [&toDelete](Internal::CMakeFile *cmf) {
- if (toDelete.contains(cmf->filePath())) {
- delete cmf;
- return false;
- }
- return true;
- });
-
- // Add new file watchers:
- QSet<Utils::FileName> toAdd = toWatch;
- toAdd.subtract(currentWatched);
- foreach (const Utils::FileName &fn, toAdd) {
- CMakeFile *cm = new CMakeFile(this, fn);
- Core::DocumentManager::addDocument(cm);
- m_watchedFiles.insert(cm);
- }
+ QTC_ASSERT(m_reader, return);
+ QTC_ASSERT(m_futureInterface, return);
+
+ const Utils::FileName projectFile = m_buildConfiguration->target()->project()->projectFilePath();
+ QList<FileNode *> tmp = Utils::filtered(m_futureInterface->future().result(),
+ [projectFile](const FileNode *fn) -> bool {
+ const Utils::FileName &path = fn->filePath();
+ return path != projectFile && !path.toString().startsWith(projectFile.toString() + ".user");
+ });
+ Utils::sort(tmp, ProjectExplorer::Node::sortByPath);
+
+ m_futureInterface.reset(); // Make sure to flush the stale results
+
+ const QList<FileNode *> allFiles = tmp;
+ m_reader->generateProjectTree(root, allFiles);
+ QSet<FileNode *> usedNodes;
+ foreach (FileNode *fn, root->recursiveFileNodes())
+ usedNodes.insert(fn);
- QList<FileNode *> fileNodes = m_files;
- root->buildTree(fileNodes);
- m_files.clear(); // Some of the FileNodes in files() were deleted!
+ QList<FileNode *> leftOvers = Utils::filtered(allFiles, [&usedNodes](FileNode *fn) {
+ return !usedNodes.contains(fn);
+ });
+ qDeleteAll(leftOvers);
}
QSet<Core::Id> BuildDirManager::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
{
- QSet<Core::Id> languages;
- ToolChain *tc = ToolChainKitInformation::toolChain(kit(), ToolChain::Language::Cxx);
- const Utils::FileName sysroot = SysRootKitInformation::sysRoot(kit());
-
- QHash<QString, QStringList> targetDataCache;
- foreach (const CMakeBuildTarget &cbt, buildTargets()) {
- if (cbt.targetType == UtilityType)
- continue;
-
- // CMake shuffles the include paths that it reports via the CodeBlocks generator
- // So remove the toolchain include paths, so that at least those end up in the correct
- // place.
- QStringList cxxflags = getCXXFlagsFor(cbt, targetDataCache);
- QSet<QString> tcIncludes;
- foreach (const HeaderPath &hp, tc->systemHeaderPaths(cxxflags, sysroot))
- tcIncludes.insert(hp.path());
- QStringList includePaths;
- foreach (const QString &i, cbt.includeFiles) {
- if (!tcIncludes.contains(i))
- includePaths.append(i);
- }
- includePaths += buildDirectory().toString();
- ppBuilder.setIncludePaths(includePaths);
- ppBuilder.setCFlags(cxxflags);
- ppBuilder.setCxxFlags(cxxflags);
- ppBuilder.setDefines(cbt.defines);
- ppBuilder.setDisplayName(cbt.title);
-
- const QSet<Core::Id> partLanguages
- = QSet<Core::Id>::fromList(ppBuilder.createProjectPartsForFiles(cbt.files));
-
- languages.unite(partLanguages);
- }
- return languages;
+ QTC_ASSERT(m_reader, return QSet<Core::Id>());
+ return m_reader->updateCodeModel(ppBuilder);
}
void BuildDirManager::parse()
{
- checkConfiguration();
-
- CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
- const QStringList generatorArgs = CMakeGeneratorKitInformation::generatorArguments(kit());
-
- QTC_ASSERT(tool, return);
-
- const QString cbpFile = CMakeManager::findCbpFile(QDir(workDirectory().toString()));
- const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile);
- if (!cbpFileFi.exists()) {
- // Initial create:
- startCMake(tool, generatorArgs, intendedConfiguration());
- return;
- }
+ TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
- const bool mustUpdate = m_cmakeFiles.isEmpty()
- || Utils::anyOf(m_cmakeFiles, [&cbpFileFi](const Utils::FileName &f) {
- return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
- });
- if (mustUpdate) {
- startCMake(tool, generatorArgs, CMakeConfig());
- } else {
- extractData();
- m_hasData = true;
- emit dataAvailable();
- }
+ updateReaderType([this]() { parseOnceReaderReady(false); });
}
void BuildDirManager::clearCache()
@@ -336,367 +380,34 @@ void BuildDirManager::clearCache()
QList<CMakeBuildTarget> BuildDirManager::buildTargets() const
{
- return m_buildTargets;
+ if (!m_reader)
+ return QList<CMakeBuildTarget>();
+ return m_reader->buildTargets();
}
CMakeConfig BuildDirManager::parsedConfiguration() const
{
- if (m_cmakeCache.isEmpty()) {
- Utils::FileName cacheFile = workDirectory();
- cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
- if (!cacheFile.exists())
- return m_cmakeCache;
- QString errorMessage;
- m_cmakeCache = parseConfiguration(cacheFile, &errorMessage);
- if (!errorMessage.isEmpty())
- emit errorOccured(errorMessage);
- const Utils::FileName sourceOfBuildDir
- = Utils::FileName::fromUtf8(CMakeConfigItem::valueOf("CMAKE_HOME_DIRECTORY", m_cmakeCache));
- const Utils::FileName canonicalSourceOfBuildDir = Utils::FileUtils::canonicalPath(sourceOfBuildDir);
- const Utils::FileName canonicalSourceDirectory = Utils::FileUtils::canonicalPath(sourceDirectory());
- if (canonicalSourceOfBuildDir != canonicalSourceDirectory) // Uses case-insensitive compare where appropriate
- emit errorOccured(tr("The build directory is not for %1 but for %2")
- .arg(canonicalSourceOfBuildDir.toUserOutput(),
- canonicalSourceDirectory.toUserOutput()));
- }
+ if (!m_reader)
+ return m_cmakeCache;
+ if (m_cmakeCache.isEmpty())
+ m_cmakeCache = m_reader->parsedConfiguration();
return m_cmakeCache;
}
-void BuildDirManager::stopProcess()
-{
- if (!m_cmakeProcess)
- return;
-
- m_cmakeProcess->disconnect();
-
- if (m_cmakeProcess->state() == QProcess::Running) {
- m_cmakeProcess->terminate();
- if (!m_cmakeProcess->waitForFinished(500) && m_cmakeProcess->state() == QProcess::Running)
- m_cmakeProcess->kill();
- }
-
- cleanUpProcess();
-
- if (!m_future)
- return;
- m_future->reportCanceled();
- m_future->reportFinished();
- delete m_future;
- m_future = nullptr;
-}
-
-void BuildDirManager::cleanUpProcess()
-{
- if (!m_cmakeProcess)
- return;
-
- QTC_ASSERT(m_cmakeProcess->state() == QProcess::NotRunning, return);
-
- m_cmakeProcess->disconnect();
-
- if (m_cmakeProcess->state() == QProcess::Running) {
- m_cmakeProcess->terminate();
- if (!m_cmakeProcess->waitForFinished(500) && m_cmakeProcess->state() == QProcess::Running)
- m_cmakeProcess->kill();
- }
- m_cmakeProcess->waitForFinished();
- delete m_cmakeProcess;
- m_cmakeProcess = nullptr;
-
- // Delete issue parser:
- m_parser->flush();
- delete m_parser;
- m_parser = nullptr;
-}
-
-void BuildDirManager::extractData()
-{
- const Utils::FileName topCMake
- = Utils::FileName::fromString(sourceDirectory().toString() + QLatin1String("/CMakeLists.txt"));
-
- resetData();
-
- m_projectName = sourceDirectory().fileName();
- m_files.append(new FileNode(topCMake, ProjectFileType, false));
- // Do not insert topCMake into m_cmakeFiles: The project already watches that!
-
- // Find cbp file
- QString cbpFile = CMakeManager::findCbpFile(workDirectory().toString());
- if (cbpFile.isEmpty())
- return;
- m_cmakeFiles.insert(Utils::FileName::fromString(cbpFile));
-
- // Add CMakeCache.txt file:
- Utils::FileName cacheFile = workDirectory();
- cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
- if (cacheFile.toFileInfo().exists())
- m_cmakeFiles.insert(cacheFile);
-
- // setFolderName
- CMakeCbpParser cbpparser;
- // Parsing
- if (!cbpparser.parseCbpFile(kit(), cbpFile, sourceDirectory().toString()))
- return;
-
- m_projectName = cbpparser.projectName();
-
- m_files = cbpparser.fileList();
- if (cbpparser.hasCMakeFiles()) {
- m_files.append(cbpparser.cmakeFileList());
- foreach (const FileNode *node, cbpparser.cmakeFileList())
- m_cmakeFiles.insert(node->filePath());
- }
-
- // Make sure the top cmakelists.txt file is always listed:
- if (!Utils::contains(m_files, [topCMake](FileNode *fn) { return fn->filePath() == topCMake; })) {
- m_files.append(new FileNode(topCMake, ProjectFileType, false));
- }
-
- m_buildTargets = cbpparser.buildTargets();
-}
-
-void BuildDirManager::startCMake(CMakeTool *tool, const QStringList &generatorArgs,
- const CMakeConfig &config)
-{
- QTC_ASSERT(tool && tool->isValid(), return);
-
- QTC_ASSERT(!m_cmakeProcess, return);
- QTC_ASSERT(!m_parser, return);
- QTC_ASSERT(!m_future, return);
-
- // Find a directory to set up into:
- if (!buildDirectory().exists()) {
- if (!m_tempDir)
- m_tempDir = new QTemporaryDir(QDir::tempPath() + QLatin1String("/qtc-cmake-XXXXXX"));
- QTC_ASSERT(m_tempDir->isValid(), return);
- }
-
- // Make sure work directory exists:
- QTC_ASSERT(workDirectory().exists(), return);
-
- m_parser = new CMakeParser;
- QDir source = QDir(sourceDirectory().toString());
- connect(m_parser, &IOutputParser::addTask, m_parser,
- [source](const Task &task) {
- if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) {
- TaskHub::addTask(task);
- } else {
- Task t = task;
- t.file = Utils::FileName::fromString(source.absoluteFilePath(task.file.toString()));
- TaskHub::addTask(t);
- }
- });
-
- // Always use the sourceDir: If we are triggered because the build directory is getting deleted
- // then we are racing against CMakeCache.txt also getting deleted.
- const QString srcDir = sourceDirectory().toString();
-
- m_cmakeProcess = new Utils::QtcProcess(this);
- m_cmakeProcess->setWorkingDirectory(workDirectory().toString());
- m_cmakeProcess->setEnvironment(m_buildConfiguration->environment());
-
- connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
- this, &BuildDirManager::processCMakeOutput);
- connect(m_cmakeProcess, &QProcess::readyReadStandardError,
- this, &BuildDirManager::processCMakeError);
- connect(m_cmakeProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
- this, &BuildDirManager::cmakeFinished);
-
- QString args;
- Utils::QtcProcess::addArg(&args, srcDir);
- Utils::QtcProcess::addArgs(&args, generatorArgs);
- Utils::QtcProcess::addArgs(&args, toArguments(config, kit()));
-
- TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
-
- Core::MessageManager::write(tr("Running \"%1 %2\" in %3.")
- .arg(tool->cmakeExecutable().toUserOutput())
- .arg(args)
- .arg(workDirectory().toUserOutput()));
-
- m_future = new QFutureInterface<void>();
- m_future->setProgressRange(0, 1);
- Core::ProgressManager::addTask(m_future->future(),
- tr("Configuring \"%1\"").arg(m_buildConfiguration->target()->project()->displayName()),
- "CMake.Configure");
-
- m_cmakeProcess->setCommand(tool->cmakeExecutable().toString(), args);
- m_cmakeProcess->start();
- emit configurationStarted();
-}
-
-void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
-{
- QTC_ASSERT(m_cmakeProcess, return);
-
- // process rest of the output:
- processCMakeOutput();
- processCMakeError();
-
- cleanUpProcess();
-
- extractData(); // try even if cmake failed...
-
- QString msg;
- if (status != QProcess::NormalExit)
- msg = tr("*** cmake process crashed.");
- else if (code != 0)
- msg = tr("*** cmake process exited with exit code %1.").arg(code);
-
- if (!msg.isEmpty()) {
- Core::MessageManager::write(msg);
- TaskHub::addTask(Task::Error, msg, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
- m_future->reportCanceled();
- } else {
- m_future->setProgressValue(1);
- }
-
- m_future->reportFinished();
- delete m_future;
- m_future = nullptr;
-
- m_hasData = true;
- emit dataAvailable();
-}
-
-static QString lineSplit(const QString &rest, const QByteArray &array, std::function<void(const QString &)> f)
-{
- QString tmp = rest + Utils::SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(array));
- int start = 0;
- int end = tmp.indexOf(QLatin1Char('\n'), start);
- while (end >= 0) {
- f(tmp.mid(start, end - start));
- start = end + 1;
- end = tmp.indexOf(QLatin1Char('\n'), start);
- }
- return tmp.mid(start);
-}
-
-void BuildDirManager::processCMakeOutput()
-{
- static QString rest;
- rest = lineSplit(rest, m_cmakeProcess->readAllStandardOutput(), [this](const QString &s) { Core::MessageManager::write(s); });
-}
-
-void BuildDirManager::processCMakeError()
-{
- static QString rest;
- rest = lineSplit(rest, m_cmakeProcess->readAllStandardError(), [this](const QString &s) {
- m_parser->stdError(s);
- Core::MessageManager::write(s);
- });
-}
-
-QStringList BuildDirManager::getCXXFlagsFor(const CMakeBuildTarget &buildTarget,
- QHash<QString, QStringList> &cache)
-{
- // check cache:
- auto it = cache.constFind(buildTarget.title);
- if (it != cache.constEnd())
- return *it;
-
- if (extractCXXFlagsFromMake(buildTarget, cache))
- return cache.value(buildTarget.title);
-
- if (extractCXXFlagsFromNinja(buildTarget, cache))
- return cache.value(buildTarget.title);
-
- cache.insert(buildTarget.title, QStringList());
- return QStringList();
-}
-
-bool BuildDirManager::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget,
- QHash<QString, QStringList> &cache)
-{
- QString makeCommand = QDir::fromNativeSeparators(buildTarget.makeCommand);
- int startIndex = makeCommand.indexOf('\"');
- int endIndex = makeCommand.indexOf('\"', startIndex + 1);
- if (startIndex != -1 && endIndex != -1) {
- startIndex += 1;
- QString makefile = makeCommand.mid(startIndex, endIndex - startIndex);
- int slashIndex = makefile.lastIndexOf('/');
- makefile.truncate(slashIndex);
- makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
- QFile file(makefile);
- if (file.exists()) {
- file.open(QIODevice::ReadOnly | QIODevice::Text);
- QTextStream stream(&file);
- while (!stream.atEnd()) {
- QString line = stream.readLine().trimmed();
- if (line.startsWith("CXX_FLAGS =")) {
- // Skip past =
- cache.insert(buildTarget.title,
- line.mid(11).trimmed().split(' ', QString::SkipEmptyParts));
- return true;
- }
- }
- }
- }
- return false;
-}
-
-bool BuildDirManager::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget,
- QHash<QString, QStringList> &cache)
-{
- Q_UNUSED(buildTarget)
- if (!cache.isEmpty()) // We fill the cache in one go!
- return false;
-
- // Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS) from there if no suitable flags.make were
- // found
- // Get "all" target's working directory
- QByteArray ninjaFile;
- QString buildNinjaFile = QDir::fromNativeSeparators(buildTargets().at(0).workingDirectory);
- buildNinjaFile += "/build.ninja";
- QFile buildNinja(buildNinjaFile);
- if (buildNinja.exists()) {
- buildNinja.open(QIODevice::ReadOnly | QIODevice::Text);
- ninjaFile = buildNinja.readAll();
- buildNinja.close();
- }
-
- if (ninjaFile.isEmpty())
- return false;
-
- QTextStream stream(ninjaFile);
- bool cxxFound = false;
- const QString targetSignature = "# Object build statements for ";
- QString currentTarget;
-
- while (!stream.atEnd()) {
- // 1. Look for a block that refers to the current target
- // 2. Look for a build rule which invokes CXX_COMPILER
- // 3. Return the FLAGS definition
- QString line = stream.readLine().trimmed();
- if (line.startsWith('#')) {
- if (line.startsWith(targetSignature)) {
- int pos = line.lastIndexOf(' ');
- currentTarget = line.mid(pos + 1);
- }
- } else if (!currentTarget.isEmpty() && line.startsWith("build")) {
- cxxFound = line.indexOf("CXX_COMPILER") != -1;
- } else if (cxxFound && line.startsWith("FLAGS =")) {
- // Skip past =
- cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
- }
- }
- return !cache.isEmpty();
-}
-
void BuildDirManager::checkConfiguration()
{
if (m_tempDir) // always throw away changes in the tmpdir!
return;
Kit *k = m_buildConfiguration->target()->kit();
- const CMakeConfig cache = parsedConfiguration();
+ const CMakeConfig cache = m_reader->parsedConfiguration();
if (cache.isEmpty())
return; // No cache file yet.
CMakeConfig newConfig;
QSet<QString> changedKeys;
QSet<QString> removedKeys;
- foreach (const CMakeConfigItem &iBc, intendedConfiguration()) {
+ foreach (const CMakeConfigItem &iBc, m_buildConfiguration->cmakeConfiguration()) {
const CMakeConfigItem &iCache
= Utils::findOrDefault(cache, [&iBc](const CMakeConfigItem &i) { return i.key == iBc.key; });
if (iCache.isNull()) {
@@ -729,194 +440,26 @@ void BuildDirManager::checkConfiguration()
QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow());
box->setText(tr("CMake configuration has changed on disk."));
box->setInformativeText(tr("The CMakeCache.txt file has changed: %1").arg(table));
- box->setStandardButtons(QMessageBox::Discard | QMessageBox::Apply);
- box->setDefaultButton(QMessageBox::Discard);
+ auto *defaultButton = box->addButton(tr("Overwrite Changes in CMake"), QMessageBox::RejectRole);
+ box->addButton(tr("Apply Changes to Project"), QMessageBox::AcceptRole);
+ box->setDefaultButton(defaultButton);
int ret = box->exec();
- if (ret == QMessageBox::Apply)
+ if (ret == QMessageBox::Apply) {
m_buildConfiguration->setCMakeConfiguration(newConfig);
- }
-}
-
-void BuildDirManager::handleDocumentSaves(Core::IDocument *document)
-{
- CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
- if (!m_cmakeFiles.contains(document->filePath()) || !tool || !tool->isAutoRun())
- return;
-
- m_reparseTimer.start(100);
-}
-
-static QByteArray trimCMakeCacheLine(const QByteArray &in) {
- int start = 0;
- while (start < in.count() && (in.at(start) == ' ' || in.at(start) == '\t'))
- ++start;
-
- return in.mid(start, in.count() - start - 1);
-}
-
-static QByteArrayList splitCMakeCacheLine(const QByteArray &line) {
- const int colonPos = line.indexOf(':');
- if (colonPos < 0)
- return QByteArrayList();
-
- const int equalPos = line.indexOf('=', colonPos + 1);
- if (equalPos < colonPos)
- return QByteArrayList();
-
- return QByteArrayList() << line.mid(0, colonPos)
- << line.mid(colonPos + 1, equalPos - colonPos - 1)
- << line.mid(equalPos + 1);
-}
-
-static CMakeConfigItem::Type fromByteArray(const QByteArray &type) {
- if (type == "BOOL")
- return CMakeConfigItem::BOOL;
- if (type == "STRING")
- return CMakeConfigItem::STRING;
- if (type == "FILEPATH")
- return CMakeConfigItem::FILEPATH;
- if (type == "PATH")
- return CMakeConfigItem::PATH;
- QTC_CHECK(type == "INTERNAL" || type == "STATIC");
-
- return CMakeConfigItem::INTERNAL;
-}
-
-CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile,
- QString *errorMessage)
-{
- CMakeConfig result;
- QFile cache(cacheFile.toString());
- if (!cache.open(QIODevice::ReadOnly | QIODevice::Text)) {
- if (errorMessage)
- *errorMessage = tr("Failed to open %1 for reading.").arg(cacheFile.toUserOutput());
- return CMakeConfig();
- }
-
- QSet<QByteArray> advancedSet;
- QMap<QByteArray, QByteArray> valuesMap;
- QByteArray documentation;
- while (!cache.atEnd()) {
- const QByteArray line = trimCMakeCacheLine(cache.readLine());
-
- if (line.isEmpty() || line.startsWith('#'))
- continue;
-
- if (line.startsWith("//")) {
- documentation = line.mid(2);
- continue;
- }
-
- const QByteArrayList pieces = splitCMakeCacheLine(line);
- if (pieces.isEmpty())
- continue;
-
- QTC_ASSERT(pieces.count() == 3, continue);
- const QByteArray key = pieces.at(0);
- const QByteArray type = pieces.at(1);
- const QByteArray value = pieces.at(2);
-
- if (key.endsWith("-ADVANCED") && value == "1") {
- advancedSet.insert(key.left(key.count() - 9 /* "-ADVANCED" */));
- } else if (key.endsWith("-STRINGS") && fromByteArray(type) == CMakeConfigItem::INTERNAL) {
- valuesMap[key.left(key.count() - 8) /* "-STRINGS" */] = value;
- } else {
- CMakeConfigItem::Type t = fromByteArray(type);
- result << CMakeConfigItem(key, t, documentation, value);
+ updateReaderData(); // Apply changes to reader
}
}
-
- // Set advanced flags:
- for (int i = 0; i < result.count(); ++i) {
- CMakeConfigItem &item = result[i];
- item.isAdvanced = advancedSet.contains(item.key);
-
- if (valuesMap.contains(item.key)) {
- item.values = CMakeConfigItem::cmakeSplitValue(QString::fromUtf8(valuesMap[item.key]));
- } else if (item.key == "CMAKE_BUILD_TYPE") {
- // WA for known options
- item.values << "" << "Debug" << "Release" << "MinSizeRel" << "RelWithDebInfo";
- }
- }
-
- Utils::sort(result, CMakeConfigItem::sortOperator());
-
- return result;
-}
-
-void BuildDirManager::handleCmakeFileChange()
-{
- Target *t = m_buildConfiguration->target()->project()->activeTarget();
- BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
-
- if (m_buildConfiguration->target() == t && m_buildConfiguration == bc)
- cmakeFilesChanged();
}
void BuildDirManager::maybeForceReparse()
{
- checkConfiguration();
-
- const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
- const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
- const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";
-
- const QByteArrayList criticalKeys
- = QByteArrayList() << GENERATOR_KEY << CMAKE_COMMAND_KEY;
-
- if (!m_hasData) {
+ if (!m_reader || !m_reader->hasData()) {
forceReparse();
return;
}
- const CMakeConfig currentConfig = parsedConfiguration();
-
- const CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
- QTC_ASSERT(tool, return); // No cmake... we should not have ended up here in the first place
- const QString extraKitGenerator = CMakeGeneratorKitInformation::extraGenerator(kit());
- const QString mainKitGenerator = CMakeGeneratorKitInformation::generator(kit());
- CMakeConfig targetConfig = m_buildConfiguration->cmakeConfiguration();
- targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL,
- QByteArray(), mainKitGenerator.toUtf8()));
- if (!extraKitGenerator.isEmpty())
- targetConfig.append(CMakeConfigItem(EXTRA_GENERATOR_KEY, CMakeConfigItem::INTERNAL,
- QByteArray(), extraKitGenerator.toUtf8()));
- targetConfig.append(CMakeConfigItem(CMAKE_COMMAND_KEY, CMakeConfigItem::INTERNAL,
- QByteArray(), tool->cmakeExecutable().toUserOutput().toUtf8()));
- Utils::sort(targetConfig, CMakeConfigItem::sortOperator());
-
- bool mustReparse = false;
- auto ccit = currentConfig.constBegin();
- auto kcit = targetConfig.constBegin();
-
- while (ccit != currentConfig.constEnd() && kcit != targetConfig.constEnd()) {
- if (ccit->key == kcit->key) {
- if (ccit->value != kcit->value) {
- if (criticalKeys.contains(kcit->key)) {
- clearCache();
- return;
- }
- mustReparse = true;
- }
- ++ccit;
- ++kcit;
- } else {
- if (ccit->key < kcit->key) {
- ++ccit;
- } else {
- ++kcit;
- mustReparse = true;
- }
- }
- }
-
- // If we have keys that do not exist yet, then reparse.
- //
- // The critical keys *must* be set in cmake configuration, so those were already
- // handled above.
- if (mustReparse || kcit != targetConfig.constEnd())
- forceReparse();
+ updateReaderType([this]() { maybeForceReparseOnceReaderReady(); });
}
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h
index ec26d0c3bb..3d3a98411b 100644
--- a/src/plugins/cmakeprojectmanager/builddirmanager.h
+++ b/src/plugins/cmakeprojectmanager/builddirmanager.h
@@ -25,26 +25,19 @@
#pragma once
-#include "cmakecbpparser.h"
+#include "builddirreader.h"
#include "cmakeconfigitem.h"
-#include "cmakefile.h"
-#include <projectexplorer/task.h>
-
-#include <utils/environment.h>
-#include <utils/qtcprocess.h>
#include <utils/fileutils.h>
-#include <QByteArray>
-#include <QFutureInterface>
+#include <QFutureWatcher>
#include <QObject>
-#include <QSet>
+#include <QTemporaryDir>
#include <QTimer>
-QT_FORWARD_DECLARE_CLASS(QTemporaryDir);
-QT_FORWARD_DECLARE_CLASS(QFileSystemWatcher);
+#include <functional>
+#include <memory>
-namespace Core { class IDocument; }
namespace CppTools { class ProjectPartBuilder; }
namespace ProjectExplorer {
@@ -68,11 +61,10 @@ class BuildDirManager : public QObject
public:
BuildDirManager(CMakeBuildConfiguration *bc);
- ~BuildDirManager() override;
+ ~BuildDirManager() final;
bool isParsing() const;
- void parse();
void clearCache();
void forceReparse();
void maybeForceReparse(); // Only reparse if the configuration has changed...
@@ -86,11 +78,6 @@ public:
QList<CMakeBuildTarget> buildTargets() const;
CMakeConfig parsedConfiguration() const;
- void checkConfiguration();
-
- void handleDocumentSaves(Core::IDocument *document);
- void handleCmakeFileChange();
-
signals:
void configurationStarted() const;
void dataAvailable() const;
@@ -100,48 +87,33 @@ protected:
static CMakeConfig parseConfiguration(const Utils::FileName &cacheFile,
QString *errorMessage);
- const ProjectExplorer::Kit *kit() const;
- const Utils::FileName buildDirectory() const;
const Utils::FileName workDirectory() const;
- const Utils::FileName sourceDirectory() const;
- const CMakeConfig intendedConfiguration() const;
private:
- void cmakeFilesChanged();
+ void emitDataAvailable();
+ void checkConfiguration();
- void stopProcess();
- void cleanUpProcess();
- void extractData();
+ void updateReaderType(std::function<void()> todo);
+ void updateReaderData();
- void startCMake(CMakeTool *tool, const QStringList &generatorArgs, const CMakeConfig &config);
+ void parseOnceReaderReady(bool force);
+ void maybeForceReparseOnceReaderReady();
- void cmakeFinished(int code, QProcess::ExitStatus status);
- void processCMakeOutput();
- void processCMakeError();
+ void parse();
- QStringList getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
- bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
- bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
+ void becameDirty();
- bool m_hasData = false;
+ void asyncScanForFiles(QFutureInterface<QList<ProjectExplorer::FileNode*>> &fi);
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
- Utils::QtcProcess *m_cmakeProcess = nullptr;
- QTemporaryDir *m_tempDir = nullptr;
+ mutable std::unique_ptr<QTemporaryDir> m_tempDir = nullptr;
mutable CMakeConfig m_cmakeCache;
- QSet<Utils::FileName> m_cmakeFiles;
- QString m_projectName;
- QList<CMakeBuildTarget> m_buildTargets;
- QList<ProjectExplorer::FileNode *> m_files;
-
- // For error reporting:
- ProjectExplorer::IOutputParser *m_parser = nullptr;
- QFutureInterface<void> *m_future = nullptr;
-
QTimer m_reparseTimer;
- QSet<Internal::CMakeFile *> m_watchedFiles;
+ std::unique_ptr<BuildDirReader> m_reader;
+ std::unique_ptr<QFutureInterface<QList<ProjectExplorer::FileNode*>>> m_futureInterface;
+ QFutureWatcher<QList<ProjectExplorer::FileNode*>> m_futureWatcher;
};
} // namespace Internal
diff --git a/src/plugins/cmakeprojectmanager/builddirreader.cpp b/src/plugins/cmakeprojectmanager/builddirreader.cpp
new file mode 100644
index 0000000000..741ddc2da4
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/builddirreader.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "builddirreader.h"
+
+#include "cmakebuildconfiguration.h"
+#include "cmakekitinformation.h"
+#include "servermodereader.h"
+#include "tealeafreader.h"
+
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/target.h>
+
+using namespace ProjectExplorer;
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+// --------------------------------------------------------------------
+// BuildDirReader:
+// --------------------------------------------------------------------
+
+BuildDirReader::Parameters::Parameters() = default;
+
+BuildDirReader::Parameters::Parameters(const CMakeBuildConfiguration *bc)
+{
+ const ProjectExplorer::Kit *k = bc->target()->kit();
+
+ projectName = bc->target()->project()->displayName();
+
+ sourceDirectory = bc->target()->project()->projectDirectory();
+ buildDirectory = bc->buildDirectory();
+
+ environment = bc->environment();
+
+ CMakeTool *cmake = CMakeKitInformation::cmakeTool(k);
+ cmakeVersion = cmake->version();
+ cmakeHasServerMode = cmake->hasServerMode();
+ cmakeExecutable = cmake->cmakeExecutable();
+
+ pathMapper = cmake->pathMapper();
+ isAutorun = cmake->isAutoRun();
+
+ auto tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::ToolChain::Language::Cxx);
+ if (tc)
+ toolChainId = tc->id();
+ sysRoot = ProjectExplorer::SysRootKitInformation::sysRoot(k);
+
+ expander = k->macroExpander();
+
+ configuration = bc->cmakeConfiguration();
+
+ generator = CMakeGeneratorKitInformation::generator(k);
+ extraGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
+ platform = CMakeGeneratorKitInformation::platform(k);
+ toolset = CMakeGeneratorKitInformation::toolset(k);
+ generatorArguments = CMakeGeneratorKitInformation::generatorArguments(k);
+}
+
+BuildDirReader::Parameters::Parameters(const BuildDirReader::Parameters &other) = default;
+
+
+BuildDirReader *BuildDirReader::createReader(const BuildDirReader::Parameters &p)
+{
+ if (p.cmakeHasServerMode)
+ return new ServerModeReader;
+ return new TeaLeafReader;
+}
+
+void BuildDirReader::setParameters(const BuildDirReader::Parameters &p)
+{
+ m_parameters = p;
+}
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/builddirreader.h b/src/plugins/cmakeprojectmanager/builddirreader.h
new file mode 100644
index 0000000000..db0a5bfc46
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/builddirreader.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "cmakeconfigitem.h"
+#include "cmakeproject.h"
+#include "cmaketool.h"
+
+#include <utils/environment.h>
+#include <utils/fileutils.h>
+#include <utils/macroexpander.h>
+
+#include <QFutureInterface>
+#include <QObject>
+
+namespace CppTools { class ProjectPartBuilder; }
+
+namespace ProjectExplorer {
+class IOutputParser;
+class Kit;
+} // ProjectExplorer
+
+namespace Utils { class QtcProcess; }
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class CMakeBuildConfiguration;
+
+class BuildDirReader : public QObject
+{
+ Q_OBJECT
+
+public:
+ struct Parameters {
+ Parameters();
+ Parameters(const CMakeBuildConfiguration *bc);
+ Parameters(const Parameters &other);
+
+ QString projectName;
+
+ Utils::FileName sourceDirectory;
+ Utils::FileName buildDirectory;
+ Utils::Environment environment;
+ Utils::FileName cmakeExecutable;
+ CMakeTool::Version cmakeVersion;
+ bool cmakeHasServerMode;
+ CMakeTool::PathMapper pathMapper;
+
+ QByteArray toolChainId;
+
+ Utils::FileName sysRoot;
+
+ Utils::MacroExpander *expander = nullptr;
+
+ CMakeConfig configuration;
+
+ QString generator;
+ QString extraGenerator;
+ QString platform;
+ QString toolset;
+ QStringList generatorArguments;
+ bool isAutorun = false;
+ };
+
+ static BuildDirReader *createReader(const BuildDirReader::Parameters &p);
+ virtual void setParameters(const Parameters &p);
+
+ virtual bool isCompatible(const Parameters &p) = 0;
+ virtual void resetData() = 0;
+ virtual void parse(bool force) = 0;
+ virtual void stop() = 0;
+
+ virtual bool isReady() const { return true; }
+ virtual bool isParsing() const = 0;
+ virtual bool hasData() const = 0;
+
+ virtual CMakeConfig parsedConfiguration() const = 0;
+ virtual QList<CMakeBuildTarget> buildTargets() const = 0;
+ virtual void generateProjectTree(CMakeProjectNode *root,
+ const QList<ProjectExplorer::FileNode *> &allFiles) = 0;
+ virtual QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) = 0;
+
+signals:
+ void isReadyNow() const;
+ void configurationStarted() const;
+ void dataAvailable() const;
+ void dirty() const;
+ void errorOccured(const QString &message) const;
+
+protected:
+ Parameters m_parameters;
+};
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index c5d6bdafc4..34dac4e1d6 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -139,17 +139,17 @@ void CMakeBuildConfiguration::ctor()
target()->kit(),
displayName(), BuildConfiguration::Unknown));
- connect(m_buildDirManager, &BuildDirManager::dataAvailable,
+ connect(m_buildDirManager.get(), &BuildDirManager::dataAvailable,
this, &CMakeBuildConfiguration::dataAvailable);
- connect(m_buildDirManager, &BuildDirManager::errorOccured,
+ connect(m_buildDirManager.get(), &BuildDirManager::errorOccured,
this, &CMakeBuildConfiguration::setError);
- connect(m_buildDirManager, &BuildDirManager::configurationStarted,
+ connect(m_buildDirManager.get(), &BuildDirManager::configurationStarted,
this, [this]() { m_completeConfigurationCache.clear(); emit parsingStarted(); });
connect(this, &CMakeBuildConfiguration::environmentChanged,
- m_buildDirManager, &BuildDirManager::forceReparse);
+ m_buildDirManager.get(), &BuildDirManager::forceReparse);
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged,
- m_buildDirManager, &BuildDirManager::forceReparse);
+ m_buildDirManager.get(), &BuildDirManager::forceReparse);
connect(this, &CMakeBuildConfiguration::parsingStarted, project, &CMakeProject::handleParsingStarted);
connect(this, &CMakeBuildConfiguration::dataAvailable, project, &CMakeProject::updateProjectData);
@@ -185,7 +185,6 @@ void CMakeBuildConfiguration::runCMake()
if (!m_buildDirManager || m_buildDirManager->isParsing())
return;
- m_buildDirManager->checkConfiguration();
m_buildDirManager->forceReparse();
}
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
index 2fa82cb7d5..a4cf71d12e 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
@@ -32,6 +32,8 @@
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/abi.h>
+#include <memory>
+
namespace CppTools { class ProjectPartBuilder; }
namespace ProjectExplorer { class ToolChain; }
@@ -114,7 +116,7 @@ private:
mutable QList<CMakeConfigItem> m_completeConfigurationCache;
- BuildDirManager *const m_buildDirManager = nullptr;
+ std::unique_ptr<BuildDirManager> m_buildDirManager;
friend class CMakeBuildSettingsWidget;
friend class CMakeProjectManager::CMakeProject;
diff --git a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
index 9b8a5179ba..0895bd8999 100644
--- a/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakecbpparser.cpp
@@ -45,13 +45,13 @@ namespace Internal {
////
namespace {
-int distance(const QString &targetDirectory, const FileName &fileName)
+int distance(const FileName &targetDirectory, const FileName &fileName)
{
- const QString commonParent = Utils::commonPath(QStringList() << targetDirectory << fileName.toString());
- return targetDirectory.mid(commonParent.size()).count(QLatin1Char('/'))
- + fileName.toString().mid(commonParent.size()).count(QLatin1Char('/'));
-}
+ const QString commonParent = commonPath(QStringList({ targetDirectory.toString(), fileName.toString() }));
+ return targetDirectory.toString().mid(commonParent.size()).count('/')
+ + fileName.toString().mid(commonParent.size()).count('/');
}
+} // namespace
// called after everything is parsed
// this function tries to figure out to which CMakeBuildTarget
@@ -60,10 +60,9 @@ int distance(const QString &targetDirectory, const FileName &fileName)
void CMakeCbpParser::sortFiles()
{
QLoggingCategory log("qtc.cmakeprojectmanager.filetargetmapping");
- FileNameList fileNames = Utils::transform(m_fileList, &FileNode::filePath);
-
- Utils::sort(fileNames);
+ FileNameList fileNames = transform(m_fileList, &FileNode::filePath);
+ sort(fileNames);
CMakeBuildTarget *last = 0;
FileName parentDirectory;
@@ -101,9 +100,9 @@ void CMakeCbpParser::sortFiles()
if (!unitTargets.isEmpty()) {
// cmake >= 3.3:
foreach (const QString &unitTarget, unitTargets) {
- int index = Utils::indexOf(m_buildTargets, Utils::equal(&CMakeBuildTarget::title, unitTarget));
+ int index = indexOf(m_buildTargets, equal(&CMakeBuildTarget::title, unitTarget));
if (index != -1) {
- m_buildTargets[index].files.append(fileName.toString());
+ m_buildTargets[index].files.append(fileName);
qCDebug(log) << " into" << m_buildTargets[index].title << "(target attribute)";
continue;
}
@@ -114,7 +113,7 @@ void CMakeCbpParser::sortFiles()
// fallback for cmake < 3.3:
if (fileName.parentDir() == parentDirectory && last) {
// easy case, same parent directory as last file
- last->files.append(fileName.toString());
+ last->files.append(fileName);
qCDebug(log) << " into" << last->title << "(same parent)";
} else {
int bestDistance = std::numeric_limits<int>::max();
@@ -142,7 +141,7 @@ void CMakeCbpParser::sortFiles()
}
if (bestIndex != -1) {
- m_buildTargets[bestIndex].files.append(fileName.toString());
+ m_buildTargets[bestIndex].files.append(fileName);
last = &m_buildTargets[bestIndex];
parentDirectory = fileName.parentDir();
qCDebug(log) << " into" << last->title;
@@ -157,19 +156,21 @@ void CMakeCbpParser::sortFiles()
qCDebug(log) << target.title << target.sourceDirectory << target.includeFiles << target.defines << target.files << "\n";
}
-bool CMakeCbpParser::parseCbpFile(const Kit *const kit, const QString &fileName, const QString &sourceDirectory)
+bool CMakeCbpParser::parseCbpFile(CMakeTool::PathMapper mapper, const FileName &fileName,
+ const FileName &sourceDirectory)
{
- m_kit = kit;
- m_buildDirectory = QFileInfo(fileName).absolutePath();
+
+ m_pathMapper = mapper;
+ m_buildDirectory = FileName::fromString(fileName.toFileInfo().absolutePath());
m_sourceDirectory = sourceDirectory;
- QFile fi(fileName);
+ QFile fi(fileName.toString());
if (fi.exists() && fi.open(QFile::ReadOnly)) {
setDevice(&fi);
while (!atEnd()) {
readNext();
- if (name() == QLatin1String("CodeBlocks_project_file"))
+ if (name() == "CodeBlocks_project_file")
parseCodeBlocks_project_file();
else if (isStartElement())
parseUnknownElement();
@@ -181,7 +182,7 @@ bool CMakeCbpParser::parseCbpFile(const Kit *const kit, const QString &fileName,
// There is always a clean target:
CMakeBuildTarget cleanTarget;
- cleanTarget.title = QLatin1String("clean");
+ cleanTarget.title = "clean";
cleanTarget.targetType = UtilityType;
cleanTarget.workingDirectory = m_buildDirectory;
cleanTarget.sourceDirectory = m_sourceDirectory;
@@ -199,7 +200,7 @@ void CMakeCbpParser::parseCodeBlocks_project_file()
readNext();
if (isEndElement())
return;
- else if (name() == QLatin1String("Project"))
+ else if (name() == "Project")
parseProject();
else if (isStartElement())
parseUnknownElement();
@@ -212,11 +213,11 @@ void CMakeCbpParser::parseProject()
readNext();
if (isEndElement())
return;
- else if (name() == QLatin1String("Option"))
+ else if (name() == "Option")
parseOption();
- else if (name() == QLatin1String("Unit"))
+ else if (name() == "Unit")
parseUnit();
- else if (name() == QLatin1String("Build"))
+ else if (name() == "Build")
parseBuild();
else if (isStartElement())
parseUnknownElement();
@@ -229,7 +230,7 @@ void CMakeCbpParser::parseBuild()
readNext();
if (isEndElement())
return;
- else if (name() == QLatin1String("Target"))
+ else if (name() == "Target")
parseBuildTarget();
else if (isStartElement())
parseUnknownElement();
@@ -240,23 +241,23 @@ void CMakeCbpParser::parseBuildTarget()
{
m_buildTarget.clear();
- if (attributes().hasAttribute(QLatin1String("title")))
- m_buildTarget.title = attributes().value(QLatin1String("title")).toString();
+ if (attributes().hasAttribute("title"))
+ m_buildTarget.title = attributes().value("title").toString();
while (!atEnd()) {
readNext();
if (isEndElement()) {
- if (!m_buildTarget.title.endsWith(QLatin1String("/fast"))
- && !m_buildTarget.title.endsWith(QLatin1String("_automoc"))) {
+ if (!m_buildTarget.title.endsWith("/fast")
+ && !m_buildTarget.title.endsWith("_automoc")) {
if (m_buildTarget.executable.isEmpty() && m_buildTarget.targetType == ExecutableType)
m_buildTarget.targetType = UtilityType;
m_buildTargets.append(m_buildTarget);
}
return;
- } else if (name() == QLatin1String("Compiler")) {
+ } else if (name() == "Compiler") {
parseCompiler();
- } else if (name() == QLatin1String("Option")) {
+ } else if (name() == "Option") {
parseBuildTargetOption();
- } else if (name() == QLatin1String("MakeCommands")) {
+ } else if (name() == "MakeCommands") {
parseMakeCommands();
} else if (isStartElement()) {
parseUnknownElement();
@@ -266,13 +267,10 @@ void CMakeCbpParser::parseBuildTarget()
void CMakeCbpParser::parseBuildTargetOption()
{
- if (attributes().hasAttribute(QLatin1String("output"))) {
- m_buildTarget.executable = attributes().value(QLatin1String("output")).toString();
- CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
- if (tool)
- m_buildTarget.executable = tool->mapAllPaths(m_kit, m_buildTarget.executable);
- } else if (attributes().hasAttribute(QLatin1String("type"))) {
- const QStringRef value = attributes().value(QLatin1String("type"));
+ if (attributes().hasAttribute("output")) {
+ m_buildTarget.executable = m_pathMapper(FileName::fromString(attributes().value("output").toString()));
+ } else if (attributes().hasAttribute("type")) {
+ const QStringRef value = attributes().value("type");
if (value == "0" || value == "1")
m_buildTarget.targetType = ExecutableType;
else if (value == "2")
@@ -281,10 +279,10 @@ void CMakeCbpParser::parseBuildTargetOption()
m_buildTarget.targetType = DynamicLibraryType;
else
m_buildTarget.targetType = UtilityType;
- } else if (attributes().hasAttribute(QLatin1String("working_dir"))) {
- m_buildTarget.workingDirectory = attributes().value(QLatin1String("working_dir")).toString();
+ } else if (attributes().hasAttribute("working_dir")) {
+ m_buildTarget.workingDirectory = FileName::fromUserInput(attributes().value("working_dir").toString());
- QFile cmakeSourceInfoFile(m_buildTarget.workingDirectory
+ QFile cmakeSourceInfoFile(m_buildTarget.workingDirectory.toString()
+ QStringLiteral("/CMakeFiles/CMakeDirectoryInformation.cmake"));
if (cmakeSourceInfoFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream stream(&cmakeSourceInfoFile);
@@ -292,18 +290,19 @@ void CMakeCbpParser::parseBuildTargetOption()
while (!stream.atEnd()) {
const QString lineTopSource = stream.readLine().trimmed();
if (lineTopSource.startsWith(searchSource, Qt::CaseInsensitive)) {
- m_buildTarget.sourceDirectory = lineTopSource.mid(searchSource.size());
- m_buildTarget.sourceDirectory.chop(2); // cut off ")
+ QString src = lineTopSource.mid(searchSource.size());
+ src.chop(2);
+ m_buildTarget.sourceDirectory = FileName::fromString(src);
break;
}
}
}
if (m_buildTarget.sourceDirectory.isEmpty()) {
- QDir dir(m_buildDirectory);
- const QString relative = dir.relativeFilePath(m_buildTarget.workingDirectory);
- m_buildTarget.sourceDirectory
- = FileName::fromString(m_sourceDirectory).appendPath(relative).toString();
+ QDir dir(m_buildDirectory.toString());
+ const QString relative = dir.relativeFilePath(m_buildTarget.workingDirectory.toString());
+ m_buildTarget.sourceDirectory = m_sourceDirectory;
+ m_buildTarget.sourceDirectory.appendPath(relative).toString();
}
}
while (!atEnd()) {
@@ -322,11 +321,11 @@ QString CMakeCbpParser::projectName() const
void CMakeCbpParser::parseOption()
{
- if (attributes().hasAttribute(QLatin1String("title")))
- m_projectName = attributes().value(QLatin1String("title")).toString();
+ if (attributes().hasAttribute("title"))
+ m_projectName = attributes().value("title").toString();
- if (attributes().hasAttribute(QLatin1String("compiler")))
- m_compiler = attributes().value(QLatin1String("compiler")).toString();
+ if (attributes().hasAttribute("compiler"))
+ m_compiler = attributes().value("compiler").toString();
while (!atEnd()) {
readNext();
@@ -343,9 +342,9 @@ void CMakeCbpParser::parseMakeCommands()
readNext();
if (isEndElement())
return;
- else if (name() == QLatin1String("Build"))
+ else if (name() == "Build")
parseBuildTargetBuild();
- else if (name() == QLatin1String("Clean"))
+ else if (name() == "Clean")
parseBuildTargetClean();
else if (isStartElement())
parseUnknownElement();
@@ -354,13 +353,8 @@ void CMakeCbpParser::parseMakeCommands()
void CMakeCbpParser::parseBuildTargetBuild()
{
- if (attributes().hasAttribute(QLatin1String("command"))) {
- m_buildTarget.makeCommand = attributes().value(QLatin1String("command")).toString();
-
- CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
- if (tool)
- m_buildTarget.makeCommand = tool->mapAllPaths(m_kit, m_buildTarget.makeCommand);
- }
+ if (attributes().hasAttribute("command"))
+ m_buildTarget.makeCommand = m_pathMapper(FileName::fromUserInput(attributes().value("command").toString()));
while (!atEnd()) {
readNext();
if (isEndElement())
@@ -387,7 +381,7 @@ void CMakeCbpParser::parseCompiler()
readNext();
if (isEndElement())
return;
- else if (name() == QLatin1String("Add"))
+ else if (name() == "Add")
parseAdd();
else if (isStartElement())
parseUnknownElement();
@@ -399,23 +393,20 @@ void CMakeCbpParser::parseAdd()
// CMake only supports <Add option=\> and <Add directory=\>
const QXmlStreamAttributes addAttributes = attributes();
- QString includeDirectory = addAttributes.value(QLatin1String("directory")).toString();
-
- CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
- if (tool)
- includeDirectory = tool->mapAllPaths(m_kit, includeDirectory);
+ FileName includeDirectory
+ = m_pathMapper(FileName::fromString(addAttributes.value("directory").toString()));
// allow adding multiple times because order happens
if (!includeDirectory.isEmpty())
m_buildTarget.includeFiles.append(includeDirectory);
- QString compilerOption = addAttributes.value(QLatin1String("option")).toString();
+ QString compilerOption = addAttributes.value("option").toString();
// defining multiple times a macro to the same value makes no sense
if (!compilerOption.isEmpty() && !m_buildTarget.compilerOptions.contains(compilerOption)) {
m_buildTarget.compilerOptions.append(compilerOption);
- int macroNameIndex = compilerOption.indexOf(QLatin1String("-D")) + 2;
+ int macroNameIndex = compilerOption.indexOf("-D") + 2;
if (macroNameIndex != 1) {
- int assignIndex = compilerOption.indexOf(QLatin1Char('='), macroNameIndex);
+ int assignIndex = compilerOption.indexOf('=', macroNameIndex);
if (assignIndex != -1)
compilerOption[assignIndex] = ' ';
m_buildTarget.defines.append("#define ");
@@ -435,43 +426,36 @@ void CMakeCbpParser::parseAdd()
void CMakeCbpParser::parseUnit()
{
- //qDebug()<<stream.attributes().value("filename");
FileName fileName =
- FileName::fromUserInput(attributes().value(QLatin1String("filename")).toString());
-
- CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
- if (tool) {
- QString mappedFile = tool->mapAllPaths(m_kit, fileName.toString());
- fileName = FileName::fromUserInput(mappedFile);
- }
+ m_pathMapper(FileName::fromUserInput(attributes().value("filename").toString()));
m_parsingCMakeUnit = false;
m_unitTargets.clear();
while (!atEnd()) {
readNext();
if (isEndElement()) {
- if (!fileName.endsWith(QLatin1String(".rule")) && !m_processedUnits.contains(fileName)) {
+ if (!fileName.endsWith(".rule") && !m_processedUnits.contains(fileName)) {
// Now check whether we found a virtual element beneath
if (m_parsingCMakeUnit) {
- m_cmakeFileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::ProjectFileType, false));
+ m_cmakeFileList.append( new FileNode(fileName, FileType::Project, false));
} else {
bool generated = false;
QString onlyFileName = fileName.fileName();
- if ( (onlyFileName.startsWith(QLatin1String("moc_")) && onlyFileName.endsWith(QLatin1String(".cxx")))
- || (onlyFileName.startsWith(QLatin1String("ui_")) && onlyFileName.endsWith(QLatin1String(".h")))
- || (onlyFileName.startsWith(QLatin1String("qrc_")) && onlyFileName.endsWith(QLatin1String(".cxx"))))
+ if ( (onlyFileName.startsWith("moc_") && onlyFileName.endsWith(".cxx"))
+ || (onlyFileName.startsWith("ui_") && onlyFileName.endsWith(".h"))
+ || (onlyFileName.startsWith("qrc_") && onlyFileName.endsWith(".cxx")))
generated = true;
- if (fileName.endsWith(QLatin1String(".qrc")))
- m_fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::ResourceType, generated));
+ if (fileName.endsWith(".qrc"))
+ m_fileList.append( new FileNode(fileName, FileType::Resource, generated));
else
- m_fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::SourceType, generated));
+ m_fileList.append( new FileNode(fileName, FileType::Source, generated));
}
m_unitTargetMap.insert(fileName, m_unitTargets);
m_processedUnits.insert(fileName);
}
return;
- } else if (name() == QLatin1String("Option")) {
+ } else if (name() == "Option") {
parseUnitOption();
} else if (isStartElement()) {
parseUnknownElement();
@@ -482,8 +466,8 @@ void CMakeCbpParser::parseUnit()
void CMakeCbpParser::parseUnitOption()
{
const QXmlStreamAttributes optionAttributes = attributes();
- m_parsingCMakeUnit = optionAttributes.hasAttribute(QLatin1String("virtualFolder"));
- const QString target = optionAttributes.value(QLatin1String("target")).toString();
+ m_parsingCMakeUnit = optionAttributes.hasAttribute("virtualFolder");
+ const QString target = optionAttributes.value("target").toString();
if (!target.isEmpty())
m_unitTargets.append(target);
@@ -513,12 +497,12 @@ void CMakeCbpParser::parseUnknownElement()
}
}
-QList<ProjectExplorer::FileNode *> CMakeCbpParser::fileList()
+QList<FileNode *> CMakeCbpParser::fileList()
{
return m_fileList;
}
-QList<ProjectExplorer::FileNode *> CMakeCbpParser::cmakeFileList()
+QList<FileNode *> CMakeCbpParser::cmakeFileList()
{
return m_cmakeFileList;
}
@@ -538,6 +522,5 @@ QString CMakeCbpParser::compilerName() const
return m_compiler;
}
-
} // namespace Internal
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakecbpparser.h b/src/plugins/cmakeprojectmanager/cmakecbpparser.h
index 286c0779f7..18905fa384 100644
--- a/src/plugins/cmakeprojectmanager/cmakecbpparser.h
+++ b/src/plugins/cmakeprojectmanager/cmakecbpparser.h
@@ -26,6 +26,7 @@
#pragma once
#include "cmakeproject.h"
+#include "cmaketool.h"
#include <utils/fileutils.h>
@@ -46,8 +47,8 @@ namespace Internal {
class CMakeCbpParser : public QXmlStreamReader
{
public:
- bool parseCbpFile(const ProjectExplorer::Kit *const kit, const QString &fileName,
- const QString &sourceDirectory);
+ bool parseCbpFile(CMakeTool::PathMapper mapper, const Utils::FileName &fileName,
+ const Utils::FileName &sourceDirectory);
QList<ProjectExplorer::FileNode *> fileList();
QList<ProjectExplorer::FileNode *> cmakeFileList();
QList<CMakeBuildTarget> buildTargets();
@@ -73,7 +74,7 @@ private:
void sortFiles();
QMap<Utils::FileName, QStringList> m_unitTargetMap;
- const ProjectExplorer::Kit *m_kit = 0;
+ CMakeTool::PathMapper m_pathMapper;
QList<ProjectExplorer::FileNode *> m_fileList;
QList<ProjectExplorer::FileNode *> m_cmakeFileList;
QSet<Utils::FileName> m_processedUnits;
@@ -83,8 +84,8 @@ private:
QList<CMakeBuildTarget> m_buildTargets;
QString m_projectName;
QString m_compiler;
- QString m_sourceDirectory;
- QString m_buildDirectory;
+ Utils::FileName m_sourceDirectory;
+ Utils::FileName m_buildDirectory;
QStringList m_unitTargets;
};
diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
index ff1011ef81..d2f21c90b1 100644
--- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp
@@ -134,9 +134,31 @@ QStringList CMakeConfigItem::cmakeSplitValue(const QString &in, bool keepEmpty)
return newArgs;
}
+CMakeConfigItem::Type CMakeConfigItem::typeStringToType(const QByteArray &type)
+{
+ if (type == "BOOL")
+ return CMakeConfigItem::BOOL;
+ if (type == "STRING")
+ return CMakeConfigItem::STRING;
+ if (type == "FILEPATH")
+ return CMakeConfigItem::FILEPATH;
+ if (type == "PATH")
+ return CMakeConfigItem::PATH;
+ if (type == "STATIC")
+ return CMakeConfigItem::STATIC;
+
+ QTC_CHECK(type == "INTERNAL" || type == "UNINITIALIZED");
+ return CMakeConfigItem::INTERNAL;
+}
+
QString CMakeConfigItem::expandedValue(const ProjectExplorer::Kit *k) const
{
- return k->macroExpander()->expand(QString::fromUtf8(value));
+ return expandedValue(k->macroExpander());
+}
+
+QString CMakeConfigItem::expandedValue(const Utils::MacroExpander *expander) const
+{
+ return expander->expand(QString::fromUtf8(value));
}
std::function<bool (const CMakeConfigItem &a, const CMakeConfigItem &b)> CMakeConfigItem::sortOperator()
@@ -190,26 +212,14 @@ CMakeConfigItem CMakeConfigItem::fromString(const QString &s)
// Fill in item:
CMakeConfigItem item;
if (!key.isEmpty()) {
- CMakeConfigItem::Type t = CMakeConfigItem::STRING;
- if (type == QLatin1String("FILEPATH"))
- t = CMakeConfigItem::FILEPATH;
- else if (type == QLatin1String("PATH"))
- t = CMakeConfigItem::PATH;
- else if (type == QLatin1String("BOOL"))
- t = CMakeConfigItem::BOOL;
- else if (type == QLatin1String("INTERNAL"))
- t = CMakeConfigItem::INTERNAL;
- else if (type == QLatin1String("STATIC"))
- t = CMakeConfigItem::STATIC;
-
item.key = key.toUtf8();
- item.type = t;
+ item.type = CMakeConfigItem::typeStringToType(type.toUtf8());
item.value = value.toUtf8();
}
return item;
}
-QString CMakeConfigItem::toString() const
+QString CMakeConfigItem::toString(const Utils::MacroExpander *expander) const
{
if (key.isEmpty() || type == CMakeProjectManager::CMakeConfigItem::STATIC)
return QString();
@@ -235,7 +245,14 @@ QString CMakeConfigItem::toString() const
break;
}
- return QString::fromUtf8(key) + QLatin1Char(':') + typeStr + QLatin1Char('=') + QString::fromUtf8(value);
+ const QString expandedValue
+ = expander ? expander->expand(QString::fromUtf8(value)) : QString::fromUtf8(value);
+ return QString::fromUtf8(key) + QLatin1Char(':') + typeStr + QLatin1Char('=') + expandedValue;
+}
+
+QString CMakeConfigItem::toArgument(const Utils::MacroExpander *expander) const
+{
+ return "-D" + toString(expander);
}
bool CMakeConfigItem::operator==(const CMakeConfigItem &o) const
diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
index 1484cffda3..e52a3ee535 100644
--- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
+++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h
@@ -31,6 +31,7 @@
#include <functional>
namespace ProjectExplorer { class Kit; }
+namespace Utils { class MacroExpander; }
namespace CMakeProjectManager {
@@ -46,13 +47,16 @@ public:
static QString expandedValueOf(const ProjectExplorer::Kit *k, const QByteArray &key,
const QList<CMakeConfigItem> &input);
static QStringList cmakeSplitValue(const QString &in, bool keepEmpty = false);
+ static Type typeStringToType(const QByteArray &typeString);
bool isNull() const { return key.isEmpty(); }
QString expandedValue(const ProjectExplorer::Kit *k) const;
+ QString expandedValue(const Utils::MacroExpander *expander) const;
static std::function<bool(const CMakeConfigItem &a, const CMakeConfigItem &b)> sortOperator();
static CMakeConfigItem fromString(const QString &s);
- QString toString() const;
+ QString toString(const Utils::MacroExpander *expander = nullptr) const;
+ QString toArgument(const Utils::MacroExpander *expander = nullptr) const;
bool operator==(const CMakeConfigItem &o) const;
diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
index 7375c7feb2..d38155c345 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp
@@ -420,8 +420,8 @@ void CMakeGeneratorKitInformation::upgrade(Kit *k)
} else {
info.generator = fullName;
}
+ setGeneratorInfo(k, info);
}
- setGeneratorInfo(k, info);
}
KitInformation::ItemList CMakeGeneratorKitInformation::toUserOutput(const Kit *k) const
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
index 52905ad598..0c266fbf6b 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -395,7 +395,7 @@ void CMakeProject::updateTargetRunConfigurations(Target *t)
auto btIt = buildTargetHash.constFind(cmakeRc->title());
cmakeRc->setEnabled(btIt != buildTargetHash.constEnd());
if (btIt != buildTargetHash.constEnd()) {
- cmakeRc->setExecutable(btIt.value()->executable);
+ cmakeRc->setExecutable(btIt.value()->executable.toString());
cmakeRc->setBaseWorkingDirectory(btIt.value()->workingDirectory);
}
}
@@ -436,12 +436,10 @@ void CMakeProject::updateApplicationAndDeploymentTargets()
continue;
if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType)
- deploymentData.addFile(ct.executable, deploymentPrefix + buildDir.relativeFilePath(QFileInfo(ct.executable).dir().path()), DeployableFile::TypeExecutable);
+ deploymentData.addFile(ct.executable.toString(), deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()), DeployableFile::TypeExecutable);
if (ct.targetType == ExecutableType) {
// TODO: Put a path to corresponding .cbp file into projectFilePath?
- appTargetList.list << BuildTargetInfo(ct.title,
- FileName::fromString(ct.executable),
- FileName::fromString(ct.executable));
+ appTargetList.list << BuildTargetInfo(ct.title, ct.executable, ct.executable);
}
}
@@ -500,6 +498,7 @@ void CMakeBuildTarget::clear()
includeFiles.clear();
compilerOptions.clear();
defines.clear();
+ files.clear();
}
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h
index 8ede082cd7..0cb58b9494 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.h
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.h
@@ -41,7 +41,6 @@ QT_END_NAMESPACE
namespace CMakeProjectManager {
namespace Internal {
-class CMakeFile;
class CMakeBuildSettingsWidget;
class CMakeBuildConfiguration;
class CMakeProjectNode;
@@ -59,17 +58,17 @@ class CMAKE_EXPORT CMakeBuildTarget
{
public:
QString title;
- QString executable; // TODO: rename to output?
+ Utils::FileName executable; // TODO: rename to output?
TargetType targetType = UtilityType;
- QString workingDirectory;
- QString sourceDirectory;
- QString makeCommand;
+ Utils::FileName workingDirectory;
+ Utils::FileName sourceDirectory;
+ Utils::FileName makeCommand;
// code model
- QStringList includeFiles;
+ QList<Utils::FileName> includeFiles;
QStringList compilerOptions;
QByteArray defines;
- QStringList files;
+ QList<Utils::FileName> files;
void clear();
};
@@ -129,7 +128,6 @@ private:
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
friend class Internal::CMakeBuildConfiguration;
- friend class Internal::CMakeFile;
};
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.qrc b/src/plugins/cmakeprojectmanager/cmakeproject.qrc
index 4b5080980a..6926b1d41d 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.qrc
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.qrc
@@ -1,5 +1,7 @@
<RCC>
<qresource prefix="/cmakeproject">
<file>CMakeProjectManager.mimetypes.xml</file>
+ <file>images/fileoverlay_cmake.png</file>
+ <file>images/fileoverlay_cmake@2x.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
index 1f6c33411e..94abe1c1fd 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h
@@ -54,5 +54,8 @@ const char CMAKE_SETTINGSPAGE_ID[] = "Z.CMake";
// Snippets
const char CMAKE_SNIPPETS_GROUP_ID[] = "CMake";
+// Icons
+const char FILEOVERLAY_CMAKE[] = ":/cmakeproject/images/fileoverlay_cmake.png";
+
} // namespace Constants
} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
index 82cd93df82..658564b177 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro
@@ -2,6 +2,7 @@ DEFINES += CMAKEPROJECTMANAGER_LIBRARY
include(../../qtcreatorplugin.pri)
HEADERS = builddirmanager.h \
+ builddirreader.h \
cmakebuildinfo.h \
cmakebuildstep.h \
cmakeconfigitem.h \
@@ -24,14 +25,17 @@ HEADERS = builddirmanager.h \
cmakekitinformation.h \
cmakekitconfigwidget.h \
cmakecbpparser.h \
- cmakefile.h \
cmakebuildsettingswidget.h \
cmakeindenter.h \
cmakeautocompleter.h \
configmodel.h \
- configmodelitemdelegate.h
+ configmodelitemdelegate.h \
+ servermode.h \
+ servermodereader.h \
+ tealeafreader.h
SOURCES = builddirmanager.cpp \
+ builddirreader.cpp \
cmakebuildstep.cpp \
cmakeconfigitem.cpp \
cmakeproject.cpp \
@@ -51,11 +55,13 @@ SOURCES = builddirmanager.cpp \
cmakekitinformation.cpp \
cmakekitconfigwidget.cpp \
cmakecbpparser.cpp \
- cmakefile.cpp \
cmakebuildsettingswidget.cpp \
cmakeindenter.cpp \
cmakeautocompleter.cpp \
configmodel.cpp \
- configmodelitemdelegate.cpp
+ configmodelitemdelegate.cpp \
+ servermode.cpp \
+ servermodereader.cpp \
+ tealeafreader.cpp
RESOURCES += cmakeproject.qrc
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
index 99fe635b27..6bf3e624b7 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs
@@ -20,6 +20,8 @@ QtcPlugin {
files: [
"builddirmanager.cpp",
"builddirmanager.h",
+ "builddirreader.cpp",
+ "builddirreader.h",
"cmake_global.h",
"cmakebuildconfiguration.cpp",
"cmakebuildconfiguration.h",
@@ -34,8 +36,6 @@ QtcPlugin {
"cmakeconfigitem.h",
"cmakeeditor.cpp",
"cmakeeditor.h",
- "cmakefile.cpp",
- "cmakefile.h",
"cmakefilecompletionassist.cpp",
"cmakefilecompletionassist.h",
"cmakekitconfigwidget.h",
@@ -73,6 +73,12 @@ QtcPlugin {
"configmodel.cpp",
"configmodel.h",
"configmodelitemdelegate.cpp",
- "configmodelitemdelegate.h"
+ "configmodelitemdelegate.h",
+ "servermode.cpp",
+ "servermode.h",
+ "servermodereader.cpp",
+ "servermodereader.h",
+ "tealeafreader.cpp",
+ "tealeafreader.h"
]
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
index dba81e9c27..cffcc282a6 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp
@@ -37,9 +37,11 @@
#include "cmaketoolmanager.h"
#include "cmakekitinformation.h"
-#include <utils/mimetypes/mimedatabase.h>
+#include <coreplugin/fileiconprovider.h>
#include <projectexplorer/kitmanager.h>
+#include <utils/mimetypes/mimedatabase.h>
+
using namespace CMakeProjectManager::Internal;
bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
@@ -47,6 +49,9 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
Q_UNUSED(errorMessage)
Utils::MimeDatabase::addMimeTypes(QLatin1String(":cmakeproject/CMakeProjectManager.mimetypes.xml"));
+ Core::FileIconProvider::registerIconOverlayForSuffix(Constants::FILEOVERLAY_CMAKE, "cmake");
+ Core::FileIconProvider::registerIconOverlayForFilename(Constants::FILEOVERLAY_CMAKE, "CMakeLists.txt");
+
addAutoReleasedObject(new Internal::CMakeSnippetProvider);
addAutoReleasedObject(new CMakeSettingsPage);
addAutoReleasedObject(new CMakeManager);
diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp
index f48209b35b..ea018e1126 100644
--- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp
@@ -60,7 +60,7 @@ const char TITLE_KEY[] = "CMakeProjectManager.CMakeRunConfiguation.Title";
} // namespace
CMakeRunConfiguration::CMakeRunConfiguration(Target *parent, Core::Id id, const QString &target,
- const QString &workingDirectory, const QString &title) :
+ const Utils::FileName &workingDirectory, const QString &title) :
RunConfiguration(parent, id),
m_buildTarget(target),
m_title(title)
@@ -70,7 +70,7 @@ CMakeRunConfiguration::CMakeRunConfiguration(Target *parent, Core::Id id, const
addExtraAspect(new TerminalAspect(this, QStringLiteral("CMakeProjectManager.CMakeRunConfiguration.UseTerminal")));
auto wd = new WorkingDirectoryAspect(this, QStringLiteral("CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"));
- wd->setDefaultWorkingDirectory(Utils::FileName::fromString(workingDirectory));
+ wd->setDefaultWorkingDirectory(workingDirectory);
addExtraAspect(wd);
ctor();
@@ -119,10 +119,9 @@ void CMakeRunConfiguration::setExecutable(const QString &executable)
m_buildTarget = executable;
}
-void CMakeRunConfiguration::setBaseWorkingDirectory(const QString &wd)
+void CMakeRunConfiguration::setBaseWorkingDirectory(const Utils::FileName &wd)
{
- extraAspect<WorkingDirectoryAspect>()
- ->setDefaultWorkingDirectory(Utils::FileName::fromString(wd));
+ extraAspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(wd);
}
QVariantMap CMakeRunConfiguration::toMap() const
@@ -246,7 +245,7 @@ RunConfiguration *CMakeRunConfigurationFactory::doCreate(Target *parent, Core::I
CMakeProject *project = static_cast<CMakeProject *>(parent->project());
const QString title(buildTargetFromId(id));
const CMakeBuildTarget &ct = project->buildTargetForTitle(title);
- return new CMakeRunConfiguration(parent, id, ct.executable, ct.workingDirectory, ct.title);
+ return new CMakeRunConfiguration(parent, id, ct.executable.toString(), ct.workingDirectory, ct.title);
}
bool CMakeRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const
@@ -273,7 +272,7 @@ bool CMakeRunConfigurationFactory::canRestore(Target *parent, const QVariantMap
RunConfiguration *CMakeRunConfigurationFactory::doRestore(Target *parent, const QVariantMap &map)
{
- return new CMakeRunConfiguration(parent, idFromMap(map), QString(), QString(), QString());
+ return new CMakeRunConfiguration(parent, idFromMap(map), QString(), Utils::FileName(), QString());
}
QString CMakeRunConfigurationFactory::buildTargetFromId(Core::Id id)
diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h
index b694c1a7da..eb7ef71abb 100644
--- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h
+++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h
@@ -39,13 +39,13 @@ class CMakeRunConfiguration : public ProjectExplorer::RunConfiguration
public:
CMakeRunConfiguration(ProjectExplorer::Target *parent, Core::Id id, const QString &target,
- const QString &workingDirectory, const QString &title);
+ const Utils::FileName &workingDirectory, const QString &title);
ProjectExplorer::Runnable runnable() const override;
QWidget *createConfigurationWidget() override;
void setExecutable(const QString &executable);
- void setBaseWorkingDirectory(const QString &workingDirectory);
+ void setBaseWorkingDirectory(const Utils::FileName &workingDirectory);
QString title() const;
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp
index 2cc0228656..5e917958f1 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp
@@ -228,11 +228,11 @@ void CMakeTool::setPathMapper(const CMakeTool::PathMapper &pathMapper)
m_pathMapper = pathMapper;
}
-QString CMakeTool::mapAllPaths(const ProjectExplorer::Kit *kit, const QString &in) const
+CMakeTool::PathMapper CMakeTool::pathMapper() const
{
if (m_pathMapper)
- return m_pathMapper(kit, in);
- return in;
+ return m_pathMapper;
+ return [](const Utils::FileName &fn) { return fn; };
}
void CMakeTool::readInformation(CMakeTool::QueryType type) const
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h
index 7e6ff51bc9..5851c75bfc 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.h
+++ b/src/plugins/cmakeprojectmanager/cmaketool.h
@@ -75,7 +75,7 @@ public:
bool matches(const QString &n, const QString &ex) const;
};
- typedef std::function<QString (const ProjectExplorer::Kit *, const QString &)> PathMapper;
+ typedef std::function<Utils::FileName (const Utils::FileName &)> PathMapper;
explicit CMakeTool(Detection d, const Core::Id &id);
explicit CMakeTool(const QVariantMap &map, bool fromSdk);
@@ -103,7 +103,7 @@ public:
void setDisplayName(const QString &displayName);
void setPathMapper(const PathMapper &includePathMapper);
- QString mapAllPaths(const ProjectExplorer::Kit *kit, const QString &in) const;
+ PathMapper pathMapper() const;
private:
enum class QueryType {
diff --git a/src/plugins/cmakeprojectmanager/images/fileoverlay_cmake.png b/src/plugins/cmakeprojectmanager/images/fileoverlay_cmake.png
new file mode 100644
index 0000000000..95104870c2
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/images/fileoverlay_cmake.png
Binary files differ
diff --git a/src/plugins/cmakeprojectmanager/images/fileoverlay_cmake@2x.png b/src/plugins/cmakeprojectmanager/images/fileoverlay_cmake@2x.png
new file mode 100644
index 0000000000..805db2fabd
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/images/fileoverlay_cmake@2x.png
Binary files differ
diff --git a/src/plugins/cmakeprojectmanager/servermode.cpp b/src/plugins/cmakeprojectmanager/servermode.cpp
new file mode 100644
index 0000000000..bb35fef33b
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/servermode.cpp
@@ -0,0 +1,456 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "servermode.h"
+
+#include <coreplugin/reaper.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+
+#include <QByteArray>
+#include <QCryptographicHash>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QLocalSocket>
+#include <QUuid>
+
+using namespace Utils;
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+const char COOKIE_KEY[] = "cookie";
+const char IN_REPLY_TO_KEY[] = "inReplyTo";
+const char NAME_KEY[] = "name";
+const char TYPE_KEY[] = "type";
+
+const char ERROR_TYPE[] = "error";
+const char HANDSHAKE_TYPE[] = "handshake";
+
+const char START_MAGIC[] = "\n[== \"CMake Server\" ==[\n";
+const char END_MAGIC[] = "\n]== \"CMake Server\" ==]\n";
+
+// ----------------------------------------------------------------------
+// Helpers:
+// ----------------------------------------------------------------------
+
+QString socketName(const Utils::FileName &buildDirectory)
+{
+ if (HostOsInfo::isWindowsHost()) {
+ QUuid uuid = QUuid::createUuid();
+ return "\\\\.\\pipe\\" + uuid.toString();
+ }
+ return buildDirectory.toString() + "/socket";
+}
+
+// --------------------------------------------------------------------
+// ServerMode:
+// --------------------------------------------------------------------
+
+
+ServerMode::ServerMode(const Environment &env,
+ const FileName &sourceDirectory, const FileName &buildDirectory,
+ const FileName &cmakeExecutable,
+ const QString &generator, const QString &extraGenerator,
+ const QString &platform, const QString &toolset,
+ bool experimental, int major, int minor,
+ QObject *parent) :
+ QObject(parent),
+ m_sourceDirectory(sourceDirectory), m_buildDirectory(buildDirectory),
+ m_cmakeExecutable(cmakeExecutable),
+ m_generator(generator), m_extraGenerator(extraGenerator),
+ m_platform(platform), m_toolset(toolset),
+ m_useExperimental(experimental), m_majorProtocol(major), m_minorProtocol(minor)
+{
+ QTC_ASSERT(!m_sourceDirectory.isEmpty() && m_sourceDirectory.exists(), return);
+ QTC_ASSERT(!m_buildDirectory.isEmpty() && m_buildDirectory.exists(), return);
+
+ m_connectionTimer.setInterval(100);
+ connect(&m_connectionTimer, &QTimer::timeout, this, &ServerMode::connectToServer);
+
+ m_cmakeProcess.reset(new QtcProcess);
+
+ m_cmakeProcess->setEnvironment(env);
+ m_cmakeProcess->setWorkingDirectory(buildDirectory.toString());
+ m_socketName = socketName(buildDirectory);
+ const QStringList args = QStringList({ "-E", "server", "--pipe=" + m_socketName });
+
+ connect(m_cmakeProcess.get(), &QtcProcess::started, this, [this]() { m_connectionTimer.start(); });
+ connect(m_cmakeProcess.get(),
+ static_cast<void(QtcProcess::*)(int, QProcess::ExitStatus)>(&QtcProcess::finished),
+ this, &ServerMode::handleCMakeFinished);
+
+ QString argumentString;
+ QtcProcess::addArgs(&argumentString, args);
+ if (m_useExperimental)
+ QtcProcess::addArg(&argumentString, "--experimental");
+
+ m_cmakeProcess->setCommand(cmakeExecutable.toString(), argumentString);
+
+ // Delay start:
+ QTimer::singleShot(0, [argumentString, this] {
+ emit message(tr("Running \"%1 %2\" in %3.")
+ .arg(m_cmakeExecutable.toUserOutput())
+ .arg(argumentString)
+ .arg(m_buildDirectory.toUserOutput()));
+
+ m_cmakeProcess->start();
+ });
+}
+
+ServerMode::~ServerMode()
+{
+ if (m_cmakeProcess)
+ m_cmakeProcess->disconnect();
+ if (m_cmakeSocket) {
+ m_cmakeSocket->disconnect();
+ m_cmakeSocket->abort();
+ delete(m_cmakeSocket);
+ }
+ m_cmakeSocket = nullptr;
+ Core::Reaper::reap(m_cmakeProcess.release());
+}
+
+void ServerMode::sendRequest(const QString &type, const QVariantMap &extra, const QVariant &cookie)
+{
+ QTC_ASSERT(m_cmakeSocket, return);
+ ++m_requestCounter;
+
+ QVariantMap data = extra;
+ data.insert(TYPE_KEY, type);
+ const QVariant realCookie = cookie.isNull() ? QVariant(m_requestCounter) : cookie;
+ data.insert(COOKIE_KEY, realCookie);
+ m_expectedReplies.push_back({ type, realCookie });
+
+ QJsonObject object = QJsonObject::fromVariantMap(data);
+ QJsonDocument document;
+ document.setObject(object);
+
+ const QByteArray rawData = START_MAGIC + document.toJson() + END_MAGIC;
+ m_cmakeSocket->write(rawData);
+ m_cmakeSocket->flush();
+}
+
+bool ServerMode::isConnected()
+{
+ return m_cmakeSocket && m_isConnected;
+}
+
+void ServerMode::connectToServer()
+{
+ QTC_ASSERT(m_cmakeProcess, return);
+ if (m_cmakeSocket)
+ return; // We connected in the meantime...
+
+ static int counter = 0;
+ ++counter;
+
+ if (counter > 50) {
+ counter = 0;
+ m_cmakeProcess->disconnect();
+ reportError(tr("Running \"%1\" failed: Timeout waiting for pipe \"%2\".")
+ .arg(m_cmakeExecutable.toUserOutput())
+ .arg(m_socketName));
+
+ Core::Reaper::reap(m_cmakeProcess.release());
+ emit disconnected();
+ return;
+ }
+
+ QTC_ASSERT(!m_cmakeSocket, return);
+
+ auto socket = new QLocalSocket(m_cmakeProcess.get());
+ connect(socket, &QLocalSocket::readyRead, this, &ServerMode::handleRawCMakeServerData);
+ connect(socket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error),
+ this, [this, socket]() {
+ reportError(socket->errorString());
+ m_cmakeSocket = nullptr;
+ socket->disconnect();
+ socket->deleteLater();
+ });
+ connect(socket, &QLocalSocket::connected, this, [this, socket]() { m_cmakeSocket = socket; });
+ connect(socket, &QLocalSocket::disconnected, this, [this, socket]() {
+ if (m_cmakeSocket)
+ emit disconnected();
+ m_cmakeSocket = nullptr;
+ socket->disconnect();
+ socket->deleteLater();
+ });
+
+ socket->connectToServer(m_socketName);
+ m_connectionTimer.start();
+}
+
+void ServerMode::handleCMakeFinished(int code, QProcess::ExitStatus status)
+{
+ QString msg;
+ if (status != QProcess::NormalExit)
+ msg = tr("CMake process \"%1\" crashed.").arg(m_cmakeExecutable.toUserOutput());
+ else if (code != 0)
+ msg = tr("CMake process \"%1\" quit with exit code %2.").arg(m_cmakeExecutable.toUserOutput()).arg(code);
+
+ if (!msg.isEmpty()) {
+ reportError(msg);
+ } else {
+ emit message(tr("CMake process \"%1\" quit normally.").arg(m_cmakeExecutable.toUserOutput()));
+ }
+
+ if (m_cmakeSocket) {
+ m_cmakeSocket->disconnect();
+ delete m_cmakeSocket;
+ m_cmakeSocket = nullptr;
+ }
+
+ if (!HostOsInfo::isWindowsHost())
+ QFile::remove(m_socketName);
+
+ emit disconnected();
+}
+
+void ServerMode::handleRawCMakeServerData()
+{
+ const static QByteArray startNeedle(START_MAGIC);
+ const static QByteArray endNeedle(END_MAGIC);
+
+ if (!m_cmakeSocket) // might happen during shutdown
+ return;
+
+ m_buffer.append(m_cmakeSocket->readAll());
+
+ while (true) {
+ const int startPos = m_buffer.indexOf(startNeedle);
+ if (startPos >= 0) {
+ const int afterStartNeedle = startPos + startNeedle.count();
+ const int endPos = m_buffer.indexOf(endNeedle, afterStartNeedle);
+ if (endPos > afterStartNeedle) {
+ // Process JSON, remove junk and JSON-part, continue to loop with shorter buffer
+ parseBuffer(m_buffer.mid(afterStartNeedle, endPos - afterStartNeedle));
+ m_buffer.remove(0, endPos + endNeedle.count());
+ } else {
+ // Remove junk up to the start needle and break out of the loop
+ if (startPos > 0)
+ m_buffer.remove(0, startPos);
+ break;
+ }
+ } else {
+ // Keep at last startNeedle.count() characters (as that might be a
+ // partial startNeedle), break out of the loop
+ if (m_buffer.count() > startNeedle.count())
+ m_buffer.remove(0, m_buffer.count() - startNeedle.count());
+ break;
+ }
+ }
+}
+
+void ServerMode::parseBuffer(const QByteArray &buffer)
+{
+ QJsonDocument document = QJsonDocument::fromJson(buffer);
+ if (document.isNull()) {
+ reportError(tr("Failed to parse JSON from CMake server."));
+ return;
+ }
+ QJsonObject rootObject = document.object();
+ if (rootObject.isEmpty()) {
+ reportError(tr("JSON data from CMake server was not a JSON object."));
+ return;
+ }
+
+ parseJson(rootObject.toVariantMap());
+}
+
+void ServerMode::parseJson(const QVariantMap &data)
+{
+ QString type = data.value(TYPE_KEY).toString();
+ if (type == "hello") {
+ if (m_gotHello) {
+ reportError(tr("Unexpected hello received from CMake server."));
+ return;
+ } else {
+ handleHello(data);
+ m_gotHello = true;
+ return;
+ }
+ }
+ if (!m_gotHello && type != ERROR_TYPE) {
+ reportError(tr("Unexpected type \"%1\" received while waiting for \"hello\".").arg(type));
+ return;
+ }
+
+ if (type == "reply") {
+ if (m_expectedReplies.empty()) {
+ reportError(tr("Received a reply even though no request is open."));
+ return;
+ }
+ const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
+ const QVariant cookie = data.value(COOKIE_KEY);
+
+ const auto expected = m_expectedReplies.begin();
+ if (expected->type != replyTo) {
+ reportError(tr("Received a reply to a request of type \"%1\", when a request of type \"%2\" was sent.")
+ .arg(replyTo).arg(expected->type));
+ return;
+ }
+ if (expected->cookie != cookie) {
+ reportError(tr("Received a reply with cookie \"%1\", when \"%2\" was expected.")
+ .arg(cookie.toString()).arg(expected->cookie.toString()));
+ return;
+ }
+
+ m_expectedReplies.erase(expected);
+ if (replyTo != HANDSHAKE_TYPE)
+ emit cmakeReply(data, replyTo, cookie);
+ else {
+ m_isConnected = true;
+ emit connected();
+ }
+ return;
+ }
+ if (type == "error") {
+ if (m_expectedReplies.empty()) {
+ reportError(tr("An error was reported even though no request is open."));
+ return;
+ }
+ const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
+ const QVariant cookie = data.value(COOKIE_KEY);
+
+ const auto expected = m_expectedReplies.begin();
+ if (expected->type != replyTo) {
+ reportError(tr("Received an error in response to a request of type \"%1\", when a request of type \"%2\" was sent.")
+ .arg(replyTo).arg(expected->type));
+ return;
+ }
+ if (expected->cookie != cookie) {
+ reportError(tr("Received an error with cookie \"%1\", when \"%2\" was expected.")
+ .arg(cookie.toString()).arg(expected->cookie.toString()));
+ return;
+ }
+
+ m_expectedReplies.erase(expected);
+
+ emit cmakeError(data.value("errorMessage").toString(), replyTo, cookie);
+ if (replyTo == HANDSHAKE_TYPE) {
+ Core::Reaper::reap(m_cmakeProcess.release());
+ m_cmakeSocket->disconnect();
+ m_cmakeSocket->disconnectFromServer();
+ m_cmakeSocket = nullptr;
+ emit disconnected();
+ }
+ return;
+ }
+ if (type == "message") {
+ const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
+ const QVariant cookie = data.value(COOKIE_KEY);
+
+ const auto expected = m_expectedReplies.begin();
+ if (expected->type != replyTo) {
+ reportError(tr("Received a message in response to a request of type \"%1\", when a request of type \"%2\" was sent.")
+ .arg(replyTo).arg(expected->type));
+ return;
+ }
+ if (expected->cookie != cookie) {
+ reportError(tr("Received a message with cookie \"%1\", when \"%2\" was expected.")
+ .arg(cookie.toString()).arg(expected->cookie.toString()));
+ return;
+ }
+
+ emit cmakeMessage(data.value("message").toString(), replyTo, cookie);
+ return;
+ }
+ if (type == "progress") {
+ const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
+ const QVariant cookie = data.value(COOKIE_KEY);
+
+ const auto expected = m_expectedReplies.begin();
+ if (expected->type != replyTo) {
+ reportError(tr("Received a progress report in response to a request of type \"%1\", when a request of type \"%2\" was sent.")
+ .arg(replyTo).arg(expected->type));
+ return;
+ }
+ if (expected->cookie != cookie) {
+ reportError(tr("Received a progress report with cookie \"%1\", when \"%2\" was expected.")
+ .arg(cookie.toString()).arg(expected->cookie.toString()));
+ return;
+ }
+
+ emit cmakeProgress(data.value("progressMinimum").toInt(),
+ data.value("progressCurrent").toInt(),
+ data.value("progressMaximum").toInt(), replyTo, cookie);
+ return;
+ }
+ if (type == "signal") {
+ const QString replyTo = data.value(IN_REPLY_TO_KEY).toString();
+ const QVariant cookie = data.value(COOKIE_KEY);
+ const QString name = data.value(NAME_KEY).toString();
+
+ if (name.isEmpty()) {
+ reportError(tr("Received a signal without a name."));
+ return;
+ }
+ if (!replyTo.isEmpty() || cookie.isValid()) {
+ reportError(tr("Received a signal in reply to a request."));
+ return;
+ }
+
+ emit cmakeSignal(name, data);
+ return;
+ }
+}
+
+void ServerMode::handleHello(const QVariantMap &data)
+{
+ Q_UNUSED(data);
+ QVariantMap extra;
+ QVariantMap version;
+ version.insert("major", m_majorProtocol);
+ if (m_minorProtocol >= 0)
+ version.insert("minor", m_minorProtocol);
+ extra.insert("protocolVersion", version);
+ extra.insert("sourceDirectory", m_sourceDirectory.toString());
+ extra.insert("buildDirectory", m_buildDirectory.toString());
+ extra.insert("generator", m_generator);
+ if (!m_platform.isEmpty())
+ extra.insert("platform", m_platform);
+ if (!m_toolset.isEmpty())
+ extra.insert("toolset", m_toolset);
+ if (!m_extraGenerator.isEmpty())
+ extra.insert("extraGenerator", m_extraGenerator);
+ if (!m_platform.isEmpty())
+ extra.insert("platform", m_platform);
+ if (!m_toolset.isEmpty())
+ extra.insert("toolset", m_toolset);
+
+ sendRequest(HANDSHAKE_TYPE, extra);
+}
+
+void ServerMode::reportError(const QString &msg)
+{
+ emit message(msg);
+ emit errorOccured(msg);
+}
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/servermode.h b/src/plugins/cmakeprojectmanager/servermode.h
new file mode 100644
index 0000000000..00d4393825
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/servermode.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <utils/qtcprocess.h>
+
+#include <QTemporaryDir>
+#include <QTimer>
+#include <QVariantMap>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QLocalSocket);
+
+namespace Utils { class QtcProcess; }
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class ServerMode : public QObject
+{
+ Q_OBJECT
+
+public:
+ ServerMode(const Utils::Environment &env,
+ const Utils::FileName &sourceDirectory, const Utils::FileName &buildDirectory,
+ const Utils::FileName &cmakeExecutable,
+ const QString &generator, const QString &extraGenerator,
+ const QString &platform, const QString &toolset,
+ bool experimental, int major, int minor = -1,
+ QObject *parent = nullptr);
+ ~ServerMode() final;
+
+ void sendRequest(const QString &type, const QVariantMap &extra = QVariantMap(),
+ const QVariant &cookie = QVariant());
+
+ bool isConnected();
+
+signals:
+ void connected();
+ void disconnected();
+ void message(const QString &msg);
+ void errorOccured(const QString &msg);
+
+ // Forward stuff from the server
+ void cmakeReply(const QVariantMap &data, const QString &inResponseTo, const QVariant &cookie);
+ void cmakeError(const QString &errorMessage, const QString &inResponseTo, const QVariant &cookie);
+ void cmakeMessage(const QString &message, const QString &inResponseTo, const QVariant &cookie);
+ void cmakeProgress(int min, int cur, int max, const QString &inResponseTo, const QVariant &cookie);
+ void cmakeSignal(const QString &name, const QVariantMap &data);
+
+private:
+ void connectToServer();
+ void handleCMakeFinished(int code, QProcess::ExitStatus status);
+
+ void handleRawCMakeServerData();
+ void parseBuffer(const QByteArray &buffer);
+ void parseJson(const QVariantMap &data);
+
+ void handleHello(const QVariantMap &data);
+
+ void reportError(const QString &msg);
+
+ std::unique_ptr<Utils::QtcProcess> m_cmakeProcess;
+ QLocalSocket *m_cmakeSocket = nullptr;
+ QTimer m_connectionTimer;
+
+ Utils::FileName m_sourceDirectory;
+ Utils::FileName m_buildDirectory;
+ Utils::FileName m_cmakeExecutable;
+
+ QByteArray m_buffer;
+
+ struct ExpectedReply {
+ QString type;
+ QVariant cookie;
+ };
+ std::vector<ExpectedReply> m_expectedReplies;
+
+ const QString m_generator;
+ const QString m_extraGenerator;
+ const QString m_platform;
+ const QString m_toolset;
+ QString m_socketName;
+ const bool m_useExperimental;
+ bool m_gotHello = false;
+ bool m_isConnected = false;
+ const int m_majorProtocol = -1;
+ const int m_minorProtocol = -1;
+
+ int m_requestCounter = 0;
+};
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp
new file mode 100644
index 0000000000..5295a07ccd
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "servermodereader.h"
+
+#include "cmakebuildconfiguration.h"
+#include "cmakeprojectconstants.h"
+#include "cmakeprojectmanager.h"
+#include "cmakeprojectnodes.h"
+#include "servermode.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <cpptools/projectpartbuilder.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/task.h>
+#include <projectexplorer/taskhub.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+const char CACHE_TYPE[] = "cache";
+const char CODEMODEL_TYPE[] = "codemodel";
+const char CONFIGURE_TYPE[] = "configure";
+const char CMAKE_INPUTS_TYPE[] = "cmakeInputs";
+const char COMPUTE_TYPE[] = "compute";
+
+const char NAME_KEY[] = "name";
+const char SOURCE_DIRECTORY_KEY[] = "sourceDirectory";
+const char SOURCES_KEY[] = "sources";
+
+const int MAX_PROGRESS = 1400;
+
+// ----------------------------------------------------------------------
+// Helpers:
+// ----------------------------------------------------------------------
+
+QString socketName(const BuildDirReader::Parameters &p)
+{
+ return p.buildDirectory.toString() + "/socket";
+}
+
+// --------------------------------------------------------------------
+// ServerModeReader:
+// --------------------------------------------------------------------
+
+ServerModeReader::ServerModeReader()
+{
+ connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave,
+ this, [this](const Core::IDocument *document) {
+ if (m_cmakeFiles.contains(document->filePath()))
+ emit dirty();
+ });
+}
+
+ServerModeReader::~ServerModeReader()
+{
+ stop();
+}
+
+void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
+{
+ BuildDirReader::setParameters(p);
+ if (!m_cmakeServer) {
+ m_cmakeServer.reset(new ServerMode(p.environment,
+ p.sourceDirectory, p.buildDirectory, p.cmakeExecutable,
+ p.generator, p.extraGenerator, p.platform, p.toolset,
+ true, 1));
+ connect(m_cmakeServer.get(), &ServerMode::errorOccured,
+ this, &ServerModeReader::errorOccured);
+ connect(m_cmakeServer.get(), &ServerMode::cmakeReply,
+ this, &ServerModeReader::handleReply);
+ connect(m_cmakeServer.get(), &ServerMode::cmakeError,
+ this, &ServerModeReader::handleError);
+ connect(m_cmakeServer.get(), &ServerMode::cmakeProgress,
+ this, &ServerModeReader::handleProgress);
+ connect(m_cmakeServer.get(), &ServerMode::cmakeMessage,
+ this, [this](const QString &m) { Core::MessageManager::write(m); });
+ connect(m_cmakeServer.get(), &ServerMode::message,
+ this, [](const QString &m) { Core::MessageManager::write(m); });
+ connect(m_cmakeServer.get(), &ServerMode::connected,
+ this, &ServerModeReader::isReadyNow, Qt::QueuedConnection); // Delay
+ connect(m_cmakeServer.get(), &ServerMode::disconnected,
+ this, [this]() { m_cmakeServer.reset(); }, Qt::QueuedConnection); // Delay
+ }
+}
+
+bool ServerModeReader::isCompatible(const BuildDirReader::Parameters &p)
+{
+ // Server mode connection got lost, reset...
+ if (!m_parameters.cmakeExecutable.isEmpty() && !m_cmakeServer)
+ return false;
+
+ return p.cmakeHasServerMode
+ && p.cmakeExecutable == m_parameters.cmakeExecutable
+ && p.environment == m_parameters.environment
+ && p.generator == m_parameters.generator
+ && p.extraGenerator == m_parameters.extraGenerator
+ && p.platform == m_parameters.platform
+ && p.toolset == m_parameters.toolset
+ && p.sourceDirectory == m_parameters.sourceDirectory
+ && p.buildDirectory == m_parameters.buildDirectory;
+}
+
+void ServerModeReader::resetData()
+{
+ m_hasData = false;
+}
+
+void ServerModeReader::parse(bool force)
+{
+ QTC_ASSERT(m_cmakeServer, return);
+ QVariantMap extra;
+ if (force)
+ extra.insert("cacheArguments", QVariant(transform(m_parameters.configuration,
+ [this](const CMakeConfigItem &i) {
+ return i.toArgument(m_parameters.expander);
+ })));
+
+ m_future.reset(new QFutureInterface<void>());
+ m_future->setProgressRange(0, MAX_PROGRESS);
+ m_progressStepMinimum = 0;
+ m_progressStepMaximum = 1000;
+ Core::ProgressManager::addTask(m_future->future(),
+ tr("Configuring \"%1\"").arg(m_parameters.projectName),
+ "CMake.Configure");
+
+ m_cmakeServer->sendRequest(CONFIGURE_TYPE, extra);
+}
+
+void ServerModeReader::stop()
+{
+ if (m_future) {
+ m_future->reportCanceled();
+ m_future->reportFinished();
+ m_future.reset();
+ }
+}
+
+bool ServerModeReader::isReady() const
+{
+ return m_cmakeServer->isConnected();
+}
+
+bool ServerModeReader::isParsing() const
+{
+ return static_cast<bool>(m_future);
+}
+
+bool ServerModeReader::hasData() const
+{
+ return m_hasData;
+}
+
+QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
+{
+ return transform(m_targets, [](const Target *t) -> CMakeBuildTarget {
+ CMakeBuildTarget ct;
+ ct.title = t->name;
+ ct.executable = t->artifacts.isEmpty() ? FileName() : t->artifacts.at(0);
+ TargetType type = UtilityType;
+ if (t->type == "STATIC_LIBRARY")
+ type = StaticLibraryType;
+ else if (t->type == "MODULE_LIBRARY"
+ || t->type == "SHARED_LIBRARY"
+ || t->type == "INTERFACE_LIBRARY"
+ || t->type == "OBJECT_LIBRARY")
+ type = DynamicLibraryType;
+ else
+ type = UtilityType;
+ ct.targetType = type;
+ ct.workingDirectory = t->buildDirectory;
+ ct.sourceDirectory = t->sourceDirectory;
+ return ct;
+ });
+}
+
+CMakeConfig ServerModeReader::parsedConfiguration() const
+{
+ return m_cmakeCache;
+}
+
+void ServerModeReader::generateProjectTree(CMakeProjectNode *root, const QList<FileNode *> &allFiles)
+{
+ Q_UNUSED(allFiles);
+ QSet<Utils::FileName> knownFiles;
+ for (auto it = m_cmakeInputsFileNodes.constBegin(); it != m_cmakeInputsFileNodes.constEnd(); ++it)
+ knownFiles.insert((*it)->filePath());
+
+ QList<FileNode *> fileGroupNodes = m_cmakeInputsFileNodes;
+ m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore!
+ foreach (const FileGroup *fg, m_fileGroups) {
+ for (const FileName &s : fg->sources) {
+ const int oldCount = knownFiles.count();
+ knownFiles.insert(s);
+ if (oldCount != knownFiles.count())
+ fileGroupNodes.append(new FileNode(s, FileType::Source, fg->isGenerated));
+ }
+ }
+ root->buildTree(fileGroupNodes);
+}
+
+QSet<Core::Id> ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
+{
+ QSet<Core::Id> languages;
+ int counter = 0;
+ foreach (const FileGroup *fg, m_fileGroups) {
+ ++counter;
+ const QString defineArg
+ = transform(fg->defines, [](const QString &s) -> QString { return QString::fromLatin1("#define ") + s; }).join('\n');
+ const QStringList flags = QtcProcess::splitArgs(fg->compileFlags);
+ const QStringList includes = transform(fg->includePaths, [](const IncludePath *ip) { return ip->path.toString(); });
+
+ ppBuilder.setProjectFile(fg->target->sourceDirectory.toString());
+ ppBuilder.setDisplayName(fg->target->name + QString::number(counter));
+ ppBuilder.setDefines(defineArg.toUtf8());
+ ppBuilder.setIncludePaths(includes);
+ ppBuilder.setCFlags(flags);
+ ppBuilder.setCxxFlags(flags);
+
+
+ languages.unite(QSet<Core::Id>::fromList(ppBuilder.createProjectPartsForFiles(transform(fg->sources, &FileName::toString))));
+ }
+
+ qDeleteAll(m_projects); // Not used anymore!
+ m_projects.clear();
+ m_targets.clear();
+ m_fileGroups.clear();
+
+ return languages;
+}
+
+void ServerModeReader::handleReply(const QVariantMap &data, const QString &inReplyTo)
+{
+ Q_UNUSED(data);
+ if (inReplyTo == CONFIGURE_TYPE) {
+ m_cmakeServer->sendRequest(COMPUTE_TYPE);
+ if (m_future)
+ m_future->setProgressValue(1000);
+ m_progressStepMinimum = m_progressStepMaximum;
+ m_progressStepMaximum = 1100;
+ } else if (inReplyTo == COMPUTE_TYPE) {
+ m_cmakeServer->sendRequest(CODEMODEL_TYPE);
+ if (m_future)
+ m_future->setProgressValue(1100);
+ m_progressStepMinimum = m_progressStepMaximum;
+ m_progressStepMaximum = 1200;
+ } else if (inReplyTo == CODEMODEL_TYPE) {
+ extractCodeModelData(data);
+ m_cmakeServer->sendRequest(CMAKE_INPUTS_TYPE);
+ if (m_future)
+ m_future->setProgressValue(1200);
+ m_progressStepMinimum = m_progressStepMaximum;
+ m_progressStepMaximum = 1300;
+ } else if (inReplyTo == CMAKE_INPUTS_TYPE) {
+ extractCMakeInputsData(data);
+ m_cmakeServer->sendRequest(CACHE_TYPE);
+ if (m_future)
+ m_future->setProgressValue(1300);
+ m_progressStepMinimum = m_progressStepMaximum;
+ m_progressStepMaximum = 1400;
+ } else if (inReplyTo == CACHE_TYPE) {
+ extractCacheData(data);
+ if (m_future) {
+ m_future->setProgressValue(MAX_PROGRESS);
+ m_future->reportFinished();
+ m_future.reset();
+ }
+ m_hasData = true;
+ emit dataAvailable();
+ }
+}
+
+void ServerModeReader::handleError(const QString &message)
+{
+ TaskHub::addTask(Task::Error, message, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM,
+ Utils::FileName(), -1);
+ stop();
+}
+
+void ServerModeReader::handleProgress(int min, int cur, int max, const QString &inReplyTo)
+{
+ Q_UNUSED(inReplyTo);
+
+ if (!m_future)
+ return;
+ int progress = m_progressStepMinimum
+ + (((max - min) / (cur - min)) * (m_progressStepMaximum - m_progressStepMinimum));
+ m_future->setProgressValue(progress);
+}
+
+void ServerModeReader::extractCodeModelData(const QVariantMap &data)
+{
+ const QVariantList configs = data.value("configurations").toList();
+ QTC_CHECK(configs.count() == 1); // FIXME: Support several configurations!
+ for (const QVariant &c : configs) {
+ const QVariantMap &cData = c.toMap();
+ extractConfigurationData(cData);
+ }
+}
+
+void ServerModeReader::extractConfigurationData(const QVariantMap &data)
+{
+ const QString name = data.value(NAME_KEY).toString();
+ Q_UNUSED(name);
+ const QVariantList projects = data.value("projects").toList();
+ for (const QVariant &p : projects) {
+ const QVariantMap pData = p.toMap();
+ m_projects.append(extractProjectData(pData));
+ }
+}
+
+ServerModeReader::Project *ServerModeReader::extractProjectData(const QVariantMap &data)
+{
+ auto project = new Project;
+ project->name = data.value(NAME_KEY).toString();
+ project->sourceDirectory = FileName::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
+
+ const QVariantList targets = data.value("targets").toList();
+ for (const QVariant &t : targets) {
+ const QVariantMap tData = t.toMap();
+ project->targets.append(extractTargetData(tData, project));
+ }
+ return project;
+}
+
+ServerModeReader::Target *ServerModeReader::extractTargetData(const QVariantMap &data, Project *p)
+{
+ auto target = new Target;
+ target->project = p;
+ target->name = data.value(NAME_KEY).toString();
+ target->sourceDirectory = FileName::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
+ target->buildDirectory = FileName::fromString(data.value("buildDirectory").toString());
+
+ QDir srcDir(target->sourceDirectory.toString());
+
+ target->type = data.value("type").toString();
+ const QStringList artifacts = data.value("artifacts").toStringList();
+ target->artifacts = transform(artifacts, [&srcDir](const QString &a) { return FileName::fromString(srcDir.absoluteFilePath(a)); });
+
+ const QVariantList fileGroups = data.value("fileGroups").toList();
+ for (const QVariant &fg : fileGroups) {
+ const QVariantMap fgData = fg.toMap();
+ target->fileGroups.append(extractFileGroupData(fgData, srcDir, target));
+ }
+
+ m_targets.append(target);
+ return target;
+}
+
+ServerModeReader::FileGroup *ServerModeReader::extractFileGroupData(const QVariantMap &data,
+ const QDir &srcDir,
+ Target *t)
+{
+ auto fileGroup = new FileGroup;
+ fileGroup->target = t;
+ fileGroup->compileFlags = data.value("compileFlags").toString();
+ fileGroup->defines = data.value("defines").toStringList();
+ fileGroup->includePaths = transform(data.value("includePath").toList(),
+ [](const QVariant &i) -> IncludePath* {
+ const QVariantMap iData = i.toMap();
+ auto result = new IncludePath;
+ result->path = FileName::fromString(iData.value("path").toString());
+ result->isSystem = iData.value("isSystem", false).toBool();
+ return result;
+ });
+ fileGroup->isGenerated = data.value("isGenerated", false).toBool();
+ fileGroup->sources = transform(data.value(SOURCES_KEY).toStringList(),
+ [&srcDir](const QString &s) {
+ return FileName::fromString(srcDir.absoluteFilePath(s));
+ });
+
+ m_fileGroups.append(fileGroup);
+ return fileGroup;
+}
+
+void ServerModeReader::extractCMakeInputsData(const QVariantMap &data)
+{
+ const FileName src = FileName::fromString(data.value(SOURCE_DIRECTORY_KEY).toString());
+ QTC_ASSERT(src == m_parameters.sourceDirectory, return);
+ QDir srcDir(src.toString());
+
+ const QVariantList buildFiles = data.value("buildFiles").toList();
+ for (const QVariant &bf : buildFiles) {
+ const QVariantMap &section = bf.toMap();
+ const QStringList sources = section.value(SOURCES_KEY).toStringList();
+
+ const bool isTemporary = section.value("isTemporary").toBool();
+ const bool isCMake = section.value("isCMake").toBool();
+
+ for (const QString &s : sources) {
+ const FileName sfn = FileName::fromString(srcDir.absoluteFilePath(s));
+ const int oldCount = m_cmakeFiles.count();
+ m_cmakeFiles.insert(sfn);
+ if (!isCMake && oldCount < m_cmakeFiles.count())
+ m_cmakeInputsFileNodes.append(new FileNode(sfn, FileType::Project, isTemporary));
+ }
+ }
+}
+
+void ServerModeReader::extractCacheData(const QVariantMap &data)
+{
+ CMakeConfig config;
+ const QVariantList entries = data.value("cache").toList();
+ for (const QVariant &e : entries) {
+ const QVariantMap eData = e.toMap();
+ CMakeConfigItem item;
+ item.key = eData.value("key").toByteArray();
+ item.value = eData.value("value").toByteArray();
+ item.type = CMakeConfigItem::typeStringToType(eData.value("type").toByteArray());
+ const QVariantMap properties = eData.value("properties").toMap();
+ item.isAdvanced = properties.value("ADVANCED", false).toBool();
+ item.documentation = properties.value("HELPSTRING").toByteArray();
+ item.values = CMakeConfigItem::cmakeSplitValue(properties.value("STRINGS").toString(), true);
+ config.append(item);
+ }
+ m_cmakeCache = config;
+}
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h
new file mode 100644
index 0000000000..933542e71d
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/servermodereader.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "builddirreader.h"
+#include "servermode.h"
+
+#include <utils/qtcprocess.h>
+
+#include <QSet>
+#include <QTemporaryDir>
+#include <QTimer>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QLocalSocket);
+
+namespace Utils { class QtcProcess; }
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class ServerModeReader : public BuildDirReader
+{
+ Q_OBJECT
+
+public:
+ ServerModeReader();
+ ~ServerModeReader() final;
+
+ void setParameters(const Parameters &p) final;
+
+ bool isCompatible(const Parameters &p) final;
+ void resetData() final;
+ void parse(bool force) final;
+ void stop() final;
+
+ bool isReady() const final;
+ bool isParsing() const final;
+ bool hasData() const final;
+
+ QList<CMakeBuildTarget> buildTargets() const final;
+ CMakeConfig parsedConfiguration() const final;
+ void generateProjectTree(CMakeProjectNode *root, const QList<ProjectExplorer::FileNode *> &allFiles) final;
+ QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
+
+private:
+ void handleReply(const QVariantMap &data, const QString &inReplyTo);
+ void handleError(const QString &message);
+ void handleProgress(int min, int cur, int max, const QString &inReplyTo);
+
+ struct Target;
+ struct Project;
+
+ struct IncludePath {
+ Utils::FileName path;
+ bool isSystem;
+ };
+
+ struct FileGroup {
+ ~FileGroup() { qDeleteAll(includePaths); includePaths.clear(); }
+
+ Target *target = nullptr;
+ QString compileFlags;
+ QStringList defines;
+ QList<IncludePath *> includePaths;
+ QString language;
+ QList<Utils::FileName> sources;
+ bool isGenerated;
+ };
+
+ struct Target {
+ ~Target() { qDeleteAll(fileGroups); fileGroups.clear(); }
+
+ Project *project = nullptr;
+ QString name;
+ QString type;
+ QList<Utils::FileName> artifacts;
+ Utils::FileName sourceDirectory;
+ Utils::FileName buildDirectory;
+ QList<FileGroup *> fileGroups;
+ };
+
+ struct Project {
+ ~Project() { qDeleteAll(targets); targets.clear(); }
+ QString name;
+ Utils::FileName sourceDirectory;
+ QList<Target *> targets;
+ };
+
+ void extractCodeModelData(const QVariantMap &data);
+ void extractConfigurationData(const QVariantMap &data);
+ Project *extractProjectData(const QVariantMap &data);
+ Target *extractTargetData(const QVariantMap &data, Project *p);
+ FileGroup *extractFileGroupData(const QVariantMap &data, const QDir &srcDir, Target *t);
+ void extractCMakeInputsData(const QVariantMap &data);
+ void extractCacheData(const QVariantMap &data);
+
+ bool m_hasData = false;
+
+ std::unique_ptr<ServerMode> m_cmakeServer;
+ std::unique_ptr<QFutureInterface<void>> m_future;
+
+ int m_progressStepMinimum;
+ int m_progressStepMaximum;
+
+ CMakeConfig m_cmakeCache;
+
+ QSet<Utils::FileName> m_cmakeFiles;
+ QList<ProjectExplorer::FileNode *> m_cmakeInputsFileNodes;
+
+ QList<Project *> m_projects;
+ QList<Target *> m_targets;
+ QList<FileGroup *> m_fileGroups;
+};
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp
new file mode 100644
index 0000000000..9ed8373f52
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp
@@ -0,0 +1,716 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "tealeafreader.h"
+
+#include "cmakebuildconfiguration.h"
+#include "cmakecbpparser.h"
+#include "cmakekitinformation.h"
+#include "cmakeparser.h"
+#include "cmakeprojectconstants.h"
+#include "cmakeprojectmanager.h"
+#include "cmakeprojectnodes.h"
+
+#include <coreplugin/documentmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/idocument.h>
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <coreplugin/reaper.h>
+#include <cpptools/projectpartbuilder.h>
+#include <projectexplorer/headerpath.h>
+#include <projectexplorer/ioutputparser.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/task.h>
+#include <projectexplorer/taskhub.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/toolchainmanager.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
+
+#include <QDateTime>
+#include <QFileInfo>
+
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace Utils;
+
+// --------------------------------------------------------------------
+// Helper:
+// --------------------------------------------------------------------
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class CMakeFile : public IDocument
+{
+public:
+ CMakeFile(TeaLeafReader *r, const FileName &fileName);
+
+ ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
+ bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
+
+private:
+ TeaLeafReader *m_reader;
+};
+
+CMakeFile::CMakeFile(TeaLeafReader *r, const FileName &fileName) : m_reader(r)
+{
+ setId("Cmake.ProjectFile");
+ setMimeType(Constants::CMAKEPROJECTMIMETYPE);
+ setFilePath(fileName);
+}
+
+IDocument::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
+{
+ Q_UNUSED(state)
+ Q_UNUSED(type)
+ return BehaviorSilent;
+}
+
+bool CMakeFile::reload(QString *errorString, IDocument::ReloadFlag flag, IDocument::ChangeType type)
+{
+ Q_UNUSED(errorString);
+ Q_UNUSED(flag);
+
+ if (type != TypePermissions)
+ emit m_reader->dirty();
+ return true;
+}
+
+static QString lineSplit(const QString &rest, const QByteArray &array, std::function<void(const QString &)> f)
+{
+ QString tmp = rest + SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(array));
+ int start = 0;
+ int end = tmp.indexOf(QLatin1Char('\n'), start);
+ while (end >= 0) {
+ f(tmp.mid(start, end - start));
+ start = end + 1;
+ end = tmp.indexOf(QLatin1Char('\n'), start);
+ }
+ return tmp.mid(start);
+}
+
+static QStringList toArguments(const CMakeConfig &config, const MacroExpander *expander) {
+ return transform(config, [expander](const CMakeConfigItem &i) -> QString {
+ return i.toArgument(expander);
+ });
+}
+
+static QByteArray trimCMakeCacheLine(const QByteArray &in) {
+ int start = 0;
+ while (start < in.count() && (in.at(start) == ' ' || in.at(start) == '\t'))
+ ++start;
+
+ return in.mid(start, in.count() - start - 1);
+}
+
+static QByteArrayList splitCMakeCacheLine(const QByteArray &line) {
+ const int colonPos = line.indexOf(':');
+ if (colonPos < 0)
+ return QByteArrayList();
+
+ const int equalPos = line.indexOf('=', colonPos + 1);
+ if (equalPos < colonPos)
+ return QByteArrayList();
+
+ return QByteArrayList() << line.mid(0, colonPos)
+ << line.mid(colonPos + 1, equalPos - colonPos - 1)
+ << line.mid(equalPos + 1);
+}
+
+// --------------------------------------------------------------------
+// TeaLeafReader:
+// --------------------------------------------------------------------
+
+TeaLeafReader::TeaLeafReader()
+{
+ connect(EditorManager::instance(), &EditorManager::aboutToSave,
+ this, [this](const IDocument *document) {
+ if (m_cmakeFiles.contains(document->filePath()) || !m_parameters.isAutorun)
+ emit dirty();
+ });
+}
+
+TeaLeafReader::~TeaLeafReader()
+{
+ stop();
+ resetData();
+}
+
+bool TeaLeafReader::isCompatible(const BuildDirReader::Parameters &p)
+{
+ return !p.cmakeHasServerMode;
+}
+
+void TeaLeafReader::resetData()
+{
+ m_hasData = false;
+
+ qDeleteAll(m_watchedFiles);
+ m_watchedFiles.clear();
+
+ m_cmakeCache.clear();
+ m_projectName.clear();
+ m_buildTargets.clear();
+ qDeleteAll(m_files);
+ m_files.clear();
+}
+
+void TeaLeafReader::parse(bool force)
+{
+ const QString cbpFile = CMakeManager::findCbpFile(QDir(m_parameters.buildDirectory.toString()));
+ const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile);
+ if (!cbpFileFi.exists()) {
+ // Initial create:
+ startCMake(toArguments(m_parameters.configuration, m_parameters.expander));
+ return;
+ }
+
+ const bool mustUpdate = force
+ || m_cmakeFiles.isEmpty()
+ || anyOf(m_cmakeFiles, [&cbpFileFi](const FileName &f) {
+ return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
+ });
+ if (mustUpdate) {
+ startCMake(QStringList());
+ } else {
+ extractData();
+ m_hasData = true;
+ emit dataAvailable();
+ }
+}
+
+void TeaLeafReader::stop()
+{
+ cleanUpProcess();
+
+ if (m_future) {
+ m_future->reportCanceled();
+ m_future->reportFinished();
+ delete m_future;
+ m_future = nullptr;
+ }
+}
+
+bool TeaLeafReader::isParsing() const
+{
+ return m_cmakeProcess && m_cmakeProcess->state() != QProcess::NotRunning;
+}
+
+bool TeaLeafReader::hasData() const
+{
+ return m_hasData;
+}
+
+QList<CMakeBuildTarget> TeaLeafReader::buildTargets() const
+{
+ return m_buildTargets;
+}
+
+CMakeConfig TeaLeafReader::parsedConfiguration() const
+{
+ CMakeConfig result;
+ FileName cacheFile = m_parameters.buildDirectory;
+ cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
+ if (!cacheFile.exists())
+ return result;
+ QString errorMessage;
+ m_cmakeCache = parseConfiguration(cacheFile, &errorMessage);
+ if (!errorMessage.isEmpty())
+ emit errorOccured(errorMessage);
+ const FileName sourceOfBuildDir
+ = FileName::fromUtf8(CMakeConfigItem::valueOf("CMAKE_HOME_DIRECTORY", m_cmakeCache));
+ const FileName canonicalSourceOfBuildDir = FileUtils::canonicalPath(sourceOfBuildDir);
+ const FileName canonicalSourceDirectory = FileUtils::canonicalPath(m_parameters.sourceDirectory);
+ if (canonicalSourceOfBuildDir != canonicalSourceDirectory) { // Uses case-insensitive compare where appropriate
+ emit errorOccured(tr("The build directory is not for %1 but for %2")
+ .arg(canonicalSourceOfBuildDir.toUserOutput(),
+ canonicalSourceDirectory.toUserOutput()));
+ }
+ return result;
+}
+
+CMakeConfig TeaLeafReader::parseConfiguration(const FileName &cacheFile, QString *errorMessage) const
+{
+ CMakeConfig result;
+ QFile cache(cacheFile.toString());
+ if (!cache.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ if (errorMessage)
+ *errorMessage = tr("Failed to open %1 for reading.").arg(cacheFile.toUserOutput());
+ return CMakeConfig();
+ }
+
+ QSet<QByteArray> advancedSet;
+ QMap<QByteArray, QByteArray> valuesMap;
+ QByteArray documentation;
+ while (!cache.atEnd()) {
+ const QByteArray line = trimCMakeCacheLine(cache.readLine());
+
+ if (line.isEmpty() || line.startsWith('#'))
+ continue;
+
+ if (line.startsWith("//")) {
+ documentation = line.mid(2);
+ continue;
+ }
+
+ const QByteArrayList pieces = splitCMakeCacheLine(line);
+ if (pieces.isEmpty())
+ continue;
+
+ QTC_ASSERT(pieces.count() == 3, continue);
+ const QByteArray key = pieces.at(0);
+ const QByteArray type = pieces.at(1);
+ const QByteArray value = pieces.at(2);
+
+ if (key.endsWith("-ADVANCED") && value == "1") {
+ advancedSet.insert(key.left(key.count() - 9 /* "-ADVANCED" */));
+ } else if (key.endsWith("-STRINGS") && CMakeConfigItem::typeStringToType(type) == CMakeConfigItem::INTERNAL) {
+ valuesMap[key.left(key.count() - 8) /* "-STRINGS" */] = value;
+ } else {
+ CMakeConfigItem::Type t = CMakeConfigItem::typeStringToType(type);
+ result << CMakeConfigItem(key, t, documentation, value);
+ }
+ }
+
+ // Set advanced flags:
+ for (int i = 0; i < result.count(); ++i) {
+ CMakeConfigItem &item = result[i];
+ item.isAdvanced = advancedSet.contains(item.key);
+
+ if (valuesMap.contains(item.key)) {
+ item.values = CMakeConfigItem::cmakeSplitValue(QString::fromUtf8(valuesMap[item.key]));
+ } else if (item.key == "CMAKE_BUILD_TYPE") {
+ // WA for known options
+ item.values << "" << "Debug" << "Release" << "MinSizeRel" << "RelWithDebInfo";
+ }
+ }
+
+ sort(result, CMakeConfigItem::sortOperator());
+
+ return result;
+}
+
+void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<FileNode *> &allFiles)
+{
+ root->setDisplayName(m_projectName);
+
+ // Delete no longer necessary file watcher based on m_cmakeFiles:
+ const QSet<FileName> currentWatched
+ = transform(m_watchedFiles, [](CMakeFile *cmf) { return cmf->filePath(); });
+ const QSet<FileName> toWatch = m_cmakeFiles;
+ QSet<FileName> toDelete = currentWatched;
+ toDelete.subtract(toWatch);
+ m_watchedFiles = filtered(m_watchedFiles, [&toDelete](Internal::CMakeFile *cmf) {
+ if (toDelete.contains(cmf->filePath())) {
+ delete cmf;
+ return false;
+ }
+ return true;
+ });
+
+ // Add new file watchers:
+ QSet<FileName> toAdd = toWatch;
+ toAdd.subtract(currentWatched);
+ foreach (const FileName &fn, toAdd) {
+ CMakeFile *cm = new CMakeFile(this, fn);
+ DocumentManager::addDocument(cm);
+ m_watchedFiles.insert(cm);
+ }
+
+ QList<FileNode *> added;
+ QList<FileNode *> deleted;
+
+ ProjectExplorer::compareSortedLists(m_files, allFiles, deleted, added, Node::sortByPath);
+
+ QSet<FileName> allIncludePathSet;
+ for (const CMakeBuildTarget &bt : m_buildTargets) {
+ const QList<Utils::FileName> targetIncludePaths
+ = Utils::filtered(bt.includeFiles, [root](const Utils::FileName &fn) {
+ return fn.isChildOf(root->filePath());
+ });
+ allIncludePathSet.unite(QSet<FileName>::fromList(targetIncludePaths));
+ }
+ const QList<FileName> allIncludePaths = allIncludePathSet.toList();
+
+ QList<FileNode *> includedHeaderFiles;
+ QList<FileNode *> unusedFileNodes;
+ std::tie(includedHeaderFiles, unusedFileNodes)
+ = Utils::partition(allFiles, [&allIncludePaths](const FileNode *fn) -> bool {
+ if (fn->fileType() != FileType::Header)
+ return false;
+
+ for (const FileName &inc : allIncludePaths) {
+ if (fn->filePath().isChildOf(inc))
+ return true;
+ }
+ return false;
+ });
+
+ const auto knownFiles = QSet<FileName>::fromList(Utils::transform(m_files, [](const FileNode *fn) { return fn->filePath(); }));
+ QList<FileNode *> uniqueHeaders;
+ foreach (FileNode *ifn, includedHeaderFiles) {
+ if (!knownFiles.contains(ifn->filePath())) {
+ uniqueHeaders.append(ifn);
+ ifn->setEnabled(false);
+ }
+ }
+
+ QList<FileNode *> fileNodes = m_files + uniqueHeaders;
+
+ // Filter out duplicate nodes that e.g. the servermode reader introduces:
+ QSet<FileName> uniqueFileNames;
+ QSet<Node *> uniqueNodes;
+ foreach (FileNode *fn, root->recursiveFileNodes()) {
+ const int count = uniqueFileNames.count();
+ uniqueFileNames.insert(fn->filePath());
+ if (count != uniqueFileNames.count())
+ uniqueNodes.insert(static_cast<Node *>(fn));
+ }
+ root->trim(uniqueNodes);
+ root->removeProjectNodes(root->projectNodes()); // Remove all project nodes
+
+ root->buildTree(fileNodes, m_parameters.sourceDirectory);
+ m_files.clear(); // Some of the FileNodes in files() were deleted!
+}
+
+QSet<Id> TeaLeafReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
+{
+ QSet<Id> languages;
+ const ToolChain *tc = ToolChainManager::findToolChain(m_parameters.toolChainId);
+ const FileName sysroot = m_parameters.sysRoot;
+
+ QHash<QString, QStringList> targetDataCache;
+ foreach (const CMakeBuildTarget &cbt, m_buildTargets) {
+ if (cbt.targetType == UtilityType)
+ continue;
+
+ // CMake shuffles the include paths that it reports via the CodeBlocks generator
+ // So remove the toolchain include paths, so that at least those end up in the correct
+ // place.
+ const QStringList cxxflags = getCXXFlagsFor(cbt, targetDataCache);
+ QSet<FileName> tcIncludes;
+ QStringList includePaths;
+ if (tc) {
+ foreach (const HeaderPath &hp, tc->systemHeaderPaths(cxxflags, sysroot))
+ tcIncludes.insert(FileName::fromString(hp.path()));
+ foreach (const FileName &i, cbt.includeFiles) {
+ if (!tcIncludes.contains(i))
+ includePaths.append(i.toString());
+ }
+ } else {
+ includePaths = transform(cbt.includeFiles, &FileName::toString);
+ }
+ includePaths += m_parameters.buildDirectory.toString();
+ ppBuilder.setIncludePaths(includePaths);
+ ppBuilder.setCFlags(cxxflags);
+ ppBuilder.setCxxFlags(cxxflags);
+ ppBuilder.setDefines(cbt.defines);
+ ppBuilder.setDisplayName(cbt.title);
+
+ const QSet<Id> partLanguages
+ = QSet<Id>::fromList(ppBuilder.createProjectPartsForFiles(
+ transform(cbt.files, [](const FileName &fn) { return fn.toString(); })));
+
+ languages.unite(partLanguages);
+ }
+ return languages;
+
+}
+
+void TeaLeafReader::cleanUpProcess()
+{
+ if (m_cmakeProcess) {
+ m_cmakeProcess->disconnect();
+ Reaper::reap(m_cmakeProcess);
+ m_cmakeProcess = nullptr;
+ }
+
+ // Delete issue parser:
+ if (m_parser)
+ m_parser->flush();
+ delete m_parser;
+ m_parser = nullptr;
+}
+
+void TeaLeafReader::extractData()
+{
+ const FileName srcDir = m_parameters.sourceDirectory;
+ const FileName bldDir = m_parameters.buildDirectory;
+ const FileName topCMake = Utils::FileName(srcDir).appendPath("CMakeLists.txt");
+
+ resetData();
+
+ m_projectName = m_parameters.projectName;
+ m_files.append(new FileNode(topCMake, FileType::Project, false));
+ // Do not insert topCMake into m_cmakeFiles: The project already watches that!
+
+ // Find cbp file
+ FileName cbpFile = FileName::fromString(CMakeManager::findCbpFile(bldDir.toString()));
+ if (cbpFile.isEmpty())
+ return;
+ m_cmakeFiles.insert(cbpFile);
+
+ // Add CMakeCache.txt file:
+ FileName cacheFile = m_parameters.buildDirectory;
+ cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
+ if (cacheFile.toFileInfo().exists())
+ m_cmakeFiles.insert(cacheFile);
+
+ // setFolderName
+ CMakeCbpParser cbpparser;
+ // Parsing
+ if (!cbpparser.parseCbpFile(m_parameters.pathMapper, cbpFile, srcDir))
+ return;
+
+ m_projectName = cbpparser.projectName();
+
+ m_files = cbpparser.fileList();
+ if (cbpparser.hasCMakeFiles()) {
+ m_files.append(cbpparser.cmakeFileList());
+ foreach (const FileNode *node, cbpparser.cmakeFileList())
+ m_cmakeFiles.insert(node->filePath());
+ }
+
+ // Make sure the top cmakelists.txt file is always listed:
+ if (!contains(m_files, [topCMake](FileNode *fn) { return fn->filePath() == topCMake; }))
+ m_files.append(new FileNode(topCMake, FileType::Project, false));
+
+ Utils::sort(m_files, &Node::sortByPath);
+
+ m_buildTargets = cbpparser.buildTargets();
+}
+
+void TeaLeafReader::startCMake(const QStringList &configurationArguments)
+{
+ const FileName buildDirectory = m_parameters.buildDirectory;
+ QTC_ASSERT(!m_cmakeProcess, return);
+ QTC_ASSERT(!m_parser, return);
+ QTC_ASSERT(!m_future, return);
+ QTC_ASSERT(buildDirectory.exists(), return);
+
+ const QString srcDir = m_parameters.sourceDirectory.toString();
+
+ m_parser = new CMakeParser;
+ QDir source = QDir(srcDir);
+ connect(m_parser, &IOutputParser::addTask, m_parser,
+ [source](const Task &task) {
+ if (task.file.isEmpty() || task.file.toFileInfo().isAbsolute()) {
+ TaskHub::addTask(task);
+ } else {
+ Task t = task;
+ t.file = FileName::fromString(source.absoluteFilePath(task.file.toString()));
+ TaskHub::addTask(t);
+ }
+ });
+
+ // Always use the sourceDir: If we are triggered because the build directory is getting deleted
+ // then we are racing against CMakeCache.txt also getting deleted.
+
+ m_cmakeProcess = new QtcProcess;
+ m_cmakeProcess->setWorkingDirectory(buildDirectory.toString());
+ m_cmakeProcess->setEnvironment(m_parameters.environment);
+
+ connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
+ this, &TeaLeafReader::processCMakeOutput);
+ connect(m_cmakeProcess, &QProcess::readyReadStandardError,
+ this, &TeaLeafReader::processCMakeError);
+ connect(m_cmakeProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
+ this, &TeaLeafReader::cmakeFinished);
+
+ QString args;
+ QtcProcess::addArg(&args, srcDir);
+ QtcProcess::addArgs(&args, m_parameters.generatorArguments);
+ QtcProcess::addArgs(&args, configurationArguments);
+
+ TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
+
+ MessageManager::write(tr("Running \"%1 %2\" in %3.")
+ .arg(m_parameters.cmakeExecutable.toUserOutput())
+ .arg(args)
+ .arg(buildDirectory.toUserOutput()));
+
+ m_future = new QFutureInterface<void>();
+ m_future->setProgressRange(0, 1);
+ ProgressManager::addTask(m_future->future(),
+ tr("Configuring \"%1\"").arg(m_parameters.projectName),
+ "CMake.Configure");
+
+ m_cmakeProcess->setCommand(m_parameters.cmakeExecutable.toString(), args);
+ m_cmakeProcess->start();
+ emit configurationStarted();
+}
+
+void TeaLeafReader::cmakeFinished(int code, QProcess::ExitStatus status)
+{
+ QTC_ASSERT(m_cmakeProcess, return);
+
+ // process rest of the output:
+ processCMakeOutput();
+ processCMakeError();
+
+ m_cmakeProcess->disconnect();
+ cleanUpProcess();
+
+ extractData(); // try even if cmake failed...
+
+ QString msg;
+ if (status != QProcess::NormalExit)
+ msg = tr("*** cmake process crashed.");
+ else if (code != 0)
+ msg = tr("*** cmake process exited with exit code %1.").arg(code);
+
+ if (!msg.isEmpty()) {
+ MessageManager::write(msg);
+ TaskHub::addTask(Task::Error, msg, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
+ m_future->reportCanceled();
+ } else {
+ m_future->setProgressValue(1);
+ }
+
+ m_future->reportFinished();
+ delete m_future;
+ m_future = nullptr;
+
+ m_hasData = true;
+ emit dataAvailable();
+}
+
+void TeaLeafReader::processCMakeOutput()
+{
+ static QString rest;
+ rest = lineSplit(rest, m_cmakeProcess->readAllStandardOutput(),
+ [this](const QString &s) { MessageManager::write(s); });
+}
+
+void TeaLeafReader::processCMakeError()
+{
+ static QString rest;
+ rest = lineSplit(rest, m_cmakeProcess->readAllStandardError(), [this](const QString &s) {
+ m_parser->stdError(s);
+ MessageManager::write(s);
+ });
+}
+
+QStringList TeaLeafReader::getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache)
+{
+ // check cache:
+ auto it = cache.constFind(buildTarget.title);
+ if (it != cache.constEnd())
+ return *it;
+
+ if (extractCXXFlagsFromMake(buildTarget, cache))
+ return cache.value(buildTarget.title);
+
+ if (extractCXXFlagsFromNinja(buildTarget, cache))
+ return cache.value(buildTarget.title);
+
+ cache.insert(buildTarget.title, QStringList());
+ return QStringList();
+}
+
+bool TeaLeafReader::extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache)
+{
+ QString makeCommand = buildTarget.makeCommand.toString();
+ int startIndex = makeCommand.indexOf('\"');
+ int endIndex = makeCommand.indexOf('\"', startIndex + 1);
+ if (startIndex != -1 && endIndex != -1) {
+ startIndex += 1;
+ QString makefile = makeCommand.mid(startIndex, endIndex - startIndex);
+ int slashIndex = makefile.lastIndexOf('/');
+ makefile.truncate(slashIndex);
+ makefile.append("/CMakeFiles/" + buildTarget.title + ".dir/flags.make");
+ QFile file(makefile);
+ if (file.exists()) {
+ file.open(QIODevice::ReadOnly | QIODevice::Text);
+ QTextStream stream(&file);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ if (line.startsWith("CXX_FLAGS =")) {
+ // Skip past =
+ cache.insert(buildTarget.title,
+ line.mid(11).trimmed().split(' ', QString::SkipEmptyParts));
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool TeaLeafReader::extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache)
+{
+ Q_UNUSED(buildTarget)
+ if (!cache.isEmpty()) // We fill the cache in one go!
+ return false;
+
+ // Attempt to find build.ninja file and obtain FLAGS (CXX_FLAGS) from there if no suitable flags.make were
+ // found
+ // Get "all" target's working directory
+ QByteArray ninjaFile;
+ QString buildNinjaFile = buildTargets().at(0).workingDirectory.toString();
+ buildNinjaFile += "/build.ninja";
+ QFile buildNinja(buildNinjaFile);
+ if (buildNinja.exists()) {
+ buildNinja.open(QIODevice::ReadOnly | QIODevice::Text);
+ ninjaFile = buildNinja.readAll();
+ buildNinja.close();
+ }
+
+ if (ninjaFile.isEmpty())
+ return false;
+
+ QTextStream stream(ninjaFile);
+ bool cxxFound = false;
+ const QString targetSignature = "# Object build statements for ";
+ QString currentTarget;
+
+ while (!stream.atEnd()) {
+ // 1. Look for a block that refers to the current target
+ // 2. Look for a build rule which invokes CXX_COMPILER
+ // 3. Return the FLAGS definition
+ QString line = stream.readLine().trimmed();
+ if (line.startsWith('#')) {
+ if (line.startsWith(targetSignature)) {
+ int pos = line.lastIndexOf(' ');
+ currentTarget = line.mid(pos + 1);
+ }
+ } else if (!currentTarget.isEmpty() && line.startsWith("build")) {
+ cxxFound = line.indexOf("CXX_COMPILER") != -1;
+ } else if (cxxFound && line.startsWith("FLAGS =")) {
+ // Skip past =
+ cache.insert(currentTarget, line.mid(7).trimmed().split(' ', QString::SkipEmptyParts));
+ }
+ }
+ return !cache.isEmpty();
+}
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.h b/src/plugins/cmakeprojectmanager/tealeafreader.h
new file mode 100644
index 0000000000..beecfa6b76
--- /dev/null
+++ b/src/plugins/cmakeprojectmanager/tealeafreader.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "builddirreader.h"
+
+namespace Utils { class QtcProcess; }
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+class CMakeFile;
+
+class TeaLeafReader : public BuildDirReader
+{
+ Q_OBJECT
+
+public:
+ TeaLeafReader();
+ ~TeaLeafReader() final;
+
+ bool isCompatible(const Parameters &p) final;
+ void resetData() final;
+ void parse(bool force) final;
+ void stop() final;
+
+ bool isParsing() const final;
+ bool hasData() const final;
+
+ QList<CMakeBuildTarget> buildTargets() const final;
+ CMakeConfig parsedConfiguration() const final;
+ void generateProjectTree(CMakeProjectNode *root,
+ const QList<ProjectExplorer::FileNode *> &allFiles) final;
+ QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
+
+private:
+ void cleanUpProcess();
+ void extractData();
+
+ void startCMake(const QStringList &configurationArguments);
+
+ void cmakeFinished(int code, QProcess::ExitStatus status);
+ void processCMakeOutput();
+ void processCMakeError();
+
+ QStringList getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
+ bool extractCXXFlagsFromMake(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
+ bool extractCXXFlagsFromNinja(const CMakeBuildTarget &buildTarget, QHash<QString, QStringList> &cache);
+
+ CMakeConfig parseConfiguration(const Utils::FileName &cacheFile, QString *errorMessage) const;
+
+ Utils::QtcProcess *m_cmakeProcess = nullptr;
+
+ // For error reporting:
+ ProjectExplorer::IOutputParser *m_parser = nullptr;
+ QFutureInterface<void> *m_future = nullptr;
+
+ bool m_hasData = false;
+
+ mutable CMakeConfig m_cmakeCache;
+ QSet<Utils::FileName> m_cmakeFiles;
+ QString m_projectName;
+ QList<CMakeBuildTarget> m_buildTargets;
+ QList<ProjectExplorer::FileNode *> m_files;
+ QSet<Internal::CMakeFile *> m_watchedFiles;
+
+ friend class CMakeFile;
+};
+
+} // namespace Internal
+} // namespace CMakeProjectManager
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
index 888abfbb5c..9423fce3bc 100644
--- a/src/plugins/coreplugin/coreplugin.cpp
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -32,6 +32,7 @@
#include "modemanager.h"
#include "infobar.h"
#include "iwizardfactory.h"
+#include "reaper_p.h"
#include "themechooser.h"
#include <coreplugin/actionmanager/actionmanager.h>
diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h
index 62a11fb2e9..8322ba93bd 100644
--- a/src/plugins/coreplugin/coreplugin.h
+++ b/src/plugins/coreplugin/coreplugin.h
@@ -25,6 +25,8 @@
#pragma once
+#include "reaper_p.h"
+
#include <extensionsystem/iplugin.h>
QT_BEGIN_NAMESPACE
@@ -84,6 +86,7 @@ private:
EditMode *m_editMode;
DesignMode *m_designMode;
Locator *m_locator;
+ ReaperPrivate m_reaper;
};
} // namespace Internal
diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro
index 6de7837acf..035316e5d0 100644
--- a/src/plugins/coreplugin/coreplugin.pro
+++ b/src/plugins/coreplugin/coreplugin.pro
@@ -56,6 +56,7 @@ SOURCES += corejsextensions.cpp \
progressmanager/progressview.cpp \
progressmanager/progressbar.cpp \
progressmanager/futureprogress.cpp \
+ reaper.cpp \
statusbarwidget.cpp \
coreplugin.cpp \
modemanager.cpp \
@@ -160,6 +161,8 @@ HEADERS += corejsextensions.h \
progressmanager/progressbar.h \
progressmanager/futureprogress.h \
progressmanager/progressmanager.h \
+ reaper.h \
+ reaper_p.h \
icontext.h \
icore.h \
infobar.h \
diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs
index fe6b3cb75e..e6ea7f8d3c 100644
--- a/src/plugins/coreplugin/coreplugin.qbs
+++ b/src/plugins/coreplugin/coreplugin.qbs
@@ -88,6 +88,7 @@ Project {
"outputwindow.cpp", "outputwindow.h",
"patchtool.cpp", "patchtool.h",
"plugindialog.cpp", "plugindialog.h",
+ "reaper.cpp", "reaper.h", "reaper_p.h",
"removefiledialog.cpp", "removefiledialog.h", "removefiledialog.ui",
"rightpane.cpp", "rightpane.h",
"settingsdatabase.cpp", "settingsdatabase.h",
diff --git a/src/plugins/coreplugin/fileiconprovider.cpp b/src/plugins/coreplugin/fileiconprovider.cpp
index 1d89aeef9a..b216b41248 100644
--- a/src/plugins/coreplugin/fileiconprovider.cpp
+++ b/src/plugins/coreplugin/fileiconprovider.cpp
@@ -74,6 +74,14 @@ public:
QIcon icon(const QFileInfo &info);
using QFileIconProvider::icon;
+ void registerIconOverlayForFilename(const QIcon &icon, const QString &filename)
+ {
+ QTC_ASSERT(!icon.isNull() && !filename.isEmpty(), return);
+
+ const QPixmap fileIconPixmap = FileIconProvider::overlayIcon(QStyle::SP_FileIcon, icon, QSize(16, 16));
+ m_filenameCache.insert(filename, fileIconPixmap);
+ }
+
void registerIconOverlayForSuffix(const QIcon &icon, const QString &suffix)
{
if (debug)
@@ -83,7 +91,7 @@ public:
const QPixmap fileIconPixmap = FileIconProvider::overlayIcon(QStyle::SP_FileIcon, icon, QSize(16, 16));
// replace old icon, if it exists
- m_cache.insert(suffix, fileIconPixmap);
+ m_suffixCache.insert(suffix, fileIconPixmap);
}
void registerIconOverlayForMimeType(const QIcon &icon, const Utils::MimeType &mimeType)
@@ -93,7 +101,8 @@ public:
}
// Mapping of file suffix to icon.
- QHash<QString, QIcon> m_cache;
+ QHash<QString, QIcon> m_suffixCache;
+ QHash<QString, QIcon> m_filenameCache;
QIcon m_unknownFileIcon;
};
@@ -115,19 +124,27 @@ QIcon FileIconProviderImplementation::icon(const QFileInfo &fileInfo)
qDebug() << "FileIconProvider::icon" << fileInfo.absoluteFilePath();
// Check for cached overlay icons by file suffix.
bool isDir = fileInfo.isDir();
- QString suffix = !isDir ? fileInfo.suffix() : QString();
- if (!m_cache.isEmpty() && !isDir && !suffix.isEmpty()) {
- if (m_cache.contains(suffix))
- return m_cache.value(suffix);
+ const QString filename = !isDir ? fileInfo.fileName() : QString();
+ if (!filename.isEmpty()) {
+ auto it = m_filenameCache.constFind(filename);
+ if (it != m_filenameCache.constEnd())
+ return it.value();
}
- // Get icon from OS.
+ const QString suffix = !isDir ? fileInfo.suffix() : QString();
+ if (!suffix.isEmpty()) {
+ auto it = m_suffixCache.constFind(suffix);
+ if (it != m_suffixCache.constEnd())
+ return it.value();
+ }
+
+ // Get icon from OS (and cache it based on suffix!)
QIcon icon;
if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost())
icon = QFileIconProvider::icon(fileInfo);
else // File icons are unknown on linux systems.
icon = isDir ? QFileIconProvider::icon(fileInfo) : m_unknownFileIcon;
if (!isDir && !suffix.isEmpty())
- m_cache.insert(suffix, icon);
+ m_suffixCache.insert(suffix, icon);
return icon;
}
@@ -174,29 +191,32 @@ QPixmap overlayIcon(QStyle::StandardPixmap baseIcon, const QIcon &overlay, const
Registers an icon for a given suffix, overlaying the system file icon.
See platform note in class documentation about recommended usage.
*/
-void registerIconOverlayForSuffix(const char *path, const char *suffix)
+void registerIconOverlayForSuffix(const QString &path, const QString &suffix)
{
- instance()->registerIconOverlayForSuffix(QIcon(QLatin1String(path)), QLatin1String(suffix));
+ instance()->registerIconOverlayForSuffix(QIcon(path), suffix);
}
/*!
Registers an icon for all the suffixes of a given mime type, overlaying the system file icon.
*/
-void registerIconOverlayForMimeType(const QIcon &icon, const char *mimeType)
+void registerIconOverlayForMimeType(const QIcon &icon, const QString &mimeType)
{
Utils::MimeDatabase mdb;
- instance()->registerIconOverlayForMimeType(icon,
- mdb.mimeTypeForName(QString::fromLatin1(mimeType)));
+ instance()->registerIconOverlayForMimeType(icon, mdb.mimeTypeForName(mimeType));
}
/*!
* \overload
*/
-void registerIconOverlayForMimeType(const char *path, const char *mimeType)
+void registerIconOverlayForMimeType(const QString &path, const QString &mimeType)
{
Utils::MimeDatabase mdb;
- instance()->registerIconOverlayForMimeType(QIcon(QLatin1String(path)),
- mdb.mimeTypeForName(QString::fromLatin1(mimeType)));
+ instance()->registerIconOverlayForMimeType(QIcon(path), mdb.mimeTypeForName(mimeType));
+}
+
+void registerIconOverlayForFilename(const QString &path, const QString &filename)
+{
+ instance()->registerIconOverlayForFilename(QIcon(path), filename);
}
} // namespace FileIconProvider
diff --git a/src/plugins/coreplugin/fileiconprovider.h b/src/plugins/coreplugin/fileiconprovider.h
index 5262bd26bc..dc7f57c299 100644
--- a/src/plugins/coreplugin/fileiconprovider.h
+++ b/src/plugins/coreplugin/fileiconprovider.h
@@ -44,9 +44,10 @@ CORE_EXPORT QIcon icon(QFileIconProvider::IconType type);
// Register additional overlay icons
CORE_EXPORT QPixmap overlayIcon(const QPixmap &baseIcon, const QIcon &overlayIcon);
CORE_EXPORT QPixmap overlayIcon(QStyle::StandardPixmap baseIcon, const QIcon &overlayIcon, const QSize &size);
-CORE_EXPORT void registerIconOverlayForSuffix(const char *path, const char *suffix);
-CORE_EXPORT void registerIconOverlayForMimeType(const char *path, const char *mimeType);
-CORE_EXPORT void registerIconOverlayForMimeType(const QIcon &icon, const char *mimeType);
+CORE_EXPORT void registerIconOverlayForSuffix(const QString &path, const QString &suffix);
+CORE_EXPORT void registerIconOverlayForFilename(const QString &path, const QString &filename);
+CORE_EXPORT void registerIconOverlayForMimeType(const QString &path, const QString &mimeType);
+CORE_EXPORT void registerIconOverlayForMimeType(const QIcon &icon, const QString &mimeType);
} // namespace FileIconProvider
} // namespace Core
diff --git a/src/plugins/coreplugin/find/findplugin.cpp b/src/plugins/coreplugin/find/findplugin.cpp
index 0b3eb6962b..1a690e6679 100644
--- a/src/plugins/coreplugin/find/findplugin.cpp
+++ b/src/plugins/coreplugin/find/findplugin.cpp
@@ -386,11 +386,6 @@ QStringListModel *Find::replaceCompletionModel()
return &(d->m_replaceCompletionModel);
}
-QKeySequence IFindFilter::defaultShortcut() const
-{
- return QKeySequence();
-}
-
// declared in textfindconstants.h
QTextDocument::FindFlags textDocumentFlagsForFindFlags(FindFlags flags)
{
diff --git a/src/plugins/coreplugin/find/ifindfilter.cpp b/src/plugins/coreplugin/find/ifindfilter.cpp
index db1c712190..e080e249f0 100644
--- a/src/plugins/coreplugin/find/ifindfilter.cpp
+++ b/src/plugins/coreplugin/find/ifindfilter.cpp
@@ -28,6 +28,7 @@
#include <coreplugin/coreicons.h>
#include <QApplication>
+#include <QKeySequence>
#include <QPainter>
#include <QPixmap>
@@ -218,6 +219,11 @@
namespace Core {
+QKeySequence IFindFilter::defaultShortcut() const
+{
+ return QKeySequence();
+}
+
FindFlags IFindFilter::supportedFindFlags() const
{
return FindCaseSensitively
diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h
index a78775bae3..eb880e7c70 100644
--- a/src/plugins/coreplugin/iversioncontrol.h
+++ b/src/plugins/coreplugin/iversioncontrol.h
@@ -93,6 +93,17 @@ public:
virtual Id id() const = 0;
/*!
+ * \brief isVcsFileOrDirectory
+ * \param fileName
+ * \return True if filename is a file or directory that is maintained by the
+ * version control system.
+ *
+ * It will return true only for exact matches of the name, not for e.g. files in a
+ * directory owned by the version control system (e.g. .git/control).
+ */
+ virtual bool isVcsFileOrDirectory(const Utils::FileName &fileName) const = 0;
+
+ /*!
* Returns whether files in this directory should be managed with this
* version control.
* If \a topLevel is non-null, it should return the topmost directory,
@@ -232,6 +243,9 @@ public:
{ }
~TestVersionControl();
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final
+ { Q_UNUSED(fileName); return false; }
+
void setManagedDirectories(const QHash<QString, QString> &dirs);
void setManagedFiles(const QSet<QString> &files);
diff --git a/src/plugins/coreplugin/reaper.cpp b/src/plugins/coreplugin/reaper.cpp
new file mode 100644
index 0000000000..1cc9d12c0c
--- /dev/null
+++ b/src/plugins/coreplugin/reaper.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "reaper.h"
+#include "reaper_p.h"
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+#include <QThread>
+
+namespace Core {
+namespace Internal {
+
+static ReaperPrivate *d = nullptr;
+
+ProcessReaper::ProcessReaper(QProcess *p, int timeoutMs) : m_process(p)
+{
+ d->m_reapers.append(this);
+
+ m_iterationTimer.setInterval(timeoutMs);
+ m_iterationTimer.setSingleShot(true);
+ connect(&m_iterationTimer, &QTimer::timeout, this, &ProcessReaper::nextIteration);
+
+ QTimer::singleShot(0, this, &ProcessReaper::nextIteration);
+ m_futureInterface.reportStarted();
+}
+
+ProcessReaper::~ProcessReaper()
+{
+ d->m_reapers.removeOne(this);
+}
+
+int ProcessReaper::timeoutMs() const
+{
+ const int remaining = m_iterationTimer.remainingTime();
+ if (remaining < 0)
+ return m_iterationTimer.interval();
+ m_iterationTimer.stop();
+ return remaining;
+}
+
+bool ProcessReaper::isFinished() const
+{
+ return !m_process;
+}
+
+void ProcessReaper::nextIteration()
+{
+ QProcess::ProcessState state = m_process ? m_process->state() : QProcess::NotRunning;
+ if (state == QProcess::NotRunning || m_emergencyCounter > 5) {
+ delete m_process;
+ m_process = nullptr;
+ m_futureInterface.reportFinished();
+ return;
+ }
+
+ if (state == QProcess::Starting) {
+ if (m_lastState == QProcess::Starting)
+ m_process->kill();
+ } else if (state == QProcess::Running) {
+ if (m_lastState == QProcess::Running)
+ m_process->kill();
+ else
+ m_process->terminate();
+ }
+
+ m_lastState = state;
+ m_iterationTimer.start();
+
+ ++m_emergencyCounter;
+}
+
+ReaperPrivate::ReaperPrivate()
+{
+ d = this;
+}
+
+ReaperPrivate::~ReaperPrivate()
+{
+ while (!m_reapers.isEmpty()) {
+ int alreadyWaited = 0;
+ QList<ProcessReaper *> toDelete;
+
+ // push reapers along:
+ foreach (ProcessReaper *pr, m_reapers) {
+ const int timeoutMs = pr->timeoutMs();
+ if (alreadyWaited < timeoutMs) {
+ const unsigned long toSleep = static_cast<unsigned long>(timeoutMs - alreadyWaited);
+ QThread::msleep(toSleep);
+ alreadyWaited += toSleep;
+ }
+
+ pr->nextIteration();
+
+ if (pr->isFinished())
+ toDelete.append(pr);
+ }
+
+ // Clean out reapers that finished in the meantime
+ qDeleteAll(toDelete);
+ toDelete.clear();
+ }
+
+ d = nullptr;
+}
+
+} // namespace Internal
+
+namespace Reaper {
+
+void reap(QProcess *process, int timeoutMs)
+{
+ if (!process)
+ return;
+
+ QTC_ASSERT(Internal::d, return);
+
+ new Internal::ProcessReaper(process, timeoutMs);
+}
+
+} // namespace Reaper
+} // namespace Core
+
diff --git a/src/plugins/cmakeprojectmanager/cmakefile.h b/src/plugins/coreplugin/reaper.h
index 4f3376b640..7c2b2a356a 100644
--- a/src/plugins/cmakeprojectmanager/cmakefile.h
+++ b/src/plugins/coreplugin/reaper.h
@@ -25,24 +25,14 @@
#pragma once
-#include <coreplugin/idocument.h>
+#include "core_global.h"
-namespace CMakeProjectManager {
-namespace Internal {
+QT_FORWARD_DECLARE_CLASS(QProcess);
-class BuildDirManager;
+namespace Core {
+namespace Reaper {
-class CMakeFile : public Core::IDocument
-{
-public:
- CMakeFile(BuildDirManager *bdm, const Utils::FileName &fileName);
+CORE_EXPORT void reap(QProcess *p, int timeoutMs = 500);
- ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override;
- bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override;
-
-private:
- BuildDirManager *m_buildDirManager;
-};
-
-} // namespace Internal
-} // namespace CMakeProjectManager
+} // namespace Reaper
+} // namespace Core
diff --git a/src/plugins/cmakeprojectmanager/cmakefile.cpp b/src/plugins/coreplugin/reaper_p.h
index 612e48ec8d..474dbc6e0c 100644
--- a/src/plugins/cmakeprojectmanager/cmakefile.cpp
+++ b/src/plugins/coreplugin/reaper_p.h
@@ -23,43 +23,49 @@
**
****************************************************************************/
-#include "cmakefile.h"
+#pragma once
-#include "builddirmanager.h"
-#include "cmakeprojectconstants.h"
+#include <QObject>
+#include <QFutureInterface>
+#include <QProcess>
+#include <QTimer>
-#include <projectexplorer/target.h>
+namespace Core {
+namespace Internal {
-#include <utils/fileutils.h>
+class CorePlugin;
-using namespace Utils;
+class ProcessReaper : public QObject
+{
+ Q_OBJECT
-namespace CMakeProjectManager {
-namespace Internal {
+public:
+ ProcessReaper(QProcess *p, int timeoutMs);
+ ~ProcessReaper();
-CMakeFile::CMakeFile(BuildDirManager *bdm, const FileName &fileName) : m_buildDirManager(bdm)
-{
- setId("Cmake.ProjectFile");
- setMimeType(QLatin1String(Constants::CMAKEPROJECTMIMETYPE));
- setFilePath(fileName);
-}
+ int timeoutMs() const;
+ bool isFinished() const;
+ void nextIteration();
-Core::IDocument::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
-{
- Q_UNUSED(state)
- Q_UNUSED(type)
- return BehaviorSilent;
-}
+private:
+ mutable QTimer m_iterationTimer;
+ QFutureInterface<void> m_futureInterface;
+ QProcess *m_process;
+ int m_emergencyCounter = 0;
+ QProcess::ProcessState m_lastState = QProcess::NotRunning;
+};
-bool CMakeFile::reload(QString *errorString, Core::IDocument::ReloadFlag flag, Core::IDocument::ChangeType type)
-{
- Q_UNUSED(errorString);
- Q_UNUSED(flag);
+class ReaperPrivate {
+public:
+ ~ReaperPrivate();
+
+ QList<ProcessReaper *> m_reapers;
+
+private:
+ ReaperPrivate();
- if (type != TypePermissions)
- m_buildDirManager->handleCmakeFileChange();
- return true;
-}
+ friend class CorePlugin;
+};
} // namespace Internal
-} // namespace CMakeProjectManager
+} // namespace Core
diff --git a/src/plugins/cvs/cvsclient.cpp b/src/plugins/cvs/cvsclient.cpp
index 5f85889092..bd6052a4ee 100644
--- a/src/plugins/cvs/cvsclient.cpp
+++ b/src/plugins/cvs/cvsclient.cpp
@@ -29,7 +29,7 @@
#include <vcsbase/vcsbaseplugin.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseconstants.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
#include <QDir>
#include <QFileInfo>
@@ -43,20 +43,19 @@ namespace Cvs {
namespace Internal {
// Parameter widget controlling whitespace diff mode, associated with a parameter
-class CvsDiffParameterWidget : public VcsBaseEditorParameterWidget
+class CvsDiffConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- explicit CvsDiffParameterWidget(VcsBaseClientSettings &settings, QWidget *parent = 0);
+ CvsDiffConfig(VcsBaseClientSettings &settings, QToolBar *toolBar);
QStringList arguments() const;
private:
VcsBaseClientSettings &m_settings;
};
-CvsDiffParameterWidget::CvsDiffParameterWidget(VcsBaseClientSettings &settings,
- QWidget *parent) :
- VcsBaseEditorParameterWidget(parent),
+CvsDiffConfig::CvsDiffConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar),
m_settings(settings)
{
mapSetting(addToggleButton(QLatin1String("-w"), tr("Ignore Whitespace")),
@@ -65,18 +64,20 @@ CvsDiffParameterWidget::CvsDiffParameterWidget(VcsBaseClientSettings &settings,
settings.boolPointer(CvsSettings::diffIgnoreBlankLinesKey));
}
-QStringList CvsDiffParameterWidget::arguments() const
+QStringList CvsDiffConfig::arguments() const
{
QStringList args;
args = m_settings.stringValue(CvsSettings::diffOptionsKey).split(QLatin1Char(' '),
QString::SkipEmptyParts);
- args += VcsBaseEditorParameterWidget::arguments();
+ args += VcsBaseEditorConfig::arguments();
return args;
}
CvsClient::CvsClient() : VcsBaseClient(new CvsSettings)
{
- setDiffParameterWidgetCreator([this] { return new CvsDiffParameterWidget(settings()); });
+ setDiffConfigCreator([this](QToolBar *toolBar) {
+ return new CvsDiffConfig(settings(), toolBar);
+ });
}
CvsSettings &CvsClient::settings() const
diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp
index c277557d16..d9bf55a86e 100644
--- a/src/plugins/cvs/cvscontrol.cpp
+++ b/src/plugins/cvs/cvscontrol.cpp
@@ -33,6 +33,7 @@
#include <vcsbase/vcscommand.h>
#include <utils/fileutils.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
@@ -54,6 +55,12 @@ Core::Id CvsControl::id() const
return Core::Id(VcsBase::Constants::VCS_ID_CVS);
}
+bool CvsControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ return fileName.toFileInfo().isDir()
+ && !fileName.fileName().compare("CVS", Utils::HostOsInfo::fileNameCaseSensitivity());
+}
+
bool CvsControl::isConfigured() const
{
const Utils::FileName binary = m_plugin->client()->vcsBinary();
diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h
index ea9d94ccf7..1bc093b788 100644
--- a/src/plugins/cvs/cvscontrol.h
+++ b/src/plugins/cvs/cvscontrol.h
@@ -39,28 +39,30 @@ class CvsControl : public Core::IVersionControl
public:
explicit CvsControl(CvsPlugin *plugin);
- QString displayName() const override;
- Core::Id id() const override;
+ QString displayName() const final;
+ Core::Id id() const final;
- bool managesDirectory(const QString &directory, QString *topLevel = 0) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
- bool isConfigured() const override;
- bool supportsOperation(Operation operation) const override;
- OpenSupportMode openSupportMode(const QString &fileName) const override;
- bool vcsOpen(const QString &fileName) override;
- bool vcsAdd(const QString &fileName) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
- bool vcsAnnotate(const QString &file, int line) override;
+ bool managesDirectory(const QString &directory, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
- QString vcsOpenText() const override;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ OpenSupportMode openSupportMode(const QString &fileName) const final;
+ bool vcsOpen(const QString &fileName) final;
+ bool vcsAdd(const QString &fileName) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
+ bool vcsAnnotate(const QString &file, int line) final;
+
+ QString vcsOpenText() const final;
Core::ShellCommand *createInitialCheckoutCommand(const QString &url,
const Utils::FileName &baseDirectory,
const QString &localName,
- const QStringList &extraArgs) override;
+ const QStringList &extraArgs) final;
void emitRepositoryChanged(const QString &s);
void emitFilesChanged(const QStringList &l);
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 336a45f6a8..06c25a4270 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -34,7 +34,6 @@
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcsbaseeditor.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <vcsbase/vcscommand.h>
#include <vcsbase/vcsoutputwindow.h>
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 49c2f0633a..f23da12034 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -1880,7 +1880,6 @@ void DebuggerEngine::validateExecutable(DebuggerRunParameters *sp)
switch (sp->toolChainAbi.binaryFormat()) {
case Abi::PEFormat: {
if (sp->masterEngineType != CdbEngineType) {
- warnOnInappropriateDebugger = true;
detailedWarning = tr(
"The inferior is in the Portable Executable format.\n"
"Selecting CDB as debugger would improve the debugging "
@@ -1904,7 +1903,6 @@ void DebuggerEngine::validateExecutable(DebuggerRunParameters *sp)
}
case Abi::ElfFormat: {
if (sp->masterEngineType == CdbEngineType) {
- warnOnInappropriateDebugger = true;
detailedWarning = tr(
"The inferior is in the ELF format.\n"
"Selecting GDB or LLDB as debugger would improve the debugging "
diff --git a/src/plugins/designer/resourcehandler.cpp b/src/plugins/designer/resourcehandler.cpp
index 8f8d791969..32e86796cc 100644
--- a/src/plugins/designer/resourcehandler.cpp
+++ b/src/plugins/designer/resourcehandler.cpp
@@ -68,7 +68,7 @@ void QrcFilesVisitor::visitProjectNode(ProjectNode *projectNode)
void QrcFilesVisitor::visitFolderNode(FolderNode *folderNode)
{
foreach (const FileNode *fileNode, folderNode->fileNodes()) {
- if (fileNode->fileType() == ResourceType)
+ if (fileNode->fileType() == FileType::Resource)
m_qrcFiles.append(fileNode->filePath().toString());
}
if (dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp
index e33d20dd94..264b2e8b24 100644
--- a/src/plugins/genericprojectmanager/genericproject.cpp
+++ b/src/plugins/genericprojectmanager/genericproject.cpp
@@ -92,15 +92,15 @@ GenericProject::GenericProject(Manager *manager, const QString &fileName)
DocumentManager::addDocument(m_configIDocument);
FileNode *projectFilesNode = new FileNode(Utils::FileName::fromString(m_filesFileName),
- ProjectFileType,
+ FileType::Project,
/* generated = */ false);
FileNode *projectIncludesNode = new FileNode(Utils::FileName::fromString(m_includesFileName),
- ProjectFileType,
+ FileType::Project,
/* generated = */ false);
FileNode *projectConfigNode = new FileNode(Utils::FileName::fromString(m_configFileName),
- ProjectFileType,
+ FileType::Project,
/* generated = */ false);
rootProjectNode()->addFileNodes(QList<FileNode *>() << projectFilesNode
@@ -277,9 +277,9 @@ void GenericProject::refresh(RefreshOptions options)
if (options & Files) {
QList<FileNode *> fileNodes = Utils::transform(files(), [](const QString &f) {
- FileType fileType = SourceType; // ### FIXME
+ FileType fileType = FileType::Source; // ### FIXME
if (f.endsWith(QLatin1String(".qrc")))
- fileType = ResourceType;
+ fileType = FileType::Resource;
return new FileNode(Utils::FileName::fromString(f), fileType, false);
});
rootProjectNode()->buildTree(fileNodes);
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 41078392a7..3ab1733a05 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -54,7 +54,7 @@
#include <vcsbase/submitfilemodel.h>
#include <vcsbase/vcsbaseeditor.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h>
#include <vcsbase/vcscommand.h>
#include <vcsbase/vcsoutputwindow.h>
@@ -389,13 +389,13 @@ void ShowController::reloadFinished(bool success)
///////////////////////////////
-class BaseGitDiffArgumentsWidget : public VcsBaseEditorParameterWidget
+class BaseGitDiffArgumentsWidget : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- BaseGitDiffArgumentsWidget(VcsBaseClientSettings &settings, QWidget *parent = nullptr) :
- VcsBaseEditorParameterWidget(parent)
+ BaseGitDiffArgumentsWidget(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar)
{
m_patienceButton
= addToggleButton("--patience", tr("Patience"),
@@ -408,17 +408,17 @@ public:
}
protected:
- QToolButton *m_patienceButton;
- QToolButton *m_ignoreWSButton;
+ QAction *m_patienceButton;
+ QAction *m_ignoreWSButton;
};
-class GitBlameArgumentsWidget : public VcsBaseEditorParameterWidget
+class GitBlameArgumentsWidget : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- GitBlameArgumentsWidget(VcsBaseClientSettings &settings, QWidget *parent = nullptr) :
- VcsBaseEditorParameterWidget(parent)
+ GitBlameArgumentsWidget(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar)
{
mapSetting(addToggleButton(QString(), tr("Omit Date"),
tr("Hide the date of a change from the output.")),
@@ -434,22 +434,27 @@ class GitLogArgumentsWidget : public BaseGitDiffArgumentsWidget
Q_OBJECT
public:
- GitLogArgumentsWidget(VcsBaseClientSettings &settings, QWidget *parent = nullptr) :
- BaseGitDiffArgumentsWidget(settings, parent)
+ GitLogArgumentsWidget(VcsBaseClientSettings &settings, QToolBar *toolBar = nullptr) :
+ BaseGitDiffArgumentsWidget(settings, toolBar)
{
- QToolButton *diffButton = addToggleButton("--patch", tr("Show Diff"),
+ QAction *diffButton = addToggleButton("--patch", tr("Show Diff"),
tr("Show difference."));
mapSetting(diffButton, settings.boolPointer(GitSettings::logDiffKey));
- connect(diffButton, &QToolButton::toggled, m_patienceButton, &QToolButton::setVisible);
- connect(diffButton, &QToolButton::toggled, m_ignoreWSButton, &QToolButton::setVisible);
+ connect(diffButton, &QAction::toggled, m_patienceButton, &QAction::setVisible);
+ connect(diffButton, &QAction::toggled, m_ignoreWSButton, &QAction::setVisible);
m_patienceButton->setVisible(diffButton->isChecked());
m_ignoreWSButton->setVisible(diffButton->isChecked());
+ QAction *firstParentButton =
+ addToggleButton({ "-m", "--first-parent" },
+ tr("First Parent"),
+ tr("Follow only the first parent on merge commits."));
+ mapSetting(firstParentButton, settings.boolPointer(GitSettings::firstParentKey));
const QStringList graphArguments = {
"--graph", "--oneline", "--topo-order",
QLatin1String("--pretty=format:") + graphLogFormatC
};
- QToolButton *graphButton = addToggleButton(graphArguments, tr("Graph"),
- tr("Show textual graph log."));
+ QAction *graphButton = addToggleButton(graphArguments, tr("Graph"),
+ tr("Show textual graph log."));
mapSetting(graphButton, settings.boolPointer(GitSettings::graphLogKey));
}
};
@@ -813,7 +818,7 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName,
QString msgArg;
if (!fileName.isEmpty())
msgArg = fileName;
- else if (!args.isEmpty())
+ else if (!args.isEmpty() && !args.first().startsWith('-'))
msgArg = args.first();
else
msgArg = workingDirectory;
@@ -824,11 +829,14 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName,
const QString sourceFile = VcsBaseEditor::getSource(workingDir, fileName);
VcsBaseEditorWidget *editor = createVcsEditor(editorId, title, sourceFile,
codecFor(CodecLogOutput), "logTitle", msgArg);
- if (!editor->configurationWidget()) {
- auto *argWidget = new GitLogArgumentsWidget(settings());
- connect(argWidget, &VcsBaseEditorParameterWidget::commandExecutionRequested,
- [=]() { this->log(workingDir, fileName, enableAnnotationContextMenu, args); });
- editor->setConfigurationWidget(argWidget);
+ QStringList effectiveArgs = args;
+ if (!editor->configurationAdded()) {
+ auto *argWidget = new GitLogArgumentsWidget(settings(), editor->toolBar());
+ argWidget->setBaseArguments(args);
+ connect(argWidget, &VcsBaseEditorConfig::commandExecutionRequested,
+ [=]() { this->log(workingDir, fileName, enableAnnotationContextMenu, argWidget->arguments()); });
+ effectiveArgs = argWidget->arguments();
+ editor->setConfigurationAdded();
}
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
editor->setWorkingDirectory(workingDir);
@@ -838,11 +846,7 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName,
if (logCount > 0)
arguments << "-n" << QString::number(logCount);
- auto *argWidget = editor->configurationWidget();
- argWidget->setBaseArguments(args);
- QStringList userArgs = argWidget->arguments();
-
- arguments.append(userArgs);
+ arguments.append(effectiveArgs);
if (!fileName.isEmpty())
arguments << "--follow" << "--" << fileName;
@@ -911,21 +915,22 @@ VcsBaseEditorWidget *GitClient::annotate(
VcsBaseEditorWidget *editor
= createVcsEditor(editorId, title, sourceFile, codecFor(CodecSource, sourceFile),
"blameFileName", id);
- if (!editor->configurationWidget()) {
- auto *argWidget = new GitBlameArgumentsWidget(settings());
+ QStringList effectiveArgs = extraOptions;
+ if (!editor->configurationAdded()) {
+ auto *argWidget = new GitBlameArgumentsWidget(settings(), editor->toolBar());
argWidget->setBaseArguments(extraOptions);
- connect(argWidget, &VcsBaseEditorParameterWidget::commandExecutionRequested,
+ connect(argWidget, &VcsBaseEditorConfig::commandExecutionRequested,
[=] {
const int line = VcsBaseEditor::lineNumberOfCurrentEditor();
- annotate(workingDir, file, revision, line, extraOptions);
+ annotate(workingDir, file, revision, line, argWidget->arguments());
} );
- editor->setConfigurationWidget(argWidget);
+ effectiveArgs = argWidget->arguments();
+ editor->setConfigurationAdded();
}
editor->setWorkingDirectory(workingDir);
QStringList arguments = { "blame", "--root" };
- arguments << editor->configurationWidget()->arguments();
- arguments << "--" << file;
+ arguments << effectiveArgs << "--" << file;
if (!revision.isEmpty())
arguments << revision;
vcsExec(workingDir, arguments, editor, false, 0, lineNumber);
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index 869ed36622..5261d5afb8 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -50,7 +50,6 @@ namespace VcsBase {
class VcsCommand;
class SubmitFileModel;
class VcsBaseEditorWidget;
- class VcsBaseEditorParameterWidget;
}
namespace DiffEditor {
diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp
index 337db12627..ce9bb5589b 100644
--- a/src/plugins/git/gitsettings.cpp
+++ b/src/plugins/git/gitsettings.cpp
@@ -44,6 +44,7 @@ const QLatin1String GitSettings::gitkOptionsKey("GitKOptions");
const QLatin1String GitSettings::logDiffKey("LogDiff");
const QLatin1String GitSettings::repositoryBrowserCmd("RepositoryBrowserCmd");
const QLatin1String GitSettings::graphLogKey("GraphLog");
+const QLatin1String GitSettings::firstParentKey("FirstParent");
const QLatin1String GitSettings::lastResetIndexKey("LastResetIndex");
GitSettings::GitSettings()
@@ -64,6 +65,7 @@ GitSettings::GitSettings()
declareKey(logDiffKey, false);
declareKey(repositoryBrowserCmd, QString());
declareKey(graphLogKey, false);
+ declareKey(firstParentKey, false);
declareKey(lastResetIndexKey, 0);
}
diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h
index c2f2281721..ec31d2ed94 100644
--- a/src/plugins/git/gitsettings.h
+++ b/src/plugins/git/gitsettings.h
@@ -55,6 +55,7 @@ public:
static const QLatin1String logDiffKey;
static const QLatin1String repositoryBrowserCmd;
static const QLatin1String graphLogKey;
+ static const QLatin1String firstParentKey;
static const QLatin1String lastResetIndexKey;
Utils::FileName gitExecutable(bool *ok = 0, QString *errorMessage = 0) const;
diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp
index b1ba613911..564c32d3b9 100644
--- a/src/plugins/git/gitversioncontrol.cpp
+++ b/src/plugins/git/gitversioncontrol.cpp
@@ -30,6 +30,8 @@
#include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcscommand.h>
+#include <utils/hostosinfo.h>
+
#include <QFileInfo>
#include <QProcessEnvironment>
@@ -74,6 +76,12 @@ Core::Id GitVersionControl::id() const
return Core::Id(VcsBase::Constants::VCS_ID_GIT);
}
+bool GitVersionControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ return fileName.toFileInfo().isDir()
+ && !fileName.fileName().compare(".git", Utils::HostOsInfo::fileNameCaseSensitivity());
+}
+
bool GitVersionControl::isConfigured() const
{
return !m_client->vcsBinary().isEmpty();
diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h
index b46ee90484..2df3c7c856 100644
--- a/src/plugins/git/gitversioncontrol.h
+++ b/src/plugins/git/gitversioncontrol.h
@@ -39,29 +39,31 @@ class GitVersionControl : public Core::IVersionControl
public:
explicit GitVersionControl(GitClient *client);
- QString displayName() const override;
- Core::Id id() const override;
+ QString displayName() const final;
+ Core::Id id() const final;
- bool managesDirectory(const QString &directory, QString *topLevel) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
- bool isConfigured() const override;
- bool supportsOperation(Operation operation) const override;
- bool vcsOpen(const QString &fileName) override;
- bool vcsAdd(const QString &fileName) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
+ bool managesDirectory(const QString &directory, QString *topLevel) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
- bool vcsAnnotate(const QString &file, int line) override;
- QString vcsTopic(const QString &directory) override;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ bool vcsOpen(const QString &fileName) final;
+ bool vcsAdd(const QString &fileName) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
+
+ bool vcsAnnotate(const QString &file, int line) final;
+ QString vcsTopic(const QString &directory) final;
Core::ShellCommand *createInitialCheckoutCommand(const QString &url,
const Utils::FileName &baseDirectory,
const QString &localName,
- const QStringList &extraArgs) override;
+ const QStringList &extraArgs) final;
- QStringList additionalToolsPath() const override;
+ QStringList additionalToolsPath() const final;
void emitFilesChanged(const QStringList &);
void emitRepositoryChanged(const QString &);
diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp
index 21149bce98..3efc8a3352 100644
--- a/src/plugins/mercurial/mercurialclient.cpp
+++ b/src/plugins/mercurial/mercurialclient.cpp
@@ -30,9 +30,10 @@
#include <vcsbase/vcsoutputwindow.h>
#include <vcsbase/vcsbaseplugin.h>
#include <vcsbase/vcsbaseeditor.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
#include <utils/synchronousprocess.h>
#include <utils/fileutils.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QDateTime>
@@ -49,12 +50,12 @@ namespace Mercurial {
namespace Internal {
// Parameter widget controlling whitespace diff mode, associated with a parameter
-class MercurialDiffParameterWidget : public VcsBaseEditorParameterWidget
+class MercurialDiffConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- MercurialDiffParameterWidget(VcsBaseClientSettings &settings, QWidget *parent = 0) :
- VcsBaseEditorParameterWidget(parent)
+ MercurialDiffConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar)
{
mapSetting(addToggleButton(QLatin1String("-w"), tr("Ignore Whitespace")),
settings.boolPointer(MercurialSettings::diffIgnoreWhiteSpaceKey));
@@ -65,7 +66,9 @@ public:
MercurialClient::MercurialClient() : VcsBaseClient(new MercurialSettings)
{
- setDiffParameterWidgetCreator([this] { return new MercurialDiffParameterWidget(settings()); });
+ setDiffConfigCreator([this](QToolBar *toolBar) {
+ return new MercurialDiffConfig(settings(), toolBar);
+ });
}
bool MercurialClient::manifestSync(const QString &repository, const QString &relativeFilename)
@@ -333,6 +336,12 @@ void MercurialClient::revertAll(const QString &workingDir, const QString &revisi
QStringList(extraOptions) << QLatin1String("--all"));
}
+bool MercurialClient::isVcsDirectory(const FileName &fileName) const
+{
+ return fileName.toFileInfo().isDir()
+ && !fileName.fileName().compare(Constants::MERCURIALREPO, HostOsInfo::fileNameCaseSensitivity());
+}
+
void MercurialClient::view(const QString &source, const QString &id,
const QStringList &extraOptions)
{
diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h
index f1dfce97ae..2692b4bfd6 100644
--- a/src/plugins/mercurial/mercurialclient.h
+++ b/src/plugins/mercurial/mercurialclient.h
@@ -70,6 +70,7 @@ public:
void revertAll(const QString &workingDir, const QString &revision = QString(),
const QStringList &extraOptions = QStringList()) override;
+ bool isVcsDirectory(const Utils::FileName &fileName) const;
QString findTopLevelForFile(const QFileInfo &file) const override;
public slots:
diff --git a/src/plugins/mercurial/mercurialcontrol.cpp b/src/plugins/mercurial/mercurialcontrol.cpp
index 3c3a42bccf..b60fd3e419 100644
--- a/src/plugins/mercurial/mercurialcontrol.cpp
+++ b/src/plugins/mercurial/mercurialcontrol.cpp
@@ -78,6 +78,11 @@ Core::Id MercurialControl::id() const
return Core::Id(VcsBase::Constants::VCS_ID_MERCURIAL);
}
+bool MercurialControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ return mercurialClient->isVcsDirectory(fileName);
+}
+
bool MercurialControl::managesDirectory(const QString &directory, QString *topLevel) const
{
QFileInfo dir(directory);
diff --git a/src/plugins/mercurial/mercurialcontrol.h b/src/plugins/mercurial/mercurialcontrol.h
index f9cf123fe2..39917063ac 100644
--- a/src/plugins/mercurial/mercurialcontrol.h
+++ b/src/plugins/mercurial/mercurialcontrol.h
@@ -45,23 +45,25 @@ class MercurialControl : public Core::IVersionControl
public:
explicit MercurialControl(MercurialClient *mercurialClient);
- QString displayName() const override;
- Core::Id id() const override;
- bool managesDirectory(const QString &filename, QString *topLevel = 0) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
- bool isConfigured() const override;
- bool supportsOperation(Operation operation) const override;
- bool vcsOpen(const QString &fileName) override;
- bool vcsAdd(const QString &filename) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
- bool vcsAnnotate(const QString &file, int line) override;
+ QString displayName() const final;
+ Core::Id id() const final;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
+
+ bool managesDirectory(const QString &filename, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ bool vcsOpen(const QString &fileName) final;
+ bool vcsAdd(const QString &filename) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
+ bool vcsAnnotate(const QString &file, int line) final;
Core::ShellCommand *createInitialCheckoutCommand(const QString &url,
const Utils::FileName &baseDirectory,
const QString &localName,
- const QStringList &extraArgs) override;
+ const QStringList &extraArgs) final;
bool sccManaged(const QString &filename);
diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp
index f7bdd58670..349b4ed7aa 100644
--- a/src/plugins/modeleditor/componentviewcontroller.cpp
+++ b/src/plugins/modeleditor/componentviewcontroller.cpp
@@ -296,7 +296,7 @@ void UpdateIncludeDependenciesVisitor::collectElementPaths(const ProjectExplorer
QStringList elementsPath = qmt::NameController::buildElementsPath(nodePath, false);
filePathsMap->insertMulti(elementName, Node(fileNode->filePath().toString(), elementsPath));
}
- foreach (const ProjectExplorer::FolderNode *subNode, folderNode->subFolderNodes())
+ foreach (const ProjectExplorer::FolderNode *subNode, folderNode->folderNodes())
collectElementPaths(subNode, filePathsMap);
}
@@ -419,7 +419,7 @@ void ComponentViewController::createComponentModel(const ProjectExplorer::Folder
}
}
- foreach (const ProjectExplorer::FolderNode *subNode, folderNode->subFolderNodes())
+ foreach (const ProjectExplorer::FolderNode *subNode, folderNode->folderNodes())
createComponentModel(subNode, diagram, anchorFolder);
}
diff --git a/src/plugins/modeleditor/modelindexer.cpp b/src/plugins/modeleditor/modelindexer.cpp
index 7dd932d3a1..eac685f433 100644
--- a/src/plugins/modeleditor/modelindexer.cpp
+++ b/src/plugins/modeleditor/modelindexer.cpp
@@ -456,7 +456,7 @@ QString ModelIndexer::findFirstModel(ProjectExplorer::FolderNode *folderNode)
if (mimeType.name() == QLatin1String(Constants::MIME_TYPE_MODEL))
return fileNode->filePath().toString();
}
- foreach (ProjectExplorer::FolderNode *subFolderNode, folderNode->subFolderNodes()) {
+ foreach (ProjectExplorer::FolderNode *subFolderNode, folderNode->folderNodes()) {
QString modelFileName = findFirstModel(subFolderNode);
if (!modelFileName.isEmpty())
return modelFileName;
diff --git a/src/plugins/modeleditor/pxnodecontroller.cpp b/src/plugins/modeleditor/pxnodecontroller.cpp
index ecac98854c..7fa03a4d75 100644
--- a/src/plugins/modeleditor/pxnodecontroller.cpp
+++ b/src/plugins/modeleditor/pxnodecontroller.cpp
@@ -137,7 +137,7 @@ void PxNodeController::addExplorerNode(const ProjectExplorer::Node *node,
node->filePath().toString());
switch (node->nodeType()) {
- case ProjectExplorer::FileNodeType:
+ case ProjectExplorer::NodeType::File:
{
QStringList classNames = d->classViewController->findClassDeclarations(
node->filePath().toString()).toList();
@@ -162,16 +162,16 @@ void PxNodeController::addExplorerNode(const ProjectExplorer::Node *node,
menu->popup(QCursor::pos());
break;
}
- case ProjectExplorer::FolderNodeType:
- case ProjectExplorer::VirtualFolderNodeType:
- case ProjectExplorer::ProjectNodeType:
+ case ProjectExplorer::NodeType::Folder:
+ case ProjectExplorer::NodeType::VirtualFolder:
+ case ProjectExplorer::NodeType::Project:
{
QString stereotype;
switch (node->nodeType()) {
- case ProjectExplorer::VirtualFolderNodeType:
+ case ProjectExplorer::NodeType::VirtualFolder:
stereotype = QStringLiteral("virtual folder");
break;
- case ProjectExplorer::ProjectNodeType:
+ case ProjectExplorer::NodeType::Project:
stereotype = QStringLiteral("project");
break;
default:
@@ -198,7 +198,7 @@ void PxNodeController::addExplorerNode(const ProjectExplorer::Node *node,
menu->popup(QCursor::pos());
break;
}
- case ProjectExplorer::SessionNodeType:
+ case ProjectExplorer::NodeType::Session:
break;
}
}
diff --git a/src/plugins/modeleditor/pxnodeutilities.cpp b/src/plugins/modeleditor/pxnodeutilities.cpp
index c3b7d79bb1..6df0e93a97 100644
--- a/src/plugins/modeleditor/pxnodeutilities.cpp
+++ b/src/plugins/modeleditor/pxnodeutilities.cpp
@@ -69,18 +69,18 @@ QString PxNodeUtilities::calcRelativePath(const ProjectExplorer::Node *node,
QString nodePath;
switch (node->nodeType()) {
- case ProjectExplorer::FileNodeType:
+ case ProjectExplorer::NodeType::File:
{
QFileInfo fileInfo = node->filePath().toFileInfo();
nodePath = fileInfo.path();
break;
}
- case ProjectExplorer::FolderNodeType:
- case ProjectExplorer::VirtualFolderNodeType:
- case ProjectExplorer::ProjectNodeType:
+ case ProjectExplorer::NodeType::Folder:
+ case ProjectExplorer::NodeType::VirtualFolder:
+ case ProjectExplorer::NodeType::Project:
nodePath = node->filePath().toString();
break;
- case ProjectExplorer::SessionNodeType:
+ case ProjectExplorer::NodeType::Session:
QTC_ASSERT(false, return QString());
break;
}
diff --git a/src/plugins/nim/project/nimbuildconfigurationfactory.cpp b/src/plugins/nim/project/nimbuildconfigurationfactory.cpp
index 1d2a548d15..107d0e7fe1 100644
--- a/src/plugins/nim/project/nimbuildconfigurationfactory.cpp
+++ b/src/plugins/nim/project/nimbuildconfigurationfactory.cpp
@@ -108,7 +108,9 @@ BuildConfiguration *NimBuildConfigurationFactory::create(Target *parent, const B
break;
}
nimCompilerBuildStep->setDefaultCompilerOptions(defaultOption);
- nimCompilerBuildStep->setTargetNimFile(project->nimFiles().first());
+ Utils::FileNameList nimFiles = project->nimFiles();
+ if (!nimFiles.isEmpty())
+ nimCompilerBuildStep->setTargetNimFile(nimFiles.first());
buildSteps->appendStep(nimCompilerBuildStep);
}
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp
index 10c400c228..6b13968c5d 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.cpp
+++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp
@@ -26,6 +26,7 @@
#include "nimcompilerbuildstep.h"
#include "nimbuildconfiguration.h"
#include "nimcompilerbuildstepconfigwidget.h"
+#include "nimproject.h"
#include "../nimconstants.h"
@@ -50,6 +51,8 @@ NimCompilerBuildStep::NimCompilerBuildStep(BuildStepList *parentList)
this, &NimCompilerBuildStep::updateProcessParameters);
connect(this, &NimCompilerBuildStep::outFilePathChanged,
bc, &NimBuildConfiguration::outFilePathChanged);
+ connect(bc->target()->project(), &ProjectExplorer::Project::fileListChanged,
+ this, &NimCompilerBuildStep::updateTargetNimFile);
updateProcessParameters();
}
@@ -202,5 +205,13 @@ void NimCompilerBuildStep::updateEnvironment()
processParameters()->setEnvironment(bc->environment());
}
+void NimCompilerBuildStep::updateTargetNimFile()
+{
+ if (!m_targetNimFile.isEmpty())
+ return;
+ const Utils::FileNameList nimFiles = static_cast<NimProject *>(project())->nimFiles();
+ if (!nimFiles.isEmpty())
+ setTargetNimFile(nimFiles.at(0));
}
+} // namespace Nim
diff --git a/src/plugins/nim/project/nimcompilerbuildstep.h b/src/plugins/nim/project/nimcompilerbuildstep.h
index 1c22df2707..50fecb4248 100644
--- a/src/plugins/nim/project/nimcompilerbuildstep.h
+++ b/src/plugins/nim/project/nimcompilerbuildstep.h
@@ -74,6 +74,8 @@ private:
void updateArguments();
void updateEnvironment();
+ void updateTargetNimFile();
+
DefaultBuildOptions m_defaultOptions;
QStringList m_userCompilerOptions;
Utils::FileName m_targetNimFile;
diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp
index eb0829e7a6..794336f88d 100644
--- a/src/plugins/nim/project/nimproject.cpp
+++ b/src/plugins/nim/project/nimproject.cpp
@@ -30,6 +30,7 @@
#include "../nimconstants.h"
+#include <coreplugin/progressmanager/progressmanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
@@ -37,6 +38,8 @@
#include <texteditor/textdocument.h>
#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+#include <utils/runextensions.h>
#include <QFileInfo>
#include <QQueue>
@@ -60,9 +63,12 @@ NimProject::NimProject(NimProjectManager *projectManager, const QString &fileNam
rootProjectNode()->setDisplayName(dir.dirName());
m_projectScanTimer.setSingleShot(true);
- connect(&m_projectScanTimer, &QTimer::timeout, this, &NimProject::populateProject);
+ connect(&m_projectScanTimer, &QTimer::timeout, this, &NimProject::collectProjectFiles);
- populateProject();
+ m_futureWatcher.setFuture(m_futureInterface.future());
+ connect(&m_futureWatcher, &QFutureWatcher<QList<FileNode *>>::finished, this, &NimProject::updateProject);
+
+ collectProjectFiles();
connect(&m_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &NimProject::scheduleProjectScan);
}
@@ -74,7 +80,7 @@ QString NimProject::displayName() const
QStringList NimProject::files(FilesMode) const
{
- return QStringList(m_files.toList());
+ return m_files;
}
bool NimProject::needsConfiguration() const
@@ -91,24 +97,46 @@ void NimProject::scheduleProjectScan()
m_projectScanTimer.start();
}
} else {
- populateProject();
+ collectProjectFiles();
}
}
-void NimProject::populateProject()
+void NimProject::collectProjectFiles()
{
m_lastProjectScan.start();
+ QTC_ASSERT(!m_futureInterface.isRunning(), return);
+
+ runAsync([this]() {
+ m_futureInterface.reportStarted();
+ QList<FileNode *> nodes
+ = FileNode::scanForFiles(projectDirectory(),
+ [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); },
+ &m_futureInterface);
+ m_futureInterface.setProgressValue(m_futureInterface.progressMaximum());
+ m_futureInterface.reportResult(nodes);
+ m_futureInterface.reportFinished();
+ });
+ Core::ProgressManager::addTask(m_futureInterface.future(), tr("Scanning for Nim files"), "Nim.Project.Scan");
+}
- QSet<QString> oldFiles = m_files;
+void NimProject::updateProject()
+{
+ QStringList oldFiles = m_files;
m_files.clear();
- recursiveScanDirectory(QDir(projectDirectory().toString()), m_files);
- if (m_files == oldFiles)
+ QList<FileNode *> fileNodes = Utils::filtered(m_futureInterface.future().result(),
+ [](const FileNode *fn) {
+ const QString fileName = fn->filePath().fileName();
+ return !fileName.endsWith(".nimproject", HostOsInfo::fileNameCaseSensitivity())
+ && !fileName.contains(".nimproject.user", HostOsInfo::fileNameCaseSensitivity());
+ });
+
+ m_files = Utils::transform(fileNodes, [](const FileNode *fn) { return fn->filePath().toString(); });
+ Utils::sort(m_files, [](const QString &a, const QString &b) { return a < b; });
+
+ if (oldFiles == m_files)
return;
- QList<FileNode *> fileNodes = Utils::transform(m_files.toList(), [](const QString &f) {
- return new FileNode(FileName::fromString(f), SourceType, false);
- });
rootProjectNode()->buildTree(fileNodes);
emit fileListChanged();
@@ -116,22 +144,6 @@ void NimProject::populateProject()
emit parsingFinished();
}
-void NimProject::recursiveScanDirectory(const QDir &dir, QSet<QString> &container)
-{
- static const QRegExp projectFilePattern(QLatin1String(".*\\.nimproject(?:\\.user)?$"));
- for (const QFileInfo &info : dir.entryInfoList(QDir::AllDirs |
- QDir::Files |
- QDir::NoDotAndDotDot |
- QDir::NoSymLinks |
- QDir::CaseSensitive)) {
- if (info.isDir())
- recursiveScanDirectory(QDir(info.filePath()), container);
- else if (projectFilePattern.indexIn(info.fileName()) == -1)
- container << info.filePath();
- }
- m_fsWatcher.addPath(dir.absolutePath());
-}
-
bool NimProject::supportsKit(Kit *k, QString *) const
{
return k->isValid();
@@ -150,7 +162,7 @@ FileNameList NimProject::nimFiles() const
if (file->displayName().endsWith(QLatin1String(".nim")))
result.append(file->filePath());
}
- folders.append(folder->subFolderNodes());
+ folders.append(folder->folderNodes());
}
return result;
diff --git a/src/plugins/nim/project/nimproject.h b/src/plugins/nim/project/nimproject.h
index 7c308bc17c..8e7f87f4b0 100644
--- a/src/plugins/nim/project/nimproject.h
+++ b/src/plugins/nim/project/nimproject.h
@@ -28,8 +28,9 @@
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
-#include <QFileSystemWatcher>
#include <QElapsedTimer>
+#include <QFileSystemWatcher>
+#include <QFutureWatcher>
#include <QTimer>
namespace TextEditor { class TextDocument; }
@@ -54,11 +55,13 @@ public:
private:
void scheduleProjectScan();
- void populateProject();
- void recursiveScanDirectory(const QDir &dir, QSet<QString> &container);
+ void collectProjectFiles();
+ void updateProject();
- QSet<QString> m_files;
+ QStringList m_files;
QFileSystemWatcher m_fsWatcher;
+ QFutureInterface<QList<ProjectExplorer::FileNode *>> m_futureInterface;
+ QFutureWatcher<QList<ProjectExplorer::FileNode *>> m_futureWatcher;
QElapsedTimer m_lastProjectScan;
QTimer m_projectScanTimer;
diff --git a/src/plugins/nim/project/nimprojectnode.cpp b/src/plugins/nim/project/nimprojectnode.cpp
index 8d77072a67..88a53227f4 100644
--- a/src/plugins/nim/project/nimprojectnode.cpp
+++ b/src/plugins/nim/project/nimprojectnode.cpp
@@ -44,10 +44,10 @@ QList<ProjectAction> NimProjectNode::supportedActions(Node *node) const
ProjectAction::RemoveFile
};
switch (node->nodeType()) {
- case FileNodeType:
+ case NodeType::File:
return fileActions;
- case FolderNodeType:
- case ProjectNodeType:
+ case NodeType::Folder:
+ case NodeType::Project:
return folderActions;
default:
return ProjectNode::supportedActions(node);
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index a351014293..53f6284280 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -53,7 +53,7 @@
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsoutputwindow.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
#include <QAction>
#include <QDebug>
@@ -1195,11 +1195,11 @@ struct PerforceDiffParameters
};
// Parameter widget controlling whitespace diff mode, associated with a parameter
-class PerforceDiffParameterWidget : public VcsBaseEditorParameterWidget
+class PerforceDiffConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- explicit PerforceDiffParameterWidget(const PerforceDiffParameters &p, QWidget *parent = 0);
+ explicit PerforceDiffConfig(const PerforceDiffParameters &p, QToolBar *toolBar);
void triggerReRun();
signals:
@@ -1209,15 +1209,15 @@ private:
const PerforceDiffParameters m_parameters;
};
-PerforceDiffParameterWidget::PerforceDiffParameterWidget(const PerforceDiffParameters &p, QWidget *parent) :
- VcsBaseEditorParameterWidget(parent), m_parameters(p)
+PerforceDiffConfig::PerforceDiffConfig(const PerforceDiffParameters &p, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar), m_parameters(p)
{
setBaseArguments(p.diffArguments);
addToggleButton(QLatin1String("w"), tr("Ignore Whitespace"));
- connect(this, &VcsBaseEditorParameterWidget::argumentsChanged, this, &PerforceDiffParameterWidget::triggerReRun);
+ connect(this, &VcsBaseEditorConfig::argumentsChanged, this, &PerforceDiffConfig::triggerReRun);
}
-void PerforceDiffParameterWidget::triggerReRun()
+void PerforceDiffConfig::triggerReRun()
{
PerforceDiffParameters effectiveParameters = m_parameters;
effectiveParameters.diffArguments = arguments();
@@ -1269,12 +1269,12 @@ void PerforcePlugin::p4Diff(const PerforceDiffParameters &p)
auto diffEditorWidget = qobject_cast<VcsBaseEditorWidget *>(editor->widget());
// Wire up the parameter widget to trigger a re-run on
// parameter change and 'revert' from inside the diff editor.
- auto pw = new PerforceDiffParameterWidget(p);
- connect(pw, &PerforceDiffParameterWidget::reRunDiff,
+ auto pw = new PerforceDiffConfig(p, diffEditorWidget->toolBar());
+ connect(pw, &PerforceDiffConfig::reRunDiff,
this, [this](const PerforceDiffParameters &p) { p4Diff(p); });
connect(diffEditorWidget, &VcsBaseEditorWidget::diffChunkReverted,
- pw, &PerforceDiffParameterWidget::triggerReRun);
- diffEditorWidget->setConfigurationWidget(pw);
+ pw, &PerforceDiffConfig::triggerReRun);
+ diffEditorWidget->setConfigurationAdded();
}
void PerforcePlugin::describe(const QString & source, const QString &n)
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index d436991b0f..e027a8ef26 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -49,6 +49,12 @@ Core::Id PerforceVersionControl::id() const
return Core::Id(VcsBase::Constants::VCS_ID_PERFORCE);
}
+bool PerforceVersionControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ Q_UNUSED(fileName);
+ return false; // Perforce does not seem to litter its files into the source tree.
+}
+
bool PerforceVersionControl::isConfigured() const
{
const QString binary = m_plugin->settings().p4BinaryPath();
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
index 5ca6c7b20e..6f1a2c2bc3 100644
--- a/src/plugins/perforce/perforceversioncontrol.h
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -38,24 +38,25 @@ class PerforceVersionControl : public Core::IVersionControl
public:
explicit PerforceVersionControl(PerforcePlugin *plugin);
- QString displayName() const override;
- Core::Id id() const override;
+ QString displayName() const final;
+ Core::Id id() const final;
- bool managesDirectory(const QString &directory, QString *topLevel = 0) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
+ bool managesDirectory(const QString &directory, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
- bool isConfigured() const override;
- bool supportsOperation(Operation operation) const override;
- OpenSupportMode openSupportMode(const QString &fileName) const override;
- bool vcsOpen(const QString &fileName) override;
- SettingsFlags settingsFlags() const override;
- bool vcsAdd(const QString &fileName) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
- bool vcsAnnotate(const QString &file, int line) override;
- QString vcsOpenText() const override;
- QString vcsMakeWritableText() const override;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ OpenSupportMode openSupportMode(const QString &fileName) const final;
+ bool vcsOpen(const QString &fileName) final;
+ SettingsFlags settingsFlags() const final;
+ bool vcsAdd(const QString &fileName) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
+ bool vcsAnnotate(const QString &file, int line) final;
+ QString vcsOpenText() const final;
+ QString vcsMakeWritableText() const final;
void emitRepositoryChanged(const QString &s);
void emitFilesChanged(const QStringList &l);
diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp
index 36f94b65cc..8d5e6efb33 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -253,7 +253,7 @@ void KitManager::saveKits()
d->m_writer->save(data, ICore::mainWindow());
}
-static bool isLoaded()
+bool KitManager::isLoaded()
{
return d->m_initialized;
}
diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h
index e47acd6e41..cde9075657 100644
--- a/src/plugins/projectexplorer/kitmanager.h
+++ b/src/plugins/projectexplorer/kitmanager.h
@@ -155,6 +155,8 @@ public:
static void saveKits();
+ static bool isLoaded();
+
signals:
void kitAdded(ProjectExplorer::Kit *);
// Kit is still valid when this call happens!
diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h
index 7f636f8ad8..5eda1ceb29 100644
--- a/src/plugins/projectexplorer/project.h
+++ b/src/plugins/projectexplorer/project.h
@@ -168,7 +168,6 @@ signals:
void projectContextUpdated();
void projectLanguagesUpdated();
-signals: // for tests only
void parsingFinished();
protected:
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index fb4f32c01d..4e53fc1087 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -277,6 +277,8 @@ public:
void runConfigurationConfigurationFinished();
+ QList<QPair<QString, QString> > recentProjects() const;
+
public:
QMenu *m_sessionMenu;
QMenu *m_openWithMenu;
@@ -1066,6 +1068,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
if (!dd->m_shuttingDown && !SessionManager::loadingSession())
SessionManager::save();
});
+ connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) {
+ if (state == Qt::ApplicationActive)
+ dd->updateWelcomePage();
+ });
addAutoReleasedObject(new ProjectTreeWidgetFactory);
addAutoReleasedObject(new FolderNavigationWidgetFactory);
@@ -1078,8 +1084,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
s->value(QLatin1String("ProjectExplorer/RecentProjects/DisplayNames")).toStringList();
if (fileNames.size() == displayNames.size()) {
for (int i = 0; i < fileNames.size(); ++i) {
- if (QFileInfo(fileNames.at(i)).isFile())
- dd->m_recentProjects.append(qMakePair(fileNames.at(i), displayNames.at(i)));
+ dd->m_recentProjects.append(qMakePair(fileNames.at(i), displayNames.at(i)));
}
}
@@ -1983,20 +1988,27 @@ void ProjectExplorerPluginPrivate::runConfigurationConfigurationFinished()
executeRunConfiguration(rc, runMode);
}
+QList<QPair<QString, QString> > ProjectExplorerPluginPrivate::recentProjects() const
+{
+ return Utils::filtered(dd->m_recentProjects, [](const QPair<QString, QString> &p) {
+ return QFileInfo(p.first).isFile();
+ });
+}
+
static QString pathOrDirectoryFor(Node *node, bool dir)
{
Utils::FileName path = node->filePath();
QString location;
FolderNode *folder = node->asFolderNode();
- if (node->nodeType() == VirtualFolderNodeType && folder) {
+ if (node->nodeType() == NodeType::VirtualFolder && folder) {
// Virtual Folder case
// If there are files directly below or no subfolders, take the folder path
- if (!folder->fileNodes().isEmpty() || folder->subFolderNodes().isEmpty()) {
+ if (!folder->fileNodes().isEmpty() || folder->folderNodes().isEmpty()) {
location = path.toString();
} else {
// Otherwise we figure out a commonPath from the subfolders
QStringList list;
- foreach (FolderNode *f, folder->subFolderNodes())
+ foreach (FolderNode *f, folder->folderNodes())
list << f->filePath().toString() + QLatin1Char('/');
location = Utils::commonPath(list);
}
@@ -2844,11 +2856,11 @@ void ProjectExplorerPluginPrivate::updateRecentProjectMenu()
QMenu *menu = aci->menu();
menu->clear();
- bool hasRecentProjects = false;
int acceleratorKey = 1;
+ auto projects = recentProjects();
//projects (ignore sessions, they used to be in this list)
- const StringPairListConstIterator end = dd->m_recentProjects.constEnd();
- for (StringPairListConstIterator it = dd->m_recentProjects.constBegin(); it != end; ++it, ++acceleratorKey) {
+ const StringPairListConstIterator end = projects.constEnd();
+ for (StringPairListConstIterator it = projects.constBegin(); it != end; ++it, ++acceleratorKey) {
const QString fileName = it->first;
if (fileName.endsWith(QLatin1String(".qws")))
continue;
@@ -2859,8 +2871,8 @@ void ProjectExplorerPluginPrivate::updateRecentProjectMenu()
connect(action, &QAction::triggered, this, [this, fileName] {
openRecentProject(fileName);
});
- hasRecentProjects = true;
}
+ const bool hasRecentProjects = !projects.empty();
menu->setEnabled(hasRecentProjects);
// add the Clear Menu item
@@ -2929,7 +2941,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
Node *currentNode = ProjectTree::currentNode();
- if (currentNode && currentNode->projectNode()) {
+ if (currentNode && currentNode->managingProject()) {
QList<ProjectAction> actions = currentNode->supportedActions(currentNode);
if (ProjectNode *pn = currentNode->asProjectNode()) {
@@ -2957,10 +2969,10 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions()
// Also handles ProjectNode
m_addNewFileAction->setEnabled(actions.contains(AddNewFile)
&& !ICore::isNewItemDialogRunning());
- m_addNewSubprojectAction->setEnabled(currentNode->nodeType() == ProjectNodeType
+ m_addNewSubprojectAction->setEnabled(currentNode->nodeType() == NodeType::Project
&& actions.contains(AddSubProject)
&& !ICore::isNewItemDialogRunning());
- m_removeProjectAction->setEnabled(currentNode->nodeType() == ProjectNodeType
+ m_removeProjectAction->setEnabled(currentNode->nodeType() == NodeType::Project
&& actions.contains(RemoveSubProject));
m_addExistingFilesAction->setEnabled(actions.contains(AddExistingFile));
m_addExistingDirectoryAction->setEnabled(actions.contains(AddExistingDirectory));
@@ -3033,7 +3045,7 @@ void ProjectExplorerPluginPrivate::addNewSubproject()
Node *currentNode = ProjectTree::currentNode();
QString location = directoryFor(currentNode);
- if (currentNode->nodeType() == ProjectNodeType
+ if (currentNode->nodeType() == NodeType::Project
&& currentNode->supportedActions(
currentNode).contains(AddSubProject)) {
QVariantMap map;
@@ -3097,7 +3109,7 @@ void ProjectExplorerPlugin::addExistingFiles(FolderNode *folderNode, const QStri
if (!notAdded.isEmpty()) {
const QString message = tr("Could not add following files to project %1:")
- .arg(folderNode->projectNode()->displayName()) + QLatin1Char('\n');
+ .arg(folderNode->managingProject()->displayName()) + QLatin1Char('\n');
const QStringList nativeFiles
= Utils::transform(notAdded,
[](const QString &f) { return QDir::toNativeSeparators(f); });
@@ -3115,10 +3127,10 @@ void ProjectExplorerPluginPrivate::removeProject()
Node *node = ProjectTree::currentNode();
if (!node)
return;
- ProjectNode *subProjectNode = node->projectNode();
+ ProjectNode *subProjectNode = node->managingProject();
if (!subProjectNode)
return;
- ProjectNode *projectNode = subProjectNode->parentFolderNode()->asProjectNode();
+ ProjectNode *projectNode = subProjectNode->managingProject();
if (projectNode) {
RemoveFileDialog removeFileDialog(subProjectNode->filePath().toString(), ICore::mainWindow());
removeFileDialog.setDeleteFileVisible(false);
@@ -3154,7 +3166,7 @@ void ProjectExplorerPluginPrivate::openTerminalHere()
void ProjectExplorerPluginPrivate::removeFile()
{
Node *currentNode = ProjectTree::currentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == FileNodeType, return);
+ QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
FileNode *fileNode = currentNode->asFileNode();
@@ -3172,7 +3184,7 @@ void ProjectExplorerPluginPrivate::removeFile()
QMessageBox::warning(ICore::mainWindow(), tr("Removing File Failed"),
tr("Could not remove file %1 from project %2.")
.arg(QDir::toNativeSeparators(filePath))
- .arg(folderNode->projectNode()->displayName()));
+ .arg(folderNode->managingProject()->displayName()));
if (!deleteFile)
return;
}
@@ -3185,7 +3197,7 @@ void ProjectExplorerPluginPrivate::removeFile()
void ProjectExplorerPluginPrivate::duplicateFile()
{
Node *currentNode = ProjectTree::currentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == FileNodeType, return);
+ QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
FileNode *fileNode = currentNode->asFileNode();
QString filePath = currentNode->filePath().toString();
@@ -3216,7 +3228,7 @@ void ProjectExplorerPluginPrivate::duplicateFile()
void ProjectExplorerPluginPrivate::deleteFile()
{
Node *currentNode = ProjectTree::currentNode();
- QTC_ASSERT(currentNode && currentNode->nodeType() == FileNodeType, return);
+ QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return);
FileNode *fileNode = currentNode->asFileNode();
@@ -3266,7 +3278,7 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &newFilePath)
{
const QString oldFilePath = node->filePath().toFileInfo().absoluteFilePath();
FolderNode *folderNode = node->parentFolderNode();
- const QString projectFileName = folderNode->projectNode()->filePath().fileName();
+ const QString projectFileName = folderNode->managingProject()->filePath().fileName();
if (oldFilePath == newFilePath)
return;
@@ -3386,7 +3398,7 @@ void ProjectExplorerPlugin::openOpenProjectDialog()
QList<QPair<QString, QString> > ProjectExplorerPlugin::recentProjects()
{
- return dd->m_recentProjects;
+ return dd->recentProjects();
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index dcaf3c1932..e597e23bf7 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -50,122 +50,20 @@ namespace {
bool sortNodes(Node *n1, Node *n2)
{
- // Ordering is: project files, project, folder, file
-
- const NodeType n1Type = n1->nodeType();
- const NodeType n2Type = n2->nodeType();
-
- // project files
- FileNode *file1 = n1->asFileNode();
- FileNode *file2 = n2->asFileNode();
- if (file1 && file1->fileType() == ProjectFileType) {
- if (file2 && file2->fileType() == ProjectFileType) {
- const QString fileName1 = file1->filePath().fileName();
- const QString fileName2 = file2->filePath().fileName();
-
- int result = caseFriendlyCompare(fileName1, fileName2);
- if (result != 0)
- return result < 0;
- else
- return file1 < file2;
- } else {
- return true; // project file is before everything else
- }
- } else {
- if (file2 && file2->fileType() == ProjectFileType)
- return false;
- }
-
- // projects
- if (n1Type == ProjectNodeType) {
- if (n2Type == ProjectNodeType) {
- auto project1 = static_cast<ProjectNode*>(n1);
- auto project2 = static_cast<ProjectNode*>(n2);
-
- int result = caseFriendlyCompare(project1->displayName(), project2->displayName());
- if (result != 0)
- return result < 0;
-
- result = caseFriendlyCompare(project1->filePath().toString(),
- project2->filePath().toString());
- if (result != 0)
- return result < 0;
- return project1 < project2; // sort by pointer value
- } else {
- return true; // project is before folder & file
- }
- }
- if (n2Type == ProjectNodeType)
- return false;
-
- if (n1Type == VirtualFolderNodeType) {
- if (n2Type == VirtualFolderNodeType) {
- auto folder1 = static_cast<VirtualFolderNode *>(n1);
- auto folder2 = static_cast<VirtualFolderNode *>(n2);
-
- if (folder1->priority() > folder2->priority())
- return true;
- if (folder1->priority() < folder2->priority())
- return false;
- int result = caseFriendlyCompare(folder1->filePath().toString(),
- folder2->filePath().toString());
- if (result != 0)
- return result < 0;
- else
- return folder1 < folder2;
- } else {
- return true; // virtual folder is before folder
- }
- }
-
- if (n2Type == VirtualFolderNodeType)
+ if (n1->priority() > n2->priority())
+ return true;
+ if (n1->priority() < n2->priority())
return false;
+ const int displayNameResult = caseFriendlyCompare(n1->displayName(), n2->displayName());
+ if (displayNameResult != 0)
+ return displayNameResult < 0;
- if (n1Type == FolderNodeType) {
- if (n2Type == FolderNodeType) {
- auto folder1 = static_cast<FolderNode*>(n1);
- auto folder2 = static_cast<FolderNode*>(n2);
-
- int result = caseFriendlyCompare(folder1->filePath().toString(),
- folder2->filePath().toString());
- if (result != 0)
- return result < 0;
- else
- return folder1 < folder2;
- } else {
- return true; // folder is before file
- }
- }
- if (n2Type == FolderNodeType)
- return false;
-
- // must be file nodes
- {
- int result = caseFriendlyCompare(n1->displayName(), n2->displayName());
- if (result != 0)
- return result < 0;
-
- const QString filePath1 = n1->filePath().toString();
- const QString filePath2 = n2->filePath().toString();
-
- const QString fileName1 = n1->filePath().fileName();
- const QString fileName2 = n2->filePath().fileName();
-
- result = caseFriendlyCompare(fileName1, fileName2);
- if (result != 0) {
- return result < 0; // sort by filename
- } else {
- result = caseFriendlyCompare(filePath1, filePath2);
- if (result != 0)
- return result < 0; // sort by filepath
-
- if (n1->line() != n2->line())
- return n1->line() < n2->line(); // sort by line numbers
- return n1 < n2; // sort by pointer value
- }
- }
- return false;
+ const int filePathResult = caseFriendlyCompare(n1->filePath().toString(),
+ n2->filePath().toString());
+ if (filePathResult != 0)
+ return filePathResult < 0;
+ return n1 < n2; // sort by pointer value
}
} // namespace anon
@@ -252,9 +150,9 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
case Qt::DisplayRole: {
QString name = node->displayName();
- if (node->nodeType() == ProjectNodeType
+ if (node->nodeType() == NodeType::Project
&& node->parentFolderNode()
- && node->parentFolderNode()->nodeType() == SessionNodeType) {
+ && node->parentFolderNode()->nodeType() == NodeType::Session) {
const QString vcsTopic = static_cast<ProjectNode *>(node)->vcsTopic();
if (!vcsTopic.isEmpty())
@@ -386,7 +284,7 @@ bool FlatModel::canFetchMore(const QModelIndex & parent) const
void FlatModel::recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
{
- foreach (FolderNode *folderNode, startNode->subFolderNodes()) {
+ foreach (FolderNode *folderNode, startNode->folderNodes()) {
if (folderNode && !blackList.contains(folderNode))
recursiveAddFolderNodesImpl(folderNode, list, blackList);
}
@@ -398,7 +296,7 @@ void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *>
if (!blackList.contains(startNode))
list->append(startNode);
} else {
- foreach (FolderNode *folderNode, startNode->subFolderNodes()) {
+ foreach (FolderNode *folderNode, startNode->folderNodes()) {
if (folderNode && !blackList.contains(folderNode))
recursiveAddFolderNodesImpl(folderNode, list, blackList);
}
@@ -407,7 +305,7 @@ void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *>
void FlatModel::recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
{
- foreach (FolderNode *subFolderNode, startNode->subFolderNodes()) {
+ foreach (FolderNode *subFolderNode, startNode->folderNodes()) {
if (!blackList.contains(subFolderNode))
recursiveAddFileNodes(subFolderNode, list, blackList);
}
@@ -422,7 +320,7 @@ QList<Node*> FlatModel::childNodes(FolderNode *parentNode, const QSet<Node*> &bl
qCDebug(logger()) << " FlatModel::childNodes for " << parentNode->filePath();
QList<Node*> nodeList;
- if (parentNode->nodeType() == SessionNodeType) {
+ if (parentNode->nodeType() == NodeType::Session) {
auto sessionNode = static_cast<SessionNode*>(parentNode);
QList<ProjectNode*> projectList = sessionNode->projectNodes();
for (int i = 0; i < projectList.size(); ++i) {
@@ -855,7 +753,7 @@ void FlatModel::foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<Fo
void FlatModel::removeFromCache(QList<FolderNode *> list)
{
foreach (FolderNode *fn, list) {
- removeFromCache(fn->subFolderNodes());
+ removeFromCache(fn->folderNodes());
m_childNodes.remove(fn);
}
}
diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
index 9d97dff941..24b3451c12 100644
--- a/src/plugins/projectexplorer/projectnodes.cpp
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -60,13 +60,13 @@ namespace ProjectExplorer {
*/
Node::Node(NodeType nodeType, const Utils::FileName &filePath, int line) :
- m_nodeType(nodeType),
- m_line(line),
- m_filePath(filePath)
+ m_filePath(filePath), m_line(line), m_nodeType(nodeType)
{ }
-Node::~Node()
-{ }
+void Node::setPriority(int p)
+{
+ m_priority = p;
+}
void Node::emitNodeSortKeyAboutToChange()
{
@@ -97,13 +97,23 @@ NodeType Node::nodeType() const
return m_nodeType;
}
+int Node::priority() const
+{
+ return m_priority;
+}
+
/*!
The project that owns and manages the node. It is the first project in the list
of ancestors.
*/
-ProjectNode *Node::projectNode() const
+ProjectNode *Node::parentProjectNode() const
{
- return m_projectNode;
+ if (!m_parentFolderNode)
+ return nullptr;
+ auto pn = m_parentFolderNode->asProjectNode();
+ if (pn)
+ return pn;
+ return m_parentFolderNode->parentProjectNode();
}
/*!
@@ -111,7 +121,20 @@ ProjectNode *Node::projectNode() const
*/
FolderNode *Node::parentFolderNode() const
{
- return m_folderNode;
+ return m_parentFolderNode;
+}
+
+ProjectNode *Node::managingProject()
+{
+ if (asSessionNode())
+ return nullptr;
+ ProjectNode *pn = parentProjectNode();
+ return pn ? pn : asProjectNode(); // projects manage themselves...
+}
+
+const ProjectNode *Node::managingProject() const
+{
+ return const_cast<Node *>(this)->managingProject();
}
/*!
@@ -139,7 +162,10 @@ QString Node::tooltip() const
bool Node::isEnabled() const
{
- return parentFolderNode()->isEnabled();
+ if (!m_isEnabled)
+ return false;
+ FolderNode *parent = parentFolderNode();
+ return parent ? parent->isEnabled() : true;
}
QList<ProjectAction> Node::supportedActions(Node *node) const
@@ -149,9 +175,12 @@ QList<ProjectAction> Node::supportedActions(Node *node) const
return list;
}
-void Node::setProjectNode(ProjectNode *project)
+void Node::setEnabled(bool enabled)
{
- m_projectNode = project;
+ if (m_isEnabled == enabled)
+ return;
+ m_isEnabled = enabled;
+ emitNodeUpdated();
}
void Node::emitNodeUpdated()
@@ -160,29 +189,19 @@ void Node::emitNodeUpdated()
ProjectTree::instance()->emitNodeUpdated(this);
}
-FileNode *Node::asFileNode()
-{
- return nullptr;
-}
-
-FolderNode *Node::asFolderNode()
+Node *Node::trim(const QSet<Node *> &keepers)
{
- return nullptr;
+ return keepers.contains(this) ? nullptr : this;
}
-ProjectNode *Node::asProjectNode()
+bool Node::sortByPath(Node *a, Node *b)
{
- return nullptr;
-}
-
-SessionNode *Node::asSessionNode()
-{
- return nullptr;
+ return a->filePath() < b->filePath();
}
void Node::setParentFolderNode(FolderNode *parentFolder)
{
- m_folderNode = parentFolder;
+ m_parentFolderNode = parentFolder;
}
/*!
@@ -197,10 +216,15 @@ void Node::setParentFolderNode(FolderNode *parentFolder)
FileNode::FileNode(const Utils::FileName &filePath,
const FileType fileType,
- bool generated, int line) : Node(FileNodeType, filePath, line),
+ bool generated, int line) : Node(NodeType::File, filePath, line),
m_fileType(fileType),
m_generated(generated)
-{ }
+{
+ if (fileType == FileType::Project)
+ setPriority(DefaultProjectFilePriority);
+ else
+ setPriority(DefaultFilePriority);
+}
FileType FileNode::fileType() const
{
@@ -215,9 +239,59 @@ bool FileNode::isGenerated() const
return m_generated;
}
-FileNode *FileNode::asFileNode()
+static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory,
+ const std::function<FileNode *(const Utils::FileName &)> factory,
+ QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future,
+ double progressStart, double progressRange)
+{
+ QList<FileNode *> result;
+
+ const QDir baseDir = QDir(directory.toString());
+
+ // Do not follow directory loops:
+ const int visitedCount = visited.count();
+ visited.insert(baseDir.canonicalPath());
+ if (visitedCount == visited.count())
+ return result;
+
+ const Core::IVersionControl *vcsControl
+ = Core::VcsManager::findVersionControlForDirectory(baseDir.absolutePath(), nullptr);
+ const QList<QFileInfo> entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot);
+ double progress = 0;
+ const double progressIncrement = progressRange / static_cast<double>(entries.count());
+ int lastIntProgress = 0;
+ for (const QFileInfo &entry : entries) {
+ if (future && future->isCanceled())
+ return result;
+
+ const Utils::FileName entryName = Utils::FileName::fromString(entry.absoluteFilePath());
+ if (!vcsControl || !vcsControl->isVcsFileOrDirectory(entryName)) {
+ if (entry.isDir())
+ result.append(scanForFilesRecursively(entryName, factory, visited, future, progress, progressIncrement));
+ else
+ result.append(factory(entryName));
+ }
+ if (future) {
+ progress += progressIncrement;
+ const int intProgress = std::min(static_cast<int>(progressStart + progress), future->progressMaximum());
+ if (lastIntProgress < intProgress) {
+ future->setProgressValue(intProgress);
+ lastIntProgress = intProgress;
+ }
+ }
+ }
+ if (future)
+ future->setProgressValue(std::min(static_cast<int>(progressStart + progressRange), future->progressMaximum()));
+ return result;
+}
+
+QList<FileNode *> FileNode::scanForFiles(const Utils::FileName &directory,
+ const std::function<FileNode *(const Utils::FileName &)> factory,
+ QFutureInterface<QList<FileNode*>> *future)
{
- return this;
+ QSet<QString> visited;
+ future->setProgressRange(0, 1000000);
+ return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0);
}
/*!
@@ -228,16 +302,17 @@ FileNode *FileNode::asFileNode()
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
*/
FolderNode::FolderNode(const Utils::FileName &folderPath, NodeType nodeType, const QString &displayName) :
- Node(nodeType, folderPath),
+ Node(nodeType, folderPath, -1),
m_displayName(displayName)
{
+ setPriority(DefaultFolderPriority);
if (m_displayName.isEmpty())
m_displayName = folderPath.toUserOutput();
}
FolderNode::~FolderNode()
{
- qDeleteAll(m_subFolderNodes);
+ qDeleteAll(m_folderNodes);
qDeleteAll(m_fileNodes);
}
@@ -264,74 +339,125 @@ QIcon FolderNode::icon() const
return m_icon;
}
+Node *FolderNode::trim(const QSet<Node *> &keepers)
+{
+ if (keepers.contains(this))
+ return nullptr;
+
+ bool keepThis = false;
+ QList<Node *> toTrim = Utils::transform(m_fileNodes, [&keepers](Node *n) { return n->trim(keepers); });
+ int count = toTrim.count();
+ toTrim = Utils::filtered(toTrim, [](const Node *n) { return n; });
+ keepThis = (count != toTrim.count());
+ removeFileNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<FileNode *>(n); }));
+
+ toTrim = Utils::transform(m_folderNodes, [&keepers](Node *n) { return n->trim(keepers); });
+ count = toTrim.count();
+ toTrim = Utils::filtered(toTrim, [](const Node *n) { return n; });
+ keepThis = keepThis || (count != toTrim.count());
+ removeFolderNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<FolderNode *>(n); }));
+ return keepThis ? nullptr : this;
+}
+
QList<FileNode*> FolderNode::fileNodes() const
{
return m_fileNodes;
}
+FileNode *FolderNode::fileNode(const Utils::FileName &file) const
+{
+ return Utils::findOrDefault(m_fileNodes, [&file](const FileNode *fn) {
+ return fn->filePath() == file;
+ });
+}
+
+FileNode *FolderNode::recursiveFileNode(const Utils::FileName &file) const
+{
+ Utils::FileName dir = file.parentDir();
+
+ const QDir thisDir(filePath().toString());
+ QString relativePath = thisDir.relativeFilePath(dir.toString());
+ if (relativePath == ".")
+ relativePath.clear();
+ QStringList parts = relativePath.split('/', QString::SkipEmptyParts);
+ const ProjectExplorer::FolderNode *parent = this;
+ foreach (const QString &part, parts) {
+ dir.appendPath(part);
+ // Find folder in subFolders
+ parent = Utils::findOrDefault(parent->folderNodes(), [&dir](const FolderNode *fn) {
+ return fn->filePath() == dir;
+ });
+ if (!parent)
+ return nullptr;
+ }
+ return parent->fileNode(file);
+}
+
QList<FileNode *> FolderNode::recursiveFileNodes() const
{
QList<FileNode *> result = fileNodes();
- foreach (ProjectExplorer::FolderNode *folder, subFolderNodes())
+ foreach (ProjectExplorer::FolderNode *folder, folderNodes())
result.append(folder->recursiveFileNodes());
return result;
}
-QList<FolderNode*> FolderNode::subFolderNodes() const
+QList<FolderNode*> FolderNode::folderNodes() const
{
- return m_subFolderNodes;
+ return m_folderNodes;
}
-FolderNode *FolderNode::findOrCreateSubFolderNode(const QString &directory)
+FolderNode *FolderNode::folderNode(const Utils::FileName &directory) const
{
- Utils::FileName path = filePath();
- QDir parentDir(path.toString());
- QString relativePath = parentDir.relativeFilePath(directory);
- if (relativePath == ".")
- relativePath.clear();
- QStringList parts = relativePath.split('/', QString::SkipEmptyParts);
+ return Utils::findOrDefault(m_folderNodes, [&directory](const FolderNode *fn) {
+ return fn->filePath() == directory;
+ });
+}
+
+FolderNode *FolderNode::recursiveFindOrCreateFolderNode(const QString &directory,
+ const Utils::FileName &overrideBaseDir)
+{
+ Utils::FileName path = overrideBaseDir.isEmpty() ? filePath() : overrideBaseDir;
+ QString workPath;
+ if (path.isEmpty() || path.toFileInfo().isRoot()) {
+ workPath = directory;
+ } else {
+ QDir parentDir(path.toString());
+ workPath = parentDir.relativeFilePath(directory);
+ if (workPath == ".")
+ workPath.clear();
+ }
+ const QStringList parts = workPath.split('/', QString::SkipEmptyParts);
+
ProjectExplorer::FolderNode *parent = this;
foreach (const QString &part, parts) {
path.appendPath(part);
// Find folder in subFolders
- bool found = false;
- foreach (ProjectExplorer::FolderNode *folder, parent->subFolderNodes()) {
- if (folder->filePath() == path) {
- // yeah found something :)
- parent = folder;
- found = true;
- break;
- }
- }
- if (!found) {
+ FolderNode *next = parent->folderNode(path);
+ if (!next) {
// No FolderNode yet, so create it
auto tmp = new ProjectExplorer::FolderNode(path);
tmp->setDisplayName(part);
parent->addFolderNodes(QList<ProjectExplorer::FolderNode *>({ tmp }));
- parent = tmp;
+ next = tmp;
}
+ parent = next;
}
return parent;
}
-static bool sortNodesByPath(Node *a, Node *b)
-{
- return a->filePath() < b->filePath();
-}
-
-void FolderNode::buildTree(QList<FileNode *> &files)
+void FolderNode::buildTree(QList<FileNode *> &files, const Utils::FileName &overrideBaseDir)
{
// Gather old list
QList<ProjectExplorer::FileNode *> oldFiles = recursiveFileNodes();
- Utils::sort(oldFiles, sortNodesByPath);
- Utils::sort(files, sortNodesByPath);
+ Utils::sort(oldFiles, Node::sortByPath);
+ Utils::sort(files, Node::sortByPath);
QList<ProjectExplorer::FileNode *> added;
QList<ProjectExplorer::FileNode *> deleted;
- ProjectExplorer::compareSortedLists(oldFiles, files, deleted, added, sortNodesByPath);
+ ProjectExplorer::compareSortedLists(oldFiles, files, deleted, added, Node::sortByPath);
- qDeleteAll(ProjectExplorer::subtractSortedList(files, added, sortNodesByPath));
+ qDeleteAll(ProjectExplorer::subtractSortedList(files, added, Node::sortByPath));
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > addedFolderMapping;
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > deletedFolderMapping;
@@ -340,7 +466,8 @@ void FolderNode::buildTree(QList<FileNode *> &files)
foreach (ProjectExplorer::FileNode *fn, added) {
// Get relative path to rootNode
QString parentDir = fn->filePath().toFileInfo().absolutePath();
- ProjectExplorer::FolderNode *folder = findOrCreateSubFolderNode(parentDir);
+ ProjectExplorer::FolderNode *folder
+ = recursiveFindOrCreateFolderNode(parentDir, overrideBaseDir);
addedFolderMapping[folder] << fn;
}
@@ -354,8 +481,12 @@ void FolderNode::buildTree(QList<FileNode *> &files)
for (auto i = deletedFolderMapping.constBegin(); i != deletedFolderMapping.constEnd(); ++i) {
ProjectExplorer::FolderNode *parent = i.key();
parent->removeFileNodes(i.value());
+
+ if (parent == this) // Never delete this node!
+ continue;
+
// Check for empty parent
- while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
+ while (parent->folderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
ProjectExplorer::FolderNode *grandparent = parent->parentFolderNode();
grandparent->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent);
parent = grandparent;
@@ -368,7 +499,7 @@ void FolderNode::buildTree(QList<FileNode *> &files)
void FolderNode::accept(NodesVisitor *visitor)
{
visitor->visitFolderNode(this);
- foreach (FolderNode *subFolder, m_subFolderNodes)
+ foreach (FolderNode *subFolder, m_folderNodes)
subFolder->accept(visitor);
}
@@ -394,36 +525,41 @@ QString FolderNode::addFileFilter() const
bool FolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
{
- if (projectNode())
- return projectNode()->addFiles(filePaths, notAdded);
+ ProjectNode *pn = managingProject();
+ if (pn)
+ return pn->addFiles(filePaths, notAdded);
return false;
}
bool FolderNode::removeFiles(const QStringList &filePaths, QStringList *notRemoved)
{
- if (projectNode())
- return projectNode()->removeFiles(filePaths, notRemoved);
+ ProjectNode *pn = managingProject();
+ if (pn)
+ return pn->removeFiles(filePaths, notRemoved);
return false;
}
bool FolderNode::deleteFiles(const QStringList &filePaths)
{
- if (projectNode())
- return projectNode()->deleteFiles(filePaths);
+ ProjectNode *pn = managingProject();
+ if (pn)
+ return pn->deleteFiles(filePaths);
return false;
}
bool FolderNode::canRenameFile(const QString &filePath, const QString &newFilePath)
{
- if (projectNode())
- return projectNode()->canRenameFile(filePath, newFilePath);
+ ProjectNode *pn = managingProject();
+ if (pn)
+ return pn->canRenameFile(filePath, newFilePath);
return false;
}
bool FolderNode::renameFile(const QString &filePath, const QString &newFilePath)
{
- if (projectNode())
- return projectNode()->renameFile(filePath, newFilePath);
+ ProjectNode *pn = managingProject();
+ if (pn)
+ return pn->renameFile(filePath, newFilePath);
return false;
}
@@ -443,7 +579,8 @@ FolderNode::AddNewInformation FolderNode::addNewInformation(const QStringList &f
void FolderNode::addFileNodes(const QList<FileNode *> &files)
{
- Q_ASSERT(projectNode());
+ Q_ASSERT(managingProject());
+
if (files.isEmpty())
return;
@@ -454,7 +591,6 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files)
qDebug("File node has already a parent folder"));
file->setParentFolderNode(this);
- file->setProjectNode(projectNode());
// Now find the correct place to insert file
if (m_fileNodes.count() == 0
|| m_fileNodes.last() < file) {
@@ -479,7 +615,7 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files)
void FolderNode::removeFileNodes(const QList<FileNode *> &files)
{
- Q_ASSERT(projectNode());
+ Q_ASSERT(managingProject());
if (files.isEmpty())
return;
@@ -510,7 +646,7 @@ void FolderNode::removeFileNodes(const QList<FileNode *> &files)
*/
void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders)
{
- Q_ASSERT(projectNode());
+ Q_ASSERT(managingProject());
if (subFolders.isEmpty())
return;
@@ -520,21 +656,20 @@ void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders)
QTC_ASSERT(!folder->parentFolderNode(),
qDebug("Project node has already a parent folder"));
folder->setParentFolderNode(this);
- folder->setProjectNode(projectNode());
// Find the correct place to insert
- if (m_subFolderNodes.count() == 0
- || m_subFolderNodes.last() < folder) {
+ if (m_folderNodes.count() == 0
+ || m_folderNodes.last() < folder) {
// empty list or greater then last node
- m_subFolderNodes.append(folder);
+ m_folderNodes.append(folder);
} else {
// Binary Search for insertion point
- auto it = std::lower_bound(m_subFolderNodes.begin(), m_subFolderNodes.end(), folder);
- m_subFolderNodes.insert(it, folder);
+ auto it = std::lower_bound(m_folderNodes.begin(), m_folderNodes.end(), folder);
+ m_folderNodes.insert(it, folder);
}
// project nodes have to be added via addProjectNodes
- QTC_ASSERT(folder->nodeType() != ProjectNodeType,
+ QTC_ASSERT(folder->nodeType() != NodeType::Project,
qDebug("project nodes have to be added via addProjectNodes"));
}
@@ -549,7 +684,7 @@ void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders)
*/
void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders)
{
- Q_ASSERT(projectNode());
+ Q_ASSERT(managingProject());
if (subFolders.isEmpty())
return;
@@ -560,27 +695,22 @@ void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders)
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin();
- auto folderIter = m_subFolderNodes.begin();
+ auto folderIter = m_folderNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
- QTC_ASSERT((*toRemoveIter)->nodeType() != ProjectNodeType,
+ QTC_ASSERT((*toRemoveIter)->nodeType() != NodeType::Project,
qDebug("project nodes have to be removed via removeProjectNodes"));
while (*folderIter != *toRemoveIter) {
++folderIter;
- QTC_ASSERT(folderIter != m_subFolderNodes.end(),
+ QTC_ASSERT(folderIter != m_folderNodes.end(),
qDebug("Folder to remove is not part of specified folder!"));
}
delete *folderIter;
- folderIter = m_subFolderNodes.erase(folderIter);
+ folderIter = m_folderNodes.erase(folderIter);
}
ProjectTree::instance()->emitFoldersRemoved(this);
}
-FolderNode *FolderNode::asFolderNode()
-{
- return this;
-}
-
bool FolderNode::showInSimpleTree() const
{
return false;
@@ -598,13 +728,9 @@ bool FolderNode::showInSimpleTree() const
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
*/
VirtualFolderNode::VirtualFolderNode(const Utils::FileName &folderPath, int priority) :
- FolderNode(folderPath, VirtualFolderNodeType),
- m_priority(priority)
-{ }
-
-int VirtualFolderNode::priority() const
+ FolderNode(folderPath, NodeType::VirtualFolder, QString())
{
- return m_priority;
+ setPriority(priority);
}
/*!
@@ -621,10 +747,9 @@ int VirtualFolderNode::priority() const
Creates an uninitialized project node object.
*/
ProjectNode::ProjectNode(const Utils::FileName &projectFilePath) :
- FolderNode(projectFilePath, ProjectNodeType)
+ FolderNode(projectFilePath, NodeType::Project)
{
- // project node "manages" itself
- setProjectNode(this);
+ setPriority(DefaultProjectPriority);
setDisplayName(projectFilePath.fileName());
}
@@ -639,11 +764,6 @@ QString ProjectNode::vcsTopic() const
return QString();
}
-QList<ProjectNode*> ProjectNode::subProjectNodes() const
-{
- return m_subProjectNodes;
-}
-
bool ProjectNode::canAddSubProject(const QString &proFilePath) const
{
Q_UNUSED(proFilePath)
@@ -716,10 +836,22 @@ void ProjectNode::accept(NodesVisitor *visitor)
{
visitor->visitProjectNode(this);
- foreach (FolderNode *folder, m_subFolderNodes)
+ foreach (FolderNode *folder, m_folderNodes)
folder->accept(visitor);
}
+ProjectNode *ProjectNode::projectNode(const Utils::FileName &file) const
+{
+ return Utils::findOrDefault(m_projectNodes, [&file](const ProjectNode *fn) {
+ return fn->filePath() == file;
+ });
+}
+
+QList<ProjectNode*> ProjectNode::projectNodes() const
+{
+ return m_projectNodes;
+}
+
/*!
Adds project nodes specified by \a subProjects to the node hierarchy and
emits the corresponding signals.
@@ -737,11 +869,11 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
qDebug("Project node has already a parent"));
project->setParentFolderNode(this);
- m_subFolderNodes.append(project);
- m_subProjectNodes.append(project);
+ m_folderNodes.append(project);
+ m_projectNodes.append(project);
}
- Utils::sort(m_subFolderNodes);
- Utils::sort(m_subProjectNodes);
+ Utils::sort(m_folderNodes);
+ Utils::sort(m_projectNodes);
ProjectTree::instance()->emitFoldersAdded(this);
}
@@ -765,40 +897,51 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin();
- auto folderIter = m_subFolderNodes.begin();
- auto projectIter = m_subProjectNodes.begin();
+ auto folderIter = m_folderNodes.begin();
+ auto projectIter = m_projectNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
while (*projectIter != *toRemoveIter) {
++projectIter;
- QTC_ASSERT(projectIter != m_subProjectNodes.end(),
+ QTC_ASSERT(projectIter != m_projectNodes.end(),
qDebug("Project to remove is not part of specified folder!"));
}
while (*folderIter != *toRemoveIter) {
++folderIter;
- QTC_ASSERT(folderIter != m_subFolderNodes.end(),
+ QTC_ASSERT(folderIter != m_folderNodes.end(),
qDebug("Project to remove is not part of specified folder!"));
}
delete *projectIter;
- projectIter = m_subProjectNodes.erase(projectIter);
- folderIter = m_subFolderNodes.erase(folderIter);
+ projectIter = m_projectNodes.erase(projectIter);
+ folderIter = m_folderNodes.erase(folderIter);
}
ProjectTree::instance()->emitFoldersRemoved(this);
}
}
-ProjectNode *ProjectNode::asProjectNode()
+Node *ProjectNode::trim(const QSet<Node *> &keepers)
{
- return this;
-}
+ if (keepers.contains(this))
+ return nullptr;
+ QList<Node *> toTrim
+ = Utils::transform(m_projectNodes, [&keepers](Node *n) { return n->trim(keepers); });
+ int count = toTrim.count();
+ toTrim = Utils::filtered(toTrim, [](Node *n) { return n; });
+ removeProjectNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<ProjectNode *>(n); }));
+
+ if (!FolderNode::trim(keepers))
+ return nullptr;
+
+ return (toTrim.count() != count) ? nullptr : this;
+}
/*!
\class ProjectExplorer::SessionNode
*/
SessionNode::SessionNode() :
- FolderNode(Utils::FileName::fromString("session"), SessionNodeType)
+ FolderNode(Utils::FileName::fromString("session"), NodeType::Session)
{ }
QList<ProjectAction> SessionNode::supportedActions(Node *node) const
@@ -826,11 +969,6 @@ void SessionNode::projectDisplayNameChanged(Node *node)
ProjectTree::instance()->emitNodeSortKeyChanged(node);
}
-SessionNode *SessionNode::asSessionNode()
-{
- return this;
-}
-
QList<ProjectNode*> SessionNode::projectNodes() const
{
return m_projectNodes;
@@ -854,11 +992,11 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
QTC_ASSERT(!project->parentFolderNode(),
qDebug("Project node has already a parent folder"));
project->setParentFolderNode(this);
- m_subFolderNodes.append(project);
+ m_folderNodes.append(project);
m_projectNodes.append(project);
}
- Utils::sort(m_subFolderNodes);
+ Utils::sort(m_folderNodes);
Utils::sort(m_projectNodes);
ProjectTree::instance()->emitFoldersAdded(this);
@@ -877,7 +1015,7 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
auto toRemoveIter = toRemove.constBegin();
- auto folderIter = m_subFolderNodes.begin();
+ auto folderIter = m_folderNodes.begin();
auto projectIter = m_projectNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
while (*projectIter != *toRemoveIter) {
@@ -887,11 +1025,11 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
}
while (*folderIter != *toRemoveIter) {
++folderIter;
- QTC_ASSERT(folderIter != m_subFolderNodes.end(),
+ QTC_ASSERT(folderIter != m_folderNodes.end(),
qDebug("Project to remove is not part of specified folder!"));
}
projectIter = m_projectNodes.erase(projectIter);
- folderIter = m_subFolderNodes.erase(folderIter);
+ folderIter = m_folderNodes.erase(folderIter);
}
ProjectTree::instance()->emitFoldersRemoved(this);
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
index a4b4ea4765..3de04ecf13 100644
--- a/src/plugins/projectexplorer/projectnodes.h
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -29,12 +29,15 @@
#include <utils/fileutils.h>
+#include <QFutureInterface>
#include <QIcon>
#include <QObject>
#include <QStringList>
#include <QDebug>
+#include <functional>
+
QT_BEGIN_NAMESPACE
class QFileInfo;
QT_END_NAMESPACE
@@ -42,24 +45,24 @@ QT_END_NAMESPACE
namespace ProjectExplorer {
class RunConfiguration;
-enum NodeType {
- FileNodeType = 1,
- FolderNodeType,
- VirtualFolderNodeType,
- ProjectNodeType,
- SessionNodeType
+enum class NodeType : quint16 {
+ File = 1,
+ Folder,
+ VirtualFolder,
+ Project,
+ Session
};
// File types common for qt projects
-enum FileType {
- UnknownFileType = 0,
- HeaderType,
- SourceType,
- FormType,
- StateChartType,
- ResourceType,
- QMLType,
- ProjectFileType,
+enum class FileType : quint16 {
+ Unknown = 0,
+ Header,
+ Source,
+ Form,
+ StateChart,
+ Resource,
+ QML,
+ Project,
FileTypeSize
};
@@ -104,42 +107,70 @@ class SessionManager;
class PROJECTEXPLORER_EXPORT Node
{
public:
- virtual ~Node();
+ enum PriorityLevel {
+ DefaultPriority = 0,
+ DefaultFilePriority = 100000,
+ DefaultFolderPriority = 200000,
+ DefaultVirtualFolderPriority = 300000,
+ DefaultProjectPriority = 400000,
+ DefaultProjectFilePriority = 500000
+ };
+
+ virtual ~Node() = default;
NodeType nodeType() const;
- ProjectNode *projectNode() const; // managing project
+ int priority() const;
+
+ ProjectNode *parentProjectNode() const; // parent project, will be nullptr for the top-level project
FolderNode *parentFolderNode() const; // parent folder or project
+
+ ProjectNode *managingProject(); // project managing this node.
+ // result is nullptr if node is the SessionNode
+ // or node if node is a ProjectNode directly below SessionNode
+ // or node->parentProjectNode() for all other cases.
+ const ProjectNode *managingProject() const; // see above.
+
const Utils::FileName &filePath() const; // file system path
int line() const;
virtual QString displayName() const;
virtual QString tooltip() const;
- virtual bool isEnabled() const;
+ bool isEnabled() const;
virtual QList<ProjectAction> supportedActions(Node *node) const;
+ void setEnabled(bool enabled);
void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
void emitNodeUpdated();
- virtual FileNode *asFileNode();
- virtual FolderNode *asFolderNode();
- virtual ProjectNode *asProjectNode();
- virtual SessionNode *asSessionNode();
+ virtual Node *trim(const QSet<Node *> &keepers);
+
+ virtual FileNode *asFileNode() { return nullptr; }
+ virtual const FileNode *asFileNode() const { return nullptr; }
+ virtual FolderNode *asFolderNode() { return nullptr; }
+ virtual const FolderNode *asFolderNode() const { return nullptr; }
+ virtual ProjectNode *asProjectNode() { return nullptr; }
+ virtual const ProjectNode *asProjectNode() const { return nullptr; }
+ virtual SessionNode *asSessionNode() { return nullptr; }
+ virtual const SessionNode *asSessionNode() const { return nullptr; }
+
+ static bool sortByPath(Node *a, Node *b);
protected:
Node(NodeType nodeType, const Utils::FileName &filePath, int line = -1);
- void setProjectNode(ProjectNode *project);
+ void setPriority(int priority);
void setParentFolderNode(FolderNode *parentFolder);
void emitNodeSortKeyAboutToChange();
void emitNodeSortKeyChanged();
private:
- NodeType m_nodeType;
- int m_line;
- ProjectNode *m_projectNode = nullptr;
- FolderNode *m_folderNode = nullptr;
+ FolderNode *m_parentFolderNode = nullptr;
Utils::FileName m_filePath;
+ int m_line = -1;
+ int m_priority = DefaultPriority;
+ const NodeType m_nodeType;
+ bool m_isEnabled = true;
};
class PROJECTEXPLORER_EXPORT FileNode : public Node
@@ -150,7 +181,12 @@ public:
FileType fileType() const;
bool isGenerated() const;
- FileNode *asFileNode() override;
+ FileNode *asFileNode() final { return this; }
+ const FileNode *asFileNode() const final { return this; }
+
+ static QList<FileNode *> scanForFiles(const Utils::FileName &directory,
+ const std::function<FileNode *(const Utils::FileName &fileName)> factory,
+ QFutureInterface<QList<FileNode *>> *future = nullptr);
private:
// managed by ProjectNode
@@ -165,18 +201,24 @@ private:
class PROJECTEXPLORER_EXPORT FolderNode : public Node
{
public:
- explicit FolderNode(const Utils::FileName &folderPath, NodeType nodeType = FolderNodeType,
+ explicit FolderNode(const Utils::FileName &folderPath, NodeType nodeType = NodeType::Folder,
const QString &displayName = QString());
~FolderNode() override;
QString displayName() const override;
QIcon icon() const;
+ Node *trim(const QSet<Node *> &keepers) override;
+
QList<FileNode *> fileNodes() const;
+ FileNode *fileNode(const Utils::FileName &file) const;
+ FileNode *recursiveFileNode(const Utils::FileName &file) const;
QList<FileNode *> recursiveFileNodes() const;
- QList<FolderNode *> subFolderNodes() const;
- FolderNode *findOrCreateSubFolderNode(const QString &directory);
- void buildTree(QList<FileNode *> &files);
+ QList<FolderNode *> folderNodes() const;
+ FolderNode *folderNode(const Utils::FileName &directory) const;
+ FolderNode *recursiveFindOrCreateFolderNode(const QString &directory,
+ const Utils::FileName &overrideBaseDir = Utils::FileName());
+ void buildTree(QList<FileNode *> &files, const Utils::FileName &overrideBaseDir = Utils::FileName());
virtual void accept(NodesVisitor *visitor);
@@ -213,28 +255,25 @@ public:
void addFolderNodes(const QList<FolderNode*> &subFolders);
void removeFolderNodes(const QList<FolderNode*> &subFolders);
- FolderNode *asFolderNode() override;
+ FolderNode *asFolderNode() final { return this; }
+ const FolderNode *asFolderNode() const final { return this; }
protected:
- QList<FolderNode*> m_subFolderNodes;
+ QList<FolderNode*> m_folderNodes;
QList<FileNode*> m_fileNodes;
private:
- // managed by ProjectNode
- friend class ProjectNode;
QString m_displayName;
mutable QIcon m_icon;
+
+ // managed by ProjectNode
+ friend class ProjectNode;
};
class PROJECTEXPLORER_EXPORT VirtualFolderNode : public FolderNode
{
public:
explicit VirtualFolderNode(const Utils::FileName &folderPath, int priority);
-
- int priority() const;
-
-private:
- int m_priority;
};
// Documentation inside.
@@ -243,9 +282,6 @@ class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode
public:
QString vcsTopic() const;
- // all subFolders that are projects
- QList<ProjectNode*> subProjectNodes() const;
-
virtual bool canAddSubProject(const QString &proFilePath) const;
virtual bool addSubProjects(const QStringList &proFilePaths);
virtual bool removeSubProjects(const QStringList &proFilePaths);
@@ -263,14 +299,16 @@ public:
void accept(NodesVisitor *visitor) override;
- bool isEnabled() const override { return true; }
-
- // to be called in implementation of
- // the corresponding public functions
+ ProjectNode *projectNode(const Utils::FileName &file) const;
+ // all subFolders that are projects
+ QList<ProjectNode*> projectNodes() const;
void addProjectNodes(const QList<ProjectNode*> &subProjects);
void removeProjectNodes(const QList<ProjectNode*> &subProjects);
- ProjectNode *asProjectNode() override;
+ ProjectNode *asProjectNode() final { return this; }
+ const ProjectNode *asProjectNode() const final { return this; }
+
+ Node *trim(const QSet<Node *> &keepers) override;
protected:
// this is just the in-memory representation, a subclass
@@ -278,7 +316,7 @@ protected:
explicit ProjectNode(const Utils::FileName &projectFilePath);
private:
- QList<ProjectNode*> m_subProjectNodes;
+ QList<ProjectNode*> m_projectNodes;
// let SessionNode call setParentFolderNode
friend class SessionNode;
@@ -299,12 +337,12 @@ public:
void accept(NodesVisitor *visitor) override;
- bool isEnabled() const override { return true; }
-
bool showInSimpleTree() const override;
void projectDisplayNameChanged(Node *node);
- SessionNode *asSessionNode() override;
+ SessionNode *asSessionNode() final { return this; }
+ const SessionNode *asSessionNode() const final { return this; }
+
protected:
void addProjectNodes(const QList<ProjectNode*> &projectNodes);
void removeProjectNodes(const QList<ProjectNode*> &projectNodes);
diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp
index 3e89539aac..1ec856c651 100644
--- a/src/plugins/projectexplorer/projecttree.cpp
+++ b/src/plugins/projectexplorer/projecttree.cpp
@@ -341,10 +341,10 @@ void ProjectTree::emitFoldersAboutToBeRemoved(FolderNode *parentFolder, const QL
while (n) {
if (FolderNode *fn = n->asFolderNode()) {
if (staleFolders.contains(fn)) {
- ProjectNode *pn = n->projectNode();
+ ProjectNode *pn = n->parentProjectNode();
// Make sure the node we are switching too isn't going to be removed also
while (staleFolders.contains(pn))
- pn = pn->parentFolderNode()->projectNode();
+ pn = pn->parentFolderNode()->parentProjectNode();
m_resetCurrentNodeFolder = true;
break;
}
@@ -492,22 +492,22 @@ void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &global
if (!node)
node = SessionManager::sessionNode();
- if (node->nodeType() != SessionNodeType) {
+ if (node->nodeType() != NodeType::Session) {
Project *project = SessionManager::projectForNode(node);
emit s_instance->aboutToShowContextMenu(project, node);
switch (node->nodeType()) {
- case ProjectNodeType:
+ case NodeType::Project:
if (node->parentFolderNode() == SessionManager::sessionNode())
contextMenu = Core::ActionManager::actionContainer(Constants::M_PROJECTCONTEXT)->menu();
else
contextMenu = Core::ActionManager::actionContainer(Constants::M_SUBPROJECTCONTEXT)->menu();
break;
- case VirtualFolderNodeType:
- case FolderNodeType:
+ case NodeType::VirtualFolder:
+ case NodeType::Folder:
contextMenu = Core::ActionManager::actionContainer(Constants::M_FOLDERCONTEXT)->menu();
break;
- case FileNodeType:
+ case NodeType::File:
contextMenu = Core::ActionManager::actionContainer(Constants::M_FILECONTEXT)->menu();
break;
default:
diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp
index 233b0c95ca..ba2f304c7a 100644
--- a/src/plugins/projectexplorer/projecttreewidget.cpp
+++ b/src/plugins/projectexplorer/projecttreewidget.cpp
@@ -533,7 +533,7 @@ void ProjectTreeWidget::initView()
void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
{
Node *node = m_model->nodeForIndex(mainIndex);
- if (node->nodeType() != FileNodeType)
+ if (node->nodeType() != NodeType::File)
return;
IEditor *editor = EditorManager::openEditor(node->filePath().toString());
if (editor && node->line() >= 0)
diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp
index 7d7980a965..24e1d79d9d 100644
--- a/src/plugins/projectexplorer/projectwizardpage.cpp
+++ b/src/plugins/projectexplorer/projectwizardpage.cpp
@@ -170,7 +170,7 @@ BestNodeSelector::BestNodeSelector(const QString &commonDirectory, const QString
void BestNodeSelector::inspect(AddNewTree *tree, bool isContextNode)
{
FolderNode *node = tree->node();
- if (node->nodeType() == ProjectNodeType) {
+ if (node->nodeType() == NodeType::Project) {
if (static_cast<ProjectNode *>(node)->deploysFolder(m_commonDirectory)) {
m_deploys = true;
m_deployText += tree->displayName() + QLatin1Char('\n');
@@ -232,7 +232,7 @@ static inline AddNewTree *createNoneNode(BestNodeSelector *selector)
static inline AddNewTree *buildAddProjectTree(ProjectNode *root, const QString &projectPath, Node *contextNode, BestNodeSelector *selector)
{
QList<AddNewTree *> children;
- foreach (ProjectNode *pn, root->subProjectNodes()) {
+ foreach (ProjectNode *pn, root->projectNodes()) {
AddNewTree *child = buildAddProjectTree(pn, projectPath, contextNode, selector);
if (child)
children.append(child);
@@ -269,7 +269,7 @@ static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList
Node *contextNode, BestNodeSelector *selector)
{
QList<AddNewTree *> children;
- foreach (FolderNode *fn, root->subFolderNodes()) {
+ foreach (FolderNode *fn, root->folderNodes()) {
AddNewTree *child = buildAddFilesTree(fn, files, contextNode, selector);
if (child)
children.append(child);
diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp
index ee33bc79cc..a470814c56 100644
--- a/src/plugins/projectexplorer/session.cpp
+++ b/src/plugins/projectexplorer/session.cpp
@@ -610,7 +610,7 @@ Node *SessionManager::nodeForFile(const Utils::FileName &fileName)
Node *node = nullptr;
foreach (Node *n, nodesForFile(fileName)) {
// prefer file nodes
- if (!node || (node->nodeType() != FileNodeType && n->nodeType() == FileNodeType))
+ if (!node || (node->nodeType() != NodeType::File && n->nodeType() == NodeType::File))
node = n;
}
return node;
diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp
index 2aab5cf231..60ed1a9d7f 100644
--- a/src/plugins/pythoneditor/pythoneditorplugin.cpp
+++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp
@@ -598,7 +598,7 @@ class PythonFileNode : public FileNode
{
public:
PythonFileNode(const Utils::FileName &filePath, const QString &nodeDisplayName)
- : FileNode(filePath, SourceType, false)
+ : FileNode(filePath, FileType::Source, false)
, m_displayName(nodeDisplayName)
{}
diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp
index dd847f5bdb..27796ed6d4 100644
--- a/src/plugins/qbsprojectmanager/qbsnodes.cpp
+++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp
@@ -87,7 +87,7 @@ QIcon QbsProductNode::m_productIcon;
static QbsProjectNode *parentQbsProjectNode(ProjectExplorer::Node *node)
{
- for (ProjectExplorer::FolderNode *pn = node->projectNode(); pn; pn = pn->parentFolderNode()) {
+ for (ProjectExplorer::FolderNode *pn = node->managingProject(); pn; pn = pn->parentProjectNode()) {
QbsProjectNode *prjNode = dynamic_cast<QbsProjectNode *>(pn);
if (prjNode)
return prjNode;
@@ -252,7 +252,7 @@ static QList<ProjectExplorer::ProjectAction> supportedNodeActions(ProjectExplore
return actions;
if (managesFiles)
actions << ProjectExplorer::AddNewFile << ProjectExplorer::AddExistingFile;
- if (node->nodeType() == ProjectExplorer::FileNodeType
+ if (node->nodeType() == ProjectExplorer::NodeType::File
&& !project->qbsProject().buildSystemFiles().contains(node->filePath().toString())) {
actions << ProjectExplorer::RemoveFile << ProjectExplorer::Rename;
}
@@ -323,21 +323,13 @@ QbsGroupNode::QbsGroupNode(const qbs::GroupData &grp, const QString &productPath
setIcon(m_groupIcon);
QbsFileNode *idx = new QbsFileNode(Utils::FileName::fromString(grp.location().filePath()),
- ProjectExplorer::ProjectFileType, false,
+ ProjectExplorer::FileType::Project, false,
grp.location().line());
addFileNodes(QList<ProjectExplorer::FileNode *>() << idx);
updateQbsGroupData(grp, productPath, true, true);
}
-bool QbsGroupNode::isEnabled() const
-{
- if (!parentFolderNode() || !m_qbsGroupData.isValid())
- return false;
- return static_cast<QbsProductNode *>(parentFolderNode())->isEnabled()
- && m_qbsGroupData.isEnabled();
-}
-
QList<ProjectExplorer::ProjectAction> QbsGroupNode::supportedActions(ProjectExplorer::Node *node) const
{
return supportedNodeActions(node, true);
@@ -413,6 +405,8 @@ void QbsGroupNode::updateQbsGroupData(const qbs::GroupData &grp, const QString &
bool groupIsEnabled = productIsEnabled && grp.isEnabled();
bool updateExisting = groupWasEnabled != groupIsEnabled;
+ setEnabled(groupIsEnabled);
+
m_productPath = productPath;
m_qbsGroupData = grp;
@@ -481,8 +475,8 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root,
QList<ProjectExplorer::FileNode *> filesToAdd;
QList<ProjectExplorer::FolderNode *> foldersToRemove;
- foreach (ProjectExplorer::FolderNode *fn, root->subFolderNodes()) {
- if (fn->nodeType() == ProjectExplorer::ProjectNodeType)
+ foreach (ProjectExplorer::FolderNode *fn, root->folderNodes()) {
+ if (fn->nodeType() == ProjectExplorer::NodeType::Project)
continue; // Skip ProjectNodes mixed into the folders...
const auto * const qbsFolder = dynamic_cast<QbsFolderNode *>(fn);
if (qbsFolder && qbsFolder->isGeneratedFilesFolder())
@@ -493,8 +487,8 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root,
foreach (FileTreeNode *c, fileTree->children) {
Utils::FileName path = Utils::FileName::fromString(c->path());
const ProjectExplorer::FileType newFileType =
- fileTypeHash.value(c->path(), ProjectExplorer::UnknownFileType);
- const bool isQrcFile = newFileType == ProjectExplorer::ResourceType;
+ fileTypeHash.value(c->path(), ProjectExplorer::FileType::Unknown);
+ const bool isQrcFile = newFileType == ProjectExplorer::FileType::Resource;
// Handle files:
if (c->isFile() && !isQrcFile) {
@@ -517,7 +511,7 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root,
continue;
} else {
ProjectExplorer::FolderNode *fn = 0;
- foreach (ProjectExplorer::FolderNode *f, root->subFolderNodes()) {
+ foreach (ProjectExplorer::FolderNode *f, root->folderNodes()) {
// There can be one match only here!
if (f->filePath() != path)
continue;
@@ -530,7 +524,7 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root,
fn = new ResourceTopLevelNode(Utils::FileName::fromString(c->path()), QString(), root);
} else {
fn = new QbsFolderNode(Utils::FileName::fromString(c->path()),
- ProjectExplorer::FolderNodeType,
+ ProjectExplorer::NodeType::Folder,
displayNameFromPath(c->path(), baseDir), false);
}
root->addFolderNodes(QList<FolderNode *>() << fn);
@@ -555,23 +549,23 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root,
ProjectExplorer::FileType QbsGroupNode::fileType(const qbs::ArtifactData &artifact)
{
- QTC_ASSERT(artifact.isValid(), return ProjectExplorer::UnknownFileType);
+ QTC_ASSERT(artifact.isValid(), return ProjectExplorer::FileType::Unknown);
if (artifact.fileTags().contains(QLatin1String("c"))
|| artifact.fileTags().contains(QLatin1String("cpp"))
|| artifact.fileTags().contains(QLatin1String("objc"))
|| artifact.fileTags().contains(QLatin1String("objcpp"))) {
- return ProjectExplorer::SourceType;
+ return ProjectExplorer::FileType::Source;
}
if (artifact.fileTags().contains(QLatin1String("hpp")))
- return ProjectExplorer::HeaderType;
+ return ProjectExplorer::FileType::Header;
if (artifact.fileTags().contains(QLatin1String("qrc")))
- return ProjectExplorer::ResourceType;
+ return ProjectExplorer::FileType::Resource;
if (artifact.fileTags().contains(QLatin1String("ui")))
- return ProjectExplorer::FormType;
+ return ProjectExplorer::FileType::Form;
if (artifact.fileTags().contains(QLatin1String("scxml")))
- return ProjectExplorer::StateChartType;
- return ProjectExplorer::UnknownFileType;
+ return ProjectExplorer::FileType::StateChart;
+ return ProjectExplorer::FileType::Unknown;
}
// --------------------------------------------------------------------
@@ -581,7 +575,7 @@ ProjectExplorer::FileType QbsGroupNode::fileType(const qbs::ArtifactData &artifa
QbsProductNode::QbsProductNode(const qbs::Project &project, const qbs::ProductData &prd) :
QbsBaseProjectNode(Utils::FileName::fromString(prd.location().filePath())),
m_generatedFilesNode(new QbsFolderNode(Utils::FileName::fromString(prd.buildDirectory()),
- ProjectExplorer::FolderNodeType,
+ ProjectExplorer::NodeType::Folder,
QCoreApplication::translate("QbsProductNode", "Generated files"), true))
{
if (m_productIcon.isNull())
@@ -591,18 +585,13 @@ QbsProductNode::QbsProductNode(const qbs::Project &project, const qbs::ProductDa
addFolderNodes(QList<ProjectExplorer::FolderNode *>() << m_generatedFilesNode);
auto idx = new QbsFileNode(Utils::FileName::fromString(prd.location().filePath()),
- ProjectExplorer::ProjectFileType, false,
+ ProjectExplorer::FileType::Project, false,
prd.location().line());
addFileNodes(QList<ProjectExplorer::FileNode *>() << idx);
setQbsProductData(project, prd);
}
-bool QbsProductNode::isEnabled() const
-{
- return m_qbsProductData.isEnabled();
-}
-
bool QbsProductNode::showInSimpleTree() const
{
return true;
@@ -675,6 +664,8 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
bool productIsEnabled = prd.isEnabled();
bool updateExisting = productWasEnabled != productIsEnabled;
+ setEnabled(prd.isEnabled());
+
setDisplayName(QbsProject::productDisplayName(project, prd));
setAbsoluteFilePathAndLine(Utils::FileName::fromString(prd.location().filePath()), line());
const QString &productPath = QFileInfo(prd.location().filePath()).absolutePath();
@@ -691,7 +682,7 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
prd.location().line());
QList<ProjectExplorer::ProjectNode *> toAdd;
- QList<ProjectExplorer::ProjectNode *> toRemove = subProjectNodes();
+ QList<ProjectExplorer::ProjectNode *> toRemove = projectNodes();
foreach (const qbs::GroupData &grp, prd.groups()) {
if (grp.name() == prd.name() && grp.location() == prd.location()) {
@@ -728,7 +719,7 @@ void QbsProductNode::setQbsProductData(const qbs::Project &project, const qbs::P
QList<ProjectExplorer::RunConfiguration *> QbsProductNode::runConfigurations() const
{
QList<ProjectExplorer::RunConfiguration *> result;
- QbsProjectNode *pn = dynamic_cast<QbsProjectNode *>(projectNode());
+ auto pn = dynamic_cast<const QbsProjectNode *>(managingProject());
if (!isEnabled() || !pn || m_qbsProductData.targetExecutable().isEmpty())
return result;
@@ -745,7 +736,7 @@ QList<ProjectExplorer::RunConfiguration *> QbsProductNode::runConfigurations() c
QbsGroupNode *QbsProductNode::findGroupNode(const QString &name)
{
- foreach (ProjectExplorer::ProjectNode *n, subProjectNodes()) {
+ foreach (ProjectExplorer::ProjectNode *n, projectNodes()) {
QbsGroupNode *qn = static_cast<QbsGroupNode *>(n);
if (qn->qbsGroupData().name() == name)
return qn;
@@ -771,7 +762,7 @@ QbsProjectNode::~QbsProjectNode()
void QbsProjectNode::update(const qbs::Project &qbsProject, const qbs::ProjectData &prjData)
{
QList<ProjectExplorer::ProjectNode *> toAdd;
- QList<ProjectExplorer::ProjectNode *> toRemove = subProjectNodes();
+ QList<ProjectExplorer::ProjectNode *> toRemove = projectNodes();
foreach (const qbs::ProjectData &subData, prjData.subProjects()) {
QbsProjectNode *qn = findProjectNode(subData.name());
@@ -828,12 +819,12 @@ void QbsProjectNode::ctor()
setIcon(m_projectIcon);
addFileNodes(QList<ProjectExplorer::FileNode *>()
- << new ProjectExplorer::FileNode(filePath(), ProjectExplorer::ProjectFileType, false));
+ << new ProjectExplorer::FileNode(filePath(), ProjectExplorer::FileType::Project, false));
}
QbsProductNode *QbsProjectNode::findProductNode(const QString &uniqueName)
{
- foreach (ProjectExplorer::ProjectNode *n, subProjectNodes()) {
+ foreach (ProjectExplorer::ProjectNode *n, projectNodes()) {
QbsProductNode *qn = dynamic_cast<QbsProductNode *>(n);
if (qn && QbsProject::uniqueProductName(qn->qbsProductData()) == uniqueName)
return qn;
@@ -843,7 +834,7 @@ QbsProductNode *QbsProjectNode::findProductNode(const QString &uniqueName)
QbsProjectNode *QbsProjectNode::findProjectNode(const QString &name)
{
- foreach (ProjectExplorer::ProjectNode *n, subProjectNodes()) {
+ foreach (ProjectExplorer::ProjectNode *n, projectNodes()) {
QbsProjectNode *qn = dynamic_cast<QbsProjectNode *>(n);
if (qn && qn->qbsProjectData().name() == name)
return qn;
@@ -859,7 +850,7 @@ QbsRootProjectNode::QbsRootProjectNode(QbsProject *project) :
QbsProjectNode(project->projectFilePath()),
m_project(project),
m_buildSystemFiles(new ProjectExplorer::FolderNode(project->projectDirectory(),
- ProjectExplorer::FolderNodeType,
+ ProjectExplorer::NodeType::Folder,
QCoreApplication::translate("QbsRootProjectNode", "Qbs files")))
{
addFolderNodes(QList<FolderNode *>() << m_buildSystemFiles);
diff --git a/src/plugins/qbsprojectmanager/qbsnodes.h b/src/plugins/qbsprojectmanager/qbsnodes.h
index cfc86deb89..846b93f8ff 100644
--- a/src/plugins/qbsprojectmanager/qbsnodes.h
+++ b/src/plugins/qbsprojectmanager/qbsnodes.h
@@ -92,7 +92,6 @@ class QbsGroupNode : public QbsBaseProjectNode
public:
QbsGroupNode(const qbs::GroupData &grp, const QString &productPath);
- bool isEnabled() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0) override;
@@ -130,7 +129,6 @@ class QbsProductNode : public QbsBaseProjectNode
public:
explicit QbsProductNode(const qbs::Project &project, const qbs::ProductData &prd);
- bool isEnabled() const override;
bool showInSimpleTree() const override;
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0) override;
diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
index 04cc9c25ae..b078fc6b7e 100644
--- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
+++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp
@@ -258,8 +258,10 @@ void QbsProjectManagerPlugin::updateContextActions()
&& m_selectedProject && !m_selectedProject->isParsing()
&& m_selectedNode && m_selectedNode->isEnabled();
- bool isFile = m_selectedProject && m_selectedNode && (m_selectedNode->nodeType() == FileNodeType);
- bool isProduct = m_selectedProject && m_selectedNode && dynamic_cast<QbsProductNode *>(m_selectedNode->projectNode());
+ bool isFile = m_selectedProject && m_selectedNode && (m_selectedNode->nodeType() == NodeType::File);
+ bool isProduct = m_selectedProject
+ && m_selectedNode
+ && dynamic_cast<QbsProductNode *>(m_selectedNode->parentProjectNode());
QbsProjectNode *subproject = dynamic_cast<QbsProjectNode *>(m_selectedNode);
bool isSubproject = m_selectedProject && subproject && subproject != m_selectedProject->rootProjectNode();
@@ -293,10 +295,10 @@ void QbsProjectManagerPlugin::updateBuildActions()
&& !m_editorProject->isParsing();
fileName = m_editorNode->filePath().fileName();
- fileVisible = m_editorProject && m_editorNode && dynamic_cast<QbsBaseProjectNode *>(m_editorNode->projectNode());
+ fileVisible = m_editorProject && m_editorNode && dynamic_cast<QbsBaseProjectNode *>(m_editorNode->parentProjectNode());
QbsProductNode *productNode
- = dynamic_cast<QbsProductNode *>(m_editorNode ? m_editorNode->projectNode() : 0);
+ = dynamic_cast<QbsProductNode *>(m_editorNode ? m_editorNode->parentProjectNode() : 0);
if (productNode) {
productVisible = true;
productName = productNode->displayName();
@@ -393,7 +395,7 @@ void QbsProjectManagerPlugin::buildProduct()
if (!m_editorProject || !m_editorNode)
return;
- QbsProductNode *product = dynamic_cast<QbsProductNode *>(m_editorNode->projectNode());
+ QbsProductNode *product = dynamic_cast<QbsProductNode *>(m_editorNode->parentProjectNode());
if (!product)
return;
@@ -423,7 +425,7 @@ void QbsProjectManagerPlugin::buildSubproject()
return;
QbsProjectNode *subproject = 0;
- QbsBaseProjectNode *start = dynamic_cast<QbsBaseProjectNode *>(m_editorNode->projectNode());
+ QbsBaseProjectNode *start = dynamic_cast<QbsBaseProjectNode *>(m_editorNode->parentProjectNode());
while (start && start != m_editorProject->rootProjectNode()) {
QbsProjectNode *tmp = dynamic_cast<QbsProjectNode *>(start);
if (tmp) {
diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp
index ac2b0f0e29..d9e1242359 100644
--- a/src/plugins/qmakeprojectmanager/profileeditor.cpp
+++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp
@@ -195,11 +195,11 @@ ProFileEditorFactory::ProFileEditorFactory()
const QString defaultOverlay = QLatin1String(ProjectExplorer::Constants::FILEOVERLAY_QT);
Core::FileIconProvider::registerIconOverlayForSuffix(
- creatorTheme()->imageFile(Theme::IconOverlayPro, defaultOverlay).toLatin1().data(), "pro");
+ creatorTheme()->imageFile(Theme::IconOverlayPro, defaultOverlay), "pro");
Core::FileIconProvider::registerIconOverlayForSuffix(
- creatorTheme()->imageFile(Theme::IconOverlayPri, defaultOverlay).toLatin1().data(), "pri");
+ creatorTheme()->imageFile(Theme::IconOverlayPri, defaultOverlay), "pri");
Core::FileIconProvider::registerIconOverlayForSuffix(
- creatorTheme()->imageFile(Theme::IconOverlayPrf, defaultOverlay).toLatin1().data(), "prf");
+ creatorTheme()->imageFile(Theme::IconOverlayPrf, defaultOverlay), "prf");
}
} // namespace Internal
diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
index e25359110e..0881b6313a 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
@@ -95,19 +95,19 @@ struct FileTypeDataStorage {
};
static const FileTypeDataStorage fileTypeDataStorage[] = {
- { HeaderType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Headers"),
+ { FileType::Header, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Headers"),
ProjectExplorer::Constants::FILEOVERLAY_H, "*.h; *.hh; *.hpp; *.hxx;"},
- { SourceType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Sources"),
+ { FileType::Source, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Sources"),
ProjectExplorer::Constants::FILEOVERLAY_CPP, "*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++;" },
- { FormType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Forms"),
+ { FileType::Form, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Forms"),
Constants::FILEOVERLAY_UI, "*.ui;" },
- { StateChartType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "State charts"),
+ { FileType::StateChart, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "State charts"),
ProjectExplorer::Constants::FILEOVERLAY_SCXML, "*.scxml;" },
- { ResourceType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Resources"),
+ { FileType::Resource, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Resources"),
ProjectExplorer::Constants::FILEOVERLAY_QRC, "*.qrc;" },
- { QMLType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "QML"),
+ { FileType::QML, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "QML"),
ProjectExplorer::Constants::FILEOVERLAY_QML, "*.qml;" },
- { UnknownFileType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Other files"),
+ { FileType::Unknown, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Other files"),
ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN, "*;" }
};
@@ -129,7 +129,7 @@ class QmakeNodeStaticData {
public:
class FileTypeData {
public:
- FileTypeData(FileType t = UnknownFileType,
+ FileTypeData(FileType t = FileType::Unknown,
const QString &tN = QString(),
const QString &aff = QString(),
const QIcon &i = QIcon()) :
@@ -321,8 +321,8 @@ struct InternalNode
QList<InternalNode *> virtualfolders;
QMap<QString, InternalNode *> subnodes;
FileNameList files;
- FileType type = UnknownFileType;
- int priority = 0;
+ FileType type = FileType::Unknown;
+ int priority = Node::DefaultVirtualFolderPriority;
QString displayName;
QString typeName;
QString addFileFilter;
@@ -426,7 +426,7 @@ struct InternalNode
newNode = new FolderNode(FileName::fromString(node->fullPath));
} else {
auto n = new ProVirtualFolderNode(FileName::fromString(node->fullPath),
- node->priority, node->typeName);
+ node->priority, node->typeName);
n->setAddFileFilter(node->addFileFilter);
newNode = n;
}
@@ -440,15 +440,15 @@ struct InternalNode
// Makes the projectNode's subtree below the given folder match this internal node's subtree
void updateSubFolders(FolderNode *folder)
{
- if (type == ResourceType)
+ if (type == FileType::Resource)
updateResourceFiles(folder);
else
updateFiles(folder, type);
// updateFolders
QMultiMap<QString, FolderNode *> existingFolderNodes;
- foreach (FolderNode *node, folder->subFolderNodes())
- if (node->nodeType() != ProjectNodeType && !dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(node))
+ foreach (FolderNode *node, folder->folderNodes())
+ if (node->nodeType() != NodeType::Project && !dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(node))
existingFolderNodes.insert(node->filePath().toString(), node);
QList<FolderNode *> foldersToRemove;
@@ -466,7 +466,7 @@ struct InternalNode
QMultiMap<QString, FolderNode *>::const_iterator oldit
= existingFolderNodes.constFind(path);
while (oldit != existingFolderNodes.constEnd() && oldit.key() == path) {
- if (oldit.value()->nodeType() == VirtualFolderNodeType) {
+ if (oldit.value()->nodeType() == NodeType::VirtualFolder) {
VirtualFolderNode *vfn = dynamic_cast<VirtualFolderNode *>(oldit.value());
if (vfn->priority() == (*it)->priority) {
found = true;
@@ -495,7 +495,7 @@ struct InternalNode
QMultiMap<QString, FolderNode *>::const_iterator oldit
= existingFolderNodes.constFind(path);
while (oldit != existingFolderNodes.constEnd() && oldit.key() == path) {
- if (oldit.value()->nodeType() == FolderNodeType) {
+ if (oldit.value()->nodeType() == NodeType::Folder) {
found = true;
break;
}
@@ -560,7 +560,7 @@ struct InternalNode
void updateResourceFiles(FolderNode *folder)
{
QList<FolderNode *> existingResourceNodes; // for resource special handling
- foreach (FolderNode *folderNode, folder->subFolderNodes()) {
+ foreach (FolderNode *folderNode, folder->folderNodes()) {
if (ResourceEditor::ResourceTopLevelNode *rn = dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
existingResourceNodes << rn;
}
@@ -578,7 +578,7 @@ struct InternalNode
nodesToAdd.reserve(resourcesToAdd.size());
foreach (const FileName &file, resourcesToAdd) {
- auto vfs = static_cast<QmakePriFileNode *>(folder->projectNode())->m_project->qmakeVfs();
+ auto vfs = static_cast<QmakePriFileNode *>(folder->parentProjectNode())->m_project->qmakeVfs();
QString contents;
// Prefer the cumulative file if it's non-empty, based on the assumption
// that it contains more "stuff".
@@ -715,7 +715,7 @@ void QmakePriFileNode::update(const Internal::PriFileEvalResult &result)
{
// add project file node
if (m_fileNodes.isEmpty())
- addFileNodes(QList<FileNode *>() << new FileNode(m_projectFilePath, ProjectFileType, false));
+ addFileNodes(QList<FileNode *>() << new FileNode(m_projectFilePath, FileType::Project, false));
m_recursiveEnumerateFiles = result.recursiveEnumerateFiles;
watchFolders(result.folders.toSet());
@@ -739,7 +739,7 @@ void QmakePriFileNode::update(const Internal::PriFileEvalResult &result)
subfolder->fullPath = m_projectDir;
subfolder->typeName = fileTypes.at(i).typeName;
subfolder->addFileFilter = fileTypes.at(i).addFileFilter;
- subfolder->priority = -i;
+ subfolder->priority = Node::DefaultVirtualFolderPriority - i;
subfolder->displayName = fileTypes.at(i).typeName;
contents.virtualfolders.append(subfolder);
// create the hierarchy with subdirectories
@@ -816,7 +816,7 @@ bool QmakePriFileNode::folderChanged(const QString &changedFolder, const QSet<Fi
subfolder->icon = fileTypes.at(i).icon;
subfolder->fullPath = m_projectDir;
subfolder->typeName = fileTypes.at(i).typeName;
- subfolder->priority = -i;
+ subfolder->priority = Node::DefaultVirtualFolderPriority - i;
subfolder->displayName = fileTypes.at(i).typeName;
contents.virtualfolders.append(subfolder);
// create the hierarchy with subdirectories
@@ -855,7 +855,7 @@ QList<RunConfiguration *> QmakePriFileNode::runConfigurations() const
QList<QmakePriFileNode *> QmakePriFileNode::subProjectNodesExact() const
{
QList<QmakePriFileNode *> nodes;
- foreach (ProjectNode *node, subProjectNodes()) {
+ foreach (ProjectNode *node, projectNodes()) {
QmakePriFileNode *n = dynamic_cast<QmakePriFileNode *>(node);
if (n && n->includedInExactParse())
nodes << n;
@@ -904,12 +904,12 @@ QList<ProjectAction> QmakePriFileNode::supportedActions(Node *node) const
actions << RemoveFile;
bool addExistingFiles = true;
- if (node->nodeType() == VirtualFolderNodeType) {
+ if (node->nodeType() == NodeType::VirtualFolder) {
// A virtual folder, we do what the projectexplorer does
FolderNode *folder = node->asFolderNode();
if (folder) {
QStringList list;
- foreach (FolderNode *f, folder->subFolderNodes())
+ foreach (FolderNode *f, folder->folderNodes())
list << f->filePath().toString() + QLatin1Char('/');
if (deploysFolder(Utils::commonPath(list)))
addExistingFiles = false;
@@ -931,7 +931,7 @@ QList<ProjectAction> QmakePriFileNode::supportedActions(Node *node) const
}
FileNode *fileNode = node->asFileNode();
- if ((fileNode && fileNode->fileType() != ProjectFileType)
+ if ((fileNode && fileNode->fileType() != FileType::Project)
|| dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(node)) {
actions << Rename;
actions << DuplicateFile;
@@ -1110,7 +1110,7 @@ bool QmakePriFileNode::renameFile(const QString &filePath, const QString &newFil
FolderNode::AddNewInformation QmakePriFileNode::addNewInformation(const QStringList &files, Node *context) const
{
Q_UNUSED(files)
- return FolderNode::AddNewInformation(filePath().fileName(), context && context->projectNode() == this ? 120 : 90);
+ return FolderNode::AddNewInformation(filePath().fileName(), context && context->parentProjectNode() == this ? 120 : 90);
}
bool QmakePriFileNode::priFileWritable(const QString &path)
@@ -1345,11 +1345,11 @@ QStringList QmakePriFileNode::varNames(FileType type, QtSupport::ProFileReader *
{
QStringList vars;
switch (type) {
- case HeaderType:
+ case FileType::Header:
vars << QLatin1String("HEADERS");
vars << QLatin1String("PRECOMPILED_HEADER");
break;
- case SourceType: {
+ case FileType::Source: {
vars << QLatin1String("SOURCES");
QStringList listOfExtraCompilers = readerExact->values(QLatin1String("QMAKE_EXTRA_COMPILERS"));
foreach (const QString &var, listOfExtraCompilers) {
@@ -1365,19 +1365,19 @@ QStringList QmakePriFileNode::varNames(FileType type, QtSupport::ProFileReader *
}
break;
}
- case ResourceType:
+ case FileType::Resource:
vars << QLatin1String("RESOURCES");
break;
- case FormType:
+ case FileType::Form:
vars << QLatin1String("FORMS");
break;
- case StateChartType:
+ case FileType::StateChart:
vars << QLatin1String("STATECHARTS");
break;
- case ProjectFileType:
+ case FileType::Project:
vars << QLatin1String("SUBDIRS");
break;
- case QMLType:
+ case FileType::QML:
vars << QLatin1String("OTHER_FILES");
vars << QLatin1String("DISTFILES");
break;
@@ -1454,10 +1454,10 @@ QStringList QmakePriFileNode::varNamesForRemoving()
QSet<FileName> QmakePriFileNode::filterFilesProVariables(FileType fileType, const QSet<FileName> &files)
{
- if (fileType != QMLType && fileType != UnknownFileType)
+ if (fileType != FileType::QML && fileType != FileType::Unknown)
return files;
QSet<FileName> result;
- if (fileType == QMLType) {
+ if (fileType == FileType::QML) {
foreach (const FileName &file, files)
if (file.toString().endsWith(QLatin1String(".qml")))
result << file;
@@ -1472,9 +1472,9 @@ QSet<FileName> QmakePriFileNode::filterFilesProVariables(FileType fileType, cons
QSet<FileName> QmakePriFileNode::filterFilesRecursiveEnumerata(FileType fileType, const QSet<FileName> &files)
{
QSet<FileName> result;
- if (fileType != QMLType && fileType != UnknownFileType)
+ if (fileType != FileType::QML && fileType != FileType::Unknown)
return result;
- if (fileType == QMLType) {
+ if (fileType == FileType::QML) {
foreach (const FileName &file, files)
if (file.toString().endsWith(QLatin1String(".qml")))
result << file;
@@ -1541,7 +1541,7 @@ QmakeProFileNode *QmakeProFileNode::findProFileFor(const FileName &fileName) con
{
if (fileName == filePath())
return const_cast<QmakeProFileNode *>(this);
- foreach (ProjectNode *pn, subProjectNodes())
+ foreach (ProjectNode *pn, projectNodes())
if (QmakeProFileNode *qmakeProFileNode = dynamic_cast<QmakeProFileNode *>(pn))
if (QmakeProFileNode *result = qmakeProFileNode->findProFileFor(fileName))
return result;
@@ -1635,7 +1635,7 @@ bool QmakeProFileNode::showInSimpleTree() const
FolderNode::AddNewInformation QmakeProFileNode::addNewInformation(const QStringList &files, Node *context) const
{
Q_UNUSED(files)
- return AddNewInformation(filePath().fileName(), context && context->projectNode() == this ? 120 : 100);
+ return AddNewInformation(filePath().fileName(), context && context->parentProjectNode() == this ? 120 : 100);
}
bool QmakeProFileNode::showInSimpleTree(QmakeProjectType projectType) const
@@ -1674,7 +1674,7 @@ QString QmakeProFileNode::singleVariableValue(const QmakeVariable var) const
void QmakeProFileNode::setParseInProgressRecursive(bool b)
{
setParseInProgress(b);
- foreach (ProjectNode *subNode, subProjectNodes()) {
+ foreach (ProjectNode *subNode, projectNodes()) {
if (QmakeProFileNode *node = dynamic_cast<QmakeProFileNode *>(subNode))
node->setParseInProgressRecursive(b);
}
@@ -1691,7 +1691,7 @@ void QmakeProFileNode::setParseInProgress(bool b)
void QmakeProFileNode::setValidParseRecursive(bool b)
{
setValidParse(b);
- foreach (ProjectNode *subNode, subProjectNodes()) {
+ foreach (ProjectNode *subNode, projectNodes()) {
if (QmakeProFileNode *node = dynamic_cast<QmakeProFileNode *>(subNode))
node->setValidParseRecursive(b);
}
@@ -2050,8 +2050,8 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
// delete files && folders && projects
removeFileNodes(fileNodes());
- removeProjectNodes(subProjectNodes());
- removeFolderNodes(subFolderNodes());
+ removeProjectNodes(projectNodes());
+ removeFolderNodes(folderNodes());
m_projectType = InvalidProject;
}
@@ -2064,7 +2064,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
if (result->projectType != m_projectType) {
// probably all subfiles/projects have changed anyway
// delete files && folders && projects
- foreach (ProjectNode *projectNode, subProjectNodes()) {
+ foreach (ProjectNode *projectNode, projectNodes()) {
if (QmakeProFileNode *qmakeProFileNode = dynamic_cast<QmakeProFileNode *>(projectNode)) {
qmakeProFileNode->setValidParseRecursive(false);
qmakeProFileNode->setParseInProgressRecursive(false);
@@ -2072,8 +2072,8 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
}
removeFileNodes(fileNodes());
- removeProjectNodes(subProjectNodes());
- removeFolderNodes(subFolderNodes());
+ removeProjectNodes(projectNodes());
+ removeFolderNodes(folderNodes());
bool changesShowInSimpleTree = showInSimpleTree() ^ showInSimpleTree(result->projectType);
@@ -2102,7 +2102,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
IncludedPriFile *tree = toCompare.first().second;
toCompare.pop_front();
- QList<ProjectNode*> existingProjectNodes = pn->subProjectNodes();
+ QList<ProjectNode*> existingProjectNodes = pn->projectNodes();
Utils::sort(existingProjectNodes, sortByPath);
// result is already sorted
@@ -2451,7 +2451,7 @@ QStringList QmakeProFileNode::generatedFiles(const QString &buildDir,
// ui_*.h files into a special directory, or even change the .h suffix, we
// cannot help doing this here.
switch (sourceFile->fileType()) {
- case FormType: {
+ case FileType::Form: {
FileName location;
auto it = m_varValues.constFind(UiDirVar);
if (it != m_varValues.constEnd() && !it.value().isEmpty())
@@ -2465,7 +2465,7 @@ QStringList QmakeProFileNode::generatedFiles(const QString &buildDir,
+ singleVariableValue(HeaderExtensionVar));
return QStringList(QDir::cleanPath(location.toString()));
}
- case StateChartType: {
+ case FileType::StateChart: {
if (buildDir.isEmpty())
return QStringList();
QString location = QDir::cleanPath(FileName::fromString(buildDir).appendPath(
diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
index 8be3ff5c5a..1f5a79d8dc 100644
--- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp
@@ -117,14 +117,14 @@ public:
void clear();
bool equals(const QmakeProjectFiles &f) const;
- QStringList files[FileTypeSize];
- QStringList generatedFiles[FileTypeSize];
+ QStringList files[static_cast<int>(FileType::FileTypeSize)];
+ QStringList generatedFiles[static_cast<int>(FileType::FileTypeSize)];
QStringList proFiles;
};
void QmakeProjectFiles::clear()
{
- for (int i = 0; i < FileTypeSize; ++i) {
+ for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
files[i].clear();
generatedFiles[i].clear();
}
@@ -133,7 +133,7 @@ void QmakeProjectFiles::clear()
bool QmakeProjectFiles::equals(const QmakeProjectFiles &f) const
{
- for (int i = 0; i < FileTypeSize; ++i)
+ for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i)
if (files[i] != f.files[i] || generatedFiles[i] != f.generatedFiles[i])
return false;
if (proFiles != f.proFiles)
@@ -151,7 +151,7 @@ QDebug operator<<(QDebug d, const QmakeProjectFiles &f)
{
QDebug nsp = d.nospace();
nsp << "QmakeProjectFiles: proFiles=" << f.proFiles << '\n';
- for (int i = 0; i < FileTypeSize; ++i)
+ for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i)
nsp << "Type " << i << " files=" << f.files[i] << " generated=" << f.generatedFiles[i] << '\n';
return d;
}
@@ -190,7 +190,7 @@ void ProjectFilesVisitor::findProjectFiles(QmakeProFileNode *rootNode, QmakeProj
files->clear();
ProjectFilesVisitor visitor(files);
rootNode->accept(&visitor);
- for (int i = 0; i < FileTypeSize; ++i) {
+ for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
Utils::sort(files->files[i]);
unique(files->files[i]);
Utils::sort(files->generatedFiles[i]);
@@ -209,10 +209,10 @@ void ProjectFilesVisitor::visitProjectNode(ProjectNode *projectNode)
void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
{
if (dynamic_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
- m_files->files[ResourceType].push_back(folderNode->filePath().toString());
+ m_files->files[static_cast<int>(FileType::Resource)].push_back(folderNode->filePath().toString());
foreach (FileNode *fileNode, folderNode->fileNodes()) {
- const int type = fileNode->fileType();
+ const int type = static_cast<int>(fileNode->fileType());
QStringList &targetList = fileNode->isGenerated() ? m_files->generatedFiles[type] : m_files->files[type];
targetList.push_back(fileNode->filePath().toString());
}
@@ -806,7 +806,7 @@ QString QmakeProject::displayName() const
QStringList QmakeProject::files(FilesMode fileMode) const
{
QStringList files;
- for (int i = 0; i < FileTypeSize; ++i) {
+ for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
if (fileMode & SourceFiles)
files += m_projectFiles->files[i];
if (fileMode & GeneratedFiles)
@@ -824,7 +824,7 @@ static FolderNode *folderOf(FolderNode *in, const FileName &fileName)
foreach (FileNode *fn, in->fileNodes())
if (fn->filePath() == fileName)
return in;
- foreach (FolderNode *folder, in->subFolderNodes())
+ foreach (FolderNode *folder, in->folderNodes())
if (FolderNode *pn = folderOf(folder, fileName))
return pn;
return 0;
@@ -986,7 +986,7 @@ void QmakeProject::collectAllProFiles(QList<QmakeProFileNode *> &list, QmakeProF
if (parse == ExactAndCumulativeParse || node->includedInExactParse())
if (projectTypes.isEmpty() || projectTypes.contains(node->projectType()))
list.append(node);
- foreach (ProjectNode *n, node->subProjectNodes()) {
+ foreach (ProjectNode *n, node->projectNodes()) {
QmakeProFileNode *qmakeProFileNode = dynamic_cast<QmakeProFileNode *>(n);
if (qmakeProFileNode)
collectAllProFiles(list, qmakeProFileNode, parse, projectTypes);
@@ -1070,7 +1070,7 @@ bool QmakeProject::hasSubNode(QmakePriFileNode *root, const FileName &path)
{
if (root->filePath() == path)
return true;
- foreach (FolderNode *fn, root->subFolderNodes()) {
+ foreach (FolderNode *fn, root->folderNodes()) {
if (dynamic_cast<QmakeProFileNode *>(fn)) {
// we aren't interested in pro file nodes
} else if (QmakePriFileNode *qt4prifilenode = dynamic_cast<QmakePriFileNode *>(fn)) {
@@ -1086,7 +1086,7 @@ void QmakeProject::findProFile(const FileName &fileName, QmakeProFileNode *root,
if (hasSubNode(root, fileName))
list.append(root);
- foreach (FolderNode *fn, root->subFolderNodes())
+ foreach (FolderNode *fn, root->folderNodes())
if (QmakeProFileNode *qt4proFileNode = dynamic_cast<QmakeProFileNode *>(fn))
findProFile(fileName, qt4proFileNode, list);
}
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp
index 2bdf16f76c..aa9f96d423 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp
@@ -221,7 +221,7 @@ void QmakeManager::buildFile()
Project *project = SessionManager::projectForFile(file);
if (project && node)
- handleSubDirContextMenu(BUILD, true, project, node->projectNode(), node);
+ handleSubDirContextMenu(BUILD, true, project, node->parentProjectNode(), node);
}
}
diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
index a1d269a188..30ba229d27 100644
--- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp
@@ -323,12 +323,12 @@ void QmakeProjectManagerPlugin::updateContextActions(ProjectExplorer::Node *node
auto qmakeProject = qobject_cast<QmakeProject *>(project);
QmakeProFileNode *subProjectNode = nullptr;
if (node) {
- if (auto subPriFileNode = dynamic_cast<QmakePriFileNode *>(node->projectNode()))
+ if (auto subPriFileNode = dynamic_cast<QmakePriFileNode *>(node->parentProjectNode()))
subProjectNode = subPriFileNode->proFileNode();
}
ProjectExplorer::FileNode *fileNode = node ? node->asFileNode() : nullptr;
bool buildFilePossible = subProjectNode && fileNode
- && (fileNode->fileType() == ProjectExplorer::SourceType);
+ && (fileNode->fileType() == ProjectExplorer::FileType::Source);
m_qmakeProjectManager->setContextNode(subProjectNode);
m_qmakeProjectManager->setContextProject(qmakeProject);
@@ -397,7 +397,7 @@ void QmakeProjectManagerPlugin::updateBuildFileAction()
m_buildFileAction->setParameter(file.fileName());
visible = qobject_cast<QmakeProject *>(project)
&& node
- && dynamic_cast<QmakePriFileNode *>(node->projectNode());
+ && dynamic_cast<QmakePriFileNode *>(node->parentProjectNode());
enabled = !BuildManager::isBuilding(project);
}
diff --git a/src/plugins/qmldesigner/components/integration/componentaction.cpp b/src/plugins/qmldesigner/components/integration/componentaction.cpp
index 01497f8c1c..d04f84da5f 100644
--- a/src/plugins/qmldesigner/components/integration/componentaction.cpp
+++ b/src/plugins/qmldesigner/components/integration/componentaction.cpp
@@ -46,7 +46,7 @@ void ComponentAction::setCurrentIndex(int index)
dontEmitCurrentComponentChanged = false;
}
-QWidget *ComponentAction::createWidget(QWidget *parent)
+QWidget *ComponentAction::createWidget(QWidget *parent)
{
QComboBox *comboBox = new QComboBox(parent);
comboBox->setMinimumWidth(120);
diff --git a/src/plugins/qmldesigner/components/integration/componentaction.h b/src/plugins/qmldesigner/components/integration/componentaction.h
index 4d697cc7f4..f6cc02b303 100644
--- a/src/plugins/qmldesigner/components/integration/componentaction.h
+++ b/src/plugins/qmldesigner/components/integration/componentaction.h
@@ -47,7 +47,7 @@ public:
protected:
- QWidget *createWidget(QWidget *parent);
+ QWidget *createWidget(QWidget *parent);
signals:
void currentComponentChanged(const ModelNode &node);
diff --git a/src/plugins/qmldesigner/components/integration/componentview.cpp b/src/plugins/qmldesigner/components/integration/componentview.cpp
index 77d2bf78a8..f341c1e31e 100644
--- a/src/plugins/qmldesigner/components/integration/componentview.cpp
+++ b/src/plugins/qmldesigner/components/integration/componentview.cpp
@@ -83,7 +83,6 @@ void ComponentView::removeSingleNodeFromList(const ModelNode &node)
}
}
-
int ComponentView::indexForNode(const ModelNode &node) const
{
for (int row = 0; row < m_standardItemModel->rowCount(); row++) {
diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp
index d1aecf0ee1..1caa8c433d 100644
--- a/src/plugins/qmldesigner/documentmanager.cpp
+++ b/src/plugins/qmldesigner/documentmanager.cpp
@@ -381,23 +381,25 @@ void DocumentManager::findPathToIsoProFile(bool *iconResourceFileAlreadyExists,
ProjectExplorer::Node *iconQrcFileNode = nullptr;
while (node && !iconQrcFileNode) {
- qCDebug(documentManagerLog) << "Checking" << node->displayName() << "(" << node << node->nodeType() << ")";
+ qCDebug(documentManagerLog) << "Checking" << node->displayName()
+ << "(" << node << static_cast<int>(node->nodeType()) << ")";
- if (node->nodeType() == ProjectExplorer::VirtualFolderNodeType && node->displayName() == "Resources") {
+ if (node->nodeType() == ProjectExplorer::NodeType::VirtualFolder && node->displayName() == "Resources") {
ProjectExplorer::VirtualFolderNode *virtualFolderNode = dynamic_cast<ProjectExplorer::VirtualFolderNode*>(node);
- for (int subFolderIndex = 0; subFolderIndex < virtualFolderNode->subFolderNodes().size() && !iconQrcFileNode; ++subFolderIndex) {
- ProjectExplorer::FolderNode *subFolderNode = virtualFolderNode->subFolderNodes().at(subFolderIndex);
+ for (int subFolderIndex = 0; subFolderIndex < virtualFolderNode->folderNodes().size() && !iconQrcFileNode; ++subFolderIndex) {
+ ProjectExplorer::FolderNode *subFolderNode = virtualFolderNode->folderNodes().at(subFolderIndex);
qCDebug(documentManagerLog) << "Checking if" << subFolderNode->displayName() << "("
- << subFolderNode << subFolderNode->nodeType() << ") is" << isoIconsQrcFile;
+ << subFolderNode << static_cast<int>(subFolderNode->nodeType())
+ << ") is" << isoIconsQrcFile;
- if (subFolderNode->nodeType() == ProjectExplorer::FolderNodeType
+ if (subFolderNode->nodeType() == ProjectExplorer::NodeType::Folder
&& subFolderNode->displayName() == isoIconsQrcFile) {
qCDebug(documentManagerLog) << "Found" << isoIconsQrcFile << "in" << virtualFolderNode->filePath();
iconQrcFileNode = subFolderNode;
- *resourceFileProPath = iconQrcFileNode->projectNode()->filePath().toString();
+ *resourceFileProPath = iconQrcFileNode->parentProjectNode()->filePath().toString();
}
}
}
@@ -414,7 +416,7 @@ void DocumentManager::findPathToIsoProFile(bool *iconResourceFileAlreadyExists,
*resourceFilePath = project->projectDirectory().toString() + "/" + isoIconsQrcFile;
// We assume that the .pro containing the QML file is an acceptable place to add the .qrc file.
- ProjectExplorer::ProjectNode *projectNode = ProjectExplorer::SessionManager::nodeForFile(qmlFileName)->projectNode();
+ ProjectExplorer::ProjectNode *projectNode = ProjectExplorer::SessionManager::nodeForFile(qmlFileName)->parentProjectNode();
*resourceFileProPath = projectNode->filePath().toString();
} else {
// We found the QRC file that we want.
diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp
new file mode 100644
index 0000000000..1e772df1b3
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "qmljseditingsettingspage.h"
+#include "qmljseditorconstants.h"
+
+#include <qmljstools/qmljstoolsconstants.h>
+#include <coreplugin/icore.h>
+
+#include <QSettings>
+#include <QTextStream>
+#include <QCheckBox>
+
+
+using namespace QmlJSEditor;
+using namespace QmlJSEditor::Internal;
+
+QmlJsEditingSettings::QmlJsEditingSettings()
+ : m_enableContextPane(false),
+ m_pinContextPane(false),
+ m_autoFormatOnSave(false),
+ m_autoFormatOnlyCurrentProject(false)
+{}
+
+void QmlJsEditingSettings::set()
+{
+ if (get() != *this)
+ toSettings(Core::ICore::settings());
+}
+
+void QmlJsEditingSettings::fromSettings(QSettings *settings)
+{
+ settings->beginGroup(QLatin1String(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML));
+ m_enableContextPane = settings->value(
+ QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANE_KEY),
+ QVariant(false)).toBool();
+ m_pinContextPane = settings->value(
+ QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANEPIN_KEY),
+ QVariant(false)).toBool();
+ m_autoFormatOnSave = settings->value(
+ QLatin1String(QmlJSEditor::Constants::AUTO_FORMAT_ON_SAVE),
+ QVariant(false)).toBool();
+ m_autoFormatOnlyCurrentProject = settings->value(
+ QLatin1String(QmlJSEditor::Constants::AUTO_FORMAT_ONLY_CURRENT_PROJECT),
+ QVariant(false)).toBool();
+ settings->endGroup();
+}
+
+void QmlJsEditingSettings::toSettings(QSettings *settings) const
+{
+ settings->beginGroup(QLatin1String(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML));
+ settings->setValue(QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANE_KEY),
+ m_enableContextPane);
+ settings->setValue(QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANEPIN_KEY),
+ m_pinContextPane);
+ settings->setValue(QLatin1String(QmlJSEditor::Constants::AUTO_FORMAT_ON_SAVE),
+ m_autoFormatOnSave);
+ settings->setValue(QLatin1String(QmlJSEditor::Constants::AUTO_FORMAT_ONLY_CURRENT_PROJECT),
+ m_autoFormatOnlyCurrentProject);
+ settings->endGroup();
+}
+
+bool QmlJsEditingSettings::equals(const QmlJsEditingSettings &other) const
+{
+ return m_enableContextPane == other.m_enableContextPane
+ && m_pinContextPane == other.m_pinContextPane
+ && m_autoFormatOnSave == other.m_autoFormatOnSave
+ && m_autoFormatOnlyCurrentProject == other.m_autoFormatOnlyCurrentProject;
+}
+
+bool QmlJsEditingSettings::enableContextPane() const
+{
+ return m_enableContextPane;
+}
+
+void QmlJsEditingSettings::setEnableContextPane(const bool enableContextPane)
+{
+ m_enableContextPane = enableContextPane;
+}
+
+bool QmlJsEditingSettings::pinContextPane() const
+{
+ return m_pinContextPane;
+}
+
+void QmlJsEditingSettings::setPinContextPane(const bool pinContextPane)
+{
+ m_pinContextPane = pinContextPane;
+}
+
+bool QmlJsEditingSettings::autoFormatOnSave() const
+{
+ return m_autoFormatOnSave;
+}
+
+void QmlJsEditingSettings::setAutoFormatOnSave(const bool autoFormatOnSave)
+{
+ m_autoFormatOnSave = autoFormatOnSave;
+}
+
+bool QmlJsEditingSettings::autoFormatOnlyCurrentProject() const
+{
+ return m_autoFormatOnlyCurrentProject;
+}
+
+void QmlJsEditingSettings::setAutoFormatOnlyCurrentProject(const bool autoFormatOnlyCurrentProject)
+{
+ m_autoFormatOnlyCurrentProject = autoFormatOnlyCurrentProject;
+}
+
+QmlJsEditingSettignsPageWidget::QmlJsEditingSettignsPageWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ m_ui.setupUi(this);
+}
+
+QmlJsEditingSettings QmlJsEditingSettignsPageWidget::settings() const
+{
+ QmlJsEditingSettings s;
+ s.setEnableContextPane(m_ui.textEditHelperCheckBox->isChecked());
+ s.setPinContextPane(m_ui.textEditHelperCheckBoxPin->isChecked());
+ s.setAutoFormatOnSave(m_ui.autoFormatOnSave->isChecked());
+ s.setAutoFormatOnlyCurrentProject(m_ui.autoFormatOnlyCurrentProject->isChecked());
+ return s;
+}
+
+void QmlJsEditingSettignsPageWidget::setSettings(const QmlJsEditingSettings &s)
+{
+ m_ui.textEditHelperCheckBox->setChecked(s.enableContextPane());
+ m_ui.textEditHelperCheckBoxPin->setChecked(s.pinContextPane());
+ m_ui.autoFormatOnSave->setChecked(s.autoFormatOnSave());
+ m_ui.autoFormatOnlyCurrentProject->setChecked(s.autoFormatOnlyCurrentProject());
+}
+
+QmlJsEditingSettings QmlJsEditingSettings::get()
+{
+ QmlJsEditingSettings settings;
+ settings.fromSettings(Core::ICore::settings());
+ return settings;
+}
+
+QmlJsEditingSettingsPage::QmlJsEditingSettingsPage() :
+ m_widget(0)
+{
+ setId("C.QmlJsEditing");
+ setDisplayName(tr("QML/JS Editing"));
+ setCategory(Constants::SETTINGS_CATEGORY_QML);
+ setDisplayCategory(QCoreApplication::translate("QmlJSEditor",
+ QmlJSEditor::Constants::SETTINGS_TR_CATEGORY_QML));
+ setCategoryIcon(Utils::Icon(QmlJSTools::Constants::SETTINGS_CATEGORY_QML_ICON));
+}
+
+QWidget *QmlJsEditingSettingsPage::widget()
+{
+ if (!m_widget) {
+ m_widget = new QmlJsEditingSettignsPageWidget;
+ m_widget->setSettings(QmlJsEditingSettings::get());
+ }
+ return m_widget;
+}
+
+void QmlJsEditingSettingsPage::apply()
+{
+ if (!m_widget) // page was never shown
+ return;
+ m_widget->settings().set();
+}
+
+void QmlJsEditingSettingsPage::finish()
+{
+ delete m_widget;
+}
diff --git a/src/plugins/qmljseditor/quicktoolbarsettingspage.h b/src/plugins/qmljseditor/qmljseditingsettingspage.h
index db0c5ee99b..85687d6871 100644
--- a/src/plugins/qmljseditor/quicktoolbarsettingspage.h
+++ b/src/plugins/qmljseditor/qmljseditingsettingspage.h
@@ -25,7 +25,7 @@
#pragma once
-#include "ui_quicktoolbarsettingspage.h"
+#include "ui_qmljseditingsettingspage.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
#include <QWidget>
@@ -36,61 +36,77 @@ QT_END_NAMESPACE
namespace QmlJSEditor {
- class QuickToolBarSettings {
+ class QmlJsEditingSettings {
public:
- QuickToolBarSettings();
+ QmlJsEditingSettings();
- static QuickToolBarSettings get();
+ static QmlJsEditingSettings get();
void set();
void fromSettings(QSettings *);
void toSettings(QSettings *) const;
- bool equals(const QuickToolBarSettings &other) const;
- bool enableContextPane;
- bool pinContextPane;
+ bool equals(const QmlJsEditingSettings &other) const;
+
+ bool enableContextPane() const;
+ void setEnableContextPane(const bool enableContextPane);
+
+ bool pinContextPane() const;
+ void setPinContextPane(const bool pinContextPane);
+
+ bool autoFormatOnSave() const;
+ void setAutoFormatOnSave(const bool autoFormatOnSave);
+
+ bool autoFormatOnlyCurrentProject() const;
+ void setAutoFormatOnlyCurrentProject(const bool autoFormatOnlyCurrentProject);
+
+ private:
+ bool m_enableContextPane;
+ bool m_pinContextPane;
+ bool m_autoFormatOnSave;
+ bool m_autoFormatOnlyCurrentProject;
};
- inline bool operator==(const QuickToolBarSettings &s1, const QuickToolBarSettings &s2)
+ inline bool operator==(const QmlJsEditingSettings &s1, const QmlJsEditingSettings &s2)
{ return s1.equals(s2); }
- inline bool operator!=(const QuickToolBarSettings &s1, const QuickToolBarSettings &s2)
+ inline bool operator!=(const QmlJsEditingSettings &s1, const QmlJsEditingSettings &s2)
{ return !s1.equals(s2); }
-class QuickToolBarSettings;
+class QmlJsEditingSettings;
namespace Internal {
-class QuickToolBarSettingsPageWidget : public QWidget
+class QmlJsEditingSettignsPageWidget : public QWidget
{
Q_OBJECT
public:
- explicit QuickToolBarSettingsPageWidget(QWidget *parent = 0);
+ explicit QmlJsEditingSettignsPageWidget(QWidget *parent = 0);
- QuickToolBarSettings settings() const;
- void setSettings(const QuickToolBarSettings &);
+ QmlJsEditingSettings settings() const;
+ void setSettings(const QmlJsEditingSettings &);
- static QuickToolBarSettings get();
+ static QmlJsEditingSettings get();
private:
- Ui::QuickToolBarSettingsPage m_ui;
+ Ui::QmlJsEditingSettingsPage m_ui;
};
-class QuickToolBarSettingsPage : public Core::IOptionsPage
+class QmlJsEditingSettingsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
- QuickToolBarSettingsPage();
+ QmlJsEditingSettingsPage();
QWidget *widget();
void apply();
void finish();
private:
- QPointer<QuickToolBarSettingsPageWidget> m_widget;
+ QPointer<QmlJsEditingSettignsPageWidget> m_widget;
};
} // namespace Internal
diff --git a/src/plugins/qmljseditor/quicktoolbarsettingspage.ui b/src/plugins/qmljseditor/qmljseditingsettingspage.ui
index fddcffef6b..c0c4c2d6b0 100644
--- a/src/plugins/qmljseditor/quicktoolbarsettingspage.ui
+++ b/src/plugins/qmljseditor/qmljseditingsettingspage.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>QmlJSEditor::Internal::QuickToolBarSettingsPage</class>
- <widget class="QWidget" name="QmlJSEditor::Internal::QuickToolBarSettingsPage">
+ <class>QmlJSEditor::Internal::QmlJsEditingSettingsPage</class>
+ <widget class="QWidget" name="QmlJSEditor::Internal::QmlJsEditingSettingsPage">
<property name="geometry">
<rect>
<x>0</x>
@@ -14,8 +14,8 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QGroupBox" name="groupBox">
+ <item row="1" column="0">
+ <widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Qt Quick Toolbars</string>
</property>
@@ -40,7 +40,7 @@
</layout>
</widget>
</item>
- <item row="1" column="0">
+ <item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -48,13 +48,56 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
- <height>207</height>
+ <height>40</height>
</size>
</property>
</spacer>
</item>
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Automatic Formatting on File Save</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="autoFormatOnSave">
+ <property name="text">
+ <string>Enable auto format on file save</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="autoFormatOnlyCurrentProject">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Restrict to files contained in the current project</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
</widget>
<resources/>
- <connections/>
+ <connections>
+ <connection>
+ <sender>autoFormatOnSave</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>autoFormatOnlyCurrentProject</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>216</x>
+ <y>40</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>216</x>
+ <y>63</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
</ui>
diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro
index f5a0e42e92..978bc4cfe6 100644
--- a/src/plugins/qmljseditor/qmljseditor.pro
+++ b/src/plugins/qmljseditor/qmljseditor.pro
@@ -17,7 +17,7 @@ HEADERS += \
qmloutlinemodel.h \
qmltaskmanager.h \
qmljsoutlinetreeview.h \
- quicktoolbarsettingspage.h \
+ qmljseditingsettingspage.h \
quicktoolbar.h \
qmljscomponentnamedialog.h \
qmljsfindreferences.h \
@@ -46,7 +46,7 @@ SOURCES += \
qmltaskmanager.cpp \
qmljsquickfixes.cpp \
qmljsoutlinetreeview.cpp \
- quicktoolbarsettingspage.cpp \
+ qmljseditingsettingspage.cpp \
quicktoolbar.cpp \
qmljscomponentnamedialog.cpp \
qmljsfindreferences.cpp \
@@ -62,5 +62,5 @@ SOURCES += \
qmljseditordocument.cpp
FORMS += \
- quicktoolbarsettingspage.ui \
+ qmljseditingsettingspage.ui \
qmljscomponentnamedialog.ui
diff --git a/src/plugins/qmljseditor/qmljseditor.qbs b/src/plugins/qmljseditor/qmljseditor.qbs
index 0cba20a7a6..940f414c9b 100644
--- a/src/plugins/qmljseditor/qmljseditor.qbs
+++ b/src/plugins/qmljseditor/qmljseditor.qbs
@@ -26,6 +26,9 @@ QtcPlugin {
"qmljscomponentnamedialog.cpp",
"qmljscomponentnamedialog.h",
"qmljscomponentnamedialog.ui",
+ "qmljseditingsettingspage.cpp",
+ "qmljseditingsettingspage.h",
+ "qmljseditingsettingspage.ui",
"qmljseditor.cpp",
"qmljseditor.h",
"qmljseditor_global.h",
@@ -68,9 +71,6 @@ QtcPlugin {
"qmltaskmanager.h",
"quicktoolbar.cpp",
"quicktoolbar.h",
- "quicktoolbarsettingspage.cpp",
- "quicktoolbarsettingspage.h",
- "quicktoolbarsettingspage.ui",
]
Export {
diff --git a/src/plugins/qmljseditor/qmljseditorconstants.h b/src/plugins/qmljseditor/qmljseditorconstants.h
index 3f22b6e1ef..bfebc16d47 100644
--- a/src/plugins/qmljseditor/qmljseditorconstants.h
+++ b/src/plugins/qmljseditor/qmljseditorconstants.h
@@ -57,5 +57,8 @@ const char QML_CONTEXTPANEPIN_KEY[] = "QmlJSEditor.ContextPanePinned";
const char QML_UI_FILE_WARNING[] = "QmlJSEditor.QmlUiFileWarning";
+const char AUTO_FORMAT_ON_SAVE[] = "QmlJSEditor.AutoFormatOnSave";
+const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "QmlJSEditor.AutoFormatOnlyCurrentProject";
+
} // namespace Constants
} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp
index 6bd676e7b8..9a427a1b08 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.cpp
+++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp
@@ -23,18 +23,18 @@
**
****************************************************************************/
-#include "qmljseditorplugin.h"
-#include "qmljshighlighter.h"
+#include "qmljseditingsettingspage.h"
#include "qmljseditor.h"
#include "qmljseditorconstants.h"
#include "qmljseditordocument.h"
+#include "qmljseditorplugin.h"
+#include "qmljshighlighter.h"
#include "qmljsoutline.h"
#include "qmljspreviewrunner.h"
+#include "qmljsquickfixassist.h"
#include "qmljssnippetprovider.h"
#include "qmltaskmanager.h"
#include "quicktoolbar.h"
-#include "quicktoolbarsettingspage.h"
-#include "qmljsquickfixassist.h"
#include <qmljs/qmljsicons.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -50,6 +50,8 @@
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/taskhub.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projecttree.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <texteditor/texteditorconstants.h>
#include <utils/qtcassert.h>
@@ -193,11 +195,14 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e
addAutoReleasedObject(new QmlJSOutlineWidgetFactory);
addAutoReleasedObject(new QuickToolBar);
- addAutoReleasedObject(new QuickToolBarSettingsPage);
+ addAutoReleasedObject(new QmlJsEditingSettingsPage);
connect(EditorManager::instance(), &EditorManager::currentEditorChanged,
this, &QmlJSEditorPlugin::currentEditorChanged);
+ connect(EditorManager::instance(), &Core::EditorManager::aboutToSave,
+ this, &QmlJSEditorPlugin::autoFormatOnSave);
+
return true;
}
@@ -234,9 +239,25 @@ void QmlJSEditorPlugin::renameUsages()
void QmlJSEditorPlugin::reformatFile()
{
if (m_currentDocument) {
- QTC_ASSERT(!m_currentDocument->isSemanticInfoOutdated(), return);
+ QmlJS::Document::Ptr document = m_currentDocument->semanticInfo().document;
+ QmlJS::Snapshot snapshot = QmlJS::ModelManagerInterface::instance()->snapshot();
+
+ if (m_currentDocument->isSemanticInfoOutdated()) {
+ QmlJS::Document::MutablePtr latestDocument;
- const QString &newText = QmlJS::reformat(m_currentDocument->semanticInfo().document);
+ const QString fileName = m_currentDocument->filePath().toString();
+ latestDocument = snapshot.documentFromSource(QString::fromUtf8(m_currentDocument->contents()),
+ fileName,
+ QmlJS::ModelManagerInterface::guessLanguageOfFile(fileName));
+ latestDocument->parseQml();
+ snapshot.insert(latestDocument);
+ document = latestDocument;
+ }
+
+ if (!document->isParsedCorrectly())
+ return;
+
+ const QString &newText = QmlJS::reformat(document);
QTextCursor tc(m_currentDocument->document());
tc.movePosition(QTextCursor::Start);
tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
@@ -296,4 +317,25 @@ void QmlJSEditorPlugin::checkCurrentEditorSemanticInfoUpToDate()
m_reformatFileAction->setEnabled(semanticInfoUpToDate);
}
+void QmlJSEditorPlugin::autoFormatOnSave(Core::IDocument *document)
+{
+ if (!QmlJsEditingSettings::get().autoFormatOnSave())
+ return;
+
+ // Check that we are dealing with a QML/JS editor
+ if (document->id() != Constants::C_QMLJSEDITOR_ID)
+ return;
+
+ // Check if file is contained in the current project (if wished)
+ if (QmlJsEditingSettings::get().autoFormatOnlyCurrentProject()) {
+ const ProjectExplorer::Project *pro = ProjectExplorer::ProjectTree::currentProject();
+ if (!pro || !pro->files(ProjectExplorer::Project::SourceFiles).contains(
+ document->filePath().toString())) {
+ return;
+ }
+ }
+
+ reformatFile();
+}
+
} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h
index a85f16b389..b176866d95 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.h
+++ b/src/plugins/qmljseditor/qmljseditorplugin.h
@@ -38,6 +38,7 @@ namespace Utils { class JsonSchemaManager; }
namespace Core {
class Command;
class ActionContainer;
+class IDocument;
class IEditor;
}
@@ -82,6 +83,7 @@ private:
void currentEditorChanged(Core::IEditor *editor);
void runSemanticScan();
void checkCurrentEditorSemanticInfoUpToDate();
+ void autoFormatOnSave(Core::IDocument *document);
Core::Command *addToolAction(QAction *a, Core::Context &context, Core::Id id,
Core::ActionContainer *c1, const QString &keySequence);
diff --git a/src/plugins/qmljseditor/quicktoolbar.cpp b/src/plugins/qmljseditor/quicktoolbar.cpp
index 863b778c17..9bc5b69855 100644
--- a/src/plugins/qmljseditor/quicktoolbar.cpp
+++ b/src/plugins/qmljseditor/quicktoolbar.cpp
@@ -24,7 +24,7 @@
****************************************************************************/
#include "quicktoolbar.h"
-#include "quicktoolbarsettingspage.h"
+#include "qmljseditingsettingspage.h"
#include <utils/changeset.h>
#include <qmleditorwidgets/contextpanewidget.h>
@@ -114,7 +114,7 @@ QuickToolBar::~QuickToolBar()
void QuickToolBar::apply(TextEditor::TextEditorWidget *editorWidget, Document::Ptr document, const ScopeChain *scopeChain, Node *node, bool update, bool force)
{
- if (!QuickToolBarSettings::get().enableContextPane && !force && !update) {
+ if (!QmlJsEditingSettings::get().enableContextPane() && !force && !update) {
contextWidget()->hide();
return;
}
@@ -219,10 +219,10 @@ void QuickToolBar::apply(TextEditor::TextEditorWidget *editorWidget, Document::P
if (!update)
contextWidget()->setType(m_prototypes);
if (!update)
- contextWidget()->activate(p3 , p1, p2, QuickToolBarSettings::get().pinContextPane);
+ contextWidget()->activate(p3 , p1, p2, QmlJsEditingSettings::get().pinContextPane());
else
- contextWidget()->rePosition(p3 , p1, p2, QuickToolBarSettings::get().pinContextPane);
- contextWidget()->setOptions(QuickToolBarSettings::get().enableContextPane, QuickToolBarSettings::get().pinContextPane);
+ contextWidget()->rePosition(p3 , p1, p2, QmlJsEditingSettings::get().pinContextPane());
+ contextWidget()->setOptions(QmlJsEditingSettings::get().enableContextPane(), QmlJsEditingSettings::get().pinContextPane());
contextWidget()->setPath(document->path());
contextWidget()->setProperties(&propertyReader);
m_doc = document;
@@ -404,16 +404,16 @@ void QuickToolBar::onPropertyRemovedAndChange(const QString &remove, const QStri
void QuickToolBar::onPinnedChanged(bool b)
{
- QuickToolBarSettings settings = QuickToolBarSettings::get();
- settings.pinContextPane = b;
+ QmlJsEditingSettings settings = QmlJsEditingSettings::get();
+ settings.setPinContextPane(b);
settings.set();
}
void QuickToolBar::onEnabledChanged(bool b)
{
- QuickToolBarSettings settings = QuickToolBarSettings::get();
- settings.pinContextPane = b;
- settings.enableContextPane = b;
+ QmlJsEditingSettings settings = QmlJsEditingSettings::get();
+ settings.setPinContextPane(b);
+ settings.setEnableContextPane(b);
settings.set();
}
diff --git a/src/plugins/qmljseditor/quicktoolbarsettingspage.cpp b/src/plugins/qmljseditor/quicktoolbarsettingspage.cpp
deleted file mode 100644
index c98124499e..0000000000
--- a/src/plugins/qmljseditor/quicktoolbarsettingspage.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "quicktoolbarsettingspage.h"
-#include "qmljseditorconstants.h"
-
-#include <qmljstools/qmljstoolsconstants.h>
-#include <coreplugin/icore.h>
-
-#include <QSettings>
-#include <QTextStream>
-#include <QCheckBox>
-
-
-using namespace QmlJSEditor;
-using namespace QmlJSEditor::Internal;
-
-QuickToolBarSettings::QuickToolBarSettings()
- : enableContextPane(false),
- pinContextPane(false)
-{}
-
-void QuickToolBarSettings::set()
-{
- if (get() != *this)
- toSettings(Core::ICore::settings());
-}
-
-void QuickToolBarSettings::fromSettings(QSettings *settings)
-{
- settings->beginGroup(QLatin1String(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML));
- enableContextPane = settings->value(
- QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANE_KEY), QVariant(false)).toBool();
- pinContextPane = settings->value(
- QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANEPIN_KEY), QVariant(false)).toBool();
- settings->endGroup();
-}
-
-void QuickToolBarSettings::toSettings(QSettings *settings) const
-{
- settings->beginGroup(QLatin1String(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML));
- settings->setValue(QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANE_KEY), enableContextPane);
- settings->setValue(QLatin1String(QmlJSEditor::Constants::QML_CONTEXTPANEPIN_KEY), pinContextPane);
- settings->endGroup();
-}
-
-bool QuickToolBarSettings::equals(const QuickToolBarSettings &other) const
-{
- return enableContextPane == other.enableContextPane
- && pinContextPane == other.pinContextPane;
-}
-
-
-QuickToolBarSettingsPageWidget::QuickToolBarSettingsPageWidget(QWidget *parent) :
- QWidget(parent)
-{
- m_ui.setupUi(this);
-}
-
-QuickToolBarSettings QuickToolBarSettingsPageWidget::settings() const
-{
- QuickToolBarSettings ds;
- ds.enableContextPane = m_ui.textEditHelperCheckBox->isChecked();
- ds.pinContextPane = m_ui.textEditHelperCheckBoxPin->isChecked();
- return ds;
-}
-
-void QuickToolBarSettingsPageWidget::setSettings(const QuickToolBarSettings &s)
-{
- m_ui.textEditHelperCheckBox->setChecked(s.enableContextPane);
- m_ui.textEditHelperCheckBoxPin->setChecked(s.pinContextPane);
-}
-
-QuickToolBarSettings QuickToolBarSettings::get()
-{
- QuickToolBarSettings settings;
- settings.fromSettings(Core::ICore::settings());
- return settings;
-}
-
-QuickToolBarSettingsPage::QuickToolBarSettingsPage() :
- m_widget(0)
-{
- setId("C.QmlToolbar");
- setDisplayName(tr("Qt Quick ToolBar"));
- setCategory(Constants::SETTINGS_CATEGORY_QML);
- setDisplayCategory(QCoreApplication::translate("QmlJSEditor",
- QmlJSEditor::Constants::SETTINGS_TR_CATEGORY_QML));
- setCategoryIcon(Utils::Icon(QmlJSTools::Constants::SETTINGS_CATEGORY_QML_ICON));
-}
-
-QWidget *QuickToolBarSettingsPage::widget()
-{
- if (!m_widget) {
- m_widget = new QuickToolBarSettingsPageWidget;
- m_widget->setSettings(QuickToolBarSettings::get());
- }
- return m_widget;
-}
-
-void QuickToolBarSettingsPage::apply()
-{
- if (!m_widget) // page was never shown
- return;
- m_widget->settings().set();
-}
-
-void QuickToolBarSettingsPage::finish()
-{
- delete m_widget;
-}
diff --git a/src/plugins/qmljstools/qmljstools.pro b/src/plugins/qmljstools/qmljstools.pro
index 662c0d950f..bea9367a1b 100644
--- a/src/plugins/qmljstools/qmljstools.pro
+++ b/src/plugins/qmljstools/qmljstools.pro
@@ -2,7 +2,7 @@ include(../../qtcreatorplugin.pri)
DEFINES += QMLJSTOOLS_LIBRARY
-!dll {
+!contains(CONFIG, dll) {
DEFINES += QMLJSTOOLS_STATIC
}
diff --git a/src/plugins/qmlprofiler/debugmessagesmodel.cpp b/src/plugins/qmlprofiler/debugmessagesmodel.cpp
index d3df28d601..f9665bd054 100644
--- a/src/plugins/qmlprofiler/debugmessagesmodel.cpp
+++ b/src/plugins/qmlprofiler/debugmessagesmodel.cpp
@@ -39,7 +39,7 @@ int DebugMessagesModel::typeId(int index) const
return m_data[index].typeId;
}
-QColor DebugMessagesModel::color(int index) const
+QRgb DebugMessagesModel::color(int index) const
{
return colorBySelectionId(index);
}
diff --git a/src/plugins/qmlprofiler/debugmessagesmodel.h b/src/plugins/qmlprofiler/debugmessagesmodel.h
index bbcfa387b6..4cb49e4e27 100644
--- a/src/plugins/qmlprofiler/debugmessagesmodel.h
+++ b/src/plugins/qmlprofiler/debugmessagesmodel.h
@@ -38,7 +38,7 @@ public:
DebugMessagesModel(QmlProfilerModelManager *manager, QObject *parent = 0);
int typeId(int index) const override;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
QVariantList labels() const override;
QVariantMap details(int index) const override;
int expandedRow(int index) const override;
diff --git a/src/plugins/qmlprofiler/inputeventsmodel.cpp b/src/plugins/qmlprofiler/inputeventsmodel.cpp
index a7827ee3aa..f31d19d0ce 100644
--- a/src/plugins/qmlprofiler/inputeventsmodel.cpp
+++ b/src/plugins/qmlprofiler/inputeventsmodel.cpp
@@ -45,7 +45,7 @@ int InputEventsModel::typeId(int index) const
return selectionId(index) == Mouse ? m_mouseTypeId : m_keyTypeId;
}
-QColor InputEventsModel::color(int index) const
+QRgb InputEventsModel::color(int index) const
{
return colorBySelectionId(index);
}
diff --git a/src/plugins/qmlprofiler/inputeventsmodel.h b/src/plugins/qmlprofiler/inputeventsmodel.h
index 23509c19e0..0e77893a17 100644
--- a/src/plugins/qmlprofiler/inputeventsmodel.h
+++ b/src/plugins/qmlprofiler/inputeventsmodel.h
@@ -50,7 +50,7 @@ public:
void clear() override;
int typeId(int index) const override;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
QVariantList labels() const override;
QVariantMap details(int index) const override;
int expandedRow(int index) const override;
diff --git a/src/plugins/qmlprofiler/memoryusagemodel.cpp b/src/plugins/qmlprofiler/memoryusagemodel.cpp
index a380c8c304..d989b76df3 100644
--- a/src/plugins/qmlprofiler/memoryusagemodel.cpp
+++ b/src/plugins/qmlprofiler/memoryusagemodel.cpp
@@ -61,7 +61,7 @@ int MemoryUsageModel::typeId(int index) const
return m_data[index].typeId;
}
-QColor MemoryUsageModel::color(int index) const
+QRgb MemoryUsageModel::color(int index) const
{
return colorBySelectionId(index);
}
diff --git a/src/plugins/qmlprofiler/memoryusagemodel.h b/src/plugins/qmlprofiler/memoryusagemodel.h
index dd978da788..b20f435f47 100644
--- a/src/plugins/qmlprofiler/memoryusagemodel.h
+++ b/src/plugins/qmlprofiler/memoryusagemodel.h
@@ -59,7 +59,7 @@ public:
int expandedRow(int index) const override;
int collapsedRow(int index) const override;
int typeId(int index) const override;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
float relativeHeight(int index) const override;
QVariantMap location(int index) const override;
diff --git a/src/plugins/qmlprofiler/pixmapcachemodel.cpp b/src/plugins/qmlprofiler/pixmapcachemodel.cpp
index b38256c9a8..01770c579b 100644
--- a/src/plugins/qmlprofiler/pixmapcachemodel.cpp
+++ b/src/plugins/qmlprofiler/pixmapcachemodel.cpp
@@ -60,7 +60,7 @@ int PixmapCacheModel::typeId(int index) const
return m_data[index].typeId;
}
-QColor PixmapCacheModel::color(int index) const
+QRgb PixmapCacheModel::color(int index) const
{
if (m_data[index].pixmapEventType == PixmapCacheCountChanged)
return colorByHue(s_pixmapCacheCountHue);
diff --git a/src/plugins/qmlprofiler/pixmapcachemodel.h b/src/plugins/qmlprofiler/pixmapcachemodel.h
index cdbfee49bb..9d899e6565 100644
--- a/src/plugins/qmlprofiler/pixmapcachemodel.h
+++ b/src/plugins/qmlprofiler/pixmapcachemodel.h
@@ -102,7 +102,7 @@ public:
int expandedRow(int index) const override;
int collapsedRow(int index) const override;
int typeId(int index) const override;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
float relativeHeight(int index) const override;
QVariantList labels() const override;
diff --git a/src/plugins/qmlprofiler/qmlevent.cpp b/src/plugins/qmlprofiler/qmlevent.cpp
index 225186df25..2d06933719 100644
--- a/src/plugins/qmlprofiler/qmlevent.cpp
+++ b/src/plugins/qmlprofiler/qmlevent.cpp
@@ -59,14 +59,14 @@ enum SerializationTypeOffset {
};
template<typename Number>
-static void readNumbers(QDataStream &stream, Number *data, quint16 length)
+static inline void readNumbers(QDataStream &stream, Number *data, quint16 length)
{
for (quint16 i = 0; i != length; ++i)
stream >> data[i];
}
template<typename Number>
-static Number readNumber(QDataStream &stream, qint8 type)
+static inline Number readNumber(QDataStream &stream, qint8 type)
{
switch (type) {
case OneByte: {
@@ -150,7 +150,7 @@ QDataStream &operator>>(QDataStream &stream, QmlEvent &event)
return stream;
}
-static qint8 minimumType(const QmlEvent &event, quint16 length, quint16 origBitsPerNumber)
+static inline qint8 minimumType(const QmlEvent &event, quint16 length, quint16 origBitsPerNumber)
{
qint8 type = OneByte;
bool ok = true;
@@ -182,7 +182,7 @@ static qint8 minimumType(const QmlEvent &event, quint16 length, quint16 origBits
}
template<typename Number>
-static qint8 minimumType(Number number)
+static inline qint8 minimumType(Number number)
{
if (static_cast<qint8>(number) == number)
return OneByte;
@@ -194,14 +194,14 @@ static qint8 minimumType(Number number)
}
template<typename Number>
-static void writeNumbers(QDataStream &stream, const QmlEvent &event, quint16 length)
+static inline void writeNumbers(QDataStream &stream, const QmlEvent &event, quint16 length)
{
for (quint16 i = 0; i != length; ++i)
stream << event.number<Number>(i);
}
template<typename Number>
-static void writeNumber(QDataStream &stream, Number number, qint8 type)
+static inline void writeNumber(QDataStream &stream, Number number, qint8 type)
{
switch (type) {
case OneByte:
diff --git a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp
index 8e0bd30e84..97cee62797 100644
--- a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp
+++ b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp
@@ -137,7 +137,7 @@ int QmlProfilerAnimationsModel::collapsedRow(int index) const
return rowFromThreadId(selectionId(index));
}
-QColor QmlProfilerAnimationsModel::color(int index) const
+QRgb QmlProfilerAnimationsModel::color(int index) const
{
double fpsFraction = m_data[index].framerate / 60.0;
if (fpsFraction > 1.0)
diff --git a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.h b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.h
index 073383e47c..084851a667 100644
--- a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.h
+++ b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.h
@@ -58,7 +58,7 @@ public:
Q_INVOKABLE int expandedRow(int index) const override;
Q_INVOKABLE int collapsedRow(int index) const override;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
float relativeHeight(int index) const override;
QVariantList labels() const override;
diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp
index 0390d493cd..52a17f7416 100644
--- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp
@@ -154,6 +154,15 @@ void QmlProfilerDataModel::addEvent(const QmlEvent &event)
d->eventStream << event;
}
+void QmlProfilerDataModel::addEvents(const QVector<QmlEvent> &events)
+{
+ Q_D(QmlProfilerDataModel);
+ for (const QmlEvent &event : events) {
+ d->modelManager->dispatch(event, d->eventTypes[event.typeIndex()]);
+ d->eventStream << event;
+ }
+}
+
void QmlProfilerDataModel::clear()
{
Q_D(QmlProfilerDataModel);
diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h
index 5bb97abea4..4698dac409 100644
--- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h
+++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h
@@ -52,6 +52,7 @@ public:
void clear();
bool isEmpty() const;
void addEvent(const QmlEvent &event);
+ void addEvents(const QVector<QmlEvent> &events);
void replayEvents(qint64 startTime, qint64 endTime,
QmlProfilerModelManager::EventLoader loader) const;
void finalize();
diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp
index 4c933040e6..6a236a12f9 100644
--- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp
@@ -378,8 +378,8 @@ void QmlProfilerModelManager::load(const QString &filename)
connect(reader, &QmlProfilerFileReader::notesLoaded,
d->notesModel, &QmlProfilerNotesModel::setNotes);
- connect(reader, &QmlProfilerFileReader::qmlEventLoaded,
- d->model, &QmlProfilerDataModel::addEvent);
+ connect(reader, &QmlProfilerFileReader::qmlEventsLoaded,
+ d->model, &QmlProfilerDataModel::addEvents);
connect(reader, &QmlProfilerFileReader::success, this, [this, reader]() {
d->traceTime->setTime(reader->traceStart(), reader->traceEnd());
diff --git a/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp b/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp
index f52c46f7dc..a4c76f9d90 100644
--- a/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp
@@ -180,7 +180,7 @@ int QmlProfilerRangeModel::bindingLoopDest(int index) const
return m_data[index].bindingLoopHead;
}
-QColor QmlProfilerRangeModel::color(int index) const
+QRgb QmlProfilerRangeModel::color(int index) const
{
return colorBySelectionId(index);
}
diff --git a/src/plugins/qmlprofiler/qmlprofilerrangemodel.h b/src/plugins/qmlprofiler/qmlprofilerrangemodel.h
index 1b97833335..adc68ee836 100644
--- a/src/plugins/qmlprofiler/qmlprofilerrangemodel.h
+++ b/src/plugins/qmlprofiler/qmlprofilerrangemodel.h
@@ -62,7 +62,7 @@ public:
Q_INVOKABLE int expandedRow(int index) const override;
Q_INVOKABLE int collapsedRow(int index) const override;
int bindingLoopDest(int index) const;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
QVariantList labels() const override;
QVariantMap details(int index) const override;
diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp
index 67188e32fa..ec9195bbd0 100644
--- a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp
@@ -123,7 +123,7 @@ QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
m_loadedFeatures(0)
{
static int meta[] = {
- qRegisterMetaType<QmlEvent>(),
+ qRegisterMetaType<QVector<QmlEvent> >(),
qRegisterMetaType<QVector<QmlEventType> >(),
qRegisterMetaType<QVector<QmlNote> >()
};
@@ -248,7 +248,9 @@ bool QmlProfilerFileReader::loadQzt(QIODevice *device)
emit notesLoaded(m_notes);
updateProgress(device);
- QmlEvent event;
+ const int eventBufferLength = 1024;
+ QVector<QmlEvent> eventBuffer(eventBufferLength);
+ int eventBufferIndex = 0;
while (!stream.atEnd()) {
stream >> data;
buffer.setData(qUncompress(data));
@@ -256,6 +258,7 @@ bool QmlProfilerFileReader::loadQzt(QIODevice *device)
while (!buffer.atEnd()) {
if (isCanceled())
return false;
+ QmlEvent &event = eventBuffer[eventBufferIndex];
bufferStream >> event;
if (bufferStream.status() == QDataStream::Ok) {
if (event.typeIndex() >= m_eventTypes.length()) {
@@ -263,7 +266,6 @@ bool QmlProfilerFileReader::loadQzt(QIODevice *device)
return false;
}
m_loadedFeatures |= (1ULL << m_eventTypes[event.typeIndex()].feature());
- emit qmlEventLoaded(event);
} else if (bufferStream.status() == QDataStream::ReadPastEnd) {
break; // Apparently EOF is a character so we end up here after the last event.
} else if (bufferStream.status() == QDataStream::ReadCorruptData) {
@@ -272,10 +274,16 @@ bool QmlProfilerFileReader::loadQzt(QIODevice *device)
} else {
Q_UNREACHABLE();
}
+ if (++eventBufferIndex == eventBufferLength) {
+ emit qmlEventsLoaded(eventBuffer);
+ eventBufferIndex = 0;
+ }
}
buffer.close();
updateProgress(device);
}
+ eventBuffer.resize(eventBufferIndex);
+ emit qmlEventsLoaded(eventBuffer);
emit success();
return true;
}
@@ -499,8 +507,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream)
std::sort(events.begin(), events.end(), [](const QmlEvent &a, const QmlEvent &b) {
return a.timestamp() < b.timestamp();
});
- foreach (const QmlEvent &event, events)
- emit qmlEventLoaded(event);
+ emit qmlEventsLoaded(events);
return;
}
break;
diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.h b/src/plugins/qmlprofiler/qmlprofilertracefile.h
index 937ec1de29..b705f07e68 100644
--- a/src/plugins/qmlprofiler/qmlprofilertracefile.h
+++ b/src/plugins/qmlprofiler/qmlprofilertracefile.h
@@ -62,7 +62,7 @@ public:
signals:
void typesLoaded(const QVector<QmlProfiler::QmlEventType> &types);
void notesLoaded(const QVector<QmlProfiler::QmlNote> &notes);
- void qmlEventLoaded(const QmlProfiler::QmlEvent &event);
+ void qmlEventsLoaded(const QVector<QmlProfiler::QmlEvent> &event);
void error(const QString &error);
void success();
diff --git a/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp b/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp
index d983630175..8ffb3f8290 100644
--- a/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp
+++ b/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp
@@ -94,7 +94,7 @@ int SceneGraphTimelineModel::typeId(int index) const
return m_data[index].typeId;
}
-QColor SceneGraphTimelineModel::color(int index) const
+QRgb SceneGraphTimelineModel::color(int index) const
{
return colorBySelectionId(index);
}
diff --git a/src/plugins/qmlprofiler/scenegraphtimelinemodel.h b/src/plugins/qmlprofiler/scenegraphtimelinemodel.h
index baa06a83db..805b53b3e3 100644
--- a/src/plugins/qmlprofiler/scenegraphtimelinemodel.h
+++ b/src/plugins/qmlprofiler/scenegraphtimelinemodel.h
@@ -88,7 +88,7 @@ public:
int expandedRow(int index) const override;
int collapsedRow(int index) const override;
int typeId(int index) const override;
- QColor color(int index) const override;
+ QRgb color(int index) const override;
QVariantList labels() const override;
diff --git a/src/plugins/qmlprofiler/tests/debugmessagesmodel_test.cpp b/src/plugins/qmlprofiler/tests/debugmessagesmodel_test.cpp
index c48d8a5219..7be5f04ff1 100644
--- a/src/plugins/qmlprofiler/tests/debugmessagesmodel_test.cpp
+++ b/src/plugins/qmlprofiler/tests/debugmessagesmodel_test.cpp
@@ -64,7 +64,7 @@ void DebugMessagesModelTest::testColor()
// TimelineModel::colorBySelectionId ...
for (int i = 0; i < 10; ++i) {
QCOMPARE(model.color(i),
- QColor::fromHsl((i % (QtMsgType::QtInfoMsg + 1) * 25) % 360, 150, 166));
+ QColor::fromHsl((i % (QtMsgType::QtInfoMsg + 1) * 25) % 360, 150, 166).rgb());
}
}
diff --git a/src/plugins/qmlprofiler/tests/inputeventsmodel_test.cpp b/src/plugins/qmlprofiler/tests/inputeventsmodel_test.cpp
index f0212b66a3..c67856bc03 100644
--- a/src/plugins/qmlprofiler/tests/inputeventsmodel_test.cpp
+++ b/src/plugins/qmlprofiler/tests/inputeventsmodel_test.cpp
@@ -74,15 +74,15 @@ void InputEventsModelTest::testTypeId()
void InputEventsModelTest::testColor()
{
- QColor keyColor;
- QColor mouseColor;
+ QRgb keyColor = 0;
+ QRgb mouseColor = 0;
for (int i = 0; i < 10; ++i) {
InputEventType type = static_cast<InputEventType>(i % MaximumInputEventType);
int selectionId = (type <= InputKeyUnknown ? Key : Mouse);
QCOMPARE(selectionId, model.selectionId(i));
- QColor &expectedColor = selectionId == Key ? keyColor : mouseColor;
- if (expectedColor.isValid())
+ QRgb &expectedColor = selectionId == Key ? keyColor : mouseColor;
+ if (expectedColor != 0)
QCOMPARE(model.color(i), expectedColor);
else
expectedColor = model.color(i);
diff --git a/src/plugins/qmlprofiler/tests/memoryusagemodel_test.cpp b/src/plugins/qmlprofiler/tests/memoryusagemodel_test.cpp
index 274f3a9c01..b561074bf8 100644
--- a/src/plugins/qmlprofiler/tests/memoryusagemodel_test.cpp
+++ b/src/plugins/qmlprofiler/tests/memoryusagemodel_test.cpp
@@ -122,9 +122,9 @@ void MemoryUsageModelTest::testTypeId()
void MemoryUsageModelTest::testColor()
{
- QColor heapPageColor = model.color(0);
- QColor smallItemColor = model.color(1);
- QColor largeItemColor = model.color(2);
+ QRgb heapPageColor = model.color(0);
+ QRgb smallItemColor = model.color(1);
+ QRgb largeItemColor = model.color(2);
QVERIFY(smallItemColor != heapPageColor);
QVERIFY(largeItemColor != heapPageColor);
QVERIFY(smallItemColor != largeItemColor);
diff --git a/src/plugins/qmlprofiler/tests/pixmapcachemodel_test.cpp b/src/plugins/qmlprofiler/tests/pixmapcachemodel_test.cpp
index 8332904f87..069de0cca1 100644
--- a/src/plugins/qmlprofiler/tests/pixmapcachemodel_test.cpp
+++ b/src/plugins/qmlprofiler/tests/pixmapcachemodel_test.cpp
@@ -270,20 +270,20 @@ void PixmapCacheModelTest::testRowMaxValue()
void PixmapCacheModelTest::testColor()
{
- QColor row1Color;
- QColor dingsColor;
- QColor blahColor;
+ QRgb row1Color = 0;
+ QRgb dingsColor = 0;
+ QRgb blahColor = 0;
for (int i = 0; i < model.count(); ++i) {
if (model.collapsedRow(i) == 1) {
- if (!row1Color.isValid())
+ if (row1Color == 0)
row1Color = model.color(i);
else
QCOMPARE(model.color(i), row1Color);
} else {
const QmlEventType &type = manager.qmlModel()->eventTypes()[model.typeId(i)];
- QColor &pixmapColor = (type.location().filename() == QString("blah.png")) ?
+ QRgb &pixmapColor = (type.location().filename() == QString("blah.png")) ?
blahColor : dingsColor;
- if (!pixmapColor.isValid())
+ if (pixmapColor == 0)
pixmapColor = model.color(i);
else
QCOMPARE(model.color(i), pixmapColor);
diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
index c470c92f90..6062d117ab 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
@@ -60,14 +60,14 @@ void QmlProjectNode::refresh()
using namespace ProjectExplorer;
FileNode *projectFilesNode = new FileNode(m_project->filesFileName(),
- ProjectFileType,
+ FileType::Project,
/* generated = */ false);
QStringList files = m_project->files();
files.removeAll(m_project->filesFileName().toString());
QList<FileNode *> fileNodes = Utils::transform(files, [](const QString &f) {
- FileType fileType = SourceType; // ### FIXME
+ FileType fileType = FileType::Source; // ### FIXME
return new FileNode(Utils::FileName::fromString(f), fileType, false);
});
@@ -87,9 +87,9 @@ QList<ProjectExplorer::ProjectAction> QmlProjectNode::supportedActions(Node *nod
QList<ProjectExplorer::ProjectAction> actions;
actions.append(ProjectExplorer::AddNewFile);
actions.append(ProjectExplorer::EraseFile);
- if (node->nodeType() == ProjectExplorer::FileNodeType) {
+ if (node->nodeType() == ProjectExplorer::NodeType::File) {
ProjectExplorer::FileNode *fileNode = static_cast<ProjectExplorer::FileNode *>(node);
- if (fileNode->fileType() != ProjectExplorer::ProjectFileType)
+ if (fileNode->fileType() != ProjectExplorer::FileType::Project)
actions.append(ProjectExplorer::Rename);
}
return actions;
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
index 459e07dd07..8978fff35a 100644
--- a/src/plugins/qtsupport/baseqtversion.cpp
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -1082,13 +1082,19 @@ FileName BaseQtVersion::mkspecPath() const
bool BaseQtVersion::hasMkspec(const FileName &spec) const
{
- QFileInfo fi;
- fi.setFile(QDir::fromNativeSeparators(qmakeProperty("QT_HOST_DATA"))
- + QLatin1String("/mkspecs/") + spec.toString());
- if (fi.isDir())
+ if (spec.isEmpty())
+ return true; // default spec of a Qt version
+
+ QDir mkspecDir = QDir(QDir::fromNativeSeparators(qmakeProperty("QT_HOST_DATA"))
+ + QLatin1String("/mkspecs/"));
+ const QString absSpec = mkspecDir.absoluteFilePath(spec.toString());
+ if (QFileInfo(absSpec).isDir() && QFileInfo(absSpec + "/qmake.conf").isFile())
return true;
- fi.setFile(sourcePath().toString() + QLatin1String("/mkspecs/") + spec.toString());
- return fi.isDir();
+ mkspecDir.setPath(sourcePath().toString() + QLatin1String("/mkspecs/"));
+ const QString absSrcSpec = mkspecDir.absoluteFilePath(spec.toString());
+ return absSrcSpec != absSpec
+ && QFileInfo(absSrcSpec).isDir()
+ && QFileInfo(absSrcSpec + "/qmake.conf").isFile();
}
BaseQtVersion::QmakeBuildConfigs BaseQtVersion::defaultBuildConfig() const
diff --git a/src/plugins/qtsupport/qscxmlcgenerator.cpp b/src/plugins/qtsupport/qscxmlcgenerator.cpp
index 423bfc763b..e912e3d24b 100644
--- a/src/plugins/qtsupport/qscxmlcgenerator.cpp
+++ b/src/plugins/qtsupport/qscxmlcgenerator.cpp
@@ -136,7 +136,7 @@ Utils::FileName QScxmlcGenerator::tmpFile() const
FileType QScxmlcGeneratorFactory::sourceType() const
{
- return StateChartType;
+ return FileType::StateChart;
}
QString QScxmlcGeneratorFactory::sourceTag() const
diff --git a/src/plugins/qtsupport/uicgenerator.cpp b/src/plugins/qtsupport/uicgenerator.cpp
index ff8c93e1bb..a88619e521 100644
--- a/src/plugins/qtsupport/uicgenerator.cpp
+++ b/src/plugins/qtsupport/uicgenerator.cpp
@@ -88,7 +88,7 @@ FileNameToContentsHash UicGenerator::handleProcessFinished(QProcess *process)
FileType UicGeneratorFactory::sourceType() const
{
- return FormType;
+ return FileType::Form;
}
QString UicGeneratorFactory::sourceTag() const
diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp
index f76bdd11de..1bb7b8c0ed 100644
--- a/src/plugins/resourceeditor/resourcenode.cpp
+++ b/src/plugins/resourceeditor/resourcenode.cpp
@@ -44,7 +44,7 @@
using namespace ResourceEditor;
using namespace ResourceEditor::Internal;
-static bool priority(const QStringList &files)
+static bool hasPriority(const QStringList &files)
{
if (files.isEmpty())
return false;
@@ -226,7 +226,7 @@ void ResourceTopLevelNode::update()
}
- QList<ProjectExplorer::FolderNode *> oldPrefixList = subFolderNodes();
+ QList<ProjectExplorer::FolderNode *> oldPrefixList = folderNodes();
QList<ProjectExplorer::FolderNode *> prefixesToAdd;
QList<ProjectExplorer::FolderNode *> prefixesToRemove;
@@ -242,12 +242,12 @@ void ResourceTopLevelNode::update()
// delete nodes that weren't added
qDeleteAll(ProjectExplorer::subtractSortedList(newPrefixList, prefixesToAdd, sortByPrefixAndLang));
- foreach (FolderNode *sfn, subFolderNodes()) {
+ foreach (FolderNode *sfn, folderNodes()) {
ResourceFolderNode *srn = static_cast<ResourceFolderNode *>(sfn);
PrefixFolderLang folderId(srn->prefix(), QString(), srn->lang());
srn->updateFiles(filesToAdd[folderId]);
srn->updateFolders(foldersToAddToPrefix[folderId]);
- foreach (FolderNode* ssfn, sfn->subFolderNodes()) {
+ foreach (FolderNode* ssfn, sfn->folderNodes()) {
SimpleResourceFolderNode *sssn = static_cast<SimpleResourceFolderNode *>(ssfn);
sssn->addFilesAndSubfolders(filesToAdd, foldersToAddToFolders, srn->prefix(), srn->lang());
}
@@ -341,11 +341,11 @@ ProjectExplorer::FolderNode::AddNewInformation ResourceTopLevelNode::addNewInfor
.arg(QLatin1Char('/'));
int p = -1;
- if (priority(files)) { // images/* and qml/js mimetypes
+ if (hasPriority(files)) { // images/* and qml/js mimetypes
p = 110;
if (context == this)
p = 120;
- else if (projectNode() == context)
+ else if (parentProjectNode() == context)
p = 150; // steal from our project node
// The ResourceFolderNode '/' defers to us, as otherwise
// two nodes would be responsible for '/'
@@ -497,7 +497,7 @@ ProjectExplorer::FolderNode::AddNewInformation ResourceFolderNode::addNewInforma
.arg(displayName());
int p = -1; // never the default
- if (priority(files)) { // image/* and qml/js mimetypes
+ if (hasPriority(files)) { // image/* and qml/js mimetypes
p = 105; // prefer against .pro and .pri files
if (context == this)
p = 120;
@@ -552,7 +552,7 @@ void ResourceFolderNode::updateFiles(QList<ProjectExplorer::FileNode *> newList)
void ResourceFolderNode::updateFolders(QList<ProjectExplorer::FolderNode *> newList)
{
- QList<ProjectExplorer::FolderNode *> oldList = subFolderNodes();
+ QList<ProjectExplorer::FolderNode *> oldList = folderNodes();
QList<ProjectExplorer::FolderNode *> foldersToAdd;
QList<ProjectExplorer::FolderNode *> foldersToRemove;
@@ -593,7 +593,7 @@ bool ResourceFileWatcher::reload(QString *errorString, ReloadFlag flag, ChangeTy
}
ResourceFileNode::ResourceFileNode(const Utils::FileName &filePath, const QString &qrcPath, const QString &displayName)
- : ProjectExplorer::FileNode(filePath, ProjectExplorer::UnknownFileType, false)
+ : ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Unknown, false)
, m_qrcPath(qrcPath)
, m_displayName(displayName)
{
@@ -737,7 +737,7 @@ void SimpleResourceFolderNode::updateFiles(QList<ProjectExplorer::FileNode *> ne
void SimpleResourceFolderNode::updateFolders(QList<ProjectExplorer::FolderNode *> newList)
{
- QList<ProjectExplorer::FolderNode *> oldList = subFolderNodes();
+ QList<ProjectExplorer::FolderNode *> oldList = folderNodes();
QList<ProjectExplorer::FolderNode *> foldersToAdd;
QList<ProjectExplorer::FolderNode *> foldersToRemove;
@@ -761,7 +761,7 @@ void SimpleResourceFolderNode::addFilesAndSubfolders(QMap<PrefixFolderLang,
{
updateFiles(filesToAdd.value(PrefixFolderLang(prefix, m_folderName, lang)));
updateFolders(foldersToAdd.value(PrefixFolderLang(prefix, m_folderName, lang)));
- foreach (FolderNode* subNode, subFolderNodes()) {
+ foreach (FolderNode* subNode, folderNodes()) {
SimpleResourceFolderNode* sn = static_cast<SimpleResourceFolderNode*>(subNode);
sn->addFilesAndSubfolders(filesToAdd, foldersToAdd, prefix, lang);
}
diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp
index d17ba17625..73e69806e2 100644
--- a/src/plugins/subversion/subversionclient.cpp
+++ b/src/plugins/subversion/subversionclient.cpp
@@ -31,7 +31,7 @@
#include <vcsbase/vcscommand.h>
#include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcsbaseeditor.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
+#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h>
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
@@ -55,12 +55,12 @@ using namespace VcsBase;
namespace Subversion {
namespace Internal {
-class SubversionLogParameterWidget : public VcsBaseEditorParameterWidget
+class SubversionLogConfig : public VcsBaseEditorConfig
{
Q_OBJECT
public:
- SubversionLogParameterWidget(VcsBaseClientSettings &settings, QWidget *parent = 0) :
- VcsBaseEditorParameterWidget(parent)
+ SubversionLogConfig(VcsBaseClientSettings &settings, QToolBar *toolBar) :
+ VcsBaseEditorConfig(toolBar)
{
mapSetting(addToggleButton(QLatin1String("--verbose"), tr("Verbose"),
tr("Show files changed in each revision")),
@@ -70,7 +70,9 @@ public:
SubversionClient::SubversionClient() : VcsBaseClient(new SubversionSettings)
{
- setLogParameterWidgetCreator([this] { return new SubversionLogParameterWidget(settings()); });
+ setLogConfigCreator([this](QToolBar *toolBar) {
+ return new SubversionLogConfig(settings(), toolBar);
+ });
}
VcsCommand *SubversionClient::createCommitCmd(const QString &repositoryRoot,
diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp
index c8de2421b7..e7265534ea 100644
--- a/src/plugins/subversion/subversioncontrol.cpp
+++ b/src/plugins/subversion/subversioncontrol.cpp
@@ -77,6 +77,11 @@ Core::Id SubversionControl::id() const
return Core::Id(VcsBase::Constants::VCS_ID_SUBVERSION);
}
+bool SubversionControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const
+{
+ return m_plugin->isVcsDirectory(fileName);
+}
+
bool SubversionControl::isConfigured() const
{
const Utils::FileName binary = m_plugin->client()->vcsBinary();
diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h
index 9f244fd529..8e63be6427 100644
--- a/src/plugins/subversion/subversioncontrol.h
+++ b/src/plugins/subversion/subversioncontrol.h
@@ -38,26 +38,27 @@ class SubversionControl : public Core::IVersionControl
Q_OBJECT
public:
explicit SubversionControl(SubversionPlugin *plugin);
- QString displayName() const override;
- Core::Id id() const override;
+ QString displayName() const final;
+ Core::Id id() const final;
+ bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final;
- bool managesDirectory(const QString &directory, QString *topLevel = 0) const override;
- bool managesFile(const QString &workingDirectory, const QString &fileName) const override;
+ bool managesDirectory(const QString &directory, QString *topLevel = 0) const final;
+ bool managesFile(const QString &workingDirectory, const QString &fileName) const final;
- bool isConfigured() const override;
- bool supportsOperation(Operation operation) const override;
- bool vcsOpen(const QString &fileName) override;
- bool vcsAdd(const QString &fileName) override;
- bool vcsDelete(const QString &filename) override;
- bool vcsMove(const QString &from, const QString &to) override;
- bool vcsCreateRepository(const QString &directory) override;
+ bool isConfigured() const final;
+ bool supportsOperation(Operation operation) const final;
+ bool vcsOpen(const QString &fileName) final;
+ bool vcsAdd(const QString &fileName) final;
+ bool vcsDelete(const QString &filename) final;
+ bool vcsMove(const QString &from, const QString &to) final;
+ bool vcsCreateRepository(const QString &directory) final;
- bool vcsAnnotate(const QString &file, int line) override;
+ bool vcsAnnotate(const QString &file, int line) final;
Core::ShellCommand *createInitialCheckoutCommand(const QString &url,
const Utils::FileName &baseDirectory,
const QString &localName,
- const QStringList &extraArgs) override;
+ const QStringList &extraArgs) final;
void emitRepositoryChanged(const QString &);
void emitFilesChanged(const QStringList &);
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index 9c17f34f81..2abc041d12 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -39,7 +39,6 @@
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseconstants.h>
#include <vcsbase/vcsoutputwindow.h>
-#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <texteditor/textdocument.h>
@@ -54,6 +53,7 @@
#include <coreplugin/locator/commandlocator.h>
#include <coreplugin/messagemanager.h>
+#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
@@ -408,6 +408,15 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *e
return true;
}
+bool SubversionPlugin::isVcsDirectory(const FileName &fileName)
+{
+ const QString baseName = fileName.fileName();
+ return fileName.toFileInfo().isDir()
+ && contains(m_svnDirectories, [baseName](const QString &s) {
+ return !baseName.compare(s, HostOsInfo::fileNameCaseSensitivity());
+ });
+}
+
SubversionClient *SubversionPlugin::client() const
{
QTC_CHECK(m_client);
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
index da05a072a5..3c614eeb7c 100644
--- a/src/plugins/subversion/subversionplugin.h
+++ b/src/plugins/subversion/subversionplugin.h
@@ -73,6 +73,8 @@ public:
bool initialize(const QStringList &arguments, QString *errorMessage);
+ bool isVcsDirectory(const Utils::FileName &fileName);
+
SubversionClient *client() const;
SubversionSubmitEditor *openSubversionSubmitEditor(const QString &fileName);
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 5b1f0f6d7a..21c097913f 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -256,6 +256,8 @@ public:
void print(QPrinter *printer);
void maybeSelectLine();
+ void duplicateSelection(bool comment);
+ void duplicateBlockSelection(bool comment);
void updateCannotDecodeInfo();
void collectToCircularClipboard();
@@ -6165,6 +6167,128 @@ void TextEditorWidget::copyLine()
copy();
}
+void TextEditorWidgetPrivate::duplicateSelection(bool comment)
+{
+ if (m_inBlockSelectionMode) {
+ duplicateBlockSelection(comment);
+ return;
+ }
+
+ QTextCursor cursor = q->textCursor();
+
+ if (cursor.hasSelection()) {
+
+ // Cannot "duplicate and comment" files without multi-line comment
+ if (comment && !m_commentDefinition.hasMultiLineStyle())
+ return;
+
+ QString dupText = cursor.selectedText().replace(QChar::ParagraphSeparator, QLatin1Char('\n'));
+ if (comment)
+ dupText = (m_commentDefinition.multiLineStart + dupText + m_commentDefinition.multiLineEnd);
+ const int selStart = cursor.selectionStart();
+ const int selEnd = cursor.selectionEnd();
+ const bool cursorAtStart = (cursor.position() == selStart);
+ cursor.setPosition(selEnd);
+ cursor.insertText(dupText);
+ cursor.setPosition(cursorAtStart ? selEnd : selStart);
+ cursor.setPosition(cursorAtStart ? selStart : selEnd, QTextCursor::KeepAnchor);
+ } else {
+ const int curPos = cursor.position();
+ const QTextBlock &block = cursor.block();
+ QString dupText = block.text() + QLatin1Char('\n');
+ if (comment && m_commentDefinition.hasSingleLineStyle())
+ dupText.append(m_commentDefinition.singleLine);
+ cursor.setPosition(block.position());
+ cursor.insertText(dupText);
+ cursor.setPosition(curPos);
+ }
+ q->setTextCursor(cursor);
+}
+
+void TextEditorWidgetPrivate::duplicateBlockSelection(bool comment)
+{
+ QTextCursor cursor = q->textCursor();
+
+ const TextBlockSelection curSel = m_blockSelection;
+
+ if (curSel.positionColumn == curSel.anchorColumn) {
+ // No columns selected, duplicating multiple lines
+
+ const bool isUp = curSel.positionBlock > curSel.anchorBlock;
+ const QString commentText =
+ (comment && m_commentDefinition.hasSingleLineStyle()) ?
+ m_commentDefinition.singleLine : QString();
+
+ QTextBlock block = cursor.block();
+ QString dupText = commentText + block.text() + QLatin1Char('\n');
+
+ for (int b = curSel.firstBlockNumber(); b < curSel.lastBlockNumber(); ++b) {
+ if (isUp) {
+ block = block.previous();
+ dupText.prepend(commentText + block.text() + QLatin1Char('\n'));
+ } else {
+ block = block.next();
+ dupText.append(commentText + block.text() + QLatin1Char('\n'));
+ }
+ }
+
+ if (isUp)
+ block = cursor.block();
+
+ cursor.setPosition(block.position() + block.length());
+ cursor.insertText(dupText);
+
+ } else {
+ // Duplicating full block selection with columns
+
+ // Cannot "duplicate and comment" files without multi-line comment
+ if (comment && !m_commentDefinition.hasMultiLineStyle())
+ return;
+
+ const int fc = curSel.firstVisualColumn();
+ const int lc = curSel.lastVisualColumn();
+ const int l = lc - fc;
+
+ cursor.beginEditBlock();
+ for (int b = curSel.firstBlockNumber(); b <= curSel.lastBlockNumber(); ++b) {
+ const QTextBlock &block = m_document->document()->findBlockByNumber(b);
+ QString dupText = block.text();
+ const int dupTextLength = dupText.length();
+
+ if (dupTextLength < lc) {
+ const QString addSpace(lc - dupTextLength, ' ');
+ cursor.setPosition(block.position() + dupTextLength);
+ cursor.insertText(addSpace);
+ dupText.append(addSpace);
+ }
+
+ cursor.setPosition(block.position() + lc);
+ dupText = dupText.mid(fc, l);
+
+ if (comment)
+ dupText = (m_commentDefinition.multiLineStart + dupText + m_commentDefinition.multiLineEnd);
+ cursor.insertText(dupText);
+ }
+ cursor.endEditBlock();
+ }
+
+ enableBlockSelection(curSel.positionBlock, curSel.positionColumn,
+ curSel.anchorBlock, curSel.anchorColumn);
+
+ cursor = m_blockSelection.cursor(m_document.data());
+ q->doSetTextCursor(cursor, m_blockSelection.hasSelection());
+}
+
+void TextEditorWidget::duplicateSelection()
+{
+ d->duplicateSelection(false);
+}
+
+void TextEditorWidget::duplicateSelectionAndComment()
+{
+ d->duplicateSelection(true);
+}
+
void TextEditorWidget::deleteLine()
{
d->maybeSelectLine();
@@ -7145,6 +7269,11 @@ void TextEditorWidget::setCursorPosition(int pos)
setTextCursor(tc);
}
+QToolBar *TextEditorWidget::toolBar()
+{
+ return d->m_toolBar;
+}
+
void BaseTextEditor::select(int toPos)
{
editorWidget()->setBlockSelection(false);
diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h
index 2cd60da380..592bd73e57 100644
--- a/src/plugins/texteditor/texteditor.h
+++ b/src/plugins/texteditor/texteditor.h
@@ -190,6 +190,7 @@ public:
using QPlainTextEdit::cursorRect;
QRect cursorRect(int pos) const;
void setCursorPosition(int pos);
+ QToolBar *toolBar();
void print(QPrinter *);
@@ -357,6 +358,8 @@ public:
void cutLine();
void copyLine();
+ void duplicateSelection();
+ void duplicateSelectionAndComment();
void deleteLine();
void deleteEndOfWord();
void deleteEndOfWordCamelCase();
diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp
index 81472b6eea..bbd14f9efd 100644
--- a/src/plugins/texteditor/texteditoractionhandler.cpp
+++ b/src/plugins/texteditor/texteditoractionhandler.cpp
@@ -142,6 +142,8 @@ public:
QAction *m_unfoldAction;
QAction *m_cutLineAction;
QAction *m_copyLineAction;
+ QAction *m_duplicateSelectionAction;
+ QAction *m_duplicateSelectionAndCommentAction;
QAction *m_deleteLineAction;
QAction *m_deleteEndOfWordAction;
QAction *m_deleteEndOfWordCamelCaseAction;
@@ -206,6 +208,8 @@ TextEditorActionHandlerPrivate::TextEditorActionHandlerPrivate
m_unfoldAction(0),
m_cutLineAction(0),
m_copyLineAction(0),
+ m_duplicateSelectionAction(0),
+ m_duplicateSelectionAndCommentAction(0),
m_deleteLineAction(0),
m_deleteEndOfWordAction(0),
m_deleteEndOfWordCamelCaseAction(0),
@@ -403,6 +407,14 @@ void TextEditorActionHandlerPrivate::createActions()
[this] (TextEditorWidget *w) { w->copyLine(); }, false, tr("Copy &Line"),
QKeySequence(tr("Ctrl+Ins")),
G_EDIT_TEXT, advancedEditMenu);
+ m_duplicateSelectionAction = registerAction(DUPLICATE_SELECTION,
+ [this] (TextEditorWidget *w) { w->duplicateSelection(); }, false, tr("&Duplicate Selection"),
+ QKeySequence(),
+ G_EDIT_TEXT, advancedEditMenu);
+ m_duplicateSelectionAndCommentAction = registerAction(DUPLICATE_SELECTION_AND_COMMENT,
+ [this] (TextEditorWidget *w) { w->duplicateSelectionAndComment(); }, false, tr("&Duplicate Selection and Comment"),
+ QKeySequence(),
+ G_EDIT_TEXT, advancedEditMenu);
m_upperCaseSelectionAction = registerAction(UPPERCASE_SELECTION,
[this] (TextEditorWidget *w) { w->uppercaseSelection(); }, true, tr("Uppercase Selection"),
QKeySequence(Core::UseMacShortcuts ? tr("Meta+Shift+U") : tr("Alt+Shift+U")),
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
index 8dbaf93de4..9b392e3980 100644
--- a/src/plugins/texteditor/texteditorconstants.h
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -144,6 +144,8 @@ const char UPPERCASE_SELECTION[] = "TextEditor.UppercaseSelection";
const char LOWERCASE_SELECTION[] = "TextEditor.LowercaseSelection";
const char CUT_LINE[] = "TextEditor.CutLine";
const char COPY_LINE[] = "TextEditor.CopyLine";
+const char DUPLICATE_SELECTION[] = "TextEditor.DuplicateSelection";
+const char DUPLICATE_SELECTION_AND_COMMENT[] = "TextEditor.DuplicateSelectionAndComment";
const char DELETE_LINE[] = "TextEditor.DeleteLine";
const char DELETE_END_OF_WORD[] = "TextEditor.DeleteEndOfWord";
const char DELETE_END_OF_WORD_CAMEL_CASE[] = "TextEditor.DeleteEndOfWordCamelCase";
diff --git a/src/plugins/todo/todoitemsprovider.cpp b/src/plugins/todo/todoitemsprovider.cpp
index 3bedefac05..858efa6731 100644
--- a/src/plugins/todo/todoitemsprovider.cpp
+++ b/src/plugins/todo/todoitemsprovider.cpp
@@ -146,7 +146,7 @@ void TodoItemsProvider::setItemsListWithinSubproject()
// TODO prefer current editor as source of sub-project
Node *node = ProjectTree::currentNode();
if (node) {
- ProjectNode *projectNode = node->projectNode();
+ ProjectNode *projectNode = node->parentProjectNode();
if (projectNode) {
FindAllFilesVisitor filesVisitor;
diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro
index 94616bd866..461dc152c0 100644
--- a/src/plugins/vcsbase/vcsbase.pro
+++ b/src/plugins/vcsbase/vcsbase.pro
@@ -25,7 +25,7 @@ HEADERS += vcsbase_global.h \
vcscommand.h \
vcsbaseclient.h \
vcsbaseclientsettings.h \
- vcsbaseeditorparameterwidget.h \
+ vcsbaseeditorconfig.h \
submitfieldwidget.h \
submiteditorwidget.h
@@ -52,7 +52,7 @@ SOURCES += vcsplugin.cpp \
vcscommand.cpp \
vcsbaseclient.cpp \
vcsbaseclientsettings.cpp \
- vcsbaseeditorparameterwidget.cpp \
+ vcsbaseeditorconfig.cpp \
submitfieldwidget.cpp \
submiteditorwidget.cpp
diff --git a/src/plugins/vcsbase/vcsbase.qbs b/src/plugins/vcsbase/vcsbase.qbs
index a19269e857..deeb41a4c7 100644
--- a/src/plugins/vcsbase/vcsbase.qbs
+++ b/src/plugins/vcsbase/vcsbase.qbs
@@ -55,8 +55,8 @@ QtcPlugin {
"vcsbaseconstants.h",
"vcsbaseeditor.cpp",
"vcsbaseeditor.h",
- "vcsbaseeditorparameterwidget.cpp",
- "vcsbaseeditorparameterwidget.h",
+ "vcsbaseeditorconfig.cpp",
+ "vcsbaseeditorconfig.h",
"vcsbaseoptionspage.cpp",
"vcsbaseoptionspage.h",
"vcsbaseplugin.cpp",
diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp
index 76e560597d..aa0204cc75 100644
--- a/src/plugins/vcsbase/vcsbaseclient.cpp
+++ b/src/plugins/vcsbase/vcsbaseclient.cpp
@@ -26,7 +26,7 @@
#include "vcsbaseclient.h"
#include "vcscommand.h"
#include "vcsbaseclientsettings.h"
-#include "vcsbaseeditorparameterwidget.h"
+#include "vcsbaseeditorconfig.h"
#include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h>
@@ -278,21 +278,21 @@ void VcsBaseClientImpl::saveSettings()
class VcsBaseClientPrivate
{
public:
- VcsBaseEditorParameterWidget *createDiffEditor();
- VcsBaseEditorParameterWidget *createLogEditor();
+ VcsBaseEditorConfig *createDiffEditor(VcsBaseEditorWidget *editor);
+ VcsBaseEditorConfig *createLogEditor(VcsBaseEditorWidget *editor);
- VcsBaseClient::ParameterWidgetCreator m_diffParamWidgetCreator;
- VcsBaseClient::ParameterWidgetCreator m_logParamWidgetCreator;
+ VcsBaseClient::ConfigCreator m_diffConfigCreator;
+ VcsBaseClient::ConfigCreator m_logConfigCreator;
};
-VcsBaseEditorParameterWidget *VcsBaseClientPrivate::createDiffEditor()
+VcsBaseEditorConfig *VcsBaseClientPrivate::createDiffEditor(VcsBaseEditorWidget *editor)
{
- return m_diffParamWidgetCreator ? m_diffParamWidgetCreator() : 0;
+ return m_diffConfigCreator ? m_diffConfigCreator(editor->toolBar()) : 0;
}
-VcsBaseEditorParameterWidget *VcsBaseClientPrivate::createLogEditor()
+VcsBaseEditorConfig *VcsBaseClientPrivate::createLogEditor(VcsBaseEditorWidget *editor)
{
- return m_logParamWidgetCreator ? m_logParamWidgetCreator() : 0;
+ return m_logConfigCreator ? m_logConfigCreator(editor->toolBar()) : 0;
}
VcsBaseClient::StatusItem::StatusItem(const QString &s, const QString &f) :
@@ -433,19 +433,21 @@ void VcsBaseClient::diff(const QString &workingDir, const QStringList &files,
vcsCmdString.toLatin1().constData(), id);
editor->setWorkingDirectory(workingDir);
- VcsBaseEditorParameterWidget *paramWidget = editor->configurationWidget();
- if (!paramWidget && (paramWidget = d->createDiffEditor())) {
- // editor has been just created, createVcsEditor() didn't set a configuration widget yet
- connect(editor, &VcsBaseEditorWidget::diffChunkReverted,
- paramWidget, &VcsBaseEditorParameterWidget::executeCommand);
- connect(paramWidget, &VcsBaseEditorParameterWidget::commandExecutionRequested,
- [=] { diff(workingDir, files, extraOptions); } );
- editor->setConfigurationWidget(paramWidget);
+ QStringList effectiveArgs = extraOptions;
+ if (!editor->configurationAdded()) {
+ if (VcsBaseEditorConfig *paramWidget = d->createDiffEditor(editor)) {
+ // editor has been just created, createVcsEditor() didn't set a configuration widget yet
+ connect(editor, &VcsBaseEditorWidget::diffChunkReverted,
+ paramWidget, &VcsBaseEditorConfig::executeCommand);
+ connect(paramWidget, &VcsBaseEditorConfig::commandExecutionRequested,
+ [=] { diff(workingDir, files, extraOptions + paramWidget->arguments()); } );
+ effectiveArgs = paramWidget->arguments();
+ editor->setConfigurationAdded();
+ }
}
QStringList args;
- const QStringList paramArgs = paramWidget != 0 ? paramWidget->arguments() : QStringList();
- args << vcsCmdString << extraOptions << paramArgs << files;
+ args << vcsCmdString << effectiveArgs << files;
QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VcsBaseEditor::getCodec(source);
VcsCommand *command = createCommand(workingDir, editor);
command->setCodec(codec);
@@ -466,17 +468,20 @@ void VcsBaseClient::log(const QString &workingDir, const QStringList &files,
vcsCmdString.toLatin1().constData(), id);
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
- VcsBaseEditorParameterWidget *paramWidget = editor->configurationWidget();
- if (!paramWidget && (paramWidget = d->createLogEditor())) {
- // editor has been just created, createVcsEditor() didn't set a configuration widget yet
- connect(paramWidget, &VcsBaseEditorParameterWidget::commandExecutionRequested,
- [=]() { this->log(workingDir, files, extraOptions, enableAnnotationContextMenu); } );
- editor->setConfigurationWidget(paramWidget);
+ QStringList effectiveArgs = extraOptions;
+ if (!editor->configurationAdded()) {
+ if (VcsBaseEditorConfig *paramWidget = d->createLogEditor(editor)) {
+ // editor has been just created, createVcsEditor() didn't set a configuration widget yet
+ connect(paramWidget, &VcsBaseEditorConfig::commandExecutionRequested,
+ [=]() { this->log(workingDir, files, extraOptions + paramWidget->arguments(),
+ enableAnnotationContextMenu); } );
+ effectiveArgs = paramWidget->arguments();
+ editor->setConfigurationAdded();
+ }
}
QStringList args;
- const QStringList paramArgs = paramWidget != 0 ? paramWidget->arguments() : QStringList();
- args << vcsCmdString << extraOptions << paramArgs << files;
+ args << vcsCmdString << effectiveArgs << files;
enqueueJob(createCommand(workingDir, editor), args);
}
@@ -556,14 +561,14 @@ Utils::ExitCodeInterpreter VcsBaseClient::exitCodeInterpreter(VcsCommandTag cmd)
return Utils::defaultExitCodeInterpreter;
}
-void VcsBaseClient::setDiffParameterWidgetCreator(ParameterWidgetCreator creator)
+void VcsBaseClient::setDiffConfigCreator(ConfigCreator creator)
{
- d->m_diffParamWidgetCreator = std::move(creator);
+ d->m_diffConfigCreator = std::move(creator);
}
-void VcsBaseClient::setLogParameterWidgetCreator(ParameterWidgetCreator creator)
+void VcsBaseClient::setLogConfigCreator(ConfigCreator creator)
{
- d->m_logParamWidgetCreator = std::move(creator);
+ d->m_logConfigCreator = std::move(creator);
}
void VcsBaseClient::import(const QString &repositoryRoot, const QStringList &files,
diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h
index 2c97afb076..d693a4357e 100644
--- a/src/plugins/vcsbase/vcsbaseclient.h
+++ b/src/plugins/vcsbase/vcsbaseclient.h
@@ -39,6 +39,7 @@
QT_BEGIN_NAMESPACE
class QFileInfo;
class QProcessEnvironment;
+class QToolBar;
QT_END_NAMESPACE
namespace Core { class Id; }
@@ -51,7 +52,7 @@ class VcsBaseClientSettings;
class VcsJob;
class VcsBaseClientImplPrivate;
class VcsBaseClientPrivate;
-class VcsBaseEditorParameterWidget;
+class VcsBaseEditorConfig;
class VCSBASE_EXPORT VcsBaseClientImpl : public QObject
{
@@ -227,9 +228,9 @@ protected:
virtual QStringList revisionSpec(const QString &revision) const = 0;
- typedef std::function<VcsBaseEditorParameterWidget *()> ParameterWidgetCreator;
- void setDiffParameterWidgetCreator(ParameterWidgetCreator creator);
- void setLogParameterWidgetCreator(ParameterWidgetCreator creator);
+ typedef std::function<VcsBaseEditorConfig *(QToolBar *)> ConfigCreator;
+ void setDiffConfigCreator(ConfigCreator creator);
+ void setLogConfigCreator(ConfigCreator creator);
virtual StatusItem parseStatusLine(const QString &line) const = 0;
diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp
index 6d6678f6fc..b179923112 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditor.cpp
@@ -28,7 +28,7 @@
#include "baseannotationhighlighter.h"
#include "basevcseditorfactory.h"
#include "vcsbaseplugin.h"
-#include "vcsbaseeditorparameterwidget.h"
+#include "vcsbaseeditorconfig.h"
#include "vcscommand.h"
#include <coreplugin/icore.h>
@@ -565,7 +565,7 @@ public:
QString m_annotateRevisionTextFormat;
QString m_annotatePreviousRevisionTextFormat;
QString m_copyRevisionTextFormat;
- VcsBaseEditorParameterWidget *m_configurationWidget = nullptr;
+ bool m_configurationAdded = false;
QList<AbstractTextCursorHandler *> m_textCursorHandlers;
QPointer<VcsCommand> m_command;
QObject *m_describeReceiver = nullptr;
@@ -1390,20 +1390,14 @@ QString VcsBaseEditor::getTitleId(const QString &workingDirectory,
return rc;
}
-bool VcsBaseEditorWidget::setConfigurationWidget(VcsBaseEditorParameterWidget *w)
+void VcsBaseEditorWidget::setConfigurationAdded()
{
- if (d->m_configurationWidget)
- return false;
-
- d->m_configurationWidget = w;
- insertExtraToolBarWidget(TextEditorWidget::Right, w);
-
- return true;
+ d->m_configurationAdded = true;
}
-VcsBaseEditorParameterWidget *VcsBaseEditorWidget::configurationWidget() const
+bool VcsBaseEditorWidget::configurationAdded() const
{
- return d->m_configurationWidget;
+ return d->m_configurationAdded;
}
void VcsBaseEditorWidget::setCommand(VcsCommand *command)
diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h
index d23eee46ff..4b765e1f53 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.h
+++ b/src/plugins/vcsbase/vcsbaseeditor.h
@@ -46,7 +46,7 @@ class VcsBaseEditorWidgetPrivate;
class BaseAnnotationHighlighter;
class VcsBaseEditorWidget;
-class VcsBaseEditorParameterWidget;
+class VcsBaseEditorConfig;
class VcsCommand;
// Documentation inside
@@ -209,8 +209,8 @@ public:
EditorContentType contentType() const;
- bool setConfigurationWidget(VcsBaseEditorParameterWidget *w);
- VcsBaseEditorParameterWidget *configurationWidget() const;
+ void setConfigurationAdded();
+ bool configurationAdded() const;
void setCommand(VcsCommand *command);
diff --git a/src/plugins/vcsbase/vcsbaseeditorparameterwidget.cpp b/src/plugins/vcsbase/vcsbaseeditorconfig.cpp
index bd4aaf5f7e..8ef9f506f6 100644
--- a/src/plugins/vcsbase/vcsbaseeditorparameterwidget.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditorconfig.cpp
@@ -23,10 +23,10 @@
**
****************************************************************************/
-#include "vcsbaseeditorparameterwidget.h"
+#include "vcsbaseeditorconfig.h"
#include <QComboBox>
-#include <QToolButton>
+#include <QAction>
#include <QHBoxLayout>
#include <QStringList>
@@ -74,66 +74,65 @@ private:
Type m_type;
};
-class VcsBaseEditorParameterWidgetPrivate
+class VcsBaseEditorConfigPrivate
{
public:
- VcsBaseEditorParameterWidgetPrivate() :
- m_layout(0)
- { }
+ VcsBaseEditorConfigPrivate(QToolBar *toolBar) : m_toolBar(toolBar)
+ {
+ if (!toolBar)
+ return;
+ toolBar->setContentsMargins(3, 0, 3, 0);
+ toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ }
QStringList m_baseArguments;
- QHBoxLayout *m_layout;
- QList<VcsBaseEditorParameterWidget::OptionMapping> m_optionMappings;
- QHash<QWidget*, SettingMappingData> m_settingMapping;
+ QList<VcsBaseEditorConfig::OptionMapping> m_optionMappings;
+ QHash<QObject *, SettingMappingData> m_settingMapping;
+ QToolBar *m_toolBar;
};
} // namespace Internal
/*!
- \class VcsBase::VcsBaseEditorParameterWidget
+ \class VcsBase::VcsBaseEditorConfig
- \brief The VcsBaseEditorParameterWidget is a toolbar-like widget for use
- with VcsBase::VcsBaseEditor::setConfigurationWidget()
- influencing for example the generation of VCS diff output.
+ \brief The VcsBaseEditorConfig is a widget/action aggregator for use
+ with VcsBase::VcsBaseEditor, influencing for example the generation of VCS diff output.
- The widget maintains a list of command line arguments (starting from baseArguments())
+ The class maintains a list of command line arguments (starting from baseArguments())
which are set according to the state of the inside widgets. A change signal is provided
that should trigger the rerun of the VCS operation.
*/
-VcsBaseEditorParameterWidget::ComboBoxItem::ComboBoxItem(const QString &text,
- const QVariant &val) :
+VcsBaseEditorConfig::ComboBoxItem::ComboBoxItem(const QString &text, const QVariant &val) :
displayText(text),
value(val)
{
}
-VcsBaseEditorParameterWidget::VcsBaseEditorParameterWidget(QWidget *parent) :
- QWidget(parent), d(new Internal::VcsBaseEditorParameterWidgetPrivate)
+VcsBaseEditorConfig::VcsBaseEditorConfig(QToolBar *toolBar) :
+ QObject(toolBar), d(new Internal::VcsBaseEditorConfigPrivate(toolBar))
{
- d->m_layout = new QHBoxLayout(this);
- d->m_layout->setContentsMargins(3, 0, 3, 0);
- d->m_layout->setSpacing(2);
- connect(this, &VcsBaseEditorParameterWidget::argumentsChanged,
- this, &VcsBaseEditorParameterWidget::handleArgumentsChanged);
+ connect(this, &VcsBaseEditorConfig::argumentsChanged,
+ this, &VcsBaseEditorConfig::handleArgumentsChanged);
}
-VcsBaseEditorParameterWidget::~VcsBaseEditorParameterWidget()
+VcsBaseEditorConfig::~VcsBaseEditorConfig()
{
delete d;
}
-QStringList VcsBaseEditorParameterWidget::baseArguments() const
+QStringList VcsBaseEditorConfig::baseArguments() const
{
return d->m_baseArguments;
}
-void VcsBaseEditorParameterWidget::setBaseArguments(const QStringList &b)
+void VcsBaseEditorConfig::setBaseArguments(const QStringList &b)
{
d->m_baseArguments = b;
}
-QStringList VcsBaseEditorParameterWidget::arguments() const
+QStringList VcsBaseEditorConfig::arguments() const
{
// Compile effective arguments
QStringList args = baseArguments();
@@ -142,39 +141,42 @@ QStringList VcsBaseEditorParameterWidget::arguments() const
return args;
}
-QToolButton *VcsBaseEditorParameterWidget::addToggleButton(const QString &option,
- const QString &label,
- const QString &tooltip)
+QAction *VcsBaseEditorConfig::addToggleButton(const QString &option,
+ const QString &label,
+ const QString &tooltip)
{
return addToggleButton(option.isEmpty() ? QStringList() : QStringList(option), label, tooltip);
}
-QToolButton *VcsBaseEditorParameterWidget::addToggleButton(const QStringList &options, const QString &label, const QString &tooltip)
+QAction *VcsBaseEditorConfig::addToggleButton(const QStringList &options,
+ const QString &label,
+ const QString &tooltip)
{
- auto tb = new QToolButton;
- tb->setText(label);
- tb->setToolTip(tooltip);
- tb->setCheckable(true);
- connect(tb, &QToolButton::toggled, this, &VcsBaseEditorParameterWidget::argumentsChanged);
- d->m_layout->addWidget(tb);
- d->m_optionMappings.append(OptionMapping(options, tb));
- return tb;
+ auto action = new QAction(label, d->m_toolBar);
+ action->setToolTip(tooltip);
+ action->setCheckable(true);
+ connect(action, &QAction::toggled, this, &VcsBaseEditorConfig::argumentsChanged);
+ const QList<QAction *> actions = d->m_toolBar->actions();
+ // Insert the action before line/column and split actions.
+ d->m_toolBar->insertAction(actions.at(qMax(actions.count() - 2, 0)), action);
+ d->m_optionMappings.append(OptionMapping(options, action));
+ return action;
}
-QComboBox *VcsBaseEditorParameterWidget::addComboBox(const QStringList &options,
- const QList<ComboBoxItem> &items)
+QComboBox *VcsBaseEditorConfig::addComboBox(const QStringList &options,
+ const QList<ComboBoxItem> &items)
{
auto cb = new QComboBox;
foreach (const ComboBoxItem &item, items)
cb->addItem(item.displayText, item.value);
connect(cb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
- this, &VcsBaseEditorParameterWidget::argumentsChanged);
- d->m_layout->addWidget(cb);
+ this, &VcsBaseEditorConfig::argumentsChanged);
+ d->m_toolBar->addWidget(cb);
d->m_optionMappings.append(OptionMapping(options, cb));
return cb;
}
-void VcsBaseEditorParameterWidget::mapSetting(QToolButton *button, bool *setting)
+void VcsBaseEditorConfig::mapSetting(QAction *button, bool *setting)
{
if (!d->m_settingMapping.contains(button) && button) {
d->m_settingMapping.insert(button, Internal::SettingMappingData(setting));
@@ -186,7 +188,7 @@ void VcsBaseEditorParameterWidget::mapSetting(QToolButton *button, bool *setting
}
}
-void VcsBaseEditorParameterWidget::mapSetting(QComboBox *comboBox, QString *setting)
+void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, QString *setting)
{
if (!d->m_settingMapping.contains(comboBox) && comboBox) {
d->m_settingMapping.insert(comboBox, Internal::SettingMappingData(setting));
@@ -200,7 +202,7 @@ void VcsBaseEditorParameterWidget::mapSetting(QComboBox *comboBox, QString *sett
}
}
-void VcsBaseEditorParameterWidget::mapSetting(QComboBox *comboBox, int *setting)
+void VcsBaseEditorConfig::mapSetting(QComboBox *comboBox, int *setting)
{
if (d->m_settingMapping.contains(comboBox) || !comboBox)
return;
@@ -215,42 +217,42 @@ void VcsBaseEditorParameterWidget::mapSetting(QComboBox *comboBox, int *setting)
comboBox->blockSignals(false);
}
-void VcsBaseEditorParameterWidget::handleArgumentsChanged()
+void VcsBaseEditorConfig::handleArgumentsChanged()
{
updateMappedSettings();
executeCommand();
}
-void VcsBaseEditorParameterWidget::executeCommand()
+void VcsBaseEditorConfig::executeCommand()
{
emit commandExecutionRequested();
}
-VcsBaseEditorParameterWidget::OptionMapping::OptionMapping(const QString &option, QWidget *w) :
- widget(w)
+VcsBaseEditorConfig::OptionMapping::OptionMapping(const QString &option, QObject *obj) :
+ object(obj)
{
if (!option.isEmpty())
options << option;
}
-VcsBaseEditorParameterWidget::OptionMapping::OptionMapping(const QStringList &optionList, QWidget *w) :
+VcsBaseEditorConfig::OptionMapping::OptionMapping(const QStringList &optionList, QObject *obj) :
options(optionList),
- widget(w)
+ object(obj)
{
}
-const QList<VcsBaseEditorParameterWidget::OptionMapping> &VcsBaseEditorParameterWidget::optionMappings() const
+const QList<VcsBaseEditorConfig::OptionMapping> &VcsBaseEditorConfig::optionMappings() const
{
return d->m_optionMappings;
}
-QStringList VcsBaseEditorParameterWidget::argumentsForOption(const OptionMapping &mapping) const
+QStringList VcsBaseEditorConfig::argumentsForOption(const OptionMapping &mapping) const
{
- const QToolButton *tb = qobject_cast<const QToolButton *>(mapping.widget);
- if (tb && tb->isChecked())
+ const QAction *action = qobject_cast<const QAction *>(mapping.object);
+ if (action && action->isChecked())
return mapping.options;
- const QComboBox *cb = qobject_cast<const QComboBox *>(mapping.widget);
+ const QComboBox *cb = qobject_cast<const QComboBox *>(mapping.object);
if (cb) {
const QString value = cb->itemData(cb->currentIndex()).toString();
QStringList args;
@@ -262,29 +264,28 @@ QStringList VcsBaseEditorParameterWidget::argumentsForOption(const OptionMapping
return QStringList();
}
-void VcsBaseEditorParameterWidget::updateMappedSettings()
+void VcsBaseEditorConfig::updateMappedSettings()
{
foreach (const OptionMapping &optMapping, d->m_optionMappings) {
- if (d->m_settingMapping.contains(optMapping.widget)) {
- Internal::SettingMappingData& settingData = d->m_settingMapping[optMapping.widget];
+ if (d->m_settingMapping.contains(optMapping.object)) {
+ Internal::SettingMappingData& settingData = d->m_settingMapping[optMapping.object];
switch (settingData.type()) {
case Internal::SettingMappingData::Bool :
{
- const QToolButton *tb = qobject_cast<const QToolButton *>(optMapping.widget);
- if (tb)
- *settingData.boolSetting = tb->isChecked();
+ if (auto action = qobject_cast<const QAction *>(optMapping.object))
+ *settingData.boolSetting = action->isChecked();
break;
}
case Internal::SettingMappingData::String :
{
- const QComboBox *cb = qobject_cast<const QComboBox *>(optMapping.widget);
+ const QComboBox *cb = qobject_cast<const QComboBox *>(optMapping.object);
if (cb && cb->currentIndex() != -1)
*settingData.stringSetting = cb->itemData(cb->currentIndex()).toString();
break;
}
case Internal::SettingMappingData::Int:
{
- const QComboBox *cb = qobject_cast<const QComboBox *>(optMapping.widget);
+ const QComboBox *cb = qobject_cast<const QComboBox *>(optMapping.object);
if (cb && cb->currentIndex() != -1)
*settingData.intSetting = cb->currentIndex();
break;
diff --git a/src/plugins/vcsbase/vcsbaseeditorparameterwidget.h b/src/plugins/vcsbase/vcsbaseeditorconfig.h
index 2152f714b5..d019b79d47 100644
--- a/src/plugins/vcsbase/vcsbaseeditorparameterwidget.h
+++ b/src/plugins/vcsbase/vcsbaseeditorconfig.h
@@ -28,7 +28,7 @@
#include "vcsbase_global.h"
#include <QVariant>
-#include <QWidget>
+#include <QToolBar>
QT_BEGIN_NAMESPACE
class QComboBox;
@@ -38,16 +38,18 @@ QT_END_NAMESPACE
namespace VcsBase {
-namespace Internal { class VcsBaseEditorParameterWidgetPrivate; }
+class VcsBaseEditorWidget;
+
+namespace Internal { class VcsBaseEditorConfigPrivate; }
// Documentation->inside.
-class VCSBASE_EXPORT VcsBaseEditorParameterWidget : public QWidget
+class VCSBASE_EXPORT VcsBaseEditorConfig : public QObject
{
Q_OBJECT
public:
- explicit VcsBaseEditorParameterWidget(QWidget *parent = 0);
- ~VcsBaseEditorParameterWidget() override;
+ explicit VcsBaseEditorConfig(QToolBar *toolBar);
+ ~VcsBaseEditorConfig() override;
class VCSBASE_EXPORT ComboBoxItem
{
@@ -61,13 +63,13 @@ public:
QStringList baseArguments() const;
void setBaseArguments(const QStringList &);
- QToolButton *addToggleButton(const QString &option, const QString &label,
- const QString &tooltip = QString());
- QToolButton *addToggleButton(const QStringList &options, const QString &label,
- const QString &tooltip = QString());
+ QAction *addToggleButton(const QString &option, const QString &label,
+ const QString &tooltip = QString());
+ QAction *addToggleButton(const QStringList &options, const QString &label,
+ const QString &tooltip = QString());
QComboBox *addComboBox(const QStringList &options, const QList<ComboBoxItem> &items);
- void mapSetting(QToolButton *button, bool *setting);
+ void mapSetting(QAction *button, bool *setting);
void mapSetting(QComboBox *comboBox, QString *setting);
void mapSetting(QComboBox *comboBox, int *setting);
@@ -89,10 +91,10 @@ protected:
{
public:
OptionMapping() = default;
- OptionMapping(const QString &option, QWidget *w);
- OptionMapping(const QStringList &optionList, QWidget *w);
+ OptionMapping(const QString &option, QObject *obj);
+ OptionMapping(const QStringList &optionList, QObject *obj);
QStringList options;
- QWidget *widget = nullptr;
+ QObject *object = nullptr;
};
const QList<OptionMapping> &optionMappings() const;
@@ -100,8 +102,8 @@ protected:
void updateMappedSettings();
private:
- friend class Internal::VcsBaseEditorParameterWidgetPrivate;
- Internal::VcsBaseEditorParameterWidgetPrivate *const d;
+ friend class Internal::VcsBaseEditorConfigPrivate;
+ Internal::VcsBaseEditorConfigPrivate *const d;
};
} // namespace VcsBase