From ecc578c2dd4979a97cc4505a9e407178e4971693 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 3 Jan 2019 22:00:22 +0100 Subject: [PATCH] - error messages - style changes --- .../qml/hifi/AvatarPackagerWindow.qml | 8 -- .../hifi/avatarPackager/AvatarPackagerApp.qml | 114 +++++++++++++++--- .../avatarPackager/AvatarPackagerFooter.qml | 3 +- .../avatarPackager/AvatarPackagerHeader.qml | 5 - .../qml/hifi/avatarPackager/AvatarProject.qml | 6 +- .../avatarPackager/AvatarProjectUpload.qml | 5 +- .../avatarPackager/CreateAvatarProject.qml | 7 +- .../qml/hifi/avatarPackager/InfoBox.qml | 18 +-- interface/src/avatar/AvatarPackager.cpp | 54 +++++---- interface/src/avatar/AvatarPackager.h | 8 +- interface/src/avatar/AvatarProject.cpp | 65 ++++++++-- interface/src/avatar/AvatarProject.h | 32 ++++- 12 files changed, 242 insertions(+), 83 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarPackagerWindow.qml b/interface/resources/qml/hifi/AvatarPackagerWindow.qml index 9d434ef97c..82bcd3fa40 100644 --- a/interface/resources/qml/hifi/AvatarPackagerWindow.qml +++ b/interface/resources/qml/hifi/AvatarPackagerWindow.qml @@ -1,15 +1,7 @@ import QtQuick 2.6 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQml.Models 2.1 -import QtGraphicalEffects 1.0 -import "../controlsUit" 1.0 as HifiControls import "../stylesUit" 1.0 import "../windows" as Windows -import "../controls" 1.0 -import "../dialogs" import "avatarPackager" 1.0 -import "avatarapp" 1.0 as AvatarApp Windows.ScrollingWindow { id: root diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml index 0a678dafee..fb7987ca76 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml @@ -3,9 +3,9 @@ import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQml.Models 2.1 import QtGraphicalEffects 1.0 +import Hifi.AvatarPackager.AvatarProjectStatus 1.0 import "../../controlsUit" 1.0 as HifiControls import "../../stylesUit" 1.0 -import "../../windows" as Windows import "../../controls" 1.0 import "../../dialogs" import "../avatarapp" 1.0 as AvatarApp @@ -16,9 +16,6 @@ Item { property alias desktopObject: avatarPackager.desktopObject id: windowContent - // height: pane ? pane.height : parent.width - // width: pane ? pane.width : parent.width - MouseArea { anchors.fill: parent @@ -75,6 +72,37 @@ Item { } } + InfoBox { + id: errorPopup + + property string errorMessage; + + boxWidth: 380 + boxHeight: 293 + + content: RalewayRegular { + + id: bodyMessage + + anchors.fill: parent + anchors.bottomMargin: 10 + anchors.leftMargin: 29 + anchors.rightMargin: 29 + + size: 20 + color: "white" + text: errorPopup.errorMessage + width: parent.width + wrapMode: Text.WordWrap + } + + function show(title, message) { + errorPopup.title = title; + errorMessage = message; + errorPopup.open(); + } + } + Rectangle { id: modalOverlay anchors.fill: parent @@ -85,8 +113,8 @@ Item { // This mouse area captures the cursor events while the modalOverlay is active MouseArea { anchors.fill: parent - propagateComposedEvents: false; - hoverEnabled: true; + propagateComposedEvents: false + hoverEnabled: true } } @@ -133,12 +161,58 @@ Item { property var desktopObject: desktop function openProject(path) { - let project = AvatarPackagerCore.openAvatarProject(path); - if (project) { - avatarProject.reset(); - avatarPackager.state = AvatarPackagerState.project; + let status = AvatarPackagerCore.openAvatarProject(path); + if (status !== AvatarProjectStatus.SUCCESS) { + displayErrorMessage(status); + return status; } - return project; + avatarProject.reset(); + avatarPackager.state = AvatarPackagerState.project; + return status; + } + + function displayErrorMessage(status) { + if (status === AvatarProjectStatus.SUCCESS) { + return; + } + switch (status) { + case AvatarProjectStatus.ERROR_CREATE_PROJECT_NAME: + errorPopup.show("Project Folder Already Exists", "A folder with that name already exists at that location. Please choose a different project name or location."); + break; + case AvatarProjectStatus.ERROR_CREATE_CREATING_DIRECTORIES: + errorPopup.show("Project Folders Creation Error", "There was a problem during the creation of the Avatar Project directories. Please select a project location with write permissions."); + break; + case AvatarProjectStatus.ERROR_CREATE_FIND_MODEL: + errorPopup.show("Cannot Find Model File", "There was a problem while trying to find the specified model file. Please verify if it exist at the specified location."); + break; + case AvatarProjectStatus.ERROR_CREATE_OPEN_MODEL: + errorPopup.show("Cannot Open Model File", "There was a problem while trying to open the specified model file. Please verify if you have read permissions at the specified location."); + break; + case AvatarProjectStatus.ERROR_CREATE_READ_MODEL: + errorPopup.show("Error Read Model File", "There was a problem while trying to read the specified model file. Please verify if the model file is supported by High Fidelity."); + break; + case AvatarProjectStatus.ERROR_CREATE_WRITE_FST: + errorPopup.show("Error Writing Project File", "There was a problem while trying to write the FST file."); + break; + case AvatarProjectStatus.ERROR_OPEN_INVALID_FILE_TYPE: + errorPopup.show("Invalid Project Path", "The avatar packager can only open FST files."); + break; + case AvatarProjectStatus.ERROR_OPEN_PROJECT_FOLDER: + errorPopup.show("Project Missing", "Project folder cannot be found. Please locate the folder and copy/move it to its original location."); + break; + case AvatarProjectStatus.ERROR_OPEN_FIND_FST: + errorPopup.show("File Missing", "We cannot find the project file (avatar.fst) in the folder. Please locate it and move to the project folder."); + break; + case AvatarProjectStatus.ERROR_OPEN_OPEN_FST: + errorPopup.show("File Read Error", "We cannot read the project file (avatar.fst). Please make sure that it is not in use by another program."); + break; + case AvatarProjectStatus.ERROR_OPEN_FIND_MODEL: + errorPopup.show("File Missing", "We cannot find the avatar model file (.fbx) in the folder. Please locate it and move to the project folder."); + break; + default: + errorPopup.show("Error Message Missing", "Error message missing for status " + status); + } + } function openDocs() { @@ -233,10 +307,8 @@ Item { browser.selectedFile.connect(function(fileUrl) { let fstFilePath = fileDialogHelper.urlToPath(fileUrl); - let currentAvatarProject = avatarPackager.openProject(fstFilePath); - if (currentAvatarProject) { - avatarPackager.showModalOverlay = false; - } + avatarPackager.showModalOverlay = false; + avatarPackager.openProject(fstFilePath); }); } } @@ -253,12 +325,20 @@ Item { RalewayRegular { size: 20 color: "white" - text: qsTr("Use a custom avatar to express your identity") + text: "Use a custom avatar of your choice." + width: parent.width + wrapMode: Text.WordWrap } RalewayRegular { size: 20 color: "white" - text: qsTr("To learn more about using this tool, visit our docs") + text: "Visit our docs to learn more about using the packager." + linkColor: "#00B4EF" + width: parent.width + wrapMode: Text.WordWrap + onLinkActivated: { + avatarPackager.openDocs(); + } } } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerFooter.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerFooter.qml index e1d9396e04..31e05672d2 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerFooter.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerFooter.qml @@ -38,5 +38,4 @@ Rectangle { width: parent.width } } - -} \ No newline at end of file +} diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml index d0b06ea15f..cd6fdb72fe 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml @@ -93,7 +93,6 @@ ShadowRectangle { z: 200 onFocusChanged: { if (titleArea.state === "renaming" && !titleArea.focus) { - //titleArea.state = ""; accepted(); } } @@ -104,11 +103,7 @@ ShadowRectangle { } onAccepted: { if (acceptableInput) { - //AvatarPackagerCore.renameProject(text); - console.warn(text); AvatarPackagerCore.currentAvatarProject.name = text; - console.warn(AvatarPackagerCore.currentAvatarProject.name); - } titleArea.state = ""; } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml index a5a2263346..8f7a4be481 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml @@ -52,7 +52,7 @@ Item { colorScheme: root.colorScheme width: 133 height: 40 - onClicked: function() { + onClicked: { uploadNew(); } } @@ -70,7 +70,7 @@ Item { colorScheme: root.colorScheme width: 134 height: 40 - onClicked: function() { + onClicked: { showConfirmUploadPopup(uploadNew, uploadUpdate); } } @@ -90,7 +90,7 @@ Item { colorScheme: root.colorScheme width: 134 height: 40 - onClicked: function() { + onClicked: { showConfirmUploadPopup(uploadNew, uploadUpdate); } } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml index c1d1a98158..68f465f514 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml @@ -29,10 +29,11 @@ Item { function stateChangedCallback(newState) { if (newState >= 4) { - root.uploader.stateChanged.disconnect(stateChangedCallback) + root.uploader.stateChanged.disconnect(stateChangedCallback); backToProjectTimer.start(); } } + onVisibleChanged: { if (visible) { root.uploader.stateChanged.connect(stateChangedCallback); @@ -120,6 +121,7 @@ Item { source: "../../../icons/checkmark-stroke.svg" } } + Item { id: statusRows @@ -169,6 +171,7 @@ Item { color: "white" text: "We couldn't upload your avatar at this time. Please try again later." } + AvatarPackagerFooter { id: errorFooter diff --git a/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml b/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml index d6f530a196..1e9a3d9e84 100644 --- a/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml +++ b/interface/resources/qml/hifi/avatarPackager/CreateAvatarProject.qml @@ -2,6 +2,8 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 +import Hifi.AvatarPackager.AvatarProjectStatus 1.0 + import "../../controlsUit" 1.0 as HifiControls import "../../stylesUit" 1.0 @@ -24,8 +26,9 @@ Item { text: qsTr("Create") enabled: false onClicked: { - if (!AvatarPackagerCore.createAvatarProject(projectLocation.text, name.text, avatarModel.text, textureFolder.text)) { - Window.alert('Failed to create project'); + let status = AvatarPackagerCore.createAvatarProject(projectLocation.text, name.text, avatarModel.text, textureFolder.text); + if (status !== AvatarProjectStatus.SUCCESS) { + avatarPackager.displayErrorMessage(status); return; } avatarPackager.state = AvatarPackagerState.project; diff --git a/interface/resources/qml/hifi/avatarPackager/InfoBox.qml b/interface/resources/qml/hifi/avatarPackager/InfoBox.qml index 89f5d5c7f8..301386acfa 100644 --- a/interface/resources/qml/hifi/avatarPackager/InfoBox.qml +++ b/interface/resources/qml/hifi/avatarPackager/InfoBox.qml @@ -5,9 +5,9 @@ import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls Rectangle { - id: root; - visible: false; - color: Qt.rgba(.34, .34, .34, 0.6); + id: root + visible: false + color: Qt.rgba(.34, .34, .34, 0.6) z: 999; anchors.fill: parent @@ -17,6 +17,9 @@ Rectangle { property bool closeOnClickOutside: false; + property alias boxWidth: mainContainer.width + property alias boxHeight: mainContainer.height + function open() { visible = true; } @@ -44,15 +47,15 @@ Rectangle { } Rectangle { - id: mainContainer; + id: mainContainer width: Math.max(parent.width * 0.8, 400) height: parent.height * 0.6 MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; + anchors.fill: parent + propagateComposedEvents: false + hoverEnabled: true onClicked: function(ev) { ev.accepted = true; } @@ -107,6 +110,5 @@ Rectangle { colorScheme: hifi.colorSchemes.dark; } } - } } diff --git a/interface/src/avatar/AvatarPackager.cpp b/interface/src/avatar/AvatarPackager.cpp index eef574a8b5..941aff6943 100644 --- a/interface/src/avatar/AvatarPackager.cpp +++ b/interface/src/avatar/AvatarPackager.cpp @@ -22,7 +22,6 @@ #include #include -#include "scripting/HMDScriptingInterface.h" #include "ui/TabletScriptingInterface.h" std::once_flag setupQMLTypesFlag; @@ -32,6 +31,14 @@ AvatarPackager::AvatarPackager() { qmlRegisterType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); + qmlRegisterUncreatableMetaObject( + AvatarProjectStatus::staticMetaObject, + "Hifi.AvatarPackager.AvatarProjectStatus", + 1, 0, + "AvatarProjectStatus", + "Error: only enums" + ); }); recentProjectsFromVariantList(_recentProjectsSetting.get()); @@ -41,39 +48,39 @@ AvatarPackager::AvatarPackager() { } bool AvatarPackager::open() { - static const QUrl url{ "hifi/AvatarPackagerWindow.qml" }; - const auto packageModelDialogCreated = [=](QQmlContext* context, QObject* newObject) { context->setContextProperty("AvatarPackagerCore", this); }; static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; - auto tabletScriptingInterface = DependencyManager::get(); - auto tablet = dynamic_cast(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); - auto hmd = DependencyManager::get(); + auto tablet = dynamic_cast(DependencyManager::get()->getTablet(SYSTEM_TABLET)); if (tablet->getToolbarMode()) { + static const QUrl url{ "hifi/AvatarPackagerWindow.qml" }; DependencyManager::get()->show(url, "AvatarPackager", packageModelDialogCreated); - } else { - static const QUrl url("hifi/tablet/AvatarPackager.qml"); - if (!tablet->isPathLoaded(url)) { - tablet->getTabletSurface()->getSurfaceContext()->setContextProperty("AvatarPackagerCore", this); - tablet->pushOntoStack(url); - } + return true; } - return true; + + static const QUrl url{ "hifi/tablet/AvatarPackager.qml" }; + if (!tablet->isPathLoaded(url)) { + tablet->getTabletSurface()->getSurfaceContext()->setContextProperty("AvatarPackagerCore", this); + tablet->pushOntoStack(url); + return true; + } + + return false; } void AvatarPackager::addCurrentProjectToRecentProjects() { const int MAX_RECENT_PROJECTS = 5; const QString& fstPath = _currentAvatarProject->getFSTPath(); auto removeProjects = QVector(); - for (auto project : _recentProjects) { + for (const auto& project : _recentProjects) { if (project.getProjectFSTPath() == fstPath) { removeProjects.append(project); } } - for (const auto removeProject : removeProjects) { + for (const auto& removeProject : removeProjects) { _recentProjects.removeOne(removeProject); } @@ -110,14 +117,19 @@ void AvatarPackager::recentProjectsFromVariantList(QVariantList projectsVariant) } } -AvatarProject* AvatarPackager::openAvatarProject(const QString& avatarProjectFSTPath) { - setAvatarProject(AvatarProject::openAvatarProject(avatarProjectFSTPath)); - return _currentAvatarProject; +AvatarProjectStatus::AvatarProjectStatus AvatarPackager::openAvatarProject(const QString& avatarProjectFSTPath) { + AvatarProjectStatus::AvatarProjectStatus status; + setAvatarProject(AvatarProject::openAvatarProject(avatarProjectFSTPath, status)); + return status; } -AvatarProject* AvatarPackager::createAvatarProject(const QString& projectsFolder, const QString& avatarProjectName, const QString& avatarModelPath, const QString& textureFolder) { - setAvatarProject(AvatarProject::createAvatarProject(projectsFolder, avatarProjectName, avatarModelPath, textureFolder)); - return _currentAvatarProject; +AvatarProjectStatus::AvatarProjectStatus AvatarPackager::createAvatarProject(const QString& projectsFolder, + const QString& avatarProjectName, + const QString& avatarModelPath, + const QString& textureFolder) { + AvatarProjectStatus::AvatarProjectStatus status; + setAvatarProject(AvatarProject::createAvatarProject(projectsFolder, avatarProjectName, avatarModelPath, textureFolder, status)); + return status; } void AvatarPackager::setAvatarProject(AvatarProject* avatarProject) { diff --git a/interface/src/avatar/AvatarPackager.h b/interface/src/avatar/AvatarPackager.h index 343176497f..c9c5b9d312 100644 --- a/interface/src/avatar/AvatarPackager.h +++ b/interface/src/avatar/AvatarPackager.h @@ -63,8 +63,12 @@ public: AvatarPackager(); bool open(); - Q_INVOKABLE AvatarProject* createAvatarProject(const QString& projectsFolder, const QString& avatarProjectName, const QString& avatarModelPath, const QString& textureFolder); - Q_INVOKABLE AvatarProject* openAvatarProject(const QString& avatarProjectFSTPath); + Q_INVOKABLE AvatarProjectStatus::AvatarProjectStatus createAvatarProject(const QString& projectsFolder, + const QString& avatarProjectName, + const QString& avatarModelPath, + const QString& textureFolder); + + Q_INVOKABLE AvatarProjectStatus::AvatarProjectStatus openAvatarProject(const QString& avatarProjectFSTPath); Q_INVOKABLE bool isValidNewProjectName(const QString& projectPath, const QString& projectName) { return AvatarProject::isValidNewProjectName(projectPath, projectName); } signals: diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index 0c29bcf906..e049dc0ba3 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -22,55 +22,98 @@ #include #include "scripting/HMDScriptingInterface.h" -AvatarProject* AvatarProject::openAvatarProject(const QString& path) { +AvatarProject* AvatarProject::openAvatarProject(const QString& path, AvatarProjectStatus::AvatarProjectStatus& status) { + status = AvatarProjectStatus::NONE; + if (!path.toLower().endsWith(".fst")) { + status = AvatarProjectStatus::ERROR_OPEN_INVALID_FILE_TYPE; return nullptr; } - QFile file{ path }; + + QFileInfo fstFileInfo{ path }; + if (!fstFileInfo.absoluteDir().exists()) { + status = AvatarProjectStatus::ERROR_OPEN_PROJECT_FOLDER; + return nullptr; + } + + if (!fstFileInfo.exists()) { + status = AvatarProjectStatus::ERROR_OPEN_FIND_FST; + return nullptr; + } + + QFile file{ fstFileInfo.filePath() }; if (!file.open(QIODevice::ReadOnly)) { + status = AvatarProjectStatus::ERROR_OPEN_OPEN_FST; return nullptr; } + const auto project = new AvatarProject(path, file.readAll()); + + QFileInfo fbxFileInfo{ project->getFBXPath() }; + if (!fbxFileInfo.exists()) { + project->deleteLater(); + status = AvatarProjectStatus::ERROR_OPEN_FIND_MODEL; + return nullptr; + } + QQmlEngine::setObjectOwnership(project, QQmlEngine::CppOwnership); + status = AvatarProjectStatus::SUCCESS; return project; } -AvatarProject* AvatarProject::createAvatarProject(const QString& projectsFolder, const QString& avatarProjectName, const QString& avatarModelPath, const QString& textureFolder) { +AvatarProject* AvatarProject::createAvatarProject(const QString& projectsFolder, const QString& avatarProjectName, + const QString& avatarModelPath, const QString& textureFolder, + AvatarProjectStatus::AvatarProjectStatus& status) { + status = AvatarProjectStatus::NONE; + if (!isValidNewProjectName(projectsFolder, avatarProjectName)) { + status = AvatarProjectStatus::ERROR_CREATE_PROJECT_NAME; return nullptr; } + QDir projectDir(projectsFolder + "/" + avatarProjectName); if (!projectDir.mkpath(".")) { + status = AvatarProjectStatus::ERROR_CREATE_CREATING_DIRECTORIES; return nullptr; } + QDir projectTexturesDir(projectDir.path() + "/textures"); if (!projectTexturesDir.mkpath(".")) { + status = AvatarProjectStatus::ERROR_CREATE_CREATING_DIRECTORIES; return nullptr; } + QDir projectScriptsDir(projectDir.path() + "/scripts"); if (!projectScriptsDir.mkpath(".")) { + status = AvatarProjectStatus::ERROR_CREATE_CREATING_DIRECTORIES; return nullptr; } + const auto fileName = QFileInfo(avatarModelPath).fileName(); const auto newModelPath = projectDir.absoluteFilePath(fileName); const auto newFSTPath = projectDir.absoluteFilePath("avatar.fst"); QFile::copy(avatarModelPath, newModelPath); - QFileInfo fbxInfo(newModelPath); - QFile fbx(fbxInfo.filePath()); - if (!fbxInfo.exists() || !fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) { - // TODO: Can't open model FBX (throw error here) + QFileInfo fbxInfo{ newModelPath }; + if (!fbxInfo.exists() || !fbxInfo.isFile()) { + status = AvatarProjectStatus::ERROR_CREATE_FIND_MODEL; + return nullptr; + } + + QFile fbx{ fbxInfo.filePath() }; + if (!fbx.open(QIODevice::ReadOnly)) { + status = AvatarProjectStatus::ERROR_CREATE_OPEN_MODEL; return nullptr; } std::shared_ptr hfmModel; try { - qDebug() << "Reading FBX file : " << fbxInfo.filePath(); const QByteArray fbxContents = fbx.readAll(); hfmModel = FBXSerializer().read(fbxContents, QVariantHash(), fbxInfo.filePath()); } catch (const QString& error) { - qDebug() << "Error reading: " << error; + Q_UNUSED(error) + status = AvatarProjectStatus::ERROR_CREATE_READ_MODEL; return nullptr; } QStringList textures{}; @@ -111,9 +154,11 @@ AvatarProject* AvatarProject::createAvatarProject(const QString& projectsFolder, fst->setName(avatarProjectName); if (!fst->write()) { + status = AvatarProjectStatus::ERROR_CREATE_WRITE_FST; return nullptr; } + status = AvatarProjectStatus::SUCCESS; return new AvatarProject(fst); } @@ -157,7 +202,7 @@ AvatarProject::AvatarProject(FST* fst) { _projectPath = fileInfo.absoluteDir().absolutePath(); } -void AvatarProject::appendDirectory(QString prefix, QDir dir) { +void AvatarProject::appendDirectory(const QString& prefix, const QDir& dir) { constexpr auto flags = QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot | QDir::Hidden; for (auto& entry : dir.entryInfoList({}, flags)) { if (entry.isFile()) { diff --git a/interface/src/avatar/AvatarProject.h b/interface/src/avatar/AvatarProject.h index 469324004d..c422c14d62 100644 --- a/interface/src/avatar/AvatarProject.h +++ b/interface/src/avatar/AvatarProject.h @@ -22,6 +22,27 @@ #include #include +namespace AvatarProjectStatus { + Q_NAMESPACE + enum AvatarProjectStatus { + NONE, + SUCCESS, + ERROR_CREATE_PROJECT_NAME, + ERROR_CREATE_CREATING_DIRECTORIES, + ERROR_CREATE_FIND_MODEL, + ERROR_CREATE_OPEN_MODEL, + ERROR_CREATE_READ_MODEL, + ERROR_CREATE_WRITE_FST, + ERROR_OPEN_INVALID_FILE_TYPE, + ERROR_OPEN_PROJECT_FOLDER, + ERROR_OPEN_FIND_FST, + ERROR_OPEN_OPEN_FST, + ERROR_OPEN_FIND_MODEL + }; + Q_ENUM_NS(AvatarProjectStatus) +} + + class AvatarProject : public QObject { Q_OBJECT Q_PROPERTY(FST* fst READ getFST CONSTANT) @@ -48,16 +69,19 @@ public: } Q_INVOKABLE QString getProjectPath() const { return _projectPath; } Q_INVOKABLE QString getFSTPath() const { return _fst->getPath(); } - Q_INVOKABLE QString getFBXPath() const { return _fst->getModelPath(); } + Q_INVOKABLE QString getFBXPath() const { + return QDir::cleanPath(QDir(_projectPath).absoluteFilePath(_fst->getModelPath())); + } /** * returns the AvatarProject or a nullptr on failure. */ - static AvatarProject* openAvatarProject(const QString& path); + static AvatarProject* openAvatarProject(const QString& path, AvatarProjectStatus::AvatarProjectStatus& status); static AvatarProject* createAvatarProject(const QString& projectsFolder, const QString& avatarProjectName, const QString& avatarModelPath, - const QString& textureFolder); + const QString& textureFolder, + AvatarProjectStatus::AvatarProjectStatus& status); static bool isValidNewProjectName(const QString& projectPath, const QString& projectName); @@ -78,7 +102,7 @@ private: FST* getFST() { return _fst; } void refreshProjectFiles(); - void appendDirectory(QString prefix, QDir dir); + void appendDirectory(const QString& prefix, const QDir& dir); QStringList getScriptPaths(const QDir& scriptsDir); FST* _fst;