2 To use the Options system:
4 1. Create an OptionGroup:
5 options = OptionGroup('MyProg', 'Options')
6 You can also use the handy rox.setup_app_options() in most applications.
9 colour = Option('colour', 'red', options)
10 size = Option('size', 3, options)
11 icons = ListOption('icons', ('circle', 'square', 'triangle'), options)
13 3. Register any callbacks (notification of options changing):
15 if colour.has_changed:
16 print "The colour is now", colour.value
17 options.add_notify(my_callback)
19 4. Notify any changes from defaults:
22 See OptionsBox for editing options. Do not change the value of options
26 from __future__
import generators
30 from rox
import choices
, basedir
32 from xml
.dom
import Node
, minidom
35 """Return all the text directly inside this DOM Node."""
36 return ''.join([text
.nodeValue
for text
in node
.childNodes
37 if text
.nodeType
== Node
.TEXT_NODE
])
40 """An Option stores a single value. Every option is part of exactly one OptionGroup.
42 The read-only attributes value and int_value can be used to get the current setting
43 for the Option. int_value will be -1 if the value is not a valid integer.
45 The has_changed attribute is used during notify() calls to indicate whether this
46 Option's value has changed since the last notify (or option creation).
47 You may set has_changed = 1 right after creating an option if you want to force
48 notification the first time even if the default is used.
50 def __init__(self
, name
, value
, group
= None):
51 """Create a new option with this name and default value.
52 Add to 'group', or to rox.app_options if no group is given.
53 The value cannot be used until the first notify() call to
56 assert rox
.app_options
57 group
= rox
.app_options
59 self
.has_changed
= 0 # ... since last notify/default
60 self
.default_value
= str(value
)
66 self
.group
._register
(self
)
68 def _set(self
, value
):
69 if self
.value
!= value
:
70 self
.value
= str(value
)
73 if self
.value
== 'True':
75 elif self
.value
== 'False':
78 self
.int_value
= int(float(self
.value
))
82 def _to_xml(self
, parent
):
83 doc
= parent
.ownerDocument
84 node
= doc
.createElement('Option')
85 node
.setAttribute('name', self
.name
)
86 node
.appendChild(doc
.createTextNode(self
.value
))
87 parent
.appendChild(node
)
90 return "<Option %s=%s>" % (self
.name
, self
.value
)
92 class ListOption(Option
):
93 """A ListOption stores a list of values. Every option is part of exactly one OptionGroup.
95 The read-only attribute list_value can be used to get the current setting
96 for the ListOption. value will be str(list_value) and int_value wille be -1.
98 The has_changed attribute is used during notify() calls to indicate whether this
99 ListOption's value has changed since the last notify (or option creation).
100 You may set has_changed = 1 right after creating an option if you want to force
101 notification the first time even if the default is used.
103 def __init__(self
, name
, value
, group
= None):
105 rox
.options
.Option
.__init
__(self
, name
, value
, group
)
107 self
.default_value
=value
109 def _set(self
, value
):
113 rox
.options
.Option
._set
(self
, value
)
115 if hasattr(value
, 'upper'):
116 # Assume it's a string
117 rox
.options
.Option
._set
(self
, value
)
120 if self
.list_value
!=value
:
121 self
.list_value
=list(value
)
122 self
.value
=str(value
)
126 def _to_xml(self
, parent
):
127 doc
= parent
.ownerDocument
128 node
= doc
.createElement('ListOption')
129 node
.setAttribute('name', self
.name
)
131 for v
in self
.list_value
:
132 snode
=doc
.createElement('Value')
133 snode
.appendChild(doc
.createTextNode(v
))
134 node
.appendChild(snode
)
135 parent
.appendChild(node
)
138 return "<ListOption %s=%s>" % (self
.name
, self
.list_value
)
141 def __init__(self
, program
, leaf
, site
= None):
142 """program/leaf is a Choices pair for the saved options. If site
143 is given, the basedir module is used for saving choices (the new system).
144 Otherwise, the deprecated choices module is used."""
146 self
.program
= program
148 self
.pending
= {} # Loaded, but not registered
149 self
.options
= {} # Name -> Option
151 self
.too_late_for_registrations
= 0
154 path
= basedir
.load_first_config(site
, program
, leaf
)
156 path
= choices
.load(program
, leaf
)
161 doc
= minidom
.parse(path
)
163 root
= doc
.documentElement
164 assert root
.localName
== 'Options'
165 for o
in root
.childNodes
:
166 if o
.nodeType
!= Node
.ELEMENT_NODE
:
168 if o
.localName
== 'Option':
169 name
= o
.getAttribute('name')
170 self
.pending
[name
] = data(o
)
171 elif o
.localName
=='ListOption':
172 name
= o
.getAttribute('name')
174 for s
in o
.getElementsByTagName('Value'):
178 print "Warning: Non Option element", o
180 rox
.report_exception()
182 def _register(self
, option
):
183 """Called by Option.__init__."""
184 assert option
.name
not in self
.options
185 assert not self
.too_late_for_registrations
189 self
.options
[name
] = option
191 if name
in self
.pending
:
192 option
._set
(self
.pending
[name
])
193 del self
.pending
[name
]
196 """Save all option values. Usually called by OptionsBox()."""
197 assert self
.too_late_for_registrations
200 d
= basedir
.save_config_path(self
.site
, self
.program
)
201 path
= os
.path
.join(d
, self
.leaf
)
203 path
= choices
.save(self
.program
, self
.leaf
)
205 return # Saving is disabled
207 from xml
.dom
.minidom
import Document
209 root
= doc
.createElement('Options')
210 doc
.appendChild(root
)
216 stream
= open(path
, 'w')
220 def add_notify(self
, callback
):
221 "Call callback() after one or more options have changed value."
222 assert callback
not in self
.callbacks
224 self
.callbacks
.append(callback
)
226 def remove_notify(self
, callback
):
227 """Remove a callback added with add_notify()."""
228 self
.callbacks
.remove(callback
)
230 def notify(self
, warn_unused
=True):
231 """Call this after creating any new options or changing their values."""
232 if not self
.too_late_for_registrations
:
233 self
.too_late_for_registrations
= 1
234 if self
.pending
and warn_unused
:
235 print "Warning: Some options loaded but unused:"
236 for (key
, value
) in self
.pending
.iteritems():
237 print "%s=%s" % (key
, value
)
240 o
._set
(o
.default_value
)
241 map(apply, self
.callbacks
)
243 option
.has_changed
= 0
246 return self
.options
.itervalues()