23 #include "gui/wadseekerinterface.h"
24 #include "ui_wadseekerinterface.h"
26 #include "application.h"
27 #include "configuration/doomseekerconfig.h"
28 #include "gui/commongui.h"
29 #include "gui/helpers/taskbarbutton.h"
30 #include "gui/helpers/taskbarprogress.h"
31 #include "mainwindow.h"
32 #include "serverapi/server.h"
34 #include "strings.hpp"
35 #include "wadseeker/entities/checksum.h"
36 #include "wadseeker/entities/modfile.h"
37 #include "wadseeker/entities/modset.h"
39 #include <QMessageBox>
41 const int WadseekerInterface::UPDATE_INTERVAL_MS = 500;
44 DClass<WadseekerInterface> :
public Ui::WadseekerInterface
47 bool bCompletedSuccessfully;
62 WadseekerInterface::WadseekerInterface(ServerPtr server, QWidget *parent)
68 d->lblTop->setText(tr(
"Downloading WADs for server \"%1\"").arg(server->name()));
69 setCustomSites(server->allWebSites());
72 WadseekerInterface::~WadseekerInterface()
74 currentInstance =
nullptr;
77 void WadseekerInterface::abortService(
const QString &service)
79 message(tr(
"Aborting service: %1").arg(service), WadseekerLib::Notice);
80 wadseeker.skipService(service);
83 void WadseekerInterface::abortSite(
const QUrl &url)
85 message(tr(
"Aborting site: %1").arg(url.toString()), WadseekerLib::Notice);
86 wadseeker.skipSiteSeek(url);
89 void WadseekerInterface::accept()
93 if (d->bCompletedSuccessfully)
94 done(QDialog::Accepted);
98 if (d->leWadName->text().isEmpty())
103 QStringList pwadNames = d->leWadName->text().split(
',', Qt::SkipEmptyParts);
104 for (QString pwadName : pwadNames)
106 seekedWads << pwadName.trimmed();
109 startSeeking(seekedWads);
113 void WadseekerInterface::allDone(
bool bSuccess)
116 d->bCompletedSuccessfully = bSuccess;
117 QApplication::alert(
this);
120 displayMessage(tr(
"All done. Success."), WadseekerLib::NoticeImportant,
false);
122 if (isAutomatic() && !d->preventGame)
124 if (isActiveWindow())
125 done(QDialog::Accepted);
127 d->btnStartGame->show();
132 QList<PWad> failures = unsuccessfulWads();
134 for (
const PWad &failure : failures)
136 d->twWads->setFileFailed(failure.name());
139 displayMessage(tr(
"All done. Fail."), WadseekerLib::CriticalError,
false);
143 void WadseekerInterface::connectWadseekerObject()
146 this->connect(&wadseeker, SIGNAL(allDone(
bool)),
147 SLOT(allDone(
bool)));
148 this->connect(&wadseeker, SIGNAL(message(
const QString&,WadseekerLib::MessageType)),
149 SLOT(message(
const QString&,WadseekerLib::MessageType)));
150 this->connect(&wadseeker, SIGNAL(seekStarted(
const ModSet&)),
151 SLOT(seekStarted(
const ModSet&)));
152 this->connect(&wadseeker, SIGNAL(fileInstalled(
const ModFile&)),
153 SLOT(fileDownloadSuccessful(
const ModFile&)));
154 this->connect(&wadseeker, SIGNAL(siteFinished(
const QUrl&)),
155 SLOT(siteFinished(
const QUrl&)));
156 this->connect(&wadseeker, SIGNAL(siteProgress(
const QUrl&,qint64,qint64)),
157 SLOT(siteProgress(
const QUrl&,qint64,qint64)));
158 this->connect(&wadseeker, SIGNAL(siteRedirect(
const QUrl&,
const QUrl&)),
159 SLOT(siteRedirect(
const QUrl&,
const QUrl&)));
160 this->connect(&wadseeker, SIGNAL(siteStarted(
const QUrl&)),
161 SLOT(siteStarted(
const QUrl&)));
162 this->connect(&wadseeker, SIGNAL(serviceStarted(QString)),
163 SLOT(serviceStarted(QString)));
164 this->connect(&wadseeker, SIGNAL(serviceFinished(QString)),
165 SLOT(serviceFinished(QString)));
168 d->twWads->connect(&wadseeker, SIGNAL(fileDownloadFinished(
const ModFile&)),
169 SLOT(setFileDownloadFinished(
const ModFile&)));
170 d->twWads->connect(&wadseeker, SIGNAL(fileDownloadProgress(
const ModFile&,qint64,qint64)),
171 SLOT(setFileProgress(
const ModFile&,qint64,qint64)));
172 d->twWads->connect(&wadseeker, SIGNAL(fileDownloadStarted(
const ModFile&,
const QUrl&)),
173 SLOT(setFileUrl(
const ModFile&,
const QUrl&)));
176 void WadseekerInterface::construct()
180 d->preventGame =
false;
181 d->bCompletedSuccessfully =
false;
185 d->taskbarProgress = d->taskbarButton->progress();
186 d->taskbarProgress->setMaximum(d->pbOverallProgress->maximum());
192 this->setWindowIcon(QIcon(
":/icon.png"));
193 d->btnStartGame->hide();
194 this->connect(&updateTimer, SIGNAL(timeout()), SLOT(registerUpdateRequest()));
196 connectWadseekerObject();
199 this->connect(d->twWads, SIGNAL(rightMouseClick(
const QModelIndex&,
const QPoint&)),
200 SLOT(wadsTableRightClicked(
const QModelIndex&,
const QPoint&)));
205 QStringList urlList = gConfig.wadseeker.searchURLs;
206 if (gConfig.wadseeker.bAlwaysUseDefaultSites)
208 for (
int i = 0; !Wadseeker::defaultSites[i].isEmpty(); ++i)
209 urlList << Wadseeker::defaultSites[i];
212 wadseeker.setPrimarySites(urlList);
214 updateTimer.setSingleShot(
false);
215 updateTimer.start(UPDATE_INTERVAL_MS);
220 if (!isInstantiated())
223 return currentInstance;
230 if (!isInstantiated())
233 return currentInstance;
241 if (interface !=
nullptr)
243 interface->setupAutomatic();
244 interface->d->preventGame =
true;
249 void WadseekerInterface::displayMessage(
const QString &message, WadseekerLib::MessageType type,
bool bPrependErrorsWithMessageType)
251 QString strProcessedMessage;
253 bool bPrependWithNewline =
false;
254 QString wrapHtmlLeft =
"<div style=\"%1\">";
255 QString wrapHtmlRight =
"</div>";
260 case WadseekerLib::CriticalError:
261 htmlStyle = QString(
"color: %1; font-weight: bold;").arg(colorHtmlMessageFatalError);
262 bPrependWithNewline =
true;
264 if (bPrependErrorsWithMessageType)
265 strProcessedMessage = tr(
"CRITICAL ERROR: %1").arg(message);
267 strProcessedMessage = message;
272 case WadseekerLib::Error:
273 htmlStyle = QString(
"color: %1;").arg(colorHtmlMessageError);
275 if (bPrependErrorsWithMessageType)
276 strProcessedMessage = tr(
"Error: %1").arg(message);
278 strProcessedMessage = message;
281 case WadseekerLib::Notice:
282 htmlStyle = QString(
"color: %1;").arg(colorHtmlMessageNotice);
284 strProcessedMessage = message;
287 case WadseekerLib::NoticeImportant:
288 htmlStyle = QString(
"color: %1; font-weight: bold;").arg(colorHtmlMessageNotice);
289 bPrependWithNewline =
true;
291 strProcessedMessage = message;
295 if (bPrependWithNewline && !d->teWadseekerOutput->toPlainText().isEmpty())
296 strProcessedMessage =
"<br>" + strProcessedMessage;
298 wrapHtmlLeft = wrapHtmlLeft.arg(htmlStyle);
300 strProcessedMessage = wrapHtmlLeft + strProcessedMessage + wrapHtmlRight;
302 d->teWadseekerOutput->append(strProcessedMessage);
305 void WadseekerInterface::fileDownloadSuccessful(
const ModFile &filename)
307 successfulWads << filename;
308 d->twWads->setFileSuccessful(filename.fileName());
311 void WadseekerInterface::initMessageColors()
313 colorHtmlMessageNotice = gConfig.wadseeker.colorMessageNotice;
314 colorHtmlMessageError = gConfig.wadseeker.colorMessageError;
315 colorHtmlMessageFatalError = gConfig.wadseeker.colorMessageCriticalError;
318 bool WadseekerInterface::isInstantiated()
320 return currentInstance !=
nullptr;
323 void WadseekerInterface::message(
const QString &message, WadseekerLib::MessageType type)
325 displayMessage(message, type,
true);
328 void WadseekerInterface::registerUpdateRequest()
334 void WadseekerInterface::reject()
343 this->done(Rejected);
348 void WadseekerInterface::resetTitleToDefault()
350 setWindowTitle(tr(
"Wadseeker"));
353 void WadseekerInterface::seekStarted(
const ModSet &filenames)
357 for (ModFile modFile : filenames.modFiles())
360 names << modFile.fileName();
362 d->teWadseekerOutput->clear();
363 d->pbOverallProgress->setValue(0);
364 d->taskbarProgress->setValue(0);
365 displayMessage(
"Seek started on filenames: " + names.join(
", "), WadseekerLib::Notice,
false);
368 successfulWads.clear();
369 d->twSites->setRowCount(0);
370 d->twWads->setRowCount(0);
371 setStateDownloading();
373 for (
const PWad &wad : seekedWads)
375 d->twWads->addFile(wad.name());
379 void WadseekerInterface::setStateDownloading()
381 d->btnClose->setText(tr(
"Abort"));
382 d->btnDownload->setEnabled(
false);
383 d->taskbarProgress->show();
387 void WadseekerInterface::setStateWaiting()
389 d->btnClose->setText(tr(
"Close"));
390 d->btnDownload->setEnabled(
true);
391 d->taskbarProgress->hide();
395 void WadseekerInterface::setupAutomatic()
399 d->btnDownload->hide();
400 d->leWadName->hide();
409 for (
PWad wad : wads)
413 d->leWadName->setText(names.join(
", "));
417 void WadseekerInterface::setupIdgames()
419 wadseeker.setIdgamesEnabled(gConfig.wadseeker.bSearchInIdgames);
420 wadseeker.setIdgamesUrl(gConfig.wadseeker.idgamesURL);
421 wadseeker.setWadArchiveEnabled(gConfig.wadseeker.bSearchInWadArchive);
424 void WadseekerInterface::showEvent(QShowEvent *event)
429 d->taskbarButton->setWindow(windowHandle());
433 startSeeking(seekedWads);
437 void WadseekerInterface::serviceStarted(
const QString &service)
439 d->twSites->addService(service);
442 void WadseekerInterface::serviceFinished(
const QString &service)
444 d->twSites->removeService(service);
447 void WadseekerInterface::siteFinished(
const QUrl &site)
449 d->twSites->removeUrl(site);
450 displayMessage(
"Site finished: " + site.toString(), WadseekerLib::Notice,
false);
453 void WadseekerInterface::siteProgress(
const QUrl &site, qint64 bytes, qint64 total)
455 d->twSites->setUrlProgress(site, bytes, total);
458 void WadseekerInterface::siteRedirect(
const QUrl &oldUrl,
const QUrl &newUrl)
460 d->twSites->removeUrl(oldUrl);
461 d->twSites->addUrl(newUrl);
462 displayMessage(
"Site redirect: " + oldUrl.toString() +
" -> " + newUrl.toString(), WadseekerLib::Notice,
false);
465 void WadseekerInterface::siteStarted(
const QUrl &site)
467 d->twSites->addUrl(site);
468 displayMessage(
"Site started: " + site.toString(), WadseekerLib::Notice,
false);
471 void WadseekerInterface::startSeeking(
const QList<PWad> &seekedFilesList)
473 if (seekedFilesList.isEmpty())
475 d->bCompletedSuccessfully =
false;
478 for (
PWad seekedFile : seekedFilesList)
480 listWads.addModFile(seekedFile);
485 wadseeker.setTargetDirectory(gConfig.wadseeker.targetDirectory);
486 wadseeker.setCustomSites(customSites);
487 wadseeker.setMaximumConcurrentSeeks(gConfig.wadseeker.maxConcurrentSiteDownloads);
488 wadseeker.setMaximumConcurrentDownloads(gConfig.wadseeker.maxConcurrentWadDownloads);
489 wadseeker.startSeek(listWads);
492 void WadseekerInterface::updateProgressBar()
494 double totalPercentage = d->twWads->totalDonePercentage();
495 auto progressBarValue = (unsigned)(totalPercentage * 100.0);
497 d->pbOverallProgress->setValue(progressBarValue);
498 d->taskbarProgress->setValue(progressBarValue);
501 void WadseekerInterface::updateTitle()
507 double totalPercentage = d->twWads->totalDonePercentage();
508 if (totalPercentage < 0.0)
509 totalPercentage = 0.0;
511 setWindowTitle(tr(
"[%1%] Wadseeker").arg(totalPercentage, 6,
'f', 2));
517 resetTitleToDefault();
522 QList<PWad> WadseekerInterface::unsuccessfulWads()
const
524 QList<PWad> allWads = seekedWads;
525 for (
PWad successfulWad : successfulWads)
527 for (
int i = 0; i < allWads.size(); ++i)
529 if (allWads[i].name() == successfulWad.name())
539 void WadseekerInterface::wadsTableRightClicked(
const QModelIndex &index,
const QPoint &cursorPosition)
544 QString fileName = d->twWads->fileNameAtRow(index.row());
545 if (!wadseeker.isDownloadingFile(fileName))
546 menu->actionSkipCurrentSite->setEnabled(
false);
548 QAction *pResult = menu->exec();
550 if (pResult == menu->actionSkipCurrentSite)
552 QString wadName = d->twWads->fileNameAtRow(index.row());
553 d->twWads->setFileUrl(fileName, QUrl());
555 wadseeker.skipFileCurrentUrl(wadName);
557 else if (pResult !=
nullptr)
558 QMessageBox::warning(
this, tr(
"Context menu error"), tr(
"Unknown action selected."));