Allow drag-and-drop of snapshots into Interface

This commit is contained in:
stojce 2014-02-12 02:12:52 +01:00
parent 803d0fd7c7
commit 68584c654b
9 changed files with 190 additions and 73 deletions

View file

@ -48,6 +48,8 @@
#include <QXmlStreamReader>
#include <QXmlStreamAttributes>
#include <QMediaPlayer>
#include <QMimeData>
#include <QMessageBox>
#include <AudioInjector.h>
#include <Logging.h>
@ -197,7 +199,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
connect(audioThread, SIGNAL(started()), &_audio, SLOT(start()));
audioThread->start();
connect(nodeList, SIGNAL(domainChanged(const QString&)), SLOT(domainChanged(const QString&)));
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
@ -1378,6 +1380,32 @@ void Application::wheelEvent(QWheelEvent* event) {
}
}
void Application::dropEvent(QDropEvent *event) {
QString snapshotPath;
const QMimeData *mimeData = event->mimeData();
foreach (QUrl url, mimeData->urls()) {
if (url.url().toLower().endsWith("jpg")) {
snapshotPath = url.url().remove("file://");
break;
}
}
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
if (snapshotData != NULL) {
if (!snapshotData->getDomain().isEmpty()) {
Menu::getInstance()->goToDomain(snapshotData->getDomain());
}
_myAvatar->setPosition(snapshotData->getLocation());
_myAvatar->setOrientation(snapshotData->getOrientation());
} else {
QMessageBox msgBox;
msgBox.setText("No location details were found in this JPG, try dragging in an authentic Hifi snapshot.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
}
}
void Application::sendPingPackets() {
QByteArray pingPacket = NodeList::getInstance()->constructPingPacket();
controlledBroadcastToNodes(pingPacket, NodeSet() << NodeType::VoxelServer
@ -3794,7 +3822,7 @@ void Application::updateWindowTitle(){
QString title = QString() + _profile.getUsername() + " " + nodeList->getSessionUUID().toString()
+ " @ " + nodeList->getDomainHostname() + buildVersion;
qDebug("Application title set to: %s", title.toStdString().c_str());
_window->setWindowTitle(title);
}
@ -4170,6 +4198,6 @@ void Application::takeSnapshot() {
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
player->play();
Snapshot::saveSnapshot(_glWidget, _profile.getUsername(), _myAvatar->getPosition());
Snapshot::saveSnapshot(_glWidget, &_profile, _myAvatar);
}

View file

@ -127,7 +127,8 @@ public:
void touchUpdateEvent(QTouchEvent* event);
void wheelEvent(QWheelEvent* event);
void dropEvent(QDropEvent *event);
void makeVoxel(glm::vec3 position,
float scale,
unsigned char red,

View file

@ -9,6 +9,8 @@
#include "Application.h"
#include "GLCanvas.h"
#include <QMimeData>
#include <QUrl>
GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)) {
}
@ -16,6 +18,7 @@ GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuf
void GLCanvas::initializeGL() {
Application::getInstance()->initializeGL();
setAttribute(Qt::WA_AcceptTouchEvents);
setAcceptDrops(true);
}
void GLCanvas::paintGL() {
@ -67,4 +70,18 @@ bool GLCanvas::event(QEvent* event) {
void GLCanvas::wheelEvent(QWheelEvent* event) {
Application::getInstance()->wheelEvent(event);
}
}
void GLCanvas::dragEnterEvent(QDragEnterEvent* event) {
const QMimeData *mimeData = event->mimeData();
foreach (QUrl url, mimeData->urls()) {
if (url.url().toLower().endsWith("jpg")) {
event->acceptProposedAction();
break;
}
}
}
void GLCanvas::dropEvent(QDropEvent* event) {
Application::getInstance()->dropEvent(event);
}

View file

@ -31,6 +31,9 @@ protected:
virtual bool event(QEvent* event);
virtual void wheelEvent(QWheelEvent* event);
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent* event);
};
#endif /* defined(__hifi__GLCanvas__) */

View file

@ -109,7 +109,7 @@ Menu::Menu() :
MenuOption::GoToDomain,
Qt::CTRL | Qt::Key_D,
this,
SLOT(goToDomain()));
SLOT(goToDomainDialog()));
addActionToQMenuAndActionHash(fileMenu,
MenuOption::GoToLocation,
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
@ -889,7 +889,18 @@ void Menu::editPreferences() {
sendFakeEnterEvent();
}
void Menu::goToDomain() {
void Menu::goToDomain(const QString newDomain) {
if (NodeList::getInstance()->getDomainHostname() != newDomain) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
Application::getInstance()->getAvatar()->sendKillAvatar();
// give our nodeList the new domain-server hostname
NodeList::getInstance()->setDomainHostname(newDomain);
}
}
void Menu::goToDomainDialog() {
QString currentDomainHostname = NodeList::getInstance()->getDomainHostname();
@ -913,17 +924,46 @@ void Menu::goToDomain() {
// the user input a new hostname, use that
newHostname = domainDialog.textValue();
}
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
Application::getInstance()->getAvatar()->sendKillAvatar();
// give our nodeList the new domain-server hostname
NodeList::getInstance()->setDomainHostname(domainDialog.textValue());
goToDomain(newHostname);
}
sendFakeEnterEvent();
}
bool Menu::goToDestination(QString destination) {
QStringList coordinateItems = destination.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) {
double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble();
double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble();
double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).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->setPosition(newAvatarPos);
}
return true;
}
// no coordinates were parsed
return false;
}
void Menu::goTo() {
QInputDialog gotoDialog(Application::getInstance()->getWindow());
@ -939,31 +979,8 @@ void Menu::goTo() {
destination = gotoDialog.textValue();
QStringList coordinateItems = destination.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) {
double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble();
double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble();
double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).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->setPosition(newAvatarPos);
}
} else {
// go to coordinate destination or to Username
if (!goToDestination(destination)) {
// there's a username entered by the user, make a request to the data-server
DataServerClient::getValuesForKeysAndUserString(
QStringList()
@ -994,29 +1011,7 @@ void Menu::goToLocation() {
int dialogReturn = coordinateDialog.exec();
if (dialogReturn == QDialog::Accepted && !coordinateDialog.textValue().isEmpty()) {
QByteArray newCoordinates;
QString delimiterPattern(",");
QStringList coordinateItems = coordinateDialog.textValue().split(delimiterPattern);
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) {
double x = coordinateItems[X_ITEM].toDouble();
double y = coordinateItems[Y_ITEM].toDouble();
double z = coordinateItems[Z_ITEM].toDouble();
glm::vec3 newAvatarPos(x, y, z);
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->setPosition(newAvatarPos);
}
}
goToDestination(coordinateDialog.textValue());
}
sendFakeEnterEvent();

View file

@ -84,6 +84,8 @@ public:
const char* member = NULL,
QAction::MenuRole role = QAction::NoRole);
virtual void removeAction(QMenu* menu, const QString& actionName);
bool goToDestination(QString destination);
void goToDomain(const QString newDomain);
public slots:
void bandwidthDetails();
@ -100,7 +102,7 @@ private slots:
void aboutApp();
void login();
void editPreferences();
void goToDomain();
void goToDomainDialog();
void goToLocation();
void bandwidthDetailsClosed();
void voxelStatsDetailsClosed();

View file

@ -14,6 +14,8 @@
#include <QFileInfo>
#include <QDebug>
#include <glm/glm.hpp>
// filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg
// %1 <= username, %2 <= date and time, %3 <= current location
const QString FILENAME_PATH_FORMAT = "hifi-snap-by-%1-on-%2@%3.jpg";
@ -21,18 +23,69 @@ const QString FILENAME_PATH_FORMAT = "hifi-snap-by-%1-on-%2@%3.jpg";
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss";
const QString SNAPSHOTS_DIRECTORY = "Snapshots";
void Snapshot::saveSnapshot(QGLWidget* widget, QString username, glm::vec3 location) {
QImage shot = widget->grabFrameBuffer();
const QString LOCATION_X = "location-x";
const QString LOCATION_Y = "location-y";
const QString LOCATION_Z = "location-z";
const QString ORIENTATION_X = "orientation-x";
const QString ORIENTATION_Y = "orientation-y";
const QString ORIENTATION_Z = "orientation-z";
const QString ORIENTATION_W = "orientation-w";
const QString DOMAIN_KEY = "domain";
SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) {
if (!QFile(snapshotPath).exists()) {
return NULL;
}
QImage shot(snapshotPath);
// no location data stored
if (shot.text(LOCATION_X).isEmpty() || shot.text(LOCATION_Y).isEmpty() || shot.text(LOCATION_Z).isEmpty()) {
return NULL;
}
SnapshotMetaData* data = new SnapshotMetaData();
data->setLocation(glm::vec3(shot.text(LOCATION_X).toFloat(),
shot.text(LOCATION_Y).toFloat(),
shot.text(LOCATION_Z).toFloat()));
data->setOrientation(glm::quat(shot.text(ORIENTATION_X).toFloat(),
shot.text(ORIENTATION_Y).toFloat(),
shot.text(ORIENTATION_Z).toFloat(),
shot.text(ORIENTATION_W).toFloat()));
data->setDomain(shot.text(DOMAIN_KEY));
return data;
}
void Snapshot::saveSnapshot(QGLWidget* widget, Profile* profile, MyAvatar* avatar) {
QImage shot = widget->grabFrameBuffer();
glm::vec3 location = avatar->getPosition();
glm::quat orientation = avatar->getHead().getOrientation();
// add metadata
shot.setText("location-x", QString::number(location.x));
shot.setText("location-y", QString::number(location.y));
shot.setText("location-z", QString::number(location.z));
shot.setText(LOCATION_X, QString::number(location.x));
shot.setText(LOCATION_Y, QString::number(location.y));
shot.setText(LOCATION_Z, QString::number(location.z));
shot.setText(ORIENTATION_X, QString::number(orientation.x));
shot.setText(ORIENTATION_Y, QString::number(orientation.y));
shot.setText(ORIENTATION_Z, QString::number(orientation.z));
shot.setText(ORIENTATION_W, QString::number(orientation.w));
shot.setText(DOMAIN_KEY, profile->getLastDomain());
QString formattedLocation = QString("%1_%2_%3").arg(location.x).arg(location.y).arg(location.z);
// replace decimal . with '-'
formattedLocation.replace('.', '-');
QString username = profile->getUsername();
// normalize username, replace all non alphanumeric with '-'
username.replace(QRegExp("[^A-Za-z0-9_]"), "-");

View file

@ -13,15 +13,32 @@
#include <QImage>
#include <QGLWidget>
#include <glm/glm.hpp>
#include "avatar/MyAvatar.h"
#include "avatar/Profile.h"
class SnapshotMetaData {
public:
QString getDomain() { return _domain; }
void setDomain(QString domain) { _domain = domain; }
glm::vec3 getLocation() { return _location; }
void setLocation(glm::vec3 location) { _location = location; }
glm::quat getOrientation() { return _orientation; }
void setOrientation(glm::quat orientation) { _orientation = orientation; }
private:
QString _domain;
glm::vec3 _location;
glm::quat _orientation;;
};
class Snapshot {
public:
static void saveSnapshot(QGLWidget* widget, QString username, glm::vec3 location);
private:
QString _username;
static void saveSnapshot(QGLWidget* widget, Profile* profile, MyAvatar* avatar);
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
};
#endif /* defined(__hifi__Snapshot__) */

View file

@ -807,7 +807,8 @@ void NodeList::loadData(QSettings *settings) {
} else {
_domainHostname = DEFAULT_DOMAIN_HOSTNAME;
}
emit domainChanged(_domainHostname);
settings->endGroup();
}