From 9ee063bdc19e9905564b37289dc1a91da893a93c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 17 Sep 2014 16:00:20 -0700 Subject: [PATCH 1/9] remove the access token from API urls and put in Authorization header --- libraries/networking/src/AccountManager.cpp | 11 ++++++++--- libraries/networking/src/OAuthAccessToken.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 1100371ac9..b24f720edf 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -25,6 +25,8 @@ const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; +const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization"; + AccountManager& AccountManager::getInstance() { static AccountManager sharedInstance; return sharedInstance; @@ -188,7 +190,8 @@ void AccountManager::invokedRequest(const QString& path, if (requiresAuthentication) { if (hasValidAccessToken()) { - requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); + networkRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, + _accountInfo.getAccessToken().authorizationHeaderValue()); } else { qDebug() << "No valid access token present. Bailing on authenticated invoked request."; return; @@ -405,9 +408,11 @@ void AccountManager::requestProfile() { QUrl profileURL = _authURL; profileURL.setPath("/api/v1/users/profile"); - profileURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); + + QNetworkRequest profileRequest(profileURL); + profileRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, _accountInfo.getAccessToken().authorizationHeaderValue()); - QNetworkReply* profileReply = networkAccessManager.get(QNetworkRequest(profileURL)); + QNetworkReply* profileReply = networkAccessManager.get(profileRequest); connect(profileReply, &QNetworkReply::finished, this, &AccountManager::requestProfileFinished); connect(profileReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError))); } diff --git a/libraries/networking/src/OAuthAccessToken.h b/libraries/networking/src/OAuthAccessToken.h index 36859b79f8..167bb824da 100644 --- a/libraries/networking/src/OAuthAccessToken.h +++ b/libraries/networking/src/OAuthAccessToken.h @@ -23,6 +23,8 @@ public: OAuthAccessToken(const QJsonObject& jsonObject); OAuthAccessToken(const OAuthAccessToken& otherToken); OAuthAccessToken& operator=(const OAuthAccessToken& otherToken); + + QByteArray authorizationHeaderValue() const { return QString("Bearer %1").arg(token).toUtf8(); } bool isExpired() const { return expiryTimestamp <= QDateTime::currentMSecsSinceEpoch(); } From e0a56b4a95c25eb459a1f0e3f5d1275a8b75ca04 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 17 Sep 2014 17:57:08 -0700 Subject: [PATCH 2/9] Rejiggered the blender handling: allow up to N blenders active at once so that with small numbers of avatars, the blenders can stack for lower latency. --- interface/src/renderer/GeometryCache.cpp | 30 ++++++- interface/src/renderer/GeometryCache.h | 9 +- interface/src/renderer/Model.cpp | 100 +++++++++++------------ interface/src/renderer/Model.h | 11 ++- 4 files changed, 91 insertions(+), 59 deletions(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 1ec6ea8f23..7c3c2dc1ca 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -20,6 +20,10 @@ #include "Model.h" #include "world.h" +GeometryCache::GeometryCache() : + _pendingBlenders(0) { +} + GeometryCache::~GeometryCache() { foreach (const VerticesIndices& vbo, _hemisphereVBOs) { glDeleteBuffers(1, &vbo.first); @@ -296,10 +300,30 @@ QSharedPointer GeometryCache::getGeometry(const QUrl& url, cons return getResource(url, fallback, delayLoad).staticCast(); } -void GeometryCache::setBlendedVertices(const QPointer& model, const QWeakPointer& geometry, - const QVector& vertices, const QVector& normals) { +void GeometryCache::noteRequiresBlend(Model* model) { + if (_pendingBlenders < QThread::idealThreadCount()) { + if (model->maybeStartBlender()) { + _pendingBlenders++; + } + return; + } + if (!_modelsRequiringBlends.contains(model)) { + _modelsRequiringBlends.append(model); + } +} + +void GeometryCache::setBlendedVertices(const QPointer& model, int blendNumber, + const QWeakPointer& geometry, const QVector& vertices, const QVector& normals) { if (!model.isNull()) { - model->setBlendedVertices(geometry, vertices, normals); + model->setBlendedVertices(blendNumber, geometry, vertices, normals); + } + _pendingBlenders--; + while (!_modelsRequiringBlends.isEmpty()) { + Model* nextModel = _modelsRequiringBlends.takeFirst(); + if (nextModel && nextModel->maybeStartBlender()) { + _pendingBlenders++; + return; + } } } diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 2e5725e1b1..647e0592fd 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -35,6 +35,7 @@ class GeometryCache : public ResourceCache { public: + GeometryCache(); virtual ~GeometryCache(); void renderHemisphere(int slices, int stacks); @@ -47,9 +48,12 @@ public: /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested QSharedPointer getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); + /// Adds the specified model to the list requiring vertex blends. + void noteRequiresBlend(Model* model); + public slots: - void setBlendedVertices(const QPointer& model, const QWeakPointer& geometry, + void setBlendedVertices(const QPointer& model, int blendNumber, const QWeakPointer& geometry, const QVector& vertices, const QVector& normals); protected: @@ -68,6 +72,9 @@ private: QHash _gridBuffers; QHash > _networkGeometry; + + QList > _modelsRequiringBlends; + int _pendingBlenders; }; /// Geometry loaded from the network. diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 7f83147bb8..19d711a69d 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -62,8 +62,8 @@ Model::Model(QObject* parent) : _lodDistance(0.0f), _pupilDilation(0.0f), _url("http://invalid.com"), - _blenderPending(false), - _blendRequired(false) { + _blendNumber(0), + _appliedBlendNumber(0) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -826,7 +826,7 @@ void Model::updateShapePositions() { class Blender : public QRunnable { public: - Blender(Model* model, const QWeakPointer& geometry, + Blender(Model* model, int blendNumber, const QWeakPointer& geometry, const QVector& meshes, const QVector& blendshapeCoefficients); virtual void run(); @@ -834,55 +834,55 @@ public: private: QPointer _model; + int _blendNumber; QWeakPointer _geometry; QVector _meshes; QVector _blendshapeCoefficients; }; -Blender::Blender(Model* model, const QWeakPointer& geometry, +Blender::Blender(Model* model, int blendNumber, const QWeakPointer& geometry, const QVector& meshes, const QVector& blendshapeCoefficients) : _model(model), + _blendNumber(blendNumber), _geometry(geometry), _meshes(meshes), _blendshapeCoefficients(blendshapeCoefficients) { } void Blender::run() { - // make sure the model still exists - if (_model.isNull()) { - return; - } QVector vertices, normals; - int offset = 0; - foreach (const FBXMesh& mesh, _meshes) { - if (mesh.blendshapes.isEmpty()) { - continue; - } - vertices += mesh.vertices; - normals += mesh.normals; - glm::vec3* meshVertices = vertices.data() + offset; - glm::vec3* meshNormals = normals.data() + offset; - offset += mesh.vertices.size(); - const float NORMAL_COEFFICIENT_SCALE = 0.01f; - for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) { - float vertexCoefficient = _blendshapeCoefficients.at(i); - if (vertexCoefficient < EPSILON) { + if (!_model.isNull()) { + int offset = 0; + foreach (const FBXMesh& mesh, _meshes) { + if (mesh.blendshapes.isEmpty()) { continue; } - float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE; - const FBXBlendshape& blendshape = mesh.blendshapes.at(i); - for (int j = 0; j < blendshape.indices.size(); j++) { - int index = blendshape.indices.at(j); - meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient; - meshNormals[index] += blendshape.normals.at(j) * normalCoefficient; + vertices += mesh.vertices; + normals += mesh.normals; + glm::vec3* meshVertices = vertices.data() + offset; + glm::vec3* meshNormals = normals.data() + offset; + offset += mesh.vertices.size(); + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) { + float vertexCoefficient = _blendshapeCoefficients.at(i); + if (vertexCoefficient < EPSILON) { + continue; + } + float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE; + const FBXBlendshape& blendshape = mesh.blendshapes.at(i); + for (int j = 0; j < blendshape.indices.size(); j++) { + int index = blendshape.indices.at(j); + meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient; + meshNormals[index] += blendshape.normals.at(j) * normalCoefficient; + } } } } - // post the result to the geometry cache, which will dispatch to the model if still alive QMetaObject::invokeMethod(Application::getInstance()->getGeometryCache(), "setBlendedVertices", - Q_ARG(const QPointer&, _model), Q_ARG(const QWeakPointer&, _geometry), - Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); + Q_ARG(const QPointer&, _model), Q_ARG(int, _blendNumber), + Q_ARG(const QWeakPointer&, _geometry), Q_ARG(const QVector&, vertices), + Q_ARG(const QVector&, normals)); } void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) { @@ -1020,14 +1020,9 @@ void Model::simulateInternal(float deltaTime) { } // post the blender if we're not currently waiting for one to finish - if (geometry.hasBlendedMeshes()) { - if (_blenderPending) { - _blendRequired = true; - } else { - _blendRequired = false; - _blenderPending = true; - QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); - } + if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + _blendedBlendshapeCoefficients = _blendshapeCoefficients; + Application::getInstance()->getGeometryCache()->noteRequiresBlend(this); } } @@ -1290,22 +1285,23 @@ void Model::renderJointCollisionShapes(float alpha) { // implement this when we have shapes for regular models } -void Model::setBlendedVertices(const QWeakPointer& geometry, const QVector& vertices, - const QVector& normals) { - _blenderPending = false; - - // start the next blender if required +bool Model::maybeStartBlender() { const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); - if (_blendRequired) { - _blendRequired = false; - if (fbxGeometry.hasBlendedMeshes()) { - _blenderPending = true; - QThreadPool::globalInstance()->start(new Blender(this, _geometry, fbxGeometry.meshes, _blendshapeCoefficients)); - } + if (fbxGeometry.hasBlendedMeshes()) { + QThreadPool::globalInstance()->start(new Blender(this, ++_blendNumber, _geometry, + fbxGeometry.meshes, _blendshapeCoefficients)); + return true; } - if (_geometry != geometry || _blendedVertexBuffers.isEmpty()) { + return false; +} + +void Model::setBlendedVertices(int blendNumber, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals) { + if (_geometry != geometry || _blendedVertexBuffers.isEmpty() || blendNumber < _appliedBlendNumber) { return; } + _appliedBlendNumber = blendNumber; + const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); int index = 0; for (int i = 0; i < fbxGeometry.meshes.size(); i++) { const FBXMesh& mesh = fbxGeometry.meshes.at(i); @@ -1358,6 +1354,8 @@ void Model::deleteGeometry() { if (_geometry) { _geometry->clearLoadPriority(this); } + + _blendedBlendshapeCoefficients.clear(); } void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index f2d98ac589..63b2058a20 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -165,9 +165,11 @@ public: virtual void renderJointCollisionShapes(float alpha); + bool maybeStartBlender(); + /// Sets blended vertices computed in a separate thread. - void setBlendedVertices(const QWeakPointer& geometry, const QVector& vertices, - const QVector& normals); + void setBlendedVertices(int blendNumber, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals); class LocalLight { public: @@ -285,8 +287,9 @@ private: glm::vec4 _localLightColors[MAX_LOCAL_LIGHTS]; glm::vec4 _localLightDirections[MAX_LOCAL_LIGHTS]; - bool _blenderPending; - bool _blendRequired; + QVector _blendedBlendshapeCoefficients; + int _blendNumber; + int _appliedBlendNumber; static ProgramObject _program; static ProgramObject _normalMapProgram; From 9a523a60cfefa58a488ec88e3487232c8b5ec0c0 Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 18 Sep 2014 06:59:29 +0200 Subject: [PATCH 3/9] Add option to toggle on/off names above heads --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/Avatar.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d3d1c8c0d0..c59727045d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -269,6 +269,7 @@ Menu::Menu() : QObject* avatar = appInstance->getAvatar(); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ChatCircling, 0, false); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b43e7cb75e..9bc9fd2204 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -395,6 +395,7 @@ namespace MenuOption { const QString FullscreenMirror = "Fullscreen Mirror"; const QString GlowMode = "Cycle Glow Mode"; const QString GlowWhenSpeaking = "Glow When Speaking"; + const QString NamesAboveHeads = "Names Above Heads"; const QString GoToUser = "Go To User"; const QString HeadMouse = "Head Mouse"; const QString IncreaseAvatarSize = "Increase Avatar Size"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b62c744fa2..73e937116e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1036,7 +1036,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { } } - if (showDisplayName) { + if (showDisplayName && Menu::getInstance()->isOptionChecked(MenuOption::NamesAboveHeads)) { _displayNameTargetAlpha = DISPLAYNAME_ALPHA; } else { _displayNameTargetAlpha = 0.0f; From a6a48aafdc950e79f1e7a638b823ec388c440ba3 Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 18 Sep 2014 07:34:14 +0200 Subject: [PATCH 4/9] Hide name for all avatars, including MyAvatar --- interface/src/avatar/Avatar.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 73e937116e..11537294ea 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1027,6 +1027,11 @@ float Avatar::getPelvisToHeadLength() const { } void Avatar::setShowDisplayName(bool showDisplayName) { + if (!Menu::getInstance()->isOptionChecked(MenuOption::NamesAboveHeads)) { + _displayNameAlpha = 0.0f; + return; + } + // For myAvatar, the alpha update is not done (called in simulate for other avatars) if (Application::getInstance()->getAvatar() == this) { if (showDisplayName) { @@ -1036,7 +1041,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { } } - if (showDisplayName && Menu::getInstance()->isOptionChecked(MenuOption::NamesAboveHeads)) { + if (showDisplayName) { _displayNameTargetAlpha = DISPLAYNAME_ALPHA; } else { _displayNameTargetAlpha = 0.0f; From e2c3b626b334e2598e9b1ac75ee31a385175d30b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 18 Sep 2014 09:05:25 -0700 Subject: [PATCH 5/9] add a DataWebDialog for authenticated access to data-web html --- interface/src/Application.cpp | 4 ++ interface/src/ui/DataWebDialog.cpp | 39 +++++++++++++++++ interface/src/ui/DataWebDialog.h | 25 +++++++++++ libraries/networking/src/AccountManager.cpp | 2 - libraries/networking/src/AccountManager.h | 2 + libraries/networking/src/LimitedNodeList.cpp | 2 +- .../src/OAuthNetworkAccessManager.cpp | 43 +++++++++++++++++++ .../src/OAuthNetworkAccessManager.h | 24 +++++++++++ 8 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 interface/src/ui/DataWebDialog.cpp create mode 100644 interface/src/ui/DataWebDialog.h create mode 100644 libraries/networking/src/OAuthNetworkAccessManager.cpp create mode 100644 libraries/networking/src/OAuthNetworkAccessManager.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index efa5a481f6..f0b386e5fa 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -68,6 +68,7 @@ #include #include "Application.h" +#include "ui/DataWebDialog.h" #include "InterfaceVersion.h" #include "Menu.h" #include "ModelUploader.h" @@ -429,6 +430,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : MIDIManager& midiManagerInstance = MIDIManager::getInstance(); midiManagerInstance.openDefaultPort(); #endif + + DataWebDialog* dialogForPath = DataWebDialog::dialogForPath("/locations"); + dialogForPath->show(); } Application::~Application() { diff --git a/interface/src/ui/DataWebDialog.cpp b/interface/src/ui/DataWebDialog.cpp new file mode 100644 index 0000000000..9914383220 --- /dev/null +++ b/interface/src/ui/DataWebDialog.cpp @@ -0,0 +1,39 @@ +// +// DataWebDialog.cpp +// interface/src/ui +// +// Created by Stephen Birarda on 2014-09-17. +// Copyright 2014 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 + +#include +#include +#include + +#include "DataWebDialog.h" + +DataWebDialog::DataWebDialog() { + // make sure the dialog deletes itself when it closes + setAttribute(Qt::WA_DeleteOnClose); + + // use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed + page()->setNetworkAccessManager(OAuthNetworkAccessManager::getInstance()); +} + +DataWebDialog* DataWebDialog::dialogForPath(const QString& path) { + DataWebDialog* dialogWebView = new DataWebDialog(); + + QUrl dataWebUrl(DEFAULT_NODE_AUTH_URL); + dataWebUrl.setPath(path); + + qDebug() << "Opening a data web dialog for" << dataWebUrl.toString(); + + dialogWebView->load(dataWebUrl); + + return dialogWebView; +} \ No newline at end of file diff --git a/interface/src/ui/DataWebDialog.h b/interface/src/ui/DataWebDialog.h new file mode 100644 index 0000000000..c69a9207b9 --- /dev/null +++ b/interface/src/ui/DataWebDialog.h @@ -0,0 +1,25 @@ +// +// DataWebDialog.h +// interface/src/ui +// +// Created by Stephen Birarda on 2014-09-17. +// Copyright 2014 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 +// + +#ifndef hifi_DataWebDialog_h +#define hifi_DataWebDialog_h + +#include +#include + +class DataWebDialog : public QWebView { + Q_OBJECT +public: + DataWebDialog(); + static DataWebDialog* dialogForPath(const QString& path); +}; + +#endif // hifi_WebkitDialog_h \ No newline at end of file diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index b24f720edf..88e4bad7b2 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -25,8 +25,6 @@ const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; -const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization"; - AccountManager& AccountManager::getInstance() { static AccountManager sharedInstance; return sharedInstance; diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 64d62cd1c2..edccab0b75 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -37,6 +37,8 @@ public: QString updateSlot; }; +const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization"; + class AccountManager : public QObject { Q_OBJECT public: diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d42cab6210..bfdfc28d5e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -33,7 +33,7 @@ const char SOLO_NODE_TYPES[2] = { NodeType::AudioMixer }; -const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://data.highfidelity.io"); +const QUrl DEFAULT_NODE_AUTH_URL = QUrl("http://localhost:3000"); LimitedNodeList* LimitedNodeList::_sharedInstance = NULL; diff --git a/libraries/networking/src/OAuthNetworkAccessManager.cpp b/libraries/networking/src/OAuthNetworkAccessManager.cpp new file mode 100644 index 0000000000..493398230a --- /dev/null +++ b/libraries/networking/src/OAuthNetworkAccessManager.cpp @@ -0,0 +1,43 @@ +// +// OAuthNetworkAccessManager.cpp +// libraries/networking/src +// +// Created by Stephen Birarda on 2014-09-18. +// Copyright 2014 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 +#include +#include + +#include "AccountManager.h" + +#include "OAuthNetworkAccessManager.h" + +QThreadStorage oauthNetworkAccessManagers; + +OAuthNetworkAccessManager* OAuthNetworkAccessManager::getInstance() { + if (!oauthNetworkAccessManagers.hasLocalData()) { + oauthNetworkAccessManagers.setLocalData(new OAuthNetworkAccessManager()); + } + + return oauthNetworkAccessManagers.localData(); +} + +QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& req, + QIODevice* outgoingData) { + AccountManager& accountManager = AccountManager::getInstance(); + + if (accountManager.hasValidAccessToken()) { + QNetworkRequest authenticatedRequest(req); + authenticatedRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, + accountManager.getAccountInfo().getAccessToken().authorizationHeaderValue()); + + return QNetworkAccessManager::createRequest(op, authenticatedRequest, outgoingData); + } else { + return QNetworkAccessManager::createRequest(op, req, outgoingData); + } +} diff --git a/libraries/networking/src/OAuthNetworkAccessManager.h b/libraries/networking/src/OAuthNetworkAccessManager.h new file mode 100644 index 0000000000..acfd52e18f --- /dev/null +++ b/libraries/networking/src/OAuthNetworkAccessManager.h @@ -0,0 +1,24 @@ +// +// OAuthNetworkAccessManager.h +// libraries/networking/src +// +// Created by Stephen Birarda on 2014-09-18. +// Copyright 2014 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 +// + +#ifndef hifi_OAuthNetworkAccessManager_h +#define hifi_OAuthNetworkAccessManager_h + +#include + +class OAuthNetworkAccessManager : public QNetworkAccessManager { +public: + static OAuthNetworkAccessManager* getInstance(); +protected: + virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& req, QIODevice* outgoingData = 0); +}; + +#endif // hifi_OAuthNetworkAccessManager_h \ No newline at end of file From d860b8e8dbc34023808114602c5725082ffbcabb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 18 Sep 2014 09:22:14 -0700 Subject: [PATCH 6/9] remove test DataWebDialog from Application --- interface/src/Application.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0b386e5fa..1a537d64bd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -430,9 +430,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : MIDIManager& midiManagerInstance = MIDIManager::getInstance(); midiManagerInstance.openDefaultPort(); #endif - - DataWebDialog* dialogForPath = DataWebDialog::dialogForPath("/locations"); - dialogForPath->show(); } Application::~Application() { From bf83e8fe09a2e1d09bc1c51a29e3e96a8225e6b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 18 Sep 2014 09:23:22 -0700 Subject: [PATCH 7/9] remove the user locations model --- interface/src/UserLocationsModel.cpp | 251 --------------------------- interface/src/UserLocationsModel.h | 82 --------- 2 files changed, 333 deletions(-) delete mode 100644 interface/src/UserLocationsModel.cpp delete mode 100644 interface/src/UserLocationsModel.h diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp deleted file mode 100644 index 0fae0d8800..0000000000 --- a/interface/src/UserLocationsModel.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// UserLocationsModel.cpp -// interface/src -// -// Created by Ryan Huffman on 06/24/14. -// Copyright 2014 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 -#include -#include -#include - -#include "AccountManager.h" -#include "Application.h" -#include "UserLocationsModel.h" - -static const QString LOCATIONS_GET = "/api/v1/locations"; -static const QString LOCATION_UPDATE_OR_DELETE = "/api/v1/locations/%1"; - -UserLocation::UserLocation(const QString& id, const QString& name, const QString& address) : - _id(id), - _name(name), - _address(address), - _previousName(name), - _updating(false) { -} - -void UserLocation::requestRename(const QString& newName) { - if (!_updating && newName.toLower() != _name) { - _updating = true; - - JSONCallbackParameters callbackParams(this, "handleRenameResponse", this, "handleRenameError"); - - QJsonObject jsonNameObject; - jsonNameObject.insert("name", newName); - - QJsonObject locationObject; - locationObject.insert("location", jsonNameObject); - - QJsonDocument jsonDocument(jsonNameObject); - AccountManager::getInstance().authenticatedRequest(LOCATION_UPDATE_OR_DELETE.arg(_id), - QNetworkAccessManager::PutOperation, - callbackParams, - jsonDocument.toJson()); - _previousName = _name; - _name = newName; - - emit updated(_name); - } -} - -void UserLocation::handleRenameResponse(const QJsonObject& responseData) { - _updating = false; - - QJsonValue status = responseData["status"]; - if (!status.isUndefined() && status.toString() == "success") { - qDebug() << responseData; - QString updatedName = responseData["data"].toObject()["location"].toObject()["name"].toString(); - qDebug() << "The updated name is" << updatedName; - _name = updatedName; - } else { - _name = _previousName; - - QString msg = "There was an error renaming location '" + _name + "'"; - - QJsonValue data = responseData["data"]; - if (!data.isUndefined()) { - QJsonValue nameError = data.toObject()["name"]; - if (!nameError.isUndefined()) { - msg += ": " + nameError.toString(); - } - } - qDebug() << msg; - QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); - } - - emit updated(_name); -} - -void UserLocation::handleRenameError(QNetworkReply& errorReply) { - _updating = false; - - QString msg = "There was an error renaming location '" + _name + "': " + errorReply.errorString(); - qDebug() << msg; - QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); - - emit updated(_name); -} - -void UserLocation::requestDelete() { - if (!_updating) { - _updating = true; - - JSONCallbackParameters callbackParams(this, "handleDeleteResponse", this, "handleDeleteError"); - AccountManager::getInstance().authenticatedRequest(LOCATION_UPDATE_OR_DELETE.arg(_id), - QNetworkAccessManager::DeleteOperation, - callbackParams); - } -} - -void UserLocation::handleDeleteResponse(const QJsonObject& responseData) { - _updating = false; - - QJsonValue status = responseData["status"]; - if (!status.isUndefined() && status.toString() == "success") { - emit deleted(_name); - } else { - QString msg = "There was an error deleting location '" + _name + "'"; - qDebug() << msg; - QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); - } -} - -void UserLocation::handleDeleteError(QNetworkReply& errorReply) { - _updating = false; - - QString msg = "There was an error deleting location '" + _name + "': " + errorReply.errorString(); - qDebug() << msg; - QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); -} - -UserLocationsModel::UserLocationsModel(QObject* parent) : - QAbstractListModel(parent), - _updating(false) { - - refresh(); -} - -UserLocationsModel::~UserLocationsModel() { - qDeleteAll(_locations); - _locations.clear(); -} - -void UserLocationsModel::update() { - beginResetModel(); - endResetModel(); -} - -void UserLocationsModel::deleteLocation(const QModelIndex& index) { - UserLocation* location = _locations[index.row()]; - location->requestDelete(); -} - -void UserLocationsModel::renameLocation(const QModelIndex& index, const QString& newName) { - UserLocation* location = _locations[index.row()]; - location->requestRename(newName); -} - -void UserLocationsModel::refresh() { - if (!_updating) { - beginResetModel(); - qDeleteAll(_locations); - _locations.clear(); - _updating = true; - endResetModel(); - - JSONCallbackParameters callbackParams(this, "handleLocationsResponse"); - AccountManager::getInstance().authenticatedRequest(LOCATIONS_GET, - QNetworkAccessManager::GetOperation, - callbackParams); - } -} - -void UserLocationsModel::handleLocationsResponse(const QJsonObject& responseData) { - _updating = false; - - QJsonValue status = responseData["status"]; - if (!status.isUndefined() && status.toString() == "success") { - beginResetModel(); - QJsonArray locations = responseData["data"].toObject()["locations"].toArray(); - for (QJsonArray::const_iterator it = locations.constBegin(); it != locations.constEnd(); it++) { - QJsonObject location = (*it).toObject(); - QString locationAddress = "hifi://" + location["domain"].toObject()["name"].toString() - + location["path"].toString(); - UserLocation* userLocation = new UserLocation(location["id"].toString(), location["name"].toString(), - locationAddress); - _locations.append(userLocation); - connect(userLocation, &UserLocation::deleted, this, &UserLocationsModel::removeLocation); - connect(userLocation, &UserLocation::updated, this, &UserLocationsModel::update); - } - endResetModel(); - } else { - qDebug() << "Error loading location data"; - } -} - -void UserLocationsModel::removeLocation(const QString& name) { - beginResetModel(); - for (QList::iterator it = _locations.begin(); it != _locations.end(); it++) { - if ((*it)->name() == name) { - _locations.erase(it); - break; - } - } - endResetModel(); -} - -int UserLocationsModel::rowCount(const QModelIndex& parent) const { - if (parent.isValid()) { - return 0; - } - - if (_updating) { - return 1; - } - - return _locations.length(); -} - -QVariant UserLocationsModel::data(const QModelIndex& index, int role) const { - if (role == Qt::DisplayRole) { - if (_updating) { - return QVariant("Updating..."); - } else if (index.row() > _locations.length()) { - return QVariant(); - } else if (index.column() == NameColumn) { - return _locations[index.row()]->name(); - } else if (index.column() == AddressColumn) { - return QVariant(_locations[index.row()]->address()); - } - } - - return QVariant(); - -} -QVariant UserLocationsModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - switch (section) { - case NameColumn: return "Name"; - case AddressColumn: return "Address"; - default: return QVariant(); - } - } - - return QVariant(); -} - -Qt::ItemFlags UserLocationsModel::flags(const QModelIndex& index) const { - if (index.row() < _locations.length()) { - UserLocation* ul = _locations[index.row()]; - if (ul->isUpdating()) { - return Qt::NoItemFlags; - } - } - - return QAbstractListModel::flags(index); -} diff --git a/interface/src/UserLocationsModel.h b/interface/src/UserLocationsModel.h deleted file mode 100644 index 54518d72e1..0000000000 --- a/interface/src/UserLocationsModel.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// UserLocationsModel.h -// interface/src -// -// Created by Ryan Huffman on 06/24/14. -// Copyright 2014 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 -// - -#ifndef hifi_UserLocationsModel_h -#define hifi_UserLocationsModel_h - -#include -#include -#include - - -class UserLocation : public QObject { - Q_OBJECT -public: - UserLocation(const QString& id, const QString& name, const QString& address); - bool isUpdating() { return _updating; } - void requestRename(const QString& newName); - void requestDelete(); - - const QString& id() { return _id; } - const QString& name() { return _name; } - const QString& address() { return _address; } - -public slots: - void handleRenameResponse(const QJsonObject& responseData); - void handleRenameError(QNetworkReply& errorReply); - void handleDeleteResponse(const QJsonObject& responseData); - void handleDeleteError(QNetworkReply& errorReply); - -signals: - void updated(const QString& name); - void deleted(const QString& name); - -private: - QString _id; - QString _name; - QString _address; - QString _previousName; - bool _updating; - -}; - -class UserLocationsModel : public QAbstractListModel { - Q_OBJECT -public: - UserLocationsModel(QObject* parent = NULL); - ~UserLocationsModel(); - - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - virtual int columnCount(const QModelIndex& parent = QModelIndex()) const { return 2; }; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual Qt::ItemFlags flags(const QModelIndex& index) const; - - void deleteLocation(const QModelIndex& index); - void renameLocation(const QModelIndex& index, const QString& newName); - - enum Columns { - NameColumn = 0, - AddressColumn - }; - -public slots: - void refresh(); - void update(); - void handleLocationsResponse(const QJsonObject& responseData); - void removeLocation(const QString& name); - -private: - bool _updating; - QList _locations; -}; - -#endif // hifi_UserLocationsModel_h From 93561d3b212302963ed5362ba95c3789e53f312a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 18 Sep 2014 09:27:07 -0700 Subject: [PATCH 8/9] remove the existing user locations dialog --- interface/src/ui/UserLocationsDialog.cpp | 79 ------------------------ interface/src/ui/UserLocationsDialog.h | 35 ----------- 2 files changed, 114 deletions(-) delete mode 100644 interface/src/ui/UserLocationsDialog.cpp delete mode 100644 interface/src/ui/UserLocationsDialog.h diff --git a/interface/src/ui/UserLocationsDialog.cpp b/interface/src/ui/UserLocationsDialog.cpp deleted file mode 100644 index 31f388d045..0000000000 --- a/interface/src/ui/UserLocationsDialog.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// UserLocationsDialog.cpp -// interface/src/ui -// -// Created by Ryan Huffman on 06/24/14. -// Copyright 2014 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 -#include -#include - -#include - -#include "Menu.h" -#include "UserLocationsDialog.h" - -UserLocationsDialog::UserLocationsDialog(QWidget* parent) : - QDialog(parent), - _ui(), - _proxyModel(this), - _userLocationsModel(this) { - - _ui.setupUi(this); - - _proxyModel.setSourceModel(&_userLocationsModel); - _proxyModel.setDynamicSortFilter(true); - - _ui.locationsTreeView->setModel(&_proxyModel); - _ui.locationsTreeView->setSortingEnabled(true); - _ui.locationsTreeView->sortByColumn(UserLocationsModel::NameColumn, Qt::AscendingOrder); - - connect(_ui.locationsTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, - this, &UserLocationsDialog::updateEnabled); - connect(&_userLocationsModel, &UserLocationsModel::modelReset, this, &UserLocationsDialog::updateEnabled); - connect(&_userLocationsModel, &UserLocationsModel::modelReset, &_proxyModel, &QSortFilterProxyModel::invalidate); - connect(_ui.locationsTreeView, &QTreeView::doubleClicked, this, &UserLocationsDialog::goToModelIndex); - - connect(_ui.deleteButton, &QPushButton::clicked, this, &UserLocationsDialog::deleteSelection); - connect(_ui.renameButton, &QPushButton::clicked, this, &UserLocationsDialog::renameSelection); - connect(_ui.refreshButton, &QPushButton::clicked, &_userLocationsModel, &UserLocationsModel::refresh); - - this->setWindowTitle("My Locations"); -} - -void UserLocationsDialog::updateEnabled() { - bool enabled = _ui.locationsTreeView->selectionModel()->hasSelection(); - _ui.renameButton->setEnabled(enabled); - _ui.deleteButton->setEnabled(enabled); -} - -void UserLocationsDialog::goToModelIndex(const QModelIndex& index) { - QVariant address = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::AddressColumn)); - AddressManager::getInstance().handleLookupString(address.toString()); -} - -void UserLocationsDialog::deleteSelection() { - QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex(); - selection = _proxyModel.mapToSource(selection); - if (selection.isValid()) { - _userLocationsModel.deleteLocation(selection); - } -} - -void UserLocationsDialog::renameSelection() { - QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex(); - selection = _proxyModel.mapToSource(selection); - if (selection.isValid()) { - bool ok; - QString name = _userLocationsModel.data(selection.sibling(selection.row(), UserLocationsModel::NameColumn)).toString(); - QString newName = QInputDialog::getText(this, "Rename '" + name + "'", "Set name to:", QLineEdit::Normal, name, &ok); - if (ok && !newName.isEmpty()) { - _userLocationsModel.renameLocation(selection, newName); - } - } -} diff --git a/interface/src/ui/UserLocationsDialog.h b/interface/src/ui/UserLocationsDialog.h deleted file mode 100644 index 0e596ece87..0000000000 --- a/interface/src/ui/UserLocationsDialog.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// UserLocationsDialog.h -// interface/src/ui -// -// Created by Ryan Huffman on 06/24/14. -// Copyright 2014 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 -// - -#ifndef hifi_UserLocationsDialog_h -#define hifi_UserLocationsDialog_h - -#include "ui_userLocationsDialog.h" -#include "UserLocationsModel.h" - -class UserLocationsDialog : public QDialog { - Q_OBJECT -public: - UserLocationsDialog(QWidget* parent = NULL); - -protected slots: - void updateEnabled(); - void goToModelIndex(const QModelIndex& index); - void deleteSelection(); - void renameSelection(); - -private: - Ui::UserLocationsDialog _ui; - QSortFilterProxyModel _proxyModel; - UserLocationsModel _userLocationsModel; -}; - -#endif // hifi_UserLocationsDialog_h From a0675162b6d1f52105f895311a4e8a94f37d08b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 18 Sep 2014 09:35:33 -0700 Subject: [PATCH 9/9] hook My Locations to data-web dialog --- interface/src/Menu.cpp | 12 ++++++++---- interface/src/Menu.h | 6 +++--- libraries/networking/src/LimitedNodeList.cpp | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 34026398f8..3c6ca76573 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1210,13 +1210,17 @@ void Menu::displayNameLocationResponse(const QString& errorString) { void Menu::toggleLocationList() { if (!_userLocationsDialog) { - _userLocationsDialog = new UserLocationsDialog(Application::getInstance()->getWindow()); + _userLocationsDialog = DataWebDialog::dialogForPath("/locations"); } - if (_userLocationsDialog->isVisible()) { - _userLocationsDialog->hide(); - } else { + + if (!_userLocationsDialog->isVisible()) { _userLocationsDialog->show(); } + + _userLocationsDialog->raise(); + _userLocationsDialog->activateWindow(); + _userLocationsDialog->showNormal(); + } void Menu::nameLocation() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f2df7a2885..6077788bd4 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -28,12 +28,12 @@ #endif #include "location/LocationManager.h" -#include "ui/PreferencesDialog.h" #include "ui/ChatWindow.h" +#include "ui/DataWebDialog.h" #include "ui/JSConsole.h" #include "ui/LoginDialog.h" +#include "ui/PreferencesDialog.h" #include "ui/ScriptEditorWindow.h" -#include "ui/UserLocationsDialog.h" const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -273,7 +273,7 @@ private: QDialog* _jsConsole; OctreeStatsDialog* _octreeStatsDialog; LodToolsDialog* _lodToolsDialog; - UserLocationsDialog* _userLocationsDialog; + QPointer _userLocationsDialog; #ifdef Q_OS_MAC SpeechRecognizer _speechRecognizer; #endif diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index bfdfc28d5e..d42cab6210 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -33,7 +33,7 @@ const char SOLO_NODE_TYPES[2] = { NodeType::AudioMixer }; -const QUrl DEFAULT_NODE_AUTH_URL = QUrl("http://localhost:3000"); +const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://data.highfidelity.io"); LimitedNodeList* LimitedNodeList::_sharedInstance = NULL;