Merge pull request #3404 from birarda/data-web-domain-lookup

initial transition to new metaverse API
This commit is contained in:
Brad Hefta-Gaub 2014-09-12 13:45:40 -07:00
commit b209b70094
31 changed files with 599 additions and 612 deletions

View file

@ -189,6 +189,12 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
populateDefaultStaticAssignmentsExcludingTypes(parsedTypes);
LimitedNodeList* nodeList = LimitedNodeList::createInstance(domainServerPort, domainServerDTLSPort);
const QString DOMAIN_CONFIG_ID_KEY = "id";
// set our LimitedNodeList UUID to match the UUID from our config
// nodes will currently use this to add resources to data-web that relate to our domain
nodeList->setSessionUUID(_argumentVariantMap.value(DOMAIN_CONFIG_ID_KEY).toString());
connect(nodeList, &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
connect(nodeList, &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);

View file

@ -51,6 +51,7 @@
#include <QMimeData>
#include <QMessageBox>
#include <AddressManager.h>
#include <AccountManager.h>
#include <AudioInjector.h>
#include <EntityScriptingInterface.h>
@ -80,10 +81,10 @@
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AudioDeviceScriptingInterface.h"
#include "scripting/ClipboardScriptingInterface.h"
#include "scripting/LocationScriptingInterface.h"
#include "scripting/MenuScriptingInterface.h"
#include "scripting/SettingsScriptingInterface.h"
#include "scripting/WindowScriptingInterface.h"
#include "scripting/LocationScriptingInterface.h"
#include "ui/InfoView.h"
#include "ui/OAuthWebViewHandler.h"
@ -358,9 +359,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
Particle::setVoxelEditPacketSender(&_voxelEditSender);
Particle::setParticleEditPacketSender(&_particleEditSender);
// when -url in command line, teleport to location
urlGoTo(argc, constArgv);
// For now we're going to set the PPS for outbound packets to be super high, this is
// probably not the right long term solution. But for now, we're going to do this to
// allow you to move a particle around in your hand
@ -405,9 +403,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(_window, &MainWindow::windowGeometryChanged,
_runningScriptsWidget, &RunningScriptsWidget::setBoundary);
AddressManager& addressManager = AddressManager::getInstance();
//When -url in command line, teleport to location
urlGoTo(argc, constArgv);
// connect to the domainChangeRequired signal on AddressManager
connect(&addressManager, &AddressManager::possibleDomainChangeRequired,
this, &Application::changeDomainHostname);
// when -url in command line, teleport to location
addressManager.handleLookupString(getCmdOption(argc, constArgv, "-url"));
// call the OAuthWebviewHandler static getter so that its instance lives in our thread
OAuthWebViewHandler::getInstance();
@ -807,12 +811,14 @@ bool Application::event(QEvent* event) {
// handle custom URL
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);
if (isHifiSchemeURL) {
Menu::getInstance()->goToURL(fileEvent->url().toLocalFile());
if (!fileEvent->url().isEmpty()) {
AddressManager::getInstance().handleLookupString(fileEvent->url().toLocalFile());
}
return false;
}
return QApplication::event(event);
}
@ -912,7 +918,12 @@ void Application::keyPressEvent(QKeyEvent* event) {
case Qt::Key_Return:
case Qt::Key_Enter:
Menu::getInstance()->triggerOption(MenuOption::Chat);
if (isMeta) {
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
} else {
Menu::getInstance()->triggerOption(MenuOption::Chat);
}
break;
case Qt::Key_Up:
@ -1059,10 +1070,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
case Qt::Key_Equal:
_myAvatar->resetSize();
break;
case Qt::Key_At:
Menu::getInstance()->goTo();
break;
default:
event->ignore();
break;
@ -1321,7 +1328,7 @@ void Application::dropEvent(QDropEvent *event) {
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
if (snapshotData) {
if (!snapshotData->getDomain().isEmpty()) {
Menu::getInstance()->goToDomain(snapshotData->getDomain());
changeDomainHostname(snapshotData->getDomain());
}
_myAvatar->setPosition(snapshotData->getLocation());
@ -3377,31 +3384,53 @@ void Application::updateWindowTitle(){
#ifndef WIN32
// crashes with vs2013/win32
qDebug("Application title set to: %s", title.toStdString().c_str());
#endif //!WIN32
#endif
_window->setWindowTitle(title);
}
void Application::updateLocationInServer() {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
const QUuid& domainUUID = NodeList::getInstance()->getDomainHandler().getUUID();
if (accountManager.isLoggedIn() && !domainUUID.isNull()) {
// construct a QJsonObject given the user's current address information
QJsonObject updatedLocationObject;
QJsonObject rootObject;
QJsonObject addressObject;
addressObject.insert("position", QString(createByteArray(_myAvatar->getPosition())));
addressObject.insert("orientation", QString(createByteArray(glm::degrees(safeEulerAngles(_myAvatar->getOrientation())))));
addressObject.insert("domain", NodeList::getInstance()->getDomainHandler().getHostname());
QJsonObject locationObject;
QString pathString = AddressManager::pathForPositionAndOrientation(_myAvatar->getPosition(),
true,
_myAvatar->getOrientation());
const QString LOCATION_KEY_IN_ROOT = "location";
const QString PATH_KEY_IN_LOCATION = "path";
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, domainUUID.toString());
updatedLocationObject.insert("address", addressObject);
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), QJsonDocument(updatedLocationObject).toJson());
accountManager.authenticatedRequest("/api/v1/users/location", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
}
}
void Application::changeDomainHostname(const QString &newDomainHostname) {
NodeList* nodeList = NodeList::getInstance();
if (!nodeList->getDomainHandler().isCurrentHostname(newDomainHostname)) {
// tell the MyAvatar object to send a kill packet so that it dissapears from its old avatar mixer immediately
_myAvatar->sendKillAvatar();
// call the domain hostname change as a queued connection on the nodelist
QMetaObject::invokeMethod(&NodeList::getInstance()->getDomainHandler(), "setHostname",
Q_ARG(const QString&, newDomainHostname));
}
}
void Application::domainChanged(const QString& domainHostname) {
updateWindowTitle();
@ -3785,12 +3814,11 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", WindowScriptingInterface::getInstance());
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter, windowValue);
LocationScriptingInterface::locationSetter, windowValue);
// register `location` on the global object.
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter);
LocationScriptingInterface::locationSetter);
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
@ -3918,6 +3946,15 @@ void Application::uploadAttachment() {
uploadModel(ATTACHMENT_MODEL);
}
void Application::openUrl(const QUrl& url) {
if (url.scheme() == HIFI_URL_SCHEME) {
AddressManager::getInstance().handleLookupString(url.toString());
} else {
// address manager did not handle - ask QDesktopServices to handle
QDesktopServices::openUrl(url);
}
}
void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) {
// from the domain-handler, figure out the satoshi cost per voxel and per meter cubed
@ -4114,37 +4151,3 @@ void Application::takeSnapshot() {
}
_snapshotShareDialog->show();
}
void Application::urlGoTo(int argc, const char * constArgv[]) {
//Gets the url (hifi://domain/destination/orientation)
QString customUrl = getCmdOption(argc, constArgv, "-url");
if(customUrl.startsWith(CUSTOM_URL_SCHEME + "//")) {
QStringList urlParts = customUrl.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts);
if (urlParts.count() == 1) {
// location coordinates or place name
QString domain = urlParts[0];
Menu::goToDomain(domain);
} else if (urlParts.count() > 1) {
// if url has 2 or more parts, the first one is domain name
QString domain = urlParts[0];
// second part is either a destination coordinate or
// a place name
QString destination = urlParts[1];
// any third part is an avatar orientation.
QString orientation = urlParts.count() > 2 ? urlParts[2] : QString();
Menu::goToDomain(domain);
// goto either @user, #place, or x-xx,y-yy,z-zz
// style co-ordinate.
Menu::goTo(destination);
if (!orientation.isEmpty()) {
// location orientation
Menu::goToOrientation(orientation);
}
}
}
}

View file

@ -114,7 +114,6 @@ static const float NODE_KILLED_GREEN = 0.0f;
static const float NODE_KILLED_BLUE = 0.0f;
static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString CUSTOM_URL_SCHEME = "hifi:";
static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees
static const float BILLBOARD_DISTANCE = 5.0f; // meters
@ -153,7 +152,6 @@ public:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void urlGoTo(int argc, const char * constArgv[]);
void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event);
@ -316,6 +314,7 @@ signals:
void importDone();
public slots:
void changeDomainHostname(const QString& newDomainHostname);
void domainChanged(const QString& domainHostname);
void updateWindowTitle();
void updateLocationInServer();
@ -355,6 +354,8 @@ public slots:
void uploadHead();
void uploadSkeleton();
void uploadAttachment();
void openUrl(const QUrl& url);
void bumpSettings() { ++_numChangedSettings; }

View file

@ -30,6 +30,7 @@
#include <QDesktopServices>
#include <AccountManager.h>
#include <AddressManager.h>
#include <XmppClient.h>
#include <UUID.h>
#include <UserActivityLogger.h>
@ -155,21 +156,6 @@ Menu::Menu() :
appInstance, SLOT(toggleRunningScriptsWidget()));
addDisabledActionAndSeparator(fileMenu, "Go");
addActionToQMenuAndActionHash(fileMenu,
MenuOption::GoHome,
Qt::CTRL | Qt::Key_G,
appInstance->getAvatar(),
SLOT(goHome()));
addActionToQMenuAndActionHash(fileMenu,
MenuOption::GoToDomain,
Qt::CTRL | Qt::Key_D,
this,
SLOT(goToDomainDialog()));
addActionToQMenuAndActionHash(fileMenu,
MenuOption::GoToLocation,
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
this,
SLOT(goToLocation()));
addActionToQMenuAndActionHash(fileMenu,
MenuOption::NameLocation,
Qt::CTRL | Qt::Key_N,
@ -181,12 +167,10 @@ Menu::Menu() :
this,
SLOT(toggleLocationList()));
addActionToQMenuAndActionHash(fileMenu,
MenuOption::GoTo,
Qt::Key_At,
MenuOption::AddressBar,
Qt::CTRL | Qt::Key_Enter,
this,
SLOT(goTo()));
connect(&LocationManager::getInstance(), &LocationManager::multipleDestinationsFound,
this, &Menu::multipleDestinationsDecision);
SLOT(toggleAddressBar()));
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead()));
@ -1155,147 +1139,25 @@ void Menu::changePrivateKey() {
sendFakeEnterEvent();
}
void Menu::goToDomain(const QString newDomain) {
if (NodeList::getInstance()->getDomainHandler().getHostname() != newDomain) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
Application::getInstance()->getAvatar()->sendKillAvatar();
void Menu::toggleAddressBar() {
// give our nodeList the new domain-server hostname
NodeList::getInstance()->getDomainHandler().setHostname(newDomain);
QInputDialog addressBarDialog(Application::getInstance()->getWindow());
addressBarDialog.setWindowTitle("Address Bar");
addressBarDialog.setWindowFlags(Qt::Sheet);
addressBarDialog.setLabelText("place, domain, @user, example.com, /position/orientation");
addressBarDialog.resize(addressBarDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
addressBarDialog.size().height());
int dialogReturn = addressBarDialog.exec();
if (dialogReturn == QDialog::Accepted && !addressBarDialog.textValue().isEmpty()) {
// let the AddressManger figure out what to do with this
AddressManager::getInstance().handleLookupString(addressBarDialog.textValue());
}
}
void Menu::goToDomainDialog() {
QString currentDomainHostname = NodeList::getInstance()->getDomainHandler().getHostname();
if (NodeList::getInstance()->getDomainHandler().getPort() != DEFAULT_DOMAIN_SERVER_PORT) {
// add the port to the currentDomainHostname string if it is custom
currentDomainHostname.append(QString(":%1").arg(NodeList::getInstance()->getDomainHandler().getPort()));
}
QInputDialog domainDialog(Application::getInstance()->getWindow());
domainDialog.setWindowTitle("Go to Domain");
domainDialog.setLabelText("Domain server:");
domainDialog.setTextValue(currentDomainHostname);
domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height());
int dialogReturn = domainDialog.exec();
if (dialogReturn == QDialog::Accepted) {
QString newHostname(DEFAULT_DOMAIN_HOSTNAME);
if (domainDialog.textValue().size() > 0) {
// the user input a new hostname, use that
newHostname = domainDialog.textValue();
}
goToDomain(newHostname);
}
sendFakeEnterEvent();
}
void Menu::goToOrientation(QString orientation) {
LocationManager::getInstance().goToOrientation(orientation);
}
bool Menu::goToDestination(QString destination) {
return LocationManager::getInstance().goToDestination(destination);
}
void Menu::goTo(QString destination) {
LocationManager::getInstance().goTo(destination);
}
void Menu::goTo() {
QInputDialog gotoDialog(Application::getInstance()->getWindow());
gotoDialog.setWindowTitle("Go to");
gotoDialog.setLabelText("Destination or URL:\n @user, #place, hifi://domain/location/orientation");
QString destination = QString();
gotoDialog.setTextValue(destination);
gotoDialog.resize(gotoDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, gotoDialog.size().height());
int dialogReturn = gotoDialog.exec();
if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) {
QString desiredDestination = gotoDialog.textValue();
if (!goToURL(desiredDestination)) {;
goTo(desiredDestination);
}
}
sendFakeEnterEvent();
}
bool Menu::goToURL(QString location) {
if (location.startsWith(CUSTOM_URL_SCHEME + "/")) {
QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length()).split('/', QString::SkipEmptyParts);
if (urlParts.count() > 1) {
// if url has 2 or more parts, the first one is domain name
QString domain = urlParts[0];
// second part is either a destination coordinate or
// a place name
QString destination = urlParts[1];
// any third part is an avatar orientation.
QString orientation = urlParts.count() > 2 ? urlParts[2] : QString();
goToDomain(domain);
// goto either @user, #place, or x-xx,y-yy,z-zz
// style co-ordinate.
goTo(destination);
if (!orientation.isEmpty()) {
// location orientation
goToOrientation(orientation);
}
} else if (urlParts.count() == 1) {
QString destination = urlParts[0];
// If this starts with # or @, treat it as a user/location, otherwise treat it as a domain
if (destination[0] == '#' || destination[0] == '@') {
goTo(destination);
} else {
goToDomain(destination);
}
}
return true;
}
return false;
}
void Menu::goToUser(const QString& user) {
LocationManager::getInstance().goTo(user);
}
/// Open a url, shortcutting any "hifi" scheme URLs to the local application.
void Menu::openUrl(const QUrl& url) {
if (url.scheme() == "hifi") {
goToURL(url.toString());
} else {
QDesktopServices::openUrl(url);
}
}
void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
QMessageBox msgBox;
msgBox.setText("Both user and location exists with same name");
msgBox.setInformativeText("Where you wanna go?");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Open);
msgBox.button(QMessageBox::Ok)->setText("User");
msgBox.button(QMessageBox::Open)->setText("Place");
int userResponse = msgBox.exec();
if (userResponse == QMessageBox::Ok) {
Application::getInstance()->getAvatar()->goToLocationFromAddress(userData["address"].toObject());
} else if (userResponse == QMessageBox::Open) {
Application::getInstance()->getAvatar()->goToLocationFromAddress(placeData["address"].toObject());
}
}
void Menu::muteEnvironment() {
int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment);
int packetSize = headerSize + sizeof(glm::vec3) + sizeof(float);
@ -1320,43 +1182,13 @@ void Menu::muteEnvironment() {
free(packet);
}
void Menu::goToLocation() {
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
glm::vec3 avatarPos = myAvatar->getPosition();
QString currentLocation = QString("%1, %2, %3").arg(QString::number(avatarPos.x),
QString::number(avatarPos.y), QString::number(avatarPos.z));
void Menu::displayNameLocationResponse(const QString& errorString) {
QInputDialog coordinateDialog(Application::getInstance()->getWindow());
coordinateDialog.setWindowTitle("Go to Location");
coordinateDialog.setLabelText("Coordinate as x,y,z:");
coordinateDialog.setTextValue(currentLocation);
coordinateDialog.resize(coordinateDialog.parentWidget()->size().width() * 0.30, coordinateDialog.size().height());
int dialogReturn = coordinateDialog.exec();
if (dialogReturn == QDialog::Accepted && !coordinateDialog.textValue().isEmpty()) {
goToDestination(coordinateDialog.textValue());
}
sendFakeEnterEvent();
}
void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse response) {
if (response == LocationManager::Created) {
return;
}
QMessageBox msgBox;
switch (response) {
case LocationManager::AlreadyExists:
msgBox.setText("That name has been already claimed, try something else.");
break;
default:
msgBox.setText("An unexpected error has occurred, please try again later.");
break;
}
msgBox.exec();
if (!errorString.isEmpty()) {
QMessageBox msgBox;
msgBox.setText(errorString);
msgBox.exec();
}
}
void Menu::toggleLocationList() {
@ -1374,23 +1206,34 @@ void Menu::nameLocation() {
// check if user is logged in or show login dialog if not
AccountManager& accountManager = AccountManager::getInstance();
if (!accountManager.isLoggedIn()) {
QMessageBox msgBox;
msgBox.setText("We need to tie this location to your username.");
msgBox.setInformativeText("Please login first, then try naming the location again.");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.button(QMessageBox::Ok)->setText("Login");
if (msgBox.exec() == QMessageBox::Ok) {
loginForCurrentDomain();
}
return;
}
DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler();
if (domainHandler.getUUID().isNull()) {
const QString UNREGISTERED_DOMAIN_MESSAGE = "This domain is not registered with High Fidelity."
"\n\nYou cannot create a global location in an unregistered domain.";
QMessageBox::critical(this, "Unregistered Domain", UNREGISTERED_DOMAIN_MESSAGE);
return;
}
QInputDialog nameDialog(Application::getInstance()->getWindow());
nameDialog.setWindowTitle("Name this location");
nameDialog.setLabelText("Name this location, then share that name with others.\n"
"When they come here, they'll be in the same location and orientation\n"
"When they come here, they'll have the same viewpoint\n"
"(wherever you are standing and looking now) as you.\n\n"
"Location name:");
@ -1405,10 +1248,10 @@ void Menu::nameLocation() {
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
LocationManager* manager = new LocationManager();
connect(manager, &LocationManager::creationCompleted, this, &Menu::namedLocationCreated);
connect(manager, &LocationManager::creationCompleted, this, &Menu::displayNameLocationResponse);
NamedLocation* location = new NamedLocation(locationName,
myAvatar->getPosition(), myAvatar->getOrientation(),
NodeList::getInstance()->getDomainHandler().getHostname());
domainHandler.getUUID());
manager->createNamedLocation(location);
}
}

View file

@ -164,11 +164,6 @@ public:
int menuItemLocation = UNSPECIFIED_POSITION);
void removeAction(QMenu* menu, const QString& actionName);
bool static goToDestination(QString destination);
void static goToOrientation(QString orientation);
void static goToDomain(const QString newDomain);
void static goTo(QString destination);
const QByteArray& getWalletPrivateKey() const { return _walletPrivateKey; }
@ -187,11 +182,8 @@ public slots:
void saveSettings(QSettings* settings = NULL);
void importSettings();
void exportSettings();
void goTo();
bool goToURL(QString location);
void goToUser(const QString& user);
void toggleAddressBar();
void pasteToVoxel();
void openUrl(const QUrl& url);
void toggleLoginMenuItem();
@ -213,8 +205,6 @@ private slots:
void editAttachments();
void editAnimations();
void changePrivateKey();
void goToDomainDialog();
void goToLocation();
void nameLocation();
void toggleLocationList();
void bandwidthDetailsClosed();
@ -228,8 +218,7 @@ private slots:
void toggleConsole();
void toggleChat();
void audioMuteToggled();
void namedLocationCreated(LocationManager::NamedLocationCreateResponse response);
void multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData);
void displayNameLocationResponse(const QString& errorString);
void muteEnvironment();
private:
@ -318,6 +307,7 @@ private:
namespace MenuOption {
const QString AboutApp = "About Interface";
const QString AddressBar = "Show Address Bar";
const QString AlignForearmsWithWrists = "Align Forearms with Wrists";
const QString AlternateIK = "Alternate IK";
const QString AmbientOcclusion = "Ambient Occlusion";
@ -403,10 +393,7 @@ namespace MenuOption {
const QString FullscreenMirror = "Fullscreen Mirror";
const QString GlowMode = "Cycle Glow Mode";
const QString GlowWhenSpeaking = "Glow When Speaking";
const QString GoHome = "Go Home";
const QString GoToDomain = "Go To Domain...";
const QString GoTo = "Go To...";
const QString GoToLocation = "Go To Location...";
const QString GoToUser = "Go To User";
const QString HeadMouse = "Head Mouse";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IncreaseVoxelSize = "Increase Voxel Size";

View file

@ -421,11 +421,11 @@ void ModelUploader::uploadSuccess(const QJsonObject& jsonResponse) {
checkS3();
}
void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString) {
void ModelUploader::uploadFailed(QNetworkReply& errorReply) {
if (_progressDialog) {
_progressDialog->reject();
}
qDebug() << "Model upload failed (" << errorCode << "): " << errorString;
qDebug() << "Model upload failed (" << errorReply.error() << "): " << errorReply.errorString();
QMessageBox::warning(NULL,
QString("ModelUploader::uploadFailed()"),
QString("There was a problem with your upload, please try again later."),

View file

@ -43,7 +43,7 @@ private slots:
void checkJSON(const QJsonObject& jsonResponse);
void uploadUpdate(qint64 bytesSent, qint64 bytesTotal);
void uploadSuccess(const QJsonObject& jsonResponse);
void uploadFailed(QNetworkReply::NetworkError errorCode, const QString& errorString);
void uploadFailed(QNetworkReply& errorReply);
void checkS3();
void processCheck();

View file

@ -18,14 +18,13 @@
#include "Application.h"
#include "UserLocationsModel.h"
static const QString PLACES_GET = "/api/v1/places";
static const QString PLACES_UPDATE = "/api/v1/places/%1";
static const QString PLACES_DELETE= "/api/v1/places/%1";
static const QString LOCATIONS_GET = "/api/v1/locations";
static const QString LOCATION_UPDATE_OR_DELETE = "/api/v1/locations/%1";
UserLocation::UserLocation(QString id, QString name, QString location) :
UserLocation::UserLocation(const QString& id, const QString& name, const QString& address) :
_id(id),
_name(name),
_location(location),
_address(address),
_previousName(name),
_updating(false) {
}
@ -35,10 +34,15 @@ void UserLocation::requestRename(const QString& newName) {
_updating = true;
JSONCallbackParameters callbackParams(this, "handleRenameResponse", this, "handleRenameError");
QJsonObject jsonNameObject;
jsonNameObject.insert("name", QJsonValue(newName));
jsonNameObject.insert("name", newName);
QJsonObject locationObject;
locationObject.insert("location", jsonNameObject);
QJsonDocument jsonDocument(jsonNameObject);
AccountManager::getInstance().authenticatedRequest(PLACES_UPDATE.arg(_id),
AccountManager::getInstance().authenticatedRequest(LOCATION_UPDATE_OR_DELETE.arg(_id),
QNetworkAccessManager::PutOperation,
callbackParams,
jsonDocument.toJson());
@ -54,7 +58,9 @@ void UserLocation::handleRenameResponse(const QJsonObject& responseData) {
QJsonValue status = responseData["status"];
if (!status.isUndefined() && status.toString() == "success") {
QString updatedName = responseData["data"].toObject()["name"].toString();
qDebug() << responseData;
QString updatedName = responseData["data"].toObject()["location"].toObject()["name"].toString();
qDebug() << "The updated name is" << updatedName;
_name = updatedName;
} else {
_name = _previousName;
@ -75,10 +81,10 @@ void UserLocation::handleRenameResponse(const QJsonObject& responseData) {
emit updated(_name);
}
void UserLocation::handleRenameError(QNetworkReply::NetworkError error, const QString& errorString) {
void UserLocation::handleRenameError(QNetworkReply& errorReply) {
_updating = false;
QString msg = "There was an error renaming location '" + _name + "': " + errorString;
QString msg = "There was an error renaming location '" + _name + "': " + errorReply.errorString();
qDebug() << msg;
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
@ -90,7 +96,7 @@ void UserLocation::requestDelete() {
_updating = true;
JSONCallbackParameters callbackParams(this, "handleDeleteResponse", this, "handleDeleteError");
AccountManager::getInstance().authenticatedRequest(PLACES_DELETE.arg(_id),
AccountManager::getInstance().authenticatedRequest(LOCATION_UPDATE_OR_DELETE.arg(_id),
QNetworkAccessManager::DeleteOperation,
callbackParams);
}
@ -109,10 +115,10 @@ void UserLocation::handleDeleteResponse(const QJsonObject& responseData) {
}
}
void UserLocation::handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString) {
void UserLocation::handleDeleteError(QNetworkReply& errorReply) {
_updating = false;
QString msg = "There was an error deleting location '" + _name + "': " + errorString;
QString msg = "There was an error deleting location '" + _name + "': " + errorReply.errorString();
qDebug() << msg;
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
}
@ -153,7 +159,7 @@ void UserLocationsModel::refresh() {
endResetModel();
JSONCallbackParameters callbackParams(this, "handleLocationsResponse");
AccountManager::getInstance().authenticatedRequest(PLACES_GET,
AccountManager::getInstance().authenticatedRequest(LOCATIONS_GET,
QNetworkAccessManager::GetOperation,
callbackParams);
}
@ -165,14 +171,13 @@ void UserLocationsModel::handleLocationsResponse(const QJsonObject& responseData
QJsonValue status = responseData["status"];
if (!status.isUndefined() && status.toString() == "success") {
beginResetModel();
QJsonArray locations = responseData["data"].toObject()["places"].toArray();
QJsonArray locations = responseData["data"].toObject()["locations"].toArray();
for (QJsonArray::const_iterator it = locations.constBegin(); it != locations.constEnd(); it++) {
QJsonObject location = (*it).toObject();
QJsonObject address = location["address"].toObject();
QString locationAddress = "hifi://" + location["domain"].toObject()["name"].toString()
+ location["path"].toString();
UserLocation* userLocation = new UserLocation(location["id"].toString(), location["name"].toString(),
"hifi://" + address["domain"].toString()
+ "/" + address["position"].toString()
+ "/" + address["orientation"].toString());
locationAddress);
_locations.append(userLocation);
connect(userLocation, &UserLocation::deleted, this, &UserLocationsModel::removeLocation);
connect(userLocation, &UserLocation::updated, this, &UserLocationsModel::update);
@ -214,8 +219,8 @@ QVariant UserLocationsModel::data(const QModelIndex& index, int role) const {
return QVariant();
} else if (index.column() == NameColumn) {
return _locations[index.row()]->name();
} else if (index.column() == LocationColumn) {
return QVariant(_locations[index.row()]->location());
} else if (index.column() == AddressColumn) {
return QVariant(_locations[index.row()]->address());
}
}
@ -226,7 +231,7 @@ QVariant UserLocationsModel::headerData(int section, Qt::Orientation orientation
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case NameColumn: return "Name";
case LocationColumn: return "Location";
case AddressColumn: return "Address";
default: return QVariant();
}
}

View file

@ -20,20 +20,20 @@
class UserLocation : public QObject {
Q_OBJECT
public:
UserLocation(QString id, QString name, QString location);
UserLocation(const QString& id, const QString& name, const QString& address);
bool isUpdating() { return _updating; }
void requestRename(const QString& newName);
void requestDelete();
QString id() { return _id; }
QString name() { return _name; }
QString location() { return _location; }
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::NetworkError error, const QString& errorString);
void handleRenameError(QNetworkReply& errorReply);
void handleDeleteResponse(const QJsonObject& responseData);
void handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString);
void handleDeleteError(QNetworkReply& errorReply);
signals:
void updated(const QString& name);
@ -42,7 +42,7 @@ signals:
private:
QString _id;
QString _name;
QString _location;
QString _address;
QString _previousName;
bool _updating;
@ -65,7 +65,7 @@ public:
enum Columns {
NameColumn = 0,
LocationColumn
AddressColumn
};
public slots:

View file

@ -21,6 +21,7 @@
#include <QtCore/QTimer>
#include <AccountManager.h>
#include <AddressManager.h>
#include <GeometryUtil.h>
#include <NodeList.h>
#include <PacketHeaders.h>
@ -91,6 +92,9 @@ MyAvatar::MyAvatar() :
Ragdoll* ragdoll = _skeletonModel.buildRagdoll();
_physicsSimulation.setRagdoll(ragdoll);
_physicsSimulation.addEntity(&_voxelShapeManager);
// connect to AddressManager signal for location jumps
connect(&AddressManager::getInstance(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation);
}
MyAvatar::~MyAvatar() {
@ -1763,11 +1767,6 @@ void MyAvatar::maybeUpdateBillboard() {
sendBillboardPacket();
}
void MyAvatar::goHome() {
qDebug("Going Home!");
slamPosition(START_LOCATION);
}
void MyAvatar::increaseSize() {
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
_targetScale *= (1.0f + SCALING_RATIO);
@ -1787,45 +1786,26 @@ void MyAvatar::resetSize() {
qDebug("Reseted scale to %f", _targetScale);
}
void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
QJsonObject locationObject = jsonObject["data"].toObject()["address"].toObject();
bool isOnline = jsonObject["data"].toObject()["online"].toBool();
if (isOnline ) {
goToLocationFromAddress(locationObject);
} else {
QMessageBox::warning(Application::getInstance()->getWindow(), "", "The user is not online.");
void MyAvatar::goToLocation(const glm::vec3& newPosition, bool hasOrientation, const glm::vec3& newOrientation) {
glm::quat quatOrientation = getOrientation();
qDebug().nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", "
<< newPosition.y << ", " << newPosition.z;
if (hasOrientation) {
qDebug().nospace() << "MyAvatar goToLocation - new orientation is "
<< newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z;
// orient the user to face the target
glm::quat quatOrientation = glm::quat(glm::radians(newOrientation))
* glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
setOrientation(quatOrientation);
}
}
void MyAvatar::goToLocationFromAddress(const QJsonObject& locationObject) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
sendKillAvatar();
QString positionString = locationObject["position"].toString();
QString orientationString = locationObject["orientation"].toString();
QString domainHostnameString = locationObject["domain"].toString();
qDebug() << "Changing domain to" << domainHostnameString <<
", position to" << positionString <<
", and orientation to" << orientationString;
QStringList coordinateItems = positionString.split(',');
QStringList orientationItems = orientationString.split(',');
NodeList::getInstance()->getDomainHandler().setHostname(domainHostnameString);
// orient the user to face the target
glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(),
orientationItems[1].toFloat(),
orientationItems[2].toFloat())))
* glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
setOrientation(newOrientation);
// move the user a couple units away
const float DISTANCE_TO_USER = 2.0f;
glm::vec3 newPosition = glm::vec3(coordinateItems[0].toFloat(), coordinateItems[1].toFloat(),
coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
slamPosition(newPosition);
glm::vec3 shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
slamPosition(shiftedPosition);
emit transformChanged();
}

View file

@ -150,13 +150,11 @@ public:
const PlayerPointer getPlayer() const { return _player; }
public slots:
void goHome();
void increaseSize();
void decreaseSize();
void resetSize();
void goToLocationFromResponse(const QJsonObject& jsonObject);
void goToLocationFromAddress(const QJsonObject& jsonObject);
void goToLocation(const glm::vec3& newPosition, bool hasOrientation = false, const glm::vec3& newOrientation = glm::vec3());
// Set/Get update the thrust that will move the avatar around
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };

View file

@ -9,43 +9,33 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QMessageBox>
#include <qjsonobject.h>
#include <AccountManager.h>
#include "Application.h"
#include "LocationManager.h"
#include <UserActivityLogger.h>
const QString GET_USER_ADDRESS = "/api/v1/users/%1/address";
const QString GET_PLACE_ADDRESS = "/api/v1/places/%1";
const QString GET_ADDRESSES = "/api/v1/addresses/%1";
const QString POST_PLACE_CREATE = "/api/v1/places/";
LocationManager::LocationManager() {
};
const QString POST_LOCATION_CREATE = "/api/v1/locations/";
LocationManager& LocationManager::getInstance() {
static LocationManager sharedInstance;
return sharedInstance;
}
const QString UNKNOWN_ERROR_MESSAGE = "Unknown error creating named location. Please try again!";
void LocationManager::namedLocationDataReceived(const QJsonObject& data) {
if (data.isEmpty()) {
return;
}
if (data.contains("status") && data["status"].toString() == "success") {
emit creationCompleted(LocationManager::Created);
emit creationCompleted(QString());
} else {
emit creationCompleted(LocationManager::AlreadyExists);
emit creationCompleted(UNKNOWN_ERROR_MESSAGE);
}
}
void LocationManager::errorDataReceived(QNetworkReply::NetworkError error, const QString& message) {
emit creationCompleted(LocationManager::SystemError);
}
void LocationManager::createNamedLocation(NamedLocation* namedLocation) {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
@ -55,185 +45,45 @@ void LocationManager::createNamedLocation(NamedLocation* namedLocation) {
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "errorDataReceived";
accountManager.authenticatedRequest(POST_PLACE_CREATE, QNetworkAccessManager::PostOperation,
accountManager.authenticatedRequest(POST_LOCATION_CREATE, QNetworkAccessManager::PostOperation,
callbackParams, namedLocation->toJsonString().toUtf8());
}
}
void LocationManager::goTo(QString destination) {
const QString USER_DESTINATION_TYPE = "user";
const QString PLACE_DESTINATION_TYPE = "place";
const QString OTHER_DESTINATION_TYPE = "coordinate_or_username";
void LocationManager::errorDataReceived(QNetworkReply& errorReply) {
if (destination.startsWith("@")) {
// remove '@' and go to user
QString destinationUser = destination.remove(0, 1);
UserActivityLogger::getInstance().wentTo(USER_DESTINATION_TYPE, destinationUser);
goToUser(destinationUser);
return;
}
if (destination.startsWith("#")) {
// remove '#' and go to named place
QString destinationPlace = destination.remove(0, 1);
UserActivityLogger::getInstance().wentTo(PLACE_DESTINATION_TYPE, destinationPlace);
goToPlace(destinationPlace);
return;
}
// go to coordinate destination or to Username
if (!goToDestination(destination)) {
destination = QString(QUrl::toPercentEncoding(destination));
UserActivityLogger::getInstance().wentTo(OTHER_DESTINATION_TYPE, destination);
if (errorReply.header(QNetworkRequest::ContentTypeHeader).toString().startsWith("application/json")) {
// we have some JSON error data we can parse for our error message
QJsonDocument responseJson = QJsonDocument::fromJson(errorReply.readAll());
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "goToAddressFromResponse";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "handleAddressLookupError";
QJsonObject dataObject = responseJson.object()["data"].toObject();
AccountManager::getInstance().authenticatedRequest(GET_ADDRESSES.arg(destination),
QNetworkAccessManager::GetOperation,
callbackParams);
}
}
void LocationManager::goToAddressFromResponse(const QJsonObject& responseData) {
QJsonValue status = responseData["status"];
const QJsonObject& data = responseData["data"].toObject();
const QJsonValue& userObject = data["user"];
const QJsonValue& placeObject = data["place"];
if (!placeObject.isUndefined() && !userObject.isUndefined()) {
emit multipleDestinationsFound(userObject.toObject(), placeObject.toObject());
} else if (placeObject.isUndefined()) {
Application::getInstance()->getAvatar()->goToLocationFromAddress(userObject.toObject()["address"].toObject());
} else {
Application::getInstance()->getAvatar()->goToLocationFromAddress(placeObject.toObject()["address"].toObject());
}
}
void LocationManager::goToUser(QString userName) {
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar();
callbackParams.jsonCallbackMethod = "goToLocationFromResponse";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "handleAddressLookupError";
userName = QString(QUrl::toPercentEncoding(userName));
AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(userName),
QNetworkAccessManager::GetOperation,
callbackParams);
}
void LocationManager::goToPlace(QString placeName) {
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar();
callbackParams.jsonCallbackMethod = "goToLocationFromResponse";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "handleAddressLookupError";
placeName = QString(QUrl::toPercentEncoding(placeName));
AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(placeName),
QNetworkAccessManager::GetOperation,
callbackParams);
}
void LocationManager::goToOrientation(QString orientation) {
if (orientation.isEmpty()) {
return;
}
QStringList orientationItems = orientation.remove(' ').split(QRegExp("_|,"), QString::SkipEmptyParts);
const int NUMBER_OF_ORIENTATION_ITEMS = 4;
const int W_ITEM = 0;
const int X_ITEM = 1;
const int Y_ITEM = 2;
const int Z_ITEM = 3;
if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) {
// replace last occurrence of '_' with decimal point
replaceLastOccurrence('-', '.', orientationItems[W_ITEM]);
replaceLastOccurrence('-', '.', orientationItems[X_ITEM]);
replaceLastOccurrence('-', '.', orientationItems[Y_ITEM]);
replaceLastOccurrence('-', '.', orientationItems[Z_ITEM]);
double w = orientationItems[W_ITEM].toDouble();
double x = orientationItems[X_ITEM].toDouble();
double y = orientationItems[Y_ITEM].toDouble();
double z = orientationItems[Z_ITEM].toDouble();
glm::quat newAvatarOrientation(w, x, y, z);
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
glm::quat avatarOrientation = myAvatar->getOrientation();
if (newAvatarOrientation != avatarOrientation) {
myAvatar->setOrientation(newAvatarOrientation);
emit myAvatar->transformChanged();
qDebug() << dataObject;
QString errorString = "There was a problem creating that location.\n";
// construct the error string from the returned attribute errors
foreach(const QString& key, dataObject.keys()) {
errorString += "\n\u2022 " + key + " - ";
QJsonValue keyedErrorValue = dataObject[key];
if (keyedErrorValue.isArray()) {
foreach(const QJsonValue& attributeErrorValue, keyedErrorValue.toArray()) {
errorString += attributeErrorValue.toString() + ", ";
}
// remove the trailing comma at end of error list
errorString.remove(errorString.length() - 2, 2);
} else if (keyedErrorValue.isString()) {
errorString += keyedErrorValue.toString();
}
}
}
}
bool LocationManager::goToDestination(QString destination) {
QStringList coordinateItems = destination.remove(' ').split(QRegExp("_|,"), QString::SkipEmptyParts);
const int NUMBER_OF_COORDINATE_ITEMS = 3;
const int X_ITEM = 0;
const int Y_ITEM = 1;
const int Z_ITEM = 2;
if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) {
// replace last occurrence of '_' with decimal point
replaceLastOccurrence('-', '.', coordinateItems[X_ITEM]);
replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM]);
replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM]);
double x = coordinateItems[X_ITEM].toDouble();
double y = coordinateItems[Y_ITEM].toDouble();
double z = coordinateItems[Z_ITEM].toDouble();
glm::vec3 newAvatarPos(x, y, z);
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
glm::vec3 avatarPos = myAvatar->getPosition();
if (newAvatarPos != avatarPos) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
MyAvatar::sendKillAvatar();
qDebug("Going To Location: %f, %f, %f...", x, y, z);
myAvatar->slamPosition(newAvatarPos);
emit myAvatar->transformChanged();
}
return true;
}
// no coordinates were parsed
return false;
}
void LocationManager::handleAddressLookupError(QNetworkReply::NetworkError networkError,
const QString& errorString) {
QString messageBoxString;
if (networkError == QNetworkReply::ContentNotFoundError) {
messageBoxString = "That address could not be found.";
// emit our creationCompleted signal with the error
emit creationCompleted(errorString);
} else {
messageBoxString = errorString;
}
QMessageBox::warning(Application::getInstance()->getWindow(), "", messageBoxString);
}
void LocationManager::replaceLastOccurrence(const QChar search, const QChar replace, QString& string) {
int lastIndex;
lastIndex = string.lastIndexOf(search);
if (lastIndex > 0) {
lastIndex = string.lastIndexOf(search);
string.replace(lastIndex, 1, replace);
creationCompleted(UNKNOWN_ERROR_MESSAGE);
}
}

View file

@ -13,8 +13,8 @@
#define hifi_LocationManager_h
#include <QtCore>
#include <QtNetwork/QNetworkReply>
#include "AccountManager.h"
#include "NamedLocation.h"
class LocationManager : public QObject {
@ -29,29 +29,14 @@ public:
SystemError
};
LocationManager();
void createNamedLocation(NamedLocation* namedLocation);
void goTo(QString destination);
void goToUser(QString userName);
void goToPlace(QString placeName);
void goToOrientation(QString orientation);
bool goToDestination(QString destination);
public slots:
void handleAddressLookupError(QNetworkReply::NetworkError networkError, const QString& errorString);
private:
void replaceLastOccurrence(const QChar search, const QChar replace, QString& string);
signals:
void creationCompleted(LocationManager::NamedLocationCreateResponse response);
void multipleDestinationsFound(const QJsonObject& userData, const QJsonObject& placeData);
void creationCompleted(const QString& errorMessage);
private slots:
void namedLocationDataReceived(const QJsonObject& data);
void errorDataReceived(QNetworkReply::NetworkError error, const QString& message);
void goToAddressFromResponse(const QJsonObject& jsonObject);
void errorDataReceived(QNetworkReply& errorReply);
};

View file

@ -9,19 +9,25 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <AddressManager.h>
#include <UUID.h>
#include "NamedLocation.h"
const QString JSON_FORMAT = "{\"address\":{\"position\":\"%1,%2,%3\","
"\"orientation\":\"%4,%5,%6,%7\",\"domain\":\"%8\"},\"name\":\"%9\"}";
NamedLocation::NamedLocation(const QString& name,
const glm::vec3& position, const glm::quat& orientation,
const QUuid& domainID) :
_name(name),
_position(position),
_orientation(orientation),
_domainID(domainID)
{
}
const QString JSON_FORMAT = "{\"location\":{\"path\":\"%1\",\"domain_id\":\"%2\",\"name\":\"%3\"}}";
QString NamedLocation::toJsonString() {
return JSON_FORMAT.arg(QString::number(_location.x),
QString::number(_location.y),
QString::number(_location.z),
QString::number(_orientation.w),
QString::number(_orientation.x),
QString::number(_orientation.y),
QString::number(_orientation.z),
_domain,
_locationName);
return JSON_FORMAT.arg(AddressManager::pathForPositionAndOrientation(_position, true, _orientation),
uuidStringWithoutCurlyBraces(_domainID), _name);
}

View file

@ -22,39 +22,33 @@ class NamedLocation : public QObject {
Q_OBJECT
public:
NamedLocation(QString locationName, glm::vec3 location, glm::quat orientation, QString domain) {
_locationName = locationName;
_location = location;
_orientation = orientation;
_domain = domain;
}
NamedLocation(const QString& name, const glm::vec3& position, const glm::quat& orientation, const QUuid& domainID);
QString toJsonString();
bool isEmpty() { return _locationName.isNull() || _locationName.isEmpty(); }
bool isEmpty() { return _name.isNull() || _name.isEmpty(); }
void setLocationName(QString locationName) { _locationName = locationName; }
QString locationName() { return _locationName; }
void setName(QString name) { _name = name; }
const QString& getName() const { return _name; }
void setLocation(glm::vec3 location) { _location = location; }
glm::vec3 location() { return _location; }
void setLocation(glm::vec3 position) { _position = position; }
const glm::vec3& getPosition() const { return _position; }
void setOrientation(glm::quat orentation) { _orientation = orentation; }
glm::quat orientation() { return _orientation; }
void setOrientation(const glm::quat& orentation) { _orientation = orentation; }
const glm::quat& getOrientation() const { return _orientation; }
void setDomain(QString domain) { _domain = domain; }
QString domain() { return _domain; }
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
const QUuid& getDomainID() const { return _domainID; }
signals:
void dataReceived(bool locationExists);
private:
QString _locationName;
QString _name;
QString _createdBy;
glm::vec3 _location;
glm::vec3 _position;
glm::quat _orientation;
QString _domain;
QUuid _domainID;
};

View file

@ -29,10 +29,9 @@ QString LocationScriptingInterface::getHref() {
}
QString LocationScriptingInterface::getPathname() {
const glm::vec3& position = Application::getInstance()->getAvatar()->getPosition();
QString path;
path.sprintf("/%.4f,%.4f,%.4f", position.x, position.y, position.z);
return path;
MyAvatar* applicationAvatar = Application::getInstance()->getAvatar();
return AddressManager::pathForPositionAndOrientation(applicationAvatar->getPosition(),
true, applicationAvatar->getOrientation());
}
QString LocationScriptingInterface::getHostname() {
@ -40,7 +39,7 @@ QString LocationScriptingInterface::getHostname() {
}
void LocationScriptingInterface::assign(const QString& url) {
QMetaObject::invokeMethod(Menu::getInstance(), "goToURL", Q_ARG(const QString&, url));
QMetaObject::invokeMethod(&AddressManager::getInstance(), "handleLookupString", Q_ARG(const QString&, url));
}
QScriptValue LocationScriptingInterface::locationGetter(QScriptContext* context, QScriptEngine* engine) {

View file

@ -18,6 +18,8 @@
#include <QScriptValue>
#include <QString>
#include <AddressManager.h>
#include "Application.h"
class LocationScriptingInterface : public QObject {
@ -33,7 +35,7 @@ public:
bool isConnected();
QString getHref();
QString getProtocol() { return CUSTOM_URL_SCHEME; };
QString getProtocol() { return HIFI_URL_SCHEME; };
QString getPathname();
QString getHostname();

View file

@ -19,8 +19,8 @@ ChatMessageArea::ChatMessageArea(bool useFixedHeight) : QTextBrowser(), _useFixe
connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
this, &ChatMessageArea::updateLayout);
connect(this, &QTextBrowser::anchorClicked,
Menu::getInstance(), &Menu::openUrl);
connect(this, &QTextBrowser::anchorClicked, Application::getInstance(), &Application::openUrl);
}
void ChatMessageArea::setHtml(const QString& html) {

View file

@ -17,6 +17,9 @@
#include <QSizePolicy>
#include <QTimer>
#include <AddressManager.h>
#include <AccountManager.h>
#include "Application.h"
#include "ChatMessageArea.h"
#include "FlowLayout.h"
@ -28,7 +31,6 @@
#include "ChatWindow.h"
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?)|(?:hifi))://\\S+)");
@ -169,7 +171,7 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
} else if (event->type() == QEvent::MouseButtonRelease) {
QVariant userVar = sender->property("user");
if (userVar.isValid()) {
Menu::getInstance()->goToUser("@" + userVar.toString());
AddressManager::getInstance().goToUser(userVar.toString());
return true;
}
}

View file

@ -11,6 +11,8 @@
#include <QtWebKitWidgets/QWebView>
#include <AccountManager.h>
#include "Application.h"
#include "OAuthWebViewHandler.h"

View file

@ -23,6 +23,8 @@
#include <QTimer>
#include <QWidget>
#include <NetworkAccessManager.h>
#include "Application.h"
#include "ScriptHighlighting.h"

View file

@ -13,6 +13,8 @@
#include <QInputDialog>
#include <QPushButton>
#include <AddressManager.h>
#include "Menu.h"
#include "UserLocationsDialog.h"
@ -51,8 +53,8 @@ void UserLocationsDialog::updateEnabled() {
}
void UserLocationsDialog::goToModelIndex(const QModelIndex& index) {
QVariant location = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::LocationColumn));
Menu::getInstance()->goToURL(location.toString());
QVariant address = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::AddressColumn));
AddressManager::getInstance().handleLookupString(address.toString());
}
void UserLocationsDialog::deleteSelection() {

View file

@ -9,7 +9,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "../../Application.h"
#include <NetworkAccessManager.h>
#include "Application.h"
#include "BillboardOverlay.h"

View file

@ -292,8 +292,7 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
if (callbackParams.errorCallbackReceiver) {
// invoke the right method on the callback receiver
QMetaObject::invokeMethod(callbackParams.errorCallbackReceiver, qPrintable(callbackParams.errorCallbackMethod),
Q_ARG(QNetworkReply::NetworkError, requestReply->error()),
Q_ARG(const QString&, requestReply->errorString()));
Q_ARG(QNetworkReply&, *requestReply));
// remove the related reply-callback group from the map
_pendingCallbackMap.remove(requestReply);

View file

@ -0,0 +1,244 @@
//
// AddressManager.cpp
// libraries/networking/src
//
// Created by Stephen Birarda on 2014-09-10.
// 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 <qdebug.h>
#include <qregexp.h>
#include <qstringlist.h>
#include <GLMHelpers.h>
#include "AddressManager.h"
AddressManager& AddressManager::getInstance() {
static AddressManager sharedInstance;
return sharedInstance;
}
QString AddressManager::pathForPositionAndOrientation(const glm::vec3& position, bool hasOrientation,
const glm::quat& orientation) {
QString pathString = "/" + createByteArray(position);
if (hasOrientation) {
QString orientationString = createByteArray(glm::degrees(safeEulerAngles(orientation)));
pathString += "/" + orientationString;
}
return pathString;
}
const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
static bool hasSetupParameters = false;
static JSONCallbackParameters callbackParams;
if (!hasSetupParameters) {
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "handleAPIResponse";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "handleAPIError";
}
return callbackParams;
}
bool AddressManager::handleUrl(const QUrl& lookupUrl) {
if (lookupUrl.scheme() == HIFI_URL_SCHEME) {
// there are 4 possible lookup strings
// 1. global place name (name of domain or place) - example: sanfrancisco
// 2. user name (prepended with @) - example: @philip
// 3. location string (posX,posY,posZ/eulerX,eulerY,eulerZ)
// 4. domain network address (IP or dns resolvable hostname)
qDebug() << lookupUrl;
if (lookupUrl.isRelative()) {
// if this is a relative path then handle it as a relative viewpoint
handleRelativeViewpoint(lookupUrl.path());
} else {
// use our regex'ed helpers to figure out what we're supposed to do with this
if (!handleUsername(lookupUrl.authority())) {
// we're assuming this is either a network address or global place name
// check if it is a network address first
if (!handleNetworkAddress(lookupUrl.host())) {
// wasn't an address - lookup the place name
attemptPlaceNameLookup(lookupUrl.host());
}
// we may have a path that defines a relative viewpoint - if so we should jump to that now
handleRelativeViewpoint(lookupUrl.path());
}
}
return true;
}
return false;
}
void AddressManager::handleLookupString(const QString& lookupString) {
// we've verified that this is a valid hifi URL - hand it off to handleLookupString
QString sanitizedString = lookupString;
const QRegExp HIFI_SCHEME_REGEX = QRegExp(HIFI_URL_SCHEME + ":\\/{1,2}", Qt::CaseInsensitive);
sanitizedString = sanitizedString.remove(HIFI_SCHEME_REGEX);
handleUrl(QUrl(HIFI_URL_SCHEME + "://" + sanitizedString));
}
void AddressManager::handleAPIResponse(const QJsonObject &jsonObject) {
QJsonObject dataObject = jsonObject["data"].toObject();
const QString ADDRESS_API_DOMAIN_KEY = "domain";
const QString ADDRESS_API_ONLINE_KEY = "online";
if (!dataObject.contains(ADDRESS_API_ONLINE_KEY)
|| dataObject[ADDRESS_API_ONLINE_KEY].toBool()) {
if (dataObject.contains(ADDRESS_API_DOMAIN_KEY)) {
QJsonObject domainObject = dataObject[ADDRESS_API_DOMAIN_KEY].toObject();
const QString DOMAIN_NETWORK_ADDRESS_KEY = "network_address";
QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString();
emit possibleDomainChangeRequired(domainHostname);
// take the path that came back
const QString LOCATION_KEY = "location";
const QString LOCATION_PATH_KEY = "path";
QString returnedPath;
if (domainObject.contains(LOCATION_PATH_KEY)) {
returnedPath = domainObject[LOCATION_PATH_KEY].toString();
} else if (domainObject.contains(LOCATION_KEY)) {
returnedPath = domainObject[LOCATION_KEY].toObject()[LOCATION_PATH_KEY].toString();
}
if (!returnedPath.isEmpty()) {
// try to parse this returned path as a viewpoint, that's the only thing it could be for now
if (!handleRelativeViewpoint(returnedPath)) {
qDebug() << "Received a location path that was could not be handled as a viewpoint -" << returnedPath;
}
}
} else {
qDebug() << "Received an address manager API response with no domain key. Cannot parse.";
qDebug() << jsonObject;
}
} else {
// we've been told that this result exists but is offline, emit our signal so the application can handle
emit lookupResultIsOffline();
}
}
void AddressManager::handleAPIError(QNetworkReply& errorReply) {
qDebug() << "AddressManager API error -" << errorReply.error() << "-" << errorReply.errorString();
}
const QString GET_PLACE = "/api/v1/places/%1";
void AddressManager::attemptPlaceNameLookup(const QString& lookupString) {
// assume this is a place name and see if we can get any info on it
QString placeName = QUrl::toPercentEncoding(lookupString);
AccountManager::getInstance().authenticatedRequest(GET_PLACE.arg(placeName),
QNetworkAccessManager::GetOperation,
apiCallbackParameters());
}
bool AddressManager::handleNetworkAddress(const QString& lookupString) {
const QString IP_ADDRESS_REGEX_STRING = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}"
"([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(:\\d{1,5})?$";
const QString HOSTNAME_REGEX_STRING = "^((?:[A-Z0-9]|[A-Z0-9][A-Z0-9\\-]{0,61}[A-Z0-9])"
"(?:\\.(?:[A-Z0-9]|[A-Z0-9][A-Z0-9\\-]{0,61}[A-Z0-9]))+|localhost)(:{1}\\d{1,5})?$";
QRegExp hostnameRegex(HOSTNAME_REGEX_STRING, Qt::CaseInsensitive);
if (hostnameRegex.indexIn(lookupString) != -1) {
emit possibleDomainChangeRequired(hostnameRegex.cap(0));
return true;
}
QRegExp ipAddressRegex(IP_ADDRESS_REGEX_STRING);
if (ipAddressRegex.indexIn(lookupString) != -1) {
emit possibleDomainChangeRequired(ipAddressRegex.cap(0));
return true;
}
return false;
}
bool AddressManager::handleRelativeViewpoint(const QString& lookupString) {
const QString FLOAT_REGEX_STRING = "([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?)";
const QString TRIPLE_FLOAT_REGEX_STRING = QString("\\/") + FLOAT_REGEX_STRING + "\\s*,\\s*" +
FLOAT_REGEX_STRING + "\\s*,\\s*" + FLOAT_REGEX_STRING + "\\s*(?:$|\\/)";
QRegExp tripleFloatRegex(TRIPLE_FLOAT_REGEX_STRING);
if (tripleFloatRegex.indexIn(lookupString) != -1) {
// we have at least a position, so emit our signal to say we need to change position
glm::vec3 newPosition(tripleFloatRegex.cap(1).toFloat(),
tripleFloatRegex.cap(2).toFloat(),
tripleFloatRegex.cap(3).toFloat());
if (!isNaN(newPosition.x) && !isNaN(newPosition.y) && !isNaN(newPosition.z)) {
glm::vec3 newOrientation;
// we may also have an orientation
if (lookupString[tripleFloatRegex.matchedLength() - 1] == QChar('/')
&& tripleFloatRegex.indexIn(lookupString, tripleFloatRegex.matchedLength() - 1) != -1) {
glm::vec3 newOrientation(tripleFloatRegex.cap(1).toFloat(),
tripleFloatRegex.cap(2).toFloat(),
tripleFloatRegex.cap(3).toFloat());
if (!isNaN(newOrientation.x) && !isNaN(newOrientation.y) && !isNaN(newOrientation.z)) {
emit locationChangeRequired(newPosition, true, newOrientation);
return true;
} else {
qDebug() << "Orientation parsed from lookup string is invalid. Will not use for location change.";
}
}
emit locationChangeRequired(newPosition, false, newOrientation);
} else {
qDebug() << "Could not jump to position from lookup string because it has an invalid value.";
}
return true;
}
return false;
}
const QString GET_USER_LOCATION = "/api/v1/users/%1/location";
bool AddressManager::handleUsername(const QString& lookupString) {
const QString USERNAME_REGEX_STRING = "^@(\\S+)";
QRegExp usernameRegex(USERNAME_REGEX_STRING);
if (usernameRegex.indexIn(lookupString) != -1) {
goToUser(usernameRegex.cap(1));
return true;
}
return false;
}
void AddressManager::goToUser(const QString& username) {
QString formattedUsername = QUrl::toPercentEncoding(username);
// this is a username - pull the captured name and lookup that user's location
AccountManager::getInstance().authenticatedRequest(GET_USER_LOCATION.arg(formattedUsername),
QNetworkAccessManager::GetOperation,
apiCallbackParameters());
}

View file

@ -0,0 +1,53 @@
//
// AddressManager.h
// libraries/networking/src
//
// Created by Stephen Birarda on 2014-09-10.
// 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_AddressManager_h
#define hifi_AddressManager_h
#include <qobject.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "AccountManager.h"
static const QString HIFI_URL_SCHEME = "hifi";
class AddressManager : public QObject {
Q_OBJECT
public:
static AddressManager& getInstance();
static QString pathForPositionAndOrientation(const glm::vec3& position, bool hasOrientation = false,
const glm::quat& orientation = glm::quat());
void attemptPlaceNameLookup(const QString& lookupString);
public slots:
void handleLookupString(const QString& lookupString);
void handleAPIResponse(const QJsonObject& jsonObject);
void handleAPIError(QNetworkReply& errorReply);
void goToUser(const QString& username);
signals:
void lookupResultIsOffline();
void possibleDomainChangeRequired(const QString& newHostname);
void locationChangeRequired(const glm::vec3& newPosition, bool hasOrientationChange, const glm::vec3& newOrientation);
private:
const JSONCallbackParameters& apiCallbackParameters();
bool handleUrl(const QUrl& lookupUrl);
bool handleNetworkAddress(const QString& lookupString);
bool handleRelativeViewpoint(const QString& pathSubsection);
bool handleUsername(const QString& lookupString);
};
#endif // hifi_AddressManager_h

View file

@ -73,6 +73,22 @@ void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hos
_hostname = hostname;
}
void DomainHandler::setUUID(const QUuid& uuid) {
if (uuid != _uuid) {
_uuid = uuid;
qDebug() << "Domain uuid changed to" << uuidStringWithoutCurlyBraces(_uuid);
}
}
QString DomainHandler::hostnameWithoutPort(const QString& hostname) {
int colonIndex = hostname.indexOf(':');
return colonIndex > 0 ? hostname.left(colonIndex) : hostname;
}
bool DomainHandler::isCurrentHostname(const QString& hostname) {
return hostnameWithoutPort(hostname) == _hostname;
}
void DomainHandler::setHostname(const QString& hostname) {
if (hostname != _hostname) {

View file

@ -37,10 +37,11 @@ public:
void clearSettings();
const QUuid& getUUID() const { return _uuid; }
void setUUID(const QUuid& uuid) { _uuid = uuid; }
void setUUID(const QUuid& uuid);
static QString hostnameWithoutPort(const QString& hostname);
bool isCurrentHostname(const QString& hostname);
const QString& getHostname() const { return _hostname; }
void setHostname(const QString& hostname);
const QHostAddress& getIP() const { return _sockAddr.getAddress(); }
void setIPToLocalhost() { _sockAddr.setAddress(QHostAddress(QHostAddress::LocalHost)); }
@ -63,6 +64,8 @@ public:
void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket);
void softReset();
public slots:
void setHostname(const QString& hostname);
private slots:
void completedHostnameLookup(const QHostInfo& hostInfo);

View file

@ -397,7 +397,10 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
_numNoReplyDomainCheckIns = 0;
// if this was the first domain-server list from this domain, we've now connected
_domainHandler.setIsConnected(true);
if (!_domainHandler.isConnected()) {
_domainHandler.setUUID(uuidFromPacketHeader(packet));
_domainHandler.setIsConnected(true);
}
int readNodes = 0;

View file

@ -73,8 +73,8 @@ void UserActivityLogger::requestFinished(const QJsonObject& object) {
// qDebug() << object;
}
void UserActivityLogger::requestError(QNetworkReply::NetworkError error,const QString& string) {
qDebug() << error << ": " << string;
void UserActivityLogger::requestError(QNetworkReply& errorReply) {
qDebug() << errorReply.error() << "-" << errorReply.errorString();
}
void UserActivityLogger::launch(QString applicationVersion) {

View file

@ -40,7 +40,7 @@ public slots:
private slots:
void requestFinished(const QJsonObject& object);
void requestError(QNetworkReply::NetworkError error,const QString& string);
void requestError(QNetworkReply& errorReply);
private:
UserActivityLogger();