diff --git a/BUILD.md b/BUILD.md index c1ccd3193e..c868a8e9d9 100644 --- a/BUILD.md +++ b/BUILD.md @@ -18,6 +18,7 @@ * [oglplus](http://oglplus.org/) ~> 0.63 * [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only) * [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1 +* [QuaZip](http://sourceforge.net/projects/quazip/files/quazip/) ~> 0.7.1 * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3 * [soxr](http://soxr.sourceforge.net) ~> 0.1.1 * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3 diff --git a/CMakeLists.txt b/CMakeLists.txt index a167207683..2bcd2352de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,6 +204,7 @@ set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX}) setup_externals_binary_dir() option(USE_NSIGHT "Attempt to find the nSight libraries" 1) +option(GET_QUAZIP "Get QuaZip library automatically as external project" 1) if (WIN32) diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt new file mode 100644 index 0000000000..f00403640a --- /dev/null +++ b/cmake/externals/quazip/CMakeLists.txt @@ -0,0 +1,55 @@ +set(EXTERNAL_NAME quazip) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) +cmake_policy(SET CMP0046 OLD) + +include(ExternalProject) + +if (WIN32) + # windows shell does not like backslashes expanded on the command line, + # so convert all backslashes in the QT path to forward slashes + string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +elseif ($ENV{QT_CMAKE_PREFIX_PATH}) + set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +endif () + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.7.2.zip + URL_MD5 2955176048a31262c09259ca8d309d19 + BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +add_dependencies(quazip zlib) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES + FOLDER "hidden/externals" + INSTALL_NAME_DIR ${INSTALL_DIR}/lib + BUILD_WITH_INSTALL_RPATH True) + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include CACHE PATH "List of QuaZip include directories") +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of QuaZip include directories") +set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/lib CACHE FILEPATH "Location of QuaZip DLL") + +if (APPLE) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library") +elseif (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/quazip5.lib CACHE FILEPATH "Location of QuaZip release library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/quazip5d.lib CACHE FILEPATH "Location of QuaZip release library") +else () + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.so CACHE FILEPATH "Location of QuaZip release library") +endif () + +include(SelectLibraryConfigurations) +select_library_configurations(${EXTERNAL_NAME_UPPER}) + +# Force selected libraries into the cache +set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of QuaZip libraries") +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of QuaZip libraries") \ No newline at end of file diff --git a/cmake/macros/TargetQuazip.cmake b/cmake/macros/TargetQuazip.cmake new file mode 100644 index 0000000000..f704f03050 --- /dev/null +++ b/cmake/macros/TargetQuazip.cmake @@ -0,0 +1,16 @@ +# +# Copyright 2015 High Fidelity, Inc. +# Created by Leonardo Murillo on 2015/11/20 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_QUAZIP) + add_dependency_external_projects(quazip) + find_package(QuaZip REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${QUAZIP_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES}) + if (WIN32) + add_paths_to_fixup_libs(${QUAZIP_DLL_PATH}) + endif () +endmacro() \ No newline at end of file diff --git a/cmake/modules/FindQuaZip.cmake b/cmake/modules/FindQuaZip.cmake new file mode 100644 index 0000000000..2b2a577919 --- /dev/null +++ b/cmake/modules/FindQuaZip.cmake @@ -0,0 +1,29 @@ +# +# FindQuaZip.h +# StackManagerQt/cmake/modules +# +# Created by Mohammed Nafees. +# Copyright (c) 2014 High Fidelity. All rights reserved. +# + +# QUAZIP_FOUND - QuaZip library was found +# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir +# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR) +# QUAZIP_LIBRARIES - List of QuaZip libraries +# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers + +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("quazip") + +if (WIN32) + find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES include/quazip HINTS ${QUAZIP_SEARCH_DIRS}) +elseif (APPLE) + find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES include/quazip HINTS ${QUAZIP_SEARCH_DIRS}) +else () + find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES quazip HINTS ${QUAZIP_SEARCH_DIRS}) +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_INCLUDE_DIRS) + +mark_as_advanced(QUAZIP_INCLUDE_DIRS QUAZIP_SEARCH_DIRS) \ No newline at end of file diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 47231957c2..050e10eead 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -218,16 +218,22 @@ ScrollingWindow { onIconChanged: { console.log("New icon: " + icon) } - onNewViewRequested:{ + onNewViewRequested: { var component = Qt.createComponent("Browser.qml"); var newWindow = component.createObject(desktop); request.openIn(newWindow.webView) - } + } + Component.onCompleted: { + desktop.initWebviewProfileHandlers(webview.profile) + } + + //profile: desktop.browserProfile } } // item - + + Keys.onPressed: { switch(event.key) { case Qt.Key_L: diff --git a/interface/resources/qml/MarketplaceComboBox.qml b/interface/resources/qml/MarketplaceComboBox.qml new file mode 100644 index 0000000000..f7f224485b --- /dev/null +++ b/interface/resources/qml/MarketplaceComboBox.qml @@ -0,0 +1,103 @@ +// +// MarketplaceComboBox.qml +// +// Created by Elisa Lupin-Jimenez on 3 Aug 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtWebChannel 1.0 +import QtWebEngine 1.1 +import QtWebSockets 1.0 +import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel + +import "controls" +import "controls-uit" as Controls +import "styles" +import "styles-uit" + + +Rectangle { + HifiConstants { id: hifi } + id: marketplaceComboBox + anchors.fill: parent + color: hifi.colors.baseGrayShadow + property var currentUrl: "https://metaverse.highfidelity.com/marketplace" + + Controls.WebView { + id: webview + url: currentUrl + anchors.top: switchMarketView.bottom + width: parent.width + height: parent.height - 40 + focus: true + + Timer { + id: zipTimer + running: false + repeat: false + interval: 1500 + property var handler; + onTriggered: handler(); + } + + property var autoCancel: 'var element = $("a.btn.cancel"); + element.click();' + + onNewViewRequested: { + var component = Qt.createComponent("Browser.qml"); + var newWindow = component.createObject(desktop); + request.openIn(newWindow.webView); + if (File.isZippedFbx(desktop.currentUrl)) { + zipTimer.handler = function() { + newWindow.destroy(); + runJavaScript(autoCancel); + } + zipTimer.start(); + } + } + + property var simpleDownload: 'var element = $("a.download-file"); + element.removeClass("download-file"); + element.removeAttr("download");' + + onLinkHovered: { + desktop.currentUrl = hoveredUrl; + // add an error message for non-fbx files + if (File.isZippedFbx(desktop.currentUrl)) { + runJavaScript(simpleDownload, function(){console.log("ran the JS");}); + } + + } + + } + + Controls.ComboBox { + id: switchMarketView + anchors.top: parent.top + anchors.right: parent.right + colorScheme: hifi.colorSchemes.dark + width: 200 + height: 40 + visible: true + model: ["Marketplace", "Clara.io"] + onCurrentIndexChanged: { + if (currentIndex === 0) { webview.url = "https://metaverse.highfidelity.com/marketplace"; } + if (currentIndex === 1) { webview.url = "https://clara.io/library"; } + } + + } + + Controls.Label { + id: switchMarketLabel + anchors.verticalCenter: switchMarketView.verticalCenter + anchors.right: switchMarketView.left + color: hifi.colors.white + text: "Explore interesting content from: " + } + +} \ No newline at end of file diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index 7be747a3ad..ac6ae31c7f 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -1,13 +1,16 @@ import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick.Controls 1.4 import QtWebChannel 1.0 +import QtWebEngine 1.1 import QtWebSockets 1.0 import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel import "windows" as Windows import "controls" +import "controls-uit" as Controls import "styles" +import "styles-uit" Windows.Window { id: root @@ -23,6 +26,8 @@ Windows.Window { property var eventBridge; property var component; property var dynamicContent; + + onSourceChanged: { if (dynamicContent) { dynamicContent.destroy(); diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index eb0c08624b..fa100a965f 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -18,6 +18,7 @@ import "." as VrControls FocusScope { id: root + HifiConstants { id: hifi } property alias model: comboBox.model; property alias comboBox: comboBox diff --git a/interface/resources/qml/controls-uit/Label.qml b/interface/resources/qml/controls-uit/Label.qml index 3b4d757154..330d74fa14 100644 --- a/interface/resources/qml/controls-uit/Label.qml +++ b/interface/resources/qml/controls-uit/Label.qml @@ -13,6 +13,7 @@ import QtQuick 2.5 import "../styles-uit" RalewaySemiBold { + HifiConstants { id: hifi } property int colorScheme: hifi.colorSchemes.light size: hifi.fontSizes.inputLabel diff --git a/interface/resources/qml/controls-uit/WebView.qml b/interface/resources/qml/controls-uit/WebView.qml index b599e29fe0..faf7f746a2 100644 --- a/interface/resources/qml/controls-uit/WebView.qml +++ b/interface/resources/qml/controls-uit/WebView.qml @@ -25,6 +25,8 @@ WebEngineView { }); } + + // FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6 Timer { id: urlReplacementTimer @@ -59,11 +61,6 @@ WebEngineView { } } - onNewViewRequested:{ - var component = Qt.createComponent("../Browser.qml"); - var newWindow = component.createObject(desktop); - request.openIn(newWindow.webView) - } // This breaks the webchannel used for passing messages. Fixed in Qt 5.6 // See https://bugreports.qt.io/browse/QTBUG-49521 diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 561bd722f2..62f31f07fc 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -20,6 +20,8 @@ OriginalDesktop.Desktop { onEntered: ApplicationCompositor.reticleOverDesktop = true onExited: ApplicationCompositor.reticleOverDesktop = false acceptedButtons: Qt.NoButton + + } // The tool window, one instance @@ -71,6 +73,39 @@ OriginalDesktop.Desktop { }); } + // Accept a download through the webview + property bool webViewProfileSetup: false + property string currentUrl: "" + property string adaptedPath: "" + property string tempDir: "" + + function initWebviewProfileHandlers(profile) { + console.log("The webview url in desktop is: " + currentUrl); + if (webViewProfileSetup) return; + webViewProfileSetup = true; + + profile.downloadRequested.connect(function(download){ + console.log("Download start: " + download.state); + adaptedPath = File.convertUrlToPath(currentUrl); + tempDir = File.getTempDir(); + console.log("Temp dir created: " + tempDir); + download.path = tempDir + "/" + adaptedPath; + console.log("Path where object should download: " + download.path); + download.accept(); + if (download.state === WebEngineDownloadItem.DownloadInterrupted) { + console.log("download failed to complete"); + } + }) + + profile.downloadFinished.connect(function(download){ + if (download.state === WebEngineDownloadItem.DownloadCompleted) { + File.runUnzip(download.path, currentUrl); + } else { + console.log("The download was corrupted, state: " + download.state); + } + }) + } + // Create or fetch a toolbar with the given name function getToolbar(name) { var result = toolbars[name]; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30e2cfd9c6..5a129bc980 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -1578,6 +1579,9 @@ void Application::initializeUi() { rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); + FileScriptingInterface* fileDownload = new FileScriptingInterface(engine); + rootContext->setContextProperty("File", fileDownload); + connect(fileDownload, &FileScriptingInterface::unzipSuccess, this, &Application::showAssetServerWidget); rootContext->setContextProperty("MyAvatar", getMyAvatar()); rootContext->setContextProperty("Messages", DependencyManager::get().data()); rootContext->setContextProperty("Recording", DependencyManager::get().data()); @@ -2024,7 +2028,6 @@ bool Application::importJSONFromURL(const QString& urlString) { } bool Application::importSVOFromURL(const QString& urlString) { - emit svoImportRequested(urlString); return true; } @@ -2149,13 +2152,15 @@ bool Application::event(QEvent* event) { // handle custom URL if (event->type() == QEvent::FileOpen) { - QFileOpenEvent* fileEvent = static_cast(event); + QFileOpenEvent* fileEvent = static_cast(event); QUrl url = fileEvent->url(); if (!url.isEmpty()) { QString urlString = url.toString(); + if (canAcceptURL(urlString)) { + return acceptURL(urlString); } } @@ -5021,7 +5026,6 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { } bool Application::askToWearAvatarAttachmentUrl(const QString& url) { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(url); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); @@ -5119,11 +5123,11 @@ void Application::toggleRunningScriptsWidget() const { //} } + void Application::showAssetServerWidget(QString filePath) { if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { return; } - static const QUrl url { "AssetServer.qml" }; auto startUpload = [=](QQmlContext* context, QObject* newObject){ diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 48fda99b9d..c3a9a9f38a 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,3 +1,15 @@ set(TARGET_NAME script-engine) setup_hifi_library(Gui Network Script ScriptTools WebSockets Widgets) + +target_zlib() + +add_dependency_external_projects(quazip) +find_package(QuaZip REQUIRED) +target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES}) + +if (WIN32) + add_paths_to_fixup_libs(${QUAZIP_DLL_PATH}) +endif () + link_hifi_libraries(shared networking octree gpu ui procedural model model-networking recording avatars fbx entities controllers animation audio physics) diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp new file mode 100644 index 0000000000..fa38e46d31 --- /dev/null +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -0,0 +1,145 @@ +// +// FileScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Elisa Lupin-Jimenez on 6/28/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ResourceManager.h" + +#include "FileScriptingInterface.h" + + +FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent) { + // nothing for now +} + +void FileScriptingInterface::runUnzip(QString path, QUrl url) { + qDebug() << "Url that was downloaded: " + url.toString(); + qDebug() << "Path where download is saved: " + path; + QString fileName = "/" + path.section("/", -1); + QString tempDir = path; + tempDir.remove(fileName); + qDebug() << "Temporary directory at: " + tempDir; + if (!isTempDir(tempDir)) { + qDebug() << "Temporary directory mismatch; risk of losing files"; + return; + } + + QString file = unzipFile(path, tempDir); + if (file != "") { + qDebug() << "Object file to upload: " + file; + QUrl url = QUrl::fromLocalFile(file); + emit unzipSuccess(url.toString()); + } else { + qDebug() << "unzip failed"; + } + qDebug() << "Removing temporary directory at: " + tempDir; + QDir(tempDir).removeRecursively(); +} + +// fix to check that we are only referring to a temporary directory +bool FileScriptingInterface::isTempDir(QString tempDir) { + QString folderName = "/" + tempDir.section("/", -1); + QString tempContainer = tempDir; + tempContainer.remove(folderName); + QTemporaryDir test; + QString testDir = test.path(); + folderName = "/" + testDir.section("/", -1); + QString testContainer = testDir; + testContainer.remove(folderName); + if (testContainer == tempContainer) return true; + return false; +} + +bool FileScriptingInterface::isZippedFbx(QUrl url) { + if (url.toString().contains(".zip") && url.toString().contains("fbx")) return true; + return false; +} + +// this function is not in use +QString FileScriptingInterface::getTempDir() { + QTemporaryDir dir; + dir.setAutoRemove(false); + return dir.path(); + // do something to delete this temp dir later +} + +QString FileScriptingInterface::convertUrlToPath(QUrl url) { + QString newUrl; + QString oldUrl = url.toString(); + newUrl = oldUrl.section("filename=", 1, 1); + qDebug() << "Filename should be: " + newUrl; + return newUrl; +} + +// this function is not in use +void FileScriptingInterface::downloadZip(QString path, const QString link) { + QUrl url = QUrl(link); + auto request = ResourceManager::createResourceRequest(nullptr, url); + connect(request, &ResourceRequest::finished, this, [this, path]{ + unzipFile(path, ""); // so intellisense isn't mad + }); + request->send(); +} + + +QString FileScriptingInterface::unzipFile(QString path, QString tempDir) { + + QDir dir(path); + QString dirName = dir.path(); + QString target = tempDir + "/model_repo"; + QStringList list = JlCompress::extractDir(dirName, target); + + qDebug() << list; + + if (!list.isEmpty()) { + return list.front(); + } else { + qDebug() << "Extraction failed"; + return ""; + } + +} + +// this function is not in use +void FileScriptingInterface::recursiveFileScan(QFileInfo file, QString* dirName) { + /*if (!file.isDir()) { + qDebug() << "Regular file logged: " + file.fileName(); + return; + }*/ + QFileInfoList files; + + if (file.fileName().contains(".zip")) { + qDebug() << "Extracting archive: " + file.fileName(); + JlCompress::extractDir(file.fileName()); + } + files = file.dir().entryInfoList(); + + /*if (files.empty()) { + files = JlCompress::getFileList(file.fileName()); + }*/ + + foreach (QFileInfo file, files) { + qDebug() << "Looking into file: " + file.fileName(); + recursiveFileScan(file, dirName); + } + return; +} diff --git a/libraries/script-engine/src/FileScriptingInterface.h b/libraries/script-engine/src/FileScriptingInterface.h new file mode 100644 index 0000000000..dd6ca3225b --- /dev/null +++ b/libraries/script-engine/src/FileScriptingInterface.h @@ -0,0 +1,43 @@ +// +// FileScriptingInterface.h +// libraries/script-engine/src +// +// Created by Elisa Lupin-Jimenez on 6/28/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_FileScriptingInterface_h +#define hifi_FileScriptingInterface_h + +#include +#include +#include + +class FileScriptingInterface : public QObject { + Q_OBJECT + +public: + FileScriptingInterface(QObject* parent); + + +public slots: + bool isZippedFbx(QUrl url); + QString convertUrlToPath(QUrl url); + void runUnzip(QString path, QUrl url); + QString getTempDir(); + +signals: + void unzipSuccess(QString url); + +private: + bool isTempDir(QString tempDir); + QString unzipFile(QString path, QString tempDir); + void recursiveFileScan(QFileInfo file, QString* dirName); + void downloadZip(QString path, const QString link); + +}; + +#endif // hifi_FileScriptingInterface_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2fccd81c42..0ac2883cb5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -49,6 +49,7 @@ #include "BatchLoader.h" #include "DataViewClass.h" #include "EventTypes.h" +#include "FileScriptingInterface.h" // unzip project #include "MenuItemProperties.h" #include "ScriptAudioInjector.h" #include "ScriptCache.h" @@ -501,6 +502,9 @@ void ScriptEngine::init() { registerGlobalObject("Mat4", &_mat4Library); registerGlobalObject("Uuid", &_uuidLibrary); registerGlobalObject("Messages", DependencyManager::get().data()); + + registerGlobalObject("File", new FileScriptingInterface(this)); + qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 153d39f1f4..5aa3c6945b 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -15,7 +15,7 @@ Script.load("system/users.js"); Script.load("system/mute.js"); Script.load("system/goto.js"); Script.load("system/hmd.js"); -Script.load("system/marketplace.js"); +Script.load("system/marketplaces/marketplace.js"); Script.load("system/edit.js"); Script.load("system/mod.js"); Script.load("system/selectAudioDevice.js"); diff --git a/scripts/system/marketplaces/clara.js b/scripts/system/marketplaces/clara.js new file mode 100644 index 0000000000..7b48f49135 --- /dev/null +++ b/scripts/system/marketplaces/clara.js @@ -0,0 +1,79 @@ +// +// clara.js +// +// Created by Eric Levin on 8 Jan 2016 +// Edited by Elisa Lupin-Jimenez on 23 Aug 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var toolIconUrl = Script.resolvePath("../assets/images/tools/"); +var qml = Script.resolvePath("../../../resources/qml/MarketplaceComboBox.qml") + +var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace"; + +var marketplaceWindow = new OverlayWindow({ + title: "Marketplace", + source: qml, + width: 900, + height: 700, + toolWindow: false, + visible: false, +}); + +var toolHeight = 50; +var toolWidth = 50; +var TOOLBAR_MARGIN_Y = 0; + + +function showMarketplace(marketplaceID) { + var url = MARKETPLACE_URL; + if (marketplaceID) { + url = url + "/items/" + marketplaceID; + } + marketplaceWindow.setVisible(true); + + UserActivityLogger.openedMarketplace(); +} + +function hideMarketplace() { + marketplaceWindow.setVisible(false); +} + +function toggleMarketplace() { + if (marketplaceWindow.visible) { + hideMarketplace(); + } else { + showMarketplace(); + } +} + +var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); + +var browseExamplesButton = toolBar.addButton({ + imageURL: toolIconUrl + "market.svg", + objectName: "marketplace", + buttonState: 1, + defaultState: 1, + hoverState: 3, + alpha: 0.9 +}); + +function onExamplesWindowVisibilityChanged() { + browseExamplesButton.writeProperty('buttonState', marketplaceWindow.visible ? 0 : 1); + browseExamplesButton.writeProperty('defaultState', marketplaceWindow.visible ? 0 : 1); + browseExamplesButton.writeProperty('hoverState', marketplaceWindow.visible ? 2 : 3); +} +function onClick() { + toggleMarketplace(); +} +browseExamplesButton.clicked.connect(onClick); +marketplaceWindow.visibleChanged.connect(onExamplesWindowVisibilityChanged); + +Script.scriptEnding.connect(function () { + toolBar.removeButton("marketplace"); + browseExamplesButton.clicked.disconnect(onClick); + marketplaceWindow.visibleChanged.disconnect(onExamplesWindowVisibilityChanged); +}); diff --git a/scripts/system/marketplace.js b/scripts/system/marketplaces/marketplace.js similarity index 96% rename from scripts/system/marketplace.js rename to scripts/system/marketplaces/marketplace.js index 356ed8e8cf..a43ef6c977 100644 --- a/scripts/system/marketplace.js +++ b/scripts/system/marketplaces/marketplace.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var toolIconUrl = Script.resolvePath("assets/images/tools/"); +var toolIconUrl = Script.resolvePath("../assets/images/tools/"); var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace"; var marketplaceWindow = new OverlayWebWindow({ @@ -74,4 +74,4 @@ Script.scriptEnding.connect(function () { toolBar.removeButton("marketplace"); browseExamplesButton.clicked.disconnect(onClick); marketplaceWindow.visibleChanged.disconnect(onExamplesWindowVisibilityChanged); -}); +}); \ No newline at end of file