openMSX
Setting.cc
Go to the documentation of this file.
1 #include "Setting.hh"
2 #include "CommandController.hh"
5 #include "SettingsConfig.hh"
6 #include "TclObject.hh"
7 #include "CliComm.hh"
8 #include "XMLElement.hh"
9 #include "MSXException.hh"
10 #include "checked_cast.hh"
11 
12 using std::string;
13 
14 namespace openmsx {
15 
16 // class BaseSetting
17 
19  : name(name_.str())
20 {
21 }
22 
23 const string& BaseSetting::getName() const
24 {
25  return name;
26 }
27 
28 void BaseSetting::info(TclObject& result) const
29 {
30  result.addListElement(getTypeString());
32  additionalInfo(result);
33 }
34 
35 
36 // class Setting
37 
38 Setting::Setting(CommandController& commandController_,
39  string_ref name_, string_ref desc_,
40  const string& initialValue, SaveSetting save_)
41  : BaseSetting(name_)
42  , commandController(commandController_)
43  , description(desc_.str())
44  , value(TclObject(getInterpreter(), initialValue))
45  , defaultValue(initialValue)
46  , restoreValue(initialValue)
47  , save(save_)
48 {
49  checkFunc = [](TclObject&) { /* nothing */ };
50 }
51 
53 {
54  if (needLoadSave()) {
55  auto& settingsConfig = getGlobalCommandController()
57  if (auto* config = settingsConfig.findChild("settings")) {
58  if (auto* elem = config->findChildWithAttribute(
59  "setting", "id", getName())) {
60  try {
61  setStringDirect(elem->getData());
62  } catch (MSXException&) {
63  // saved value no longer valid, just keep default
64  }
65  }
66  }
67  }
69 
70  // This is needed to for example inform catapult of the new setting
71  // value when a setting was destroyed/recreated (by a machine switch
72  // for example).
73  notify();
74 }
75 
77 {
79 }
80 
81 
83 {
84  return description;
85 }
86 
87 void Setting::setString(const string& value)
88 {
89  getCommandController().changeSetting(*this, value);
90 }
91 
92 void Setting::notify() const
93 {
94  // Notify all subsystems of a change in the setting value. There
95  // are actually quite a few subsystems involved with the settings:
96  // - the setting classes themselves
97  // - the Tcl variables (and possibly traces on those variables)
98  // - Subject/Observers
99  // - CliComm setting-change events (for external GUIs)
100  // - SettingsConfig (keeps values, also of not yet created settings)
101  // This method takes care of the last 3 in this list.
103  commandController.getCliComm().update(
105 
106  // Always keep SettingsConfig in sync.
107  auto& config = getGlobalCommandController().getSettingsConfig().getXMLElement();
108  auto& settings = config.getCreateChild("settings");
109  string value = getString();
110  if (!needLoadSave() || (value == getDefaultValue())) {
111  // remove setting
112  if (auto* elem = settings.findChildWithAttribute(
113  "setting", "id", getName())) {
114  settings.removeChild(*elem);
115  }
116  } else {
117  // add (or overwrite) setting
118  auto& elem = settings.getCreateChildWithAttribute(
119  "setting", "id", getName());
120  // check for non-saveable value
121  // (mechanism can be generalize later when needed)
122  if (value == dontSaveValue) value = getRestoreValue();
123  elem.setData(value);
124  }
125 }
126 
128 {
129  TclObject result;
130  info(result);
131  commandController.getCliComm().update(
132  CliComm::SETTINGINFO, getName(), result.getString());
133 }
134 
136 {
137  return save == SAVE;
138 }
140 {
141  return save != DONT_TRANSFER;
142 }
143 
144 void Setting::setDontSaveValue(const std::string& dontSaveValue_)
145 {
146  dontSaveValue = dontSaveValue_;
147 }
148 
150 {
151  return commandController;
152 }
153 
154 GlobalCommandController& Setting::getGlobalCommandController() const
155 {
156  if (auto* globalCommandController =
157  dynamic_cast<GlobalCommandController*>(&commandController)) {
158  return *globalCommandController;
159  } else {
160  return checked_cast<MSXCommandController*>(&commandController)
161  ->getGlobalCommandController();
162  }
163 }
164 
166 {
167  return commandController.getInterpreter();
168 }
169 
170 void Setting::tabCompletion(std::vector<string>& /*tokens*/) const
171 {
172  // nothing
173 }
174 
175 void Setting::additionalInfo(TclObject& /*result*/) const
176 {
177  // nothing
178 }
179 
180 void Setting::setRestoreValue(const string& value)
181 {
182  restoreValue = value;
183 }
184 
185 void Setting::setChecker(std::function<void(TclObject&)> checkFunc_)
186 {
187  checkFunc = checkFunc_;
188 }
189 
190 
191 string Setting::getString() const
192 {
193  return value.getString().str();
194 }
195 
197 {
198  return defaultValue;
199 }
200 
202 {
203  return restoreValue;
204 }
205 
206 void Setting::setStringDirect(const string& str)
207 {
208  TclObject newValue(getInterpreter(), str);
209  checkFunc(newValue);
210  if (newValue != value) {
211  value = newValue;
212  notify();
213  }
214 
215  // synchronize proxy
216  auto* controller = dynamic_cast<MSXCommandController*>(
218  if (!controller) {
219  // This is not a machine specific setting.
220  return;
221  }
222  if (!controller->isActive()) {
223  // This setting does not belong to the active machine.
224  return;
225  }
226 
227  auto& globalController = controller->getGlobalCommandController();
228  // Tcl already makes sure this doesn't result in an endless loop.
229  try {
230  globalController.changeSetting(getName(), getString());
231  } catch (MSXException&) {
232  // ignore
233  }
234 }
235 
236 } // namespace openmsx
virtual std::string getDescription() const
pure virtual methods ///
Definition: Setting.cc:82
void setChecker(std::function< void(TclObject &)> checkFunc)
Set value-check-callback.
Definition: Setting.cc:185
virtual void unregisterSetting(Setting &setting)=0
virtual bool needTransfer() const
Does this setting need to be transfered on reverse.
Definition: Setting.cc:139
void notify() const
Definition: Subject.hh:65
string_ref getString() const
Definition: TclObject.cc:213
virtual void setString(const std::string &value)
Change the value of this setting to the given value.
Definition: Setting.cc:87
XMLElement & getCreateChild(string_ref name, string_ref defaultValue="")
Definition: XMLElement.cc:190
This class implements a subset of the proposal for std::string_ref (proposed for the next c++ standar...
Definition: string_ref.hh:18
virtual std::string getDefaultValue() const =0
Get the default value of this setting.
virtual std::string getRestoreValue() const
Get the value that will be set after a Tcl 'unset' command.
Definition: Setting.cc:201
BaseSetting(string_ref name)
Definition: Setting.cc:18
virtual void update(UpdateType type, string_ref name, string_ref value)=0
virtual std::string getDefaultValue() const
Get the default value of this setting.
Definition: Setting.cc:196
void save(SDL_Surface *surface, const std::string &filename)
Definition: PNG.cc:364
void notifyPropertyChange() const
Definition: Setting.cc:127
void info(TclObject &result) const
For SettingInfo.
Definition: Setting.cc:28
const std::string & getName() const
Get the name of this setting.
Definition: Setting.cc:23
virtual string_ref getTypeString() const =0
Returns a string describing the setting type (integer, string, ..) Could be used in a GUI to pick an ...
virtual void changeSetting(Setting &setting, const std::string &value)=0
virtual void tabCompletion(std::vector< std::string > &tokens) const
Complete a partly typed value.
Definition: Setting.cc:170
Setting(CommandController &commandController, string_ref name, string_ref description, const std::string &initialValue, SaveSetting save=SAVE)
Definition: Setting.cc:38
virtual Interpreter & getInterpreter()=0
virtual void setDontSaveValue(const std::string &dontSaveValue)
This value will never end up in the settings.xml file.
Definition: Setting.cc:144
virtual bool needLoadSave() const
Does this setting need to be loaded or saved (settings.xml).
Definition: Setting.cc:135
virtual void setStringDirect(const std::string &value)
Similar to setString(), but doesn't trigger Tcl traces.
Definition: Setting.cc:206
Interpreter & getInterpreter() const
Definition: Setting.cc:165
virtual SettingsConfig & getSettingsConfig()
virtual std::string getString() const
Get the current value of this setting in a string format that can be presented to the user...
Definition: Setting.cc:191
GlobalCommandController & getGlobalCommandController()
virtual void registerSetting(Setting &setting)=0
TODO.
void addListElement(string_ref element)
Definition: TclObject.cc:154
virtual ~Setting()
Definition: Setting.cc:76
virtual CliComm & getCliComm()=0
virtual void additionalInfo(TclObject &result) const
Helper method for info().
Definition: Setting.cc:175
virtual void additionalInfo(TclObject &result) const =0
Helper method for info().
void setRestoreValue(const std::string &value)
Set restore value.
Definition: Setting.cc:180
XMLElement & getXMLElement()
CommandController & getCommandController() const
Definition: Setting.cc:149
void changeSetting(const std::string &name, const std::string &value)