From 97593bc4d86c6c9b185d81e3e12b76d8a63e304b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 10 Jan 2018 17:18:12 -0800 Subject: [PATCH] Fixing compiled resource access --- .gitignore | 6 ++++ interface/CMakeLists.txt | 2 +- interface/src/Application.cpp | 15 +++++---- interface/src/avatar/MyAvatar.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 2 +- .../networking/src/FileResourceRequest.cpp | 19 +++++++---- libraries/networking/src/ResourceManager.cpp | 32 ++++++++++++------- libraries/networking/src/ResourceManager.h | 1 + libraries/shared/src/PathUtils.cpp | 16 +++++++--- libraries/shared/src/PathUtils.h | 4 ++- libraries/ui/src/InfoView.cpp | 2 +- libraries/ui/src/OffscreenQmlElement.h | 2 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 6 ++-- .../ui/src/ui/TabletScriptingInterface.cpp | 3 +- 15 files changed, 74 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index aa8635bd89..f45572c388 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,12 @@ TAGS # ignore node files for the console node_modules npm-debug.log + +# Android studio files *___jb_old___ + +# Generated assets for Android android/app/src/main/assets +# Resource binary file +interface/compiledResources \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index ce5685bc9f..51aaceccc2 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -12,7 +12,7 @@ function(JOIN VALUES GLUE OUTPUT) endfunction() set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc) -set(RESOURCES_RCC ${CMAKE_CURRENT_BINARY_DIR}/resources.rcc) +set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc) generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *) add_custom_command( diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 040b91bd51..8f2662f4c2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -808,10 +808,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo { #if defined(Q_OS_ANDROID) - const QString resourcesBinaryFile = "assets:resources.rcc"; + const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc"; #else - const QString resourcesBinaryFile = QFileInfo(argv[0]).absolutePath() + "/resources.rcc"; + const QString resourcesBinaryFile = applicationDirPath() + "/resources.rcc"; #endif + if (!QFile::exists(resourcesBinaryFile)) { + throw std::runtime_error("Unable to find primary resources"); + } if (!QResource::registerResource(resourcesBinaryFile)) { throw std::runtime_error("Unable to load primary resources"); } @@ -1037,8 +1040,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get().data(), &AddressManager::storeCurrentAddress); // Inititalize sample before registering - QFileInfo infSample = QFileInfo(PathUtils::resourcesPath() + "sounds/sample.wav"); - _sampleSound = DependencyManager::get()->getSound(QUrl::fromLocalFile(infSample.absoluteFilePath())); + _sampleSound = DependencyManager::get()->getSound(QUrl(PathUtils::resourcesUrl() + "sounds/sample.wav")); auto scriptEngines = DependencyManager::get().data(); scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ @@ -1823,8 +1825,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return entityServerNode && !isPhysicsEnabled(); }); - QFileInfo infSnap = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); - _snapshotSound = DependencyManager::get()->getSound(QUrl::fromLocalFile(infSnap.absoluteFilePath())); + _snapshotSound = DependencyManager::get()->getSound(QUrl(PathUtils::resourcesUrl() + "sounds/snap.wav")); QVariant testProperty = property(hifi::properties::TEST); qDebug() << testProperty; @@ -2356,7 +2357,7 @@ void Application::initializeUi() { offscreenUi->setProxyWindow(_window->windowHandle()); // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to // support the window management and scripting proxies for VR use - offscreenUi->createDesktop(PathUtils::qmlBasePath() + "hifi/Desktop.qml"); + offscreenUi->createDesktop(PathUtils::qmlBaseUrl("hifi/Desktop.qml")); // FIXME either expose so that dialogs can set this themselves or // do better detection in the offscreen UI of what has focus offscreenUi->setNavigationFocused(false); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 68e417ba1d..9339c097c1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1801,7 +1801,7 @@ void MyAvatar::initAnimGraph() { } else if (!_fstAnimGraphOverrideUrl.isEmpty()) { graphUrl = _fstAnimGraphOverrideUrl; } else { - graphUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "avatar/avatar-animation.json"); + graphUrl = QUrl(PathUtils::resourcesUrl() + "avatar/avatar-animation.json"); } _skeletonModel->getRig().initAnimGraph(graphUrl); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f2053e29d7..a5aca0d2b9 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -103,7 +103,7 @@ AvatarData::~AvatarData() { QUrl AvatarData::_defaultFullAvatarModelUrl = {}; // In C++, if this initialization were in the AvatarInfo, every file would have it's own copy, even for class vars. const QUrl& AvatarData::defaultFullAvatarModelUrl() { if (_defaultFullAvatarModelUrl.isEmpty()) { - _defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "/meshes/defaultAvatar_full.fst"); + _defaultFullAvatarModelUrl = QUrl(PathUtils::resourcesUrl() + "/meshes/defaultAvatar_full.fst"); } return _defaultFullAvatarModelUrl; } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 8153dba3a5..67166c40a2 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -262,7 +262,7 @@ gpu::TexturePointer getFallbackTextureForType(image::TextureUsage::Type type) { gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::TextureUsage::Type type, QVariantMap options) { QImage image = QImage(path); auto loader = image::TextureUsage::getTextureLoaderForType(type, options); - return gpu::TexturePointer(loader(std::move(image), QUrl::fromLocalFile(path).fileName().toStdString(), false)); + return gpu::TexturePointer(loader(std::move(image), path.toStdString(), false)); } QSharedPointer TextureCache::createResource(const QUrl& url, const QSharedPointer& fallback, diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 8b14dd63b8..1dfb00c932 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -17,18 +17,25 @@ #include +#include "ResourceManager.h" + void FileResourceRequest::doSend() { auto statTracker = DependencyManager::get(); statTracker->incrementStat(STAT_FILE_REQUEST_STARTED); int fileSize = 0; - QString filename = _url.toLocalFile(); - - // sometimes on windows, we see the toLocalFile() return null, - // in this case we will attempt to simply use the url as a string - if (filename.isEmpty()) { - filename = _url.toString(); + QString filename; + if (_url.scheme() == URL_SCHEME_QRC) { + filename = ":/" + _url.path(); + } else { + filename = _url.toLocalFile(); + // sometimes on windows, we see the toLocalFile() return null, + // in this case we will attempt to simply use the url as a string + if (filename.isEmpty()) { + filename = _url.toString(); + } } + // Allow platform specific versions of files loaded out of a resource cache via file:// filename = QFileSelector().select(filename); diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 3ee66f89c1..17dcd9728d 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -11,6 +11,8 @@ #include "ResourceManager.h" +#include + #include #include #include @@ -24,7 +26,6 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" - ResourceManager::ResourceManager() { _thread.setObjectName("Resource Manager Thread"); @@ -53,7 +54,7 @@ QString ResourceManager::normalizeURL(const QString& urlString) { copy = _prefixMap; } - foreach(const auto& entry, copy) { + foreach (const auto& entry, copy) { const auto& prefix = entry.first; const auto& replacement = entry.second; if (result.startsWith(prefix)) { @@ -64,13 +65,24 @@ QString ResourceManager::normalizeURL(const QString& urlString) { return result; } +const QSet& getKnownUrls() { + static QSet knownUrls; + static std::once_flag once; + std::call_once(once, [] { + knownUrls.insert(URL_SCHEME_QRC); + knownUrls.insert(URL_SCHEME_FILE); + knownUrls.insert(URL_SCHEME_HTTP); + knownUrls.insert(URL_SCHEME_HTTPS); + knownUrls.insert(URL_SCHEME_FTP); + knownUrls.insert(URL_SCHEME_ATP); + }); + return knownUrls; +} + QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) { QUrl url = QUrl(normalizeURL(originalUrl.toString())); auto scheme = url.scheme(); - if (!(scheme == URL_SCHEME_FILE || - scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP || - scheme == URL_SCHEME_ATP)) { - + if (!getKnownUrls().contains(scheme)) { // check the degenerative file case: on windows we can often have urls of the form c:/filename // this checks for and works around that case. QUrl urlWithFileScheme{ URL_SCHEME_FILE + ":///" + url.toString() }; @@ -94,7 +106,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q ResourceRequest* request = nullptr; - if (scheme == URL_SCHEME_FILE) { + if (scheme == URL_SCHEME_FILE || scheme == URL_SCHEME_QRC) { request = new FileResourceRequest(normalizedURL); } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { request = new HTTPResourceRequest(normalizedURL); @@ -113,15 +125,14 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q return request; } - bool ResourceManager::resourceExists(const QUrl& url) { auto scheme = url.scheme(); if (scheme == URL_SCHEME_FILE) { - QFileInfo file { url.toString() }; + QFileInfo file{ url.toString() }; return file.exists(); } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { auto& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest request { url }; + QNetworkRequest request{ url }; request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); @@ -159,4 +170,3 @@ bool ResourceManager::resourceExists(const QUrl& url) { qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url(); return false; } - diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index fdfd05736e..5728a7bd32 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -22,6 +22,7 @@ #include "ResourceRequest.h" +const QString URL_SCHEME_QRC = "qrc"; const QString URL_SCHEME_FILE = "file"; const QString URL_SCHEME_HTTP = "http"; const QString URL_SCHEME_HTTPS = "https"; diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index dc1bd198d9..bc9402c8ed 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -61,19 +61,27 @@ const QString& PathUtils::resourcesPath() { return staticResourcePath; } -// FIXME rename to qmlBaseUrl -const QString& PathUtils::qmlBasePath() { +const QString& PathUtils::resourcesUrl() { #if !defined(Q_OS_ANDROID) && defined(DEV_BUILD) // For dev builds, load if (USE_SOURCE_TREE_RESOURCES) { - static const QString staticResourcePath = QUrl::fromLocalFile(projectRootPath() + "/interface/resources/qml").toString(); + static const QString staticResourcePath = "file:///" + projectRootPath() + "/interface/resources/"; return staticResourcePath; } #endif - static const QString staticResourcePath = "qrc:///qml/"; + static const QString staticResourcePath = "qrc:///"; return staticResourcePath; } +const QString& PathUtils::qmlBaseUrl() { + static const QString staticResourcePath = resourcesUrl() + "qml/"; + return staticResourcePath; +} + +QUrl PathUtils::qmlBaseUrl(const QString& relativeUrl) { + return QUrl(qmlBaseUrl() + relativeUrl); +} + QString PathUtils::getAppDataPath() { return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/"; } diff --git a/libraries/shared/src/PathUtils.h b/libraries/shared/src/PathUtils.h index 6991c91258..b55416a313 100644 --- a/libraries/shared/src/PathUtils.h +++ b/libraries/shared/src/PathUtils.h @@ -33,8 +33,10 @@ class PathUtils : public QObject, public Dependency { Q_PROPERTY(QString resources READ resourcesPath CONSTANT) Q_PROPERTY(QUrl defaultScripts READ defaultScriptsLocation CONSTANT) public: + static const QString& resourcesUrl(); static const QString& resourcesPath(); - static const QString& qmlBasePath(); + static const QString& qmlBaseUrl(); + static QUrl qmlBaseUrl(const QString& relative); #ifdef DEV_BUILD static const QString& projectRootPath(); #endif diff --git a/libraries/ui/src/InfoView.cpp b/libraries/ui/src/InfoView.cpp index cb80e3f6db..99bd8b1339 100644 --- a/libraries/ui/src/InfoView.cpp +++ b/libraries/ui/src/InfoView.cpp @@ -46,7 +46,7 @@ void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQue registerType(); QUrl url; if (QDir(path).isRelative()) { - url = QUrl::fromLocalFile(PathUtils::resourcesPath() + path); + url = QUrl(PathUtils::resourcesUrl() + path); } else { url = QUrl::fromLocalFile(path); } diff --git a/libraries/ui/src/OffscreenQmlElement.h b/libraries/ui/src/OffscreenQmlElement.h index 4f0be9c572..0259085598 100644 --- a/libraries/ui/src/OffscreenQmlElement.h +++ b/libraries/ui/src/OffscreenQmlElement.h @@ -42,7 +42,7 @@ public: \ private: #define HIFI_QML_DEF(x) \ - const QUrl x::QML = QUrl(PathUtils::qmlBasePath() + #x ".qml"); \ + const QUrl x::QML = PathUtils::qmlBaseUrl(#x ".qml"); \ const QString x::NAME = #x; \ \ void x::registerType() { \ diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 902f91f9b8..9a1081eb9d 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -70,7 +70,7 @@ public: withWriteLock([&] { for (auto url : urls) { if (url.isRelative()) { - url = QUrl(PathUtils::qmlBasePath() + url.toString()); + url = PathUtils::qmlBaseUrl(url.toString()); } _callbacks[url].push_back(callback); } @@ -443,7 +443,7 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { auto rootContext = engine->rootContext(); rootContext->setContextProperty("GL", ::getGLContextData()); rootContext->setContextProperty("urlHandler", new UrlHandler()); - rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath())); + rootContext->setContextProperty("resourceDirectoryUrl", QUrl(PathUtils::resourcesUrl())); rootContext->setContextProperty("pathToFonts", "../../"); rootContext->setContextProperty("ApplicationInterface", qApp); auto javaScriptToInject = getEventBridgeJavascript(); @@ -682,7 +682,7 @@ void OffscreenQmlSurface::create() { auto qmlEngine = acquireEngine(_quickWindow); _qmlContext = new QQmlContext(qmlEngine->rootContext()); - _qmlContext->setBaseUrl(QUrl{ PathUtils::qmlBasePath() }); + _qmlContext->setBaseUrl(QUrl{ PathUtils::qmlBaseUrl() }); _qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); _qmlContext->setContextProperty("eventBridge", this); _qmlContext->setContextProperty("webEntity", this); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index c69ec1ce84..b4e468af51 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -172,9 +172,8 @@ void TabletScriptingInterface::preloadSounds() { //preload audio events const QStringList &audioSettings = tabletSoundsButtonClick.get(); for (int i = 0; i < TabletAudioEvents::Last; i++) { - QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + audioSettings.at(i)); SharedSoundPointer sound = DependencyManager::get()-> - getSound(QUrl::fromLocalFile(inf.absoluteFilePath())); + getSound(QUrl(PathUtils::resourcesUrl() + audioSettings.at(i))); _audioEvents.insert(static_cast(i), sound); } }