mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
Merge pull request #3439 from birarda/master
upload a snapshot for location on location creation, cleanup interface start errors
This commit is contained in:
commit
fd321a5ed1
8 changed files with 151 additions and 26 deletions
|
@ -288,6 +288,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// set the account manager's root URL and trigger a login request if we don't have the access token
|
||||
accountManager.setAuthURL(DEFAULT_NODE_AUTH_URL);
|
||||
UserActivityLogger::getInstance().launch(applicationVersion());
|
||||
|
||||
// grab the location manager instance early so it lives in our thread
|
||||
LocationManager::getInstance();
|
||||
|
||||
// once the event loop has started, check and signal for an access token
|
||||
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
|
||||
|
@ -927,6 +930,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
|
||||
break;
|
||||
|
||||
case Qt::Key_N:
|
||||
if (isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::NameLocation);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
|
|
|
@ -328,9 +328,9 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersVoxelNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
|
||||
&nodeBounds, SLOT(setShowVoxelNodes(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersModelNodes,
|
||||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_2, false,
|
||||
&nodeBounds, SLOT(setShowModelNodes(bool)));
|
||||
&nodeBounds, SLOT(setShowEntityNodes(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersParticleNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_3, false,
|
||||
&nodeBounds, SLOT(setShowParticleNodes(bool)));
|
||||
|
|
|
@ -439,7 +439,7 @@ namespace MenuOption {
|
|||
const QString ScriptEditor = "Script Editor...";
|
||||
const QString SettingsExport = "Export Settings";
|
||||
const QString SettingsImport = "Import Settings";
|
||||
const QString ShowBordersModelNodes = "Show Model Nodes";
|
||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||
const QString ShowBordersParticleNodes = "Show Particle Nodes";
|
||||
const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
|
||||
const QString ShowIKConstraints = "Show IK Constraints";
|
||||
|
|
|
@ -42,17 +42,15 @@ ScriptsModel::ScriptsModel(QObject* parent) :
|
|||
_localDirectory(),
|
||||
_fsWatcher(),
|
||||
_localFiles(),
|
||||
_remoteFiles() {
|
||||
|
||||
QString scriptPath = Menu::getInstance()->getScriptsLocation();
|
||||
|
||||
_localDirectory.setPath(scriptPath);
|
||||
_remoteFiles()
|
||||
{
|
||||
|
||||
_localDirectory.setFilter(QDir::Files | QDir::Readable);
|
||||
_localDirectory.setNameFilters(QStringList("*.js"));
|
||||
|
||||
_fsWatcher.addPath(_localDirectory.absolutePath());
|
||||
updateScriptsLocation(Menu::getInstance()->getScriptsLocation());
|
||||
|
||||
connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles);
|
||||
|
||||
connect(Menu::getInstance(), &Menu::scriptLocationChanged, this, &ScriptsModel::updateScriptsLocation);
|
||||
|
||||
reloadLocalFiles();
|
||||
|
@ -88,8 +86,13 @@ int ScriptsModel::rowCount(const QModelIndex& parent) const {
|
|||
|
||||
void ScriptsModel::updateScriptsLocation(const QString& newPath) {
|
||||
_fsWatcher.removePath(_localDirectory.absolutePath());
|
||||
|
||||
_localDirectory.setPath(newPath);
|
||||
_fsWatcher.addPath(_localDirectory.absolutePath());
|
||||
|
||||
if (!_localDirectory.absolutePath().isEmpty()) {
|
||||
_fsWatcher.addPath(_localDirectory.absolutePath());
|
||||
}
|
||||
|
||||
reloadLocalFiles();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <qhttpmultipart.h>
|
||||
#include <qjsonobject.h>
|
||||
|
||||
#include <AccountManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/Snapshot.h"
|
||||
|
||||
#include "LocationManager.h"
|
||||
|
||||
const QString POST_LOCATION_CREATE = "/api/v1/locations/";
|
||||
|
@ -24,13 +28,17 @@ LocationManager& LocationManager::getInstance() {
|
|||
|
||||
const QString UNKNOWN_ERROR_MESSAGE = "Unknown error creating named location. Please try again!";
|
||||
|
||||
void LocationManager::namedLocationDataReceived(const QJsonObject& data) {
|
||||
if (data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const QString LOCATION_OBJECT_KEY = "location";
|
||||
const QString LOCATION_ID_KEY = "id";
|
||||
|
||||
if (data.contains("status") && data["status"].toString() == "success") {
|
||||
void LocationManager::namedLocationDataReceived(const QJsonObject& rootObject) {
|
||||
|
||||
if (rootObject.contains("status") && rootObject["status"].toString() == "success") {
|
||||
emit creationCompleted(QString());
|
||||
|
||||
// successfuly created a location - grab the ID from the response and create a snapshot to upload
|
||||
QString locationIDString = rootObject[LOCATION_OBJECT_KEY].toObject()[LOCATION_ID_KEY].toString();
|
||||
updateSnapshotForExistingLocation(locationIDString);
|
||||
} else {
|
||||
emit creationCompleted(UNKNOWN_ERROR_MESSAGE);
|
||||
}
|
||||
|
@ -87,3 +95,57 @@ void LocationManager::errorDataReceived(QNetworkReply& errorReply) {
|
|||
creationCompleted(UNKNOWN_ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
void LocationManager::locationImageUpdateSuccess(const QJsonObject& rootObject) {
|
||||
qDebug() << "Successfuly updated a location image.";
|
||||
}
|
||||
|
||||
void LocationManager::updateSnapshotForExistingLocation(const QString& locationID) {
|
||||
// first create a snapshot and save it
|
||||
Application* application = Application::getInstance();
|
||||
|
||||
QTemporaryFile* tempImageFile = Snapshot::saveTempSnapshot(application->getGLWidget(), application->getAvatar());
|
||||
|
||||
if (tempImageFile && tempImageFile->open()) {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
|
||||
// setup a multipart that is in the AccountManager thread - we need this so it can be cleaned up after the QNetworkReply
|
||||
QHttpMultiPart* imageFileMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
imageFileMultiPart->moveToThread(accountManager.thread());
|
||||
|
||||
// parent the temp file to the QHttpMultipart after moving it to account manager thread
|
||||
tempImageFile->moveToThread(accountManager.thread());
|
||||
tempImageFile->setParent(imageFileMultiPart);
|
||||
|
||||
qDebug() << "Uploading a snapshot from" << QFileInfo(*tempImageFile).absoluteFilePath()
|
||||
<< "as location image for" << locationID;
|
||||
|
||||
const QString LOCATION_IMAGE_NAME = "location[image]";
|
||||
|
||||
QHttpPart imagePart;
|
||||
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"" + LOCATION_IMAGE_NAME + "\";"
|
||||
" filename=\"" + QFileInfo(tempImageFile->fileName()).fileName().toUtf8() + "\""));
|
||||
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||
imagePart.setBodyDevice(tempImageFile);
|
||||
|
||||
imageFileMultiPart->append(imagePart);
|
||||
|
||||
const QString LOCATION_IMAGE_PUT_PATH = "api/v1/locations/%1/image";
|
||||
|
||||
JSONCallbackParameters imageCallbackParams;
|
||||
imageCallbackParams.jsonCallbackReceiver = this;
|
||||
imageCallbackParams.jsonCallbackMethod = "locationImageUpdateSuccess";
|
||||
|
||||
// make an authenticated request via account manager to upload the image
|
||||
// don't do anything with error or success for now
|
||||
AccountManager::getInstance().authenticatedRequest(LOCATION_IMAGE_PUT_PATH.arg(locationID),
|
||||
QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QByteArray(), imageFileMultiPart);
|
||||
} else {
|
||||
qDebug() << "Couldn't open snapshot file to upload as location image. No location image will be stored.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,8 +35,12 @@ signals:
|
|||
void creationCompleted(const QString& errorMessage);
|
||||
|
||||
private slots:
|
||||
void namedLocationDataReceived(const QJsonObject& data);
|
||||
void namedLocationDataReceived(const QJsonObject& jsonObject);
|
||||
void errorDataReceived(QNetworkReply& errorReply);
|
||||
void locationImageUpdateSuccess(const QJsonObject& jsonObject);
|
||||
|
||||
private:
|
||||
void updateSnapshotForExistingLocation(const QString& locationID);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -65,6 +65,24 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
|
|||
}
|
||||
|
||||
QString Snapshot::saveSnapshot(QGLWidget* widget, Avatar* avatar) {
|
||||
QFile* snapshotFile = savedFileForSnapshot(widget, avatar, false);
|
||||
|
||||
// we don't need the snapshot file, so close it, grab its filename and delete it
|
||||
snapshotFile->close();
|
||||
|
||||
QString snapshotPath = QFileInfo(*snapshotFile).absoluteFilePath();
|
||||
|
||||
delete snapshotFile;
|
||||
|
||||
return snapshotPath;
|
||||
}
|
||||
|
||||
QTemporaryFile* Snapshot::saveTempSnapshot(QGLWidget* widget, Avatar* avatar) {
|
||||
// return whatever we get back from saved file for snapshot
|
||||
return static_cast<QTemporaryFile*>(savedFileForSnapshot(widget, avatar, true));;
|
||||
}
|
||||
|
||||
QFile* Snapshot::savedFileForSnapshot(QGLWidget* widget, Avatar* avatar, bool isTemporary) {
|
||||
QImage shot = widget->grabFrameBuffer();
|
||||
|
||||
glm::vec3 location = avatar->getPosition();
|
||||
|
@ -91,16 +109,40 @@ QString Snapshot::saveSnapshot(QGLWidget* widget, Avatar* avatar) {
|
|||
username.replace(QRegExp("[^A-Za-z0-9_]"), "-");
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QString fileName = Menu::getInstance()->getSnapshotsLocation();
|
||||
|
||||
if (!fileName.endsWith(QDir::separator())) {
|
||||
fileName.append(QDir::separator());
|
||||
}
|
||||
|
||||
fileName.append(QString(FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT), formattedLocation)));
|
||||
shot.save(fileName, 0, 100);
|
||||
|
||||
return fileName;
|
||||
QString filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT), formattedLocation);
|
||||
|
||||
const int IMAGE_QUALITY = 100;
|
||||
|
||||
if (!isTemporary) {
|
||||
QString snapshotFullPath = Menu::getInstance()->getSnapshotsLocation();
|
||||
|
||||
if (!snapshotFullPath.endsWith(QDir::separator())) {
|
||||
snapshotFullPath.append(QDir::separator());
|
||||
}
|
||||
|
||||
snapshotFullPath.append(filename);
|
||||
|
||||
QFile* imageFile = new QFile(snapshotFullPath);
|
||||
imageFile->open(QIODevice::WriteOnly);
|
||||
|
||||
shot.save(imageFile, 0, IMAGE_QUALITY);
|
||||
imageFile->close();
|
||||
|
||||
return imageFile;
|
||||
} else {
|
||||
QTemporaryFile* imageTempFile = new QTemporaryFile(QDir::tempPath() + "/XXXXXX-" + filename);
|
||||
|
||||
if (!imageTempFile->open()) {
|
||||
qDebug() << "Unable to open QTemporaryFile for temp snapshot. Will not save.";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shot.save(imageTempFile, 0, IMAGE_QUALITY);
|
||||
imageTempFile->close();
|
||||
|
||||
return imageTempFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,7 +42,11 @@ class Snapshot {
|
|||
|
||||
public:
|
||||
static QString saveSnapshot(QGLWidget* widget, Avatar* avatar);
|
||||
static QTemporaryFile* saveTempSnapshot(QGLWidget* widget, Avatar* avatar);
|
||||
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
|
||||
|
||||
private:
|
||||
static QFile* savedFileForSnapshot(QGLWidget* widget, Avatar* avatar, bool isTemporary);
|
||||
};
|
||||
|
||||
#endif // hifi_Snapshot_h
|
||||
|
|
Loading…
Reference in a new issue