Merge branch 'atp' of github.com:birarda/hifi into atp-more

This commit is contained in:
Ryan Huffman 2016-03-10 15:40:07 -08:00
commit 2d4864ed33
13 changed files with 261 additions and 136 deletions

View file

@ -464,7 +464,6 @@ void AssetServer::loadMappingsFromFile() {
shouldDrop = true;
}
if (!isValidHash(it.value().toString())) {
qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash.";
shouldDrop = true;

View file

@ -21,7 +21,7 @@ import "dialogs"
Window {
id: root
objectName: "AssetServer"
title: "Asset Server"
title: "My Asset Server"
resizable: true
destroyOnInvisible: true
x: 40; y: 40
@ -56,12 +56,13 @@ Window {
Assets.deleteMappings(path, function(err) {
if (err) {
console.log("Error deleting path: ", path, err);
errorMessage("There was an error deleting:\n" + path + "\n\nPlease try again.");
box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err));
box.selected.connect(reload);
} else {
console.log("Finished deleting path: ", path);
reload();
}
reload();
});
}
@ -80,7 +81,8 @@ Window {
Assets.renameMapping(oldPath, newPath, function(err) {
if (err) {
console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err);
errorMessage("There was an error renaming:\n" + oldPath + " to " + newPath + "\n\nPlease try again.");
box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err));
box.selected.connect(reload);
} else {
console.log("Finished rename: ", oldPath, "=>", newPath);
}
@ -95,12 +97,11 @@ Window {
function askForOverride(path, callback) {
var object = desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Question,
icon: hifi.icons.question,
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.No,
text: "Override?",
informativeText: "The following file already exists:\n" + path +
"\nDo you want to override it?"
defaultButton: OriginalDialogs.StandardButton.Yes,
title: "Overwrite File",
text: path + "\n" + "This file already exists. Do you want to overwrite it?"
});
object.selected.connect(function(button) {
if (button === OriginalDialogs.StandardButton.Yes) {
@ -123,29 +124,32 @@ Window {
Assets.mappingModel.refresh();
}
function handleGetMappingsError() {
errorMessage("There was a problem retreiving the list of assets from your Asset Server.\n"
+ "Please make sure you are connected to the Asset Server and try again. ");
function handleGetMappingsError(errorCode) {
errorMessageBox(
"There was a problem retreiving the list of assets from your Asset Server.\n"
+ Assets.getErrorString(errorCode)
);
}
function addToWorld() {
var url = assetMappingsModel.data(treeView.currentIndex, 0x102);
var url = assetProxyModel.data(treeView.currentIndex, 0x103);
if (!url) {
return;
}
Entities.addModelEntity(url, MyAvatar.position);
var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation)));
Entities.addModelEntity(url, addPosition);
}
function copyURLToClipboard(index) {
function copyURLToClipboard() {
if (!index) {
index = treeView.currentIndex;
}
var path = assetProxyModel.data(index, 0x103);
if (!path) {
var url = assetProxyModel.data(treeView.currentIndex, 0x103);
if (!url) {
return;
}
Window.copyToClipboard(path);
Window.copyToClipboard(url);
}
function renameFile(index) {
@ -159,7 +163,7 @@ Window {
var object = desktop.inputDialog({
label: "Enter new path:",
prefilledText: path,
current: path,
placeholderText: "Enter path here"
});
object.selected.connect(function(destinationPath) {
@ -188,13 +192,11 @@ Window {
var typeString = isFolder ? 'folder' : 'file';
var object = desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Question,
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.No,
text: "Deleting",
informativeText: "You are about to delete the following " + typeString + ":\n" +
path +
"\nDo you want to continue?"
icon: hifi.icons.question,
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.Yes,
title: "Delete",
text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"
});
object.selected.connect(function(button) {
if (button === OriginalDialogs.StandardButton.Yes) {
@ -214,36 +216,39 @@ Window {
});
}
property var uploadOpen: false;
function uploadClicked() {
if (uploadOpen) {
return;
}
uploadOpen = true;
var fileUrl = fileUrlTextField.text
var addToWorld = addToWorldCheckBox.checked
var path = assetProxyModel.data(treeView.currentIndex, 0x100);
var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "";
var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/";
var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1);
var object = desktop.inputDialog({
label: "Enter asset path:",
prefilledText: directory + filename,
placeholderText: "Enter path here"
});
object.selected.connect(function(destinationPath) {
if (fileExists(destinationPath)) {
askForOverride(fileUrl, function() {
doUploadFile(fileUrl, destinationPath, addToWorld);
});
Assets.uploadFile(fileUrl, directory + filename, function(err) {
if (err) {
console.log("Error uploading: ", fileUrl, " - error ", err);
errorMessage("There was an error uploading:\n" + fileUrl + "\n\nPlease try again.");
} else {
doUploadFile(fileUrl, destinationPath, addToWorld);
console.log("Finished uploading: ", fileUrl);
}
reload();
});
uploadOpen = false;
}
function errorMessage(message) {
desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Error,
buttons: OriginalDialogs.StandardButton.Ok,
text: "Error",
informativeText: message
function errorMessageBox(message) {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
}

View file

@ -96,6 +96,7 @@ ModalWindow {
}
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
RalewaySemiBold {

View file

@ -34,12 +34,10 @@ ModalWindow {
property var items;
property string label
property var result;
// FIXME not current honored
property var current;
property alias current: textResult.text
// For text boxes
property alias placeholderText: textResult.placeholderText
property alias prefilledText: textResult.text
// For combo boxes
property bool editable: true;

View file

@ -35,7 +35,7 @@ Item {
glyph = hifi.glyphs.alert;
break;
case hifi.icons.critical:
glyph = hifi.glyphs.critical;
glyph = hifi.glyphs.error;
break;
case hifi.icons.placemark:
glyph = hifi.glyphs.placemark;
@ -159,36 +159,6 @@ Item {
readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15
}
Item {
id: glyphs
readonly property string alert: "+"
readonly property string backward: "E"
readonly property string caratDn: "5"
readonly property string caratR: "3"
readonly property string caratUp: "6"
readonly property string close: "w"
readonly property string closeInverted: "x"
readonly property string closeSmall: "C"
readonly property string critical: "="
readonly property string disclosureButtonCollapse: "M"
readonly property string disclosureButtonExpand: "L"
readonly property string disclosureCollapse: "Z"
readonly property string disclosureExpand: "B"
readonly property string forward: "D"
readonly property string info: "["
readonly property string noIcon: ""
readonly property string pin: "y"
readonly property string pinInverted: "z"
readonly property string placemark: "U"
readonly property string question: "]"
readonly property string reloadSmall: "a"
readonly property string resizeHandle: "A"
readonly property string upload: "j"
readonly property string reload: "a"
readonly property string back: "1"
}
Item {
id: icons
// Values per OffscreenUi::Icon
@ -221,4 +191,103 @@ Item {
id: effects
readonly property int fadeInDuration: 300
}
Item {
id: glyphs
readonly property string noIcon: ""
readonly property string hmd: "b"
readonly property string screen: "c"
readonly property string keyboard: "d"
readonly property string handControllers: "e"
readonly property string headphonesMic: "f"
readonly property string gamepad: "g"
readonly property string headphones: "h"
readonly property string mic: "i"
readonly property string upload: "j"
readonly property string script: "k"
readonly property string text: "l"
readonly property string cube: "m"
readonly property string sphere: "n"
readonly property string zone: "o"
readonly property string light: "p"
readonly property string web: "q"
readonly property string web2: "r"
readonly property string edit: "s"
readonly property string market: "t"
readonly property string directory: "u"
readonly property string menu: "v"
readonly property string close: "w"
readonly property string closeInverted: "x"
readonly property string pin: "y"
readonly property string pinInverted: "z"
readonly property string resizeHandle: "A"
readonly property string disclosureExpand: "B"
readonly property string reloadSmall: "a"
readonly property string closeSmall: "C"
readonly property string forward: "D"
readonly property string backward: "E"
readonly property string reload: "F"
readonly property string unmuted: "G"
readonly property string muted: "H"
readonly property string minimize: "I"
readonly property string maximize: "J"
readonly property string maximizeInverted: "K"
readonly property string disclosureButtonExpand: "L"
readonly property string disclosureButtonCollapse: "M"
readonly property string scriptStop: "N"
readonly property string scriptReload: "O"
readonly property string scriptRun: "P"
readonly property string scriptNew: "Q"
readonly property string hifiForum: "2"
readonly property string hifiLogoSmall: "S"
readonly property string avatar1: "T"
readonly property string placemark: "U"
readonly property string box: "V"
readonly property string community: "0"
readonly property string grabHandle: "X"
readonly property string search: "Y"
readonly property string disclosureCollapse: "Z"
readonly property string scriptUpload: "R"
readonly property string code: "W"
readonly property string avatar: "<"
readonly property string arrowsH: ":"
readonly property string arrowsV: ";"
readonly property string arrows: "`"
readonly property string compress: "!"
readonly property string expand: "\""
readonly property string placemark1: "#"
readonly property string circle: "$"
readonly property string handPointer: "9"
readonly property string plusSquareO: "%"
readonly property string sliders: "&"
readonly property string square: "'"
readonly property string alignCenter: "8"
readonly property string alignJustify: ")"
readonly property string alignLeft: "*"
readonly property string alignRight: "^"
readonly property string bars: "7"
readonly property string circleSlash: ","
readonly property string sync: "()"
readonly property string key: "-"
readonly property string link: "."
readonly property string location: "/"
readonly property string caratR: "3"
readonly property string caratL: "4"
readonly property string caratDn: "5"
readonly property string caratUp: "6"
readonly property string folderLg: ">"
readonly property string folderSm: "?"
readonly property string levelUp: "1"
readonly property string info: "["
readonly property string question: "]"
readonly property string alert: "+"
readonly property string home: "_"
readonly property string error: "="
readonly property string settings: "@"
readonly property string trash: "{"
readonly property string objectGroup: "&#xe000;"
readonly property string cm: "}"
readonly property string msvg79: "~"
readonly property string deg: "\\"
readonly property string px: "|"
}
}

View file

@ -66,7 +66,6 @@
#include <BuildInfo.h>
#include <AssetClient.h>
#include <AssetUpload.h>
#include <AssetMappingsScriptingInterface.h>
#include <AutoUpdater.h>
#include <AudioInjectorManager.h>
#include <CursorManager.h>
@ -142,6 +141,7 @@
#include "ModelPackager.h"
#include "PluginContainerProxy.h"
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h"
#include "scripting/AudioDeviceScriptingInterface.h"
#include "scripting/ClipboardScriptingInterface.h"
#include "scripting/DesktopScriptingInterface.h"
@ -426,7 +426,6 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<MessagesClient>();
DependencyManager::set<UserInputMapper>();
DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
DependencyManager::set<AssetMappingsScriptingInterface>();
DependencyManager::set<InterfaceParentFinder>();
DependencyManager::set<EntityTreeRenderer>(true, qApp, qApp);
DependencyManager::set<CompositorHelper>();
@ -1296,7 +1295,7 @@ void Application::initializeUi() {
rootContext->setContextProperty("Quat", new Quat());
rootContext->setContextProperty("Vec3", new Vec3());
rootContext->setContextProperty("Uuid", new ScriptUUID());
rootContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface());
rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());

View file

@ -95,10 +95,6 @@ Menu::Menu() {
addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
qApp, SLOT(toggleRunningScriptsWidget()));
// Edit > Asset Server
addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0,
qApp, SLOT(toggleAssetServerWidget()));
// Edit > Open and Run Script from File... [advanced]
addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O,
qApp, SLOT(loadDialog()),
@ -131,10 +127,16 @@ Menu::Menu() {
SLOT(toggleConsole()),
QAction::NoRole, UNSPECIFIED_POSITION, "Advanced");
editMenu->addSeparator();
// Edit > My Asset Server
addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A,
qApp, SLOT(toggleAssetServerWidget()));
// Edit > Reload All Content [advanced]
addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()),
QAction::NoRole, UNSPECIFIED_POSITION, "Advanced");
// Edit > Package Model... [advanced]
addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0,

View file

@ -34,7 +34,7 @@ namespace MenuOption {
const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose";
const QString AnimDebugDrawPosition= "Debug Draw Position";
const QString AssetMigration = "ATP Asset Migration";
const QString AssetServer = "Asset Server";
const QString AssetServer = "My Asset Server";
const QString Attachments = "Attachments...";
const QString AudioNetworkStats = "Audio Network Stats";
const QString AudioNoiseReduction = "Audio Noise Reduction";

View file

@ -12,11 +12,13 @@
#include "AssetMappingsScriptingInterface.h"
#include <QtScript/QScriptEngine>
#include <QtCore/QFile>
#include <AssetRequest.h>
#include <AssetUpload.h>
#include <MappingRequest.h>
#include <NetworkLogging.h>
#include <OffscreenUi.h>
AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
_proxyModel.setSourceModel(&_assetMappingModel);
@ -25,17 +27,38 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
_proxyModel.sort(0);
}
QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const {
switch (errorCode) {
case MappingRequest::NoError:
return "No error";
case MappingRequest::NotFound:
return "Asset not found";
case MappingRequest::NetworkError:
return "Unable to communicate with Asset Server";
case MappingRequest::PermissionDenied:
return "Permission denied";
case MappingRequest::InvalidPath:
return "Path is invalid";
case MappingRequest::InvalidHash:
return "Hash is invalid";
case MappingRequest::UnknownError:
return "Asset Server internal error";
default:
return QString();
}
}
void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) {
auto assetClient = DependencyManager::get<AssetClient>();
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);
if (callback.isCallable()) {
QJSValueList args { uint8_t(request->getError()) };
callback.call(args);
}
request->deleteLater();
});
request->start();
@ -46,28 +69,64 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback
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);
if (callback.isCallable()) {
QJSValueList args { uint8_t(request->getError()) };
callback.call(args);
}
request->deleteLater();
});
request->start();
}
void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping);
if (!result.isValid()) {
return;
}
mapping = result.toString();
// Check for override
if (isKnownMapping(mapping)) {
auto message = path + "\n" + "This file already exists. Do you want to overwrite it?";
auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (button == QMessageBox::No) {
return;
}
}
auto upload = DependencyManager::get<AssetClient>()->createUpload(path);
QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
if (upload->getError() != AssetUpload::NoError) {
if (callback.isCallable()) {
QJSValueList args { uint8_t(upload->getError()) };
callback.call(args);
}
} else {
setMapping(mapping, hash, callback);
}
upload->deleteLater();
});
upload->start();
}
void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) {
auto assetClient = DependencyManager::get<AssetClient>();
auto request = assetClient->createDeleteMappingsRequest(paths);
connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable {
QJSValueList args { uint8_t(request->getError()) };
callback.call(args);
if (callback.isCallable()) {
QJSValueList args { uint8_t(request->getError()) };
callback.call(args);
}
request->deleteLater();
});
request->start();
@ -85,12 +144,12 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) {
map.setProperty(kv.first, kv.second);
}
QJSValueList args { uint8_t(request->getError()), map };
callback.call(args);
if (callback.isCallable()) {
QJSValueList args { uint8_t(request->getError()) };
callback.call(args);
}
request->deleteLater();
});
request->start();
@ -101,34 +160,28 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new
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);
if (callback.isCallable()) {
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),
AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) :
name(name),
fullPath(fullPath),
isFolder(isFolder) {
isFolder(isFolder)
{
}
static int assetMappingModelMetatypeId = qRegisterMetaType<AssetMappingModel*>("AssetMappingModel*");
AssetMappingModel::AssetMappingModel() {
}
AssetMappingModel::~AssetMappingModel() {
qDebug() << " DEST";
}
void AssetMappingModel::refresh() {
qDebug() << "Refreshing asset mapping model";
auto assetClient = DependencyManager::get<AssetClient>();
@ -184,7 +237,7 @@ void AssetMappingModel::refresh() {
while (it != existingPaths.end()) {
Q_ASSERT(_pathToItemMap.contains(*it));
auto item = _pathToItemMap[*it];
if (item->data(Qt::UserRole + 1).toBool()) {
if (item && item->data(Qt::UserRole + 1).toBool()) {
it = existingPaths.erase(it);
} else {
++it;
@ -222,7 +275,7 @@ void AssetMappingModel::refresh() {
}
}
} else {
emit errorGettingMappings(uint8_t(request->getError()));
emit errorGettingMappings(static_cast<int>(request->getError()));
}
});

View file

@ -33,24 +33,19 @@
class AssetMappingModel : public QStandardItemModel {
Q_OBJECT
public:
AssetMappingModel();
~AssetMappingModel();
// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const;
Q_INVOKABLE void refresh();
bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); };
signals:
void errorGettingMappings(uint8_t error);
void errorGettingMappings(int error);
private:
QHash<QString, QStandardItem*> _pathToItemMap;
};
class AssetMappingsScriptingInterface : public QObject, public Dependency {
class AssetMappingsScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT)
Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT)
@ -62,12 +57,15 @@ public:
Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); };
Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback);
Q_INVOKABLE void getMapping(QString path, QJSValue callback);
Q_INVOKABLE QString getErrorString(int errorCode) const;
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 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);
Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); }
Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue());
Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback = QJSValue());
protected:
QSet<AssetRequest*> _pendingRequests;

View file

@ -31,7 +31,7 @@ const size_t SHA256_HASH_LENGTH = 32;
const size_t SHA256_HASH_HEX_LENGTH = 64;
const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB
const QString ASSET_PATH_REGEX_STRING = "^\\/(?:[^\\/]|\\/(?!\\/))*$";
const QString ASSET_PATH_REGEX_STRING = "^\\/(?!\\/)(?:[^\\/]|\\/(?!\\/))*$";
const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH);
enum AssetServerError : uint8_t {

View file

@ -109,7 +109,7 @@ void SetMappingRequest::doStart() {
auto validPath = isValidPath(_path);
auto validHash = isValidHash(_hash);
if (!validPath || !validHash) {
_error = validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash;
_error = !validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash;
emit finished(this);
return;
}

View file

@ -64,6 +64,7 @@ class SetMappingRequest : public MappingRequest {
public:
SetMappingRequest(const AssetPath& path, const AssetHash& hash);
AssetPath getPath() const { return _path; }
AssetHash getHash() const { return _hash; }
signals: