diff --git a/doc/src/projects/creator-only/creator-projects-custom-wizards-json.qdoc b/doc/src/projects/creator-only/creator-projects-custom-wizards-json.qdoc index c6dc6a24b4c..e63abe650c6 100644 --- a/doc/src/projects/creator-only/creator-projects-custom-wizards-json.qdoc +++ b/doc/src/projects/creator-only/creator-projects-custom-wizards-json.qdoc @@ -981,9 +981,6 @@ as the top level directory. This setting defaults to an empty list and no subdirectories will be scanned. - \li \c firstProjectOnly is a boolean value, which will determine whether - all project files that were found will be opened as a project or - only the first one. This setting defaults to \c true. \endlist */ diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index a3bad8656f0..5db2186c46a 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -36,11 +36,19 @@ #include #include +#include #include +#include #include +#include +#include +#include #include +#include #include +#include +#include #include #ifdef WITH_TESTS @@ -49,6 +57,92 @@ namespace ProjectExplorer { +namespace Internal { + +class ProjectFileTreeItem : public Utils::TreeItem +{ +public: + ProjectFileTreeItem(JsonWizard::GeneratorFile *candidate) : m_candidate(candidate) + { + toggleProjectFileStatus(false); + } + + void toggleProjectFileStatus(bool on) + { + m_candidate->file.setAttributes(m_candidate->file.attributes() + .setFlag(Core::GeneratedFile::OpenProjectAttribute, on)); + } + +private: + QVariant data(int column, int role) const override + { + if (column != 0 || role != Qt::DisplayRole) + return QVariant(); + return QDir::toNativeSeparators(m_candidate->file.path()); + } + + JsonWizard::GeneratorFile * const m_candidate; +}; + +class ProjectFilesModel : public Utils::TreeModel +{ +public: + ProjectFilesModel(const QList &candidates, QObject *parent) + : TreeModel(parent) + { + setHeader({QCoreApplication::translate("ProjectExplorer::JsonWizard", "Project File")}); + for (JsonWizard::GeneratorFile * const candidate : candidates) + rootItem()->appendChild(new ProjectFileTreeItem(candidate)); + } +}; + +class ProjectFileChooser : public QDialog +{ +public: + ProjectFileChooser(const QList &candidates, QWidget *parent) + : QDialog(parent), m_view(new Utils::TreeView(this)) + { + setWindowTitle(QCoreApplication::translate("ProjectExplorer::JsonWizard", + "Choose project file")); + const auto model = new ProjectFilesModel(candidates, this); + m_view->setSelectionMode(Utils::TreeView::ExtendedSelection); + m_view->setSelectionBehavior(Utils::TreeView::SelectRows); + m_view->setModel(model); + const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + const auto updateOkButton = [buttonBox, this] { + buttonBox->button(QDialogButtonBox::Ok) + ->setEnabled(m_view->selectionModel()->hasSelection()); + }; + connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged, + this, updateOkButton); + updateOkButton(); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + const auto layout = new QVBoxLayout(this); + layout->addWidget(new QLabel(QCoreApplication::translate("ProjectExplorer::JsonWizard", + "The project contains more than one project file. " + "Please select the one you would like to use."))); + layout->addWidget(m_view); + layout->addWidget(buttonBox); + } + +private: + void accept() override + { + const QModelIndexList selected = m_view->selectionModel()->selectedRows(); + const auto * const model = static_cast(m_view->model()); + for (const QModelIndex &index : selected) { + const auto item = static_cast(model->itemForIndex(index)); + QTC_ASSERT(item, continue); + item->toggleProjectFileStatus(true); + } + QDialog::accept(); + } + + Utils::TreeView * const m_view; +}; + +} // namespace Internal + JsonWizard::JsonWizard(QWidget *parent) : Utils::Wizard(parent) { setMinimumSize(800, 500); @@ -113,6 +207,14 @@ JsonWizard::GeneratorFiles JsonWizard::generateFileList() return GeneratorFiles(); } + QList projectFiles; + for (JsonWizard::GeneratorFile &f : list) { + if (f.file.attributes().testFlag(Core::GeneratedFile::OpenProjectAttribute)) + projectFiles << &f; + } + if (projectFiles.count() > 1) + Internal::ProjectFileChooser(projectFiles, this).exec(); + return list; } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp index 08d3ed1f885..01494d3dd22 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp @@ -42,6 +42,8 @@ #include #include +#include + namespace ProjectExplorer { namespace Internal { @@ -70,8 +72,6 @@ bool JsonWizardScannerGenerator::setup(const QVariant &data, QString *errorMessa m_subDirectoryExpressions << regexp; } - m_firstProjectOnly = gen.value(QLatin1String("firstProjectOnly"), QLatin1String("true")).toString(); - return true; } @@ -97,17 +97,28 @@ Core::GeneratedFiles JsonWizardScannerGenerator::fileList(Utils::MacroExpander * } } - bool onlyFirst = JsonWizard::boolFromVariant(m_firstProjectOnly, expander); - result = scan(project.absolutePath(), project); - int projectCount = 0; + static const auto getDepth = [](const QString &filePath) { return filePath.count('/'); }; + int minDepth = std::numeric_limits::max(); for (auto it = result.begin(); it != result.end(); ++it) { const QString relPath = project.relativeFilePath(it->path()); it->setBinary(binaryPattern.match(relPath).hasMatch()); bool found = ProjectManager::canOpenProjectForMimeType(Utils::mimeTypeForFile(relPath)); - if (found && !(onlyFirst && projectCount++)) + if (found) { it->setAttributes(it->attributes() | Core::GeneratedFile::OpenProjectAttribute); + minDepth = std::min(minDepth, getDepth(it->path())); + } + } + + // Project files that appear on a lower level in the file system hierarchy than + // other project files are not candidates for opening. + for (Core::GeneratedFile &f : result) { + if (f.attributes().testFlag(Core::GeneratedFile::OpenProjectAttribute) + && getDepth(f.path()) > minDepth) { + f.setAttributes(f.attributes().setFlag(Core::GeneratedFile::OpenProjectAttribute, + false)); + } } return result; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h index e852ad1fe06..76475d4f97c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.h @@ -43,13 +43,11 @@ public: Core::GeneratedFiles fileList(Utils::MacroExpander *expander, const QString &wizardDir, const QString &projectDir, QString *errorMessage) override; - private: Core::GeneratedFiles scan(const QString &dir, const QDir &base); bool matchesSubdirectoryPattern(const QString &path); QString m_binaryPattern; - QString m_firstProjectOnly; QList m_subDirectoryExpressions; };