Add user locations

This commit is contained in:
Ryan Huffman 2014-06-26 16:06:28 -07:00
parent c46453c97f
commit cde36dc70d
5 changed files with 551 additions and 0 deletions

View file

@ -0,0 +1,229 @@
//
// 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 <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QMessageBox>
#include "AccountManager.h"
#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";
UserLocation::UserLocation(QString id, QString name, QString location) :
_id(id),
_name(name),
_location(location),
_previousName(name),
_updating(false) {
}
void UserLocation::requestRename(const QString& newName) {
_updating = true;
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "handleRenameResponse";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "handleRenameError";
QJsonObject jsonNameObject;
jsonNameObject.insert("name", QJsonValue(newName));
QJsonDocument jsonDocument(jsonNameObject);
AccountManager::getInstance().authenticatedRequest(PLACES_UPDATE.arg(_id),
QNetworkAccessManager::PutOperation,
callbackParams,
jsonDocument.toJson());
_previousName = _name;
_name = newName;
emit updated(_name);
}
void UserLocation::handleRenameResponse(const QJsonObject& responseData) {
_updating = false;
qDebug() << responseData;
QJsonValue status = responseData["status"];
if (status.isUndefined() || status.toString() != "success") {
_name = _previousName;
qDebug() << "There was an error renaming location '" + _name + "'";
}
emit updated(_name);
}
void UserLocation::handleRenameError(QNetworkReply::NetworkError error, const QString& errorString) {
_updating = false;
QString msg = "There was an error renaming location '" + _name + "': " + errorString;
qDebug() << msg;
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
emit updated(_name);
}
void UserLocation::requestDelete() {
_updating = true;
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "handleDeleteResponse";
callbackParams.errorCallbackReceiver = this;
callbackParams.errorCallbackMethod = "handleDeleteError";
AccountManager::getInstance().authenticatedRequest(PLACES_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 {
qDebug() << "There was an error deleting location '" + _name + "'";
}
}
void UserLocation::handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString) {
_updating = false;
QString msg = "There was an error deleting location '" + _name + "': " + errorString;
qDebug() << msg;
QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg);
}
UserLocationsModel::UserLocationsModel(QObject* parent) :
QAbstractListModel(parent),
_updating(false) {
refresh();
}
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();
_locations.clear();
_updating = true;
endResetModel();
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "handleLocationsResponse";
AccountManager::getInstance().authenticatedRequest(PLACES_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()["places"].toArray();
for (QJsonArray::const_iterator it = locations.constBegin(); it != locations.constEnd(); it++) {
QJsonObject location = (*it).toObject();
QJsonObject address = location["address"].toObject();
UserLocation* userLocation = new UserLocation(location["id"].toString(), location["name"].toString(),
"hifi://" + address["domain"].toString() + "/" + address["position"].toString() + "/" + address["orientation"].toString());
_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<UserLocation*>::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() == LocationColumn) {
return QVariant(_locations[index.row()]->location());
}
}
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 LocationColumn: return "Location";
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);
}

View file

@ -0,0 +1,81 @@
//
// 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 <QAbstractListModel>
#include <QModelIndex>
#include <QVariant>
class UserLocation : public QObject {
Q_OBJECT
public:
UserLocation(QString id, QString name, QString location);
bool isUpdating() { return _updating; }
void requestRename(const QString& newName);
void requestDelete();
QString id() { return _id; }
QString name() { return _name; }
QString location() { return _location; }
public slots:
void handleRenameResponse(const QJsonObject& responseData);
void handleRenameError(QNetworkReply::NetworkError error, const QString& errorString);
void handleDeleteResponse(const QJsonObject& responseData);
void handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString);
signals:
void updated(const QString& name);
void deleted(const QString& name);
private:
QString _id;
QString _name;
QString _location;
QString _previousName;
bool _updating;
};
class UserLocationsModel : public QAbstractListModel {
Q_OBJECT
public:
UserLocationsModel(QObject* parent = NULL);
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,
LocationColumn
};
public slots:
void refresh();
void update();
void handleLocationsResponse(const QJsonObject& responseData);
void removeLocation(const QString& name);
private:
bool _updating;
QList<UserLocation*> _locations;
};
#endif // hifi_UserLocationsModel_h

View file

@ -0,0 +1,76 @@
//
// UserLocationsWindow.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 <QDebug>
#include <QInputDialog>
#include <QPushButton>
#include "Menu.h"
#include "UserLocationsWindow.h"
UserLocationsWindow::UserLocationsWindow(QWidget* parent) :
QWidget(parent, Qt::Window),
_ui(),
_proxyModel(this),
_userLocationsModel(this) {
_ui.setupUi(this);
_proxyModel.setSourceModel(&_userLocationsModel);
_proxyModel.setDynamicSortFilter(true);
_ui.locationsTreeView->setModel(&_proxyModel);
_ui.locationsTreeView->setSortingEnabled(true);
connect(_ui.locationsTreeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &UserLocationsWindow::updateEnabled);
connect(&_userLocationsModel, &UserLocationsModel::modelReset, this, &UserLocationsWindow::updateEnabled);
connect(&_userLocationsModel, &UserLocationsModel::modelReset, &_proxyModel, &QSortFilterProxyModel::invalidate);
connect(_ui.locationsTreeView, &QTreeView::doubleClicked, this, &UserLocationsWindow::goToModelIndex);
connect(_ui.deleteButton, &QPushButton::clicked, this, &UserLocationsWindow::deleteSelection);
connect(_ui.renameButton, &QPushButton::clicked, this, &UserLocationsWindow::renameSelection);
connect(_ui.refreshButton, &QPushButton::clicked, &_userLocationsModel, &UserLocationsModel::refresh);
this->setWindowTitle("My Locations");
}
void UserLocationsWindow::updateEnabled() {
bool enabled = _ui.locationsTreeView->selectionModel()->hasSelection();
_ui.renameButton->setEnabled(enabled);
_ui.deleteButton->setEnabled(enabled);
}
void UserLocationsWindow::goToModelIndex(const QModelIndex& index) {
QVariant location = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::LocationColumn));
Menu::getInstance()->goToURL(location.toString());
}
void UserLocationsWindow::deleteSelection() {
QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex();
selection = _proxyModel.mapToSource(selection);
if (selection.isValid()) {
_userLocationsModel.deleteLocation(selection);
}
}
void UserLocationsWindow::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);
}
}
}

View file

@ -0,0 +1,35 @@
//
// UserLocationsWindow.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_UserLocationsWindow_h
#define hifi_UserLocationsWindow_h
#include "ui_userLocationsWindow.h"
#include "UserLocationsModel.h"
class UserLocationsWindow : public QWidget {
Q_OBJECT
public:
UserLocationsWindow(QWidget* parent = NULL);
protected slots:
void updateEnabled();
void goToModelIndex(const QModelIndex& index);
void deleteSelection();
void renameSelection();
private:
Ui::UserLocationsWindow _ui;
QSortFilterProxyModel _proxyModel;
UserLocationsModel _userLocationsModel;
};
#endif // hifi_UserLocationsWindow_h

View file

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserLocationsWindow</class>
<widget class="QWidget" name="UserLocationsWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>929</width>
<height>633</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>-1</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="styleSheet">
<string notr="true">font-size: 16px</string>
</property>
<property name="text">
<string>My Locations</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="refreshButton">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTreeView" name="locationsTreeView">
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>-1</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="renameButton">
<property name="text">
<string>Rename</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>