Merge pull request #110 from huffman/atp-upload

Atp upload updates
This commit is contained in:
Clément Brisset 2016-03-15 10:19:44 -07:00
commit 47f18e5166
3 changed files with 146 additions and 125 deletions

View file

@ -36,7 +36,6 @@ Window {
property var assetProxyModel: Assets.proxyModel; property var assetProxyModel: Assets.proxyModel;
property var assetMappingsModel: Assets.mappingModel; property var assetMappingsModel: Assets.mappingModel;
property var currentDirectory; property var currentDirectory;
property alias currentFileUrl: fileUrlTextField.text;
Settings { Settings {
category: "Overlay.AssetServer" category: "Overlay.AssetServer"
@ -46,8 +45,8 @@ Window {
} }
Component.onCompleted: { Component.onCompleted: {
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError) assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
reload() reload();
} }
function doDeleteFile(path) { function doDeleteFile(path) {
@ -241,47 +240,67 @@ 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; property var uploadOpen: false;
Timer {
id: timer
}
function uploadClicked() { function uploadClicked() {
if (uploadOpen) { if (uploadOpen) {
return; return;
} }
uploadOpen = true; uploadOpen = true;
var fileUrl = fileUrlTextField.text var fileUrl = "";
var shouldAddToWorld = addToWorldCheckBox.checked
var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100); var browser = desktop.fileDialog({
var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; selectDirectory: false,
var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); dir: currentDirectory
});
Assets.uploadFile(fileUrl, directory + filename, function(err, path) { browser.canceled.connect(function() {
if (err) { uploadOpen = false;
console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); });
var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err); browser.selectedFile.connect(function(url){
box.selected.connect(reload); var fileUrl = fileDialogHelper.urlToPath(url);
} else { currentDirectory = browser.dir;
console.log("Asset Browser - finished uploading: ", fileUrl);
var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100);
if (shouldAddToWorld) { var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/";
addToWorld("atp:" + path); var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1);
}
Assets.uploadFile(fileUrl, directory + filename,
reload(); 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 = errorMessageBox("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) { function errorMessageBox(message) {
@ -297,8 +316,9 @@ Window {
return treeView.selection.hasSelection() return treeView.selection.hasSelection()
} }
Column { Item {
width: pane.contentWidth width: pane.contentWidth
height: pane.height
HifiControls.ContentSection { HifiControls.ContentSection {
id: assetDirectory id: assetDirectory
@ -386,96 +406,52 @@ Window {
} }
} }
} }
}
HifiControls.Tree { HifiControls.Tree {
id: treeView id: treeView
height: 400 anchors.top: assetDirectory.bottom
treeModel: assetProxyModel anchors.bottom: uploadSection.top
colorScheme: root.colorScheme anchors.margins: 12
canEdit: true anchors.bottomMargin: 0
anchors.left: parent.left
anchors.right: parent.right
anchors.left: parent.left treeModel: assetProxyModel
anchors.right: parent.right canEdit: true
colorScheme: root.colorScheme
modifyEl: renameEl modifyEl: renameEl
MouseArea { MouseArea {
propagateComposedEvents: true propagateComposedEvents: true
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onClicked: { onClicked: {
var index = treeView.indexAt(mouse.x, mouse.y); var index = treeView.indexAt(mouse.x, mouse.y);
treeView.selection.setCurrentIndex(index, 0x0002); treeView.selection.setCurrentIndex(index, 0x0002);
contextMenu.currentIndex = index; contextMenu.currentIndex = index;
contextMenu.popup(); contextMenu.popup();
}
} }
} }
} }
HifiControls.ContentSection { HifiControls.ContentSection {
id: uploadSection id: uploadSection
name: "" name: "Upload A File"
spacing: hifi.dimensions.contentSpacing.y spacing: hifi.dimensions.contentSpacing.y
anchors.bottom: parent.bottom
HifiControls.TextField { height: 130
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
}
Item { Item {
// Take the chooseButton out of the column flow. height: parent.height
id: chooseButtonContainer width: parent.width
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
HifiControls.Button { HifiControls.Button {
id: uploadButton id: uploadButton
anchors.right: parent.right anchors.right: parent.right
text: "Upload" text: "Choose File"
color: hifi.buttons.blue color: hifi.buttons.blue
colorScheme: root.colorScheme colorScheme: root.colorScheme
height: 30 height: 30
@ -499,9 +475,44 @@ Window {
onTriggered: uploadClicked(); onTriggered: 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 {}
} }
} }
} }

View file

@ -59,11 +59,16 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback
request->start(); 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 entering the full path. Specifying "
"a new folder name will automatically create that folder for you.";
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
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()) { if (!result.isValid()) {
completedCallback.call({ -1 });
return; return;
} }
mapping = result.toString(); mapping = result.toString();
@ -79,19 +84,22 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping,
auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No); QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (button == QMessageBox::No) { if (button == QMessageBox::No) {
completedCallback.call({ -1 });
return; return;
} }
} }
startedCallback.call();
auto upload = DependencyManager::get<AssetClient>()->createUpload(path); auto upload = DependencyManager::get<AssetClient>()->createUpload(path);
QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
if (upload->getError() != AssetUpload::NoError) { if (upload->getError() != AssetUpload::NoError) {
if (callback.isCallable()) { if (completedCallback.isCallable()) {
QJSValueList args { upload->getErrorString() }; QJSValueList args { upload->getErrorString() };
callback.call(args); completedCallback.call(args);
} }
} else { } else {
setMapping(mapping, hash, callback); setMapping(mapping, hash, completedCallback);
} }
upload->deleteLater(); upload->deleteLater();

View file

@ -20,21 +20,23 @@
#include <AssetClient.h> #include <AssetClient.h>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
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;
signals: class AssetMappingModel : public QStandardItemModel {
void errorGettingMappings(QString errorString); Q_OBJECT
public:
Q_INVOKABLE void refresh();
private: bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }
QHash<QString, QStandardItem*> _pathToItemMap; bool isKnownFolder(QString path) const;
};
void errorGettingMappings(QString errorString);
private:
QHash<QString, QStandardItem*> _pathToItemMap;
};
Q_DECLARE_METATYPE(AssetMappingModel*);
class AssetMappingsScriptingInterface : public QObject { class AssetMappingsScriptingInterface : public QObject {
Q_OBJECT Q_OBJECT
@ -51,7 +53,7 @@ public:
Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue());
Q_INVOKABLE void getMapping(QString path, 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 deleteMappings(QStringList paths, QJSValue callback);
Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); }
Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue());