# HG changeset patch # User unc0rr # Date 1558733991 -7200 # Node ID 773beead236f0aea2194dc47348b72a37662cdab # Parent 0730c68fdf9702b3ebdb2aa870082ac5432dfd5d Add handling of some messages, reuse models from the old frontend diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/CMakeLists.txt --- a/qmlfrontend/CMakeLists.txt Fri May 24 22:27:19 2019 +0200 +++ b/qmlfrontend/CMakeLists.txt Fri May 24 23:39:51 2019 +0200 @@ -18,6 +18,8 @@ "engine_interface.h" "preview_acceptor.cpp" "preview_acceptor.h" "net_session.cpp" "net_session.h" + "players_model.cpp" "players_model.h" + "rooms_model.cpp" "rooms_model.h" ) target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Network Qt5::Quick) diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/net_session.cpp --- a/qmlfrontend/net_session.cpp Fri May 24 22:27:19 2019 +0200 +++ b/qmlfrontend/net_session.cpp Fri May 24 23:39:51 2019 +0200 @@ -1,6 +1,14 @@ #include "net_session.h" -NetSession::NetSession(QObject *parent) : QObject(parent) {} +#include "players_model.h" +#include "rooms_model.h" + +NetSession::NetSession(QObject *parent) + : QObject(parent), + m_playersModel(new PlayersListModel()), + m_roomsModel(new RoomsListModel()) {} + +NetSession::~NetSession() { close(); } QUrl NetSession::url() const { return m_url; } @@ -31,6 +39,8 @@ return m_sessionState; } +QString NetSession::room() const { return m_room; } + void NetSession::setUrl(const QUrl &url) { if (m_url == url) return; @@ -52,12 +62,20 @@ emit passwordChanged(m_password); } +void NetSession::setRoom(const QString &room) { + if (m_room == room) return; + + m_room = room; + emit roomChanged(m_room); +} + void NetSession::close() { if (!m_socket.isNull()) { m_socket->disconnectFromHost(); m_socket.clear(); setSessionState(NotConnected); + setRoom({}); } } @@ -182,9 +200,33 @@ void NetSession::handleLeft(const QStringList ¶meters) {} -void NetSession::handleLobbyJoined(const QStringList ¶meters) {} +void NetSession::handleLobbyJoined(const QStringList ¶meters) { + for (auto player : parameters) { + if (player == m_nickname) { + // check if server is authenticated or no authentication was performed at + // all + if (!m_serverAuthHash.isEmpty()) { + emit error(tr("Server authentication error")); + + close(); + } + + setSessionState(Lobby); + } -void NetSession::handleLobbyLeft(const QStringList ¶meters) {} + m_playersModel->addPlayer(player, false); + } +} + +void NetSession::handleLobbyLeft(const QStringList ¶meters) { + if (parameters.length() == 1) { + m_playersModel->removePlayer(parameters[0]); + } else if (parameters.length() == 2) { + m_playersModel->removePlayer(parameters[0], parameters[1]); + } else { + qWarning("Malformed LOBBY:LEFT message"); + } +} void NetSession::handleNick(const QStringList ¶meters) { if (parameters.length()) setNickname(parameters[0]); @@ -206,9 +248,29 @@ void NetSession::handleRoomAbandoned(const QStringList ¶meters) {} -void NetSession::handleRoom(const QStringList ¶meters) {} +void NetSession::handleRoom(const QStringList ¶meters) { + if (parameters.size() == 10 && parameters[0] == "ADD") { + m_roomsModel->addRoom(parameters.mid(1)); + } else if (parameters.length() == 11 && parameters[0] == "UPD") { + m_roomsModel->updateRoom(parameters[1], parameters.mid(2)); -void NetSession::handleRooms(const QStringList ¶meters) {} + // keep track of room name so correct name is displayed + if (m_room == parameters[1]) { + setRoom(parameters[2]); + } + } else if (parameters.size() == 2 && parameters[0] == "DEL") { + m_roomsModel->removeRoom(parameters[1]); + } +} + +void NetSession::handleRooms(const QStringList ¶meters) { + if (parameters.size() % 9) { + qWarning("Net: Malformed ROOMS message"); + return; + } + + m_roomsModel->setRoomsList(parameters); +} void NetSession::handleRoundFinished(const QStringList ¶meters) {} diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/net_session.h --- a/qmlfrontend/net_session.h Fri May 24 22:27:19 2019 +0200 +++ b/qmlfrontend/net_session.h Fri May 24 23:39:51 2019 +0200 @@ -6,6 +6,8 @@ #include #include +class PlayersListModel; +class RoomsListModel; class NetSession : public QObject { Q_OBJECT @@ -18,6 +20,7 @@ Q_PROPERTY(QString nickname READ nickname WRITE setNickname NOTIFY nicknameChanged) Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) Q_PROPERTY(SessionState sessionState READ sessionState NOTIFY sessionStateChanged) + Q_PROPERTY(QString room READ room NOTIFY roomChanged) // clang-format on public: @@ -25,21 +28,23 @@ Q_ENUMS(SessionState) explicit NetSession(QObject *parent = nullptr); + ~NetSession() override; QUrl url() const; QAbstractSocket::SocketState state() const; - Q_INVOKABLE void open(); - QString nickname() const; QString password() const; SessionState sessionState() const; + QString room() const; public slots: + void open(); + void close(); + void setUrl(const QUrl &url); void setNickname(const QString &nickname); void setPassword(const QString &password); - void close(); signals: void urlChanged(const QUrl url); @@ -49,6 +54,7 @@ void sessionStateChanged(SessionState sessionState); void warning(const QString &message); void error(const QString &message); + void roomChanged(const QString &room); private slots: void onReadyRead(); @@ -97,14 +103,21 @@ void send(const QString &message, const QStringList ¶meters); void send(const QStringList &message); void setSessionState(SessionState sessionState); + void setRoom(const QString &room); private: QUrl m_url; QSharedPointer m_socket; + QSharedPointer m_playersModel; + QSharedPointer m_roomsModel; QString m_nickname; QString m_password; QStringList m_buffer; SessionState m_sessionState; + QString m_serverAuthHash; + QString m_room; + + Q_DISABLE_COPY(NetSession) }; #endif // NET_SESSION_H diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/players_model.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmlfrontend/players_model.cpp Fri May 24 23:39:51 2019 +0200 @@ -0,0 +1,364 @@ +#include +#include +#include +#include +#include +#include + +#include "players_model.h" + +PlayersListModel::PlayersListModel(QObject *parent) + : QAbstractListModel(parent) { + m_fontInRoom = QFont(); + m_fontInRoom.setItalic(true); +} + +int PlayersListModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + else + return m_data.size(); +} + +QVariant PlayersListModel::data(const QModelIndex &index, int role) const { + if (!index.isValid() || index.row() < 0 || index.row() >= rowCount() || + index.column() != 0) + return QVariant(QVariant::Invalid); + + return m_data.at(index.row()).value(role); +} + +bool PlayersListModel::setData(const QModelIndex &index, const QVariant &value, + int role) { + if (!index.isValid() || index.row() < 0 || index.row() >= rowCount() || + index.column() != 0) + return false; + + m_data[index.row()].insert(role, value); + + emit dataChanged(index, index); + + return true; +} + +bool PlayersListModel::insertRows(int row, int count, + const QModelIndex &parent) { + if (parent.isValid() || row > rowCount() || row < 0 || count < 1) + return false; + + beginInsertRows(parent, row, row + count - 1); + + for (int i = 0; i < count; ++i) m_data.insert(row, DataEntry()); + + endInsertRows(); + + return true; +} + +bool PlayersListModel::removeRows(int row, int count, + const QModelIndex &parent) { + if (parent.isValid() || row + count > rowCount() || row < 0 || count < 1) + return false; + + beginRemoveRows(parent, row, row + count - 1); + + for (int i = 0; i < count; ++i) m_data.removeAt(row); + + endRemoveRows(); + + return true; +} + +QModelIndex PlayersListModel::nicknameIndex(const QString &nickname) { + QModelIndexList mil = + match(index(0), Qt::DisplayRole, nickname, 1, Qt::MatchExactly); + + if (mil.size() > 0) + return mil[0]; + else + return QModelIndex(); +} + +void PlayersListModel::addPlayer(const QString &nickname, bool notify) { + insertRow(rowCount()); + + QModelIndex mi = index(rowCount() - 1); + setData(mi, nickname); + + checkFriendIgnore(mi); + + emit nickAddedLobby(nickname, notify); +} + +void PlayersListModel::removePlayer(const QString &nickname, + const QString &msg) { + if (msg.isEmpty()) + emit nickRemovedLobby(nickname, QString()); + else + emit nickRemovedLobby(nickname, msg); + + QModelIndex mi = nicknameIndex(nickname); + + if (mi.isValid()) removeRow(mi.row()); +} + +void PlayersListModel::playerJoinedRoom(const QString &nickname, bool notify) { + QModelIndex mi = nicknameIndex(nickname); + + if (mi.isValid()) { + setData(mi, true, RoomFilterRole); + updateIcon(mi); + updateSortData(mi); + } + + emit nickAdded(nickname, notify); +} + +void PlayersListModel::playerLeftRoom(const QString &nickname) { + emit nickRemoved(nickname); + + QModelIndex mi = nicknameIndex(nickname); + + if (mi.isValid()) { + setData(mi, false, RoomFilterRole); + setData(mi, false, RoomAdmin); + setData(mi, false, Ready); + setData(mi, false, InGame); + updateIcon(mi); + } +} + +void PlayersListModel::setFlag(const QString &nickname, StateFlag flagType, + bool isSet) { + if (flagType == Friend) { + if (isSet) + m_friendsSet.insert(nickname.toLower()); + else + m_friendsSet.remove(nickname.toLower()); + + // FIXME: set proper file name + // saveSet(m_friendsSet, "friends"); + } else if (flagType == Ignore) { + if (isSet) + m_ignoredSet.insert(nickname.toLower()); + else + m_ignoredSet.remove(nickname.toLower()); + + // FIXME: set proper file name + // saveSet(m_ignoredSet, "ignore"); + } + + QModelIndex mi = nicknameIndex(nickname); + + if (mi.isValid()) { + setData(mi, isSet, flagType); + + if (flagType == Friend || flagType == ServerAdmin || flagType == Ignore || + flagType == RoomAdmin) + updateSortData(mi); + + updateIcon(mi); + } +} + +bool PlayersListModel::isFlagSet(const QString &nickname, StateFlag flagType) { + QModelIndex mi = nicknameIndex(nickname); + + if (mi.isValid()) + return mi.data(flagType).toBool(); + else if (flagType == Friend) + return isFriend(nickname); + else if (flagType == Ignore) + return isIgnored(nickname); + else + return false; +} + +void PlayersListModel::resetRoomFlags() { + for (int i = rowCount() - 1; i >= 0; --i) { + QModelIndex mi = index(i); + + if (mi.data(RoomFilterRole).toBool()) { + setData(mi, false, RoomFilterRole); + setData(mi, false, RoomAdmin); + setData(mi, false, Ready); + setData(mi, false, InGame); + + updateSortData(mi); + updateIcon(mi); + } + } +} + +void PlayersListModel::updateIcon(const QModelIndex &index) { + quint32 iconNum = 0; + + QList flags; + flags << index.data(Ready).toBool() << index.data(ServerAdmin).toBool() + << index.data(RoomAdmin).toBool() << index.data(Registered).toBool() + << index.data(Friend).toBool() << index.data(Ignore).toBool() + << index.data(InGame).toBool() << index.data(RoomFilterRole).toBool() + << index.data(InRoom).toBool() << index.data(Contributor).toBool(); + + for (int i = flags.size() - 1; i >= 0; --i) + if (flags[i]) iconNum |= 1 << i; + + if (m_icons().contains(iconNum)) { + setData(index, m_icons().value(iconNum), Qt::DecorationRole); + } else { + QPixmap result(24, 16); + result.fill(Qt::transparent); + + QPainter painter(&result); + + if (index.data(RoomFilterRole).toBool()) { + if (index.data(InGame).toBool()) { + painter.drawPixmap(0, 0, 16, 16, QPixmap(":/res/chat/ingame.png")); + } else { + if (index.data(Ready).toBool()) + painter.drawPixmap(0, 0, 16, 16, QPixmap(":/res/chat/lamp.png")); + else + painter.drawPixmap(0, 0, 16, 16, QPixmap(":/res/chat/lamp_off.png")); + } + } else { // we're in lobby + if (!index.data(InRoom).toBool()) + painter.drawPixmap(0, 0, 16, 16, QPixmap(":/res/Flake.png")); + } + + QString mainIconName(":/res/chat/"); + + if (index.data(ServerAdmin).toBool()) + mainIconName += "serveradmin"; + else { + if (index.data(RoomAdmin).toBool()) + mainIconName += "roomadmin"; + else + mainIconName += "hedgehog"; + + if (index.data(Contributor).toBool()) mainIconName += "contributor"; + } + + if (!index.data(Registered).toBool()) mainIconName += "_gray"; + + painter.drawPixmap(8, 0, 16, 16, QPixmap(mainIconName + ".png")); + + if (index.data(Ignore).toBool()) + painter.drawPixmap(8, 0, 16, 16, QPixmap(":/res/chat/ignore.png")); + else if (index.data(Friend).toBool()) + painter.drawPixmap(8, 0, 16, 16, QPixmap(":/res/chat/friend.png")); + + painter.end(); + + QIcon icon(result); + + setData(index, icon, Qt::DecorationRole); + m_icons().insert(iconNum, icon); + } + + if (index.data(Ignore).toBool()) + setData(index, QColor(Qt::gray), Qt::ForegroundRole); + else if (index.data(Friend).toBool()) + setData(index, QColor(Qt::green), Qt::ForegroundRole); + else + setData(index, QBrush(QColor(0xff, 0xcc, 0x00)), Qt::ForegroundRole); +} + +QHash &PlayersListModel::m_icons() { + static QHash iconsCache; + + return iconsCache; +} + +void PlayersListModel::updateSortData(const QModelIndex &index) { + QString result = + QString("%1%2%3%4%5%6") + // room admins go first, then server admins, then friends + .arg(1 - index.data(RoomAdmin).toInt()) + .arg(1 - index.data(ServerAdmin).toInt()) + .arg(1 - index.data(Friend).toInt()) + // ignored at bottom + .arg(index.data(Ignore).toInt()) + // keep nicknames starting from non-letter character at bottom within + // group assume there are no empty nicks in list + .arg(index.data(Qt::DisplayRole).toString().at(0).isLetter() ? 0 : 1) + // sort ignoring case + .arg(index.data(Qt::DisplayRole).toString().toLower()); + + setData(index, result, SortRole); +} + +void PlayersListModel::setNickname(const QString &nickname) { + m_nickname = nickname; + + // FIXME: set proper file names + // loadSet(m_friendsSet, "friends"); + // loadSet(m_ignoredSet, "ignore"); + + for (int i = rowCount() - 1; i >= 0; --i) checkFriendIgnore(index(i)); +} + +bool PlayersListModel::isFriend(const QString &nickname) { + return m_friendsSet.contains(nickname.toLower()); +} + +bool PlayersListModel::isIgnored(const QString &nickname) { + return m_ignoredSet.contains(nickname.toLower()); +} + +void PlayersListModel::checkFriendIgnore(const QModelIndex &mi) { + setData(mi, isFriend(mi.data().toString()), Friend); + setData(mi, isIgnored(mi.data().toString()), Ignore); + + updateIcon(mi); + updateSortData(mi); +} + +void PlayersListModel::loadSet(QSet &set, const QString &fileName) { + set.clear(); + + QFile txt(fileName); + if (!txt.open(QIODevice::ReadOnly)) return; + + QTextStream stream(&txt); + stream.setCodec("UTF-8"); + + while (!stream.atEnd()) { + QString str = stream.readLine(); + if (str.startsWith(";") || str.isEmpty()) continue; + + set.insert(str.trimmed()); + } + + txt.close(); +} + +void PlayersListModel::saveSet(const QSet &set, + const QString &fileName) { + qDebug("saving set"); + + QFile txt(fileName); + + // list empty? => rather have no file for the list than an empty one + if (set.isEmpty()) { + if (txt.exists()) { + // try to remove file, if successful we're done here. + if (txt.remove()) return; + } else + // there is no file + return; + } + + if (!txt.open(QIODevice::WriteOnly | QIODevice::Truncate)) return; + + QTextStream stream(&txt); + stream.setCodec("UTF-8"); + + stream << "; this list is used by Hedgewars - do not edit it unless you know " + "what you're doing!" + << endl; + + foreach (const QString &nick, set.values()) + stream << nick << endl; + + txt.close(); +} diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/players_model.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmlfrontend/players_model.h Fri May 24 23:39:51 2019 +0200 @@ -0,0 +1,83 @@ +#ifndef PLAYERSLISTMODEL_H +#define PLAYERSLISTMODEL_H + +#include +#include +#include +#include +#include +#include + +class PlayersListModel : public QAbstractListModel { + Q_OBJECT + + public: + enum StateFlag { + Ready = Qt::UserRole, + ServerAdmin = Qt::UserRole + 1, + RoomAdmin = Qt::UserRole + 2, + Registered = Qt::UserRole + 3, + Friend = Qt::UserRole + 4, + Ignore = Qt::UserRole + 5, + InGame = Qt::UserRole + 6, + InRoom = Qt::UserRole + 7, + Contributor = Qt::UserRole + 8 + // if you add a role that will affect the player icon, + // then also add it to the flags Qlist in updateIcon()! + }; + + enum SpecialRoles { + SortRole = Qt::UserRole + 100, + RoomFilterRole = Qt::UserRole + 101 + }; + + explicit PlayersListModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::DisplayRole) override; + + void setFlag(const QString &nickname, StateFlag flagType, bool isSet); + bool isFlagSet(const QString &nickname, StateFlag flagType); + + bool insertRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + + QModelIndex nicknameIndex(const QString &nickname); + + public slots: + void addPlayer(const QString &nickname, bool notify); + void removePlayer(const QString &nickname, const QString &msg = QString()); + void playerJoinedRoom(const QString &nickname, bool notify); + void playerLeftRoom(const QString &nickname); + void resetRoomFlags(); + void setNickname(const QString &nickname); + + signals: + void nickAdded(const QString &nick, bool notifyNick); + void nickRemoved(const QString &nick); + void nickAddedLobby(const QString &nick, bool notifyNick); + void nickRemovedLobby(const QString &nick, const QString &message); + + private: + QHash &m_icons(); + using DataEntry = QHash; + QList m_data; + QSet m_friendsSet, m_ignoredSet; + QString m_nickname; + QFont m_fontInRoom; + + void updateIcon(const QModelIndex &index); + void updateSortData(const QModelIndex &index); + void loadSet(QSet &set, const QString &fileName); + void saveSet(const QSet &set, const QString &fileName); + void checkFriendIgnore(const QModelIndex &mi); + bool isFriend(const QString &nickname); + bool isIgnored(const QString &nickname); +}; + +#endif // PLAYERSLISTMODEL_H diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/rooms_model.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmlfrontend/rooms_model.cpp Fri May 24 23:39:51 2019 +0200 @@ -0,0 +1,231 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2015 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief RoomsListModel class implementation + */ + +#include +#include +#include + +#include "rooms_model.h" + +RoomsListModel::RoomsListModel(QObject *parent) + : QAbstractTableModel(parent), c_nColumns(9) { + m_headerData = QStringList(); + m_headerData << tr("In progress"); + m_headerData << tr("Room Name"); + //: Caption of the column for the number of connected clients in the list of + // rooms + m_headerData << tr("C"); + //: Caption of the column for the number of teams in the list of rooms + m_headerData << tr("T"); + m_headerData << tr("Owner"); + m_headerData << tr("Map"); + m_headerData << tr("Script"); + m_headerData << tr("Rules"); + m_headerData << tr("Weapons"); + + // m_staticMapModel = DataManager::instance().staticMapModel(); + // m_missionMapModel = DataManager::instance().missionMapModel(); +} + +QVariant RoomsListModel::headerData(int section, Qt::Orientation orientation, + int role) const { + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + else + return QVariant(m_headerData.at(section)); +} + +int RoomsListModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + else + return m_data.size(); +} + +int RoomsListModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + else + return c_nColumns; +} + +QVariant RoomsListModel::data(const QModelIndex &index, int role) const { + int column = index.column(); + int row = index.row(); + + // invalid index + if (!index.isValid()) return QVariant(); + + // invalid row + if ((row < 0) || (row >= m_data.size())) return QVariant(); + + // invalid column + if ((column < 0) || (column >= c_nColumns)) return QVariant(); + + // not a role we have data for + if (role != Qt::DisplayRole) + // only custom-align counters + if ((role != Qt::TextAlignmentRole) || + ((column != PlayerCountColumn) && (column != TeamCountColumn))) + // only decorate name column + if ((role != Qt::DecorationRole) || (column != NameColumn)) + // only dye map column + if ((role != Qt::ForegroundRole) || (column != MapColumn)) + return QVariant(); + + // decorate room name based on room state + if (role == Qt::DecorationRole) { + const QIcon roomBusyIcon(":/res/iconDamage.png"); + const QIcon roomBusyIconGreen(":/res/iconDamageLockG.png"); + const QIcon roomBusyIconRed(":/res/iconDamageLockR.png"); + const QIcon roomWaitingIcon(":/res/iconTime.png"); + const QIcon roomWaitingIconGreen(":/res/iconTimeLockG.png"); + const QIcon roomWaitingIconRed(":/res/iconTimeLockR.png"); + + QString flags = m_data.at(row).at(StateColumn); + + if (flags.contains("g")) { + if (flags.contains("j")) + return QVariant(roomBusyIconRed); + else if (flags.contains("p")) + return QVariant(roomBusyIconGreen); + else + return QVariant(roomBusyIcon); + } else { + if (flags.contains("j")) + return QVariant(roomWaitingIconRed); + else if (flags.contains("p")) + return QVariant(roomWaitingIconGreen); + else + return QVariant(roomWaitingIcon); + } + } + + QString content = m_data.at(row).at(column); + + if (role == Qt::DisplayRole) { + // display room names + if (column == 5) { + // special names + if (content[0] == '+') { + if (content == "+rnd+") return tr("Random Map"); + if (content == "+maze+") return tr("Random Maze"); + if (content == "+perlin+") return tr("Random Perlin"); + if (content == "+drawn+") return tr("Hand-drawn"); + if (content == "+forts+") return tr("Forts"); + } + + // prefix ? if map not available + /*if (!m_staticMapModel->mapExists(content) && + !m_missionMapModel->mapExists(content)) + return QString("? %1").arg(content);*/ + } + + return content; + } + + // dye map names red if map not available + /*if (role == Qt::ForegroundRole) { + if (content == "+rnd+" || content == "+maze+" || content == "+perlin+" || + content == "+drawn+" || content == "+forts+" || + m_staticMapModel->mapExists(content) || + m_missionMapModel->mapExists(content)) + return QVariant(); + else + return QBrush(QColor("darkred")); + }*/ + + if (role == Qt::TextAlignmentRole) { + return (int)(Qt::AlignHCenter | Qt::AlignVCenter); + } + + Q_ASSERT(false); + return QVariant(); +} + +void RoomsListModel::setRoomsList(const QStringList &rooms) { + beginResetModel(); + + m_data.clear(); + + int nRooms = rooms.size(); + + for (int i = 0; i < nRooms; i += c_nColumns) { + QStringList l; + l.reserve(c_nColumns); + + for (int t = 0; t < c_nColumns; t++) { + l.append(rooms[i + t]); + } + + m_data.append(l); + } + + endResetModel(); +} + +void RoomsListModel::addRoom(const QStringList &info) { + beginInsertRows(QModelIndex(), 0, 0); + + m_data.prepend(info); + + endInsertRows(); +} + +int RoomsListModel::rowOfRoom(const QString &name) { + int size = m_data.size(); + + if (size < 1) return -1; + + int i = 0; + + // search for record with matching room name + while (m_data[i].at(NameColumn) != name) { + i++; + if (i >= size) return -1; + } + + return i; +} + +void RoomsListModel::removeRoom(const QString &name) { + int i = rowOfRoom(name); + + if (i < 0) return; + + beginRemoveRows(QModelIndex(), i, i); + + m_data.removeAt(i); + + endRemoveRows(); +} + +void RoomsListModel::updateRoom(const QString &name, const QStringList &info) { + int i = rowOfRoom(name); + + if (i < 0) return; + + m_data[i] = info; + + emit dataChanged(index(i, 0), index(i, columnCount(QModelIndex()) - 1)); +} diff -r 0730c68fdf97 -r 773beead236f qmlfrontend/rooms_model.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmlfrontend/rooms_model.h Fri May 24 23:39:51 2019 +0200 @@ -0,0 +1,69 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2015 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief RoomsListModel class definition + */ + +#ifndef HEDGEWARS_ROOMSLISTMODEL_H +#define HEDGEWARS_ROOMSLISTMODEL_H + +#include +#include + +class RoomsListModel : public QAbstractTableModel { + Q_OBJECT + public: + // if you add a column here, also incr. c_nColumns in constructor + // also adjust header in constructor to changes + enum Column { + StateColumn, + NameColumn, + PlayerCountColumn, + TeamCountColumn, + OwnerColumn, + MapColumn, + SchemeColumn, + WeaponsColumn + }; + + explicit RoomsListModel(QObject *parent = 0); + + QVariant headerData(int section, Qt::Orientation orientation, + int role) const override; + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + + public slots: + void setRoomsList(const QStringList &rooms); + void addRoom(const QStringList &info); + void removeRoom(const QString &name); + void updateRoom(const QString &name, const QStringList &info); + int rowOfRoom(const QString &name); + + private: + const int c_nColumns; + QList m_data; + QStringList m_headerData; + // MapModel * m_staticMapModel; + // MapModel * m_missionMapModel; +}; + +#endif // HEDGEWARS_ROOMSLISTMODEL_H