23 #include "configuration/doomseekerconfig.h" 24 #include "configuration/queryspeed.h" 25 #include "gui/configuration/irc/ircconfigurationdialog.h" 26 #include "gui/configuration/doomseekerconfigurationdialog.h" 27 #include "gui/helpers/playersdiagram.h" 28 #include "gui/irc/ircdock.h" 29 #include "gui/irc/ircsounds.h" 30 #include "gui/models/serverlistmodel.h" 31 #include "gui/widgets/serversstatuswidget.h" 32 #include "gui/aboutdialog.h" 33 #include "gui/copytextdlg.h" 34 #include "gui/createserverdialog.h" 35 #include "gui/demomanager.h" 36 #include "gui/dockBuddiesList.h" 37 #include "gui/helpers/taskbarbutton.h" 38 #include "gui/helpers/taskbarprogress.h" 39 #include "gui/freedoomdialog.h" 40 #include "gui/ip2cupdatebox.h" 41 #include "gui/logdock.h" 42 #include "gui/mainwindow.h" 43 #include "gui/programargshelpdialog.h" 44 #include "gui/serverdetailsdock.h" 45 #include "gui/serverfilterdock.h" 46 #include "gui/serverlist.h" 47 #include "gui/wadseekerinterface.h" 48 #include "gui/wadseekershow.h" 49 #include "ip2c/ip2cloader.h" 50 #include "irc/configuration/chatnetworkscfg.h" 51 #include "irc/configuration/ircconfig.h" 52 #include "pathfinder/pathfinder.h" 53 #include "plugins/engineplugin.h" 54 #include "plugins/pluginloader.h" 55 #include "refresher/refresher.h" 56 #include "serverapi/broadcast.h" 57 #include "serverapi/broadcastmanager.h" 58 #include "serverapi/gameclientrunner.h" 59 #include "serverapi/mastermanager.h" 60 #include "serverapi/message.h" 61 #include "serverapi/server.h" 62 #include "serverapi/serverlistcounttracker.h" 63 #include "updater/autoupdater.h" 64 #include "updater/updatechannel.h" 65 #include "updater/updateinstaller.h" 66 #include "updater/updatepackage.h" 67 #include "apprunner.h" 68 #include "commandline.h" 69 #include "connectionhandler.h" 70 #include "customservers.h" 71 #include "doomseekerfilepaths.h" 72 #include "fileutils.h" 74 #include "joincommandlinebuilder.h" 75 #include "pathfinder/wadpathfinder.h" 79 #include "ui_mainwindow.h" 82 #include <QApplication> 83 #include <QDesktopServices> 84 #include <QDesktopWidget> 85 #include <QDockWidget> 87 #include <QHeaderView> 90 #include <QMessageBox> 92 #include <QProgressBar> 94 #include <QSizePolicy> 96 const QString MainWindow::HELP_SITE_URL =
"http://doomseeker.drdteam.org/help";
105 class QueryMenuAction :
public QAction
111 this->pPlugin = plugin;
115 connect(
this, SIGNAL( toggled(
bool) ), plugin->data()->masterClient,
116 SLOT( setEnabled(
bool) ) );
117 connect(
this, SIGNAL( toggled(
bool) ), statusWidget, SLOT( setMasterEnabledStatus(
bool) ) );
130 DClass<MainWindow> :
public Ui::MainWindowWnd
133 PrivData() : bTotalRefreshInProcess(false), buddiesList(NULL),
134 bWasMaximized(false), bWantToQuit(false), logDock(NULL),
135 masterManager(NULL), trayIcon(NULL), trayIconMenu(NULL)
139 QApplication* application;
140 QTimer autoRefreshTimer;
143 QWidget* autoUpdaterStatusBarWidget;
144 QPushButton* autoUpdaterAbortButton;
145 QLabel* autoUpdaterLabel;
146 QProgressBar* autoUpdaterFileProgressBar;
147 QProgressBar* autoUpdaterOverallProgressBar;
153 bool bTotalRefreshInProcess;
171 QProgressBar* ip2cUpdateProgressBar;
175 QPointer<FreedoomDialog> freedoomDialog;
180 QHash<const EnginePlugin*, QueryMenuAction*> queryMenuPorts;
181 QHash<const EnginePlugin*, ServersStatusWidget*> serversStatusesWidgets;
182 QAction* toolBarGetServers;
183 QSystemTrayIcon* trayIcon;
187 int updaterInstallerErrorCode;
190 QDockWidget *mainDock;
200 d->autoUpdater = NULL;
202 d->connectionHandler = NULL;
204 d->updaterInstallerErrorCode = 0;
206 d->application = application;
208 this->setAttribute(Qt::WA_DeleteOnClose,
true);
212 d->taskbarProgress = d->taskbarButton->progress();
216 initAutoUpdaterWidgets();
218 d->updatesConfirmationWidget->hide();
219 d->updatesDownloadedWidget->hide();
222 #ifndef WITH_AUTOUPDATES 223 d->menuActionCheckForUpdates->setVisible(
false);
226 if (gPlugins->numPlugins() == 0)
228 QString message = tr(
230 "Doomseeker failed to detect any plugins.\n" 231 "While the core application will still work its functionality is going to be limited.\n" 232 "One of the proper locations for plugin modules is the \"engines/\" directory.\n" 235 QMessageBox::critical(NULL, tr(
"Doomseeker - plugin load failure"), message);
242 d->menuView->addAction(d->buddiesList->toggleViewAction());
243 d->buddiesList->toggleViewAction()->setText(tr(
"&Buddies"));
244 d->buddiesList->toggleViewAction()->setShortcut(tr(
"CTRL+B"));
246 connect(d->buddiesList, SIGNAL(joinServer(ServerPtr)),
this, SLOT(runGame(ServerPtr)));
247 d->buddiesList->hide();
248 this->addDockWidget(Qt::LeftDockWidgetArea, d->buddiesList);
251 initServerFilterDock();
253 splitDockWidget(d->mainDock, d->serverFilterDock, Qt::Horizontal);
256 d->serverList =
new ServerList(d->tableServers,
this);
260 d->serverList->connect(d->broadcastManager,
261 SIGNAL(newServerDetected(ServerPtr,
int)), SLOT(registerServer(ServerPtr)));
262 d->serverList->connect(d->broadcastManager,
263 SIGNAL(serverLost(ServerPtr)), SLOT(removeServer(ServerPtr)));
265 initServerDetailsDock();
266 tabifyDockWidget(d->ircDock, d->detailsDock);
269 d->menuActionRecordDemo->setChecked(gConfig.doomseeker.bRecordDemo);
273 d->buddiesList->scan(d->masterManager);
274 connect(d->masterManager, SIGNAL( masterMessage(
MasterClient*,
const QString&,
const QString&,
bool) ),
275 this, SLOT( masterManagerMessages(
MasterClient*,
const QString&,
const QString&,
bool) ) );
280 fillQueryMenu(d->masterManager);
283 QList<ServerPtr> customServers = d->masterManager->customServs()->readConfig();
284 foreach (ServerPtr server, customServers)
286 d->serverList->registerServer(server);
289 setWindowIcon(QIcon(
":/icon.png"));
292 initAutoRefreshTimer();
293 connect(&d->autoRefreshTimer, SIGNAL( timeout() ),
this, SLOT( autoRefreshTimer_timeout() ));
301 int slotStyle = gConfig.doomseeker.slotStyle;
305 d->menuActionUpdateIP2C->setEnabled(
false);
307 connectIP2CLoader(d->ip2cLoader);
308 d->ip2cLoader->load();
310 restoreState(QByteArray::fromBase64(gConfig.doomseeker.mainWindowState.toUtf8()));
311 restoreGeometry(gConfig.doomseeker.mainWindowGeometry);
315 QTimer::singleShot(1,
this, SLOT(postInitAppStartup()));
318 MainWindow::~MainWindow()
321 gConfig.doomseeker.mainWindowGeometry = saveGeometry();
322 gConfig.doomseeker.mainWindowState = saveState().toBase64();
324 if (d->updateChannelOnUpdateStart != NULL)
326 delete d->updateChannelOnUpdateStart;
328 if (d->autoUpdater != NULL)
330 d->autoUpdater->disconnect();
331 delete d->autoUpdater;
333 if(d->connectionHandler)
334 delete d->connectionHandler;
336 QList<QAction*> menuQueryActions = d->menuQuery->actions();
337 QList<QAction*>::iterator it;
338 foreach (QAction *action, menuQueryActions)
340 QString pluginName = action->text();
342 if (!pluginName.isEmpty())
344 IniSection pluginConfig = gConfig.iniSectionForPlugin(pluginName);
345 pluginConfig[
"Query"] = action->isChecked();
349 if (d->trayIcon != NULL)
351 d->trayIcon->setVisible(
false);
356 if (d->trayIconMenu != NULL)
358 delete d->trayIconMenu;
359 d->trayIconMenu = NULL;
362 delete d->serverList;
364 if(d->masterManager != NULL)
366 delete d->masterManager;
369 if (d->ip2cLoader != NULL)
371 delete d->ip2cLoader;
375 void MainWindow::abortAutoUpdater()
377 if (d->autoUpdater != NULL)
379 d->autoUpdater->abort();
383 void MainWindow::autoRefreshTimer_timeout()
385 if (gConfig.doomseeker.bQueryAutoRefreshDontIfActive && !isMinimized())
387 if (QApplication::activeWindow() != 0)
396 void MainWindow::blockRefreshButtons()
398 d->toolBarGetServers->setEnabled(
false);
403 return d->buddiesList;
406 void MainWindow::changeEvent(QEvent* event)
408 if (event->type() == QEvent::ActivationChange && isActiveWindow() && !isMinimized() && !isHidden())
410 d->serverList->cleanUp();
413 QMainWindow::changeEvent(event);
416 void MainWindow::checkForUpdates(
bool bUserTriggered)
418 if (d->autoUpdater != NULL)
420 if (d->autoUpdater->isRunning())
422 QMessageBox::warning(
this, tr(
"Doomseeker - Auto Update"),
423 tr(
"Update is already in progress."));
428 delete d->autoUpdater;
429 d->autoUpdater = NULL;
432 gLog << tr(
"Removing old update packages from local temporary space.");
433 QStringList removeFilter(QString(
"%1*").arg(DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX));
437 showAndLogStatusMessage(tr(
"Checking for updates..."));
439 this->connect(d->autoUpdater, SIGNAL(statusMessage(QString)),
440 SLOT(showAndLogStatusMessage(QString)));
441 this->connect(d->autoUpdater, SIGNAL(finished()),
442 SLOT(onAutoUpdaterFinish()));
443 this->connect(d->autoUpdater, SIGNAL(downloadAndInstallConfirmationRequested()),
444 SLOT(onAutoUpdaterDownloadAndInstallConfirmationRequest()));
445 this->connect(d->autoUpdater, SIGNAL(overallProgress(
int,
int,
const QString&)),
446 SLOT(onAutoUpdaterOverallProgress(
int,
int,
const QString&)));
447 this->connect(d->autoUpdater, SIGNAL(packageDownloadProgress(qint64, qint64)),
448 SLOT(onAutoUpdaterFileProgress(qint64, qint64)));
450 QMap<QString, QList<QString> > ignoredPackagesRevisions;
453 foreach (
const QString& package, gConfig.autoUpdates.lastKnownUpdateRevisions.keys())
455 QString revision = gConfig.autoUpdates.lastKnownUpdateRevisions[package];
458 ignoredPackagesRevisions.insert(package, list);
461 d->autoUpdater->setIgnoreRevisions(ignoredPackagesRevisions);
464 d->autoUpdater->setChannel(channel);
465 *d->updateChannelOnUpdateStart = channel;
467 bool bRequireConfirmation =
true;
470 bRequireConfirmation = (gConfig.autoUpdates.updateMode
473 d->autoUpdater->setRequireDownloadAndInstallConfirmation(bRequireConfirmation);
474 d->autoUpdaterStatusBarWidget->show();
475 d->autoUpdater->start();
481 const bool bUserTriggered =
true;
482 checkForUpdates(!bUserTriggered);
487 const bool bUserTriggered =
true;
488 checkForUpdates(bUserTriggered);
491 void MainWindow::closeEvent(QCloseEvent* event)
496 if (d->trayIcon != NULL && gConfig.doomseeker.bCloseToTrayIcon && !d->bWantToQuit)
498 d->bWasMaximized = isMaximized();
508 void MainWindow::confirmUpdateInstallation()
510 assert(d->autoUpdater != NULL &&
"MainWindow::confirmUpdateInstallation()");
511 d->updatesConfirmationWidget->hide();
512 d->autoUpdater->confirmDownloadAndInstall();
515 void MainWindow::connectIP2CLoader(
IP2CLoader* loader)
517 this->connect(d->ip2cLoader, SIGNAL( finished() ), SLOT( ip2cJobsFinished()));
518 this->connect(d->ip2cLoader, SIGNAL( downloadProgress(qint64, qint64) ),
519 SLOT( ip2cDownloadProgress(qint64, qint64) ) );
522 void MainWindow::discardUpdates()
524 assert(d->autoUpdater != NULL &&
"MainWindow::confirmUpdateInstallation()");
525 d->updatesConfirmationWidget->hide();
528 const QList<UpdatePackage>& pkgList = d->autoUpdater->newUpdatePackages();
531 gConfig.autoUpdates.lastKnownUpdateRevisions.insert(pkg.
name, pkg.
revision);
533 d->autoUpdater->abort();
539 connect(gRefresher, SIGNAL( block() ),
this, SLOT( blockRefreshButtons() ) );
540 connect(gRefresher, SIGNAL( finishedQueryingMaster(
MasterClient*) ),
this, SLOT( finishedQueryingMaster(
MasterClient*) ) );
541 connect(gRefresher, SIGNAL( sleepingModeEnter() ),
this, SLOT( refreshThreadEndsWork() ) );
542 connect(gRefresher, SIGNAL( sleepingModeEnter() ), d->buddiesList, SLOT( scan() ) );
543 connect(gRefresher, SIGNAL( sleepingModeExit() ),
this, SLOT( refreshThreadBeginsWork() ) );
546 connect(d->menuActionAbout, SIGNAL( triggered() ),
this, SLOT( menuHelpAbout() ));
547 connect(d->menuActionAboutQt, SIGNAL( triggered() ), d->application, SLOT( aboutQt() ));
548 connect(d->menuActionBuddies, SIGNAL( triggered() ),
this, SLOT( menuBuddies() ));
549 connect(d->menuActionConfigure, SIGNAL( triggered() ),
this, SLOT( menuOptionsConfigure() ));
550 connect(d->menuActionCreateServer, SIGNAL( triggered() ),
this, SLOT( menuCreateServer() ));
551 connect(d->menuActionHelp, SIGNAL( triggered() ),
this, SLOT ( menuHelpHelp() ) );
552 connect(d->menuActionIRCOptions, SIGNAL( triggered() ),
this, SLOT( menuIRCOptions() ) );
553 connect(d->menuActionLog, SIGNAL( triggered() ),
this, SLOT( menuLog() ));
554 connect(d->menuActionManageDemos, SIGNAL( triggered() ),
this, SLOT( menuManageDemos() ) );
555 connect(d->menuActionRecordDemo, SIGNAL( triggered() ),
this, SLOT( menuRecordDemo() ) );
556 connect(d->menuActionUpdateIP2C, SIGNAL( triggered() ),
this, SLOT( menuUpdateIP2C() ) );
557 connect(d->menuActionQuit, SIGNAL( triggered() ),
this, SLOT( quitProgram() ));
558 connect(d->menuActionViewIRC, SIGNAL( triggered() ) ,
this, SLOT( menuViewIRC() ));
559 connect(d->menuActionWadseeker, SIGNAL( triggered() ),
this, SLOT( menuWadSeeker() ));
562 connect(d->serverFilterDock, SIGNAL(nonEmptyServerGroupingAtTopToggled(
bool)),
563 d->serverList, SLOT(setGroupServersWithPlayersAtTop(
bool)) );
566 connect(d->serverList, SIGNAL( serverDoubleClicked(ServerPtr) ),
this, SLOT( runGame(ServerPtr) ) );
567 connect(d->serverList, SIGNAL( displayServerJoinCommandLine(
const ServerPtr&) ),
this, SLOT( showServerJoinCommandLine(
const ServerPtr&) ) );
568 connect(d->serverList, SIGNAL( findMissingWADs(
const ServerPtr&) ),
this, SLOT( findMissingWADs(
const ServerPtr&) ) );
569 connect(d->serverList, SIGNAL( serverInfoUpdated(ServerPtr) ),
this, SLOT( serverAddedToList(ServerPtr) ) );
570 connect(d->buddiesList, SIGNAL(scanCompleted()), d->serverList, SLOT(redraw()));
577 for(
unsigned i = 0; i < gPlugins->numPlugins(); ++i)
580 if(!plugin->data()->hasMasterClient() && !plugin->data()->hasBroadcast())
585 if (plugin->data()->hasMasterClient())
587 MasterClient* pMasterClient = plugin->data()->masterClient;
588 pMasterClient->updateAddress();
589 masterManager->addMaster(pMasterClient);
592 if (plugin->data()->hasBroadcast())
594 d->broadcastManager->registerPlugin(plugin);
599 d->serversStatusesWidgets.insert(plugin, statusWidget);
601 this->connect(statusWidget, SIGNAL( clicked(
const EnginePlugin*) ) ,
602 SLOT( togglePluginQueryEnabled(
const EnginePlugin*) ) );
603 this->connect(statusWidget, SIGNAL(counterUpdated()),
604 SLOT(updateRefreshProgress()));
606 statusBar()->addPermanentWidget(statusWidget);
608 QString name = gPlugins->info(i)->data()->name;
609 QueryMenuAction* query =
new QueryMenuAction(plugin, statusWidget, d->menuQuery);
610 d->queryMenuPorts.insert(plugin, query);
612 d->menuQuery->addAction(query);
614 query->setCheckable(
true);
615 query->setIcon(plugin->icon());
616 query->setText(name);
618 IniSection pluginConfig = gConfig.iniSectionForPlugin(name);
622 bool enabled = pluginConfig[
"Query"];
623 setQueryPluginEnabled(plugin, enabled);
629 setQueryPluginEnabled(plugin,
true);
634 void MainWindow::findMissingWADs(
const ServerPtr &server)
637 QList<PWad> wads = server->wads();
638 wads << server->iwad();
639 PathFinder pathFinder = server->wadPathFinder();
641 QList<PWad> missingWads;
642 foreach(
const PWad &wad, wads)
644 if(!wadFinder.find(wad.
name()).isValid())
647 missingWads << optionalWad;
650 if (missingWads.isEmpty())
652 QMessageBox::information(
this, tr(
"All WADs found"), tr(
"All of the WADs used by this server are present."));
657 dialog.setAllowIgnore(
false);
658 if (dialog.exec() == QDialog::Accepted && dialog.decision() == MissingWadsDialog::Install)
660 if (!gWadseekerShow->checkWadseekerValidity(
this))
665 wadseeker->setCustomSite(server->webSite());
666 wadseeker->
setWads(dialog.filesToDownload());
667 wadseeker->setAttribute(Qt::WA_DeleteOnClose);
675 updateMasterAddresses();
676 gRefresher->setDelayBetweenResends(gConfig.doomseeker.querySpeed().delayBetweenSingleServerAttempts);
679 if (configDialog.appearanceChanged())
681 d->tableServers->setShowGrid(gConfig.doomseeker.bDrawGridInServerTable);
682 d->serverList->redraw();
687 if (lookupHostsChanged)
689 d->serverList->lookupHosts();
693 if (configDialog.customServersChanged())
695 d->serverList->removeCustomServers();
696 QList<ServerPtr> servers = d->masterManager->customServs()->readConfig();
697 foreach (ServerPtr server, servers)
699 d->serverList->registerServer(server);
701 refreshCustomServers();
705 void MainWindow::finishedQueryingMaster(
MasterClient* master)
712 for(
int i = 0;i < master->numServers();i++)
714 d->serverList->registerServer((*master)[i]);
718 void MainWindow::fixIconsDpi()
721 QIcon icon(
":/icons/exclamation_16.png");
722 d->lblExclamation1->setPixmap(icon.pixmap(16));
723 d->lblExclamation2->setPixmap(icon.pixmap(16));
726 void MainWindow::getServers()
729 if (!isAnythingToRefresh())
731 gLog << tr(
"Senseless refresh operation attempted.");
733 QString message = tr(
"Doomseeker is unable to proceed with the refresh" 734 " operation because the following problem has occured:\n\n");
736 if (gPlugins->numPlugins() == 0)
738 message += tr(
"Plugins are missing from the \"engines/\" directory.");
740 else if (!isAnyMasterEnabled())
742 message += tr(
"No master servers are enabled in the \"Query\" menu.");
746 message += tr(
"Unknown error occured.");
750 QMessageBox::warning(
this, tr(
"Doomseeker - senseless operation"), message);
754 d->bTotalRefreshInProcess =
true;
755 d->autoRefreshTimer.stop();
756 gLog << tr(
"Total refresh process initialized!");
757 d->serverList->removeNonSpecialServers();
758 refreshCustomServers();
761 if (!isAnyMasterEnabled())
763 gLog << tr(
"Warning: No master servers were enabled for this refresh. " 764 "Check your Query menu or \"engines/\" directory. Custom servers will still refresh.");
767 d->masterManager->clearServers();
768 for (
int i = 0; i < d->masterManager->numMasters(); ++i)
774 gRefresher->registerMaster(pMaster);
779 bool MainWindow::hasCustomServers()
const 781 CustomServers* customServers = d->masterManager->customServs();
782 return customServers->numServers() > 0;
787 const unsigned MIN_DELAY = 30;
788 const unsigned MAX_DELAY = 3600;
790 bool bEnabled = gConfig.doomseeker.bQueryAutoRefreshEnabled;
794 d->autoRefreshTimer.stop();
800 unsigned& delay = gConfig.doomseeker.queryAutoRefreshEverySeconds;
803 if (delay < MIN_DELAY)
807 else if (delay > MAX_DELAY)
812 unsigned delayMs = delay * 1000;
814 d->autoRefreshTimer.setSingleShot(
false);
815 d->autoRefreshTimer.start(delayMs);
819 void MainWindow::initAutoUpdaterWidgets()
821 static const int FILE_BAR_WIDTH = 50;
822 static const int OVERALL_BAR_WIDTH = 180;
824 d->autoUpdaterStatusBarWidget =
new QWidget(statusBar());
825 d->autoUpdaterStatusBarWidget->setLayout(
new QHBoxLayout(d->autoUpdaterStatusBarWidget));
826 d->autoUpdaterStatusBarWidget->layout()->setContentsMargins(QMargins(0, 0, 0, 0));
827 statusBar()->addPermanentWidget(d->autoUpdaterStatusBarWidget);
828 d->autoUpdaterStatusBarWidget->hide();
830 d->autoUpdaterLabel =
new QLabel(d->autoUpdaterStatusBarWidget);
831 d->autoUpdaterLabel->setText(tr(
"Auto Updater:"));
832 d->autoUpdaterStatusBarWidget->layout()->addWidget(d->autoUpdaterLabel);
834 d->autoUpdaterFileProgressBar = mkStdProgressBarForStatusBar();
835 d->autoUpdaterFileProgressBar->setFormat(
"%p%");
836 d->autoUpdaterFileProgressBar->setMaximumWidth(FILE_BAR_WIDTH);
837 d->autoUpdaterFileProgressBar->setMinimumWidth(FILE_BAR_WIDTH);
838 d->autoUpdaterStatusBarWidget->layout()->addWidget(d->autoUpdaterFileProgressBar);
840 d->autoUpdaterOverallProgressBar = mkStdProgressBarForStatusBar();
841 d->autoUpdaterOverallProgressBar->setMaximumWidth(OVERALL_BAR_WIDTH);
842 d->autoUpdaterOverallProgressBar->setMinimumWidth(OVERALL_BAR_WIDTH);
843 d->autoUpdaterStatusBarWidget->layout()->addWidget(d->autoUpdaterOverallProgressBar);
845 d->autoUpdaterAbortButton =
new QPushButton(statusBar());
846 d->autoUpdaterAbortButton->setToolTip(tr(
"Abort update."));
847 d->autoUpdaterAbortButton->setIcon(QIcon(
":/icons/x.png"));
848 this->connect(d->autoUpdaterAbortButton, SIGNAL(clicked()),
849 SLOT(abortAutoUpdater()));
850 d->autoUpdaterStatusBarWidget->layout()->addWidget(d->autoUpdaterAbortButton);
853 void MainWindow::initIP2CUpdater()
855 static const int PROGRESSBAR_WIDTH = 220;
857 d->ip2cUpdateProgressBar = mkStdProgressBarForStatusBar();
858 d->ip2cUpdateProgressBar->setFormat(tr(
"IP2C Update"));
859 d->ip2cUpdateProgressBar->hide();
860 d->ip2cUpdateProgressBar->setMaximumWidth(PROGRESSBAR_WIDTH);
861 d->ip2cUpdateProgressBar->setMinimumWidth(PROGRESSBAR_WIDTH);
862 statusBar()->addPermanentWidget(d->ip2cUpdateProgressBar);
865 void MainWindow::initIRCDock()
867 d->ircDock =
new IRCDock(
this);
868 d->menuView->addAction(d->ircDock->toggleViewAction());
869 d->ircDock->toggleViewAction()->setText(tr(
"&IRC"));
870 d->ircDock->toggleViewAction()->setShortcut(tr(
"CTRL+I"));
872 this->addDockWidget(Qt::BottomDockWidgetArea, d->ircDock);
876 this->d->ircDock->setVisible(
true);
877 this->d->ircDock->performNetworkAutojoins();
881 void MainWindow::initLogDock()
883 d->logDock =
new LogDock(
this);
884 d->menuView->addAction(d->logDock->toggleViewAction());
885 d->logDock->toggleViewAction()->setText(tr(
"&Log"));
886 d->logDock->toggleViewAction()->setShortcut(tr(
"CTRL+L"));
888 this->addDockWidget(Qt::BottomDockWidgetArea, d->logDock);
890 connect(&gLog, SIGNAL( newEntry(
const QString&) ), d->logDock, SLOT( appendLogEntry(
const QString&) ) );
893 d->logDock->appendLogEntry(gLog.content());
896 void MainWindow::initMainDock()
898 setDockNestingEnabled(
true);
902 d->mainDock =
new QDockWidget(tr(
"Servers"));
903 d->mainDock->setTitleBarWidget(
new QWidget(
this));
904 d->mainDock->setObjectName(
"ServerList");
905 d->mainDock->setFeatures(QDockWidget::NoDockWidgetFeatures);
906 d->mainDock->setWidget(centralWidget());
908 addDockWidget(Qt::RightDockWidgetArea, d->mainDock);
911 void MainWindow::initServerDetailsDock()
914 d->menuView->addAction(d->detailsDock->toggleViewAction());
915 d->detailsDock->toggleViewAction()->setText(tr(
"Server &Details"));
916 d->detailsDock->toggleViewAction()->setShortcut(tr(
"CTRL+D"));
917 d->detailsDock->hide();
918 addDockWidget(Qt::BottomDockWidgetArea, d->detailsDock);
920 d->detailsDock->connect(d->serverList, SIGNAL( serversSelected(QList<ServerPtr>&) ), SLOT( displaySelection(QList<ServerPtr> &) ));
923 void MainWindow::initServerFilterDock()
927 d->menuView->addAction(d->serverFilterDock->toggleViewAction());
928 d->serverFilterDock->hide();
929 this->addDockWidget(Qt::RightDockWidgetArea, d->serverFilterDock);
934 bool isEnabled = gConfig.doomseeker.bUseTrayIcon;
935 if (!isEnabled || !QSystemTrayIcon::isSystemTrayAvailable())
937 if (d->trayIcon != NULL)
943 if (d->trayIconMenu != NULL)
945 delete d->trayIconMenu;
946 d->trayIconMenu = NULL;
949 else if (d->trayIcon == NULL)
952 d->trayIconMenu =
new QMenu(
this);
953 trayAction = d->trayIconMenu->addAction(
"Exit");
954 connect(trayAction, SIGNAL( triggered() ),
this, SLOT( quitProgram() ) );
957 d->trayIcon =
new QSystemTrayIcon(
this);
958 connect(d->trayIcon, SIGNAL( activated(QSystemTrayIcon::ActivationReason) ),
this, SLOT( trayIcon_activated(QSystemTrayIcon::ActivationReason) ) );
960 updateTrayIconTooltipAndLogTotalRefresh();
962 d->trayIcon->setContextMenu(d->trayIconMenu);
963 d->trayIcon->setIcon(QIcon(
":/icon.png"));
964 d->trayIcon->setVisible(
true);
968 void MainWindow::ip2cDownloadProgress(qint64 current, qint64 max)
970 d->ip2cUpdateProgressBar->setMaximum(max);
971 d->ip2cUpdateProgressBar->setValue(current);
974 void MainWindow::ip2cJobsFinished()
976 d->menuActionUpdateIP2C->setEnabled(
true);
977 d->serverList->updateCountryFlags();
978 d->ip2cUpdateProgressBar->hide();
980 if (d->ip2cLoader != NULL)
982 delete d->ip2cLoader;
983 d->ip2cLoader = NULL;
987 void MainWindow::ip2cStartUpdate()
989 if (d->ip2cLoader != NULL)
995 d->menuActionUpdateIP2C->setEnabled(
false);
996 d->ip2cUpdateProgressBar->show();
999 connectIP2CLoader(d->ip2cLoader);
1000 d->ip2cLoader->update();
1005 return hasCustomServers() || isAnyMasterEnabled();
1008 bool MainWindow::isAnyMasterEnabled()
const 1010 for (
int i = 0; i < d->masterManager->numMasters(); ++i)
1023 void MainWindow::masterManagerMessages(
MasterClient* pSender,
const QString& title,
const QString& content,
bool isError)
1025 QString message = tr(
"Master server for %1: %2").arg(pSender->
plugin()->data()->name).arg(content);
1029 message = tr(
"Error: %1").arg(message);
1030 statusBar()->showMessage(message);
1036 void MainWindow::masterManagerMessagesImportant(
MasterClient* pSender,
const Message& objMessage)
1038 QString strFullMessage = tr(
"%1: %2")
1039 .arg(pSender->
plugin()->data()->name)
1041 d->importantMessagesWidget->addMessage(strFullMessage, objMessage.
timestamp());
1044 void MainWindow::menuBuddies()
1046 d->buddiesList->setVisible(!d->buddiesList->isVisible());
1049 void MainWindow::menuCreateServer()
1053 dialog->setWindowIcon(this->windowIcon());
1057 void MainWindow::menuHelpAbout()
1060 d->autoRefreshTimer.stop();
1062 initAutoRefreshTimer();
1065 void MainWindow::menuHelpHelp()
1069 QMessageBox::critical(
this, tr(
"Help error"), tr(
"No help found."), QMessageBox::Ok, QMessageBox::Ok);
1073 bool bSuccess = QDesktopServices::openUrl(HELP_SITE_URL);
1077 QMessageBox::critical(
this, tr(
"Help error"), tr(
"Failed to open URL:\n%1").arg(HELP_SITE_URL), QMessageBox::Ok, QMessageBox::Ok);
1082 void MainWindow::menuIRCOptions()
1085 dialog.initOptionsList();
1088 if (d->ircDock != NULL)
1090 d->ircDock->applyAppearanceSettings();
1095 d->ircDock->sounds().loadFromConfig();
1099 void MainWindow::menuLog()
1101 d->logDock->setVisible(!d->logDock->isVisible());
1104 void MainWindow::menuManageDemos()
1110 void MainWindow::menuOptionsConfigure()
1112 DoomseekerConfigurationDialog::openConfiguration();
1115 void MainWindow::menuRecordDemo()
1117 gConfig.doomseeker.bRecordDemo = d->menuActionRecordDemo->isChecked();
1120 void MainWindow::menuUpdateIP2C()
1124 connect(&updateBox, SIGNAL( accepted() ),
this, SLOT( ip2cStartUpdate() ) );
1129 void MainWindow::menuViewIRC()
1131 d->ircDock->setVisible(!d->ircDock->isVisible());
1134 void MainWindow::menuWadSeeker()
1136 if (gWadseekerShow->checkWadseekerValidity(
this))
1139 wadseeker->setAttribute(Qt::WA_DeleteOnClose);
1144 QProgressBar* MainWindow::mkStdProgressBarForStatusBar()
1146 QProgressBar* pBar =
new QProgressBar(statusBar());
1147 pBar->setAlignment(Qt::AlignCenter);
1148 pBar->setTextVisible(
true);
1149 pBar->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1153 void MainWindow::notifyFirstRun()
1156 QMessageBox::information(NULL, tr(
"Welcome to Doomseeker"),
1157 tr(
"Before you start browsing for servers, please ensure that Doomseeker is properly configured."));
1158 d->menuActionConfigure->trigger();
1161 void MainWindow::onAutoUpdaterDownloadAndInstallConfirmationRequest()
1163 d->updatesConfirmationWidget->show();
1166 void MainWindow::onAutoUpdaterFileProgress(qint64 bytesReceived, qint64 bytesTotal)
1168 d->autoUpdaterFileProgressBar->setValue(bytesReceived);
1169 d->autoUpdaterFileProgressBar->setMaximum(bytesTotal);
1172 void MainWindow::onAutoUpdaterFinish()
1174 showAndLogStatusMessage(tr(
"Program update detection & download finished with status: [%1] %2")
1175 .arg((
int)d->autoUpdater->errorCode()).arg(d->autoUpdater->errorString()));
1176 gConfig.autoUpdates.bPerformUpdateOnNextRun =
false;
1177 if (d->autoUpdater->errorCode() == AutoUpdater::EC_Ok)
1180 if (channel == *d->updateChannelOnUpdateStart)
1182 if (!d->autoUpdater->downloadedPackagesFilenames().isEmpty())
1184 gLog << tr(
"Updates will be installed on next program start.");
1185 d->updatesDownloadedWidget->show();
1186 gConfig.autoUpdates.bPerformUpdateOnNextRun =
true;
1191 gLog << tr(
"Update channel was changed during update process. Discarding update.");
1194 gConfig.saveToFile();
1195 d->autoUpdaterStatusBarWidget->hide();
1196 d->updatesConfirmationWidget->hide();
1197 d->autoUpdater->deleteLater();
1198 d->autoUpdater = NULL;
1201 void MainWindow::onAutoUpdaterOverallProgress(
int current,
int total,
1204 d->autoUpdaterOverallProgressBar->setValue(current);
1205 d->autoUpdaterOverallProgressBar->setMaximum(total);
1206 d->autoUpdaterOverallProgressBar->setFormat(msg);
1209 void MainWindow::postInitAppStartup()
1212 d->serverFilterDock->setFilterInfo(gConfig.serverFilter.info);
1218 if (gPlugins->numPlugins() > 0)
1220 bool bGettingServers =
false;
1221 bool queryOnStartup = gConfig.doomseeker.bQueryOnStartup;
1228 if (isAnyMasterEnabled())
1230 bGettingServers =
true;
1235 gLog << tr(
"Query on startup warning: No master servers are enabled in the Query menu.");
1241 if (!bGettingServers && hasCustomServers())
1246 refreshCustomServers();
1253 QMessageBox::critical(NULL, tr(
"Doomseeker critical error"),
1254 tr(
"Doomseeker was unable to find any plugin libraries.\n" 1255 "Although the application will still work it will not be possible " 1256 "to fetch any server info or launch any game.\n\n" 1257 "Please check if there are any files in \"engines/\" directory.\n" 1258 "To fix this problem you may try downloading Doomseeker " 1259 "again from the site specified in the Help|About box and reinstalling " 1264 QueryMenuAction* MainWindow::queryMenuActionForPlugin(
const EnginePlugin* plugin)
1271 if (d->queryMenuPorts.contains(plugin))
1273 return d->queryMenuPorts[plugin];
1279 void MainWindow::quitProgram()
1281 d->bWantToQuit =
true;
1282 QApplication::closeAllWindows();
1285 void MainWindow::refreshCustomServers()
1287 CustomServers* customServers = d->masterManager->customServs();
1289 for(
int i = 0;i < customServers->numServers();i++)
1291 ServerPtr server = (*customServers)[i];
1292 gRefresher->registerServer(server.data());
1296 void MainWindow::refreshLanServers()
1298 foreach (ServerPtr server, d->broadcastManager->servers())
1300 gRefresher->registerServer(server.data());
1304 void MainWindow::refreshThreadBeginsWork()
1306 statusBar()->showMessage(tr(
"Querying..."));
1307 d->taskbarProgress->show();
1310 void MainWindow::refreshThreadEndsWork()
1312 d->toolBarGetServers->setEnabled(
true);
1314 d->serverList->cleanUpForce();
1315 statusBar()->showMessage(tr(
"Done"));
1316 updateTrayIconTooltipAndLogTotalRefresh();
1317 d->taskbarProgress->hide();
1319 if (d->bTotalRefreshInProcess)
1321 initAutoRefreshTimer();
1324 d->bTotalRefreshInProcess =
false;
1325 QList<ServerPtr> selectedServers = d->serverList->selectedServers();
1326 d->detailsDock->displaySelection(selectedServers);
1329 void MainWindow::restartAndInstallUpdatesNow()
1335 void MainWindow::runGame(
const ServerPtr &server)
1337 if(d->connectionHandler)
1338 delete d->connectionHandler;
1341 d->connectionHandler->run();
1346 assert(plugin != NULL);
1348 QueryMenuAction* pAction = queryMenuActionForPlugin(plugin);
1349 if (pAction != NULL)
1351 pAction->setChecked(bEnabled);
1352 if (plugin->data()->hasMasterClient())
1354 plugin->data()->masterClient->
setEnabled(bEnabled);
1356 if (plugin->data()->hasBroadcast())
1358 plugin->data()->broadcast->setEnabled(bEnabled);
1360 d->serversStatusesWidgets[plugin]->setMasterEnabledStatus(bEnabled);
1364 void MainWindow::serverAddedToList(
const ServerPtr &pServer)
1366 if (pServer->isKnown())
1368 const QString& gameMode = pServer->gameMode().name();
1369 d->serverFilterDock->addGameModeToComboBox(gameMode);
1375 assert(this->d->updaterInstallerErrorCode == 0 &&
1376 "MainWindow::setDisplayUpdaterProcessFailure()");
1377 this->d->updaterInstallerErrorCode = errorCode;
1378 QTimer::singleShot(0,
this, SLOT(showUpdaterProcessErrorDialog()));
1383 assert(this->d->updaterInstallerErrorCode == 0 &&
1384 "MainWindow::setDisplayUpdateInstallerError()");
1385 this->d->updaterInstallerErrorCode = errorCode;
1386 QTimer::singleShot(0,
this, SLOT(showUpdateInstallErrorDialog()));
1389 void MainWindow::setupIcons()
1391 QStyle& style = *QApplication::style();
1394 d->menuActionQuit->setIcon(style.standardIcon(QStyle::SP_TitleBarCloseButton));
1397 d->menuActionHelp->setIcon(style.standardIcon(QStyle::SP_MessageBoxQuestion));
1398 d->menuActionAbout->setIcon(style.standardIcon(QStyle::SP_MessageBoxInformation));
1401 void MainWindow::setupToolBar()
1403 QToolBar* pToolBar =
new QToolBar(tr(
"Main Toolbar"),
this);
1404 pToolBar->setMovable(
false);
1405 pToolBar->setObjectName(
"Toolbar");
1408 d->toolBarGetServers =
new QAction(QIcon(
":/icons/refresh.png"), tr(
"Get Servers"), pToolBar);
1412 pToolBar->addAction(d->toolBarGetServers);
1415 pToolBar->addSeparator();
1416 pToolBar->addAction(d->menuActionCreateServer);
1417 pToolBar->addAction(d->menuActionWadseeker);
1420 pToolBar->addSeparator();
1421 pToolBar->addAction(d->menuActionManageDemos);
1422 pToolBar->addAction(d->menuActionRecordDemo);
1424 pToolBar->addSeparator();
1427 pToolBar->addAction(d->buddiesList->toggleViewAction());
1428 pToolBar->addAction(d->logDock->toggleViewAction());
1429 pToolBar->addAction(d->ircDock->toggleViewAction());
1430 pToolBar->addAction(d->serverFilterDock->toggleViewAction());
1431 pToolBar->addAction(d->detailsDock->toggleViewAction());
1434 QLineEdit *qs = d->serverFilterDock->createQuickSearch();
1435 qs->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1436 qs->setMinimumWidth(175);
1437 qs->setMaximumWidth(175);
1439 QWidget* searchSeparator =
new QWidget();
1440 searchSeparator->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
1441 pToolBar->addWidget(searchSeparator);
1442 pToolBar->addWidget(
new QLabel(tr(
"Search:"), pToolBar));
1443 pToolBar->addWidget(qs);
1445 this->addToolBar(Qt::TopToolBarArea, pToolBar);
1446 setUnifiedTitleAndToolBarOnMac(
true);
1447 connect(pToolBar, SIGNAL( actionTriggered(QAction*) ),
this, SLOT( toolBarAction(QAction*) ) );
1450 void MainWindow::showAndLogStatusMessage(
const QString &message)
1453 statusBar()->showMessage(message);
1456 void MainWindow::showEvent(QShowEvent *event)
1458 #if QT_VERSION >= 0x050000 1460 d->taskbarButton->setWindow(windowHandle());
1464 void MainWindow::showInstallFreedoomDialog()
1466 if (!d->freedoomDialog.isNull())
1468 d->freedoomDialog->activateWindow();
1472 dialog->setAttribute(Qt::WA_DeleteOnClose);
1474 d->freedoomDialog = dialog;
1477 void MainWindow::showProgramArgsHelp()
1480 dialog->setAttribute(Qt::WA_DeleteOnClose);
1484 void MainWindow::showServerJoinCommandLine(
const ServerPtr &server)
1488 GameDemo demo = gConfig.doomseeker.bRecordDemo ? GameDemo::Unmanaged : GameDemo::NoDemo;
1490 this->connect(builder, SIGNAL(commandLineBuildFinished()), SLOT(showServerJoinCommandLineOnBuilderFinished()));
1494 void MainWindow::showServerJoinCommandLineOnBuilderFinished()
1500 QString execPath = cli.
executable.absoluteFilePath();
1501 QStringList args = cli.
args;
1506 CopyTextDlg ctd(execPath +
" " + args.join(
" "), builder->server()->name(),
this);
1511 if (!builder->error().isEmpty())
1513 QMessageBox::critical(
this, tr(
"Doomseeker - show join command line"),
1514 tr(
"Command line cannot be built:\n%1").arg(builder->error()));
1517 builder->deleteLater();
1520 void MainWindow::showUpdaterProcessErrorDialog()
1522 QString explanation;
1523 if (this->d->updaterInstallerErrorCode != UpdateInstaller::PEC_GeneralFailure)
1525 QString errorCodeExplanation = UpdateInstaller::processErrorCodeToStr(
1527 explanation = tr(
"Update installation problem:\n%1").arg(errorCodeExplanation);
1531 explanation = tr(
"Update installation failed.");
1533 QMessageBox::critical(
this, tr(
"Doomseeker - Auto Update problem"),
1534 tr(
"%1\n\nRemaining updates have been discarded.").arg(explanation));
1537 void MainWindow::showUpdateInstallErrorDialog()
1539 QString msg = tr(
"Update install problem:\n%1\n\nRemaining updates have been discarded.")
1540 .arg(UpdateInstaller::errorCodeToStr(
1542 QMessageBox::critical(
this, tr(
"Doomseeker - Auto Update problem"), msg);
1545 void MainWindow::stopAutoRefreshTimer()
1547 d->autoRefreshTimer.stop();
1552 QueryMenuAction* pAction = queryMenuActionForPlugin(plugin);
1553 assert(pAction != NULL);
1555 setQueryPluginEnabled(plugin, !pAction->isChecked());
1558 void MainWindow::toolBarAction(QAction* pAction)
1560 if (pAction == d->toolBarGetServers)
1566 void MainWindow::trayIcon_activated(QSystemTrayIcon::ActivationReason reason)
1568 if (reason == QSystemTrayIcon::Trigger)
1570 if (isMinimized() || !isVisible())
1572 d->bWasMaximized ==
true ? showMaximized() : showNormal();
1575 else if (gConfig.doomseeker.bCloseToTrayIcon)
1588 void MainWindow::updateMasterAddresses()
1590 for(
int i = 0;i < d->masterManager->numMasters();i++)
1592 (*d->masterManager)[i]->updateAddress();
1598 d->serverList->applyFilter(filterInfo);
1607 count += status->count();
1612 void MainWindow::updateRefreshProgress()
1615 d->taskbarProgress->setMaximum(count.numServers);
1616 d->taskbarProgress->setValue(count.numServers - count.numRefreshing);
1617 updateTrayIconTooltip(count);
1622 if (d->trayIcon != NULL)
1625 tip += tr(
"Generic servers: %1\n").arg(count.numGenericServers);
1626 tip += tr(
"Custom servers: %1\n").arg(count.numCustomServers);
1627 tip += tr(
"LAN servers: %1\n").arg(count.numLanServers);
1628 tip += tr(
"Human players: %1").arg(count.numHumanPlayers);
1629 d->trayIcon->setToolTip(tip);
1633 void MainWindow::updateTrayIconTooltipAndLogTotalRefresh()
1636 updateTrayIconTooltip(count);
1638 if (d->bTotalRefreshInProcess)
1640 gLog << tr(
"Finished refreshing. Servers on the list: %1 " 1641 "(+%2 custom, +%3 LAN). Players: %4.")
1642 .arg(count.numGenericServers).arg(count.numCustomServers)
1643 .arg(count.numLanServers).arg(count.numHumanPlayers);
Structure describing server filter.
void checkForUpdatesAuto()
Auto triggered updates will display install confirmation only if configured to.
static void loadImages(int style)
Performs a case-insensitive (OS independent) file searches.
Dockable widget designed for IRC communication.
Dockable widget designed for application's log presentation.
static UpdateChannel fromName(const QString &name)
Creates object from its internal name.
void togglePluginQueryEnabled(const EnginePlugin *plugin)
Structure holding parameters for application launch.
Message object used to pass messages throughout the Doomseeker's system.
void finishConfiguration(DoomseekerConfigurationDialog &, bool)
QStringList args
launch parameters
static bool bInstallUpdatesAndRestart
If true then program will install updates and restart instead of quitting if quit is requested...
bool isFilteringAnything() const
Informs if filter will apply to any server.
QVariant value() const
Extracts the value as QVariant.
Update is fully automatic.
ProcessErrorCode
"--update-failed" values.
static bool rmAllFiles(const QString &dirPath, const QStringList &nameFilters=QStringList())
Deletes all files in specified directory.
void setQueryPluginEnabled(const EnginePlugin *pClient, bool bEnabled)
Sets query for selected MasterClient object to enabled or disabled.
Generates command line for joining specified server.
QString revision
Revision used for version comparison.
void checkForUpdatesUserTriggered()
User triggered updates will always display install confirmation.
IniVariable retrieveSetting(const QString &name)
Gets a variable but only if it already exists.
static bool isUrlSafe(const QString &url)
Unsafe URLs begin with file:// and this functions returns false for such URLs.
unsigned timestamp() const
Generation time in seconds since UTC epoch.
Dialog window allowing user to host a game.
void setDisplayUpdaterProcessFailure(int errorCode)
This should be set if program was started with "--update-failed" argument.
bool isAnythingToRefresh() const
Will check if refresh operation has any sense.
virtual const EnginePlugin * plugin() const =0
Platform-agnostic wrapper for QWinTaskbarProgress.
Deals with program updates/upgrades.
void obtainJoinCommandLine()
Runs asynchronously and emits commandLineBuildFinished() when done.
void setWads(const QStringList &wads)
Sets WADs to seek.
void fillQueryMenu(MasterManager *masterManager)
Wadseeker dialog box, only one instance is allowed.
Dialog for managing demos recorded through Doomseeker.
Manager class for a number of MasterClient instances.
INI section representation.
static void escapeExecutable(QString &arg)
Escapes the executable path and handles OS X bundles.
void setDisplayUpdateInstallerError(int errorCode)
If set then MainWindow will display the reason for updater failure.
Wrapper for PathFinder that specializes in findings WADs.
QString contents() const
Customized displayable contents of this Message.
Abstract base for all MasterClients.
static void escapeArgs(QStringList &args)
Escapes all characters in all strings on the list.
QFileInfo executable
path to the executable
QString name
Name of the package (program name or plugin name).
const QString & name() const
File name of the WAD.
bool isValid() const
It's valid when at least executable is set.
void initAutoRefreshTimer()