23 #include "gui/wadseekerinterface.h"
24 #include "ui_wadseekerinterface.h"
26 #include "application.h"
27 #include "configuration/doomseekerconfig.h"
28 #include "gui/helpers/taskbarbutton.h"
29 #include "gui/helpers/taskbarprogress.h"
30 #include "mainwindow.h"
31 #include "serverapi/server.h"
33 #include "strings.hpp"
34 #include "wadseeker/entities/checksum.h"
35 #include "wadseeker/entities/modfile.h"
36 #include "wadseeker/entities/modset.h"
38 #include <QMessageBox>
40 const int WadseekerInterface::UPDATE_INTERVAL_MS = 500;
43 DClass<WadseekerInterface> :
public Ui::WadseekerInterface
46 bool bCompletedSuccessfully;
61 WadseekerInterface::WadseekerInterface(ServerPtr server, QWidget *parent)
67 d->lblTop->setText(tr(
"Downloading WADs for server \"%1\"").arg(server->name()));
68 setCustomSites(server->allWebSites());
71 WadseekerInterface::~WadseekerInterface()
73 currentInstance =
nullptr;
76 void WadseekerInterface::abortService(
const QString &service)
78 message(tr(
"Aborting service: %1").arg(service), WadseekerLib::Notice);
79 wadseeker.skipService(service);
82 void WadseekerInterface::abortSite(
const QUrl &url)
84 message(tr(
"Aborting site: %1").arg(url.toString()), WadseekerLib::Notice);
85 wadseeker.skipSiteSeek(url);
88 void WadseekerInterface::accept()
92 if (d->bCompletedSuccessfully)
93 done(QDialog::Accepted);
97 if (d->leWadName->text().isEmpty())
102 QStringList pwadNames = d->leWadName->text().split(
',', QString::SkipEmptyParts);
103 for (QString pwadName : pwadNames)
105 seekedWads << pwadName.trimmed();
108 startSeeking(seekedWads);
112 void WadseekerInterface::allDone(
bool bSuccess)
115 d->bCompletedSuccessfully = bSuccess;
116 QApplication::alert(
this);
119 displayMessage(tr(
"All done. Success."), WadseekerLib::NoticeImportant,
false);
121 if (isAutomatic() && !d->preventGame)
123 if (isActiveWindow())
124 done(QDialog::Accepted);
126 d->btnStartGame->show();
131 QList<PWad> failures = unsuccessfulWads();
133 for (
const PWad &failure : failures)
135 d->twWads->setFileFailed(failure.name());
138 displayMessage(tr(
"All done. Fail."), WadseekerLib::CriticalError,
false);
142 void WadseekerInterface::connectWadseekerObject()
145 this->connect(&wadseeker, SIGNAL(allDone(
bool)),
146 SLOT(allDone(
bool)));
147 this->connect(&wadseeker, SIGNAL(message(
const QString&,WadseekerLib::MessageType)),
148 SLOT(message(
const QString&,WadseekerLib::MessageType)));
149 this->connect(&wadseeker, SIGNAL(seekStarted(
const ModSet&)),
150 SLOT(seekStarted(
const ModSet&)));
151 this->connect(&wadseeker, SIGNAL(fileInstalled(
const ModFile&)),
152 SLOT(fileDownloadSuccessful(
const ModFile&)));
153 this->connect(&wadseeker, SIGNAL(siteFinished(
const QUrl&)),
154 SLOT(siteFinished(
const QUrl&)));
155 this->connect(&wadseeker, SIGNAL(siteProgress(
const QUrl&,qint64,qint64)),
156 SLOT(siteProgress(
const QUrl&,qint64,qint64)));
157 this->connect(&wadseeker, SIGNAL(siteRedirect(
const QUrl&,
const QUrl&)),
158 SLOT(siteRedirect(
const QUrl&,
const QUrl&)));
159 this->connect(&wadseeker, SIGNAL(siteStarted(
const QUrl&)),
160 SLOT(siteStarted(
const QUrl&)));
161 this->connect(&wadseeker, SIGNAL(serviceStarted(QString)),
162 SLOT(serviceStarted(QString)));
163 this->connect(&wadseeker, SIGNAL(serviceFinished(QString)),
164 SLOT(serviceFinished(QString)));
167 d->twWads->connect(&wadseeker, SIGNAL(fileDownloadFinished(
const ModFile&)),
168 SLOT(setFileDownloadFinished(
const ModFile&)));
169 d->twWads->connect(&wadseeker, SIGNAL(fileDownloadProgress(
const ModFile&,qint64,qint64)),
170 SLOT(setFileProgress(
const ModFile&,qint64,qint64)));
171 d->twWads->connect(&wadseeker, SIGNAL(fileDownloadStarted(
const ModFile&,
const QUrl&)),
172 SLOT(setFileUrl(
const ModFile&,
const QUrl&)));
175 void WadseekerInterface::construct()
178 d->preventGame =
false;
179 d->bCompletedSuccessfully =
false;
183 d->taskbarProgress = d->taskbarButton->progress();
184 d->taskbarProgress->setMaximum(d->pbOverallProgress->maximum());
190 this->setWindowIcon(QIcon(
":/icon.png"));
191 d->btnStartGame->hide();
192 this->connect(&updateTimer, SIGNAL(timeout()), SLOT(registerUpdateRequest()));
194 connectWadseekerObject();
197 this->connect(d->twWads, SIGNAL(rightMouseClick(
const QModelIndex&,
const QPoint&)),
198 SLOT(wadsTableRightClicked(
const QModelIndex&,
const QPoint&)));
203 QStringList urlList = gConfig.wadseeker.searchURLs;
204 if (gConfig.wadseeker.bAlwaysUseDefaultSites)
206 for (
int i = 0; !Wadseeker::defaultSites[i].isEmpty(); ++i)
207 urlList << Wadseeker::defaultSites[i];
210 wadseeker.setPrimarySites(urlList);
212 updateTimer.setSingleShot(
false);
213 updateTimer.start(UPDATE_INTERVAL_MS);
218 if (!isInstantiated())
221 return currentInstance;
228 if (!isInstantiated())
231 return currentInstance;
239 if (interface !=
nullptr)
241 interface->setupAutomatic();
242 interface->d->preventGame =
true;
247 void WadseekerInterface::displayMessage(
const QString &message, WadseekerLib::MessageType type,
bool bPrependErrorsWithMessageType)
249 QString strProcessedMessage;
251 bool bPrependWithNewline =
false;
252 QString wrapHtmlLeft =
"<div style=\"%1\">";
253 QString wrapHtmlRight =
"</div>";
258 case WadseekerLib::CriticalError:
259 htmlStyle = QString(
"color: %1; font-weight: bold;").arg(colorHtmlMessageFatalError);
260 bPrependWithNewline =
true;
262 if (bPrependErrorsWithMessageType)
263 strProcessedMessage = tr(
"CRITICAL ERROR: %1").arg(message);
265 strProcessedMessage = message;
270 case WadseekerLib::Error:
271 htmlStyle = QString(
"color: %1;").arg(colorHtmlMessageError);
273 if (bPrependErrorsWithMessageType)
274 strProcessedMessage = tr(
"Error: %1").arg(message);
276 strProcessedMessage = message;
279 case WadseekerLib::Notice:
280 htmlStyle = QString(
"color: %1;").arg(colorHtmlMessageNotice);
282 strProcessedMessage = message;
285 case WadseekerLib::NoticeImportant:
286 htmlStyle = QString(
"color: %1; font-weight: bold;").arg(colorHtmlMessageNotice);
287 bPrependWithNewline =
true;
289 strProcessedMessage = message;
293 if (bPrependWithNewline && !d->teWadseekerOutput->toPlainText().isEmpty())
294 strProcessedMessage =
"<br>" + strProcessedMessage;
296 wrapHtmlLeft = wrapHtmlLeft.arg(htmlStyle);
298 strProcessedMessage = wrapHtmlLeft + strProcessedMessage + wrapHtmlRight;
300 d->teWadseekerOutput->append(strProcessedMessage);
303 void WadseekerInterface::fileDownloadSuccessful(
const ModFile &filename)
305 successfulWads << filename;
306 d->twWads->setFileSuccessful(filename.fileName());
309 void WadseekerInterface::initMessageColors()
311 colorHtmlMessageNotice = gConfig.wadseeker.colorMessageNotice;
312 colorHtmlMessageError = gConfig.wadseeker.colorMessageError;
313 colorHtmlMessageFatalError = gConfig.wadseeker.colorMessageCriticalError;
316 bool WadseekerInterface::isInstantiated()
318 return currentInstance !=
nullptr;
321 void WadseekerInterface::message(
const QString &message, WadseekerLib::MessageType type)
323 displayMessage(message, type,
true);
326 void WadseekerInterface::registerUpdateRequest()
332 void WadseekerInterface::reject()
341 this->done(Rejected);
346 void WadseekerInterface::resetTitleToDefault()
348 setWindowTitle(tr(
"Wadseeker"));
351 void WadseekerInterface::seekStarted(
const ModSet &filenames)
355 for (ModFile modFile : filenames.modFiles())
358 names << modFile.fileName();
360 d->teWadseekerOutput->clear();
361 d->pbOverallProgress->setValue(0);
362 d->taskbarProgress->setValue(0);
363 displayMessage(
"Seek started on filenames: " + names.join(
", "), WadseekerLib::Notice,
false);
366 successfulWads.clear();
367 d->twSites->setRowCount(0);
368 d->twWads->setRowCount(0);
369 setStateDownloading();
371 for (
const PWad &wad : seekedWads)
373 d->twWads->addFile(wad.name());
377 void WadseekerInterface::setStateDownloading()
379 d->btnClose->setText(tr(
"Abort"));
380 d->btnDownload->setEnabled(
false);
381 d->taskbarProgress->show();
385 void WadseekerInterface::setStateWaiting()
387 d->btnClose->setText(tr(
"Close"));
388 d->btnDownload->setEnabled(
true);
389 d->taskbarProgress->hide();
393 void WadseekerInterface::setupAutomatic()
397 d->btnDownload->hide();
398 d->leWadName->hide();
407 for (
PWad wad : wads)
411 d->leWadName->setText(names.join(
", "));
415 void WadseekerInterface::setupIdgames()
417 wadseeker.setIdgamesEnabled(gConfig.wadseeker.bSearchInIdgames);
418 wadseeker.setIdgamesUrl(gConfig.wadseeker.idgamesURL);
419 wadseeker.setWadArchiveEnabled(gConfig.wadseeker.bSearchInWadArchive);
422 void WadseekerInterface::showEvent(QShowEvent *event)
427 d->taskbarButton->setWindow(windowHandle());
431 startSeeking(seekedWads);
435 void WadseekerInterface::serviceStarted(
const QString &service)
437 d->twSites->addService(service);
440 void WadseekerInterface::serviceFinished(
const QString &service)
442 d->twSites->removeService(service);
445 void WadseekerInterface::siteFinished(
const QUrl &site)
447 d->twSites->removeUrl(site);
448 displayMessage(
"Site finished: " + site.toString(), WadseekerLib::Notice,
false);
451 void WadseekerInterface::siteProgress(
const QUrl &site, qint64 bytes, qint64 total)
453 d->twSites->setUrlProgress(site, bytes, total);
456 void WadseekerInterface::siteRedirect(
const QUrl &oldUrl,
const QUrl &newUrl)
458 d->twSites->removeUrl(oldUrl);
459 d->twSites->addUrl(newUrl);
460 displayMessage(
"Site redirect: " + oldUrl.toString() +
" -> " + newUrl.toString(), WadseekerLib::Notice,
false);
463 void WadseekerInterface::siteStarted(
const QUrl &site)
465 d->twSites->addUrl(site);
466 displayMessage(
"Site started: " + site.toString(), WadseekerLib::Notice,
false);
469 void WadseekerInterface::startSeeking(
const QList<PWad> &seekedFilesList)
471 if (seekedFilesList.isEmpty())
473 d->bCompletedSuccessfully =
false;
476 for (
PWad seekedFile : seekedFilesList)
478 listWads.addModFile(seekedFile);
483 wadseeker.setTargetDirectory(gConfig.wadseeker.targetDirectory);
484 wadseeker.setCustomSites(customSites);
485 wadseeker.setMaximumConcurrentSeeks(gConfig.wadseeker.maxConcurrentSiteDownloads);
486 wadseeker.setMaximumConcurrentDownloads(gConfig.wadseeker.maxConcurrentWadDownloads);
487 wadseeker.startSeek(listWads);
490 void WadseekerInterface::updateProgressBar()
492 double totalPercentage = d->twWads->totalDonePercentage();
493 auto progressBarValue = (unsigned)(totalPercentage * 100.0);
495 d->pbOverallProgress->setValue(progressBarValue);
496 d->taskbarProgress->setValue(progressBarValue);
499 void WadseekerInterface::updateTitle()
505 double totalPercentage = d->twWads->totalDonePercentage();
506 if (totalPercentage < 0.0)
507 totalPercentage = 0.0;
509 setWindowTitle(tr(
"[%1%] Wadseeker").arg(totalPercentage, 6,
'f', 2));
515 resetTitleToDefault();
520 QList<PWad> WadseekerInterface::unsuccessfulWads()
const
522 QList<PWad> allWads = seekedWads;
523 for (
PWad successfulWad : successfulWads)
525 for (
int i = 0; i < allWads.size(); ++i)
527 if (allWads[i].name() == successfulWad.name())
537 void WadseekerInterface::wadsTableRightClicked(
const QModelIndex &index,
const QPoint &cursorPosition)
542 QString fileName = d->twWads->fileNameAtRow(index.row());
543 if (!wadseeker.isDownloadingFile(fileName))
544 menu->actionSkipCurrentSite->setEnabled(
false);
546 QAction *pResult = menu->exec();
548 if (pResult == menu->actionSkipCurrentSite)
550 QString wadName = d->twWads->fileNameAtRow(index.row());
551 d->twWads->setFileUrl(fileName, QUrl());
553 wadseeker.skipFileCurrentUrl(wadName);
555 else if (pResult !=
nullptr)
556 QMessageBox::warning(
this, tr(
"Context menu error"), tr(
"Unknown action selected."));