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