freedoomdialog.cpp
1 //------------------------------------------------------------------------------
2 // freedoomdialog.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 "freedoomdialog.h"
24 
25 #include "configuration/doomseekerconfig.h"
26 #include "fileutils.h"
27 #include "pathfinder/filesearchpath.h"
28 #include "pathfinder/pathfinder.h"
29 #include "pathfinder/wadpathfinder.h"
30 #include "ui_freedoomdialog.h"
31 #include <QCheckBox>
32 #include <QCompleter>
33 #include <QDirModel>
34 #include <QMessageBox>
35 #include <wadseeker/entities/checksum.h>
36 #include <wadseeker/entities/modset.h>
37 #include <wadseeker/freedoom.h>
38 #include <wadseeker/modinstall.h>
39 
40 DClass<FreedoomDialog> : public Ui::FreedoomDialog
41 {
42 public:
43  Freedoom *freedoom;
44  ModInstall *modInstall;
45  QString targetDir;
46 };
47 DPointered(FreedoomDialog)
48 
49 FreedoomDialog::FreedoomDialog(QWidget *parent)
50  : QDialog(parent)
51 {
52  d->setupUi(this);
53 
54  d->freedoom = new Freedoom(this);
55  this->connect(d->freedoom, SIGNAL(finished()), SLOT(applyFreedoomVersionInfo()));
56 
57  d->modInstall = new ModInstall(this);
58  this->connect(d->modInstall, SIGNAL(finished()), SLOT(onModInstallFinished()));
59  this->connect(d->modInstall, SIGNAL(fileDownloadProgress(QString,qint64,qint64)),
60  SLOT(showFileDownloadProgress(QString,qint64,qint64)));
61 
62  d->btnInstall->setEnabled(false);
63  setupInstallPaths();
64  setupWadsTable();
65  fetchInfo();
66 }
67 
68 FreedoomDialog::~FreedoomDialog()
69 {
70 }
71 
72 void FreedoomDialog::accept()
73 {
74  ModSet modSet = selectedModFiles();
75  if (modSet.isEmpty())
76  {
77  QMessageBox::critical(this, tr("Install Freedoom"),
78  tr("Select at least one file."));
79  return;
80  }
81  resetProgressBar();
82  showStatus(tr("Downloading & installing ..."));
83  d->targetDir = d->cboInstallPath->currentText();
84  d->modInstall->install(d->targetDir, modSet);
85 }
86 
87 void FreedoomDialog::onModInstallFinished()
88 {
89  if (!d->modInstall->isError())
90  {
91  updateConfig();
92  fetchInfo();
93  }
94  else
95  showError(d->modInstall->error());
96 }
97 
98 void FreedoomDialog::updateConfig()
99 {
100  gConfig.doomseeker.enableFreedoomInstallation(d->targetDir);
101  gConfig.saveToFile();
102 }
103 
104 void FreedoomDialog::fetchInfo()
105 {
106  resetProgressBar();
107  d->btnRetry->hide();
108  showStatus(tr("Downloading Freedoom version info ..."));
109  d->freedoom->requestModSet();
110 }
111 
112 void FreedoomDialog::resetProgressBar()
113 {
114  d->progressBar->setFormat(tr("Working ..."));
115  d->progressBar->show();
116  d->progressBar->setMaximum(0);
117  d->progressBar->setValue(0);
118 }
119 
120 void FreedoomDialog::applyFreedoomVersionInfo()
121 {
122  if (!d->freedoom->isError())
123  showModInfo(d->freedoom->modSet());
124  else
125  showError(tr("Error: %1").arg(d->freedoom->error()));
126 }
127 
128 void FreedoomDialog::showModInfo(const ModSet &modSet)
129 {
130  d->wadsArea->show();
131  d->workInProgressArea->hide();
132 
133  d->wadsTable->setSortingEnabled(false);
134  d->wadsTable->clearContents();
135  while (d->wadsTable->rowCount() > 0)
136  {
137  d->wadsTable->removeRow(d->wadsTable->rowCount() - 1);
138  }
139  for (const ModFile &file : modSet.modFiles())
140  {
141  insertModFile(file);
142  }
143  d->wadsTable->setSortingEnabled(true);
144  d->btnInstall->setEnabled(true);
145 }
146 
147 void FreedoomDialog::insertModFile(const ModFile &file)
148 {
149  WadPathFinder pathFinder = WadPathFinder(PathFinder());
150  pathFinder.setAllowAliases(false);
151  QString location = pathFinder.find(file.fileName()).path();
152 
153  QString status = tr("OK");
154  bool needsInstall = false;
155  if (location.isEmpty())
156  {
157  needsInstall = true;
158  status = tr("Missing");
159  }
160  else
161  {
162  QByteArray md5 = FileUtils::md5(location);
163  for (Checksum checksum : file.checksums())
164  {
165  if (md5 != checksum.hash() && checksum.algorithm() == QCryptographicHash::Md5)
166  {
167  status = tr("Different");
168  needsInstall = true;
169  break;
170  }
171  }
172  }
173  if (file.fileName().compare("freedm.wad", Qt::CaseInsensitive) == 0)
174  needsInstall = false;
175 
176  d->wadsTable->insertRow(d->wadsTable->rowCount());
177  int row = d->wadsTable->rowCount() - 1;
178  d->wadsTable->setItem(row, ColName, new QTableWidgetItem(file.fileName()));
179  d->wadsTable->setItem(row, ColStatus, new QTableWidgetItem(status));
180 
181  auto checkBox = new QCheckBox();
182  checkBox->setChecked(needsInstall);
183  d->wadsTable->setCellWidget(row, ColInstall, checkBox);
184 
185  QString tooltip = tr("<p>File: %1<br>Version: %2<br>"
186  "Description: %3<br>Location: %4</p>")
187  .arg(file.name(), file.version(), file.description(), location);
188 
189  for (int col = 0; col < d->wadsTable->columnCount(); ++col)
190  {
191  QTableWidgetItem *item = d->wadsTable->item(row, col);
192  if (item != nullptr)
193  item->setToolTip(tooltip);
194  }
195 }
196 
197 void FreedoomDialog::showError(const QString &text)
198 {
199  d->btnRetry->setVisible(true);
200  showStatus(text);
201  d->progressBar->hide();
202 }
203 
204 void FreedoomDialog::showStatus(const QString &text)
205 {
206  d->wadsArea->hide();
207  d->workInProgressArea->show();
208  d->btnInstall->setEnabled(false);
209  d->lblWorkInProgress->setText(text);
210 }
211 
212 ModSet FreedoomDialog::selectedModFiles() const
213 {
214  ModSet modSet;
215  for (int row = 0; row < d->wadsTable->rowCount(); ++row)
216  {
217  auto checkbox = static_cast<QCheckBox *>(d->wadsTable->cellWidget(row, ColInstall));
218  if (checkbox->isChecked())
219  {
220  QString fileName = d->wadsTable->item(row, ColName)->text();
221  modSet.addModFile(d->freedoom->modSet().findFileName(fileName));
222  }
223  }
224  return modSet;
225 }
226 
227 void FreedoomDialog::setupInstallPaths()
228 {
229  auto completer = new QCompleter(this);
230  completer->setModel(new QDirModel(completer));
231  d->cboInstallPath->setCompleter(completer);
232 
233  for (const FileSearchPath &path : gConfig.combinedWadseekPaths())
234  {
235  d->cboInstallPath->addItem(path.path());
236  }
237  d->cboInstallPath->setCurrentText(gConfig.wadseeker.targetDirectory);
238 }
239 
240 void FreedoomDialog::setupWadsTable()
241 {
242  QHeaderView *header = d->wadsTable->horizontalHeader();
243  header->setSectionResizeMode(ColName, QHeaderView::Stretch);
244  header->setSectionResizeMode(ColStatus, QHeaderView::ResizeToContents);
245  header->setSectionResizeMode(ColInstall, QHeaderView::ResizeToContents);
246  d->wadsTable->setColumnWidth(ColName, 150);
247 }
248 
249 void FreedoomDialog::showFileDownloadProgress(const QString &file,
250  qint64 current, qint64 total)
251 {
252  d->progressBar->setFormat(tr("%1 %p%").arg(file));
253  d->progressBar->setMaximum(total);
254  d->progressBar->setValue(current);
255 }