openMSX
SettingsManager.cc
Go to the documentation of this file.
1 #include "SettingsManager.hh"
3 #include "TclObject.hh"
4 #include "Setting.hh"
5 #include "CommandException.hh"
6 #include "XMLElement.hh"
7 #include "KeyRange.hh"
8 #include <cassert>
9 
10 using std::string;
11 using std::vector;
12 
13 namespace openmsx {
14 
15 // SettingsManager implementation:
16 
18  : settingInfo (commandController.getOpenMSXInfoCommand(), *this)
19  , setCompleter (commandController, *this)
20  , incrCompleter (commandController, *this, "incr")
21  , unsetCompleter(commandController, *this, "unset")
22 {
23 }
24 
26 {
27  assert(settingsMap.empty());
28 }
29 
31 {
32  assert(settingsMap.find(name) == end(settingsMap));
33  settingsMap[name] = &setting;
34 }
35 
37 {
38  assert(settingsMap.find(name) != end(settingsMap));
39  settingsMap.erase(name);
40 }
41 
43 {
44  auto it = settingsMap.find(name);
45  return (it != end(settingsMap)) ? it->second : nullptr;
46 }
47 
48 // Helper functions for setting commands
49 
50 BaseSetting& SettingsManager::getByName(string_ref cmd, string_ref name) const
51 {
52  if (auto* setting = findSetting(name)) {
53  return *setting;
54  }
55  throw CommandException(cmd + ": " + name + ": no such setting");
56 }
57 
59 {
60  // restore default values
61  for (auto* s : values(settingsMap)) {
62  if (s->needLoadSave()) {
63  s->setValue(s->getRestoreValue());
64  }
65  }
66 
67  // load new values
68  auto* settings = config.findChild("settings");
69  if (!settings) return;
70  for (auto& p : settingsMap) {
71  auto name = p.first();
72  auto& setting = *p.second;
73  if (!setting.needLoadSave()) continue;
74  if (auto* elem = settings->findChildWithAttribute(
75  "setting", "id", name)) {
76  try {
77  setting.setValue(TclObject(elem->getData()));
78  } catch (MSXException&) {
79  // ignore, keep default value
80  }
81  }
82  }
83 }
84 
85 
86 // class SettingInfo
87 
88 SettingsManager::SettingInfo::SettingInfo(
89  InfoCommand& openMSXInfoCommand, SettingsManager& manager_)
90  : InfoTopic(openMSXInfoCommand, "setting")
91  , manager(manager_)
92 {
93 }
94 
95 void SettingsManager::SettingInfo::execute(
96  array_ref<TclObject> tokens, TclObject& result) const
97 {
98  auto& settingsMap = manager.settingsMap;
99  switch (tokens.size()) {
100  case 2:
101  for (auto& p : settingsMap) {
102  result.addListElement(p.first());
103  }
104  break;
105  case 3: {
106  const auto& name = tokens[2].getString();
107  auto it = settingsMap.find(name);
108  if (it == end(settingsMap)) {
109  throw CommandException("No such setting: " + name);
110  }
111  it->second->info(result);
112  break;
113  }
114  default:
115  throw CommandException("Too many parameters.");
116  }
117 }
118 
119 string SettingsManager::SettingInfo::help(const vector<string>& /*tokens*/) const
120 {
121  return "openmsx_info setting : "
122  "returns list of all settings\n"
123  "openmsx_info setting <name> : "
124  "returns info on a specific setting\n";
125 }
126 
127 void SettingsManager::SettingInfo::tabCompletion(vector<string>& tokens) const
128 {
129  if (tokens.size() == 3) {
130  // complete setting name
131  completeString(tokens, keys(manager.settingsMap));
132  }
133 }
134 
135 
136 // class SetCompleter
137 
138 SettingsManager::SetCompleter::SetCompleter(
139  CommandController& commandController, SettingsManager& manager_)
140  : CommandCompleter(commandController, "set"), manager(manager_)
141 {
142 }
143 
144 string SettingsManager::SetCompleter::help(const vector<string>& tokens) const
145 {
146  if (tokens.size() == 2) {
147  return manager.getByName("set", tokens[1]).getDescription().str();
148  }
149  return "Set or query the value of a openMSX setting or Tcl variable\n"
150  " set <setting> shows current value\n"
151  " set <setting> <value> set a new value\n"
152  "Use 'help set <setting>' to get more info on a specific\n"
153  "openMSX setting.\n";
154 }
155 
156 void SettingsManager::SetCompleter::tabCompletion(vector<string>& tokens) const
157 {
158  switch (tokens.size()) {
159  case 2:
160  // complete setting name
161  completeString(tokens, keys(manager.settingsMap), false); // case insensitive
162  break;
163  case 3: {
164  // complete setting value
165  auto it = manager.settingsMap.find(tokens[1]);
166  if (it != end(manager.settingsMap)) {
167  it->second->tabCompletion(tokens);
168  }
169  break;
170  }
171  }
172 }
173 
174 
175 // class SettingCompleter
176 
177 SettingsManager::SettingCompleter::SettingCompleter(
178  CommandController& commandController, SettingsManager& manager_,
179  const string& name)
180  : CommandCompleter(commandController, name)
181  , manager(manager_)
182 {
183 }
184 
185 string SettingsManager::SettingCompleter::help(const vector<string>& /*tokens*/) const
186 {
187  return ""; // TODO
188 }
189 
190 void SettingsManager::SettingCompleter::tabCompletion(vector<string>& tokens) const
191 {
192  if (tokens.size() == 2) {
193  // complete setting name
194  completeString(tokens, keys(manager.settingsMap));
195  }
196 }
197 
198 } // namespace openmsx
detail::KeyRange< MAP, 1 > values(const MAP &map)
Definition: KeyRange.hh:101
string_ref::const_iterator end(const string_ref &x)
Definition: string_ref.hh:150
size_type size() const
Definition: array_ref.hh:61
This class implements a subset of the proposal for std::string_ref (proposed for the next c++ standar...
Definition: string_ref.hh:18
void loadSettings(const XMLElement &config)
void unregisterSetting(BaseSetting &setting, string_ref name)
void registerSetting(BaseSetting &setting, string_ref name)
const XMLElement * findChild(string_ref name) const
Definition: XMLElement.cc:132
Manages all settings.
This class implements a subset of the proposal for std::array_ref (proposed for the next c++ standard...
Definition: array_ref.hh:19
BaseSetting * findSetting(string_ref name) const
Find the setting with given name.
SettingsManager(GlobalCommandController &commandController)
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
detail::KeyRange< MAP, 0 > keys(const MAP &map)
Definition: KeyRange.hh:96