doomseekerconfig.cpp
1 //------------------------------------------------------------------------------
2 // doomseekerconfig.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; 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) 2010 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "doomseekerconfig.h"
24 
25 #include "configuration/queryspeed.h"
26 #include "gui/models/serverlistproxymodel.h"
27 #include "ini/ini.h"
28 #include "ini/inisection.h"
29 #include "ini/inivariable.h"
30 #include "ini/settingsproviderqt.h"
31 #include "pathfinder/filealias.h"
32 #include "pathfinder/filesearchpath.h"
33 #include "plugins/engineplugin.h"
34 #include "updater/updatechannel.h"
35 #include "wadseeker/wadseeker.h"
36 #include "datapaths.h"
37 #include "log.h"
38 #include "strings.h"
39 #include "version.h"
40 
41 #include <QLocale>
42 
43 DoomseekerConfig* DoomseekerConfig::instance = NULL;
44 
45 DoomseekerConfig::DoomseekerConfig()
46 {
47  this->dummySection = new IniSection(NULL, QString());
48 }
49 
50 DoomseekerConfig::~DoomseekerConfig()
51 {
52  delete this->dummySection;
53 }
54 
56 {
57  if (instance == NULL)
58  {
59  instance = new DoomseekerConfig();
60  }
61 
62  return *instance;
63 }
64 
66 {
67  if (instance != NULL)
68  {
69  delete instance;
70  instance = NULL;
71  }
72 }
73 
75 {
76  if (pluginName.isEmpty())
77  {
78  gLog << QObject::tr("DoomseekerConfig.iniSectionForPlugin(): empty plugin name has been specified, returning dummy IniSection.");
79  return *dummySection;
80  }
81 
82  if (!isValidPluginName(pluginName))
83  {
84  gLog << QObject::tr("DoomseekerConfig.iniSectionForPlugin(): plugin name is invalid: %1").arg(pluginName);
85  return *dummySection;
86  }
87 
88  if (this->pIni == NULL)
89  {
90  setIniFile("");
91  }
92 
93  QString sectionName = pluginName;
94  sectionName = sectionName.replace(' ', "");
95  return this->pIni->section(sectionName);
96 }
97 
99 {
100  return iniSectionForPlugin(plugin->data()->name);
101 }
102 
103 bool DoomseekerConfig::isValidPluginName(const QString& pluginName) const
104 {
105  QString invalids[] = { "doomseeker", "wadseeker", "" };
106 
107  for (int i = 0; !invalids[i].isEmpty(); ++i)
108  {
109  if (pluginName.compare(invalids[i], Qt::CaseInsensitive) == 0)
110  {
111  return false;
112  }
113  }
114 
115  return true;
116 }
117 
119 {
120  if (pIni == NULL)
121  {
122  return false;
123  }
124 
125  IniSection sectionDoomseeker = pIni->section(doomseeker.SECTION_NAME);
126  doomseeker.load(sectionDoomseeker);
127 
128  IniSection sectionServerFilter = pIni->section(serverFilter.SECTION_NAME);
129  serverFilter.load(sectionServerFilter);
130 
131  IniSection sectionWadseeker = pIni->section(wadseeker.SECTION_NAME);
132  wadseeker.load(sectionWadseeker);
133 
134  IniSection sectionAutoUpdates = pIni->section(autoUpdates.SECTION_NAME);
135  autoUpdates.load(sectionAutoUpdates);
136 
137  // Plugins should read their sections manually.
138 
139  return true;
140 }
141 
143 {
144  if (pIni == NULL)
145  {
146  return false;
147  }
148 
149 // TODO:
150 // Find a way to work around this.
151 // const QString TOP_COMMENT = QObject::tr("This is %1 configuration file.\n\
152 //Any modification done manually to this file is on your own risk.").arg(Version::fullVersionInfo());
153 //
154 // pIni->setIniTopComment(TOP_COMMENT);
155 
156  IniSection sectionDoomseeker = pIni->section(doomseeker.SECTION_NAME);
157  doomseeker.save(sectionDoomseeker);
158 
159  IniSection sectionServerFilter = pIni->section(serverFilter.SECTION_NAME);
160  serverFilter.save(sectionServerFilter);
161 
162  IniSection sectionWadseeker = pIni->section(wadseeker.SECTION_NAME);
163  wadseeker.save(sectionWadseeker);
164 
165  IniSection sectionAutoUpdates = pIni->section(autoUpdates.SECTION_NAME);
166  autoUpdates.save(sectionAutoUpdates);
167 
168  // Plugins should save their sections manually.
169  if (this->settings->isWritable())
170  {
171  this->settings->sync();
172  return true;
173  }
174  return false;
175 }
176 
177 bool DoomseekerConfig::setIniFile(const QString& filePath)
178 {
179  // Delete old instances if necessary.
180  this->pIni.reset();
181  this->settingsProvider.reset();
182  this->settings.reset();
183 
184  gLog << QObject::tr("Setting INI file: %1").arg(filePath);
185  // Create new instances.
186  this->settings.reset(new QSettings(filePath, QSettings::IniFormat));
187  this->settingsProvider.reset(new SettingsProviderQt(this->settings.data()));
188  this->pIni.reset(new Ini(this->settingsProvider.data()));
189 
190  // Init.
191  IniSection section;
192 
193  section = this->pIni->section(doomseeker.SECTION_NAME);
194  doomseeker.init(section);
195 
196  section = this->pIni->section(serverFilter.SECTION_NAME);
197  serverFilter.init(section);
198 
199  section = this->pIni->section(wadseeker.SECTION_NAME);
200  wadseeker.init(section);
201 
202  section = this->pIni->section(autoUpdates.SECTION_NAME);
203  autoUpdates.init(section);
204 
205  return true;
206 }
207 
209 DClass<DoomseekerConfig::DoomseekerCfg>
210 {
211  public:
212  IniSection section;
213  QuerySpeed querySpeed;
214 };
215 
217 
218 const QString DoomseekerConfig::DoomseekerCfg::SECTION_NAME = "Doomseeker";
219 
220 DoomseekerConfig::DoomseekerCfg::DoomseekerCfg()
221 {
222  this->bBotsAreNotPlayers = true;
223  this->bCloseToTrayIcon = false;
224  this->bColorizeServerConsole = true;
225  this->bDrawGridInServerTable = false;
226  this->bHidePasswords = false;
227  this->bGroupServersWithPlayersAtTheTopOfTheList = true;
228  this->bIP2CountryAutoUpdate = true;
229  this->bLookupHosts = true;
230  this->bQueryAutoRefreshDontIfActive = true;
231  this->bQueryAutoRefreshEnabled = false;
232  this->bQueryBeforeLaunch = true;
233  this->bQueryOnStartup = true;
234  this->bRecordDemo = false;
235  this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn = true;
236  this->bUseTrayIcon = false;
237  this->bMarkServersWithBuddies = true;
238  this->buddyServersColor = "#5ecf75";
239  this->customServersColor = "#ffaa00";
240  this->ip2CountryDatabaseMaximumAge = 60;
241  this->ip2CountryUrl = "http://doomseeker.drdteam.org/ip2c/get";
242  this->localization = QLocale::system().name();
243  this->mainWindowState = "";
244  this->mainWindowGeometry = "";
245  this->queryAutoRefreshEverySeconds = 180;
246  setQuerySpeed(QuerySpeed::moderate());
247  this->previousCreateServerConfigDir = "";
248  this->previousCreateServerExecDir = "";
249  this->previousCreateServerWadDir = "";
250  this->slotStyle = 1;
251  this->serverListSortIndex = -1;
252  this->serverListSortDirection = Qt::DescendingOrder;
253  this->wadPaths << gDefaultDataPaths->programsDataDirectoryPath();
254  this->wadPaths << gDefaultDataPaths->workingDirectory();
255 }
256 
257 DoomseekerConfig::DoomseekerCfg::~DoomseekerCfg()
258 {
259 }
260 
261 QList<ColumnSort> DoomseekerConfig::DoomseekerCfg::additionalSortColumns() const
262 {
263  QList<ColumnSort> list;
264  QVariantList varList = d->section.value("AdditionalSortColumns").toList();
265  foreach (const QVariant &var, varList)
266  {
267  list << ColumnSort::deserializeQVariant(var);
268  }
269  return list;
270 }
271 
272 void DoomseekerConfig::DoomseekerCfg::setAdditionalSortColumns(const QList<ColumnSort> &val)
273 {
274  QVariantList varList;
275  foreach (const ColumnSort &elem, val)
276  {
277  varList << elem.serializeQVariant();
278  }
279  d->section.setValue("AdditionalSortColumns", varList);
280 }
281 
283 {
284  // TODO: Make all methods use d->section
285  d->section = section;
286  section.createSetting("Localization", this->localization);
287  section.createSetting("BotsAreNotPlayers", this->bBotsAreNotPlayers);
288  section.createSetting("CloseToTrayIcon", this->bCloseToTrayIcon);
289  section.createSetting("ColorizeServerConsole", this->bColorizeServerConsole);
290  section.createSetting("DrawGridInServerTable", this->bDrawGridInServerTable);
291  section.createSetting("HidePasswords", this->bHidePasswords);
292  section.createSetting("GroupServersWithPlayersAtTheTopOfTheList", this->bGroupServersWithPlayersAtTheTopOfTheList);
293  section.createSetting("IP2CAutoUpdate", this->bIP2CountryAutoUpdate);
294  section.createSetting("LookupHosts", this->bLookupHosts);
295  section.createSetting("QueryAutoRefreshDontIfActive", this->bQueryAutoRefreshDontIfActive);
296  section.createSetting("QueryAutoRefreshEnabled", this->bQueryAutoRefreshEnabled);
297  section.createSetting("QueryOnStartup", this->bQueryOnStartup);
298  section.createSetting("RecordDemo", this->bRecordDemo);
299  section.createSetting("TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn", this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn);
300  section.createSetting("UseTrayIcon", this->bUseTrayIcon);
301  section.createSetting("MarkServersWithBuddies", this->bMarkServersWithBuddies);
302  section.createSetting("BuddyServersColor", this->buddyServersColor);
303  section.createSetting("CustomServersColor", this->customServersColor);
304  section.createSetting("IP2CMaximumAge", this->ip2CountryDatabaseMaximumAge);
305  section.createSetting("IP2CUrl", this->ip2CountryUrl);
306  section.createSetting("QueryAutoRefreshEverySeconds", this->queryAutoRefreshEverySeconds);
307  section.createSetting("QueryServerInterval", this->querySpeed().intervalBetweenServers);
308  section.createSetting("QueryServerTimeout", this->querySpeed().delayBetweenSingleServerAttempts);
309  section.createSetting("QueryAttemptsPerServer", this->querySpeed().attemptsPerServer);
310  section.createSetting("SlotStyle", this->slotStyle);
311  section.createSetting("ServerListSortIndex", this->serverListSortIndex);
312  section.createSetting("ServerListSortDirection", this->serverListSortDirection);
313  section.createSetting("WadPaths", FileSearchPath::toVariantList(this->wadPaths));
314 
315  initWadAlias();
316 }
317 
318 void DoomseekerConfig::DoomseekerCfg::initWadAlias()
319 {
320  if (!d->section.hasSetting("WadAliases"))
321  {
322  setWadAliases(FileAlias::standardWadAliases());
323  }
324 }
325 
326 void DoomseekerConfig::DoomseekerCfg::load(IniSection& section)
327 {
328  this->localization = (const QString&)section["Localization"];
329  this->bBotsAreNotPlayers = section["BotsAreNotPlayers"];
330  this->bCloseToTrayIcon = section["CloseToTrayIcon"];
331  this->bColorizeServerConsole = section["ColorizeServerConsole"];
332  this->bDrawGridInServerTable = section["DrawGridInServerTable"];
333  this->bHidePasswords = section["HidePasswords"];
334  this->bGroupServersWithPlayersAtTheTopOfTheList = section["GroupServersWithPlayersAtTheTopOfTheList"];
335  this->bIP2CountryAutoUpdate = section["IP2CAutoUpdate"];
336  this->bLookupHosts = section["LookupHosts"];
337  this->bQueryAutoRefreshDontIfActive = section["QueryAutoRefreshDontIfActive"];
338  this->bQueryAutoRefreshEnabled = section["QueryAutoRefreshEnabled"];
339  this->bQueryBeforeLaunch = section["QueryBeforeLaunch"];
340  this->bQueryOnStartup = section["QueryOnStartup"];
341  this->bRecordDemo = section["RecordDemo"];
342  this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn = section["TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn"];
343  this->bUseTrayIcon = section["UseTrayIcon"];
344  this->bMarkServersWithBuddies = section["MarkServersWithBuddies"];
345  this->buddyServersColor = (const QString &)section["BuddyServersColor"];
346  this->customServersColor = (const QString &)section["CustomServersColor"];
347  this->ip2CountryDatabaseMaximumAge = section["IP2CMaximumAge"];
348  this->ip2CountryUrl = (const QString &)section["IP2CUrl"];
349  this->mainWindowState = (const QString &)section["MainWindowState"];
350  this->mainWindowGeometry = section.value("MainWindowGeometry", "").toByteArray();
351  this->queryAutoRefreshEverySeconds = section["QueryAutoRefreshEverySeconds"];
352  d->querySpeed.intervalBetweenServers = section["QueryServerInterval"];
353  d->querySpeed.delayBetweenSingleServerAttempts = section["QueryServerTimeout"];
354  d->querySpeed.attemptsPerServer = section["QueryAttemptsPerServer"];
355  this->previousCreateServerConfigDir = (const QString &)section["PreviousCreateServerConfigDir"];
356  this->previousCreateServerExecDir = (const QString &)section["PreviousCreateServerExecDir"];
357  this->previousCreateServerWadDir = (const QString &)section["PreviousCreateServerWadDir"];
358  this->serverListColumnState = (const QString &)section["ServerListColumnState"];
359  this->serverListSortIndex = section["ServerListSortIndex"];
360  this->serverListSortDirection = section["ServerListSortDirection"];
361  this->slotStyle = section["SlotStyle"];
362 
363  // Complex data variables.
364 
365  // Custom servers
366  QList<CustomServerInfo> customServersList;
367  CustomServers::decodeConfigEntries(section["CustomServers"], customServersList);
368  this->customServers = customServersList.toVector();
369 
370  // WAD paths
371  // Backward compatibility, XXX once new stable is released:
372  QVariant variantWadPaths = section["WadPaths"].value();
373  if (variantWadPaths.isValid() && variantWadPaths.toList().isEmpty())
374  {
375  // Backward compatibility continued:
376  wadPaths.clear();
377  QStringList paths = variantWadPaths.toString().split(";");
378  foreach (const QString& path, paths)
379  {
380  wadPaths << FileSearchPath(path);
381  }
382  }
383  else
384  {
385  // This is not a part of XXX, this is proper, current behavior:
386  wadPaths = FileSearchPath::fromVariantList(section["WadPaths"].value().toList());
387  }
388  // End of backward compatibility for WAD paths.
389 
390  // Buddies list
391  QString buddiesConfigEntry = section["BuddiesList"];
392  BuddyInfo::readConfigEntry(buddiesConfigEntry, this->buddiesList);
393 }
394 
395 void DoomseekerConfig::DoomseekerCfg::save(IniSection& section)
396 {
397  section["Localization"] = this->localization;
398  section["BotsAreNotPlayers"] = this->bBotsAreNotPlayers;
399  section["CloseToTrayIcon"] = this->bCloseToTrayIcon;
400  section["ColorizeServerConsole"] = this->bColorizeServerConsole;
401  section["DrawGridInServerTable"] = this->bDrawGridInServerTable;
402  section["HidePasswords"] = this->bHidePasswords;
403  section["GroupServersWithPlayersAtTheTopOfTheList"] = this->bGroupServersWithPlayersAtTheTopOfTheList;
404  section["IP2CAutoUpdate"] = this->bIP2CountryAutoUpdate;
405  section["LookupHosts"] = this->bLookupHosts;
406  section["QueryAutoRefreshDontIfActive"] = this->bQueryAutoRefreshDontIfActive;
407  section["QueryAutoRefreshEnabled"] = this->bQueryAutoRefreshEnabled;
408  section["QueryBeforeLaunch"] = this->bQueryBeforeLaunch;
409  section["QueryOnStartup"] = this->bQueryOnStartup;
410  section["RecordDemo"] = this->bRecordDemo;
411  section["TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn"] = this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn;
412  section["UseTrayIcon"] = this->bUseTrayIcon;
413  section["MarkServersWithBuddies"] = this->bMarkServersWithBuddies;
414  section["BuddyServersColor"] = this->buddyServersColor;
415  section["CustomServersColor"] = this->customServersColor;
416  section["IP2CMaximumAge"] = this->ip2CountryDatabaseMaximumAge;
417  section["IP2CUrl"] = this->ip2CountryUrl;
418  section["MainWindowState"] = this->mainWindowState;
419  section.setValue("MainWindowGeometry", this->mainWindowGeometry);
420  section["QueryAutoRefreshEverySeconds"] = this->queryAutoRefreshEverySeconds;
421  section["QueryServerInterval"] = this->querySpeed().intervalBetweenServers;
422  section["QueryServerTimeout"] = this->querySpeed().delayBetweenSingleServerAttempts;
423  section["QueryAttemptsPerServer"] = this->querySpeed().attemptsPerServer;
424  section["PreviousCreateServerConfigDir"] = this->previousCreateServerConfigDir;
425  section["PreviousCreateServerExecDir"] = this->previousCreateServerExecDir;
426  section["PreviousCreateServerWadDir"] = this->previousCreateServerWadDir;
427  section["ServerListColumnState"] = this->serverListColumnState;
428  section["ServerListSortIndex"] = this->serverListSortIndex;
429  section["ServerListSortDirection"] = this->serverListSortDirection;
430  section["SlotStyle"] = this->slotStyle;
431 
432  // Complex data variables.
433 
434  // Custom servers
435  QStringList allCustomServers;
436  foreach (const CustomServerInfo& customServer, this->customServers)
437  {
438  QString engineName = QUrl::toPercentEncoding(customServer.engine, "", "()");
439  QString address = QUrl::toPercentEncoding(customServer.host, "", "()");
440 
441  QString customServerString = QString("(%1;%2;%3)")
442  .arg(engineName).arg(address)
443  .arg(customServer.port);
444 
445  allCustomServers << customServerString;
446  }
447  section["CustomServers"] = allCustomServers.join(";");
448 
449  // Wad paths
450  section["WadPaths"].setValue(FileSearchPath::toVariantList(this->wadPaths));
451 
452  // Buddies lists
453  QString buddiesList = BuddyInfo::createConfigEntry(this->buddiesList);
454  section["BuddiesList"] = buddiesList;
455 }
456 
457 const QuerySpeed &DoomseekerConfig::DoomseekerCfg::querySpeed() const
458 {
459  return d->querySpeed;
460 }
461 
462 void DoomseekerConfig::DoomseekerCfg::setQuerySpeed(const QuerySpeed &val)
463 {
464  d->querySpeed = val;
465 }
466 
467 QList<FileAlias> DoomseekerConfig::DoomseekerCfg::wadAliases()
468 {
469  QList<FileAlias> list;
470  QVariantList varList = d->section.value("WadAliases").toList();
471  foreach (const QVariant &var, varList)
472  {
473  list << FileAlias::deserializeQVariant(var);
474  }
475  return FileAliasList::mergeDuplicates(list);
476 }
477 
478 void DoomseekerConfig::DoomseekerCfg::setWadAliases(const QList<FileAlias> &val)
479 {
480  QVariantList varList;
481  foreach (const FileAlias &elem, val)
482  {
483  varList << elem.serializeQVariant();
484  }
485  d->section.setValue("WadAliases", varList);
486 }
487 
488 QStringList DoomseekerConfig::DoomseekerCfg::wadPathsOnly() const
489 {
490  QStringList result;
491  foreach (const FileSearchPath& path, wadPaths)
492  {
493  result << path.path();
494  }
495  return result;
496 }
498 const QString DoomseekerConfig::AutoUpdates::SECTION_NAME = "Doomseeker_AutoUpdates";
499 
500 void DoomseekerConfig::AutoUpdates::init(IniSection& section)
501 {
502  section.createSetting("UpdateChannelName", UpdateChannel::mkStable().name());
503  section.createSetting("UpdateMode", (int) UM_NotifyOnly);
504  section.createSetting("LastKnownUpdateRevisions", QVariant());
505  section.createSetting("bPerformUpdateOnNextRun", false);
506 }
507 
508 void DoomseekerConfig::AutoUpdates::load(IniSection& section)
509 {
510  updateChannelName = (const QString &)section["UpdateChannelName"];
511  updateMode = (UpdateMode)section["UpdateMode"].value().toInt();
512  QVariantMap lastKnownUpdateRevisionsVariant = section["LastKnownUpdateRevisions"].value().toMap();
513  lastKnownUpdateRevisions.clear();
514  foreach (const QString& package, lastKnownUpdateRevisionsVariant.keys())
515  {
516  QVariant revisionVariant = lastKnownUpdateRevisionsVariant[package];
517  lastKnownUpdateRevisions.insert(package, revisionVariant.toLongLong());
518  }
519  bPerformUpdateOnNextRun = section["bPerformUpdateOnNextRun"].value().toBool();
520 }
521 
522 void DoomseekerConfig::AutoUpdates::save(IniSection& section)
523 {
524  section["UpdateChannelName"] = updateChannelName;
525  section["UpdateMode"] = updateMode;
526  QVariantMap revisionsVariantMap;
527  foreach (const QString& package, lastKnownUpdateRevisions.keys())
528  {
529  revisionsVariantMap.insert(package, lastKnownUpdateRevisions[package]);
530  }
531  section["LastKnownUpdateRevisions"].setValue(revisionsVariantMap);
532  section["bPerformUpdateOnNextRun"].setValue(bPerformUpdateOnNextRun);
533 }
535 const QString DoomseekerConfig::ServerFilter::SECTION_NAME = "ServerFilter";
536 
537 void DoomseekerConfig::ServerFilter::init(IniSection& section)
538 {
539  section.createSetting("bEnabled", true);
540  section.createSetting("bShowEmpty", true);
541  section.createSetting("bShowFull", true);
542  section.createSetting("bShowOnlyValid", false);
543  section.createSetting("GameModes", QStringList());
544  section.createSetting("GameModesExcluded", QStringList());
545  section.createSetting("MaxPing", 0);
546  section.createSetting("ServerName", "");
547  section.createSetting("WADs", QStringList());
548  section.createSetting("WADsExcluded", QStringList());
549 }
550 
551 void DoomseekerConfig::ServerFilter::load(IniSection& section)
552 {
553  info.bEnabled = section["bEnabled"];
554  info.bShowEmpty = section["bShowEmpty"];
555  info.bShowFull = section["bShowFull"];
556  info.bShowOnlyValid = section["bShowOnlyValid"];
557  info.gameModes = section["GameModes"].value().toStringList();
558  info.gameModesExcluded = section["GameModesExcluded"].value().toStringList();
559  info.maxPing = section["MaxPing"];
560  info.serverName = (const QString &)section["ServerName"];
561  info.wads = section["WADs"].value().toStringList();
562  info.wadsExcluded = section["WADsExcluded"].value().toStringList();
563 }
564 
565 void DoomseekerConfig::ServerFilter::save(IniSection& section)
566 {
567  section["bEnabled"] = info.bEnabled;
568  section["bShowEmpty"] = info.bShowEmpty;
569  section["bShowFull"] = info.bShowFull;
570  section["bShowOnlyValid"] = info.bShowOnlyValid;
571  section["GameModes"].setValue(info.gameModes);
572  section["GameModesExcluded"].setValue(info.gameModesExcluded);
573  section["MaxPing"] = info.maxPing;
574  section["ServerName"] = info.serverName;
575  section["WADs"].setValue(info.wads);
576  section["WADsExcluded"].setValue(info.wadsExcluded);
577 }
579 const QString DoomseekerConfig::WadseekerCfg::SECTION_NAME = "Wadseeker";
580 
581 DoomseekerConfig::WadseekerCfg::WadseekerCfg()
582 {
583  this->bSearchInIdgames = true;
584  this->bSearchInWadArchive = true;
585  this->colorMessageCriticalError = "#ff0000";
586  this->colorMessageError = "#ff0000";
587  this->colorMessageNotice = "#000000";
588  this->connectTimeoutSeconds = WADSEEKER_CONNECT_TIMEOUT_SECONDS_DEFAULT;
589  this->downloadTimeoutSeconds = WADSEEKER_DOWNLOAD_TIMEOUT_SECONDS_DEFAULT;
590  this->idgamesURL = Wadseeker::defaultIdgamesUrl();
591  this->maxConcurrentSiteDownloads = 3;
592  this->maxConcurrentWadDownloads = 2;
593  this->targetDirectory = gDefaultDataPaths->programsDataDirectoryPath();
594 
595  // Search URLs remains unitizalized here. It will be initialized
596  // by init() and then load() since Doomseeker always calls these
597  // methods in this order.
598 }
599 
601 {
602  section.createSetting("SearchInIdgames", this->bSearchInIdgames);
603  section.createSetting("SearchInWadArchive", this->bSearchInWadArchive);
604  section.createSetting("ColorMessageCriticalError", this->colorMessageCriticalError);
605  section.createSetting("ColorMessageError", this->colorMessageError);
606  section.createSetting("ColorMessageNotice", this->colorMessageNotice);
607  section.createSetting("ConnectTimeoutSeconds", this->connectTimeoutSeconds);
608  section.createSetting("DownloadTimeoutSeconds", this->downloadTimeoutSeconds);
609  section.createSetting("IdgamesApiURL", this->idgamesURL);
610  section.createSetting("MaxConcurrentSiteDownloads", this->maxConcurrentSiteDownloads);
611  section.createSetting("MaxConcurrentWadDownloads", this->maxConcurrentWadDownloads);
612  section.createSetting("SearchURLs", Wadseeker::defaultSitesListEncoded().join(";"));
613  section.createSetting("TargetDirectory", this->targetDirectory);
614 }
615 
616 void DoomseekerConfig::WadseekerCfg::load(IniSection& section)
617 {
618  this->bSearchInIdgames = section["SearchInIdgames"];
619  this->bSearchInWadArchive = section["SearchInWadArchive"];
620  this->colorMessageCriticalError = (const QString &)section["ColorMessageCriticalError"];
621  this->colorMessageError = (const QString &)section["ColorMessageError"];
622  this->colorMessageNotice = (const QString &)section["ColorMessageNotice"];
623  this->connectTimeoutSeconds = section["ConnectTimeoutSeconds"];
624  this->downloadTimeoutSeconds = section["DownloadTimeoutSeconds"];
625  this->idgamesURL = (const QString &)section["IdgamesApiURL"];
626  this->maxConcurrentSiteDownloads = section["MaxConcurrentSiteDownloads"];
627  this->maxConcurrentWadDownloads = section["MaxConcurrentWadDownloads"];
628  this->targetDirectory = (const QString &)section["TargetDirectory"];
629 
630  // Complex data values
631  this->searchURLs.clear();
632  QStringList urlList = section["SearchURLs"].valueString().split(";", QString::SkipEmptyParts);
633  foreach (const QString& url, urlList)
634  {
635  this->searchURLs << QUrl::fromPercentEncoding(url.toAscii());
636  }
637 }
638 
639 void DoomseekerConfig::WadseekerCfg::save(IniSection& section)
640 {
641  section["SearchInIdgames"] = this->bSearchInIdgames;
642  section["SearchInWadArchive"] = this->bSearchInWadArchive;
643  section["ColorMessageCriticalError"] = this->colorMessageCriticalError;
644  section["ColorMessageError"] = this->colorMessageError;
645  section["ColorMessageNotice"] = this->colorMessageNotice;
646  section["ConnectTimeoutSeconds"] = this->connectTimeoutSeconds;
647  section["DownloadTimeoutSeconds"] = this->downloadTimeoutSeconds;
648  section["IdgamesApiURL"] = this->idgamesURL;
649  section["MaxConcurrentSiteDownloads"] = this->maxConcurrentSiteDownloads;
650  section["MaxConcurrentWadDownloads"] = this->maxConcurrentWadDownloads;
651  section["TargetDirectory"] = this->targetDirectory;
652 
653  // Complex data values
654  QStringList urlEncodedList;
655  foreach (const QString& url, this->searchURLs)
656  {
657  urlEncodedList << QUrl::toPercentEncoding(url.toAscii());
658  }
659  section["SearchURLs"] = urlEncodedList.join(";");
660 }
661 
IniVariable createSetting(const QString &name, const QVariant &data)
Inits specified variable with specified data.
Definition: inisection.cpp:57
void init(IniSection &section)
Initializes values that are not present in the section yet.
bool saveToFile()
Saves current settings to ini file. This file must be previously set by setIniFile() method...
This Singleton holds entire Doomseeker configuration in memory.
QVariant value(const QString &key) const
Retrieves a variable directly; omits the IniVariable system.
Definition: inisection.cpp:164
IniSection iniSectionForPlugin(const QString &pluginName)
This will assume that the .ini file is initialized.
static QList< FileAlias > standardWadAliases()
Standard/default aliases for configuration init.
Definition: filealias.cpp:127
static void decodeConfigEntries(const QString &str, QList< CustomServerInfo > &outCustomServerInfoList)
void init(IniSection &section)
Initializes values that are not present in the section yet.
Configuration handler.
Definition: ini.h:69
bool readFromFile()
Reads settings from ini file. This file must be previously set by setIniFile() method.
static UpdateChannel mkStable()
Creates "stable" channel object.
static DoomseekerConfig & config()
Returns the Singleton.
void setValue(const QString &key, const QVariant &value)
Sets a variable directly. Omits the IniVariable system.
Definition: inisection.cpp:154
INI section representation.
Definition: inisection.h:40
bool setIniFile(const QString &filePath)
Initializes the Ini class instance to point to a file.
static void dispose()
Disposes of the Singleton.