diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index fdb9b81d87..f9cc566d39 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -33,7 +33,7 @@ Window { HifiConstants { id: hifi } property var scripts: ScriptDiscoveryService; - property var scriptsModel: scripts.scriptsModelFilter + property var scriptsModel: Assets.mappingModel; property var currentDirectory; property alias currentFileUrl: fileUrlTextField.text; @@ -47,6 +47,11 @@ Window { function doDeleteFile(path) { console.log("Deleting " + path); + Assets.deleteMappings(path, function(err) { + print("Finished deleting path: ", path, err); + reload(); + }); + } function doUploadFile(path, mapping, addToWorld) { console.log("Uploading " + path + " to " + mapping + " (addToWorld: " + addToWorld + ")"); @@ -56,6 +61,10 @@ Window { function doRenameFile(oldPath, newPath) { console.log("Renaming " + oldPath + " to " + newPath); + Assets.renameMapping(oldPath, newPath, function(err) { + print("Finished rename: ", err); + reload(); + }); } function fileExists(destinationPath) { @@ -89,6 +98,7 @@ Window { function reload() { print("reload"); + scriptsModel.refresh(); } function addToWorld() { var path = scriptsModel.data(treeView.currentIndex, 0x100); @@ -111,7 +121,7 @@ Window { }); object.selected.connect(function(destinationPath) { if (fileExists(destinationPath)) { - askForOverride(path, function() { + askForOverride(destinationPath, function() { doRenameFile(path, destinationPath); }); } else { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 40670d42d7..17aebb6e49 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -412,6 +413,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); @@ -1266,6 +1268,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); + rootContext->setContextProperty("Assets", DependencyManager::get().data()); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); @@ -4282,8 +4285,8 @@ bool Application::askToSetAvatarUrl(const QString& url) { case FSTReader::HEAD_AND_BODY_MODEL: ok = QMessageBox::Ok == OffscreenUi::question("Set Avatar", - "Would you like to use '" + modelName + "' for your avatar?", - QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + "Would you like to use '" + modelName + "' for your avatar?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); break; default: diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 299039ae8e..e46c8c6524 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -12,6 +12,8 @@ #ifndef hifi_AssetClient_h #define hifi_AssetClient_h +#include +#include #include #include diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 0ab7d8fb36..afa20e551c 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -76,12 +76,12 @@ void GetAllMappingsRequest::doStart() { } - if (!error) { + if (!_error) { int numberOfMappings; message->readPrimitive(&numberOfMappings); for (auto i = 0; i < numberOfMappings; ++i) { auto path = message->readString(); - auto hash = message->readString(); + auto hash = message->read(SHA256_HASH_LENGTH).toHex(); _mappings[path] = hash; } } diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp new file mode 100644 index 0000000000..4dfc99b13f --- /dev/null +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp @@ -0,0 +1,221 @@ +// +// AssetMappingsScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Ryan Huffman on 2016-03-09. +// 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 "AssetMappingsScriptingInterface.h" + +#include + +#include +#include +#include +#include + +AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { +} +AssetMappingsScriptingInterface::~AssetMappingsScriptingInterface() { + qDebug() << "Destroying mapping interface"; +} + +void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createSetMappingRequest(path, hash); + + connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetMappingRequest(path); + + connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()), request->getHash() }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createDeleteMappingsRequest(paths); + + connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto map = callback.engine()->newObject(); + + for (auto& kv : mappings ) { + map.setProperty(kv.first, kv.second); + } + + QJSValueList args { uint8_t(request->getError()), map }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + +void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) { + auto assetClient = DependencyManager::get(); + auto request = assetClient->createRenameMappingRequest(oldPath, newPath); + + connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { + QJSValueList args { uint8_t(request->getError()) }; + + callback.call(args); + + request->deleteLater(); + + }); + + request->start(); +} + + +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) + : name(name), + fullPath(fullPath), + isFolder(isFolder) { + +} + +static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); + +AssetMappingModel::AssetMappingModel() { +} + +AssetMappingModel::~AssetMappingModel() { + qDebug() << " DEST"; +} + +void AssetMappingModel::refresh() { + qDebug() << "Refreshing asset mapping model"; + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable { + auto mappings = request->getMappings(); + auto existingPaths = _pathToItemMap.keys(); + for (auto& mapping : mappings) { + auto& path = mapping.first; + auto parts = path.split("/"); + auto length = parts.length(); + + existingPaths.removeOne(mapping.first); + + QString fullPath = ""; + + QStandardItem* lastItem = nullptr; + + for (int i = 0; i < length; ++i) { + fullPath += (i == 0 ? "" : "/") + parts[i]; + + auto it = _pathToItemMap.find(fullPath); + if (it == _pathToItemMap.end()) { + qDebug() << "prefix not found: " << fullPath; + auto item = new QStandardItem(parts[i]); + bool isFolder = i < length - 1; + item->setData(isFolder ? fullPath + "/" : fullPath, Qt::UserRole); + item->setData(isFolder, Qt::UserRole + 1); + if (lastItem) { + lastItem->setChild(lastItem->rowCount(), 0, item); + } else { + appendRow(item); + } + + lastItem = item; + _pathToItemMap[fullPath] = lastItem; + } + else { + lastItem = it.value(); + } + } + + Q_ASSERT(fullPath == path); + } + + // Remove folders from list + auto it = existingPaths.begin(); + while (it != existingPaths.end()) { + auto item = _pathToItemMap[*it]; + if (item->data(Qt::UserRole + 1).toBool()) { + it = existingPaths.erase(it); + } else { + ++it; + } + } + + for (auto& path : existingPaths) { + Q_ASSERT(_pathToItemMap.contains(path)); + qDebug() << "removing existing: " << path; + + auto item = _pathToItemMap[path]; + + while (item) { + // During each iteration, delete item + QStandardItem* nextItem = nullptr; + + auto parent = item->parent(); + if (parent) { + parent->removeRow(item->row()); + if (parent->rowCount() > 0) { + // The parent still contains children, set the nextItem to null so we stop processing + nextItem = nullptr; + } else { + nextItem = parent; + } + } else { + removeRow(item->row()); + } + + _pathToItemMap.remove(path); + //delete item; + + item = nextItem; + } + //removeitem->index(); + } + }); + + request->start(); +} diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/libraries/script-engine/src/AssetMappingsScriptingInterface.h new file mode 100644 index 0000000000..0bf98f47cc --- /dev/null +++ b/libraries/script-engine/src/AssetMappingsScriptingInterface.h @@ -0,0 +1,68 @@ +// +// AssetScriptingInterface.h +// libraries/script-engine/src +// +// Created by Ryan Huffman on 2016-03-09. +// 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 +// + +#pragma once + +#ifndef hifi_AssetMappingsScriptingInterface_h +#define hifi_AssetMappingsScriptingInterface_h + +#include +#include + +#include + + class AssetMappingItem : public QStandardItem { + public: + AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder); + + QString name; + QString fullPath; + bool isFolder; + }; + + + class AssetMappingModel : public QStandardItemModel { + Q_OBJECT + public: + AssetMappingModel(); + ~AssetMappingModel(); + +// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; + + Q_INVOKABLE void refresh(); + + private: + QHash _pathToItemMap; + }; + + +class AssetMappingsScriptingInterface : public QObject, public Dependency { + Q_OBJECT + Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) +public: + AssetMappingsScriptingInterface(); + ~AssetMappingsScriptingInterface(); + + Q_INVOKABLE AssetMappingModel* getAssetMappingModel() { return &_assetMappingModel; } + + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); + Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); + Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } + Q_INVOKABLE void getAllMappings(QJSValue callback); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); +protected: + QSet _pendingRequests; + AssetMappingModel _assetMappingModel; +}; + + +#endif // hifi_AssetMappingsScriptingInterface_h diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index db29008976..fb315434fd 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -84,90 +84,3 @@ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callb assetRequest->start(); } - -void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createSetMappingRequest(path, hash); - - connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::getMapping(QString path, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetMappingRequest(path); - - connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::deleteMappings(QStringList paths, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createDeleteMappingsRequest(paths); - - connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::getAllMappings(QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createGetAllMappingsRequest(); - - connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable { - auto mappings = request->getMappings(); - auto map = callback.engine()->newObject(); - - for (auto& kv : mappings ) { - map.setProperty(kv.first, kv.second); - } - - QScriptValueList args { uint8_t(request->getError()), map }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} - -void AssetScriptingInterface::renameMapping(QString oldPath, QString newPath, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - auto request = assetClient->createRenameMappingRequest(oldPath, newPath); - - connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QScriptValueList args { uint8_t(request->getError()) }; - - callback.call(_engine->currentContext()->thisObject(), args); - - request->deleteLater(); - - }); - - request->start(); -} diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index d01eb939e2..2c2c596e09 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -26,12 +26,7 @@ public: Q_INVOKABLE void uploadData(QString data, QScriptValue callback); Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); - Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); - Q_INVOKABLE void getMapping(QString path, QScriptValue callback); - Q_INVOKABLE void deleteMappings(QStringList paths, QScriptValue callback); - Q_INVOKABLE void deleteMapping(QString path, QScriptValue callback) { deleteMappings(QStringList(path), callback); } - Q_INVOKABLE void getAllMappings(QScriptValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QScriptValue callback); + protected: QSet _pendingRequests; QScriptEngine* _engine;