From 631aad80f9b891739fe250767c74ba9d6b7979dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 11 Mar 2016 09:53:08 -0800 Subject: [PATCH 1/4] Add Q_DECLARE_METATYPE(AssetMappingModel*) and fix indentation --- .../AssetMappingsScriptingInterface.h | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 99ced25d29..35a1c1ae7e 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -20,31 +20,32 @@ #include #include - class AssetMappingItem : public QStandardItem { - public: - AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); +class AssetMappingItem : public QStandardItem { +public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); - QString name; - QString fullPath; - bool isFolder; - }; + QString name; + QString fullPath; + bool isFolder; +}; - class AssetMappingModel : public QStandardItemModel { - Q_OBJECT - public: - Q_INVOKABLE void refresh(); +class AssetMappingModel : public QStandardItemModel { + Q_OBJECT +public: + Q_INVOKABLE void refresh(); - bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } - bool isKnownFolder(QString path) const; + bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); } + bool isKnownFolder(QString path) const; - signals: - void errorGettingMappings(int error); +signals: + void errorGettingMappings(int error); - private: - QHash _pathToItemMap; - }; +private: + QHash _pathToItemMap; +}; +Q_DECLARE_METATYPE(AssetMappingModel*); class AssetMappingsScriptingInterface : public QObject { Q_OBJECT From 6c27bd9eb26042e9ca1443e5a3707218597a01cd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 13 Mar 2016 21:04:07 -0700 Subject: [PATCH 2/4] Update upload flow and make asset list dynamically sized --- interface/resources/qml/AssetServer.qml | 230 ++++++++++-------- .../AssetMappingsScriptingInterface.cpp | 19 +- .../AssetMappingsScriptingInterface.h | 2 +- 3 files changed, 139 insertions(+), 112 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c5ebb04819..3ed562f59a 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -36,7 +36,6 @@ Window { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property alias currentFileUrl: fileUrlTextField.text; Settings { category: "Overlay.AssetServer" @@ -46,8 +45,8 @@ Window { } Component.onCompleted: { - assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError) - reload() + assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); + reload(); } function doDeleteFile(path) { @@ -220,47 +219,69 @@ Window { }); } - function chooseClicked() { - var browser = desktop.fileDialog({ - selectDirectory: false, - dir: currentDirectory - }); - browser.selectedFile.connect(function(url){ - fileUrlTextField.text = fileDialogHelper.urlToPath(url); - currentDirectory = browser.dir; - }); - } property var uploadOpen: false; + Timer { + id: timer + } function uploadClicked() { if (uploadOpen) { return; } uploadOpen = true; - var fileUrl = fileUrlTextField.text - var shouldAddToWorld = addToWorldCheckBox.checked + var fileUrl = ""; - var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); - var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; - var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - - Assets.uploadFile(fileUrl, directory + filename, function(err, path) { - if (err) { - console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); - var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); - box.selected.connect(reload); - } else { - console.log("Asset Browser - finished uploading: ", fileUrl); - - if (shouldAddToWorld) { - addToWorld("atp:" + path); - } - - reload(); - } + var browser = desktop.fileDialog({ + selectDirectory: false, + dir: currentDirectory + }); + browser.canceled.connect(function() { + uploadOpen = false; + }); + browser.selectedFile.connect(function(url){ + var fileUrl = fileDialogHelper.urlToPath(url); + currentDirectory = browser.dir; + + //var fileUrl = fileUrlTextField.text + + var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; + var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); + + Assets.uploadFile(fileUrl, directory + filename, + function() { + // Upload started + uploadSpinner.visible = true; + uploadButton.enabled = false; + uploadProgressLabel.text = "In progress..."; + }, + function(err, path) { + print(err, path); + if (!err) { + uploadProgressLabel.text = "Upload Complete"; + timer.interval = 1000; + timer.repeat = false; + timer.triggered.connect(function() { + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + }); + timer.start(); + console.log("Asset Browser - finished uploading: ", fileUrl); + reload(); + } else { + if (err > 0) { + console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); + var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); + } + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + } + }) }); - uploadOpen = false; } function errorMessageBox(message) { @@ -272,8 +293,9 @@ Window { }); } - Column { + Item { width: pane.contentWidth + height: pane.height HifiControls.ContentSection { id: assetDirectory @@ -359,99 +381,95 @@ Window { } } } + } - HifiControls.Tree { - id: treeView - height: 400 - treeModel: assetProxyModel - colorScheme: root.colorScheme - anchors.left: parent.left - anchors.right: parent.right - MouseArea { - propagateComposedEvents: true - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: { - var index = treeView.indexAt(mouse.x, mouse.y); - contextMenu.currentIndex = index; - contextMenu.popup(); - } + HifiControls.Tree { + id: treeView + anchors.top: assetDirectory.bottom + anchors.bottom: uploadSection.top + anchors.margins: 12 + anchors.bottomMargin: 0 + treeModel: assetProxyModel + colorScheme: root.colorScheme + anchors.left: parent.left + anchors.right: parent.right + MouseArea { + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + print("onClicked"); + var index = treeView.indexAt(mouse.x, mouse.y); + print("onClicked", assetProxyModel.data(index, 0x0100)); + treeView.selection.select(index, 0x0001 | 0x0002 | 0x0010 | 0x0020); + print("done"); + //contextMenu.currentIndex = index; + //treeView.selection.clearSelection() + //treeView.selection.clear(); + //contextMenu.popup(); } } } - HifiControls.ContentSection { id: uploadSection - name: "" + name: "Upload A File" spacing: hifi.dimensions.contentSpacing.y - - HifiControls.TextField { - id: fileUrlTextField - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: chooseButton.width + hifi.dimensions.contentSpacing.x - - label: "Upload File" - placeholderText: "Paste URL or choose file" - colorScheme: root.colorScheme - } + anchors.bottom: parent.bottom + height: 130 Item { - // Take the chooseButton out of the column flow. - id: chooseButtonContainer - anchors.top: fileUrlTextField.top - anchors.right: parent.right - - HifiControls.Button { - id: chooseButton - anchors.right: parent.right - - text: "Choose" - color: hifi.buttons.white - colorScheme: root.colorScheme - enabled: true - - width: 100 - - onClicked: root.chooseClicked() - } - } - - HifiControls.CheckBox { - id: addToWorldCheckBox - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: uploadButton.width + hifi.dimensions.contentSpacing.x - - text: "Add to world on upload" - - opacity: canAddToWorld(fileUrlTextField.text) ? 1 : 0 - - checked: false - } - - Item { - // Take the uploadButton out of the column flow. - id: uploadButtonContainer - anchors.top: addToWorldCheckBox.top - anchors.right: parent.right - + height: parent.height + width: parent.width HifiControls.Button { id: uploadButton anchors.right: parent.right - text: "Upload" + text: "Choose File" color: hifi.buttons.blue colorScheme: root.colorScheme height: 30 width: 155 - enabled: fileUrlTextField.text != "" onClicked: root.uploadClicked() } + + Item { + id: uploadSpinner + visible: false + anchors.top: parent.top + anchors.left: parent.left + width: 40 + height: 32 + + Image { + id: image + width: 24 + height: 24 + source: "../images/Loading-Outer-Ring.png" + RotationAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + duration: 2000 + } + } + Image { + width: 24 + height: 24 + source: "../images/Loading-Inner-H.png" + } + HifiControls.Label { + id: uploadProgressLabel + anchors.left: image.right + anchors.leftMargin: 10 + anchors.verticalCenter: image.verticalCenter + text: "In progress..." + colorScheme: root.colorScheme + } + + } } - HifiControls.VerticalSpacer {} } } } diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 32b697459c..0a2a12ee24 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -80,11 +80,16 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback request->start(); } -void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { + static const QString helpText = + "Upload your asset to a specific folder by enter the full path. Specifying " + "a new folder name will automatically create that folder for you."; + auto offscreenUi = DependencyManager::get(); - auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", helpText, mapping); if (!result.isValid()) { + completedCallback.call({ -1 }); return; } mapping = result.toString(); @@ -100,19 +105,22 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (button == QMessageBox::No) { + completedCallback.call({ -1 }); return; } } + startedCallback.call(); + auto upload = DependencyManager::get()->createUpload(path); QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { if (upload->getError() != AssetUpload::NoError) { - if (callback.isCallable()) { + if (completedCallback.isCallable()) { QJSValueList args { uint8_t(upload->getError()) }; - callback.call(args); + completedCallback.call(args); } } else { - setMapping(mapping, hash, callback); + setMapping(mapping, hash, completedCallback); } upload->deleteLater(); @@ -198,6 +206,7 @@ AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, } + static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); void AssetMappingModel::refresh() { diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index 35a1c1ae7e..5465901ed4 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -64,7 +64,7 @@ public: Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); - Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); From 960047f4127ac15fbbec04f2febd790474c65d93 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 13 Mar 2016 21:06:52 -0700 Subject: [PATCH 3/4] Remove right click selection --- interface/resources/qml/AssetServer.qml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3ed562f59a..b6d86b17fd 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -398,15 +398,9 @@ Window { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - print("onClicked"); var index = treeView.indexAt(mouse.x, mouse.y); - print("onClicked", assetProxyModel.data(index, 0x0100)); - treeView.selection.select(index, 0x0001 | 0x0002 | 0x0010 | 0x0020); - print("done"); - //contextMenu.currentIndex = index; - //treeView.selection.clearSelection() - //treeView.selection.clear(); - //contextMenu.popup(); + contextMenu.currentIndex = index; + contextMenu.popup(); } } } From 7947bd77241fcceed9fe16c0d1ce3ce4b10a6877 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 15 Mar 2016 10:11:53 -0700 Subject: [PATCH 4/4] Fix message typo enter => entering --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index f75a597733..64a378e14d 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -61,7 +61,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue startedCallback, QJSValue completedCallback) { static const QString helpText = - "Upload your asset to a specific folder by enter the full path. Specifying " + "Upload your asset to a specific folder by entering the full path. Specifying " "a new folder name will automatically create that folder for you."; auto offscreenUi = DependencyManager::get();