QmlDesigner: Improve project open functions

This patch:
unifies lookup for the first qml file to open;
increases number of possible fallback options;
adds missing implementations to some methods in QmlBuildSystem.

Task-number: QDS-9984
Change-Id: Ib282b1fca8b0564fe80f00e3d9ffe82c1a15c540
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Burak Hancerli <burak.hancerli@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Aleksei German
2023-06-22 19:34:15 +02:00
parent 96cd0b3668
commit fcab6a10d2
4 changed files with 97 additions and 45 deletions

View File

@@ -5,6 +5,7 @@
#include "../qmlprojectconstants.h" #include "../qmlprojectconstants.h"
#include "../qmlprojectmanagertr.h" #include "../qmlprojectmanagertr.h"
#include "../qmlproject.h"
#include <QtCore5Compat/qtextcodec.h> #include <QtCore5Compat/qtextcodec.h>
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
@@ -155,6 +156,11 @@ bool QmlBuildSystem::updateProjectFile()
return true; return true;
} }
QmlProject *QmlBuildSystem::qmlProject() const
{
return qobject_cast<QmlProject *>(project());
}
void QmlBuildSystem::triggerParsing() void QmlBuildSystem::triggerParsing()
{ {
refresh(RefreshOptions::Project); refresh(RefreshOptions::Project);
@@ -315,6 +321,66 @@ void QmlBuildSystem::setBlockFilesUpdate(bool newBlockFilesUpdate)
m_blockFilesUpdate = newBlockFilesUpdate; m_blockFilesUpdate = newBlockFilesUpdate;
} }
Utils::FilePath QmlBuildSystem::getStartupQmlFileWithFallback() const
{
const auto currentProject = project();
if (!currentProject)
return {};
if (!target())
return {};
const auto getFirstFittingFile = [](const Utils::FilePaths &files) -> Utils::FilePath {
for (const auto &file : files) {
if (file.exists())
return file;
}
return {};
};
const QStringView uiqmlstr = u"ui.qml";
const QStringView qmlstr = u"qml";
//we will check mainUiFile twice:
//first priority if it's ui.qml file, second if it's just a qml file
const Utils::FilePath mainUiFile = mainUiFilePath();
if (mainUiFile.exists() && mainUiFile.completeSuffix() == uiqmlstr)
return mainUiFile;
const Utils::FilePaths uiFiles = currentProject->files([&](const ProjectExplorer::Node *node) {
return node->filePath().completeSuffix() == uiqmlstr;
});
if (!uiFiles.isEmpty()) {
if (const auto file = getFirstFittingFile(uiFiles); !file.isEmpty())
return file;
}
//check the suffix of mainUiFile again, since there are no ui.qml files:
if (mainUiFile.exists() && mainUiFile.completeSuffix() == qmlstr)
return mainUiFile;
const Utils::FilePath mainQmlFile = mainFilePath();
if (mainQmlFile.exists() && mainQmlFile.completeSuffix() == qmlstr)
return mainQmlFile;
//maybe it's also worth priotizing qml files containing common words like "Screen"?
const Utils::FilePaths qmlFiles = currentProject->files([&](const ProjectExplorer::Node *node) {
return node->filePath().completeSuffix() == qmlstr;
});
if (!qmlFiles.isEmpty()) {
if (const auto file = getFirstFittingFile(qmlFiles); !file.isEmpty())
return file;
}
//if no source files exist in the project, lets try to open the .qmlproject file itself
const Utils::FilePath projectFile = projectFilePath();
if (projectFile.exists())
return projectFile;
return {};
}
Utils::FilePath QmlBuildSystem::mainFilePath() const Utils::FilePath QmlBuildSystem::mainFilePath() const
{ {
const QString fileName = mainFile(); const QString fileName = mainFile();

View File

@@ -94,6 +94,8 @@ public:
bool blockFilesUpdate() const; bool blockFilesUpdate() const;
void setBlockFilesUpdate(bool newBlockFilesUpdate); void setBlockFilesUpdate(bool newBlockFilesUpdate);
Utils::FilePath getStartupQmlFileWithFallback() const;
signals: signals:
void projectChanged(); void projectChanged();

View File

@@ -67,40 +67,24 @@ void QmlProject::parsingFinished(const Target *target, bool success)
// trigger only once // trigger only once
disconnect(this, &QmlProject::anyParsingFinished, this, &QmlProject::parsingFinished); disconnect(this, &QmlProject::anyParsingFinished, this, &QmlProject::parsingFinished);
// FIXME: what to do in this case?
if (!target || !success || !activeTarget()) if (!target || !success || !activeTarget())
return; return;
auto targetActive = activeTarget(); const auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>( activeTarget()->buildSystem());
targetActive->buildSystem()); if (!qmlBuildSystem)
const Utils::FilePath mainUiFile = qmlBuildSystem->mainUiFilePath();
if (mainUiFile.completeSuffix() == "ui.qml" && mainUiFile.exists()) {
QTimer::singleShot(1000, [mainUiFile]() {
Core::EditorManager::openEditor(mainUiFile, Utils::Id());
});
return; return;
}
Utils::FilePaths uiFiles = collectUiQmlFilesForFolder( const auto openFile = [&](const Utils::FilePath file) {
projectDirectory().pathAppended("content")); //why is this timer needed here?
if (uiFiles.isEmpty()) { QTimer::singleShot(1000, this, [file] {
uiFiles = collectUiQmlFilesForFolder(projectDirectory()); Core::EditorManager::openEditor(file, Utils::Id());
if (uiFiles.isEmpty())
return;
}
Utils::FilePath currentFile;
if (auto cd = Core::EditorManager::currentDocument())
currentFile = cd->filePath();
if (currentFile.isEmpty() || !isKnownFile(currentFile)) {
QTimer::singleShot(1000, [uiFiles]() {
Core::EditorManager::openEditor(uiFiles.first(), Utils::Id());
}); });
} };
const Utils::FilePath fileToOpen = qmlBuildSystem->getStartupQmlFileWithFallback();
if (!fileToOpen.isEmpty() && fileToOpen.exists() && !fileToOpen.isDir())
openFile(fileToOpen);
} }
Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *errorMessage) Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *errorMessage)
@@ -175,6 +159,14 @@ Utils::FilePaths QmlProject::collectUiQmlFilesForFolder(const Utils::FilePath &f
return uiFiles; return uiFiles;
} }
Utils::FilePaths QmlProject::collectQmlFiles() const
{
const Utils::FilePaths qmlFiles = files([&](const Node *node) {
return node->filePath().completeSuffix() == "qml";
});
return qmlFiles;
}
Tasks QmlProject::projectIssues(const Kit *k) const Tasks QmlProject::projectIssues(const Kit *k) const
{ {
Tasks result = Project::projectIssues(k); Tasks result = Project::projectIssues(k);

View File

@@ -103,30 +103,20 @@ static StudioWelcomePlugin *s_pluginInstance = nullptr;
static Utils::FilePath getMainUiFileWithFallback() static Utils::FilePath getMainUiFileWithFallback()
{ {
auto project = ProjectExplorer::ProjectManager::startupProject(); const auto project = ProjectExplorer::ProjectManager::startupProject();
if (!project) if (!project)
return {}; return {};
if (!project->activeTarget()) if (!project->activeTarget())
return {}; return {};
auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>( const auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
project->activeTarget()->buildSystem()); project->activeTarget()->buildSystem());
if (!qmlBuildSystem) if (!qmlBuildSystem)
return {}; return {};
auto mainUiFile = qmlBuildSystem->mainUiFilePath(); return qmlBuildSystem->getStartupQmlFileWithFallback();
if (mainUiFile.exists())
return mainUiFile;
const Utils::FilePaths uiFiles = project->files([&](const ProjectExplorer::Node *node) {
return node->filePath().completeSuffix() == "ui.qml";
});
if (!uiFiles.isEmpty())
return uiFiles.first();
return {};
} }
std::unique_ptr<QSettings> makeUserFeedbackSettings() std::unique_ptr<QSettings> makeUserFeedbackSettings()
@@ -255,14 +245,16 @@ public:
return; return;
m_blockOpenRecent = true; m_blockOpenRecent = true;
const FilePath projectFile = FilePath::fromVariant(data(index(row, 0), ProjectModel::FilePathRole)); const FilePath projectFile = FilePath::fromVariant(
data(index(row, 0), ProjectModel::FilePathRole));
if (projectFile.exists()) { if (projectFile.exists()) {
const ProjectExplorerPlugin::OpenProjectResult result const ProjectExplorerPlugin::OpenProjectResult result
= ProjectExplorer::ProjectExplorerPlugin::openProject(projectFile); = ProjectExplorer::ProjectExplorerPlugin::openProject(projectFile);
if (!result && !result.alreadyOpen().isEmpty()) { if (!result && !result.alreadyOpen().isEmpty()) {
const auto mainUiFile = getMainUiFileWithFallback(); const auto fileToOpen = getMainUiFileWithFallback();
if (mainUiFile.exists()) if (!fileToOpen.isEmpty() && fileToOpen.exists() && !fileToOpen.isDir()) {
Core::EditorManager::openEditor(mainUiFile, Utils::Id()); Core::EditorManager::openEditor(fileToOpen, Utils::Id());
}
}; };
} }