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