Actions are posted to the server with correct UserID.
Enabled actions are currently limited to MouseMove and DrawLine.
#include "action.h"
+#include <QDataStream>
+#include <QByteArray>
+#include <QBuffer>
+#include "base64.h"
Action::Action() {
type = INVALID;
mesgID = 0;
userID = 0;
+ timestamp = QDateTime::currentDateTime();
}
Action::Action(Type t) {
type = t;
mesgID = 0;
userID = 0;
+ timestamp = QDateTime::currentDateTime();
}
Action::~Action() {
QTextStream& operator<<(QTextStream& out, const Action& action) {
out << "0 " << action.userID << " " << action.timestamp.toString("yyyy-MM-ddThh:mm:ss.zzz") << " " << static_cast<quint16>(action.type) ; // mesgID, userID, timestamp, mesgType
switch(action.type) {
- case Action::INVALID: break;
+ case Action::INVALID:
+ case Action::UserSynced:
+ break;
case Action::UserJoin:
{
const UserJoinAction* a = static_cast<const UserJoinAction*>(&action);
case Action::AddImage:
{
const AddImageAction* a = static_cast<const AddImageAction*>(&action);
- // TODO: unbackburner this
- //out << " " << a->topLeft << a->image;
+ out << " " << a->topLeft.x() << " " << a->topLeft.y();
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ a->image.save(&buffer, "PNG");
+ buffer.close();
+ out << toBase64(ba);
} break;
case Action::UserChat:
{
MouseMove=3,
DrawLine=4,
AddImage=5,
- UserChat=6
+ UserChat=6,
+ UserSynced=7
};
Action();
#include <QTcpSocket>
#include <QTextStream>
#include "action.h"
+#include "base64.h"
+#include "shareboard.h"
ConnectionManager::ConnectionManager(QObject* parent) : QObject(parent) {
sock = new QTcpSocket();
if (sock) delete sock;
}
+void ConnectionManager::setTarget(Shareboard* t) {
+ board = t;
+}
+
void ConnectionManager::joinServer(QString _username, QString host) {
username = _username;
quint16 port = 4260;
QByteArray output;
QTextStream t(&output);
t << (*action);
+ t.flush();
qDebug() << "Sending" << output.size() << "bytes for action of type" << action->type;
sock->write(output);
}
QString im;
textstream >> im;
// im is a base64-encoded binary string.
-
-
-
+ QByteArray ba = fromBase64(im); // Convert back to binary data
+ action->image.loadFromData(ba, "PNG");
action->mesgID = mesgID;
action->userID = userID;
action->timestamp = timestamp;
action->text = chat;
break;
}
+ case Action::UserSynced:
+ {
+ board->setUserID(userID);
+ qDebug() << "User is synced :)";
+ continue;
+ }
+ break;
default:
qWarning() << "Received invalid type from server :(";
continue;
}
Q_ASSERT(act != NULL);
- // HistoryManager::instance()->newAction(action);
+ board->postAction(act);
qDebug() << "Dispatched action with type " << act->type << " that was " << data.size() << " bytes long";
}
class Action;
class QTcpSocket;
+class Shareboard;
class ConnectionManager : public QObject{
Q_OBJECT
void disconnected();
void error(QString e);
public slots:
+ void setTarget(Shareboard* t);
void joinServer(QString _username, QString host);
void sendAction(Action* action);
void onError();
//QByteArray data;
QTcpSocket* sock;
QTextStream* textStream;
+ Shareboard* board;
private slots:
void haveData();
void onConnect();
#include "connectionmanager.h"
#include "shareboard.h"
+#include "action.h"
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
createActions();
createMenus();
- connMan = new ConnectionManager(this);
-
board = new Shareboard(this);
setCentralWidget(board);
+ connMan = new ConnectionManager(this);
+ connMan->setTarget(board);
+
// Connect all actions
QObject::connect(board, SIGNAL(connectToServer(QString, QString)), connMan, SLOT(joinServer(QString, QString)));
QObject::connect(connMan, SIGNAL(connected()), this, SLOT(switchToBoard()));
QObject::connect(connMan, SIGNAL(disconnected()), this, SLOT(switchToConnect()));
QObject::connect(connMan, SIGNAL(error(QString)), this, SLOT(showError(QString)));
+ QObject::connect(board, SIGNAL(actionHappened(Action*)), this, SLOT(marshallAction(Action*)));
statusBar()->showMessage("Ready");
}
}
void MainWindow::switchToBoard() {
- // Here, we set the central widget to be the as-of-yet unimplemented Shareboard widget
board->switchToBoard();
statusBar()->showMessage(QString("Switched to Shareboard drawing surface"));
}
statusBar()->showMessage(error);
}
+void MainWindow::marshallAction(Action* action) {
+ switch(action->type) {
+ case Action::DrawLine: // set the action's thickness, color
+ {
+ DrawLineAction* a = static_cast<DrawLineAction*>(action);
+ a->color == Qt::blue;
+ a->width = 3;
+ }
+ break;
+ default: break;
+ }
+ board->postLocalAction(action);
+ connMan->sendAction(action);
+}
+
void MainWindow::createActions() {
- //joinAction = new QAction("Joi&n a board online", this);
loadPastAction = new QAction("&Open a board", this);
saveAction = new QAction("&Save board", this);
quitAction = new QAction("&Quit", this);
void MainWindow::createMenus() {
fileMenu = menuBar()->addMenu("&File");
- //fileMenu->addAction(joinAction);
fileMenu->addAction(loadPastAction);
fileMenu->addAction(saveAction);
fileMenu->addSeparator();
class ConnectWidget;
class ConnectionManager;
class Shareboard;
+class Action;
class MainWindow : public QMainWindow {
Q_OBJECT
void switchToBoard();
void switchToConnect();
void showError(QString error);
+ void marshallAction(Action* action);
private:
void createActions();
void createMenus();
#include "shareboardcanvas.h"
#include "connectwidget.h"
+#include "action.h"
+#include <QDebug>
Shareboard::Shareboard(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout(this);
setMinimumSize(640,480);
QObject::connect(prompt, SIGNAL(connectToServer(QString, QString)), this, SIGNAL(connectToServer(QString, QString)));
+ QObject::connect(canvas, SIGNAL(mouseMovedTo(QPointF)), this, SLOT(handleMouseMoved(QPointF)));
+ QObject::connect(canvas, SIGNAL(segmentDrawn(QPointF,QPointF)), this, SLOT(handleSegmentDrawn(QPointF,QPointF)));
}
Shareboard::~Shareboard() {
+ for(int i = 0; i < history.size(); i++)
+ delete history[i];
+ for(int i = 0; i < localHistory.size(); i++)
+ delete localHistory[i];
+}
+
+void Shareboard::handleMouseMoved(QPointF pos) {
+ MouseMoveAction* action = new MouseMoveAction();
+ action->userID = userID;
+ action->pos = pos;
+ localHistory.append(action);
+ emit actionHappened(action);
+ qDebug() << "shareboard.cpp: mouse moved to" << pos;
+}
+
+void Shareboard::handleSegmentDrawn(QPointF start, QPointF end) {
+ // Add segment to localHistory, dispatch to connMan
+ DrawLineAction* action = new DrawLineAction();
+ action->userID = userID;
+ action->points.append(start);
+ action->points.append(end);
+ emit actionHappened(action);
+ qDebug() << "shareboard.cpp: segment drawn from" << start << "to" << end;
+}
+void Shareboard::postAction(Action* action) {
+ if(action->userID == userID) {
+ delete localHistory[0];
+ localHistory.removeFirst();
+ }
+ history.append(action);
+}
+
+void Shareboard::postLocalAction(Action* action) {
+ localHistory.append(action);
}
void Shareboard::switchToBoard() {
void Shareboard::switchToPrompt() {
layout->setCurrentWidget(prompt);
}
+
+void Shareboard::setUserID(int id) {
+ userID = id;
+}
#define __SHAREBOARD_H__
#include <QWidget>
+#include <QPointF>
class QStackedLayout;
class ConnectWidget;
class ShareboardCanvas;
+class Action;
+typedef QList<Action*> History;
+
class Shareboard : public QWidget {
Q_OBJECT
public:
~Shareboard();
public slots:
+ void handleMouseMoved(QPointF pos);
+ void handleSegmentDrawn(QPointF start, QPointF end);
+ void postAction(Action* action);
+ void postLocalAction(Action* action);
void switchToBoard();
void switchToPrompt();
+ void setUserID(int id);
signals:
void connectToServer(QString, QString);
+ void actionHappened(Action* action);
private:
QStackedLayout* layout;
ConnectWidget* prompt;
ShareboardCanvas* canvas;
+ History history;
+ History localHistory;
+ int userID;
};
#endif // __SHAREBOARD_H__
INCLUDEPATH += .
# Input
-HEADERS += mainwindow.h action.h connectwidget.h connectionmanager.h shareboard.h shareboardcanvas.h base64.h
-SOURCES += main.cpp mainwindow.cpp action.cpp connectwidget.cpp connectionmanager.cpp shareboard.cpp shareboardcanvas.cpp base64.cpp
+HEADERS += \
+ action.h \
+ base64.h \
+ connectionmanager.h \
+ connectwidget.h \
+ mainwindow.h \
+ shareboardcanvas.h \
+ shareboard.h
+
+SOURCES += main.cpp \
+ action.cpp \
+ base64.cpp \
+ connectionmanager.cpp \
+ connectwidget.cpp \
+ mainwindow.cpp \
+ shareboardcanvas.cpp \
+ shareboard.cpp
void ShareboardCanvas::mouseMoveEvent(QMouseEvent* event) {
// Send mouse move event to network thread
+ emit mouseMovedTo(event->posF());
// If the button is down
- if(mouseDown)
+ if(mouseDown) {
+ emit segmentDrawn(dragPath.last(), event->posF());
dragPath.append(event->posF());
+ }
// Trigger a repaint
update();
}
void ShareboardCanvas::mousePressEvent(QMouseEvent* event) {
- mouseDown = true;
- dragPath.append(event->posF()); // We're starting a new drag path
+ if(event->button() & Qt::LeftButton) {
+ mouseDown = true;
+ dragPath.append(event->posF()); // We're starting a new drag path
+ }
//
}
void ShareboardCanvas::mouseReleaseEvent(QMouseEvent* event) {
- mouseDown = false;
- qDebug() << dragPath.size() << "mouse move events counted this drag";
- // Depending on the tool, we now dispatch different types of events
- dragPath.clear(); // Clear the path; we're no longer tracking a drag
+ if(event->button() & Qt::LeftButton) {
+ mouseDown = false;
+ qDebug() << dragPath.size() << "mouse move events counted this drag";
+ // Depending on the tool, we now dispatch different types of events
+ dragPath.clear(); // Clear the path; we're no longer tracking a drag
+ }
}
void ShareboardCanvas::paintEvent(QPaintEvent* event) {
+ Q_UNUSED(event)
QPainter p(this);
// Paint the background from the saved state
p.drawPixmap(0, 0, *currentScene);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void paintEvent(QPaintEvent* event);
+signals:
+ void mouseMovedTo(QPointF pos);
+ void segmentDrawn(QPointF start, QPointF end);
private:
bool mouseDown;
QPixmap* currentScene;