From: Drew Fisher Date: Tue, 5 Oct 2010 05:57:48 +0000 (-0700) Subject: Near-complete implementation of actions, a shell menu, and basic network connections. X-Git-Url: http://git.zarvox.org/shortlog/static/%24c%5B5%5D?a=commitdiff_plain;h=cd3c4fec887bab4c956ce88a6aef7e17c172c3f3;p=shareboard.git Near-complete implementation of actions, a shell menu, and basic network connections. A number of things are still stubbed out while we work out network protocol specifics. --- cd3c4fec887bab4c956ce88a6aef7e17c172c3f3 diff --git a/action.cpp b/action.cpp new file mode 100644 index 0000000..fe82a21 --- /dev/null +++ b/action.cpp @@ -0,0 +1,92 @@ +#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(action.type) ; // mesgID, userID, timestamp, mesgType + switch(action.type) { + case Action::INVALID: break; + case Action::UserJoin: + { + const UserJoinAction* a = static_cast(&action); + out << " " << a->username; + } break; + case Action::UserPart: + break; // UserPart doesn't have any special data + case Action::MouseMove: + { + const MouseMoveAction* a = static_cast(&action); + out << " " << a->pos.x() << " " << a->pos.y(); + } break; + case Action::DrawLine: + { + const DrawLineAction* a = static_cast(&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(&action); + // TODO: unbackburner this + //out << " " << a->topLeft << a->image; + } break; + case Action::UserChat: + { + const UserChatAction* a = static_cast(&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(k); + return in; +}*/ + + diff --git a/action.h b/action.h new file mode 100644 index 0000000..3f2baf2 --- /dev/null +++ b/action.h @@ -0,0 +1,83 @@ +#ifndef __ACTION_H__ +#define __ACTION_H__ + +#include +#include +#include +#include +#include +#include +#include + +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 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__ diff --git a/connectionmanager.cpp b/connectionmanager.cpp new file mode 100644 index 0000000..3ad8525 --- /dev/null +++ b/connectionmanager.cpp @@ -0,0 +1,49 @@ +#include "connectionmanager.h" +#include +#include +#include +#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"; +} diff --git a/connectionmanager.h b/connectionmanager.h new file mode 100644 index 0000000..d9bc4e5 --- /dev/null +++ b/connectionmanager.h @@ -0,0 +1,35 @@ +#ifndef __CONNECTIONMANAGER_H__ +#define __CONNECTIONMANAGER_H__ + +#include +#include +#include +#include + +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__ + diff --git a/connectwidget.cpp b/connectwidget.cpp new file mode 100644 index 0000000..9933701 --- /dev/null +++ b/connectwidget.cpp @@ -0,0 +1,49 @@ +#include "connectwidget.h" + +#include +#include +#include +#include +#include + + +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(); +} diff --git a/connectwidget.h b/connectwidget.h new file mode 100644 index 0000000..39dca00 --- /dev/null +++ b/connectwidget.h @@ -0,0 +1,33 @@ +#ifndef __CONNECTWIDGET_H__ +#define __CONNECTWIDGET_H__ + +#include + +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__ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..5f29b1c --- /dev/null +++ b/main.cpp @@ -0,0 +1,9 @@ +#include +#include "mainwindow.h" + +int main(int argc, char** argv) { + QApplication* app = new QApplication(argc, argv); + MainWindow* win = new MainWindow(); + win->show(); + return app->exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..b45c8cd --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,89 @@ +#include "mainwindow.h" +#include +#include +#include +#include +#include +#include +#include + +#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); + +} + diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..44cda15 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,37 @@ +#ifndef __MAINWINDOW_H__ +#define __MAINWINDOW_H__ + +#include + +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__ diff --git a/shareboard.pro b/shareboard.pro new file mode 100644 index 0000000..2c4c6bf --- /dev/null +++ b/shareboard.pro @@ -0,0 +1,14 @@ +###################################################################### +# 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