A number of things are still stubbed out while we work out network protocol specifics.
--- /dev/null
+#include "action.h"
+
+Action::Action() {
+ type = INVALID;
+ id = 0;
+ approved = false;
+}
+
+Action::Action(Type t) {
+ type = t;
+ id = 0;
+ approved = false;
+}
+
+Action::~Action() {
+}
+
+//
+UserJoinAction::UserJoinAction() : Action(Action::UserJoin) {
+}
+UserJoinAction::~UserJoinAction() {
+}
+
+//
+UserPartAction::UserPartAction() : Action(Action::UserPart) {
+}
+UserPartAction::~UserPartAction() {
+}
+
+//
+MouseMoveAction::MouseMoveAction() : Action(Action::MouseMove) {
+}
+MouseMoveAction::~MouseMoveAction() {
+}
+
+//
+DrawLineAction::DrawLineAction() : Action(Action::DrawLine) {
+ color = Qt::black;
+ width = 1;
+}
+DrawLineAction::~DrawLineAction() {
+}
+
+QTextStream& operator<<(QTextStream& out, const Action& action) {
+ out << "0 " << action.id << " 0 " << static_cast<quint16>(action.type) ; // mesgID, userID, timestamp, mesgType
+ switch(action.type) {
+ case Action::INVALID: break;
+ case Action::UserJoin:
+ {
+ const UserJoinAction* a = static_cast<const UserJoinAction*>(&action);
+ out << " " << a->username;
+ } break;
+ case Action::UserPart:
+ break; // UserPart doesn't have any special data
+ case Action::MouseMove:
+ {
+ const MouseMoveAction* a = static_cast<const MouseMoveAction*>(&action);
+ out << " " << a->pos.x() << " " << a->pos.y();
+ } break;
+ case Action::DrawLine:
+ {
+ const DrawLineAction* a = static_cast<const DrawLineAction*>(&action);
+ const QColor& c = a->color;
+ out << " " << c.red() << " " << c.green() << " " << c.blue() << " " << a->width;
+ foreach(QPointF p, a->points) {
+ out << " " << p.x() << " " << p.y();
+ }
+ } break;
+ case Action::AddImage:
+ {
+ const AddImageAction* a = static_cast<const AddImageAction*>(&action);
+ // TODO: unbackburner this
+ //out << " " << a->topLeft << a->image;
+ } break;
+ case Action::UserChat:
+ {
+ const UserChatAction* a = static_cast<const UserChatAction*>(&action);
+ out << " " << a->text;
+ } break;
+ }
+ out << "\n";
+ return out;
+}
+
+/*QTextStream& operator>>(QTextStream& in, Action& action){
+ quint16 k;
+ in >> k >> action.id >> action.approved >> action.when;
+ action.type = static_cast<Action::Type>(k);
+ return in;
+}*/
+
+
--- /dev/null
+#ifndef __ACTION_H__
+#define __ACTION_H__
+
+#include <QDateTime>
+#include <QPointF>
+#include <QTextStream>
+#include <QColor>
+#include <QVector>
+#include <QString>
+#include <QImage>
+
+class Action {
+public:
+ enum Type {
+ INVALID,
+ UserJoin,
+ UserPart,
+ MouseMove,
+ DrawLine,
+ AddImage,
+ UserChat
+ };
+
+ Action();
+ Action(Type t);
+ virtual ~Action();
+
+ Type type;
+ // UUID uuid; // Unique id for this
+ int id; // Which user does this refer to?
+ bool approved; // Has the server approved this event yet?
+ QDateTime when; // Time at which the server made this event official
+
+};
+
+class UserJoinAction : public Action {
+public:
+ UserJoinAction();
+ ~UserJoinAction();
+ QString username; // What's their username?
+};
+
+class UserPartAction : public Action {
+public:
+ UserPartAction();
+ ~UserPartAction();
+};
+
+class MouseMoveAction : public Action {
+public:
+ MouseMoveAction();
+ ~MouseMoveAction();
+ QPointF pos;
+};
+
+class DrawLineAction : public Action {
+public:
+ DrawLineAction();
+ ~DrawLineAction();
+ QColor color;
+ int width;
+ QVector<QPointF> points;
+
+};
+
+class AddImageAction : public Action {
+public:
+ AddImageAction();
+ ~AddImageAction();
+ QPointF topLeft;
+ QImage image;
+};
+
+class UserChatAction : public Action {
+public:
+ UserChatAction();
+ ~UserChatAction();
+ QString text;
+};
+
+QTextStream& operator<<(QTextStream& out, const Action& action);
+
+#endif //__ACTION_H__
--- /dev/null
+#include "connectionmanager.h"
+#include <QDebug>
+#include <QTcpSocket>
+#include <QTextStream>
+#include "action.h"
+
+ConnectionManager::ConnectionManager(QObject* parent) : QObject(parent) {
+ sock = new QTcpSocket();
+ textStream = new QTextStream(sock);
+ QObject::connect(sock, SIGNAL(connected()), this, SLOT(onConnect()));
+ QObject::connect(sock, SIGNAL(readyRead()), this, SLOT(haveData()));
+}
+
+ConnectionManager::~ConnectionManager() {
+ if (sock) delete sock;
+}
+
+void ConnectionManager::joinServer(QString _username, QString host) {
+ username = _username;
+ quint16 port = 4260;
+ sock->connectToHost(host, port);
+ qDebug() << "Connecting to " << host << "as " << _username;
+}
+
+void ConnectionManager::sendAction(Action* action) {
+ switch(action->type) { // Handle serializing all actions
+ default:
+ break;
+ }
+
+}
+void ConnectionManager::haveData() {
+ data.append(sock->readAll());
+ // Check if we have a full action waiting, if so, dispatch
+ // Event structure:
+ // uint32 num_bytes (we don't support things larger than 4GB, kthx
+ // uint16 type
+ // char approved
+ // QDateTime when
+ // [rest of details]
+ qDebug() << data.size() << " bytes read so far";
+}
+
+void ConnectionManager::onConnect() {
+ qDebug() << "connection established";
+ emit connected();
+ (*textStream) << "0 0 0 2 " << username << endl;
+ qDebug() << "sent JoinAction";
+}
--- /dev/null
+#ifndef __CONNECTIONMANAGER_H__
+#define __CONNECTIONMANAGER_H__
+
+#include <QObject>
+#include <QByteArray>
+#include <QString>
+#include <QTextStream>
+
+class Action;
+class QTcpSocket;
+
+class ConnectionManager : public QObject{
+ Q_OBJECT
+ public:
+ ConnectionManager(QObject* parent = 0);
+ ~ConnectionManager();
+ signals:
+ //void readData();
+ //void actionRecieved(Action* act); // act is freed by recipient of signal
+ void connected();
+ public slots:
+ void joinServer(QString _username, QString host);
+ void sendAction(Action* action);
+ private:
+ QString username;
+ QByteArray data;
+ QTcpSocket* sock;
+ QTextStream* textStream;
+ private slots:
+ void haveData();
+ void onConnect();
+};
+
+#endif // __CONNECTIONMANAGER_H__
+
--- /dev/null
+#include "connectwidget.h"
+
+#include <QGridLayout>
+#include <QVBoxLayout>
+#include <QLineEdit>
+#include <QLabel>
+#include <QPushButton>
+
+
+ConnectWidget::ConnectWidget(QWidget* parent) : QWidget(parent) {
+ layout = new QVBoxLayout();
+ grid = new QGridLayout();
+ userEdit = new QLineEdit("guest", this);
+ hostEdit = new QLineEdit("kraken.zarvox.org", this);
+ userLabel = new QLabel("Pick a username:", this);
+ userLabel->setAlignment(Qt::AlignRight);
+ hostLabel = new QLabel("Server to connect to:", this);
+ hostLabel->setAlignment(Qt::AlignRight);
+ goButton = new QPushButton("Connect!");
+
+ grid->addWidget(userLabel, 0,0);
+ grid->addWidget(userEdit, 0,1);
+ grid->addWidget(hostLabel, 1,0);
+ grid->addWidget(hostEdit, 1,1);
+ layout->addStretch();
+ layout->addLayout(grid);
+ layout->addWidget(goButton);
+ layout->addStretch();
+
+ setLayout(layout);
+ QObject::connect(goButton, SIGNAL(clicked()), this, SLOT(connect()));
+}
+
+ConnectWidget::~ConnectWidget() {
+}
+
+void ConnectWidget::connect() {
+ QString username = userEdit->text().replace(" ", "_");
+ QString host = hostEdit->text();
+ emit connectToServer(username, host);
+}
+
+QString ConnectWidget::user() {
+ return userEdit->text();
+}
+
+QString ConnectWidget::host() {
+ return hostEdit->text();
+}
--- /dev/null
+#ifndef __CONNECTWIDGET_H__
+#define __CONNECTWIDGET_H__
+
+#include <QWidget>
+
+class QGridLayout;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QVBoxLayout;
+
+class ConnectWidget : public QWidget {
+ Q_OBJECT
+ public:
+ ConnectWidget(QWidget* parent=0);
+ ~ConnectWidget();
+ QString user();
+ QString host();
+ public slots:
+ void connect();
+ signals:
+ void connectToServer(QString username, QString host);
+ private:
+ QVBoxLayout* layout;
+ QGridLayout* grid;
+ QLineEdit* userEdit;
+ QLineEdit* hostEdit;
+ QLabel* userLabel;
+ QLabel* hostLabel;
+ QPushButton* goButton;
+};
+
+#endif // __CONNECTWIDGET_H__
--- /dev/null
+#include <QApplication>
+#include "mainwindow.h"
+
+int main(int argc, char** argv) {
+ QApplication* app = new QApplication(argc, argv);
+ MainWindow* win = new MainWindow();
+ win->show();
+ return app->exec();
+}
--- /dev/null
+#include "mainwindow.h"
+#include <QAction>
+#include <QApplication>
+#include <QFile>
+#include <QFileDialog>
+#include <QLabel>
+#include <QMenuBar>
+#include <QStatusBar>
+
+#include "connectwidget.h"
+#include "connectionmanager.h"
+
+MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
+ createActions();
+ createMenus();
+
+ prompt = new ConnectWidget();
+ setCentralWidget(prompt);
+
+ connMan = new ConnectionManager(this);
+ QObject::connect(prompt, SIGNAL(connectToServer(QString, QString)), connMan, SLOT(joinServer(QString, QString)));
+
+ statusBar()->showMessage("Ready");
+}
+
+MainWindow::~MainWindow() {
+
+}
+
+void MainWindow::load() {
+ QString fileName = QFileDialog::getOpenFileName(this, "Load saved board:", ".", "Shareboards (*.board)");
+ if(fileName.isEmpty()) {
+ statusBar()->showMessage("Cancelled loading board.");
+ return;
+ }
+ QFile file(fileName);
+ QDataStream in(&file);
+ // Load all history from that file
+ statusBar()->showMessage(QString("Successfully loaded ").append(fileName));
+}
+
+void MainWindow::save() {
+ QString fileName = QFileDialog::getSaveFileName(this, "Save board history as:", ".", "Shareboards (*.board)");
+ if(fileName.isEmpty()) {
+ statusBar()->showMessage("Cancelled saving board.");
+ return;
+ }
+ if(!fileName.endsWith(".board"))
+ fileName = fileName.append(".board");
+ QFile file(fileName);
+ QDataStream out(&file);
+ // Output all history to that file
+ statusBar()->showMessage(QString("Successfully saved ").append(fileName));
+}
+
+void MainWindow::quit() {
+ // If we want, we can add some annoying dialog that says "Quit now?" and throws the user off
+ qApp->quit();
+}
+
+void MainWindow::switchToBoard() {
+ // Here, we set the central widget to be the as-of-yet unimplemented Shareboard widget
+}
+
+void MainWindow::switchToConnect() {
+ setCentralWidget(prompt);
+}
+
+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);
+ QObject::connect(loadPastAction, SIGNAL(triggered()), this, SLOT(load()));
+ QObject::connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
+ QObject::connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
+}
+
+void MainWindow::createMenus() {
+
+ fileMenu = menuBar()->addMenu("&File");
+ //fileMenu->addAction(joinAction);
+ fileMenu->addAction(loadPastAction);
+ fileMenu->addAction(saveAction);
+ fileMenu->addSeparator();
+ fileMenu->addAction(quitAction);
+
+}
+
--- /dev/null
+#ifndef __MAINWINDOW_H__
+#define __MAINWINDOW_H__
+
+#include <QMainWindow>
+
+class QMenu;
+class QAction;
+class ConnectWidget;
+class ConnectionManager;
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ MainWindow(QWidget* parent = 0);
+ ~MainWindow();
+public slots:
+// void join();
+ void load();
+ void save();
+ void quit();
+ void switchToBoard();
+ void switchToConnect();
+private:
+ void createActions();
+ void createMenus();
+ QMenu* fileMenu;
+// QAction* joinAction; // Removed in favor of central widget handling this.
+ QAction* loadPastAction;
+ QAction* saveAction;
+ QAction* quitAction;
+ ConnectionManager* connMan;
+// HistoryManager* historyManager;
+// Shareboard* board;
+ ConnectWidget* prompt;
+};
+
+#endif // __MAINWINDOW_H__
--- /dev/null
+######################################################################
+# Automatically generated by qmake (2.01a) Thu Sep 30 22:59:13 2010
+######################################################################
+
+TEMPLATE = app
+TARGET = shareboard
+CONFIG += qt
+QT += network
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += mainwindow.h action.h connectwidget.h connectionmanager.h
+SOURCES += main.cpp mainwindow.cpp action.cpp connectwidget.cpp connectionmanager.cpp