From 11f989bb93b055684948220637d5a1fc590534e7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 19 Feb 2019 18:06:10 +0100 Subject: [PATCH] ProjectExplorer: Allow to add existing project as sub-project Implemented only for qmake as of now. Fixes: QTCREATORBUG-5837 Change-Id: I78f6ce55d6a149a75ae595f7a86d39dc55496819 Reviewed-by: hjk --- .../projectexplorer/projectexplorer.cpp | 54 +++++++++++++++++++ src/plugins/projectexplorer/projectnodes.cpp | 5 ++ src/plugins/projectexplorer/projectnodes.h | 2 + .../qmakeprojectmanager/qmakenodes.cpp | 7 ++- src/plugins/qmakeprojectmanager/qmakenodes.h | 2 +- 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 0e78a50abcc..184730c76e7 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -351,6 +351,7 @@ public: void handleAddExistingFiles(); void addExistingDirectory(); void addNewSubproject(); + void addExistingProjects(); void removeProject(); void openFile(); void searchOnFileSystem(); @@ -433,6 +434,7 @@ public: QAction *m_addExistingFilesAction; QAction *m_addExistingDirectoryAction; QAction *m_addNewSubprojectAction; + QAction *m_addExistingProjectsAction; QAction *m_removeFileAction; QAction *m_duplicateFileAction; QAction *m_removeProjectAction; @@ -1127,6 +1129,13 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er msubProjectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES); mfolderContextMenu->addAction(cmd, Constants::G_FOLDER_FILES); + // add existing projects action + dd->m_addExistingProjectsAction = new QAction(tr("Add Existing Projects..."), this); + cmd = ActionManager::registerAction(dd->m_addExistingProjectsAction, + "ProjectExplorer.AddExistingProjects", projecTreeContext); + mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES); + msubProjectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES); + // add existing directory action dd->m_addExistingDirectoryAction = new QAction(tr("Add Existing Directory..."), this); cmd = ActionManager::registerAction(dd->m_addExistingDirectoryAction, @@ -1434,6 +1443,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd, &ProjectExplorerPluginPrivate::addExistingDirectory); connect(dd->m_addNewSubprojectAction, &QAction::triggered, dd, &ProjectExplorerPluginPrivate::addNewSubproject); + connect(dd->m_addExistingProjectsAction, &QAction::triggered, + dd, &ProjectExplorerPluginPrivate::addExistingProjects); connect(dd->m_removeProjectAction, &QAction::triggered, dd, &ProjectExplorerPluginPrivate::removeProject); connect(dd->m_openFileAction, &QAction::triggered, @@ -3115,6 +3126,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions() m_addExistingDirectoryAction->setEnabled(false); m_addNewFileAction->setEnabled(false); m_addNewSubprojectAction->setEnabled(false); + m_addExistingProjectsAction->setEnabled(false); m_removeProjectAction->setEnabled(false); m_removeFileAction->setEnabled(false); m_duplicateFileAction->setEnabled(false); @@ -3126,6 +3138,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions() m_addExistingDirectoryAction->setVisible(true); m_addNewFileAction->setVisible(true); m_addNewSubprojectAction->setVisible(true); + m_addExistingProjectsAction->setVisible(true); m_removeProjectAction->setVisible(true); m_removeFileAction->setVisible(true); m_duplicateFileAction->setVisible(false); @@ -3196,6 +3209,8 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions() m_addNewSubprojectAction->setEnabled(currentNode->nodeType() == NodeType::Project && supports(AddSubProject) && !ICore::isNewItemDialogRunning()); + m_addExistingProjectsAction->setEnabled(currentNode->nodeType() == NodeType::Project + && supports(AddExistingProject)); m_removeProjectAction->setEnabled(currentNode->nodeType() == NodeType::Project && supports(RemoveSubProject)); m_addExistingFilesAction->setEnabled(supports(AddExistingFile)); @@ -3241,6 +3256,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions() if (supports(HideFolderActions)) { m_addNewFileAction->setVisible(false); m_addNewSubprojectAction->setVisible(false); + m_addExistingProjectsAction->setVisible(false); m_removeProjectAction->setVisible(false); m_addExistingFilesAction->setVisible(false); m_addExistingDirectoryAction->setVisible(false); @@ -3342,6 +3358,44 @@ void ProjectExplorerPluginPrivate::addNewSubproject() } } +void ProjectExplorerPluginPrivate::addExistingProjects() +{ + Node * const currentNode = ProjectTree::findCurrentNode(); + QTC_ASSERT(currentNode, return); + ProjectNode *projectNode = currentNode->asProjectNode(); + if (!projectNode && currentNode->asContainerNode()) + projectNode = currentNode->asContainerNode()->rootProjectNode(); + QTC_ASSERT(projectNode, return); + const QString dir = directoryFor(currentNode); + QStringList subProjectFilePaths = QFileDialog::getOpenFileNames( + ICore::mainWindow(), tr("Please choose a project file"), dir, + projectNode->subProjectFileNamePatterns().join(";;")); + const QList childNodes = projectNode->nodes(); + Utils::erase(subProjectFilePaths, [childNodes](const QString &filePath) { + return Utils::anyOf(childNodes, [filePath](const Node *n) { + return n->filePath().toString() == filePath; + }); + }); + if (subProjectFilePaths.empty()) + return; + QStringList failedProjects; + QStringList addedProjects; + for (const QString &filePath : subProjectFilePaths) { + if (projectNode->addSubProject(filePath)) + addedProjects << filePath; + else + failedProjects << filePath; + } + if (!failedProjects.empty()) { + const QString message = tr("The following subprojects could not be added to project " + "\"%2\":").arg(projectNode->managingProject()->displayName()); + QMessageBox::warning(ICore::mainWindow(), tr("Adding Subproject Failed"), + message + "\n " + failedProjects.join("\n ")); + return; + } + VcsManager::promptToAdd(dir, addedProjects); +} + void ProjectExplorerPluginPrivate::handleAddExistingFiles() { Node *node = ProjectTree::findCurrentNode(); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 286899b1b73..add3e108780 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -822,6 +822,11 @@ bool ProjectNode::addSubProject(const QString &proFilePath) return false; } +QStringList ProjectNode::subProjectFileNamePatterns() const +{ + return QStringList(); +} + bool ProjectNode::removeSubProject(const QString &proFilePath) { Q_UNUSED(proFilePath) diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index c96b8f8713c..c8a32003bb0 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -68,6 +68,7 @@ enum ProjectAction { // Special value to indicate that the actions are handled by the parent InheritedFromParent, AddSubProject, + AddExistingProject, RemoveSubProject, // Let's the user select to which project file // the file is added @@ -325,6 +326,7 @@ class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode public: virtual bool canAddSubProject(const QString &proFilePath) const; virtual bool addSubProject(const QString &proFile); + virtual QStringList subProjectFileNamePatterns() const; virtual bool removeSubProject(const QString &proFilePath); virtual Utils::optional visibleAfterAddFileAction() const { return Utils::nullopt; diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 7ae34f31b62..1a5e299e88c 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -132,7 +132,7 @@ bool QmakePriFileNode::supportsAction(ProjectAction action, const Node *node) co break; } case ProjectType::SubDirsTemplate: - if (action == AddSubProject || action == RemoveSubProject) + if (action == AddSubProject || action == RemoveSubProject || action == AddExistingProject) return true; break; default: @@ -168,6 +168,11 @@ bool QmakePriFileNode::removeSubProject(const QString &proFilePath) return pri ? pri->removeSubProjects(proFilePath) : false; } +QStringList QmakePriFileNode::subProjectFileNamePatterns() const +{ + return QStringList("*.pro"); +} + bool QmakePriFileNode::addFiles(const QStringList &filePaths, QStringList *notAdded) { QmakePriFile *pri = priFile(); diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 0a70b7a8ea5..6b2f79131da 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -51,9 +51,9 @@ public: bool showInSimpleTree() const override { return false; } bool canAddSubProject(const QString &proFilePath) const override; - bool addSubProject(const QString &proFilePath) override; bool removeSubProject(const QString &proFilePath) override; + QStringList subProjectFileNamePatterns() const override; bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = nullptr) override;