24 #include <QApplication>
26 #include <QHashIterator>
28 #include <QMainWindow>
29 #include <QMessageBox>
31 #include <QThreadPool>
34 #include "configuration/doomseekerconfig.h"
35 #include "configuration/passwordscfg.h"
36 #include "configuration/queryspeed.h"
37 #include "connectionhandler.h"
38 #include "gui/mainwindow.h"
39 #include "gui/remoteconsole.h"
40 #include "ip2c/ip2c.h"
42 #include "irc/configuration/ircconfig.h"
43 #include "serverapi/server.h"
44 #include "application.h"
45 #include "cmdargshelp.h"
46 #include "commandlinetokenizer.h"
47 #include "doomseekerfilepaths.h"
48 #include "localization.h"
51 #include "plugins/engineplugin.h"
52 #include "plugins/pluginloader.h"
53 #include "refresher/refresher.h"
54 #include "serverapi/server.h"
56 #include "tests/testruns.h"
57 #include "wadseeker/wadseeker.h"
58 #include "updater/updateinstaller.h"
59 #include "lookuphost.h"
60 #include "versiondump.h"
62 QString Main::argDataDir;
64 QList<LocalizationInfo> Main::localizations;
67 Main::Main(
int argc,
char* argv[])
68 : arguments(argv), argumentsCount(argc),
73 bPortableMode =
false;
76 qRegisterMetaType<ServerPtr>(
"ServerPtr");
77 qRegisterMetaType<ServerCPtr>(
"ServerCPtr");
82 if (Application::isInit())
87 if (Refresher::isInstantiated())
89 Refresher::instance()->
quit();
90 Refresher::deinstantiate();
94 if (Application::isInit())
99 gIRCConfig.saveToFile();
100 gIRCConfig.dispose();
103 IP2C::deinstantiate();
109 int Main::connectToServerByURL()
115 connect(handler, SIGNAL(finished(
int)), gApp, SLOT(quit()));
116 int ret = gApp->exec();
132 Application::init(argumentsCount, arguments);
135 gApp->setAttribute(Qt::AA_DontShowIconsInMenus);
138 gLog <<
"Starting Doomseeker. Hello World! :)";
139 gLog <<
"Setting up data directories.";
144 QStringList failedDirsList = gDefaultDataPaths->directoriesExist();
145 QString failedDirsString = failedDirsList.join(
"\n");
147 QString errorMessage = tr(
"Doomseeker will not run because following directories cannot be created:");
148 errorMessage +=
"\n" + failedDirsString;
150 QMessageBox::critical(NULL, tr(
"Doomseeker startup error"), errorMessage);
155 PluginUrlHandler::registerAll();
159 return runTestMode();
163 #ifdef WITH_AUTOUPDATES
173 initLocalizationsDefinitions();
175 initPasswordsConfig();
181 if (!createRemoteConsole())
184 else if (connectUrl.isValid())
186 setupRefreshingThread();
187 return connectToServerByURL();
191 setupRefreshingThread();
193 #ifdef WITH_AUTOUPDATES
196 if (updateFailedCode != 0)
199 gApp->mainWindow()->setDisplayUpdaterProcessFailure(updateFailedCode);
204 gApp->mainWindow()->setDisplayUpdateInstallerError(updateInstallerResult);
210 QTimer::singleShot(0, gApp->mainWindow(), SLOT(checkForUpdatesAuto()));
216 gLog << tr(
"Init finished.");
217 gLog.addUnformattedEntry(
"================================\n");
219 int returnCode = gApp->exec();
221 LookupHost::finalizeAndJoin();
223 #ifdef WITH_AUTOUPDATES
228 updateFailedCode = 0;
229 int installResult = installPendingUpdates();
233 QMessageBox::critical(NULL, tr(
"Doomseeker - Updates Install Failure"),
242 int Main::runTestMode()
245 gLog <<
"Entering test mode.";
250 TestRuns::pTestCore = &testCore;
251 TestRuns::callTests();
254 QString strSucceded =
"Tests succeeded: %1";
255 QString strFailed =
"Tests failed: %1";
256 QString strPercentage =
"Pass percentage: %1%";
258 float passPercentage = (float)testCore.numTestsSucceeded() / (float)testCore.numTests();
259 passPercentage *= 100.0f;
261 gLog <<
"==== TESTS SUMMARY: ====";
262 gLog << strSucceded.arg(testCore.numTestsSucceeded(), 6);
263 gLog << strFailed.arg(testCore.numTestsFailed(), 6);
264 gLog << strPercentage.arg(passPercentage, 6,
'f', 2);
265 gLog <<
"==== Done. ====";
267 return testCore.numTestsFailed();
270 void Main::createMainWindow()
272 gLog << tr(
"Preparing GUI.");
274 gApp->setMainWindow(
new MainWindow(gApp, argumentsCount, arguments));
275 gApp->mainWindow()->show();
279 gApp->mainWindow()->notifyFirstRun();
283 bool Main::createRemoteConsole()
285 gLog << tr(
"Starting RCon client.");
286 if(rconPluginName.isEmpty())
295 int pIndex = gPlugins->pluginIndexFromName(rconPluginName);
298 gLog << tr(
"Couldn't find specified plugin: ") + rconPluginName;
303 const EnginePlugin *plugin = gPlugins->plugin(pIndex)->info();
305 if(!server->hasRcon())
307 gLog << tr(
"Plugin does not support RCon.");
320 DataPaths::initDefault(bPortableMode);
321 DoomseekerFilePaths::pDataPaths = gDefaultDataPaths;
322 gDefaultDataPaths->setWorkingDirectory(QCoreApplication::applicationDirPath());
323 if (!gDefaultDataPaths->createDirectories())
330 dataDirectories << gDefaultDataPaths->programsDataSupportDirectoryPath();
331 dataDirectories << gDefaultDataPaths->workingDirectory();
334 dataDirectories <<
"./";
335 #if defined(Q_OS_LINUX)
336 #ifndef INSTALL_PREFIX // For safety lets check for the defintion
337 #define INSTALL_PREFIX "/usr"
340 dataDirectories << INSTALL_PREFIX
"/share/doomseeker/";
343 dataDirectories <<
":/";
344 QDir::setSearchPaths(
"data", dataDirectories);
351 gLog << tr(
"Initializing IP2C database.");
357 void Main::initIRCConfig()
359 gLog << tr(
"Initializing IRC configuration file.");
365 QString configPath = DoomseekerFilePaths::ircIni();
366 if (!configPath.isEmpty())
368 if (gIRCConfig.setIniFile(configPath))
370 gIRCConfig.readFromFile();
375 void Main::initLocalizationsDefinitions()
377 gLog << tr(
"Loading translations definitions");
378 localizations = Localization::loadLocalizationsList(
381 QString localization = gConfig.doomseeker.localization;
382 gLog << tr(
"Loading translation \"%1\".").arg(localization);
383 bool bSuccess = Localization::loadTranslation(localization);
386 gLog << tr(
"Translation loaded.");
390 gLog << tr(
"Failed to load translation.");
394 void Main::initMainConfig()
396 gLog << tr(
"Initializing configuration file.");
402 QString configDirPath = gDefaultDataPaths->programsDataDirectoryPath();
403 if (configDirPath.isEmpty())
405 gLog << tr(
"Could not get an access to the settings directory. Configuration will not be saved.");
409 QString filePath = DoomseekerFilePaths::ini();
412 QFileInfo iniFileInfo(filePath);
413 bIsFirstRun = !iniFileInfo.exists();
416 if (gConfig.setIniFile(filePath))
418 gConfig.readFromFile();
422 void Main::initPasswordsConfig()
424 gLog << tr(
"Initializing passwords configuration file.");
426 QString configDirPath = gDefaultDataPaths->programsDataDirectoryPath();
427 if (configDirPath.isEmpty())
431 QString filePath = DoomseekerFilePaths::passwordIni();
432 PasswordsCfg::initIni(filePath);
435 void Main::initPluginConfig()
437 gLog << tr(
"Initializing configuration for plugins.");
438 gPlugins->initConfig();
441 int Main::installPendingUpdates()
444 if (gConfig.autoUpdates.bPerformUpdateOnNextRun)
446 gConfig.autoUpdates.bPerformUpdateOnNextRun =
false;
447 gConfig.saveToFile();
450 if (updateFailedCode == 0)
456 return updateInstallerResult;
461 for(
int i = 0; i < argumentsCount; ++i)
463 const char* arg = arguments[i];
465 if(strcmp(arg,
"--connect") == 0 && i+1 < argumentsCount)
467 connectUrl = QUrl(arguments[++i]);
469 else if(strcmp(arg,
"--datadir") == 0 && i+1 < argumentsCount)
472 dataDirectories.prepend(arguments[i]);
473 argDataDir = arguments[i];
475 else if(strcmp(arg,
"--rcon") == 0)
478 if(i+2 < argumentsCount)
480 rconPluginName = arguments[i+1];
485 else if(strcmp(arg,
"--help") == 0)
487 gLog.setTimestampsEnabled(
false);
489 gLog << tr(
"Available command line parameters:\n");
490 gLog << CmdArgsHelp::argsHelp();
493 else if (strcmp(arg,
"--update-failed") == 0)
496 updateFailedCode = QString(arguments[i]).toInt();
498 else if (strcmp(arg,
"--portable") == 0)
500 bPortableMode =
true;
502 else if (strcmp(arg,
"--tests") == 0)
506 else if (strcmp(arg,
"--version-json") == 0)
508 if (i + 1 < argumentsCount)
510 QString filename = arguments[i + 1];
512 if (!f.open(QIODevice::WriteOnly))
514 gLog << tr(
"Failed to open file.");
518 Application::init(argumentsCount, arguments);
521 gLog << tr(
"Dumping version info to file in JSON format.");
522 VersionDump::dumpJsonToIO(f);
527 gLog << tr(
"No file specified!");
536 void Main::setupRefreshingThread()
538 gLog << tr(
"Starting refreshing thread.");
539 gRefresher->setDelayBetweenResends(gConfig.doomseeker.querySpeed().delayBetweenSingleServerAttempts);
547 #define USE_WINMAIN_AS_ENTRY_POINT
551 #ifdef USE_WINMAIN_AS_ENTRY_POINT
553 QStringList getCommandLineArgs()
556 return tokenizer.tokenize(QString::fromUtf16((
const ushort*)GetCommandLineW()));
559 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine,
int nCmdShow)
564 QStringList commandLine = getCommandLineArgs();
567 argc = commandLine.size();
568 argv =
new char*[argc];
570 for (
int i = 0; i < commandLine.size(); ++i)
572 const QString& parameter = commandLine[i];
573 argv[i] =
new char[parameter.size() + 1];
574 strcpy(argv[i], parameter.toAscii().constData());
578 int returnValue = pMain->
run();
585 for (
int i = 0; i < argc; ++i)
594 int main(
int argc,
char* argv[])
597 int returnValue = pMain->
run();
static void translateServerAddress(const QString &addressString, QString &hostname, unsigned short &port, const QString &defaultAddress)
Translates string in format "hostname:port" to atomic values.
static void deinit()
Destroys the init() instance.
static void init(const QStringList &directories)
Attempts to load plugins from given set of directories.
static bool bInstallUpdatesAndRestart
If true then program will install updates and restart instead of quitting if quit is requested...
int run()
Replaces main().
virtual ServerPtr server(const QHostAddress &address, unsigned short port) const
Creates an instance of server object from this plugin.
bool initDataDirectories()
QString rconAddress
If not empty assume we want to launch an rcon client.
static QStringList combineManyPaths(const QStringList &fronts, const QString &pathEnd)
Combines path suffix with all fronts, returns new list.
Splits command line into separate arguments in a manner appropriate for current OS.
ErrorCode startInstallation()
Starts update process.
static void deinit()
Deinitializes the program; executed when program is shutting down.
Core for developer tests.
bool interpretCommandLineParameters()
static QStringList staticDataSearchDirs(const QString &subdir=QString())
Paths to directories where program should search for its static data.