missingwadsdialog.cpp
1 //------------------------------------------------------------------------------
2 // missingwadsdialog.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2015 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "missingwadsdialog.h"
24 
25 #include "application.h"
26 #include "gui/commongui.h"
27 #include "gui/mainwindow.h"
28 #include "gui/wadseekerinterface.h"
29 #include "plugins/engineplugin.h"
31 #include "ui_missingwadsdialog.h"
32 #include <QListWidgetItem>
33 #include <QPushButton>
34 #include <wadseeker/entities/modfile.h>
35 #include <wadseeker/freedoom.h>
36 #include <wadseeker/wadseeker.h>
37 
38 DClass<MissingWadsDialog> : public Ui::MissingWadsDialog
39 {
40 public:
41  QPushButton *btnInstall;
42  QPushButton *btnIgnore;
43 
44  ::MissingWadsDialog::MissingWadsProceed decision;
45  QList<PWad> missingWads;
46  QList<PWad> incompatibleWads;
47  EnginePlugin *plugin = nullptr;
48 };
49 DPointeredNoCopy(MissingWadsDialog)
50 
51 MissingWadsDialog::MissingWadsDialog(const QList<PWad> &missingWads, const QList<PWad> &incompatibleWads, EnginePlugin *plugin, QWidget *parent)
52  : QDialog(parent)
53 {
54  d->setupUi(this);
56  d->btnInstall = d->buttonBox->button(QDialogButtonBox::Yes);
57  d->btnIgnore = d->buttonBox->button(QDialogButtonBox::Ignore);
58  d->decision = Cancel;
59  d->missingWads = missingWads;
60  d->incompatibleWads = incompatibleWads;
61  d->plugin = plugin;
62 
63  d->btnInstall->setText(MissingWadsDialog::tr("Install"));
64  connect(d->btnInstall, &QAbstractButton::clicked,
65  this, &MissingWadsDialog::installMissingFiles);
66  connect(d->btnIgnore, &QAbstractButton::clicked,
67  this, &MissingWadsDialog::ignoreMissingFiles);
68 
69  setup();
70  adjustSize();
71 }
72 
73 MissingWadsDialog::~MissingWadsDialog()
74 {
75 }
76 
77 void MissingWadsDialog::setAllowIgnore(bool allow)
78 {
79  d->btnIgnore->setVisible(allow);
80  d->lblUseIgnore->setVisible(allow);
81  d->lblUseIgnoreCantRun->setVisible(allow);
82 }
83 
84 void MissingWadsDialog::setup()
85 {
86  d->btnInstallFreedoom->hide();
87  if (WadseekerInterface::isInstantiated())
88  setupWadseekerIsRunning();
89  else
90  setupWadseekerNotRunning();
91 }
92 
93 void MissingWadsDialog::setupWadseekerIsRunning()
94 {
95  d->areaWadseekerAlreadyRunning->show();
96  d->areaWadseekerCanBeRun->hide();
97  d->btnInstall->hide();
98 }
99 
100 void MissingWadsDialog::setupWadseekerNotRunning()
101 {
102  d->areaWadseekerAlreadyRunning->hide();
103  d->areaWadseekerCanBeRun->show();
104 
105  setupForbiddenFilesArea();
106  setupDownloadableFilesArea();
107  setupOptionalFilesArea();
108  setupIncompatibleFilesArea();
109 
110  d->btnInstall->setVisible(hasAnyAllowedFile());
111  setAllowIgnore(((optionalFiles().size() == d->missingWads.size()) ||
112  d->missingWads.size() == 0 || // there are only incompatible files
113  (d->plugin != nullptr && d->plugin->data()->inGameFileDownloads)));
114 }
115 
116 void MissingWadsDialog::setupForbiddenFilesArea()
117 {
118  QList<PWad> files = forbiddenFiles();
119  if (!files.isEmpty())
120  {
121  d->areaCantBeDownloaded->show();
122  QStringList names;
123  for (PWad file : files)
124  {
125  names << file.name();
126  }
127  d->lblCantBeDownloadedFiles->setText(names.join(", "));
128 
129  bool installFreedoom = isFreedoomReplaceableOnList(names);
130  d->lblInstallFreedoom->setVisible(installFreedoom);
131  d->btnInstallFreedoom->setVisible(installFreedoom);
132  }
133  else
134  d->areaCantBeDownloaded->hide();
135 }
136 
137 void MissingWadsDialog::setupDownloadableFilesArea()
138 {
139  QList<PWad> files = downloadableFiles();
140  if (!files.isEmpty())
141  {
142  d->areaCanBeDownloadedFiles->show();
143  QStringList names;
144  for (PWad file : files)
145  {
146  names << file.name();
147  }
148  d->lblCanBeDownloadedFiles->setText(names.join(", "));
149  }
150  else
151  d->areaCanBeDownloadedFiles->hide();
152 }
153 
154 void MissingWadsDialog::setupOptionalFilesArea()
155 {
156  QList<PWad> files = optionalFiles();
157  if (!files.isEmpty())
158  {
159  d->areaOptionalFiles->show();
160  for (const PWad &file : files)
161  {
162  auto item = new QListWidgetItem(file.name(), d->optionalFilesList);
163  item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
164  item->setCheckState(Qt::Checked);
165  }
166  }
167  else
168  d->areaOptionalFiles->hide();
169 }
170 
171 void MissingWadsDialog::setupIncompatibleFilesArea()
172 {
173  QList<PWad> files = incompatibleFiles();
174  if (!files.isEmpty())
175  {
176  d->areaIncompatibleFiles->show();
177  for (const PWad &file : files)
178  {
179  auto item = new QListWidgetItem(file.name(), d->incompatibleFilesList);
180  item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
181  item->setCheckState(Qt::Checked);
182  }
183  }
184  else
185  d->areaIncompatibleFiles->hide();
186 }
187 
188 bool MissingWadsDialog::isFreedoomReplaceableOnList(const QStringList &files) const
189 {
190  for (const QString &file : files)
191  {
192  if (Freedoom::hasFreedoomReplacement(file))
193  return true;
194  }
195  return false;
196 }
197 
198 void MissingWadsDialog::updateStateAccordingToFileSelection()
199 {
200  d->btnInstall->setEnabled(!filesToDownload().isEmpty());
201 }
202 
203 void MissingWadsDialog::ignoreMissingFiles()
204 {
205  d->decision = Ignore;
206  accept();
207 }
208 
209 void MissingWadsDialog::installFreedoom()
210 {
211  if (gApp->mainWindow() != nullptr)
212  {
213  QTimer::singleShot(0, gApp->mainWindow(), SLOT(showInstallFreedoomDialog()));
214  }
215  accept();
216 }
217 
218 void MissingWadsDialog::installMissingFiles()
219 {
220  d->decision = Install;
221  accept();
222 }
223 
224 QList<PWad> MissingWadsDialog::downloadableFiles() const
225 {
226  QList<PWad> result;
227  for (PWad file : d->missingWads)
228  {
229  if (!Wadseeker::isForbiddenWad(file) && !file.isOptional())
230  result << file;
231  }
232  return result;
233 }
234 
235 QList<PWad> MissingWadsDialog::forbiddenFiles() const
236 {
237  QList<PWad> result;
238  QList<PWad> wads;
239  wads << d->missingWads << d->incompatibleWads;
240  for (const PWad &file : wads)
241  {
242  if (Wadseeker::isForbiddenWad(file.name()))
243  result << file;
244  }
245  return result;
246 }
247 
248 QList<PWad> MissingWadsDialog::optionalFiles() const
249 {
250  QList<PWad> result;
251  for (const PWad &file : d->missingWads)
252  {
253  if (!Wadseeker::isForbiddenWad(file.name()) && file.isOptional())
254  result << file;
255  }
256  return result;
257 }
258 
259 QList<PWad> MissingWadsDialog::incompatibleFiles() const
260 {
261  QList<PWad> result;
262  for (const PWad &file : d->incompatibleWads)
263  {
264  if (!Wadseeker::isForbiddenWad(file.name()))
265  result << file;
266  }
267  return result;
268 }
269 
270 QList<PWad> MissingWadsDialog::filesToDownload() const
271 {
272  QList<PWad> result = downloadableFiles();
273  result << selectedOptionalFiles();
274  result << selectedIncompatibleFiles();
275  return result;
276 }
277 
278 QList<PWad> MissingWadsDialog::selectedOptionalFiles() const
279 {
280  QStringList result;
281  for (int i = 0; i < d->optionalFilesList->count(); ++i)
282  {
283  QListWidgetItem *item = d->optionalFilesList->item(i);
284  if (item->checkState() == Qt::Checked)
285  result << item->text();
286  }
287  return filenamesToPwads(result, optionalFiles());
288 }
289 
290 QList<PWad> MissingWadsDialog::selectedIncompatibleFiles() const
291 {
292  QStringList result;
293  for (int i = 0; i < d->incompatibleFilesList->count(); ++i)
294  {
295  QListWidgetItem *item = d->incompatibleFilesList->item(i);
296  if (item->checkState() == Qt::Checked)
297  result << item->text();
298  }
299  return filenamesToPwads(result, incompatibleFiles());
300 }
301 
302 QList<PWad> MissingWadsDialog::filenamesToPwads(const QStringList &names, QList<PWad> files) const
303 {
304  QList<PWad> result;
305  for (QString name : names)
306  {
307  for (int i = 0; i < files.size(); ++i)
308  {
309  if (files[i].name() == name)
310  {
311  result << files[i];
312  files.removeAt(i);
313  break;
314  }
315  }
316  }
317  return result;
318 }
319 
320 bool MissingWadsDialog::hasAnyAllowedFile() const
321 {
322  return !downloadableFiles().isEmpty() ||
323  !optionalFiles().isEmpty() ||
324  !incompatibleFiles().isEmpty();
325 }
326 
327 MissingWadsDialog::MissingWadsProceed MissingWadsDialog::decision() const
328 {
329  return d->decision;
330 }