mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-11 04:23:29 -08:00
[Move refactor] Reparent orphan classes (#6236)
* Move orphaned classes to their correct parent folders. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
1ef07309d6
commit
d9c65d4ae0
143 changed files with 171 additions and 169 deletions
|
|
@ -0,0 +1,368 @@
|
|||
#include "remote_decklist_tree_widget.h"
|
||||
|
||||
#include <QFileIconProvider>
|
||||
#include <QHeaderView>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_deckstorage.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
|
||||
RemoteDeckList_TreeModel::DirectoryNode::DirectoryNode(const QString &_name,
|
||||
RemoteDeckList_TreeModel::DirectoryNode *_parent)
|
||||
: RemoteDeckList_TreeModel::Node(_name, _parent)
|
||||
{
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::DirectoryNode::~DirectoryNode()
|
||||
{
|
||||
clearTree();
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::DirectoryNode::clearTree()
|
||||
{
|
||||
for (int i = 0; i < size(); ++i)
|
||||
delete at(i);
|
||||
clear();
|
||||
}
|
||||
|
||||
QString RemoteDeckList_TreeModel::DirectoryNode::getPath() const
|
||||
{
|
||||
if (parent) {
|
||||
QString parentPath = parent->getPath();
|
||||
if (parentPath.isEmpty())
|
||||
return name;
|
||||
else
|
||||
return parentPath + "/" + name;
|
||||
} else
|
||||
return name;
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::DirectoryNode *RemoteDeckList_TreeModel::DirectoryNode::getNodeByPath(QStringList path)
|
||||
{
|
||||
QString pathItem;
|
||||
if (parent) {
|
||||
if (path.isEmpty())
|
||||
return this;
|
||||
pathItem = path.takeFirst();
|
||||
if (pathItem.isEmpty() && name.isEmpty())
|
||||
return this;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
DirectoryNode *node = dynamic_cast<DirectoryNode *>(at(i));
|
||||
if (!node)
|
||||
continue;
|
||||
if (node->getName() == pathItem)
|
||||
return node->getNodeByPath(path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::FileNode *RemoteDeckList_TreeModel::DirectoryNode::getNodeById(int id) const
|
||||
{
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
DirectoryNode *node = dynamic_cast<DirectoryNode *>(at(i));
|
||||
if (node) {
|
||||
FileNode *result = node->getNodeById(id);
|
||||
if (result)
|
||||
return result;
|
||||
} else {
|
||||
FileNode *file = dynamic_cast<FileNode *>(at(i));
|
||||
if (file->getId() == id)
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::RemoteDeckList_TreeModel(AbstractClient *_client, QObject *parent)
|
||||
: QAbstractItemModel(parent), client(_client)
|
||||
{
|
||||
QFileIconProvider fip;
|
||||
dirIcon = fip.icon(QFileIconProvider::Folder);
|
||||
fileIcon = fip.icon(QFileIconProvider::File);
|
||||
|
||||
root = new DirectoryNode;
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::~RemoteDeckList_TreeModel()
|
||||
{
|
||||
delete root;
|
||||
}
|
||||
|
||||
int RemoteDeckList_TreeModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
DirectoryNode *node = getNode<DirectoryNode *>(parent);
|
||||
if (node)
|
||||
return node->size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RemoteDeckList_TreeModel::columnCount(const QModelIndex & /*parent*/) const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
QVariant RemoteDeckList_TreeModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (index.column() >= 3)
|
||||
return QVariant();
|
||||
|
||||
Node *temp = static_cast<Node *>(index.internalPointer());
|
||||
FileNode *file = dynamic_cast<FileNode *>(temp);
|
||||
if (!file) {
|
||||
DirectoryNode *node = dynamic_cast<DirectoryNode *>(temp);
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return node->getName();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
return index.column() == 0 ? dirIcon : QVariant();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
} else {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return file->getName();
|
||||
case 1:
|
||||
return file->getId();
|
||||
case 2:
|
||||
return file->getUploadTime();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
return index.column() == 0 ? fileIcon : QVariant();
|
||||
case Qt::TextAlignmentRole:
|
||||
return index.column() == 1 ? Qt::AlignRight : Qt::AlignLeft;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariant RemoteDeckList_TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
switch (role) {
|
||||
case Qt::TextAlignmentRole:
|
||||
return section == 1 ? Qt::AlignRight : Qt::AlignLeft;
|
||||
case Qt::DisplayRole: {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Name");
|
||||
case 1:
|
||||
return tr("ID");
|
||||
case 2:
|
||||
return tr("Upload time");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex RemoteDeckList_TreeModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
DirectoryNode *parentNode = getNode<DirectoryNode *>(parent);
|
||||
if (row >= parentNode->size())
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(row, column, parentNode->at(row));
|
||||
}
|
||||
|
||||
QModelIndex RemoteDeckList_TreeModel::parent(const QModelIndex &ind) const
|
||||
{
|
||||
if (!ind.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
return nodeToIndex(static_cast<Node *>(ind.internalPointer())->getParent());
|
||||
}
|
||||
|
||||
Qt::ItemFlags RemoteDeckList_TreeModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return Qt::NoItemFlags;
|
||||
}
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
QModelIndex RemoteDeckList_TreeModel::nodeToIndex(Node *node) const
|
||||
{
|
||||
if (node == nullptr || node == root)
|
||||
return QModelIndex();
|
||||
return createIndex(node->getParent()->indexOf(node), 0, node);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::addFileToTree(const ServerInfo_DeckStorage_TreeItem &file, DirectoryNode *parent)
|
||||
{
|
||||
const ServerInfo_DeckStorage_File &fileInfo = file.file();
|
||||
QDateTime time;
|
||||
time.setSecsSinceEpoch(fileInfo.creation_time());
|
||||
|
||||
beginInsertRows(nodeToIndex(parent), parent->size(), parent->size());
|
||||
parent->append(new FileNode(QString::fromStdString(file.name()), file.id(), time, parent));
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::addFolderToTree(const ServerInfo_DeckStorage_TreeItem &folder, DirectoryNode *parent)
|
||||
{
|
||||
DirectoryNode *newItem = addNamedFolderToTree(QString::fromStdString(folder.name()), parent);
|
||||
const ServerInfo_DeckStorage_Folder &folderInfo = folder.folder();
|
||||
const int folderItemsSize = folderInfo.items_size();
|
||||
for (int i = 0; i < folderItemsSize; ++i) {
|
||||
const ServerInfo_DeckStorage_TreeItem &subItem = folderInfo.items(i);
|
||||
if (subItem.has_folder())
|
||||
addFolderToTree(subItem, newItem);
|
||||
else
|
||||
addFileToTree(subItem, newItem);
|
||||
}
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::DirectoryNode *RemoteDeckList_TreeModel::addNamedFolderToTree(const QString &name,
|
||||
DirectoryNode *parent)
|
||||
{
|
||||
DirectoryNode *newItem = new DirectoryNode(name, parent);
|
||||
beginInsertRows(nodeToIndex(parent), parent->size(), parent->size());
|
||||
parent->append(newItem);
|
||||
endInsertRows();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::removeNode(RemoteDeckList_TreeModel::Node *node)
|
||||
{
|
||||
int ind = node->getParent()->indexOf(node);
|
||||
beginRemoveRows(nodeToIndex(node->getParent()), ind, ind);
|
||||
node->getParent()->removeAt(ind);
|
||||
endRemoveRows();
|
||||
delete node;
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::refreshTree()
|
||||
{
|
||||
PendingCommand *pend = client->prepareSessionCommand(Command_DeckList());
|
||||
connect(pend, &PendingCommand::finished, this, &RemoteDeckList_TreeModel::deckListFinished);
|
||||
|
||||
client->sendCommand(pend);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::clearTree()
|
||||
{
|
||||
beginResetModel();
|
||||
root->clearTree();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeModel::deckListFinished(const Response &r)
|
||||
{
|
||||
const Response_DeckList &resp = r.GetExtension(Response_DeckList::ext);
|
||||
|
||||
clearTree();
|
||||
|
||||
ServerInfo_DeckStorage_TreeItem tempRoot;
|
||||
tempRoot.set_id(0);
|
||||
tempRoot.mutable_folder()->CopyFrom(resp.root());
|
||||
addFolderToTree(tempRoot, root);
|
||||
|
||||
emit treeRefreshed();
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeWidget::RemoteDeckList_TreeWidget(AbstractClient *_client, QWidget *parent) : QTreeView(parent)
|
||||
{
|
||||
treeModel = new RemoteDeckList_TreeModel(_client, this);
|
||||
proxyModel = new QSortFilterProxyModel(this);
|
||||
proxyModel->setSourceModel(treeModel);
|
||||
proxyModel->setDynamicSortFilter(true);
|
||||
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
setModel(proxyModel);
|
||||
connect(treeModel, &RemoteDeckList_TreeModel::treeRefreshed, this, &RemoteDeckList_TreeWidget::expandAll);
|
||||
|
||||
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
setUniformRowHeights(true);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
setSortingEnabled(true);
|
||||
proxyModel->sort(0, Qt::AscendingOrder);
|
||||
header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::Node *RemoteDeckList_TreeWidget::getNode(const QModelIndex &ind) const
|
||||
{
|
||||
return treeModel->getNode<RemoteDeckList_TreeModel::Node *>(proxyModel->mapToSource(ind));
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::Node *RemoteDeckList_TreeWidget::getCurrentItem() const
|
||||
{
|
||||
return getNode(selectionModel()->currentIndex());
|
||||
}
|
||||
|
||||
QList<RemoteDeckList_TreeModel::Node *> RemoteDeckList_TreeWidget::getCurrentSelection() const
|
||||
{
|
||||
auto list = QList<RemoteDeckList_TreeModel::Node *>();
|
||||
for (const auto &row : selectionModel()->selectedRows()) {
|
||||
list << getNode(row);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::DirectoryNode *RemoteDeckList_TreeWidget::getNodeByPath(const QString &path) const
|
||||
{
|
||||
return treeModel->getRoot()->getNodeByPath(path.split("/"));
|
||||
}
|
||||
|
||||
RemoteDeckList_TreeModel::FileNode *RemoteDeckList_TreeWidget::getNodeById(int id) const
|
||||
{
|
||||
return treeModel->getRoot()->getNodeById(id);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeWidget::addFileToTree(const ServerInfo_DeckStorage_TreeItem &file,
|
||||
RemoteDeckList_TreeModel::DirectoryNode *parent)
|
||||
{
|
||||
treeModel->addFileToTree(file, parent);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeWidget::addFolderToTree(const ServerInfo_DeckStorage_TreeItem &folder,
|
||||
RemoteDeckList_TreeModel::DirectoryNode *parent)
|
||||
{
|
||||
treeModel->addFolderToTree(folder, parent);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeWidget::addFolderToTree(const QString &name, RemoteDeckList_TreeModel::DirectoryNode *parent)
|
||||
{
|
||||
treeModel->addNamedFolderToTree(name, parent);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeWidget::removeNode(RemoteDeckList_TreeModel::Node *node)
|
||||
{
|
||||
treeModel->removeNode(node);
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeWidget::refreshTree()
|
||||
{
|
||||
treeModel->refreshTree();
|
||||
}
|
||||
|
||||
void RemoteDeckList_TreeWidget::clearTree()
|
||||
{
|
||||
treeModel->clearTree();
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* @file remote_decklist_tree_widget.h
|
||||
* @ingroup NetworkingWidgets
|
||||
* @ingroup DeckStorageWidgets
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef REMOTEDECKLIST_TREEWIDGET_H
|
||||
#define REMOTEDECKLIST_TREEWIDGET_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDateTime>
|
||||
#include <QTreeView>
|
||||
|
||||
class Response;
|
||||
class AbstractClient;
|
||||
class QSortFilterProxyModel;
|
||||
class ServerInfo_DeckStorage_TreeItem;
|
||||
|
||||
class RemoteDeckList_TreeModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class DirectoryNode;
|
||||
class FileNode;
|
||||
class Node
|
||||
{
|
||||
protected:
|
||||
DirectoryNode *parent;
|
||||
QString name;
|
||||
|
||||
public:
|
||||
explicit Node(const QString &_name, DirectoryNode *_parent = nullptr) : parent(_parent), name(_name)
|
||||
{
|
||||
}
|
||||
virtual ~Node() = default;
|
||||
DirectoryNode *getParent() const
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
QString getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
};
|
||||
class DirectoryNode : public Node, public QList<Node *>
|
||||
{
|
||||
public:
|
||||
explicit DirectoryNode(const QString &_name = QString(), DirectoryNode *_parent = nullptr);
|
||||
~DirectoryNode() override;
|
||||
void clearTree();
|
||||
QString getPath() const;
|
||||
DirectoryNode *getNodeByPath(QStringList path);
|
||||
FileNode *getNodeById(int id) const;
|
||||
};
|
||||
class FileNode : public Node
|
||||
{
|
||||
private:
|
||||
int id;
|
||||
QDateTime uploadTime;
|
||||
|
||||
public:
|
||||
FileNode(const QString &_name, int _id, const QDateTime &_uploadTime, DirectoryNode *_parent = nullptr)
|
||||
: Node(_name, _parent), id(_id), uploadTime(_uploadTime)
|
||||
{
|
||||
}
|
||||
int getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
QDateTime getUploadTime() const
|
||||
{
|
||||
return uploadTime;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> T getNode(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return dynamic_cast<T>(root);
|
||||
return dynamic_cast<T>(static_cast<Node *>(index.internalPointer()));
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractClient *client;
|
||||
DirectoryNode *root;
|
||||
|
||||
QIcon fileIcon, dirIcon;
|
||||
|
||||
QModelIndex nodeToIndex(Node *node) const;
|
||||
signals:
|
||||
void treeRefreshed();
|
||||
private slots:
|
||||
void deckListFinished(const Response &r);
|
||||
|
||||
public:
|
||||
explicit RemoteDeckList_TreeModel(AbstractClient *_client, QObject *parent = nullptr);
|
||||
~RemoteDeckList_TreeModel() override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
DirectoryNode *getRoot() const
|
||||
{
|
||||
return root;
|
||||
}
|
||||
void addFileToTree(const ServerInfo_DeckStorage_TreeItem &file, DirectoryNode *parent);
|
||||
void addFolderToTree(const ServerInfo_DeckStorage_TreeItem &folder, DirectoryNode *parent);
|
||||
DirectoryNode *addNamedFolderToTree(const QString &name, DirectoryNode *parent);
|
||||
void removeNode(Node *node);
|
||||
void refreshTree();
|
||||
void clearTree();
|
||||
};
|
||||
|
||||
class RemoteDeckList_TreeWidget : public QTreeView
|
||||
{
|
||||
private:
|
||||
RemoteDeckList_TreeModel *treeModel;
|
||||
QSortFilterProxyModel *proxyModel;
|
||||
|
||||
public:
|
||||
explicit RemoteDeckList_TreeWidget(AbstractClient *_client, QWidget *parent = nullptr);
|
||||
RemoteDeckList_TreeModel::Node *getNode(const QModelIndex &ind) const;
|
||||
RemoteDeckList_TreeModel::Node *getCurrentItem() const;
|
||||
QList<RemoteDeckList_TreeModel::Node *> getCurrentSelection() const;
|
||||
RemoteDeckList_TreeModel::DirectoryNode *getNodeByPath(const QString &path) const;
|
||||
RemoteDeckList_TreeModel::FileNode *getNodeById(int id) const;
|
||||
void addFileToTree(const ServerInfo_DeckStorage_TreeItem &file, RemoteDeckList_TreeModel::DirectoryNode *parent);
|
||||
void addFolderToTree(const ServerInfo_DeckStorage_TreeItem &folder,
|
||||
RemoteDeckList_TreeModel::DirectoryNode *parent);
|
||||
void addFolderToTree(const QString &name, RemoteDeckList_TreeModel::DirectoryNode *parent);
|
||||
void removeNode(RemoteDeckList_TreeModel::Node *node);
|
||||
void refreshTree();
|
||||
void clearTree();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,383 @@
|
|||
#include "remote_replay_list_tree_widget.h"
|
||||
|
||||
#include <QFileIconProvider>
|
||||
#include <QHeaderView>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||
#include <libcockatrice/protocol/pb/command_replay_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_replay_list.pb.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_replay.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
|
||||
const int RemoteReplayList_TreeModel::numberOfColumns = 6;
|
||||
|
||||
RemoteReplayList_TreeModel::MatchNode::MatchNode(const ServerInfo_ReplayMatch &_matchInfo)
|
||||
: RemoteReplayList_TreeModel::Node(QString::fromStdString(_matchInfo.game_name())), matchInfo(_matchInfo)
|
||||
{
|
||||
for (int i = 0; i < matchInfo.replay_list_size(); ++i)
|
||||
append(new ReplayNode(matchInfo.replay_list(i), this));
|
||||
}
|
||||
|
||||
RemoteReplayList_TreeModel::MatchNode::~MatchNode()
|
||||
{
|
||||
for (int i = 0; i < size(); ++i)
|
||||
delete at(i);
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::MatchNode::updateMatchInfo(const ServerInfo_ReplayMatch &_matchInfo)
|
||||
{
|
||||
matchInfo.MergeFrom(_matchInfo);
|
||||
}
|
||||
|
||||
RemoteReplayList_TreeModel::RemoteReplayList_TreeModel(AbstractClient *_client, QObject *parent)
|
||||
: QAbstractItemModel(parent), client(_client)
|
||||
{
|
||||
QFileIconProvider fip;
|
||||
dirIcon = fip.icon(QFileIconProvider::Folder);
|
||||
fileIcon = fip.icon(QFileIconProvider::File);
|
||||
lockIcon = QPixmap("theme:icons/lock");
|
||||
}
|
||||
|
||||
RemoteReplayList_TreeModel::~RemoteReplayList_TreeModel()
|
||||
{
|
||||
clearAll();
|
||||
}
|
||||
|
||||
int RemoteReplayList_TreeModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid())
|
||||
return replayMatches.size();
|
||||
|
||||
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
|
||||
if (matchNode)
|
||||
return matchNode->size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (index.column() >= numberOfColumns)
|
||||
return QVariant();
|
||||
|
||||
ReplayNode *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
||||
if (replayNode) {
|
||||
const ServerInfo_Replay &replayInfo = replayNode->getReplayInfo();
|
||||
switch (role) {
|
||||
case Qt::TextAlignmentRole:
|
||||
return index.column() == 0 ? Qt::AlignRight : Qt::AlignLeft;
|
||||
case Qt::DisplayRole: {
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return replayInfo.replay_id();
|
||||
case 1:
|
||||
return QString::fromStdString(replayInfo.replay_name());
|
||||
case 5:
|
||||
return replayInfo.duration();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
return index.column() == 0 ? fileIcon : QVariant();
|
||||
}
|
||||
} else {
|
||||
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
|
||||
const ServerInfo_ReplayMatch &matchInfo = matchNode->getMatchInfo();
|
||||
switch (role) {
|
||||
case Qt::TextAlignmentRole:
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
case 5:
|
||||
return Qt::AlignRight;
|
||||
default:
|
||||
return Qt::AlignLeft;
|
||||
}
|
||||
case Qt::DisplayRole: {
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return matchInfo.game_id();
|
||||
case 1:
|
||||
return QString::fromStdString(matchInfo.game_name());
|
||||
case 2: {
|
||||
QStringList playerList;
|
||||
for (int i = 0; i < matchInfo.player_names_size(); ++i)
|
||||
playerList.append(QString::fromStdString(matchInfo.player_names(i)));
|
||||
return playerList.join(", ");
|
||||
}
|
||||
case 4:
|
||||
return QDateTime::fromSecsSinceEpoch(matchInfo.time_started());
|
||||
case 5:
|
||||
return matchInfo.length();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return dirIcon;
|
||||
case 3:
|
||||
return matchInfo.do_not_hide() ? lockIcon : QVariant();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant RemoteReplayList_TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
switch (role) {
|
||||
case Qt::TextAlignmentRole:
|
||||
switch (section) {
|
||||
case 0:
|
||||
case 5:
|
||||
return Qt::AlignRight;
|
||||
default:
|
||||
return Qt::AlignLeft;
|
||||
}
|
||||
case Qt::DisplayRole: {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("ID");
|
||||
case 1:
|
||||
return tr("Name");
|
||||
case 2:
|
||||
return tr("Players");
|
||||
case 3:
|
||||
return tr("Keep");
|
||||
case 4:
|
||||
return tr("Time started");
|
||||
case 5:
|
||||
return tr("Duration (sec)");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex RemoteReplayList_TreeModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
|
||||
if (matchNode) {
|
||||
if (row >= matchNode->size())
|
||||
return QModelIndex();
|
||||
return createIndex(row, column, (void *)matchNode->at(row));
|
||||
} else {
|
||||
if (row >= replayMatches.size())
|
||||
return QModelIndex();
|
||||
return createIndex(row, column, (void *)replayMatches[row]);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex RemoteReplayList_TreeModel::parent(const QModelIndex &ind) const
|
||||
{
|
||||
MatchNode const *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(ind.internalPointer()));
|
||||
if (matchNode)
|
||||
return QModelIndex();
|
||||
else {
|
||||
ReplayNode *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(ind.internalPointer()));
|
||||
return createIndex(replayNode->getParent()->indexOf(replayNode), 0, replayNode->getParent());
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags RemoteReplayList_TreeModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
ServerInfo_Replay const *RemoteReplayList_TreeModel::getReplay(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
|
||||
ReplayNode *node = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
||||
if (!node)
|
||||
return 0;
|
||||
return &node->getReplayInfo();
|
||||
}
|
||||
|
||||
ServerInfo_ReplayMatch const *RemoteReplayList_TreeModel::getReplayMatch(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return nullptr;
|
||||
|
||||
auto *node = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
return &node->getMatchInfo();
|
||||
}
|
||||
|
||||
ServerInfo_ReplayMatch const *RemoteReplayList_TreeModel::getEnclosingReplayMatch(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return nullptr;
|
||||
|
||||
auto *node = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
|
||||
if (!node) {
|
||||
auto *_node = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
||||
if (!_node)
|
||||
return nullptr;
|
||||
return &_node->getParent()->getMatchInfo();
|
||||
}
|
||||
return &node->getMatchInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all items in the model
|
||||
*/
|
||||
void RemoteReplayList_TreeModel::clearAll()
|
||||
{
|
||||
for (int i = 0; i < replayMatches.size(); ++i)
|
||||
delete replayMatches[i];
|
||||
replayMatches.clear();
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::refreshTree()
|
||||
{
|
||||
PendingCommand *pend = client->prepareSessionCommand(Command_ReplayList());
|
||||
connect(pend, &PendingCommand::finished, this, &RemoteReplayList_TreeModel::replayListFinished);
|
||||
|
||||
client->sendCommand(pend);
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::clearTree()
|
||||
{
|
||||
beginResetModel();
|
||||
clearAll();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::addMatchInfo(const ServerInfo_ReplayMatch &matchInfo)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), replayMatches.size(), replayMatches.size());
|
||||
replayMatches.append(new MatchNode(matchInfo));
|
||||
endInsertRows();
|
||||
|
||||
emit treeRefreshed();
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::updateMatchInfo(int gameId, const ServerInfo_ReplayMatch &matchInfo)
|
||||
{
|
||||
for (int i = 0; i < replayMatches.size(); ++i)
|
||||
if (replayMatches[i]->getMatchInfo().game_id() == gameId) {
|
||||
replayMatches[i]->updateMatchInfo(matchInfo);
|
||||
emit dataChanged(createIndex(i, 0, (void *)replayMatches[i]),
|
||||
createIndex(i, numberOfColumns - 1, (void *)replayMatches[i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::removeMatchInfo(int gameId)
|
||||
{
|
||||
for (int i = 0; i < replayMatches.size(); ++i)
|
||||
if (replayMatches[i]->getMatchInfo().game_id() == gameId) {
|
||||
beginRemoveRows(QModelIndex(), i, i);
|
||||
replayMatches.removeAt(i);
|
||||
endRemoveRows();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteReplayList_TreeModel::replayListFinished(const Response &r)
|
||||
{
|
||||
const Response_ReplayList &resp = r.GetExtension(Response_ReplayList::ext);
|
||||
|
||||
beginResetModel();
|
||||
clearAll();
|
||||
|
||||
for (int i = 0; i < resp.match_list_size(); ++i)
|
||||
replayMatches.append(new MatchNode(resp.match_list(i)));
|
||||
|
||||
endResetModel();
|
||||
emit treeRefreshed();
|
||||
}
|
||||
|
||||
RemoteReplayList_TreeWidget::RemoteReplayList_TreeWidget(AbstractClient *_client, QWidget *parent) : QTreeView(parent)
|
||||
{
|
||||
treeModel = new RemoteReplayList_TreeModel(_client, this);
|
||||
proxyModel = new QSortFilterProxyModel(this);
|
||||
proxyModel->setSourceModel(treeModel);
|
||||
proxyModel->setDynamicSortFilter(true);
|
||||
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
setModel(proxyModel);
|
||||
|
||||
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
header()->setStretchLastSection(false);
|
||||
setUniformRowHeights(true);
|
||||
setSortingEnabled(true);
|
||||
proxyModel->sort(0, Qt::AscendingOrder);
|
||||
header()->setSortIndicator(0, Qt::AscendingOrder);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the replay at the given index
|
||||
* @return The replay. Returns nullptr if there is no replay at the index.
|
||||
*/
|
||||
ServerInfo_Replay const *RemoteReplayList_TreeWidget::getReplay(const QModelIndex &ind) const
|
||||
{
|
||||
return treeModel->getReplay(proxyModel->mapToSource(ind));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the replay match at the given index
|
||||
* @return The replay match. Returns nullptr if there is no replay match at the index.
|
||||
*/
|
||||
ServerInfo_ReplayMatch const *RemoteReplayList_TreeWidget::getReplayMatch(const QModelIndex &ind) const
|
||||
{
|
||||
return treeModel->getReplayMatch(proxyModel->mapToSource(ind));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all currently selected replays.
|
||||
* Any selection that isn't a replay file (e.g. a folder) will appear as a nullptr in the list.
|
||||
* Make sure to check the list for nullptr before using it.
|
||||
*
|
||||
* @return A List of pointers to the selected replays, as well as nullptr for any selection that isn't a replay.
|
||||
*/
|
||||
QList<ServerInfo_Replay const *> RemoteReplayList_TreeWidget::getSelectedReplays() const
|
||||
{
|
||||
const auto selection = selectionModel()->selectedRows();
|
||||
auto replays = QList<ServerInfo_Replay const *>();
|
||||
for (const auto &row : selection) {
|
||||
replays << treeModel->getReplay(proxyModel->mapToSource(row));
|
||||
}
|
||||
|
||||
return replays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all currently selected replayMatches.
|
||||
* If a non-folder node is selected, it will return the parent folder of that node.
|
||||
*
|
||||
* @return A Set of pointers to the selected replayMatches.
|
||||
*/
|
||||
QSet<ServerInfo_ReplayMatch const *> RemoteReplayList_TreeWidget::getSelectedReplayMatches() const
|
||||
{
|
||||
const auto selection = selectionModel()->selectedRows();
|
||||
auto replayMatches = QSet<ServerInfo_ReplayMatch const *>();
|
||||
for (const auto &row : selection) {
|
||||
if (const auto replayMatch = treeModel->getEnclosingReplayMatch(proxyModel->mapToSource(row))) {
|
||||
replayMatches << replayMatch;
|
||||
}
|
||||
}
|
||||
|
||||
return replayMatches;
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* @file remote_replay_list_tree_widget.h
|
||||
* @ingroup DeckStorageWidgets
|
||||
* @ingroup Replays
|
||||
* @ingroup NetworkingWidgets
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef REMOTEREPLAYLIST_TREEWIDGET_H
|
||||
#define REMOTEREPLAYLIST_TREEWIDGET_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDateTime>
|
||||
#include <QTreeView>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_replay.pb.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_replay_match.pb.h>
|
||||
|
||||
class Response;
|
||||
class AbstractClient;
|
||||
class QSortFilterProxyModel;
|
||||
|
||||
class RemoteReplayList_TreeModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
class MatchNode;
|
||||
class ReplayNode;
|
||||
class Node
|
||||
{
|
||||
protected:
|
||||
QString name;
|
||||
|
||||
public:
|
||||
explicit Node(const QString &_name) : name(_name)
|
||||
{
|
||||
}
|
||||
virtual ~Node() = default;
|
||||
QString getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
};
|
||||
class MatchNode : public Node, public QList<ReplayNode *>
|
||||
{
|
||||
private:
|
||||
ServerInfo_ReplayMatch matchInfo;
|
||||
|
||||
public:
|
||||
explicit MatchNode(const ServerInfo_ReplayMatch &_matchInfo);
|
||||
~MatchNode() override;
|
||||
void clearTree();
|
||||
const ServerInfo_ReplayMatch &getMatchInfo()
|
||||
{
|
||||
return matchInfo;
|
||||
}
|
||||
void updateMatchInfo(const ServerInfo_ReplayMatch &_matchInfo);
|
||||
};
|
||||
class ReplayNode : public Node
|
||||
{
|
||||
private:
|
||||
MatchNode *parent;
|
||||
ServerInfo_Replay replayInfo;
|
||||
|
||||
public:
|
||||
ReplayNode(const ServerInfo_Replay &_replayInfo, MatchNode *_parent)
|
||||
: Node(QString::fromStdString(_replayInfo.replay_name())), parent(_parent), replayInfo(_replayInfo)
|
||||
{
|
||||
}
|
||||
MatchNode *getParent() const
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
const ServerInfo_Replay &getReplayInfo()
|
||||
{
|
||||
return replayInfo;
|
||||
}
|
||||
};
|
||||
|
||||
AbstractClient *client;
|
||||
QList<MatchNode *> replayMatches;
|
||||
|
||||
QIcon dirIcon, fileIcon, lockIcon;
|
||||
void clearAll();
|
||||
|
||||
static const int numberOfColumns;
|
||||
signals:
|
||||
void treeRefreshed();
|
||||
private slots:
|
||||
void replayListFinished(const Response &r);
|
||||
|
||||
public:
|
||||
explicit RemoteReplayList_TreeModel(AbstractClient *_client, QObject *parent = nullptr);
|
||||
~RemoteReplayList_TreeModel() override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override
|
||||
{
|
||||
return numberOfColumns;
|
||||
}
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
void clearTree();
|
||||
void refreshTree();
|
||||
ServerInfo_Replay const *getReplay(const QModelIndex &index) const;
|
||||
ServerInfo_ReplayMatch const *getReplayMatch(const QModelIndex &index) const;
|
||||
ServerInfo_ReplayMatch const *getEnclosingReplayMatch(const QModelIndex &index) const;
|
||||
void addMatchInfo(const ServerInfo_ReplayMatch &matchInfo);
|
||||
void updateMatchInfo(int gameId, const ServerInfo_ReplayMatch &matchInfo);
|
||||
void removeMatchInfo(int gameId);
|
||||
};
|
||||
|
||||
class RemoteReplayList_TreeWidget : public QTreeView
|
||||
{
|
||||
private:
|
||||
RemoteReplayList_TreeModel *treeModel;
|
||||
QSortFilterProxyModel *proxyModel;
|
||||
|
||||
public:
|
||||
explicit RemoteReplayList_TreeWidget(AbstractClient *_client, QWidget *parent = nullptr);
|
||||
ServerInfo_Replay const *getReplay(const QModelIndex &ind) const;
|
||||
ServerInfo_ReplayMatch const *getReplayMatch(const QModelIndex &ind) const;
|
||||
QList<ServerInfo_Replay const *> getSelectedReplays() const;
|
||||
QSet<ServerInfo_ReplayMatch const *> getSelectedReplayMatches() const;
|
||||
void clearTree()
|
||||
{
|
||||
treeModel->clearTree();
|
||||
}
|
||||
void refreshTree()
|
||||
{
|
||||
treeModel->refreshTree();
|
||||
}
|
||||
void addMatchInfo(const ServerInfo_ReplayMatch &matchInfo)
|
||||
{
|
||||
treeModel->addMatchInfo(matchInfo);
|
||||
}
|
||||
void updateMatchInfo(int gameId, const ServerInfo_ReplayMatch &matchInfo)
|
||||
{
|
||||
treeModel->updateMatchInfo(gameId, matchInfo);
|
||||
}
|
||||
void removeMatchInfo(int gameId)
|
||||
{
|
||||
treeModel->removeMatchInfo(gameId);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue