--- /dev/null
+#include "chatclient.h"
+
+#include <QtNetwork/QTcpSocket>
+
+ChatClient::ChatClient(const QString &host, int port, QObject *parent) :
+ QObject(parent)
+{
+ socket = new QTcpSocket(this);
+ m_tcphost = host;
+ m_port = port;
+
+ connect(socket, SIGNAL(connected()), this, SLOT(onConnected()));
+ connect(socket, SIGNAL(readyRead()), this, SLOT(onMessageRecieved()));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError()));
+}
+
+QString ChatClient::chatLog() const
+{
+ return m_chatLog;
+}
+
+void ChatClient::setChatLog(const QString &chatLog)
+{
+ if (m_chatLog == chatLog)
+ return;
+ m_chatLog = chatLog;
+ emit chatLogChanged(m_chatLog);
+}
+
+void ChatClient::appendToChatLog(const QString &message)
+{
+ if (message.isEmpty())
+ return;
+ m_chatLog += message;
+ emit chatLogChanged(m_chatLog);
+}
+
+void ChatClient::startChat(const QString &sessionkey)
+{
+ m_sessionkey = sessionkey;
+ socket->connectToHost(m_tcphost, m_port);
+ setChatLog("");
+}
+
+void ChatClient::stopChat()
+{
+ socket->disconnectFromHost();
+ m_sessionkey = "";
+}
+
+void ChatClient::onConnected()
+{
+ QString messageToSend = m_sessionkey + QChar('\n');
+ socket->write(messageToSend.toUtf8());
+}
+
+void ChatClient::onMessageRecieved()
+{
+ QByteArray data = socket->readAll();
+ QString message = QString::fromUtf8(data.constData(), data.size());
+ appendToChatLog(message);
+}
+
+void ChatClient::onError()
+{
+ systemMessage("Connection error: " + socket->errorString() + "\n");
+ if (socket->isOpen())
+ socket->close();
+}
+
+void ChatClient::sendMessage(const QString &message)
+{
+ QString messageToSend = message + QChar('\n');
+ socket->write(messageToSend.toUtf8());
+ appendToChatLog("You: " + messageToSend);
+}
+
+void ChatClient::systemMessage(const QString &message)
+{
+ appendToChatLog(">> " + message);
+}
--- /dev/null
+#ifndef CHATCLIENT_H
+#define CHATCLIENT_H
+
+#include <QObject>
+
+class QTcpSocket;
+
+class ChatClient : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString chatLog READ chatLog NOTIFY chatLogChanged)
+public:
+ explicit ChatClient(const QString &host, int port, QObject *parent = 0);
+
+ QString chatLog() const;
+
+signals:
+ void chatLogChanged(const QString &chatLog);
+
+public slots:
+ void startChat(const QString &sessionkey);
+ void stopChat();
+
+ void sendMessage(const QString &message);
+ void systemMessage(const QString &message);
+
+private slots:
+ void onConnected();
+ void onMessageRecieved();
+ void onError();
+
+private:
+ void setChatLog(const QString &chatLog);
+ void appendToChatLog(const QString &message);
+
+ QString m_sessionkey;
+ QString m_chatLog;
+
+ QTcpSocket *socket;
+
+ QString m_tcphost;
+ int m_port;
+};
+
+#endif // CHATCLIENT_H
#include <QtGui/QApplication>
//#include <QtOpenGL/QGLWidget>
+#include <QtDeclarative/QDeclarativeContext>
#include "qmlapplicationviewer.h"
+#include "timgame.h"
+#include "chatclient.h"
int main(int argc, char *argv[])
{
+ QString serverUrl = "http://localhost/tim/index.php";
+ QString tcphost = "localhost";
+ int tcpport = 8547;
+
QApplication app(argc, argv);
+ QCoreApplication::setApplicationName("Tim Game");
+
+ TimGame timGame(serverUrl);
+ ChatClient chatClient(tcphost, tcpport);
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
- viewer.setMainQmlFile(QLatin1String("qml/tim-game/main.qml"));
+ viewer.rootContext()->setContextProperty("timGame", &timGame);
+ viewer.rootContext()->setContextProperty("chatClient", &chatClient);
+ viewer.setMainQmlFile(QLatin1String("qml/tim-game/main.qml"));
// viewer.setViewport(new QGLWidget());
+ viewer.setWindowTitle(QCoreApplication::applicationName());
viewer.show();
return app.exec();
FocusScope {
id: wrapper
+ Flickable {
+ id: chatViewContainer
- ListView {
- id: chatView
- x: 0; y: 0
- height: parent.height - 80
- anchors.right: parent.right
- anchors.left: parent.left
- anchors.top: parent.top
+ x: 4; y: 4
+ height: parent.height - 84
+ width: parent.width - x * 2
anchors.topMargin: 0
anchors.rightMargin: 0
anchors.leftMargin: 0
+
+ contentWidth: chatView.paintedWidth
+ contentHeight: chatView.paintedHeight
+ clip: true
+ flickableDirection: Flickable.VerticalFlick
+
+ contentY: contentHeight - chatView.height
+
+ TextEdit {
+ id: chatView
+ readOnly: true
+ width: chatViewContainer.width
+ height: chatViewContainer.height
+ text: chatClient.chatLog
+ color: "orange"
+ font.pixelSize: 15
+ wrapMode: TextEdit.Wrap
+ }
}
Input {
id: inputLine
focus: true
- anchors.top: chatView.bottom
+ anchors.top: chatViewContainer.bottom
anchors.topMargin: 0
anchors.right: sendButton.left
exitChatView()
return;
}
+ chatClient.sendMessage(message);
}
function exitChatView() {
screen.state = ""
}
}
+
Button {
width: 80
id: sendButton
text: ">"
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
- anchors.top: chatView.bottom
+ anchors.top: chatViewContainer.bottom
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
return;
screen.focus = true;
screen.state = "";
+ timGame.uploadScore(highScore.text);
+ highScore.text = "";
}
}
TextInput{
id: input
width: parent.width - 12
- anchors.centerIn: parent
- maximumLength:21
+ anchors.centerIn: parent
+ maximumLength:500
font.pixelSize: 24;
font.bold: true
color: "#151515"; selectionColor: "mediumseagreen"
if (wrapper.state=="invalidinput")
return;
screen.focus = true;
- screen.state = "";
- screen.logIn();
+ screen.state = "loggingOutState";
+ timGame.login(user.text, pass.text);
+ user.text = "";
+ pass.text = "";
}
}
function goBack() {
screen.focus = true;
- screen.state = ""
+ screen.state = "";
}
}
}
states:
State {
name: "invalidinput"
- when: user.text=="" || pass.text==""
+ when: user.text === "" || pass.text === ""
PropertyChanges { target: loginButton ; opacity: 0.6 ; }
}
transitions:
--- /dev/null
+import Qt 4.7
+
+Rectangle {
+ property variant message: ""
+ signal accepted
+
+ id: messageBox
+
+ width: screen.width
+ height: 50
+ color: "#FFD700"
+
+ Text {
+ id: textBox
+ text: message
+ font.pixelSize: 40
+ horizontalAlignment: Text.AlignHCenter
+ anchors.fill: parent
+ }
+
+ MouseArea {
+ width: screen.width
+ height: screen.height
+ onClicked: {
+ messageBox.accepted()
+ }
+ }
+}
return;
screen.focus = true;
screen.state = ""
+ timGame.registration(user.text, pass.text);
+ user.text = "";
+ pass.text = "";
+ passRetyped.text = "";
}
}
Button {
function goBack() {
screen.focus = true;
- screen.state = ""
+ screen.state = "";
}
}
}
states:
State {
name: "invalidinput"
- when: user.text == "" || pass.text == "" || pass.text != passRetyped.text
+ when: user.text === "" || pass.text === "" || pass.text != passRetyped.text
PropertyChanges { target: registerButton ; opacity: 0.6 ; }
}
transitions:
--- /dev/null
+import Qt 4.7
+
+Component {
+ Item {
+ id: wrapper
+
+ height: 50 + (position == 1 ? 20 : 0)
+ x: 5
+ width: wrapper.ListView.view.width - 10
+
+ function color(position)
+ {
+ if (position == 1)
+ return "gold";
+ else if (position == 2)
+ return "silver";
+ else if(position == 3)
+ return "brown";
+ else
+ return "white";
+ }
+
+ function fontSize(position)
+ {
+ if (position == 1)
+ return 50;
+ else if (position == 2)
+ return 40;
+ else if(position == 3)
+ return 30
+ else
+ return 20
+ }
+
+ Rectangle
+ {
+ id: background
+ color: "gray"
+ opacity: 0.2
+ radius: 10
+ y: 2
+ height: parent.height - y * 2
+ width: parent.width
+ }
+
+ Text {
+ id: positionText
+ text: position + "."
+
+
+ color: wrapper.color(position)
+ font.pixelSize: wrapper.fontSize(position)
+ anchors.leftMargin: 4
+ anchors.left: background.left
+ anchors.verticalCenter: background.verticalCenter
+ }
+
+ Text {
+ id: scoreText
+ text: score
+
+ color: wrapper.color(position)
+ font.pixelSize: wrapper.fontSize(position)
+ anchors.horizontalCenter: background.horizontalCenter
+ anchors.verticalCenter: background.verticalCenter
+ }
+
+ Text {
+ id: userNameText
+ text: userName
+ color: wrapper.color(position)
+ font.pixelSize: wrapper.fontSize(position)
+ anchors.rightMargin: 4
+ anchors.right: background.right
+ anchors.verticalCenter: background.verticalCenter
+ }
+ }
+}
Item {
id: screen; width: 520; height: 480
- property bool loggedIn: false
- property variant sessionId: ""
+ property bool loggedIn: false;
function logOut() {
- loggedIn = false; sessionId = "";
+ timGame.logout();
screen.state = "";
+ chatClient.stopChat();
+ }
+
+ Connections {
+ target: timGame
+ onError: {
+ messageBox.message = "Error: " + timGame.error;
+ messageBox.state = "showMessageBox";
+ screen.state = ""
+ }
+ onLoggedIn: {
+ messageBox.message = "Logged In!";
+ messageBox.state = "showMessageBox";
+ screen.state = ""
+ chatClient.startChat(timGame.sessionkey);
+ }
+ onRegistered: {
+ messageBox.message = "Registration complete!";
+ messageBox.state = "showMessageBox";
+ }
+ onScoreUploaded: {
+ messageBox.message = "Score uploaded!";
+ messageBox.state = "showMessageBox";
+ scoreModel.reload();
+ }
}
- function logIn(sessionId) { loggedIn = true; sessionId = sessionId;}
Timer {
id: loggingOutTimer
onTriggered: { logOut() }
}
+ Timer {
+ id: loggingInTimer
+ interval: 500
+ onTriggered: screen.state = "";
+ }
+
Rectangle {
id: background
anchors.fill: parent; color: "#343434";
- state:"searchquery"
Image { source: "Components/images/stripes.png"; fillMode: Image.Tile; anchors.fill: parent; opacity: 0.3 }
+ Components.ScoreModel { id: scoreModel }
+ Components.Loading {anchors.centerIn: parent; visible: scoreModel.status == XmlListModel.Loading;}
+
ListView {
- id: highScoreTable;// model: rssModel.model; delegate: fatDelegate;
- width: parent.width; height: parent.height; x: 0; cacheBuffer: 100;
+ id: highScoreTable;
+ model: scoreModel.model
+ delegate: Components.ScoreDelegate {}
+ width: parent.width - 8; height: parent.height - 8; x: 4; y: 4; cacheBuffer: 100;
+
}
Components.LoginForm
states: [
State {
name: "loggedIn"
- when: screen.loggedIn
+ when: timGame.loggedIn
PropertyChanges {
target: toolBar
}
]
}
+
+ Components.MessageBox {
+ id: messageBox
+ y: -screen.height * 2
+ onAccepted: state = ""
+ states: [
+ State {
+ name: "showMessageBox"
+ PropertyChanges { target: messageBox; y: 150 }
+ }
+ ]
+ transitions: [
+ Transition { NumberAnimation { properties: "x,y,opacity"; duration: 500; easing.type: Easing.InOutQuad } }
+ ]
+ }
}
states: [
State {
name: "showLoginForm";
PropertyChanges { target: loginForm; x: 0; focus:true}
PropertyChanges { target: highScoreTable; x: -(parent.width * 1.5) }
- //PropertyChanges { target: titleBar; y: -80 }
PropertyChanges { target: toolBar; y: screen.height }
- //PropertyChanges { target: toolBar }
- //PropertyChanges { target: title; opacity:1}
},
State {
name: "showRegistrationForm";
--- /dev/null
+#include "serverreplyparser.h"
+
+#include <QDebug>
+
+ServerReplyParser::ServerReplyParser(QObject *parent) :
+ QObject(parent)
+{
+ reset();
+}
+
+ServerReplyParser::ReplyType ServerReplyParser::replyType()
+{
+ return m_replyType;
+}
+
+QString ServerReplyParser::error()
+{
+ return m_error;
+}
+
+QString ServerReplyParser::userName()
+{
+ return m_userName;
+}
+
+int ServerReplyParser::userId()
+{
+ return m_userId;
+}
+
+QString ServerReplyParser::sessionkey()
+{
+ return m_sessionkey;
+}
+
+bool ServerReplyParser::read(QIODevice *dev)
+{
+ reset();
+ xml.setDevice(dev);
+
+ if (xml.readNextStartElement())
+ {
+ if (xml.name() == "message")
+ readMessage();
+ else
+ xml.raiseError(QObject::tr("Unknown reply format"));
+ }
+
+ return !xml.hasError();
+}
+
+void ServerReplyParser::readMessage()
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "message");
+
+ while (xml.readNextStartElement()) {
+ if (xml.name() == "error")
+ readError();
+ else if (xml.name() == "login")
+ readLogin();
+ else if (xml.name() == "register")
+ readRegister();
+ else if (xml.name() == "setscore")
+ readSetScore();
+ else
+ xml.skipCurrentElement();
+ }
+}
+
+void ServerReplyParser::readError()
+{
+ setReplyType(ErrorReply);
+ m_error = xml.readElementText();
+}
+
+void ServerReplyParser::readLogin()
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "login");
+
+ setReplyType(LoginReply);
+ while (xml.readNextStartElement()) {
+ if (xml.name() == "sessionkey") {
+ m_sessionkey = xml.readElementText(); continue;
+ }
+ else if (xml.name() == "user") {
+ m_userName = xml.readElementText(); continue;
+ }
+ else if (xml.name() == "userid") {
+ m_userId = xml.readElementText().toInt(); continue;
+ }
+ else
+ xml.skipCurrentElement();
+ }
+}
+
+void ServerReplyParser::readRegister()
+{
+ setReplyType(RegistrationReply);
+ xml.readNext();
+}
+
+void ServerReplyParser::readSetScore()
+{
+ setReplyType(SetScoreReply);
+ xml.readNext();
+}
+
+
+void ServerReplyParser::setReplyType(ServerReplyParser::ReplyType replyType)
+{
+ if (typeDetermined)
+ return;
+ m_replyType = replyType;
+ typeDetermined = true;
+}
+
+void ServerReplyParser::reset()
+{
+ xml.clear();
+ typeDetermined = false;
+ m_replyType = UnknownReply;
+ m_error = "";
+ m_userName = "";
+ m_userId = 0;
+ m_sessionkey = "";
+}
+
+
--- /dev/null
+#ifndef SERVERREPLYPARSER_H
+#define SERVERREPLYPARSER_H
+
+#include <QObject>
+#include <QXmlStreamReader>
+
+class QIODevice;
+
+class ServerReplyParser : public QObject
+{
+ Q_OBJECT
+public:
+ enum ReplyType
+ {
+ UnknownReply,
+ ErrorReply,
+ LoginReply,
+ RegistrationReply,
+ SetScoreReply
+ };
+
+ explicit ServerReplyParser(QObject *parent = 0);
+
+ ReplyType replyType();
+
+ QString error();
+
+ QString userName();
+ int userId();
+ QString sessionkey();
+
+ bool read(QIODevice *dev);
+
+protected:
+ void readMessage();
+ void readError();
+
+ void readLogin();
+ void readRegister();
+ void readSetScore();
+
+signals:
+
+private:
+ void setReplyType(ReplyType replyType);
+ void reset();
+
+ QXmlStreamReader xml;
+
+ ReplyType m_replyType;
+ QString m_error;
+ QString m_userName;
+ int m_userId;
+ QString m_sessionkey;
+
+ bool typeDetermined;
+};
+
+#endif // SERVERREPLYPARSER_H
+QT += network
+
# Add more folders to ship with the application, here
folder_01.source = qml/tim-game
folder_01.target = qml
# MOBILITY +=
# The .cpp file which was generated for your project. Feel free to hack it.
-SOURCES += main.cpp
+SOURCES += main.cpp \
+ timgame.cpp \
+ serverreplyparser.cpp \
+ chatclient.cpp
# Please do not modify the following two lines. Required for deployment.
include(qmlapplicationviewer/qmlapplicationviewer.pri)
}
INSTALLS += target
}
+
+HEADERS += \
+ timgame.h \
+ serverreplyparser.h \
+ chatclient.h
--- /dev/null
+#include "timgame.h"
+
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkReply>
+
+#include "serverreplyparser.h"
+
+TimGame::TimGame(const QString &serverUrl, QObject *parent) :
+ QObject(parent)
+{
+ networkManager = new QNetworkAccessManager(this);
+ replyParser = new ServerReplyParser(this);
+
+ m_loggedIn = false;
+ m_userId = 0;
+
+ m_serverUrl = serverUrl;
+}
+
+bool TimGame::isLoggedIn() const
+{
+ return m_loggedIn;
+}
+
+void TimGame::setLoggedIn(bool isLoggedIn)
+{
+ if (isLoggedIn == m_loggedIn)
+ return;
+ m_loggedIn = isLoggedIn;
+ emit loggedInChanged(m_loggedIn);
+}
+
+QString TimGame::user() const
+{
+ return m_user;
+}
+
+void TimGame::setUser(const QString &name)
+{
+ if (m_user == name)
+ return;
+ m_user = name;
+ emit userChanged(m_user);
+}
+
+int TimGame::userId() const
+{
+ return m_userId;
+}
+
+void TimGame::setUserId(int userId)
+{
+ if (m_userId == userId)
+ return;
+ m_userId = userId;
+ emit userIdChanged(m_userId);
+}
+
+QString TimGame::error() const
+{
+ return m_error;
+}
+
+void TimGame::setError(const QString &error)
+{
+ if (m_error == error)
+ return;
+ m_error = error;
+ emit errorChanged(m_error);
+}
+
+QString TimGame::sessionkey() const
+{
+ return m_sessionkey;
+}
+
+void TimGame::setSessionkey(const QString &sessionkey)
+{
+ if (m_sessionkey == sessionkey)
+ return;
+ m_sessionkey = sessionkey;
+ emit sessionkeyChanged(m_sessionkey);
+}
+
+
+QString TimGame::serverUrl() const
+{
+ return m_serverUrl;
+}
+
+void TimGame::registration(const QString &user, const QString &pass)
+{
+ QNetworkRequest registrationRequest(QUrl::fromUserInput(m_serverUrl + QString("?a=register&user=%1&pass=%2").arg(user, pass)));
+ QNetworkReply *registrationReply = networkManager->get(registrationRequest);
+ connect(registrationReply, SIGNAL(finished()), this, SLOT(networkRequestComplete()));
+}
+
+void TimGame::login(const QString &user, const QString &pass)
+{
+ QNetworkRequest loginRequest(QUrl::fromUserInput(m_serverUrl + QString("?a=login&user=%1&pass=%2").arg(user, pass)));
+ QNetworkReply *loginReply = networkManager->get(loginRequest);
+ connect(loginReply, SIGNAL(finished()), this, SLOT(networkRequestComplete()));
+}
+
+void TimGame::logout()
+{
+ m_sessionkey = "";
+ setLoggedIn(false);
+}
+
+void TimGame::uploadScore(int score)
+{
+ if (!isLoggedIn())
+ return;
+ QNetworkRequest scoreRequest(QUrl::fromUserInput(m_serverUrl + QString("?a=setscore&s=%1&score=%2").arg(m_sessionkey).arg(score)));
+ QNetworkReply *scoreReply = networkManager->get(scoreRequest);
+ connect(scoreReply, SIGNAL(finished()), this, SLOT(networkRequestComplete()));
+}
+
+void TimGame::networkRequestComplete()
+{
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
+
+ if (!reply)
+ return;
+
+ if (reply->error() != QNetworkReply::NoError)
+ {
+ m_error = "Network error";
+ emit error(m_error);
+ goto finish;
+ }
+
+ if (!replyParser->read(reply))
+ {
+ m_error = "Unexpected Reply From Server (xml)";
+ emit error(m_error);
+ goto finish;
+ }
+
+ switch (replyParser->replyType())
+ {
+ case ServerReplyParser::UnknownReply:
+ m_error = "Unexpected Reply From Server";
+ emit error(m_error);
+ goto finish;
+ break;
+ case ServerReplyParser::ErrorReply:
+ m_error = replyParser->error();
+ emit error(m_error);
+ break;
+ case ServerReplyParser::LoginReply:
+ setUser(replyParser->userName());
+ setUserId(replyParser->userId());
+ m_sessionkey = replyParser->sessionkey();
+ setLoggedIn(true);
+ emit loggedIn();
+ break;
+ case ServerReplyParser::RegistrationReply:
+ emit registered();
+ break;
+ case ServerReplyParser::SetScoreReply:
+ emit scoreUploaded();
+ break;
+ }
+
+finish:
+ reply->deleteLater();
+}
--- /dev/null
+#ifndef TIMGAME_H
+#define TIMGAME_H
+
+#include <QObject>
+class QNetworkAccessManager;
+class ServerReplyParser;
+
+class TimGame : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool loggedIn READ isLoggedIn NOTIFY loggedInChanged)
+ Q_PROPERTY(QString user READ user NOTIFY userChanged)
+ Q_PROPERTY(int userId READ userId NOTIFY userIdChanged)
+ Q_PROPERTY(QString error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString sessionkey READ sessionkey NOTIFY sessionkeyChanged)
+
+ Q_PROPERTY(QString serverUrl READ serverUrl NOTIFY serverUrlChanged)
+
+public:
+ explicit TimGame(const QString &serverUrl, QObject *parent = 0);
+
+ bool isLoggedIn() const;
+ QString user() const;
+ int userId() const;
+ QString error() const;
+ QString sessionkey() const;
+
+ QString serverUrl() const;
+
+signals:
+ void error(const QString &error);
+
+ void loggedIn();
+ void loggedInChanged(bool oggedIn);
+
+ void registered();
+ void scoreUploaded();
+
+ void userChanged(const QString &name);
+ void userIdChanged(int id);
+ void errorChanged(const QString &error);
+ void sessionkeyChanged(const QString &sessionkey);
+ void serverUrlChanged(const QString &serverUrl);
+
+public slots:
+ void registration(const QString &user, const QString &pass);
+ void login(const QString &user, const QString &pass);
+ void logout();
+
+ void uploadScore(int score);
+
+private slots:
+ void networkRequestComplete();
+
+private:
+ void setLoggedIn(bool isLoggedIn);
+ void setUser(const QString &name);
+ void setUserId(int userId);
+ void setError(const QString &error);
+ void setSessionkey(const QString &sessionkey);
+
+ bool m_loggedIn;
+ QString m_user;
+ int m_userId;
+ QString m_error;
+
+ QString m_sessionkey;
+
+ QString m_serverUrl;
+
+ QNetworkAccessManager *networkManager;
+ ServerReplyParser *replyParser;
+};
+
+#endif // TIMGAME_H