doomseekerconfig.cpp
1 //------------------------------------------------------------------------------
2 // doomseekerconfig.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; 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 "fileutils.h"
38 #include "localizationinfo.h"
39 #include "log.h"
40 #include "scanner.h"
41 #include "strings.hpp"
42 #include "version.h"
43 
44 #include <QLocale>
48 static PatternList readPre1Point2BuddiesList(const QString &configEntry)
49 {
50  PatternList patterns;
51 
52  Scanner listReader(configEntry.toUtf8().constData(), configEntry.length());
53  // Syntax: {basic|advanced} "pattern";...
54  while (listReader.tokensLeft())
55  {
56  if (!listReader.checkToken(TK_Identifier))
57  {
58  break; // Invalid so lets just use what we have.
59  }
60 
61  QRegExp::PatternSyntax syntax;
62  if (listReader->str().compare("basic") == 0)
63  syntax = QRegExp::Wildcard;
64  else
65  syntax = QRegExp::RegExp;
66 
67  if (!listReader.checkToken(TK_StringConst))
68  {
69  break;
70  }
71 
72  QRegExp pattern(listReader->str(), Qt::CaseInsensitive, syntax);
73  if (pattern.isValid())
74  {
75  patterns << pattern;
76  }
77 
78  if (!listReader.checkToken(';'))
79  {
80  break;
81  }
82  }
83  return patterns;
84 }
86 DoomseekerConfig* DoomseekerConfig::instance = NULL;
87 
88 DoomseekerConfig::DoomseekerConfig()
89 {
90  this->dummySection = new IniSection(NULL, QString());
91 }
92 
93 DoomseekerConfig::~DoomseekerConfig()
94 {
95  delete this->dummySection;
96 }
97 
99 {
100  if (instance == NULL)
101  {
102  instance = new DoomseekerConfig();
103  }
104 
105  return *instance;
106 }
107 
109 {
110  if (instance != NULL)
111  {
112  delete instance;
113  instance = NULL;
114  }
115 }
116 
118 {
119  if (pluginName.isEmpty())
120  {
121  gLog << QObject::tr("DoomseekerConfig.iniSectionForPlugin(): empty plugin name has been specified, returning dummy IniSection.");
122  return *dummySection;
123  }
124 
125  if (!isValidPluginName(pluginName))
126  {
127  gLog << QObject::tr("DoomseekerConfig.iniSectionForPlugin(): plugin name is invalid: %1").arg(pluginName);
128  return *dummySection;
129  }
130 
131  if (this->pIni == NULL)
132  {
133  setIniFile("");
134  }
135 
136  QString sectionName = pluginName;
137  sectionName = sectionName.replace(' ', "");
138  return this->pIni->section(sectionName);
139 }
140 
142 {
143  return iniSectionForPlugin(plugin->data()->name);
144 }
145 
146 bool DoomseekerConfig::isValidPluginName(const QString& pluginName) const
147 {
148  QString invalids[] = { "doomseeker", "wadseeker", "" };
149 
150  for (int i = 0; !invalids[i].isEmpty(); ++i)
151  {
152  if (pluginName.compare(invalids[i], Qt::CaseInsensitive) == 0)
153  {
154  return false;
155  }
156  }
157 
158  return true;
159 }
160 
162 {
163  if (pIni == NULL)
164  {
165  return false;
166  }
167 
168  IniSection sectionDoomseeker = pIni->section(doomseeker.SECTION_NAME);
169  doomseeker.load(sectionDoomseeker);
170 
171  IniSection sectionServerFilter = pIni->section(serverFilter.SECTION_NAME);
172  serverFilter.load(sectionServerFilter);
173 
174  IniSection sectionWadseeker = pIni->section(wadseeker.SECTION_NAME);
175  wadseeker.load(sectionWadseeker);
176 
177  IniSection sectionAutoUpdates = pIni->section(autoUpdates.SECTION_NAME);
178  autoUpdates.load(sectionAutoUpdates);
179 
180  // Plugins should read their sections manually.
181 
182  return true;
183 }
184 
186 {
187  if (pIni == NULL)
188  {
189  return false;
190  }
191 
192 // TODO:
193 // Find a way to work around this.
194 // const QString TOP_COMMENT = QObject::tr("This is %1 configuration file.\n\
195 //Any modification done manually to this file is on your own risk.").arg(Version::fullVersionInfo());
196 //
197 // pIni->setIniTopComment(TOP_COMMENT);
198 
199  IniSection sectionDoomseeker = pIni->section(doomseeker.SECTION_NAME);
200  doomseeker.save(sectionDoomseeker);
201 
202  IniSection sectionServerFilter = pIni->section(serverFilter.SECTION_NAME);
203  serverFilter.save(sectionServerFilter);
204 
205  IniSection sectionWadseeker = pIni->section(wadseeker.SECTION_NAME);
206  wadseeker.save(sectionWadseeker);
207 
208  IniSection sectionAutoUpdates = pIni->section(autoUpdates.SECTION_NAME);
209  autoUpdates.save(sectionAutoUpdates);
210 
211  // Plugins should save their sections manually.
212  if (this->settings->isWritable())
213  {
214  this->settings->sync();
215  return true;
216  }
217  return false;
218 }
219 
220 bool DoomseekerConfig::setIniFile(const QString& filePath)
221 {
222  // Delete old instances if necessary.
223  this->pIni.reset();
224  this->settingsProvider.reset();
225  this->settings.reset();
226 
227  gLog << QObject::tr("Setting INI file: %1").arg(filePath);
228  // Create new instances.
229  this->settings.reset(new QSettings(filePath, QSettings::IniFormat));
230  this->settingsProvider.reset(new SettingsProviderQt(this->settings.data()));
231  this->pIni.reset(new Ini(this->settingsProvider.data()));
232 
233  // Init.
234  IniSection section;
235 
236  section = this->pIni->section(doomseeker.SECTION_NAME);
237  doomseeker.init(section);
238 
239  section = this->pIni->section(serverFilter.SECTION_NAME);
240  serverFilter.init(section);
241 
242  section = this->pIni->section(wadseeker.SECTION_NAME);
243  wadseeker.init(section);
244 
245  section = this->pIni->section(autoUpdates.SECTION_NAME);
246  autoUpdates.init(section);
247 
248  return true;
249 }
250 
251 QList<FileSearchPath> DoomseekerConfig::combinedWadseekPaths() const
252 {
253  QList<FileSearchPath> paths = doomseeker.wadPaths;
254  paths << wadseeker.targetDirectory;
255  return paths;
256 }
257 
259 DClass<DoomseekerConfig::DoomseekerCfg>
260 {
261  public:
262  IniSection section;
263  QuerySpeed querySpeed;
264 
265  QString slotStyle() const
266  {
267  // Slot styles were indexed in older versions of Doomseeker.
268  // This here provides compatibility layer that allows to load configuration
269  // files from those versions.
270  const int NUM_SLOTSTYLES = 2;
271  const char* indexedSlotStyles[NUM_SLOTSTYLES] = { "marines", "blocks" };
272  bool isInt = false;
273  int numeric = section["SlotStyle"].value().toInt(&isInt);
274  if (isInt && numeric >= 0 && numeric < NUM_SLOTSTYLES)
275  {
276  return indexedSlotStyles[numeric];
277  }
278  else
279  {
280  return section["SlotStyle"].valueString();
281  }
282  }
283 };
284 
286 
287 const QString DoomseekerConfig::DoomseekerCfg::SECTION_NAME = "Doomseeker";
288 
289 DoomseekerConfig::DoomseekerCfg::DoomseekerCfg()
290 {
291  this->bBotsAreNotPlayers = true;
292  this->bCloseToTrayIcon = false;
293  this->bColorizeServerConsole = true;
294  this->bDrawGridInServerTable = false;
295  this->bHidePasswords = false;
296  this->bGroupServersWithPlayersAtTheTopOfTheList = true;
297  this->bIP2CountryAutoUpdate = true;
298  this->bLookupHosts = true;
299  this->bQueryAutoRefreshDontIfActive = true;
300  this->bQueryAutoRefreshEnabled = false;
301  this->bQueryBeforeLaunch = true;
302  this->bQueryOnStartup = true;
303  this->bRecordDemo = false;
304  this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn = true;
305  this->bUseTrayIcon = false;
306  this->bMarkServersWithBuddies = true;
307  this->buddyServersColor = "#5ecf75";
308  this->customServersColor = "#ffaa00";
309  this->lanServersColor = "#92ebe5";
310  this->localization = LocalizationInfo::SYSTEM_FOLLOW.localeName;
311  this->mainWindowState = "";
312  this->mainWindowGeometry = "";
313  this->queryAutoRefreshEverySeconds = 180;
314  setQuerySpeed(QuerySpeed::aggressive());
315  this->previousCreateServerConfigDir = "";
316  this->previousCreateServerExecDir = "";
317  this->previousCreateServerWadDir = "";
318  this->slotStyle = 1;
319  this->serverListSortIndex = -1;
320  this->serverListSortDirection = Qt::DescendingOrder;
321  this->wadPaths = FileSearchPath::fromStringList(gDefaultDataPaths->defaultWadPaths());
322 }
323 
324 DoomseekerConfig::DoomseekerCfg::~DoomseekerCfg()
325 {
326 }
327 
328 QList<ColumnSort> DoomseekerConfig::DoomseekerCfg::additionalSortColumns() const
329 {
330  QList<ColumnSort> list;
331  QVariantList varList = d->section.value("AdditionalSortColumns").toList();
332  foreach (const QVariant &var, varList)
333  {
334  list << ColumnSort::deserializeQVariant(var);
335  }
336  return list;
337 }
338 
339 void DoomseekerConfig::DoomseekerCfg::setAdditionalSortColumns(const QList<ColumnSort> &val)
340 {
341  QVariantList varList;
342  foreach (const ColumnSort &elem, val)
343  {
344  varList << elem.serializeQVariant();
345  }
346  d->section.setValue("AdditionalSortColumns", varList);
347 }
348 
350 {
351  // TODO: Make all methods use d->section
352  d->section = section;
353  section.createSetting("Localization", this->localization);
354  section.createSetting("BotsAreNotPlayers", this->bBotsAreNotPlayers);
355  section.createSetting("CloseToTrayIcon", this->bCloseToTrayIcon);
356  section.createSetting("ColorizeServerConsole", this->bColorizeServerConsole);
357  section.createSetting("DrawGridInServerTable", this->bDrawGridInServerTable);
358  section.createSetting("HidePasswords", this->bHidePasswords);
359  section.createSetting("GroupServersWithPlayersAtTheTopOfTheList", this->bGroupServersWithPlayersAtTheTopOfTheList);
360  section.createSetting("IP2CAutoUpdate", this->bIP2CountryAutoUpdate);
361  section.createSetting("LookupHosts", this->bLookupHosts);
362  section.createSetting("QueryAutoRefreshDontIfActive", this->bQueryAutoRefreshDontIfActive);
363  section.createSetting("QueryAutoRefreshEnabled", this->bQueryAutoRefreshEnabled);
364  section.createSetting("QueryOnStartup", this->bQueryOnStartup);
365  section.createSetting("RecordDemo", this->bRecordDemo);
366  section.createSetting("TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn", this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn);
367  section.createSetting("UseTrayIcon", this->bUseTrayIcon);
368  section.createSetting("MarkServersWithBuddies", this->bMarkServersWithBuddies);
369  section.createSetting("BuddyServersColor", this->buddyServersColor);
370  section.createSetting("CustomServersColor", this->customServersColor);
371  section.createSetting("LanServersColor", this->lanServersColor);
372  section.createSetting("QueryAutoRefreshEverySeconds", this->queryAutoRefreshEverySeconds);
373  section.createSetting("QueryServerInterval", this->querySpeed().intervalBetweenServers);
374  section.createSetting("QueryServerTimeout", this->querySpeed().delayBetweenSingleServerAttempts);
375  section.createSetting("QueryAttemptsPerServer", this->querySpeed().attemptsPerServer);
376  section.createSetting("SlotStyle", this->slotStyle);
377  section.createSetting("ServerListSortIndex", this->serverListSortIndex);
378  section.createSetting("ServerListSortDirection", this->serverListSortDirection);
379  section.createSetting("WadPaths", FileSearchPath::toVariantList(this->wadPaths));
380 
381  initWadAlias();
382 }
383 
384 void DoomseekerConfig::DoomseekerCfg::initWadAlias()
385 {
386  if (!d->section.hasSetting("WadAliases"))
387  {
388  setWadAliases(FileAlias::standardWadAliases());
389  }
390 }
391 
392 void DoomseekerConfig::DoomseekerCfg::load(IniSection& section)
393 {
394  this->localization = (const QString&)section["Localization"];
395  this->bBotsAreNotPlayers = section["BotsAreNotPlayers"];
396  this->bCloseToTrayIcon = section["CloseToTrayIcon"];
397  this->bColorizeServerConsole = section["ColorizeServerConsole"];
398  this->bDrawGridInServerTable = section["DrawGridInServerTable"];
399  this->bHidePasswords = section["HidePasswords"];
400  this->bGroupServersWithPlayersAtTheTopOfTheList = section["GroupServersWithPlayersAtTheTopOfTheList"];
401  this->bIP2CountryAutoUpdate = section["IP2CAutoUpdate"];
402  this->bLookupHosts = section["LookupHosts"];
403  this->bQueryAutoRefreshDontIfActive = section["QueryAutoRefreshDontIfActive"];
404  this->bQueryAutoRefreshEnabled = section["QueryAutoRefreshEnabled"];
405  this->bQueryBeforeLaunch = section["QueryBeforeLaunch"];
406  this->bQueryOnStartup = section["QueryOnStartup"];
407  this->bRecordDemo = section["RecordDemo"];
408  this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn = section["TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn"];
409  this->bUseTrayIcon = section["UseTrayIcon"];
410  this->bMarkServersWithBuddies = section["MarkServersWithBuddies"];
411  this->buddyServersColor = (const QString &)section["BuddyServersColor"];
412  this->customServersColor = (const QString &)section["CustomServersColor"];
413  this->lanServersColor = (const QString &)section["LanServersColor"];
414  this->mainWindowState = (const QString &)section["MainWindowState"];
415  this->mainWindowGeometry = section.value("MainWindowGeometry", "").toByteArray();
416  this->queryAutoRefreshEverySeconds = section["QueryAutoRefreshEverySeconds"];
417  d->querySpeed.intervalBetweenServers = section["QueryServerInterval"];
418  d->querySpeed.delayBetweenSingleServerAttempts = section["QueryServerTimeout"];
419  d->querySpeed.attemptsPerServer = section["QueryAttemptsPerServer"];
420  this->previousCreateServerConfigDir = (const QString &)section["PreviousCreateServerConfigDir"];
421  this->previousCreateServerExecDir = (const QString &)section["PreviousCreateServerExecDir"];
422  this->previousCreateServerWadDir = (const QString &)section["PreviousCreateServerWadDir"];
423  this->serverListColumnState = (const QString &)section["ServerListColumnState"];
424  this->serverListSortIndex = section["ServerListSortIndex"];
425  this->serverListSortDirection = section["ServerListSortDirection"];
426  this->slotStyle = d->slotStyle();
427 
428  // Complex data variables.
429 
430  // Custom servers
431  // CustomServers2 is for Doomseeker >= 1.2.
432  // Deserialization of this setting is not backwards-compatible,
433  // hence we need an extra compatibility layer. The amount of
434  // information that the user could potentially lose if I had
435  // been too lazy to code this would be insufferable.
436  QList<CustomServerInfo> customServersList;
437  CustomServers::decodeConfigEntries(section["CustomServers2"], customServersList);
438  QList<CustomServerInfo> backwardCompatibleServers;
439  CustomServers::decodeConfigEntries(section["CustomServers"], backwardCompatibleServers);
440  foreach (const CustomServerInfo &backwardCompatibleServer, backwardCompatibleServers)
441  {
442  bool known = false;
443  foreach (const CustomServerInfo &knownServer, customServersList)
444  {
445  if (knownServer.isSameServer(backwardCompatibleServer))
446  {
447  known = true;
448  break;
449  }
450  }
451  if (!known)
452  customServersList << backwardCompatibleServer;
453  }
454  this->customServers = customServersList.toVector();
455 
456  // WAD paths
457  // Backward compatibility, XXX once new stable is released:
458  QVariant variantWadPaths = section["WadPaths"].value();
459  if (variantWadPaths.isValid() && variantWadPaths.toList().isEmpty())
460  {
461  // Backward compatibility continued:
462  wadPaths.clear();
463  QStringList paths = variantWadPaths.toString().split(";");
464  foreach (const QString& path, paths)
465  {
466  wadPaths << FileSearchPath(path);
467  }
468  }
469  else
470  {
471  // This is not a part of XXX, this is proper, current behavior:
472  wadPaths = FileSearchPath::fromVariantList(section["WadPaths"].value().toList());
473  }
474  // End of backward compatibility for WAD paths.
475 
476  // Buddies list
477  if (section.hasSetting("Buddies"))
478  {
479  this->buddies = PatternList::deserializeQVariant(section.value("Buddies"));
480  }
481  else if (section.hasSetting("BuddiesList"))
482  {
483  // Backward compatibility, pre 1.2.
484  this->buddies = readPre1Point2BuddiesList(section["BuddiesList"]);
485  }
486 }
487 
488 void DoomseekerConfig::DoomseekerCfg::save(IniSection& section)
489 {
490  section["Localization"] = this->localization;
491  section["BotsAreNotPlayers"] = this->bBotsAreNotPlayers;
492  section["CloseToTrayIcon"] = this->bCloseToTrayIcon;
493  section["ColorizeServerConsole"] = this->bColorizeServerConsole;
494  section["DrawGridInServerTable"] = this->bDrawGridInServerTable;
495  section["HidePasswords"] = this->bHidePasswords;
496  section["GroupServersWithPlayersAtTheTopOfTheList"] = this->bGroupServersWithPlayersAtTheTopOfTheList;
497  section["IP2CAutoUpdate"] = this->bIP2CountryAutoUpdate;
498  section["LookupHosts"] = this->bLookupHosts;
499  section["QueryAutoRefreshDontIfActive"] = this->bQueryAutoRefreshDontIfActive;
500  section["QueryAutoRefreshEnabled"] = this->bQueryAutoRefreshEnabled;
501  section["QueryBeforeLaunch"] = this->bQueryBeforeLaunch;
502  section["QueryOnStartup"] = this->bQueryOnStartup;
503  section["RecordDemo"] = this->bRecordDemo;
504  section["TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn"] = this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn;
505  section["UseTrayIcon"] = this->bUseTrayIcon;
506  section["MarkServersWithBuddies"] = this->bMarkServersWithBuddies;
507  section["BuddyServersColor"] = this->buddyServersColor;
508  section["CustomServersColor"] = this->customServersColor;
509  section["LanServersColor"] = this->lanServersColor;
510  section["MainWindowState"] = this->mainWindowState;
511  section.setValue("MainWindowGeometry", this->mainWindowGeometry);
512  section["QueryAutoRefreshEverySeconds"] = this->queryAutoRefreshEverySeconds;
513  section["QueryServerInterval"] = this->querySpeed().intervalBetweenServers;
514  section["QueryServerTimeout"] = this->querySpeed().delayBetweenSingleServerAttempts;
515  section["QueryAttemptsPerServer"] = this->querySpeed().attemptsPerServer;
516  section["PreviousCreateServerConfigDir"] = this->previousCreateServerConfigDir;
517  section["PreviousCreateServerExecDir"] = this->previousCreateServerExecDir;
518  section["PreviousCreateServerWadDir"] = this->previousCreateServerWadDir;
519  section["ServerListColumnState"] = this->serverListColumnState;
520  section["ServerListSortIndex"] = this->serverListSortIndex;
521  section["ServerListSortDirection"] = this->serverListSortDirection;
522  section["SlotStyle"] = this->slotStyle;
523 
524  // Complex data variables.
525 
526  // Custom servers
527  QStringList allCustomServers; // backward compatibility for Doomseeker <1.2
528  QStringList allCustomServers2; // Doomseeker >=1.2
529  foreach (const CustomServerInfo& customServer, this->customServers)
530  {
531  QString engineName = QUrl::toPercentEncoding(customServer.engine, "", "()");
532  QString address = QUrl::toPercentEncoding(customServer.host, "", "()");
533 
534  QString customServerStringPrefix = QString("(%1;%2;%3")
535  .arg(engineName).arg(address)
536  .arg(customServer.port);
537  QString customServerString2 = QString("%1;%2)")
538  .arg(customServerStringPrefix)
539  .arg(customServer.enabled ? 1 : 0);
540 
541  allCustomServers << customServerStringPrefix + ")";
542  allCustomServers2 << customServerString2;
543  }
544  section["CustomServers"] = allCustomServers.join(";");
545  section["CustomServers2"] = allCustomServers2.join(";");
546 
547  section["WadPaths"].setValue(FileSearchPath::toVariantList(this->wadPaths));
548  section["Buddies"].setValue(this->buddies.serializeQVariant());
549 }
550 
551 const QuerySpeed &DoomseekerConfig::DoomseekerCfg::querySpeed() const
552 {
553  return d->querySpeed;
554 }
555 
556 void DoomseekerConfig::DoomseekerCfg::setQuerySpeed(const QuerySpeed &val)
557 {
558  d->querySpeed = val;
559 }
560 
561 QList<FileAlias> DoomseekerConfig::DoomseekerCfg::wadAliases() const
562 {
563  QList<FileAlias> list;
564  QVariantList varList = d->section.value("WadAliases").toList();
565  foreach (const QVariant &var, varList)
566  {
567  list << FileAlias::deserializeQVariant(var);
568  }
569  return FileAliasList::mergeDuplicates(list);
570 }
571 
572 void DoomseekerConfig::DoomseekerCfg::setWadAliases(const QList<FileAlias> &val)
573 {
574  QVariantList varList;
575  foreach (const FileAlias &elem, val)
576  {
577  varList << elem.serializeQVariant();
578  }
579  d->section.setValue("WadAliases", varList);
580 }
581 
582 void DoomseekerConfig::DoomseekerCfg::enableFreedoomInstallation(const QString &dir)
583 {
584  if (!FileUtils::containsPath(wadPathsOnly(), dir))
585  {
586  wadPaths.prepend(dir);
587  }
588  QList<FileAlias> aliases = wadAliases();
589  aliases << FileAlias::freeDoom1Aliases();
590  aliases << FileAlias::freeDoom2Aliases();
591  aliases = FileAliasList::mergeDuplicates(aliases);
592  setWadAliases(aliases);
593 }
594 
595 QStringList DoomseekerConfig::DoomseekerCfg::wadPathsOnly() const
596 {
597  QStringList result;
598  foreach (const FileSearchPath& path, wadPaths)
599  {
600  result << path.path();
601  }
602  return result;
603 }
605 const QString DoomseekerConfig::AutoUpdates::SECTION_NAME = "Doomseeker_AutoUpdates";
606 
607 void DoomseekerConfig::AutoUpdates::init(IniSection& section)
608 {
609  section.createSetting("UpdateChannelName", UpdateChannel::mkStable().name());
610  section.createSetting("UpdateMode", (int) UM_NotifyOnly);
611  section.createSetting("LastKnownUpdateRevisions", QVariant());
612  section.createSetting("bPerformUpdateOnNextRun", false);
613 }
614 
615 void DoomseekerConfig::AutoUpdates::load(IniSection& section)
616 {
617  updateChannelName = (const QString &)section["UpdateChannelName"];
618  updateMode = (UpdateMode)section["UpdateMode"].value().toInt();
619  QVariantMap lastKnownUpdateRevisionsVariant = section["LastKnownUpdateRevisions"].value().toMap();
620  lastKnownUpdateRevisions.clear();
621  foreach (const QString& package, lastKnownUpdateRevisionsVariant.keys())
622  {
623  QVariant revisionVariant = lastKnownUpdateRevisionsVariant[package];
624  lastKnownUpdateRevisions.insert(package, revisionVariant.toString());
625  }
626  bPerformUpdateOnNextRun = section["bPerformUpdateOnNextRun"].value().toBool();
627 }
628 
629 void DoomseekerConfig::AutoUpdates::save(IniSection& section)
630 {
631  section["UpdateChannelName"] = updateChannelName;
632  section["UpdateMode"] = updateMode;
633  QVariantMap revisionsVariantMap;
634  foreach (const QString& package, lastKnownUpdateRevisions.keys())
635  {
636  revisionsVariantMap.insert(package, lastKnownUpdateRevisions[package]);
637  }
638  section["LastKnownUpdateRevisions"].setValue(revisionsVariantMap);
639  section["bPerformUpdateOnNextRun"].setValue(bPerformUpdateOnNextRun);
640 }
642 const QString DoomseekerConfig::ServerFilter::SECTION_NAME = "ServerFilter";
643 
644 void DoomseekerConfig::ServerFilter::init(IniSection& section)
645 {
646  section.createSetting("bEnabled", true);
647  section.createSetting("bShowEmpty", true);
648  section.createSetting("bShowFull", true);
649  section.createSetting("bShowOnlyValid", false);
650  section.createSetting("GameModes", QStringList());
651  section.createSetting("GameModesExcluded", QStringList());
652  section.createSetting("MaxPing", 0);
653  section.createSetting("ServerName", "");
654  section.createSetting("TestingServers", Doomseeker::Indifferent);
655  section.createSetting("WADs", QStringList());
656  section.createSetting("WADsExcluded", QStringList());
657 }
658 
659 void DoomseekerConfig::ServerFilter::load(IniSection& section)
660 {
661  info.bEnabled = section["bEnabled"];
662  info.bShowEmpty = section["bShowEmpty"];
663  info.bShowFull = section["bShowFull"];
664  info.bShowOnlyValid = section["bShowOnlyValid"];
665  info.gameModes = section["GameModes"].value().toStringList();
666  info.gameModesExcluded = section["GameModesExcluded"].value().toStringList();
667  info.maxPing = section["MaxPing"];
668  info.serverName = (const QString &)section["ServerName"];
669  info.testingServers = static_cast<Doomseeker::ShowMode>(section.value("TestingServers").toInt());
670  info.wads = section["WADs"].value().toStringList();
671  info.wadsExcluded = section["WADsExcluded"].value().toStringList();
672 }
673 
674 void DoomseekerConfig::ServerFilter::save(IniSection& section)
675 {
676  section["bEnabled"] = info.bEnabled;
677  section["bShowEmpty"] = info.bShowEmpty;
678  section["bShowFull"] = info.bShowFull;
679  section["bShowOnlyValid"] = info.bShowOnlyValid;
680  section["GameModes"].setValue(info.gameModes);
681  section["GameModesExcluded"].setValue(info.gameModesExcluded);
682  section["MaxPing"] = info.maxPing;
683  section["ServerName"] = info.serverName;
684  section["TestingServers"] = info.testingServers;
685  section["WADs"].setValue(info.wads);
686  section["WADsExcluded"].setValue(info.wadsExcluded);
687 }
689 const QString DoomseekerConfig::WadseekerCfg::SECTION_NAME = "Wadseeker";
690 
691 DoomseekerConfig::WadseekerCfg::WadseekerCfg()
692 {
693  this->bAlwaysUseDefaultSites = true;
694  this->bSearchInIdgames = true;
695  this->bSearchInWadArchive = true;
696  this->colorMessageCriticalError = "#ff0000";
697  this->colorMessageError = "#ff0000";
698  this->colorMessageNotice = "#000000";
699  this->connectTimeoutSeconds = WADSEEKER_CONNECT_TIMEOUT_SECONDS_DEFAULT;
700  this->downloadTimeoutSeconds = WADSEEKER_DOWNLOAD_TIMEOUT_SECONDS_DEFAULT;
701  this->idgamesURL = Wadseeker::defaultIdgamesUrl();
702  this->maxConcurrentSiteDownloads = 3;
703  this->maxConcurrentWadDownloads = 2;
704  this->targetDirectory = gDefaultDataPaths->programsDataDirectoryPath();
705 
706  // Search URLs remains unitizalized here. It will be initialized
707  // by init() and then load() since Doomseeker always calls these
708  // methods in this order.
709 }
710 
712 {
713  section.createSetting("AlwaysUseDefaultSites", this->bAlwaysUseDefaultSites);
714  section.createSetting("SearchInIdgames", this->bSearchInIdgames);
715  section.createSetting("SearchInWadArchive", this->bSearchInWadArchive);
716  section.createSetting("ColorMessageCriticalError", this->colorMessageCriticalError);
717  section.createSetting("ColorMessageError", this->colorMessageError);
718  section.createSetting("ColorMessageNotice", this->colorMessageNotice);
719  section.createSetting("ConnectTimeoutSeconds", this->connectTimeoutSeconds);
720  section.createSetting("DownloadTimeoutSeconds", this->downloadTimeoutSeconds);
721  section.createSetting("IdgamesApiURL", this->idgamesURL);
722  section.createSetting("MaxConcurrentSiteDownloads", this->maxConcurrentSiteDownloads);
723  section.createSetting("MaxConcurrentWadDownloads", this->maxConcurrentWadDownloads);
724  section.createSetting("SearchURLs", Wadseeker::defaultSitesListEncoded().join(";"));
725  section.createSetting("TargetDirectory", this->targetDirectory);
726 }
727 
728 void DoomseekerConfig::WadseekerCfg::load(IniSection& section)
729 {
730  this->bAlwaysUseDefaultSites = section["AlwaysUseDefaultSites"];
731  this->bSearchInIdgames = section["SearchInIdgames"];
732  this->bSearchInWadArchive = section["SearchInWadArchive"];
733  this->colorMessageCriticalError = (const QString &)section["ColorMessageCriticalError"];
734  this->colorMessageError = (const QString &)section["ColorMessageError"];
735  this->colorMessageNotice = (const QString &)section["ColorMessageNotice"];
736  this->connectTimeoutSeconds = section["ConnectTimeoutSeconds"];
737  this->downloadTimeoutSeconds = section["DownloadTimeoutSeconds"];
738  this->idgamesURL = (const QString &)section["IdgamesApiURL"];
739  this->maxConcurrentSiteDownloads = section["MaxConcurrentSiteDownloads"];
740  this->maxConcurrentWadDownloads = section["MaxConcurrentWadDownloads"];
741  this->targetDirectory = (const QString &)section["TargetDirectory"];
742 
743  // Complex data values
744  this->searchURLs.clear();
745  QStringList urlList = section["SearchURLs"].valueString().split(";", QString::SkipEmptyParts);
746  foreach (const QString& url, urlList)
747  {
748  this->searchURLs << QUrl::fromPercentEncoding(url.toUtf8());
749  }
750 }
751 
752 void DoomseekerConfig::WadseekerCfg::save(IniSection& section)
753 {
754  section["AlwaysUseDefaultSites"] = this->bAlwaysUseDefaultSites;
755  section["SearchInIdgames"] = this->bSearchInIdgames;
756  section["SearchInWadArchive"] = this->bSearchInWadArchive;
757  section["ColorMessageCriticalError"] = this->colorMessageCriticalError;
758  section["ColorMessageError"] = this->colorMessageError;
759  section["ColorMessageNotice"] = this->colorMessageNotice;
760  section["ConnectTimeoutSeconds"] = this->connectTimeoutSeconds;
761  section["DownloadTimeoutSeconds"] = this->downloadTimeoutSeconds;
762  section["IdgamesApiURL"] = this->idgamesURL;
763  section["MaxConcurrentSiteDownloads"] = this->maxConcurrentSiteDownloads;
764  section["MaxConcurrentWadDownloads"] = this->maxConcurrentWadDownloads;
765  section["TargetDirectory"] = this->targetDirectory;
766 
767  // Complex data values
768  QStringList urlEncodedList;
769  foreach (const QString& url, this->searchURLs)
770  {
771  urlEncodedList << QUrl::toPercentEncoding(url);
772  }
773  section["SearchURLs"] = urlEncodedList.join(";");
774 }
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...
QString localeName
Compliant with language_country standard. See QLocale::name()
This Singleton holds entire Doomseeker configuration in memory.
static bool containsPath(const QStringList &candidates, const QString &path)
Uses QFileInfo::operator== to see if &#39;path&#39; is on &#39;candidates&#39; list.
Definition: fileutils.cpp:71
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:170
bool hasSetting(const QString &name) const
true if setting of given name exists within the section.
Definition: inisection.cpp:84
static void decodeConfigEntries(const QString &str, QList< CustomServerInfo > &outCustomServerInfoList)
bool isSameServer(const CustomServerInfo &other) const
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
Scanner reads scripts by checking individual tokens.
Definition: scanner.h:75
bool setIniFile(const QString &filePath)
Initializes the Ini class instance to point to a file.
static void dispose()
Disposes of the Singleton.
static const LocalizationInfo SYSTEM_FOLLOW