Added server list context menu, ... (#835)

* Added server list context menu, ...

Resolve #832, #560

* The demo server listing now always appears at the top for consistency.

* Add a context menu to server listing.
Only appears during favorite server listing. Requires a valid item under cursor. Cannot be the demo server item.

* Add a new UI element: `remove_from_fav`
Only appears during favorite server listing. Require a selection to remove. Cannot be the demo server.

Uses `removefromfav.png` and `removefromfav_pressed.png` images as textures.

* Favorite servers are now loaded whenever the Lobby is created in addition to refresh and server listing switch.

* `serverlist.txt` is now renamed to `(deprecated)serverlist.txt` if read from.

* Updated comments

* Typos
This commit is contained in:
Leifa♥ 2022-07-31 04:57:01 +02:00 committed by GitHub
parent 14731a0fca
commit 1cfbfd51a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 203 additions and 83 deletions

View File

@ -131,11 +131,14 @@ public:
///////////////////////////////////////////
void set_favorite_list();
void load_favorite_list();
void save_favorite_list();
QVector<server_type> &get_favorite_list() { return favorite_list; }
// Adds the server to favorite_servers.ini
void add_favorite_server(int p_server);
void remove_favorite_server(int p_server);
void prompt_remove_favorite_server(int p_server);
void set_server_list(QVector<server_type> &servers) { server_list = servers; }
QVector<server_type> &get_server_list() { return server_list; }
@ -331,13 +334,24 @@ public:
// Append to the currently open demo file if there is one
void append_to_demofile(QString packet_string);
// Returns the contents of serverlist.txt
QVector<server_type> read_serverlist_txt();
/**
* @brief Reads favorite_servers.ini and returns a list of servers.
*
* The demo server entry is always present at the top of the list.
*
* If the server list returned was to be empty (exluding the demo server entry),
* will return a list of servers from the legacy serverlist.txt file.
*
* @return A list of servers.
*/
QVector<server_type> read_favorite_servers();
/**
* @brief Migrates the favorite serverlist format from txt to ini.
* @brief Reads serverlist.txt and returns a list of servers.
*
* @return A list of servers.
*/
void migrate_serverlist_txt(QFile &p_serverlist_txt);
QVector<server_type> read_legacy_favorite_servers();
// Returns the value of p_identifier in the design.ini file in p_design_path
QString read_design_ini(QString p_identifier, VPath p_design_path);

View File

@ -67,6 +67,7 @@ private:
AOButton *ui_refresh;
AOButton *ui_add_to_fav;
AOButton *ui_remove_from_fav;
AOButton *ui_connect;
QLabel *ui_version;
@ -99,12 +100,15 @@ private slots:
void on_refresh_released();
void on_add_to_fav_pressed();
void on_add_to_fav_released();
void on_remove_from_fav_pressed();
void on_remove_from_fav_released();
void on_connect_pressed();
void on_connect_released();
void on_about_clicked();
void on_settings_clicked();
void on_server_list_clicked(QTreeWidgetItem *p_item, int column);
void on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column);
void on_server_list_context_menu_requested(const QPoint &point);
void on_server_search_edited(QString p_text);
};

View File

@ -51,6 +51,7 @@ void AOApplication::construct_lobby()
return;
}
load_favorite_list();
w_lobby = new Lobby(this);
lobby_constructed = true;
@ -125,9 +126,34 @@ QString AOApplication::get_version_string()
void AOApplication::reload_theme() { current_theme = read_theme(); }
void AOApplication::set_favorite_list()
void AOApplication::load_favorite_list()
{
favorite_list = read_serverlist_txt();
favorite_list = read_favorite_servers();
}
void AOApplication::save_favorite_list()
{
QSettings favorite_servers_ini(get_base_path() + "favorite_servers.ini", QSettings::IniFormat);
favorite_servers_ini.setIniCodec("UTF-8");
favorite_servers_ini.clear();
// skip demo server entry, demo server entry is always at index 0
for(int i = 1; i < favorite_list.size(); ++i) {
auto fav_server = favorite_list.at(i);
favorite_servers_ini.beginGroup(QString::number(i));
favorite_servers_ini.setValue("name", fav_server.name);
favorite_servers_ini.setValue("address", fav_server.ip);
favorite_servers_ini.setValue("port", fav_server.port);
favorite_servers_ini.setValue("desc", fav_server.desc);
if (fav_server.socket_type == TCP) {
favorite_servers_ini.setValue("protocol", "tcp");
} else {
favorite_servers_ini.setValue("protocol", "ws");
}
favorite_servers_ini.endGroup();
}
favorite_servers_ini.sync();
}
QString AOApplication::get_current_char()
@ -142,25 +168,21 @@ void AOApplication::add_favorite_server(int p_server)
{
if (p_server < 0 || p_server >= server_list.size())
return;
favorite_list.append(server_list.at(p_server));
save_favorite_list();
}
server_type fav_server = server_list.at(p_server);
QSettings l_favorite_ini(get_base_path() + "favorite_servers.ini", QSettings::IniFormat);
QString l_new_group = QString::number(l_favorite_ini.childGroups().size());
l_favorite_ini.setIniCodec("UTF-8");
void AOApplication::remove_favorite_server(int p_server)
{
if (p_server < 0 || p_server >= favorite_list.size())
return;
favorite_list.removeAt(p_server);
save_favorite_list();
}
l_favorite_ini.beginGroup(l_new_group);
l_favorite_ini.setValue("name", fav_server.name);
l_favorite_ini.setValue("address", fav_server.ip);
l_favorite_ini.setValue("port", fav_server.port);
l_favorite_ini.setValue("desc", fav_server.desc);
void AOApplication::prompt_remove_favorite_server(int p_server)
{
if (fav_server.socket_type == TCP) {
l_favorite_ini.setValue("protocol", "tcp");
}
else {
l_favorite_ini.setValue("protocol", "ws");
}
l_favorite_ini.sync();
}
void AOApplication::server_disconnected()

View File

@ -6,14 +6,14 @@
#include "demoserver.h"
#include "networkmanager.h"
#include <QAction>
#include <QImageReader>
#include <QMenu>
Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
{
ao_app = p_ao_app;
//
this->setWindowTitle(tr("Attorney Online %1").arg(ao_app->applicationVersion()));
this->setWindowIcon(QIcon(":/logo.png"));
this->setWindowFlags( (this->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMaximizeButtonHint);
@ -28,6 +28,9 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
ui_refresh->setObjectName("ui_refresh");
ui_add_to_fav = new AOButton(this, ao_app);
ui_add_to_fav->setObjectName("ui_add_to_fav");
ui_remove_from_fav = new AOButton(this, ao_app);
ui_remove_from_fav->setObjectName("ui_remove_from_fav");
ui_remove_from_fav->hide();
ui_connect = new AOButton(this, ao_app);
ui_connect->setObjectName("ui_connect");
ui_version = new QLabel(this);
@ -45,6 +48,7 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
ui_server_list->setColumnWidth(0, 0);
ui_server_list->setIndentation(0);
ui_server_list->setObjectName("ui_server_list");
ui_server_list->setContextMenuPolicy(Qt::CustomContextMenu);
ui_server_search = new QLineEdit(this);
ui_server_search->setFrame(false);
@ -79,6 +83,10 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
&Lobby::on_add_to_fav_pressed);
connect(ui_add_to_fav, &AOButton::released, this,
&Lobby::on_add_to_fav_released);
connect(ui_remove_from_fav, &AOButton::pressed, this,
&Lobby::on_remove_from_fav_pressed);
connect(ui_remove_from_fav, &AOButton::released, this,
&Lobby::on_remove_from_fav_released);
connect(ui_connect, &AOButton::pressed, this, &Lobby::on_connect_pressed);
connect(ui_connect, &AOButton::released, this, &Lobby::on_connect_released);
connect(ui_about, &AOButton::clicked, this, &Lobby::on_about_clicked);
@ -87,6 +95,8 @@ Lobby::Lobby(AOApplication *p_ao_app) : QMainWindow()
&Lobby::on_server_list_clicked);
connect(ui_server_list, &QTreeWidget::itemDoubleClicked,
this, &Lobby::on_server_list_doubleclicked);
connect(ui_server_list, &QTreeWidget::customContextMenuRequested, this,
&Lobby::on_server_list_context_menu_requested);
connect(ui_server_search, &QLineEdit::textChanged, this,
&Lobby::on_server_search_edited);
connect(ui_cancel, &AOButton::clicked, ao_app, &AOApplication::loading_cancelled);
@ -145,6 +155,9 @@ void Lobby::set_widgets()
set_size_and_pos(ui_add_to_fav, "add_to_fav");
ui_add_to_fav->set_image("addtofav");
set_size_and_pos(ui_remove_from_fav, "remove_from_fav");
ui_remove_from_fav->set_image("removefromfav");
set_size_and_pos(ui_connect, "connect");
ui_connect->set_image("connect");
@ -300,6 +313,8 @@ void Lobby::on_public_servers_clicked()
{
ui_public_servers->set_image("publicservers_selected");
ui_favorites->set_image("favorites");
ui_add_to_fav->show();
ui_remove_from_fav->hide();
reset_selection();
@ -310,12 +325,14 @@ void Lobby::on_public_servers_clicked()
void Lobby::on_favorites_clicked()
{
ui_favorites->set_image("favorites_selected");
ui_public_servers->set_image("publicservers");
ui_favorites->set_image("favorites_selected");
ui_add_to_fav->hide();
ui_remove_from_fav->show();
reset_selection();
ao_app->set_favorite_list();
ao_app->load_favorite_list();
public_servers_selected = false;
@ -342,7 +359,7 @@ void Lobby::on_refresh_released()
ao_app->net_manager->get_server_list(std::bind(&Lobby::list_servers, this));
get_motd();
} else {
ao_app->set_favorite_list();
ao_app->load_favorite_list();
list_favorites();
}
}
@ -363,6 +380,25 @@ void Lobby::on_add_to_fav_released()
}
}
void Lobby::on_remove_from_fav_pressed()
{
ui_remove_from_fav->set_image("removefromfav_pressed");
}
void Lobby::on_remove_from_fav_released()
{
ui_remove_from_fav->set_image("removefromfav");
if (public_servers_selected) {
return;
}
int selection = get_selected_server();
if (selection > 0) {
ao_app->remove_favorite_server(selection);
list_favorites();
}
}
void Lobby::on_connect_pressed() { ui_connect->set_image("connect_pressed"); }
void Lobby::on_connect_released()
@ -479,6 +515,31 @@ void Lobby::on_server_list_doubleclicked(QTreeWidgetItem *p_item, int column)
//on_connect_released();
}
void Lobby::on_server_list_context_menu_requested(const QPoint &point)
{
if (public_servers_selected) {
return;
}
auto *item = ui_server_list->itemAt(point);
if (item == nullptr) {
qInfo() << "no favorite server item; skipping context menu";
return;
}
const int server_index = item->data(0, Qt::DisplayRole).toInt();
if (server_index == 0) {
qInfo() << "demo server has no context menu to display";
return;
}
auto *menu = new QMenu(this);
menu->addAction(tr("Remove"), ao_app, [this,server_index](){
ao_app->remove_favorite_server(server_index);
list_favorites();
});
menu->popup(ui_server_list->mapToGlobal(point));
}
void Lobby::on_server_search_edited(QString p_text)
{
// Iterate through all QTreeWidgetItem items

View File

@ -243,78 +243,97 @@ bool AOApplication::append_to_file(QString p_text, QString p_file,
return false;
}
QVector<server_type> AOApplication::read_serverlist_txt()
QVector<server_type> AOApplication::read_favorite_servers()
{
QVector<server_type> f_server_list;
QFile serverlist_txt(get_base_path() + "serverlist.txt");
QFile serverlist_ini(get_base_path() + "favorite_servers.ini");
if (serverlist_txt.exists() && !serverlist_ini.exists()) {
migrate_serverlist_txt(serverlist_txt);
}
if (serverlist_ini.exists()) {
QSettings l_favorite_ini(get_base_path() + "favorite_servers.ini", QSettings::IniFormat);
l_favorite_ini.setIniCodec("UTF-8");
for(QString &fav_index: l_favorite_ini.childGroups()) {
server_type f_server;
l_favorite_ini.beginGroup(fav_index);
f_server.ip = l_favorite_ini.value("address", "127.0.0.1").toString();
f_server.port = l_favorite_ini.value("port", 27016).toInt();
f_server.name = l_favorite_ini.value("name", "Missing Name").toString();
f_server.desc = l_favorite_ini.value("desc", "No description").toString();
f_server.socket_type = to_connection_type.value(l_favorite_ini.value("protocol", "tcp").toString());
f_server_list.append(f_server);
l_favorite_ini.endGroup();
}
}
QVector<server_type> serverlist;
// demo server is always at the top
server_type demo_server;
demo_server.ip = "127.0.0.1";
demo_server.port = 99999;
demo_server.name = tr("Demo playback");
demo_server.desc = tr("Play back demos you have previously recorded");
f_server_list.append(demo_server);
serverlist.append(demo_server);
return f_server_list;
QString fav_servers_ini_path(get_base_path() + "favorite_servers.ini");
if (!QFile::exists(fav_servers_ini_path)) {
qWarning() << "failed to locate favorite_servers.ini, falling back to legacy serverlist.txt";
serverlist += read_legacy_favorite_servers();
}
else {
QSettings fav_servers_ini(fav_servers_ini_path, QSettings::IniFormat);
fav_servers_ini.setIniCodec("UTF-8");
auto grouplist = fav_servers_ini.childGroups();
{ // remove all negative and non-numbers
auto filtered_grouplist = grouplist;
for (const QString &group : qAsConst(grouplist)) {
bool ok = false;
const int l_num = group.toInt(&ok);
if (ok && l_num >= 0) {
continue;
}
filtered_grouplist.append(group);
}
std::sort(filtered_grouplist.begin(), filtered_grouplist.end(), [](const auto &a, const auto &b) -> bool {
return a.toInt() < b.toInt();
});
grouplist = std::move(filtered_grouplist);
}
for(const QString &group: qAsConst(grouplist)) {
server_type f_server;
fav_servers_ini.beginGroup(group);
f_server.ip = fav_servers_ini.value("address", "127.0.0.1").toString();
f_server.port = fav_servers_ini.value("port", 27016).toInt();
f_server.name = fav_servers_ini.value("name", "Missing Name").toString();
f_server.desc = fav_servers_ini.value("desc", "No description").toString();
f_server.socket_type = to_connection_type.value(fav_servers_ini.value("protocol", "tcp").toString());
serverlist.append(std::move(f_server));
fav_servers_ini.endGroup();
}
}
return serverlist;
}
void AOApplication::migrate_serverlist_txt(QFile &p_serverlist_txt)
QVector<server_type> AOApplication::read_legacy_favorite_servers()
{
// We migrate our legacy serverlist.txt to a QSettings object.
// Then we write it to disk.
QSettings l_settings(get_base_path() + "favorite_servers.ini", QSettings::IniFormat);
l_settings.setIniCodec("UTF-8");
if (p_serverlist_txt.open(QIODevice::ReadOnly)) {
QTextStream l_favorite_textstream(&p_serverlist_txt);
l_favorite_textstream.setCodec("UTF-8");
int l_entry_index = 0;
QVector<server_type> serverlist;
while (!l_favorite_textstream.atEnd()) {
QString l_favorite_line = l_favorite_textstream.readLine();
QStringList l_line_contents = l_favorite_line.split(":");
QFile serverlist_txt(get_base_path() + "serverlist.txt");
if (!serverlist_txt.exists()) {
qWarning() << "serverlist.txt does not exist";
} else if (!serverlist_txt.open(QIODevice::ReadOnly)) {
qWarning() << "failed to open serverlist.txt";
} else {
QTextStream stream(&serverlist_txt);
stream.setCodec("UTF-8");
if (l_line_contents.size() >= 3) {
l_settings.beginGroup(QString::number(l_entry_index));
l_settings.setValue("name", l_line_contents.at(2));
l_settings.setValue("address", l_line_contents.at(0));
l_settings.setValue("port", l_line_contents.at(1));
while (!stream.atEnd())
{
QStringList contents = stream.readLine().split(":");
if (l_line_contents.size() >= 4) {
l_settings.setValue("protocol", l_line_contents.at(3));
}
else {
l_settings.setValue("protocol","tcp");
}
l_settings.endGroup();
l_entry_index++;
int item_count = contents.size();
if (item_count < 3 || item_count > 4) {
continue;
}
server_type server;
server.ip = contents.at(0);
server.port = contents.at(1).toInt();
server.name = contents.at(2);
if (item_count == 4) {
server.socket_type = connection_type(contents.at(3).toInt());
} else {
server.socket_type = TCP;
}
serverlist.append(std::move(server));
}
l_settings.sync();
serverlist_txt.close();
}
p_serverlist_txt.close();
p_serverlist_txt.rename(get_base_path() + "serverlist_deprecated.txt");
return serverlist;
}
QString AOApplication::read_design_ini(QString p_identifier,