Merge branch 'master' of ssh://marcus@cockatrice.de/home/cockgit/cockatrice

This commit is contained in:
marcus 2009-08-24 11:40:11 +02:00
commit 5b1bf7a1a2
28 changed files with 855 additions and 182 deletions

View file

@ -62,6 +62,7 @@ CardInfoWidget::CardInfoWidget(CardDatabase *_db, QWidget *parent)
retranslateUi();
setFrameStyle(QFrame::Panel | QFrame::Raised);
textLabel->setFixedHeight(130);
setFixedSize(sizeHint());
}

View file

@ -0,0 +1,250 @@
#include <QtGui>
#include "chatwidget.h"
#include "client.h"
ChannelWidget::ChannelWidget(Client *_client, const QString &_name, bool readOnly, bool _virtualChannel, QWidget *parent)
: QWidget(parent), client(_client), name(_name), virtualChannel(_virtualChannel)
{
playerList = new QListWidget;
playerList->setFixedWidth(100);
textEdit = new QTextEdit;
textEdit->setReadOnly(true);
if (!readOnly) {
sayEdit = new QLineEdit;
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage()));
}
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(textEdit);
if (!readOnly)
vbox->addWidget(sayEdit);
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addLayout(vbox);
hbox->addWidget(playerList);
setLayout(hbox);
}
ChannelWidget::~ChannelWidget()
{
if (!virtualChannel)
client->chatLeaveChannel(name);
}
void ChannelWidget::sendMessage()
{
if (sayEdit->text().isEmpty())
return;
client->chatSay(name, sayEdit->text());
sayEdit->clear();
}
void ChannelWidget::joinEvent(const QString &playerName)
{
textEdit->append(tr("%1 has joined the channel.").arg(playerName));
playerList->addItem(playerName);
}
void ChannelWidget::listPlayersEvent(const QString &playerName)
{
playerList->addItem(playerName);
}
void ChannelWidget::leaveEvent(const QString &playerName)
{
textEdit->append(tr("%1 has left the channel.").arg(playerName));
for (int i = 0; i < playerList->count(); ++i)
if (playerList->item(i)->text() == playerName) {
delete playerList->takeItem(i);
break;
}
}
void ChannelWidget::sayEvent(const QString &playerName, const QString &s)
{
textEdit->append(QString("<font color=\"red\">%1:</font> %2").arg(playerName).arg(s));
}
void ChannelWidget::serverMessageEvent(const QString &s)
{
textEdit->append(QString("<font color=\"blue\">%1</font>").arg(s));
}
ChatWidget::ChatWidget(Client *_client, QWidget *parent)
: QWidget(parent), client(_client)
{
channelList = new QTreeWidget;
channelList->setRootIsDecorated(false);
channelList->setFixedWidth(200);
joinButton = new QPushButton;
connect(joinButton, SIGNAL(clicked()), this, SLOT(joinClicked()));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(joinButton);
QVBoxLayout *leftLayout = new QVBoxLayout;
leftLayout->addWidget(channelList);
leftLayout->addLayout(buttonLayout);
tab = new QTabWidget;
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addLayout(leftLayout);
hbox->addWidget(tab, 1);
retranslateUi();
setLayout(hbox);
}
void ChatWidget::retranslateUi()
{
joinButton->setText(tr("Joi&n"));
QTreeWidgetItem *header = channelList->headerItem();
Q_ASSERT(header != 0);
header->setText(0, tr("Channel"));
header->setText(1, tr("Players"));
header->setTextAlignment(1, Qt::AlignRight);
}
void ChatWidget::enableChat()
{
connect(client, SIGNAL(chatEvent(const ChatEventData &)), this, SLOT(chatEvent(const ChatEventData &)));
client->chatListChannels();
show();
}
void ChatWidget::disableChat()
{
disconnect(client, 0, this, 0);
while (tab->count()) {
ChannelWidget *cw = qobject_cast<ChannelWidget *>(tab->widget(0));
tab->removeTab(0);
delete cw;
}
channelList->clear();
hide();
}
void ChatWidget::chatEvent(const ChatEventData &data)
{
const QStringList &msg = data.getEventData();
switch (data.getEventType()) {
case eventChatListChannels: {
if (msg.size() != 4)
break;
for (int i = 0; i < channelList->topLevelItemCount(); ++i) {
QTreeWidgetItem *twi = channelList->topLevelItem(i);
if (twi->text(0) == msg[0]) {
twi->setToolTip(0, msg[1]);
twi->setText(1, msg[2]);
return;
}
}
QTreeWidgetItem *twi = new QTreeWidgetItem(QStringList() << msg[0] << msg[2]);
twi->setTextAlignment(1, Qt::AlignRight);
twi->setToolTip(0, msg[1]);
channelList->addTopLevelItem(twi);
channelList->resizeColumnToContents(0);
channelList->resizeColumnToContents(1);
if (msg[3] == "1")
joinChannel(msg[0]);
break;
}
case eventChatJoinChannel: {
if (msg.size() != 2)
break;
ChannelWidget *w = getChannel(msg[0]);
if (!w)
break;
w->joinEvent(msg[1]);
break;
}
case eventChatListPlayers: {
if (msg.size() != 2)
break;
ChannelWidget *w = getChannel(msg[0]);
if (!w)
break;
w->listPlayersEvent(msg[1]);
break;
}
case eventChatLeaveChannel: {
if (msg.size() != 2)
break;
ChannelWidget *w = getChannel(msg[0]);
if (!w)
break;
w->leaveEvent(msg[1]);
break;
}
case eventChatSay: {
if (msg.size() != 3)
break;
ChannelWidget *w = getChannel(msg[0]);
if (!w)
break;
w->sayEvent(msg[1], msg[2]);
break;
}
case eventChatServerMessage: {
if (msg.size() != 2)
break;
ChannelWidget *w;
if (msg[0].isEmpty()) {
w = getChannel("Server");
if (!w) {
w = new ChannelWidget(client, "Server", true, true);
tab->addTab(w, "Server");
}
} else
w = getChannel(msg[0]);
w->serverMessageEvent(msg[1]);
break;
}
default: {
}
}
}
void ChatWidget::joinChannel(const QString &channelName)
{
PendingCommand *pc = client->chatJoinChannel(channelName);
pc->setExtraData(channelName);
connect(pc, SIGNAL(finished(ServerResponse)), this, SLOT(joinFinished(ServerResponse)));
}
void ChatWidget::joinClicked()
{
QTreeWidgetItem *twi = channelList->currentItem();
if (!twi)
return;
QString channelName = twi->text(0);
if (getChannel(channelName))
return;
joinChannel(channelName);
}
void ChatWidget::joinFinished(ServerResponse resp)
{
if (resp != RespOk)
return;
PendingCommand *pc = qobject_cast<PendingCommand *>(sender());
QString channelName = pc->getExtraData();
ChannelWidget *cw = new ChannelWidget(client, channelName);
tab->addTab(cw, channelName);
}
ChannelWidget *ChatWidget::getChannel(const QString &name)
{
for (int i = 0; i < tab->count(); ++i) {
ChannelWidget *cw = qobject_cast<ChannelWidget *>(tab->widget(i));
if (cw->getName() == name)
return cw;
}
return 0;
}

View file

@ -0,0 +1,59 @@
#ifndef CHATWIDGET_H
#define CHATWIDGET_H
#include <QWidget>
#include "servereventdata.h"
#include "client.h"
class QListWidget;
class QTextEdit;
class QLineEdit;
class QTreeWidget;
class QTabWidget;
class QPushButton;
class ChannelWidget : public QWidget {
Q_OBJECT
private:
QListWidget *playerList;
QTextEdit *textEdit;
QLineEdit *sayEdit;
Client *client;
QString name;
bool virtualChannel;
private slots:
void sendMessage();
public:
ChannelWidget(Client *_client, const QString &_name, bool readOnly = false, bool _virtualChannel = false, QWidget *parent = 0);
~ChannelWidget();
const QString &getName() const { return name; }
void joinEvent(const QString &playerName);
void listPlayersEvent(const QString &playerName);
void leaveEvent(const QString &playerName);
void sayEvent(const QString &playerName, const QString &s);
void serverMessageEvent(const QString &s);
};
class ChatWidget : public QWidget {
Q_OBJECT
private:
QTreeWidget *channelList;
QPushButton *joinButton;
QTabWidget *tab;
Client *client;
ChannelWidget *getChannel(const QString &name);
void joinChannel(const QString &channelName);
private slots:
void chatEvent(const ChatEventData &data);
void joinClicked();
void joinFinished(ServerResponse resp);
public:
ChatWidget(Client *_client, QWidget *parent = 0);
void retranslateUi();
void enableChat();
void disableChat();
};
#endif

View file

@ -110,6 +110,8 @@ void Client::readLine()
emit playerIdReceived(id, data[1]);
} else
emit gameEvent(event);
} else if (prefix == "chat") {
emit chatEvent(ChatEventData(line));
} else if (prefix == "resp") {
if (values.size() != 2) {
// XXX
@ -231,6 +233,26 @@ void Client::ping()
cmd("ping");
}
PendingCommand *Client::chatListChannels()
{
return cmd("chat_list_channels");
}
PendingCommand *Client::chatJoinChannel(const QString &name)
{
return cmd(QString("chat_join_channel|%1").arg(name));
}
PendingCommand *Client::chatLeaveChannel(const QString &name)
{
return cmd(QString("chat_leave_channel|%1").arg(name));
}
PendingCommand *Client::chatSay(const QString &channel, const QString &s)
{
return cmd(QString("chat_say|%1|%2").arg(channel).arg(s));
}
PendingCommand *Client::listGames()
{
return cmd("list_games");

View file

@ -33,6 +33,7 @@ private:
QString cmd;
int msgid;
int time;
QString extraData;
signals:
void finished(ServerResponse resp);
void timeout();
@ -42,6 +43,8 @@ public slots:
public:
int getMsgId() const { return msgid; }
QString getCmd() const { return cmd; }
const QString &getExtraData() const { return extraData; }
void setExtraData(const QString &_extraData) { extraData = _extraData; }
PendingCommand(const QString &_cmd, int _msgid, QObject *parent = 0);
};
@ -57,6 +60,7 @@ signals:
void responseReceived(int msgid, ServerResponse resp);
void playerIdReceived(int id, QString name);
void gameEvent(const ServerEventData &msg);
void chatEvent(const ChatEventData &msg);
void serverTimeout();
void logSocketError(const QString &errorString);
void serverError(ServerResponse resp);
@ -90,6 +94,10 @@ public:
void connectToServer(const QString &hostname, unsigned int port, const QString &_playerName, const QString &_password);
void disconnectFromServer();
public slots:
PendingCommand *chatListChannels();
PendingCommand *chatJoinChannel(const QString &name);
PendingCommand *chatLeaveChannel(const QString &name);
PendingCommand *chatSay(const QString &name, const QString &s);
PendingCommand *listGames();
PendingCommand *listPlayers();
PendingCommand *createGame(const QString &description, const QString &password, unsigned int maxPlayers);

View file

@ -300,9 +300,12 @@ void Game::gameEvent(const ServerEventData &msg)
p->gameEvent(msg);
break;
}
case eventInvalid:
case eventInvalid: {
qDebug("Unhandled global event");
}
default: {
}
}
}
}

View file

@ -9,8 +9,8 @@ GameSelector::GameSelector(Client *_client, QWidget *parent)
gameListModel = new GamesModel(this);
gameListView->setModel(gameListModel);
createButton = new QPushButton(tr("C&reate"));
joinButton = new QPushButton(tr("&Join"));
createButton = new QPushButton;
joinButton = new QPushButton;
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(createButton);
@ -20,6 +20,7 @@ GameSelector::GameSelector(Client *_client, QWidget *parent)
mainLayout->addWidget(gameListView);
mainLayout->addLayout(buttonLayout);
retranslateUi();
setLayout(mainLayout);
setMinimumWidth(gameListView->columnWidth(0) * gameListModel->columnCount());
@ -27,18 +28,13 @@ GameSelector::GameSelector(Client *_client, QWidget *parent)
connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate()));
connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin()));
connect(client, SIGNAL(gameListEvent(ServerGame *)), gameListModel, SLOT(updateGameList(ServerGame *)));
connect(client, SIGNAL(statusChanged(ProtocolStatus)), this, SLOT(statusChanged(ProtocolStatus)));
client->listGames();
}
void GameSelector::actCreate()
{
DlgCreateGame dlg(client, this);
if (dlg.exec())
deleteLater();
disableGameList();
}
void GameSelector::actRefresh()
@ -46,19 +42,13 @@ void GameSelector::actRefresh()
client->listGames();
}
void GameSelector::statusChanged(ProtocolStatus status)
{
if (status == StatusDisconnected)
deleteLater();
}
void GameSelector::checkResponse(ServerResponse response)
{
createButton->setEnabled(true);
joinButton->setEnabled(true);
if (response == RespOk)
deleteLater();
disableGameList();
else {
QMessageBox::critical(this, tr("Error"), tr("XXX"));
return;
@ -84,3 +74,23 @@ void GameSelector::actJoin()
createButton->setEnabled(false);
joinButton->setEnabled(false);
}
void GameSelector::enableGameList()
{
connect(client, SIGNAL(gameListEvent(ServerGame *)), gameListModel, SLOT(updateGameList(ServerGame *)));
client->listGames();
show();
}
void GameSelector::disableGameList()
{
disconnect(client, 0, this, 0);
hide();
gameListModel->cleanList();
}
void GameSelector::retranslateUi()
{
createButton->setText(tr("C&reate"));
joinButton->setText(tr("&Join"));
}

View file

@ -13,12 +13,14 @@ class GameSelector : public QWidget {
Q_OBJECT
public:
GameSelector(Client *_client, QWidget *parent = 0);
void enableGameList();
void disableGameList();
void retranslateUi();
private slots:
void actCreate();
void actRefresh();
void actJoin();
void checkResponse(ServerResponse response);
void statusChanged(ProtocolStatus status);
private:
Client *client;

View file

@ -69,8 +69,10 @@ void GamesModel::updateGameList(ServerGame *game)
void GamesModel::cleanList()
{
beginRemoveRows(QModelIndex(), 0, gameList.size() - 1);
QListIterator<ServerGame *> i(gameList);
while (i.hasNext())
delete i.next();
gameList.clear();
endRemoveRows();
}

View file

@ -16,11 +16,11 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
ServerGame *getGame(int row);
void cleanList();
public slots:
void updateGameList(ServerGame *game);
private:
QList<ServerGame *> gameList;
void cleanList();
};
#endif

View file

@ -64,6 +64,8 @@ Player::Player(const QString &_name, int _id, QPointF _base, bool _local, CardDa
libraryMenu->addAction(aDrawCard);
libraryMenu->addAction(aDrawCards);
libraryMenu->addSeparator();
libraryMenu->addAction(aShuffle);
libraryMenu->addSeparator();
libraryMenu->addAction(aViewLibrary);
libraryMenu->addAction(aViewTopCards);
zones.findZone("deck")->setMenu(libraryMenu, aDrawCard);

View file

@ -3,49 +3,58 @@
// Message structure for server events:
// {"private","public"}|PlayerId|PlayerName|EventType|EventData
const int event_count = 21;
const event_string event_strings[event_count] = {
{eventPlayerId, "player_id"},
{eventSay, "say"},
{eventName, "name"},
{eventJoin, "join"},
{eventLeave, "leave"},
{eventReadyStart, "ready_start"},
{eventSetupZones, "setup_zones"},
{eventGameStart, "game_start"},
{eventShuffle, "shuffle"},
{eventRollDice, "roll_dice"},
{eventDraw, "draw"},
{eventMoveCard, "move_card"},
{eventCreateToken, "create_token"},
{eventSetCardAttr, "set_card_attr"},
{eventAddCounter, "add_counter"},
{eventSetCounter, "set_counter"},
{eventDelCounter, "del_counter"},
{eventSetActivePlayer, "set_active_player"},
{eventSetActivePhase, "set_active_phase"},
{eventDumpZone, "dump_zone"},
{eventStopDumpZone, "stop_dump_zone"}
};
QHash<QString, ServerEventType> ServerEventData::eventHash;
ServerEventData::ServerEventData(const QString &line)
{
QStringList values = line.split("|");
if (eventHash.isEmpty()) {
eventHash.insert("player_id", eventPlayerId);
eventHash.insert("say", eventSay);
eventHash.insert("name", eventName);
eventHash.insert("join", eventJoin);
eventHash.insert("leave", eventLeave);
eventHash.insert("ready_start", eventReadyStart);
eventHash.insert("setup_zones", eventSetupZones);
eventHash.insert("game_start", eventGameStart);
eventHash.insert("shuffle", eventShuffle);
eventHash.insert("roll_dice", eventRollDice);
eventHash.insert("draw", eventDraw);
eventHash.insert("move_card", eventMoveCard);
eventHash.insert("create_token", eventCreateToken);
eventHash.insert("set_card_attr", eventSetCardAttr);
eventHash.insert("add_counter", eventAddCounter);
eventHash.insert("set_counter", eventSetCounter);
eventHash.insert("del_counter", eventDelCounter);
eventHash.insert("set_active_player", eventSetActivePlayer);
eventHash.insert("set_active_phase", eventSetActivePhase);
eventHash.insert("dump_zone", eventDumpZone);
eventHash.insert("stop_dump_zone", eventStopDumpZone);
}
QStringList values = line.split('|');
IsPublic = !values.takeFirst().compare("public");
PlayerId = values.takeFirst().toInt();
PlayerName = values.takeFirst();
QString type = values.takeFirst();
bool found = false;
for (int i = 0; i < event_count; i++)
if (!type.compare(event_strings[i].str)) {
EventType = event_strings[i].type;
found = true;
break;
}
if (!found)
EventType = eventInvalid;
EventType = eventHash.value(values.takeFirst(), eventInvalid);
EventData = values;
}
QHash<QString, ChatEventType> ChatEventData::eventHash;
ChatEventData::ChatEventData(const QString &line)
{
if (eventHash.isEmpty()) {
eventHash.insert("list_channels", eventChatListChannels);
eventHash.insert("join_channel", eventChatJoinChannel);
eventHash.insert("list_players", eventChatListPlayers);
eventHash.insert("leave_channel", eventChatLeaveChannel);
eventHash.insert("say", eventChatSay);
eventHash.insert("server_message", eventChatServerMessage);
}
QStringList values = line.split('|');
values.removeFirst();
eventType = eventHash.value(values.takeFirst(), eventChatInvalid);
eventData = values;
}

View file

@ -2,6 +2,7 @@
#define SERVEREVENTDATA_H
#include <QStringList>
#include <QHash>
enum ServerEventType {
eventInvalid,
@ -28,16 +29,10 @@ enum ServerEventType {
eventStopDumpZone
};
struct event_string {
ServerEventType type;
char *str;
};
extern const int event_count;
extern const event_string event_strings[];
class ServerEventData {
private:
static QHash<QString, ServerEventType> eventHash;
bool IsPublic;
int PlayerId;
QString PlayerName;
@ -47,9 +42,31 @@ public:
ServerEventData(const QString &line);
bool getPublic() const { return IsPublic; }
int getPlayerId() const { return PlayerId; }
QString getPlayerName() const { return PlayerName; }
const QString &getPlayerName() const { return PlayerName; }
ServerEventType getEventType() const { return EventType; }
QStringList getEventData() const { return EventData; }
const QStringList &getEventData() const { return EventData; }
};
enum ChatEventType {
eventChatInvalid,
eventChatListChannels,
eventChatJoinChannel,
eventChatListPlayers,
eventChatLeaveChannel,
eventChatSay,
eventChatServerMessage
};
class ChatEventData {
private:
static QHash<QString, ChatEventType> eventHash;
ChatEventType eventType;
QStringList eventData;
public:
ChatEventData(const QString &line);
ChatEventType getEventType() const { return eventType; }
const QStringList &getEventData() const { return eventData; }
};
#endif

View file

@ -35,6 +35,7 @@
#include "zoneviewzone.h"
#include "zoneviewwidget.h"
#include "zoneviewlayout.h"
#include "chatwidget.h"
void MainWindow::hoverCard(QString name)
{
@ -69,7 +70,9 @@ void MainWindow::statusChanged(ProtocolStatus _status)
aRestartGame->setEnabled(false);
aLeaveGame->setEnabled(false);
phasesToolbar->setActivePhase(-1);
phasesToolbar->setEnabled(false);
phasesToolbar->hide();
gameSelector->disableGameList();
chatWidget->disableChat();
emit logDisconnected();
break;
case StatusLoggingIn:
@ -84,14 +87,17 @@ void MainWindow::statusChanged(ProtocolStatus _status)
aRestartGame->setEnabled(false);
aLeaveGame->setEnabled(false);
phasesToolbar->setActivePhase(-1);
phasesToolbar->setEnabled(false);
phasesToolbar->hide();
GameSelector *gameSelector = new GameSelector(client);
viewLayout->insertWidget(0, gameSelector);
view->hide();
gameSelector->enableGameList();
chatWidget->enableChat();
break;
}
case StatusPlaying:
phasesToolbar->setEnabled(true);
chatWidget->disableChat();
phasesToolbar->show();
view->show();
break;
default:
break;
@ -211,6 +217,8 @@ void MainWindow::retranslateUi()
sayLabel->setText(tr("&Say:"));
cardInfo->retranslateUi();
chatWidget->retranslateUi();
gameSelector->retranslateUi();
}
void MainWindow::createActions()
@ -272,6 +280,7 @@ MainWindow::MainWindow(QTranslator *_translator, QWidget *parent)
scene = new QGraphicsScene(0, 0, 1096, 1160, this);
view = new GameView(scene);
view->hide();
// view->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
@ -285,6 +294,12 @@ MainWindow::MainWindow(QTranslator *_translator, QWidget *parent)
sayLabel = new QLabel;
sayEdit = new QLineEdit;
sayLabel->setBuddy(sayEdit);
client = new Client(this);
gameSelector = new GameSelector(client);
gameSelector->hide();
chatWidget = new ChatWidget(client);
chatWidget->hide();
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(sayLabel);
@ -296,10 +311,12 @@ MainWindow::MainWindow(QTranslator *_translator, QWidget *parent)
verticalLayout->addLayout(hLayout);
viewLayout = new QVBoxLayout;
viewLayout->addWidget(gameSelector);
viewLayout->addWidget(chatWidget);
viewLayout->addWidget(view);
phasesToolbar = new PhasesToolbar;
phasesToolbar->setEnabled(false);
phasesToolbar->hide();
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(phasesToolbar);
@ -312,7 +329,6 @@ MainWindow::MainWindow(QTranslator *_translator, QWidget *parent)
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(actSay()));
client = new Client(this);
connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout()));
connect(client, SIGNAL(statusChanged(ProtocolStatus)), this, SLOT(statusChanged(ProtocolStatus)));
connect(client, SIGNAL(playerIdReceived(int, QString)), this, SLOT(playerIdReceived(int, QString)));
@ -334,6 +350,8 @@ MainWindow::MainWindow(QTranslator *_translator, QWidget *parent)
void MainWindow::closeEvent(QCloseEvent */*event*/)
{
delete game;
chatWidget->disableChat();
gameSelector->disableGameList();
}
void MainWindow::changeEvent(QEvent *event)

View file

@ -40,6 +40,8 @@ class ServerZoneCard;
class ZoneViewLayout;
class ZoneViewWidget;
class PhasesToolbar;
class GameSelector;
class ChatWidget;
class MainWindow : public QMainWindow {
Q_OBJECT
@ -80,6 +82,8 @@ private:
QLabel *sayLabel;
QLineEdit *sayEdit;
PhasesToolbar *phasesToolbar;
GameSelector *gameSelector;
ChatWidget *chatWidget;
Client *client;
QGraphicsScene *scene;