1 /*
2  * Copyright (C) 2014-2019 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus Quest Editor is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Solarus Quest Editor is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include "widgets/package_dialog.h"
18 #include "editor_settings.h"
19 #include "quest.h"
20 #include "ui_package_dialog.h"
21 
22 #include <QFileDialog>
23 
24 /* In terms of implementation, this class wraps four states and handles the
25  * transitions
26  *
27  * 0. selection: Choose the package location and name.
28  *    You can cancel the operation (close) or go ahead to 1.
29  * 1. ongoing: Tells you the operation is in progress.
30  *    You can cancel the operation, it goes to 2 on success
31  * 2. complete: Just a little message and a close button.
32  *    Optionally there is an auto-close feature.
33  * 3. failed: The packaging failed, error message should be displayed.
34  *    After looking at the message close the dialog.
35  *
36  * For simplicity we use the widget pointers instead of the index to refer to
37  * them. (Except that we start at index 0: selection.)
38  */
39 
40 namespace SolarusEditor {
41 
42 namespace {
43 
get_default_save_path(const Quest & quest)44 QString get_default_save_path(const Quest &quest) {
45   return quest.get_root_path() + "/" + quest.get_name() + ".solarus";
46 }
47 
48 } // Anonymous namespace.
49 
PackageDialog(Quest const & quest,QWidget * parent)50 PackageDialog::PackageDialog(Quest const& quest, QWidget *parent) :
51   QDialog(parent),
52   ui(new Ui::PackageDialog),
53   process(),
54   quest(quest),
55   save_path() {
56 
57   ui->setupUi(this);
58   ui->stacked_widget->setCurrentWidget(ui->selection);
59   ui->button_box->button(QDialogButtonBox::Apply)->setText(tr("Build"));
60 
61   process.setReadChannel(QProcess::StandardOutput);
62 
63   connect(ui->button_box->button(QDialogButtonBox::Apply), &QPushButton::clicked,
64           this, &PackageDialog::process_start);
65   connect(ui->selection_browse, &QPushButton::clicked,
66           this, &PackageDialog::start_file_selection);
67   connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
68           this, &PackageDialog::process_finished);
69   connect(&process, &QProcess::readyReadStandardOutput,
70           this, &PackageDialog::handle_process_standard_output);
71 
72   const QString &saved_path = EditorSettings()
73       .get_value_string(EditorSettings::package_save_path);
74   set_save_path(saved_path.isEmpty() ? get_default_save_path(quest) : saved_path);
75 }
76 
77 PackageDialog::~PackageDialog() = default;
78 
set_save_path(const QString & new_save_path)79 void PackageDialog::set_save_path(const QString &new_save_path) {
80   save_path = new_save_path;
81   ui->selection_file->setText(save_path);
82   EditorSettings().set_value(
83         EditorSettings::package_save_path, QVariant(save_path));
84 }
85 
process_start()86 void PackageDialog::process_start() {
87   ui->button_box->button(QDialogButtonBox::Apply)->setEnabled(false);
88   ui->button_box->button(QDialogButtonBox::Close)->setEnabled(false);
89   ui->stacked_widget->setCurrentWidget(ui->ongoing);
90   ui->ongoing_output->setPlainText(tr("Starting...\n"));
91 
92   process.setWorkingDirectory(quest.get_data_path());
93   process.start("zip", QStringList() << "-r" << save_path << ".");
94 }
95 
process_finished(int code,QProcess::ExitStatus status)96 void PackageDialog::process_finished(int code, QProcess::ExitStatus status) {
97 
98   if (status == QProcess::CrashExit || code != 0) {
99     ui->failed_output->setPlainText(
100           QString(process.readAllStandardError()));
101     ui->failed_code->setText(
102           status == QProcess::CrashExit ?
103             tr("Crashed") : QString::number(code));
104     ui->stacked_widget->setCurrentWidget(ui->failed);
105   } else {
106     ui->stacked_widget->setCurrentWidget(ui->completed);
107   }
108   ui->button_box->button(QDialogButtonBox::Close)->setEnabled(true);
109 }
110 
start_file_selection()111 void PackageDialog::start_file_selection() {
112 
113   const QString& path = QFileDialog::getSaveFileName(
114         this, tr("Quest package location:"), save_path,
115         tr("Solarus Packages (*.solarus)"));
116   if (!path.isEmpty()) {
117     set_save_path(path);
118   }
119 }
120 
handle_process_standard_output()121 void PackageDialog::handle_process_standard_output() {
122   while (process.canReadLine()) {
123     const QByteArray &line = process.readLine();
124     ui->ongoing_output->moveCursor(QTextCursor::End);
125     ui->ongoing_output->insertPlainText(QString(line));
126   }
127 }
128 
129 }
130