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