Freeciv21
Develop your civilization from humble roots to a global empire
mpgui_qt.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2022 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <fc_config.h>
15 
16 // Qt
17 #include <QApplication>
18 #include <QCloseEvent>
19 #include <QHBoxLayout>
20 #include <QHeaderView>
21 #include <QLabel>
22 #include <QLineEdit>
23 #include <QMainWindow>
24 #include <QMessageBox>
25 #include <QProgressBar>
26 #include <QPushButton>
27 #include <QTableWidget>
28 
29 // utility
30 #include "fcintl.h"
31 // common
32 #include "version.h"
33 
34 // tools
35 #include "download.h"
36 #include "modinst.h"
37 #include "mpcmdline.h"
38 #include "mpdb.h"
39 #include "mpgui_qt_worker.h"
40 
41 #include "mpgui_qt.h"
42 
43 struct fcmp_params fcmp = {
44  QUrl::fromUserInput(QStringLiteral(MODPACK_LIST_URL)), QLatin1String(),
45  QLatin1String()};
46 
47 static mpgui *gui;
48 
49 static mpqt_worker *worker = nullptr;
50 
51 static int mpcount = 0;
52 
53 #define ML_COL_NAME 0
54 #define ML_COL_VER 1
55 #define ML_COL_INST 2
56 #define ML_COL_TYPE 3
57 #define ML_COL_SUBTYPE 4
58 #define ML_COL_LIC 5
59 #define ML_COL_URL 6
60 
61 #define ML_TYPE 7
62 
63 #define ML_COL_COUNT 8
64 
65 static void setup_modpack_list(const QString &name, const QUrl &url,
66  const QString &version,
67  const QString &license,
68  enum modpack_type type,
69  const QString &subtype, const QString &notes);
70 static void msg_callback(const QString &msg);
71 static void msg_callback_thr(const QString &msg);
72 static void progress_callback_thr(int downloaded, int max);
73 
74 static void gui_download_modpack(const QString &url);
75 
79 int main(int argc, char **argv)
80 {
81  QApplication app(argc, argv);
82  QCoreApplication::setApplicationVersion(freeciv21_version());
83  app.setDesktopFileName(QStringLiteral("net.longturn.freeciv21.modpack"));
84 
85  // Load window icons
86  QIcon::setThemeSearchPaths(get_data_dirs() + QIcon::themeSearchPaths());
87  QIcon::setFallbackThemeName(QIcon::themeName());
88  QIcon::setThemeName(QStringLiteral("icons"));
89 
90  qApp->setWindowIcon(QIcon::fromTheme(QStringLiteral("freeciv21-modpack")));
91 
92  // Delegate option parsing to the common function.
93  fcmp_parse_cmdline(app);
94 
95  fcmp_init();
96 
97  // Start
98  mpgui_main *main_window;
99  QWidget *central;
100  const char *errmsg;
101 
103 
104  central = new QWidget;
105  main_window = new mpgui_main(&app, central);
106 
107  main_window->resize(820, 140);
108  main_window->setWindowTitle(
109  QString::fromUtf8(_("Freeciv21 modpack installer (Qt)")));
110 
111  gui = new mpgui;
112 
113  gui->setup(central, &fcmp);
114 
115  main_window->setCentralWidget(central);
116  main_window->setVisible(true);
117 
119  if (errmsg != nullptr) {
120  gui->display_msg(errmsg);
121  }
122 
123  app.exec();
124 
125  if (worker != nullptr) {
126  if (worker->isRunning()) {
127  worker->wait();
128  }
129  delete worker;
130  }
131 
132  delete gui;
133 
134  close_mpdbs();
135 
136  fcmp_deinit();
137 
138  return EXIT_SUCCESS;
139 }
140 
144 static void msg_callback(const QString &msg) { gui->display_msg(msg); }
145 
149 static void msg_callback_thr(const QString &msg)
150 {
151  gui->display_msg_thr(msg);
152 }
153 
157 static void progress_callback_thr(int downloaded, int max)
158 {
159  gui->progress_thr(downloaded, max);
160 }
161 
165 void mpgui::setup(QWidget *central, struct fcmp_params *params)
166 {
167 #define URL_LABEL_TEXT N_("Modpack URL")
168  QVBoxLayout *main_layout = new QVBoxLayout();
169  QHBoxLayout *hl = new QHBoxLayout();
170  QPushButton *install_button =
171  new QPushButton(QString::fromUtf8(_("Install modpack")));
172  QStringList headers;
173  QLabel *URL_label;
174 
175  auto version_label =
176  new QLabel(QString(_("Version %1")).arg(freeciv21_version()));
177  version_label->setAlignment(Qt::AlignHCenter);
178  version_label->setParent(central);
179  version_label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
180  main_layout->addWidget(version_label);
181 
182  mplist_table = new QTableWidget();
183  mplist_table->setSizePolicy(QSizePolicy::MinimumExpanding,
184  QSizePolicy::MinimumExpanding);
185  mplist_table->setColumnCount(ML_COL_COUNT);
186  headers << QString::fromUtf8(_("Name")) << QString::fromUtf8(_("Version"));
187  headers << QString::fromUtf8(_("Installed"))
188  << QString::fromUtf8(Q_("?modpack:Type"));
189  headers << QString::fromUtf8(_("Subtype"))
190  << QString::fromUtf8(_("License"));
191  headers << QString::fromUtf8(_("URL")) << QStringLiteral("typeint");
192  mplist_table->setHorizontalHeaderLabels(headers);
193  mplist_table->verticalHeader()->setVisible(false);
194  mplist_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
195  mplist_table->setSelectionBehavior(QAbstractItemView::SelectRows);
196  mplist_table->setSelectionMode(QAbstractItemView::SingleSelection);
197  mplist_table->hideColumn(ML_TYPE);
198 
199  connect(mplist_table, &QTableWidget::cellClicked, this,
201  connect(mplist_table, &QAbstractItemView::doubleClicked, this,
203  connect(this, &mpgui::display_msg_thr_signal, this, &mpgui::display_msg);
204  connect(this, &mpgui::progress_thr_signal, this, &mpgui::progress);
205  connect(this, &mpgui::refresh_list_versions_thr_signal, this,
207 
208  main_layout->addWidget(mplist_table);
209 
210  URL_label = new QLabel(QString::fromUtf8(_(URL_LABEL_TEXT)));
211  URL_label->setParent(central);
212  hl->addWidget(URL_label);
213 
214  URLedit = new QLineEdit(central);
215  if (params->autoinstall == nullptr) {
216  URLedit->setText(DEFAULT_URL_START);
217  } else {
218  URLedit->setText(params->autoinstall);
219  }
220  URLedit->setFocus();
221 
222  connect(URLedit, &QLineEdit::returnPressed, this, &mpgui::URL_given);
223 
224  hl->addWidget(URLedit);
225  main_layout->addLayout(hl);
226 
227  connect(install_button, &QAbstractButton::pressed, this,
229  main_layout->addWidget(install_button);
230 
231  bar = new QProgressBar(central);
232  main_layout->addWidget(bar);
233 
234  msg_dspl = new QLabel(QString::fromUtf8(_("Select modpack to install")));
235  msg_dspl->setParent(central);
236  main_layout->addWidget(msg_dspl);
237 
238  msg_dspl->setAlignment(Qt::AlignHCenter);
239 
240  central->setLayout(main_layout);
241 }
242 
246 void mpgui::display_msg(const QString &msg)
247 {
248  QByteArray msg_bytes = msg.toLocal8Bit();
249 
250  qDebug("%s", msg_bytes.data());
251  msg_dspl->setText(msg);
252 }
253 
257 void mpgui::display_msg_thr(const QString &msg)
258 {
259  emit display_msg_thr_signal(msg);
260 }
261 
265 void mpgui::progress(int downloaded, int max)
266 {
267  bar->setMaximum(max);
268  bar->setValue(downloaded);
269 }
270 
274 void mpgui::progress_thr(int downloaded, int max)
275 {
276  emit progress_thr_signal(downloaded, max);
277 }
278 
282 static void gui_download_modpack(const QString &URL)
283 {
284  if (worker != nullptr) {
285  if (worker->isRunning()) {
286  gui->display_msg(_("Another download already active"));
287  return;
288  }
289  } else {
290  worker = new mpqt_worker;
291  }
292 
293  worker->download(QUrl::fromUserInput(URL), gui, &fcmp, msg_callback_thr,
295 }
296 
301 
306 {
307  for (int i = 0; i < mpcount; i++) {
308  QString name_str;
309  int type_int;
310  enum modpack_type type;
311  QByteArray name_bytes;
312 
313  name_str = mplist_table->item(i, ML_COL_NAME)->text();
314  type_int = mplist_table->item(i, ML_TYPE)->text().toInt();
315  type = (enum modpack_type) type_int;
316  name_bytes = name_str.toUtf8();
317 
318  auto tmp = mpdb_installed_version(qUtf8Printable(name_bytes), type);
319  QString new_inst = tmp ? tmp : _("Not installed");
320  delete[] tmp;
321 
322  mplist_table->item(i, ML_COL_INST)->setText(new_inst);
323  }
324 
325  mplist_table->resizeColumnsToContents();
326 }
327 
332 {
334 }
335 
339 void mpgui::setup_list(const QString &name, const QUrl &url,
340  const QString &version, const QString &license,
341  enum modpack_type type, const QString &subtype,
342  const QString &notes)
343 {
344  // TRANS: Unknown modpack type
345  QString type_str =
346  modpack_type_is_valid(type) ? (modpack_type_name(type)) : _("?");
347 
348  // TRANS: License of modpack is not known
349  QString lic_str = license.isEmpty() ? Q_("?license:Unknown") : license;
350 
351  const char *tmp = mpdb_installed_version(qUtf8Printable(name), type);
352  QString inst_str = tmp ? tmp : _("Not installed");
353  delete[] tmp;
354 
355  QString type_nbr;
356  QTableWidgetItem *item;
357 
358  mplist_table->setRowCount(mpcount + 1);
359 
360  item = new QTableWidgetItem(name);
361  item->setToolTip(notes);
362  mplist_table->setItem(mpcount, ML_COL_NAME, item);
363  item = new QTableWidgetItem(version);
364  item->setToolTip(notes);
365  mplist_table->setItem(mpcount, ML_COL_VER, item);
366  item = new QTableWidgetItem(inst_str);
367  item->setToolTip(notes);
368  mplist_table->setItem(mpcount, ML_COL_INST, item);
369  item = new QTableWidgetItem(type_str);
370  item->setToolTip(notes);
371  mplist_table->setItem(mpcount, ML_COL_TYPE, item);
372  item = new QTableWidgetItem(subtype);
373  item->setToolTip(notes);
375  item = new QTableWidgetItem(lic_str);
376  item->setToolTip(notes);
377  mplist_table->setItem(mpcount, ML_COL_LIC, item);
378  item = new QTableWidgetItem(url.toDisplayString());
379  item->setToolTip(notes);
380  mplist_table->setItem(mpcount, ML_COL_URL, item);
381 
382  type_nbr.setNum(type);
383  item = new QTableWidgetItem(type_nbr);
384  item->setToolTip(notes);
385  mplist_table->setItem(mpcount, ML_TYPE, item);
386 
387  mplist_table->resizeColumnsToContents();
388  mpcount++;
389 }
390 
394 static void setup_modpack_list(const QString &name, const QUrl &url,
395  const QString &version,
396  const QString &license,
397  enum modpack_type type,
398  const QString &subtype, const QString &notes)
399 {
400  // Just call setup_list for gui singleton
401  gui->setup_list(name, url, version, license, type, subtype, notes);
402 }
403 
407 void mpgui::row_selected(int row, int column)
408 {
409  QString URL = mplist_table->item(row, ML_COL_URL)->text();
410 
411  URLedit->setText(URL);
412 }
413 
417 void mpgui::row_download(const QModelIndex &index)
418 {
419  QString URL = mplist_table->item(index.row(), ML_COL_URL)->text();
420 
421  URLedit->setText(URL);
422 
423  URL_given();
424 }
425 
429 mpgui_main::mpgui_main(QApplication *qapp_in, QWidget *central_in)
430  : QMainWindow()
431 {
432  qapp = qapp_in;
433  central = central_in;
434 }
435 
440 {
441  QMessageBox ask(central);
442  int ret;
443 
444  ask.setText(_(
445  "Modpack installation in progress.\nAre you sure you want to quit?"));
446  ask.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
447  ask.setDefaultButton(QMessageBox::No);
448  ask.setIcon(QMessageBox::Warning);
449  ask.setWindowTitle(_("Quit?"));
450  ret = ask.exec();
451 
452  switch (ret) {
453  case QMessageBox::Cancel:
454  return;
455  break;
456  case QMessageBox::Ok:
457  qapp->quit();
458  break;
459  }
460 }
461 
465 void mpgui_main::closeEvent(QCloseEvent *event)
466 {
467  if (worker != nullptr && worker->isRunning()) {
468  // Download in progress. Confirm quit from user.
470  event->ignore();
471  }
472 }
void popup_quit_dialog()
Open dialog to confirm that user wants to quit modpack installer.
Definition: mpgui_qt.cpp:439
QApplication * qapp
Definition: mpgui_qt.h:37
mpgui_main(QApplication *qapp_in, QWidget *central_in)
Main window constructor.
Definition: mpgui_qt.cpp:429
QWidget * central
Definition: mpgui_qt.h:38
void closeEvent(QCloseEvent *event) override
User clicked windows close button.
Definition: mpgui_qt.cpp:465
Definition: mpgui_qt.h:44
void refresh_list_versions_thr()
Refresh display of modpack list modpack versions from another thread.
Definition: mpgui_qt.cpp:331
void row_selected(int, int)
User activated another table row.
Definition: mpgui_qt.cpp:407
QLineEdit * URLedit
Definition: mpgui_qt.h:73
void row_download(const QModelIndex &)
User activated another table row.
Definition: mpgui_qt.cpp:417
void display_msg_thr_signal(QString msg)
void refresh_list_versions_thr_signal()
void URL_given()
User entered URL.
Definition: mpgui_qt.cpp:300
void progress_thr_signal(int downloaded, int max)
QTableWidget * mplist_table
Definition: mpgui_qt.h:76
void progress_thr(int downloaded, int max)
Update progress bar from another thread.
Definition: mpgui_qt.cpp:274
QLabel * msg_dspl
Definition: mpgui_qt.h:74
void refresh_list_versions()
Refresh display of modpack list modpack versions.
Definition: mpgui_qt.cpp:305
void display_msg(const QString &msg)
Display status message.
Definition: mpgui_qt.cpp:246
QProgressBar * bar
Definition: mpgui_qt.h:75
void setup(QWidget *central, struct fcmp_params *fcmp)
Setup GUI object.
Definition: mpgui_qt.cpp:165
void progress(int downloaded, int max)
Update progress bar.
Definition: mpgui_qt.cpp:265
void setup_list(const QString &name, const QUrl &url, const QString &version, const QString &license, enum modpack_type type, const QString &subtype, const QString &notes)
Build main modpack list view.
Definition: mpgui_qt.cpp:339
void display_msg_thr(const QString &msg)
Display status message from another thread.
Definition: mpgui_qt.cpp:257
void download(const QUrl &url, mpgui *gui, fcmp_params *fcmp, const dl_msg_callback &msg_callback, const dl_pb_callback &pb_callback)
Start thread to download and install given modpack.
const char * download_modpack_list(const struct fcmp_params *fcmp, const modpack_list_setup_cb &cb, const dl_msg_callback &mcb)
Download modpack list.
Definition: download.cpp:417
enum event_type event
Definition: events.cpp:68
#define Q_(String)
Definition: fcintl.h:53
#define _(String)
Definition: fcintl.h:50
const char * name
Definition: inputfile.cpp:118
void fcmp_deinit()
Deinitialize modpack installer.
Definition: modinst.cpp:89
void load_install_info_lists(struct fcmp_params *fcmp)
Load all required install info lists.
Definition: modinst.cpp:39
void fcmp_init()
Initialize modpack installer.
Definition: modinst.cpp:77
#define DEFAULT_URL_START
Definition: modinst.h:27
#define MODPACK_LIST_URL
Definition: modinst.h:25
void fcmp_parse_cmdline(const QCoreApplication &app)
Parse commandline parameters.
Definition: mpcmdline.cpp:39
void close_mpdbs()
Close open databases.
Definition: mpdb.cpp:198
const char * mpdb_installed_version(const char *name, enum modpack_type type)
Return version of modpack.
Definition: mpdb.cpp:251
#define ML_COL_SUBTYPE
Definition: mpgui_qt.cpp:57
static mpgui * gui
Definition: mpgui_qt.cpp:47
static int mpcount
Definition: mpgui_qt.cpp:51
#define ML_TYPE
Definition: mpgui_qt.cpp:61
static void progress_callback_thr(int downloaded, int max)
Progress indications from downloader.
Definition: mpgui_qt.cpp:157
int main(int argc, char **argv)
Entry point for whole freeciv-mp-qt program.
Definition: mpgui_qt.cpp:79
static void gui_download_modpack(const QString &url)
Download modpack from given URL.
Definition: mpgui_qt.cpp:282
static void setup_modpack_list(const QString &name, const QUrl &url, const QString &version, const QString &license, enum modpack_type type, const QString &subtype, const QString &notes)
Build main modpack list view.
Definition: mpgui_qt.cpp:394
#define ML_COL_NAME
Definition: mpgui_qt.cpp:53
static void msg_callback(const QString &msg)
Progress indications from downloader.
Definition: mpgui_qt.cpp:144
#define ML_COL_LIC
Definition: mpgui_qt.cpp:58
#define URL_LABEL_TEXT
struct fcmp_params fcmp
Definition: mpgui_qt.cpp:43
static void msg_callback_thr(const QString &msg)
Progress indications from downloader thread.
Definition: mpgui_qt.cpp:149
#define ML_COL_TYPE
Definition: mpgui_qt.cpp:56
static mpqt_worker * worker
Definition: mpgui_qt.cpp:49
#define ML_COL_INST
Definition: mpgui_qt.cpp:55
#define ML_COL_URL
Definition: mpgui_qt.cpp:59
#define ML_COL_VER
Definition: mpgui_qt.cpp:54
#define ML_COL_COUNT
Definition: mpgui_qt.cpp:63
const QStringList & get_data_dirs()
Returns a list of data directory paths, in the order in which they should be searched.
Definition: shared.cpp:533
QString autoinstall
Definition: modinst.h:22
Definition: climisc.h:66
const char * freeciv21_version()
Returns the raw version string.
Definition: version.cpp:29