diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 686d93996fe..ab4717b2b00 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -30,11 +30,11 @@ #include "builddirmanager.h" #include "cmakebuildtarget.h" #include "cmakeprojectimporter.h" -#include "treescanner.h" #include -#include #include +#include +#include #include @@ -108,7 +108,7 @@ private: CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; QList m_extraCompilers; - Internal::TreeScanner m_treeScanner; + ProjectExplorer::TreeScanner m_treeScanner; Internal::BuildDirManager m_buildDirManager; bool m_waitingForScan = false; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro index c81dd01df9e..6f5ca828860 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro @@ -35,8 +35,7 @@ HEADERS = builddirmanager.h \ configmodelitemdelegate.h \ servermode.h \ servermodereader.h \ - tealeafreader.h \ - treescanner.h + tealeafreader.h SOURCES = builddirmanager.cpp \ builddirparameters.cpp \ @@ -70,8 +69,7 @@ SOURCES = builddirmanager.cpp \ configmodelitemdelegate.cpp \ servermode.cpp \ servermodereader.cpp \ - tealeafreader.cpp \ - treescanner.cpp \ + tealeafreader.cpp RESOURCES += cmakeproject.qrc diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index c71a0fd821f..e8baa388e76 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -88,8 +88,6 @@ QtcPlugin { "servermodereader.cpp", "servermodereader.h", "tealeafreader.cpp", - "tealeafreader.h", - "treescanner.cpp", - "treescanner.h", + "tealeafreader.h" ] } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 0a274e8bf02..351917f019c 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -29,9 +29,10 @@ #include "compilationdatabaseutils.h" #include -#include +#include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include +#include #include #include #include @@ -283,13 +285,17 @@ FileType fileTypeForName(const QString &fileName) void createTree(FolderNode *root, const Utils::FileName &rootPath, - const CppTools::RawProjectParts &rpps) + const CppTools::RawProjectParts &rpps, + const QList &scannedFiles = QList()) { root->setAbsoluteFilePathAndLine(rootPath, -1); for (const CppTools::RawProjectPart &rpp : rpps) { for (const QString &filePath : rpp.files) { Utils::FileName fileName = Utils::FileName::fromString(filePath); + if (!fileName.isChildOf(rootPath)) + continue; + FolderNode *parentNode = createFoldersIfNeeded(root, fileName.parentDir()); if (!parentNode->fileNode(fileName)) { parentNode->addNode(std::make_unique(fileName, @@ -297,6 +303,22 @@ void createTree(FolderNode *root, } } } + + for (FileNode *node : scannedFiles) { + if (node->fileType() != FileType::Header) + continue; + + const Utils::FileName fileName = node->filePath(); + if (!fileName.isChildOf(rootPath)) + continue; + FolderNode *parentNode = createFoldersIfNeeded(root, fileName.parentDir()); + if (!parentNode->fileNode(fileName)) { + std::unique_ptr headerNode(node->clone()); + headerNode->setEnabled(false); + parentNode->addNode(std::move(headerNode)); + } + } + qDeleteAll(scannedFiles); } struct Entry @@ -354,7 +376,6 @@ void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName CppTools::KitInfo kitInfo(this); QTC_ASSERT(kitInfo.isValid(), return); CppTools::RawProjectParts rpps; - Utils::FileName commonPath; std::sort(array.begin(), array.end(), [](const Entry &lhs, const Entry &rhs) { return std::lexicographical_compare(lhs.flags.begin(), lhs.flags.end(), @@ -370,10 +391,6 @@ void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName prevEntry = &entry; - commonPath = rpps.empty() - ? entry.fileName.parentDir() - : Utils::FileUtils::commonPath(commonPath, entry.fileName); - CppTools::RawProjectPart rpp = makeRawProjectPart(projectFile, m_kit.get(), kitInfo.cToolChain, @@ -385,7 +402,13 @@ void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName rpps.append(rpp); } - createTree(root.get(), commonPath, rpps); + m_treeScanner.future().waitForFinished(); + QCoreApplication::processEvents(); + + if (m_treeScanner.future().isCanceled()) + createTree(root.get(), rootProjectDirectory(), rpps); + else + createTree(root.get(), rootProjectDirectory(), rpps, m_treeScanner.release()); root->addNode(std::make_unique(projectFile, FileType::Project)); @@ -407,7 +430,6 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &pr setPreferredKitPredicate([](const Kit *) { return false; }); m_kit.reset(KitManager::defaultKit()->clone()); - connect(this, &CompilationDatabaseProject::parsingFinished, this, [this]() { if (!m_hasTarget) { addTarget(createTarget(m_kit.get())); @@ -415,22 +437,75 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &pr } }); - reparseProject(projectFile); + m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FileName &fn) { + // Mime checks requires more resources, so keep it last in check list + auto isIgnored = fn.toString().startsWith(projectFilePath().toString() + ".user") + || TreeScanner::isWellKnownBinary(mimeType, fn); + + // Cache mime check result for speed up + if (!isIgnored) { + auto it = m_mimeBinaryCache.find(mimeType.name()); + if (it != m_mimeBinaryCache.end()) { + isIgnored = *it; + } else { + isIgnored = TreeScanner::isMimeBinary(mimeType, fn); + m_mimeBinaryCache[mimeType.name()] = isIgnored; + } + } + + return isIgnored; + }); + m_treeScanner.setTypeFactory([](const Utils::MimeType &mimeType, const Utils::FileName &fn) { + return TreeScanner::genericFileType(mimeType, fn); + }); + + connect(this, + &CompilationDatabaseProject::rootProjectDirectoryChanged, + this, + &CompilationDatabaseProject::reparseProject); m_fileSystemWatcher.addFile(projectFile.toString(), Utils::FileSystemWatcher::WatchModifiedDate); connect(&m_fileSystemWatcher, &Utils::FileSystemWatcher::fileChanged, this, - [this](const QString &projectFile) { - reparseProject(Utils::FileName::fromString(projectFile)); - }); + &CompilationDatabaseProject::reparseProject); } -void CompilationDatabaseProject::reparseProject(const Utils::FileName &projectFile) +Project::RestoreResult CompilationDatabaseProject::fromMap(const QVariantMap &map, + QString *errorMessage) +{ + Project::RestoreResult result = Project::fromMap(map, errorMessage); + if (result == Project::RestoreResult::Ok) { + const Utils::FileName rootPath = Utils::FileName::fromString( + namedSettings(ProjectExplorer::Constants::PROJECT_ROOT_PATH_KEY).toString()); + if (rootPath.isEmpty()) + changeRootProjectDirectory(); // This triggers reparse itself. + else + reparseProject(); + } + + return result; +} + +void CompilationDatabaseProject::reparseProject() { emitParsingStarted(); + + const Utils::FileName rootPath = Utils::FileName::fromString( + namedSettings(ProjectExplorer::Constants::PROJECT_ROOT_PATH_KEY).toString()); + if (!rootPath.isEmpty()) { + m_treeScanner.asyncScanForFiles(rootPath); + + Core::ProgressManager::addTask(m_treeScanner.future(), + tr("Scan \"%1\" project tree").arg(displayName()), + "CompilationDatabase.Scan.Tree"); + } + const QFuture future = ::Utils::runAsync( - [this, projectFile]() { buildTreeAndProjectParts(projectFile); }); + [this]() { buildTreeAndProjectParts(projectFilePath()); }); + Core::ProgressManager::addTask(future, + tr("Parse \"%1\" project").arg(displayName()), + "CompilationDatabase.Parse"); m_parserWatcher.setFuture(future); } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h index 5b6fc0a1167..de887e54632 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include #include @@ -35,7 +36,9 @@ namespace CppTools { class CppProjectUpdater; } -namespace ProjectExplorer { class Kit; } +namespace ProjectExplorer { +class Kit; +} namespace CompilationDatabaseProjectManager { namespace Internal { @@ -51,13 +54,16 @@ public: bool needsBuildConfigurations() const override { return false; } private: - void reparseProject(const Utils::FileName &projectFile); + RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; + void reparseProject(); void buildTreeAndProjectParts(const Utils::FileName &projectFile); QFutureWatcher m_parserWatcher; std::unique_ptr m_cppCodeModelUpdater; std::unique_ptr m_kit; Utils::FileSystemWatcher m_fileSystemWatcher; + ProjectExplorer::TreeScanner m_treeScanner; + QHash m_mimeBinaryCache; bool m_hasTarget = false; }; diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp index 77359adc70d..6ba1d6e4258 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp @@ -29,13 +29,21 @@ #include "compilationdatabaseproject.h" #include "compilationdatabasetests.h" +#include +#include +#include #include +#include #include +#include +#include #include namespace CompilationDatabaseProjectManager { namespace Internal { +const char CHANGEROOTDIR[] = "CompilationDatabaseProjectManager.ChangeRootDirectory"; + bool CompilationDatabaseProjectManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments); @@ -45,10 +53,39 @@ bool CompilationDatabaseProjectManagerPlugin::initialize(const QStringList &argu ProjectExplorer::ProjectManager::registerProjectType( Constants::COMPILATIONDATABASEMIMETYPE); + m_changeProjectRootDirectoryAction = new QAction(tr("Change Root Directory"), this); + Core::Command *cmd = Core::ActionManager::registerAction(m_changeProjectRootDirectoryAction, + CHANGEROOTDIR); + Core::ActionContainer *mprojectContextMenu = Core::ActionManager::actionContainer( + ProjectExplorer::Constants::M_PROJECTCONTEXT); + mprojectContextMenu->addSeparator(ProjectExplorer::Constants::G_PROJECT_TREE); + mprojectContextMenu->addAction(cmd, ProjectExplorer::Constants::G_PROJECT_TREE); + + connect(m_changeProjectRootDirectoryAction, + &QAction::triggered, + ProjectExplorer::ProjectTree::instance(), + &ProjectExplorer::ProjectTree::changeProjectRootDirectory); + + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, + this, + &CompilationDatabaseProjectManagerPlugin::projectChanged); + connect(ProjectExplorer::ProjectTree::instance(), + &ProjectExplorer::ProjectTree::currentProjectChanged, + this, + &CompilationDatabaseProjectManagerPlugin::projectChanged); return true; } +void CompilationDatabaseProjectManagerPlugin::projectChanged() +{ + const auto *currentProject = qobject_cast( + ProjectExplorer::ProjectTree::currentProject()); + + m_changeProjectRootDirectoryAction->setEnabled(currentProject); +} + void CompilationDatabaseProjectManagerPlugin::extensionsInitialized() { } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h index 37c9c1db1d8..e3b56392b19 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h @@ -43,9 +43,12 @@ public: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final; private: + void projectChanged(); + QList createTestObjects() const final; CompilationDatabaseEditorFactory factory; + QAction *m_changeProjectRootDirectoryAction; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 4c3f867c515..a439beecc71 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -51,6 +51,8 @@ #include #include +#include + #include #include @@ -177,6 +179,7 @@ public: Kit::Predicate m_preferredKitPredicate; Utils::MacroExpander m_macroExpander; + Utils::FileName m_rootProjectDirectory; mutable QVector m_sortedNodeList; }; @@ -653,13 +656,30 @@ Utils::FileName Project::projectDirectory(const Utils::FileName &top) return Utils::FileName::fromString(top.toFileInfo().absoluteDir().path()); } +void Project::changeRootProjectDirectory() +{ + Utils::FileName rootPath = Utils::FileName::fromString( + QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), + tr("Select The Root Directory"), + rootProjectDirectory().toString(), + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks)); + if (rootPath != d->m_rootProjectDirectory) { + d->m_rootProjectDirectory = rootPath; + setNamedSettings(Constants::PROJECT_ROOT_PATH_KEY, d->m_rootProjectDirectory.toString()); + emit rootProjectDirectoryChanged(); + } +} + /*! Returns the common root directory that contains all files which belongs to a project. */ - Utils::FileName Project::rootProjectDirectory() const { - return projectDirectory(); // TODO parse all files and find the common path + if (!d->m_rootProjectDirectory.isEmpty()) + return d->m_rootProjectDirectory; + + return projectDirectory(); } ProjectNode *Project::rootProjectNode() const @@ -701,6 +721,9 @@ Project::RestoreResult Project::fromMap(const QVariantMap &map, QString *errorMe createTargetFromMap(map, i); } + d->m_rootProjectDirectory = Utils::FileName::fromString( + namedSettings(Constants::PROJECT_ROOT_PATH_KEY).toString()); + return RestoreResult::Ok; } diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index cf9590ad68d..0709bb5e266 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -102,9 +102,12 @@ public: Core::IDocument *document() const; Utils::FileName projectFilePath() const; Utils::FileName projectDirectory() const; - Utils::FileName rootProjectDirectory() const; static Utils::FileName projectDirectory(const Utils::FileName &top); + // This does not affect nodes, only the root path. + void changeRootProjectDirectory(); + Utils::FileName rootProjectDirectory() const; + virtual ProjectNode *rootProjectNode() const; ContainerNode *containerNode() const; @@ -221,6 +224,8 @@ signals: void parsingStarted(); void parsingFinished(bool success); + void rootProjectDirectoryChanged(); + protected: virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage); void createTargetFromMap(const QVariantMap &map, int index); diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index b92429c9a97..9ab35606067 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -160,7 +160,8 @@ HEADERS += projectexplorer.h \ customexecutablerunconfiguration.h \ projectmacro.h \ makestep.h \ - projectconfigurationaspects.h + projectconfigurationaspects.h \ + treescanner.h SOURCES += projectexplorer.cpp \ abi.cpp \ @@ -302,7 +303,8 @@ SOURCES += projectexplorer.cpp \ customexecutablerunconfiguration.cpp \ projectmacro.cpp \ makestep.cpp \ - projectconfigurationaspects.cpp + projectconfigurationaspects.cpp \ + treescanner.cpp FORMS += processstep.ui \ editorsettingspropertiespage.ui \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 40655911808..de200f7619f 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -153,6 +153,7 @@ Project { "toolchainmanager.cpp", "toolchainmanager.h", "toolchainoptionspage.cpp", "toolchainoptionspage.h", "toolchainsettingsaccessor.cpp", "toolchainsettingsaccessor.h", + "treescanner.cpp", "treescanner.h", "userfileaccessor.cpp", "userfileaccessor.h", "vcsannotatetaskhandler.cpp", "vcsannotatetaskhandler.h", "waitforstopdialog.cpp", "waitforstopdialog.h", diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 2732fca6177..ab8d72b140b 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -214,6 +214,7 @@ const char FILEOVERLAY_PY[]=":/projectexplorer/images/fileoverlay_py.png"; const char FILEOVERLAY_UNKNOWN[]=":/projectexplorer/images/fileoverlay_unknown.png"; const char ADD_FILES_DIALOG_FILTER_HISTORY_KEY[] = "ProjectExplorer.AddFilesFilterKey"; +const char PROJECT_ROOT_PATH_KEY[] = "ProjectExplorer.Project.RootPath"; } // namespace Constants } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index 6b00620b8aa..b7b0ef3b7ec 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -283,6 +283,12 @@ void ProjectTree::expandAll() w->expandAll(); } +void ProjectTree::changeProjectRootDirectory() +{ + if (m_currentProject) + m_currentProject->changeRootProjectDirectory(); +} + void ProjectTree::updateExternalFileWarning() { auto document = qobject_cast(sender()); diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h index 238c55a9109..73234ab2a00 100644 --- a/src/plugins/projectexplorer/projecttree.h +++ b/src/plugins/projectexplorer/projecttree.h @@ -81,6 +81,8 @@ public: void collapseAll(); void expandAll(); + void changeProjectRootDirectory(); + // for nodes to emit signals, do not call unless you are a node static void emitSubtreeChanged(FolderNode *node); diff --git a/src/plugins/cmakeprojectmanager/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp similarity index 96% rename from src/plugins/cmakeprojectmanager/treescanner.cpp rename to src/plugins/projectexplorer/treescanner.cpp index b1719b49e6c..9c4803cc9d6 100644 --- a/src/plugins/cmakeprojectmanager/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -24,10 +24,10 @@ ****************************************************************************/ #include "treescanner.h" +#include "projectexplorerconstants.h" #include #include -#include #include @@ -37,10 +37,7 @@ #include -using namespace ProjectExplorer; - -namespace CMakeProjectManager { -namespace Internal { +namespace ProjectExplorer { TreeScanner::TreeScanner(QObject *parent) : QObject(parent) { @@ -176,5 +173,4 @@ void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& direc fip->reportFinished(); } -} // namespace Internal -} // namespace CMakeProjectManager +} // namespace ProjectExplorer diff --git a/src/plugins/cmakeprojectmanager/treescanner.h b/src/plugins/projectexplorer/treescanner.h similarity index 94% rename from src/plugins/cmakeprojectmanager/treescanner.h rename to src/plugins/projectexplorer/treescanner.h index bf9872f6df0..f2bb9876a36 100644 --- a/src/plugins/cmakeprojectmanager/treescanner.h +++ b/src/plugins/projectexplorer/treescanner.h @@ -25,7 +25,8 @@ #pragma once -#include "projectexplorer/projectnodes.h" +#include "projectexplorer_export.h" +#include "projectnodes.h" #include #include @@ -38,10 +39,9 @@ namespace Core { class IVersionControl; } -namespace CMakeProjectManager { -namespace Internal { +namespace ProjectExplorer { -class TreeScanner : public QObject +class PROJECTEXPLORER_EXPORT TreeScanner : public QObject { Q_OBJECT @@ -98,7 +98,4 @@ private: Future m_scanFuture; }; -} // namespace Internal -} // namespace CMakeProjectManager - - +} // namespace ProjectExplorer