MainWindow.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <iostream>
  16. #include <sstream>
  17. #include <iomanip>
  18. #include <Qt>
  19. #include <QtCore/QProcess>
  20. #include <QtWidgets/QFileDialog>
  21. #include <QtCore/QDir>
  22. #include <QtCore/QSettings>
  23. #include <QtWidgets/QMessageBox>
  24. #include <QtCore/QTimer>
  25. #include <QtWidgets/QCheckBox>
  26. #include "DataInstaller.h"
  27. #include "MainWindow.h"
  28. #include "ui_MainWindow.h"
  29. /**
  30. * Indicates if an installer has already been created.
  31. */
  32. static bool installer_created = false;
  33. MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), main_window_(new Ui::MainWindow){
  34. main_window_->setupUi(this);
  35. // Goto the data tab by default.
  36. main_window_->tabWidget->setCurrentIndex(0);
  37. // Turn off the launcher tab for now since it dosen't actually work
  38. //main_window_->tabWidget->setTabEnabled(0, false);
  39. InitSettings();
  40. main_window_->btn_vgears_config->setText(settings_->value("ConfigDir").toString());
  41. main_window_->line_data_dst->setText(settings_->value("DataDir").toString());
  42. main_window_->line_vgears_exe->setText(settings_->value("VGearsEXE").toString());
  43. // TODO" Hard coded paths for debugging to save time. Remove them.
  44. main_window_->line_data_src->setText("/home/ivalentin/FF7InstallDisk/");
  45. //main_window_->line_data_dst->setText("/home/ivalentin/.v-gears/data/");
  46. timer_ = new QTimer(this);
  47. connect(timer_, SIGNAL(timeout()), this, SLOT(DoProgress()));
  48. }
  49. MainWindow::~MainWindow(){delete main_window_;}
  50. void MainWindow::InitSettings(void){
  51. bool win = false;
  52. #ifdef Q_OS_WIN
  53. settings_ = new QSettings(
  54. QCoreApplication::applicationDirPath() + "/" + "launcherSettings.ini",
  55. QSettings::IniFormat
  56. );
  57. win = true;
  58. #else
  59. settings_ = new QSettings(
  60. QSettings::NativeFormat,QSettings::UserScope, "v-gears", "launcher", 0
  61. );
  62. #endif
  63. //Check settings.
  64. if (settings_->value("ConfigDir").isNull()){
  65. if (win) settings_->setValue("ConfigDir", QString("%1/v-gears").arg(QDir::homePath()));
  66. else settings_->setValue("ConfigDir", QString("%1/.v-gears").arg(QDir::homePath()));
  67. }
  68. if (settings_->value("DataDir").isNull()){
  69. if (win) settings_->setValue("DataDir",QString("%1/v-gears/data").arg(QDir::homePath()));
  70. else settings_->setValue("DataDir",QString("%1/.v-gears/data").arg(QDir::homePath()));
  71. }
  72. if (settings_->value("VGearsEXE").isNull()){
  73. if (win){
  74. settings_->setValue(
  75. "VGearsEXE",QString("%1/v-gears.exe").arg(QCoreApplication::applicationDirPath())
  76. );
  77. }
  78. else settings_->setValue("VGearsEXE", QString("/usr/games/v-gears"));
  79. }
  80. }
  81. void MainWindow::on_line_vgears_config_editingFinished(){
  82. settings_->setValue("ConfigDir",main_window_->btn_vgears_config->text());
  83. }
  84. void MainWindow::on_btn_vgears_config_clicked(){
  85. QString temp = QFileDialog::getExistingDirectory(
  86. this, tr("Select Location of VGears Configuration Data,"),
  87. settings_->value("ConfigDir").toString()
  88. );
  89. if (!temp.isNull()){
  90. settings_->setValue("ConfigDir", temp);
  91. main_window_->btn_vgears_config->setText(temp);
  92. }
  93. }
  94. void MainWindow::on_line_vgears_exe_editingFinished(){
  95. settings_->setValue("VGearsEXE",main_window_->line_vgears_exe->text());
  96. }
  97. void MainWindow::on_btn_vgears_exe_clicked(){
  98. QString temp = QFileDialog::getOpenFileName(
  99. this, tr("Location of VGears Executable,"), QDir::rootPath()
  100. );
  101. if (!temp.isNull()){
  102. settings_->setValue("VGearsEXE", temp);
  103. main_window_->line_vgears_exe->setText(temp);
  104. }
  105. }
  106. void MainWindow::on_btn_vgears_run_clicked(){
  107. QString configDir(main_window_->btn_vgears_config->text());
  108. QString exe(main_window_->line_vgears_exe->text());
  109. QStringList args;
  110. args.append(
  111. QString("--resources-file=%1/resources.cfg").arg(main_window_->btn_vgears_config->text())
  112. );
  113. args.append(
  114. QString("--config-file=%1/v-gears.cfg").arg(main_window_->btn_vgears_config->text())
  115. );
  116. args.append(
  117. QString("--plugins-file=/%1/plugins.cfg").arg(main_window_->btn_vgears_config->text())
  118. );
  119. // Check that the config dir is set up correctly.
  120. QProcess vGears;
  121. vGears.startDetached(exe,args,configDir);
  122. }
  123. void MainWindow::on_btn_data_src_clicked(){
  124. QString temp = QFileDialog::getExistingDirectory(
  125. this, tr("Location of extracted original game data"), QDir::homePath()
  126. );
  127. main_window_->line_data_src->setText(temp);
  128. }
  129. void MainWindow::on_line_data_dst_editingFinished(){
  130. settings_->setValue("DataDir", main_window_->line_data_dst->text());
  131. }
  132. void MainWindow::on_btn_data_dst_clicked(){
  133. QString temp = QFileDialog::getExistingDirectory(
  134. this, tr("V-Gears data installation directory"), settings_->value("DataDir").toString()
  135. );
  136. if (!temp.isNull()){
  137. settings_->setValue("DataDir",temp);
  138. main_window_->line_data_dst->setText(temp);
  139. }
  140. }
  141. void MainWindow::on_btn_data_run_clicked(){
  142. if (main_window_->line_data_src->text().isEmpty()){
  143. QMessageBox::critical(
  144. this, tr("Input error"),
  145. tr(
  146. "The installation needs the original game data.\n\n"
  147. "Select a directory with the extracted data from Final Fantasy VII "
  148. "(PC version, install disk)."
  149. )
  150. );
  151. }
  152. else if (main_window_->line_data_dst->text().isEmpty())
  153. QMessageBox::critical(this, tr("Output error"), tr("No output path provided"));
  154. else{
  155. // Normalize the paths so its in / format separators.
  156. QString input = QDir::fromNativeSeparators(main_window_->line_data_src->text());
  157. if (!input.endsWith("/")) input += "/";
  158. QString output = QDir::fromNativeSeparators(main_window_->line_data_dst->text());
  159. if (!output.endsWith("/")) output += "/";
  160. // TODO: Enumerate files or find some better way to do this.
  161. const std::vector<std::string> required_files = {
  162. "data/field/char.lgp",
  163. "data/field/flevel.lgp",
  164. "data/kernel/KERNEL.BIN",
  165. "data/menu/menu_us.lgp",
  166. "data/sound/audio.fmt",
  167. "data/sound/audio.dat",
  168. "data/music/music.idx",
  169. "data/midi/midi.lgp",
  170. "data/battle/scene.bin",
  171. "ff7.exe"
  172. };
  173. // Ensure required files are in the input dir
  174. for (auto& file : required_files){
  175. QString full_path = input + QString::fromStdString(file);
  176. if (!QFile::exists(full_path)){
  177. QMessageBox::critical(
  178. this, tr("Missing input file"),
  179. tr(
  180. "Some of the required files were not found among the extracted data.\n\n"
  181. " Make sure that the file '"
  182. ) + file.c_str() + tr("' is in the extracted data.")
  183. );
  184. return;
  185. }
  186. }
  187. if (installer_created){
  188. // Due to the use of singletons, the installer can't be re-run.
  189. // TODO: Verify that this is true, and if so, try to fix it.
  190. QMessageBox::critical(
  191. this, tr("Error"),
  192. tr("Please, fix the errors, and then close the installer before trying again.")
  193. );
  194. return;
  195. }
  196. // Start data conversion
  197. try{
  198. // Parse advanced options.
  199. DataInstaller::AdvancedOptions options;
  200. options.skip_kernel = (Qt::Checked == main_window_->chk_no_kernel->checkState());
  201. options.skip_images = (Qt::Checked == main_window_->chk_no_images->checkState());
  202. options.skip_sounds = (Qt::Checked == main_window_->chk_no_sounds->checkState());
  203. options.skip_music = (Qt::Checked == main_window_->chk_no_music->checkState());
  204. options.skip_fields = (Qt::Checked == main_window_->chk_no_fields->checkState());
  205. options.skip_field_models
  206. = (Qt::Checked == main_window_->chk_no_field_models->checkState());
  207. options.no_ffmpeg = (Qt::Checked == main_window_->chk_no_ffmpeg->checkState());
  208. options.no_timidity = (Qt::Checked == main_window_->chk_no_timidity->checkState());
  209. options.keep_originals = (Qt::Checked == main_window_->chk_keep_original->checkState());
  210. installer_created = true;
  211. installer_ = std::make_unique<DataInstaller>(
  212. QDir::toNativeSeparators(input).toStdString(),
  213. QDir::toNativeSeparators(output).toStdString(),
  214. options,
  215. [this](const std::string log_line, int level, bool as_progress = false){
  216. main_window_->data_log->append(log_line.c_str());
  217. std::cout << log_line << std::endl;
  218. if (as_progress)
  219. main_window_->label_progress->setText(log_line.c_str());
  220. }
  221. );
  222. OnInstallStarted();
  223. }
  224. catch (const std::exception& ex){OnInstallStopped();}
  225. }
  226. }
  227. void MainWindow::on_chk_advanced_options_stateChanged(){
  228. if (main_window_->chk_advanced_options->checkState() == Qt::Checked)
  229. main_window_->advancedOptions->setMaximumHeight(500);
  230. else main_window_->advancedOptions->setMaximumHeight(0);
  231. }
  232. void MainWindow::EnableUi(bool enable){
  233. main_window_->btn_data_run->setEnabled(enable);
  234. main_window_->line_data_src->setEnabled(enable);
  235. main_window_->btn_data_src->setEnabled(enable);
  236. main_window_->line_data_dst->setEnabled(enable);
  237. main_window_->btn_data_dst->setEnabled(enable);
  238. main_window_->data_progress_bar->setValue(0);
  239. if (!enable) timer_->start(0);
  240. else timer_->stop();
  241. }
  242. void MainWindow::OnInstallStarted(){EnableUi(false);}
  243. void MainWindow::OnInstallStopped(){EnableUi(true);}
  244. void MainWindow::DoProgress(){
  245. try{
  246. const float progress = installer_->Progress();
  247. main_window_->data_progress_bar->setValue(std::floor(progress));
  248. std::stringstream stream;
  249. stream << std::fixed << std::setprecision(2) << progress;
  250. stream << "%";
  251. std::string s = stream.str();
  252. main_window_->label_percent->setText(QString::fromUtf8(s.c_str()));
  253. if (progress >= 100) OnInstallStopped();
  254. }
  255. catch (const std::exception& ex){
  256. OnInstallStopped();
  257. QMessageBox::critical(this, tr("Data conversion exception"), ex.what());
  258. }
  259. }