diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 04e8bcb9ef..b056a8e378 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5724,18 +5724,18 @@ void Application::showAssetServerWidget(QString filePath) { } void Application::addAssetToWorldFromURL(QString url) { - qInfo(interfaceapp) << "Download asset and add to world from" << url; + qInfo(interfaceapp) << "Download model and add to world from" << url; QString filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { QString errorInfo = "You do not have permissions to write to the Asset Server."; - qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filename, errorInfo); return; } - addAssetToWorldInfo(filename, "Downloading asset file " + filename + "."); + addAssetToWorldInfo(filename, "Downloading model file " + filename + "."); auto request = ResourceManager::createResourceRequest(nullptr, QUrl(url)); connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished); @@ -5750,7 +5750,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { QString filename = url.section("filename=", 1, 1); // Filename from trailing "?filename=" URL parameter. if (result == ResourceRequest::Success) { - qInfo(interfaceapp) << "Downloaded asset from" << url; + qInfo(interfaceapp) << "Downloaded model from" << url; QTemporaryDir temporaryDir; temporaryDir.setAutoRemove(false); if (temporaryDir.isValid()) { @@ -5802,7 +5802,7 @@ void Application::addAssetToWorld(QString filePath) { // Test repeated because possibly different code paths. if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { QString errorInfo = "You do not have permissions to write to the Asset Server."; - qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filename, errorInfo); return; } @@ -5823,7 +5823,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin } else if (result != GetMappingRequest::NoError) { QString errorInfo = "Could not map asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); - qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else if (copy < MAX_COPY_COUNT - 1) { if (copy > 0) { @@ -5835,7 +5835,7 @@ void Application::addAssetToWorldWithNewMapping(QString filePath, QString mappin } else { QString errorInfo = "Too many copies of asset name: " + mapping.left(mapping.length() - QString::number(copy).length() - 1); - qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } request->deleteLater(); @@ -5849,8 +5849,8 @@ void Application::addAssetToWorldUpload(QString filePath, QString mapping) { auto upload = DependencyManager::get()->createUpload(filePath); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { - QString errorInfo = "Could not upload asset to the Asset Server."; - qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; + QString errorInfo = "Could not upload model to the Asset Server."; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { addAssetToWorldSetMapping(filePath, mapping, hash); @@ -5875,7 +5875,7 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q connect(request, &SetMappingRequest::finished, this, [=](SetMappingRequest* request) mutable { if (request->getError() != SetMappingRequest::NoError) { QString errorInfo = "Could not set asset mapping."; - qWarning(interfaceapp) << "Error downloading asset: " + errorInfo; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { addAssetToWorldAddEntity(filePath, mapping); @@ -5902,8 +5902,8 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { // on. But FBX dimensions may be in cm, so we monitor for the dimension change and rescale again if warranted. if (entityID == QUuid()) { - QString errorInfo = "Could not add asset " + mapping + " to world."; - qWarning(interfaceapp) << "Could not add asset to world: " + errorInfo; + QString errorInfo = "Could not add model " + mapping + " to world."; + qWarning(interfaceapp) << "Could not add model to world: " + errorInfo; addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { // Monitor when asset is rendered in world so that can resize if necessary. @@ -5946,7 +5946,7 @@ void Application::addAssetToWorldCheckModelSize() { auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y, MAXIMUM_DIMENSION / dimensions.z)); dimensions *= scale; - qInfo(interfaceapp) << "Asset" << name << "auto-resized from" << previousDimensions << " to " << dimensions; + qInfo(interfaceapp) << "Model" << name << "auto-resized from" << previousDimensions << " to " << dimensions; doResize = true; item = _addAssetToWorldResizeList.erase(item); // Finished with this entity; advance to next. @@ -5961,7 +5961,7 @@ void Application::addAssetToWorldCheckModelSize() { // Rescale all dimensions. const glm::vec3 UNIT_DIMENSIONS = glm::vec3(1.0f, 1.0f, 1.0f); dimensions = UNIT_DIMENSIONS; - qInfo(interfaceapp) << "Asset" << name << "auto-resize timed out; resized to " << dimensions; + qInfo(interfaceapp) << "Model" << name << "auto-resize timed out; resized to " << dimensions; doResize = true; item = _addAssetToWorldResizeList.erase(item); // Finished with this entity; advance to next. @@ -6014,7 +6014,7 @@ void Application::addAssetToWorldInfo(QString modelName, QString infoText) { if (!_addAssetToWorldErrorTimer.isActive()) { if (!_addAssetToWorldMessageBox) { _addAssetToWorldMessageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, - "Downloading Asset", "", QMessageBox::NoButton, QMessageBox::NoButton); + "Downloading Model", "", QMessageBox::NoButton, QMessageBox::NoButton); connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed())); } @@ -6079,7 +6079,6 @@ void Application::addAssetToWorldInfoTimeout() { } } - void Application::addAssetToWorldError(QString modelName, QString errorText) { // Displays the most recent error message for a few seconds. @@ -6098,7 +6097,7 @@ void Application::addAssetToWorldError(QString modelName, QString errorText) { if (!_addAssetToWorldMessageBox) { _addAssetToWorldMessageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, - "Downloading Asset", "", QMessageBox::NoButton, QMessageBox::NoButton); + "Downloading Model", "", QMessageBox::NoButton, QMessageBox::NoButton); connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed())); } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 765c9a8499..7cfbfb174e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -60,6 +60,19 @@ WindowScriptingInterface::WindowScriptingInterface() { }); } +WindowScriptingInterface::~WindowScriptingInterface() { + QHashIterator i(_messageBoxes); + while (i.hasNext()) { + i.next(); + auto messageBox = i.value(); + disconnect(messageBox); + messageBox->setVisible(false); + messageBox->deleteLater(); + } + + _messageBoxes.clear(); +} + QScriptValue WindowScriptingInterface::hasFocus() { return qApp->hasFocus(); } @@ -210,3 +223,62 @@ void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& hr bool WindowScriptingInterface::isPhysicsEnabled() { return qApp->isPhysicsEnabled(); } + +int WindowScriptingInterface::openMessageBox(QString title, QString text, int buttons, int defaultButton) { + if (QThread::currentThread() != thread()) { + int result; + QMetaObject::invokeMethod(this, "openMessageBox", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(int, result), + Q_ARG(QString, title), + Q_ARG(QString, text), + Q_ARG(int, buttons), + Q_ARG(int, defaultButton)); + return result; + } + + return createMessageBox(title, text, buttons, defaultButton); +} + +int WindowScriptingInterface::createMessageBox(QString title, QString text, int buttons, int defaultButton) { + auto messageBox = DependencyManager::get()->createMessageBox(OffscreenUi::ICON_INFORMATION, title, text, + static_cast>(buttons), static_cast(defaultButton)); + connect(messageBox, SIGNAL(selected(int)), this, SLOT(onMessageBoxSelected(int))); + + _lastMessageBoxID += 1; + _messageBoxes.insert(_lastMessageBoxID, messageBox); + + return _lastMessageBoxID; +} + +void WindowScriptingInterface::updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton) { + auto messageBox = _messageBoxes.value(id); + if (messageBox) { + messageBox->setProperty("title", title); + messageBox->setProperty("text", text); + messageBox->setProperty("buttons", buttons); + messageBox->setProperty("defaultButton", defaultButton); + } +} + +void WindowScriptingInterface::closeMessageBox(int id) { + auto messageBox = _messageBoxes.value(id); + if (messageBox) { + disconnect(messageBox); + messageBox->setVisible(false); + messageBox->deleteLater(); + _messageBoxes.remove(id); + } +} + +void WindowScriptingInterface::onMessageBoxSelected(int button) { + auto messageBox = qobject_cast(sender()); + auto keys = _messageBoxes.keys(messageBox); + if (keys.length() > 0) { + auto id = keys[0]; // Should be just one message box. + emit messageBoxClosed(id, button); + disconnect(messageBox); + messageBox->setVisible(false); + messageBox->deleteLater(); + _messageBoxes.remove(id); + } +} diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 6aa8707496..4652e00661 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -14,7 +14,9 @@ #include #include +#include #include +#include class CustomPromptResult { public: @@ -35,6 +37,7 @@ class WindowScriptingInterface : public QObject, public Dependency { Q_PROPERTY(int y READ getY) public: WindowScriptingInterface(); + ~WindowScriptingInterface(); int getInnerWidth(); int getInnerHeight(); int getX(); @@ -56,6 +59,13 @@ public slots: void shareSnapshot(const QString& path, const QUrl& href = QUrl("")); bool isPhysicsEnabled(); + int openMessageBox(QString title, QString text, int buttons, int defaultButton); + void updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton); + void closeMessageBox(int id); + +private slots: + void onMessageBoxSelected(int button); + signals: void domainChanged(const QString& domainHostname); void svoImportRequested(const QString& url); @@ -64,9 +74,15 @@ signals: void snapshotShared(const QString& error); void processingGif(); + void messageBoxClosed(int id, int button); + private: QString getPreviousBrowseLocation() const; void setPreviousBrowseLocation(const QString& location); + + int createMessageBox(QString title, QString text, int buttons, int defaultButton); + QHash _messageBoxes; + int _lastMessageBoxID{ -1 }; }; #endif // hifi_WindowScriptingInterface_h diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 8dad85a66d..0944c4113e 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -14,12 +14,17 @@ // Event bridge messages. var CLARA_IO_DOWNLOAD = "CLARA.IO DOWNLOAD"; + var CLARA_IO_STATUS = "CLARA.IO STATUS"; + var CLARA_IO_CANCEL_DOWNLOAD = "CLARA.IO CANCEL DOWNLOAD"; + var CLARA_IO_CANCELLED_DOWNLOAD = "CLARA.IO CANCELLED DOWNLOAD"; var GOTO_DIRECTORY = "GOTO_DIRECTORY"; var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS"; var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS"; var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS"; var canWriteAssets = false; + var xmlHttpRequest = null; + var isDownloading = false; // Explicitly track download request status. function injectCommonCode(isDirectoryPage) { @@ -75,10 +80,10 @@ // Add button links. $('#exploreClaraMarketplace').on('click', function () { - window.location = "https://clara.io/library?gameCheck=true&public=true" + window.location = "https://clara.io/library?gameCheck=true&public=true"; }); $('#exploreHifiMarketplace').on('click', function () { - window.location = "http://www.highfidelity.com/marketplace" + window.location = "http://www.highfidelity.com/marketplace"; }); } @@ -111,61 +116,147 @@ element.setAttribute("href", href + parameters); } - // Replace download options with a single, "Download to High Fidelity" option. + // Remove unwanted buttons and replace download options with a single "Download to High Fidelity" button. var buttons = $("a.embed-button").parent("div"); - if (buttons.length > 0) { - var downloadFBX = buttons.find("a[data-extension=\'fbx\']")[0]; - downloadFBX.addEventListener("click", startAutoDownload); - var firstButton = buttons.children(":first-child")[0]; - buttons[0].insertBefore(downloadFBX, firstButton); - downloadFBX.setAttribute("class", "btn btn-primary download"); - downloadFBX.innerHTML = " Download to High Fidelity"; - buttons.children(":nth-child(2), .btn-group , .embed-button").each(function () { this.remove(); }); + var downloadFBX; + if (buttons.find("div.btn-group").length > 0) { + buttons.children(".btn-primary, .btn-group , .embed-button").each(function () { this.remove(); }); + if ($("#hifi-download-container").length === 0) { // Button hasn't been moved already. + downloadFBX = $(' Download to High Fidelity'); + buttons.prepend(downloadFBX); + downloadFBX[0].addEventListener("click", startAutoDownload); + } } // Move the "Download to High Fidelity" button to be more visible on tablet. if ($("#hifi-download-container").length === 0 && window.innerWidth < 700) { - // Moving the button stops the Clara.io download from starting so instead, make a visual copy in the right place - // and wire its click event to click the original button. var downloadContainer = $('
'); $(".top-title .col-sm-4").append(downloadContainer); - var downloadButton = $("a[data-extension=\'fbx\']").clone(); - downloadButton[0].addEventListener("click", function () { downloadFBX.click(); }); - downloadContainer.append(downloadButton); - downloadFBX.style.visibility = "hidden"; + downloadContainer.append(downloadFBX); } // Automatic download to High Fidelity. - var downloadTimer; - function startAutoDownload(event) { - if (!canWriteAssets) { - console.log("Clara.io FBX file download cancelled because no permissions to write to Asset Server"); - EventBridge.emitWebEvent(WARN_USER_NO_PERMISSIONS); - event.stopPropagation(); + function startAutoDownload() { + + // One file request at a time. + if (isDownloading) { + console.log("WARNIKNG: Clara.io FBX: Prepare only one download at a time"); + return; } - window.scrollTo(0, 0); // Scroll to top ready for history.back(). - if (!downloadTimer) { - downloadTimer = setInterval(autoDownload, 1000); + // User must be able to write to Asset Server. + if (!canWriteAssets) { + console.log("ERROR: Clara.io FBX: File download cancelled because no permissions to write to Asset Server"); + EventBridge.emitWebEvent(WARN_USER_NO_PERMISSIONS); + event.stopPropagation(); + return; } - } - function autoDownload() { - if ($("div.download-body").length !== 0) { - var downloadButton = $("div.download-body a.download-file"); - if (downloadButton.length > 0) { - clearInterval(downloadTimer); - downloadTimer = null; - var href = downloadButton[0].href; - EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + href); - console.log("Clara.io FBX file download initiated for " + href); - $("a.btn.cancel").click(); - history.back(); // Remove history item created by clicking "download". - }; - } else if ($("div#view-signup_login_dialog").length === 0) { - // Don't stop checking for button if user is asked to log in. - clearInterval(downloadTimer); - downloadTimer = null; + + // User must be logged in. + var loginButton = $("#topnav a[href='/signup']"); + if (loginButton.length > 0) { + loginButton[0].click(); + return; } + + // Obtain zip file to download for requested asset. + // Reference: https://clara.io/learn/sdk/api/export + + //var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?zip=true¢erScene=true&alignSceneGround=true&fbxUnit=Meter&fbxVersion=7&fbxEmbedTextures=true&imageFormat=WebGL"; + // 13 Jan 2017: Specify FBX version 5 and remove some options in order to make Clara.io site more likely to + // be successful in generating zip files. + var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?fbxUnit=Meter&fbxVersion=5&fbxEmbedTextures=true&imageFormat=WebGL"; + + var uuid = location.href.match(/\/view\/([a-z0-9\-]*)/)[1]; + var url = XMLHTTPREQUEST_URL.replace("{uuid}", uuid); + + xmlHttpRequest = new XMLHttpRequest(); + var responseTextIndex = 0; + var zipFileURL = ""; + + xmlHttpRequest.onreadystatechange = function () { + // Messages are appended to responseText; process the new ones. + var message = this.responseText.slice(responseTextIndex); + var statusMessage = ""; + + if (isDownloading) { // Ignore messages in flight after finished/cancelled. + var lines = message.split(/[\n\r]+/); + + for (var i = 0, length = lines.length; i < length; i++) { + if (lines[i].slice(0, 5) === "data:") { + // Parse line. + var data; + try { + data = JSON.parse(lines[i].slice(5)); + } + catch (e) { + data = {}; + } + + // Extract status message. + if (data.hasOwnProperty("message") && data.message !== null) { + statusMessage = data.message; + console.log("Clara.io FBX: " + statusMessage); + } + + // Extract zip file URL. + if (data.hasOwnProperty("files") && data.files.length > 0) { + zipFileURL = data.files[0].url; + if (zipFileURL.slice(-4) !== ".zip") { + console.log(JSON.stringify(data)); // Data for debugging. + } + } + } + } + + if (statusMessage !== "") { + // Update the UI with the most recent status message. + EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); + } + } + + responseTextIndex = this.responseText.length; + }; + + // Note: onprogress doesn't have computable total length so can't use it to determine % complete. + + xmlHttpRequest.onload = function () { + var statusMessage = ""; + + if (!isDownloading) { + return; + } + + var HTTP_OK = 200; + if (this.status !== HTTP_OK) { + statusMessage = "Zip file request terminated with " + this.status + " " + this.statusText; + console.log("ERROR: Clara.io FBX: " + statusMessage); + EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); + return; + } + + if (zipFileURL.slice(-4) !== ".zip") { + statusMessage = "Error creating zip file for download."; + console.log("ERROR: Clara.io FBX: " + statusMessage + ": " + zipFileURL); + EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage); + return; + } + + EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL); + console.log("Clara.io FBX: File download initiated for " + zipFileURL); + + xmlHttpRequest = null; + isDownloading = false; + } + + isDownloading = true; + + console.log("Clara.io FBX: Request zip file for " + uuid); + EventBridge.emitWebEvent(CLARA_IO_STATUS + " Initiating download"); + + xmlHttpRequest.open("POST", url, true); + xmlHttpRequest.setRequestHeader("Accept", "text/event-stream"); + xmlHttpRequest.send(); } } } @@ -210,12 +301,27 @@ EventBridge.emitWebEvent(QUERY_CAN_WRITE_ASSETS); } + function cancelClaraDownload() { + isDownloading = false; + + if (xmlHttpRequest) { + xmlHttpRequest.abort(); + xmlHttpRequest = null; + console.log("Clara.io FBX: File download cancelled"); + EventBridge.emitWebEvent(CLARA_IO_CANCELLED_DOWNLOAD); + } + } + function onLoad() { EventBridge.scriptEventReceived.connect(function (message) { if (message.slice(0, CAN_WRITE_ASSETS.length) === CAN_WRITE_ASSETS) { canWriteAssets = message.slice(-4) === "true"; } + + if (message.slice(0, CLARA_IO_CANCEL_DOWNLOAD.length) === CLARA_IO_CANCEL_DOWNLOAD) { + cancelClaraDownload(); + } }); var DIRECTORY = 0; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index c173683c74..d5530e7db2 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -22,10 +22,21 @@ var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplaces // Event bridge messages. var CLARA_IO_DOWNLOAD = "CLARA.IO DOWNLOAD"; +var CLARA_IO_STATUS = "CLARA.IO STATUS"; +var CLARA_IO_CANCEL_DOWNLOAD = "CLARA.IO CANCEL DOWNLOAD"; +var CLARA_IO_CANCELLED_DOWNLOAD = "CLARA.IO CANCELLED DOWNLOAD"; var GOTO_DIRECTORY = "GOTO_DIRECTORY"; var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS"; var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS"; var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS"; + +var CLARA_DOWNLOAD_TITLE = "Preparing Download"; +var messageBox = null; +var isDownloadBeingCancelled = false; + +var CANCEL_BUTTON = 4194304; // QMessageBox::Cancel +var NO_BUTTON = 0; // QMessageBox::NoButton + var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server."; var marketplaceWindow = new OverlayWebWindow({ @@ -36,17 +47,71 @@ var marketplaceWindow = new OverlayWebWindow({ visible: false }); marketplaceWindow.setScriptURL(MARKETPLACES_INJECT_SCRIPT_URL); -marketplaceWindow.webEventReceived.connect(function (message) { + +function onWebEventReceived(message) { if (message === GOTO_DIRECTORY) { - marketplaceWindow.setURL(MARKETPLACES_URL); + var url = MARKETPLACES_URL; + if (marketplaceWindow.visible) { + marketplaceWindow.setURL(url); + } + if (marketplaceWebTablet) { + marketplaceWebTablet.setURL(url); + } + return; } if (message === QUERY_CAN_WRITE_ASSETS) { - marketplaceWindow.emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets()); + var canWriteAssets = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets(); + if (marketplaceWindow.visible) { + marketplaceWindow.emitScriptEvent(canWriteAssets); + } + if (marketplaceWebTablet) { + marketplaceWebTablet.getOverlayObject().emitScriptEvent(canWriteAssets); + } + return; } if (message === WARN_USER_NO_PERMISSIONS) { Window.alert(NO_PERMISSIONS_ERROR_MESSAGE); + return; } -}); + + if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) { + if (isDownloadBeingCancelled) { + return; + } + + var text = message.slice(CLARA_IO_STATUS.length); + if (messageBox === null) { + messageBox = Window.openMessageBox(CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON); + } else { + Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON); + } + return; + } + + if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) { + if (messageBox !== null) { + Window.closeMessageBox(messageBox); + messageBox = null; + } + return; + } + + if (message === CLARA_IO_CANCELLED_DOWNLOAD) { + isDownloadBeingCancelled = false; + } +} + +marketplaceWindow.webEventReceived.connect(onWebEventReceived); + +function onMessageBoxClosed(id, button) { + if (id === messageBox && button === CANCEL_BUTTON) { + isDownloadBeingCancelled = true; + messageBox = null; + marketplaceWindow.emitScriptEvent(CLARA_IO_CANCEL_DOWNLOAD); + } +} + +Window.messageBoxClosed.connect(onMessageBoxClosed); var toolHeight = 50; var toolWidth = 50; @@ -71,17 +136,7 @@ function showMarketplace() { marketplaceWebTablet = new WebTablet(MARKETPLACE_URL_INITIAL, null, null, true); Settings.setValue(persistenceKey, marketplaceWebTablet.pickle()); marketplaceWebTablet.setScriptURL(MARKETPLACES_INJECT_SCRIPT_URL); - marketplaceWebTablet.getOverlayObject().webEventReceived.connect(function (message) { - if (message === GOTO_DIRECTORY) { - marketplaceWebTablet.setURL(MARKETPLACES_URL); - } - if (message === QUERY_CAN_WRITE_ASSETS) { - marketplaceWebTablet.getOverlayObject().emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets()); - } - if (message === WARN_USER_NO_PERMISSIONS) { - Window.alert(NO_PERMISSIONS_ERROR_MESSAGE); - } - }); + marketplaceWebTablet.getOverlayObject().webEventReceived.connect(onWebEventReceived); } else { marketplaceWindow.setURL(MARKETPLACE_URL_INITIAL); marketplaceWindow.setVisible(true);