3 from xml
.dom
import XML_NAMESPACE
, Node
6 from override
import FREE_NS
8 class Invalid(Exception):
11 def pair(vbox
, label
, widget
):
12 hbox
= g
.HBox(False, 0)
13 vbox
.pack_start(hbox
, False, True, 0)
14 hbox
.pack_start(g
.Label(label
+ ': '), False, True, 0)
15 hbox
.pack_start(widget
, True, True, 0)
17 match_types
= ['string', 'byte', 'big16', 'big32', 'little16', 'little32', 'host16', 'host32']
20 "MIME_Type.get_* functions return a list of these."
21 def __init__(self
, type, item
= None):
24 self
.item
= self
.get_blank_item()
34 assert self
.user
in (True, False)
39 def get_blank_item(self
):
40 raise Exception("Can't create fields of this type yet")
43 return "<%s>" % self
.item
45 def get_sub_fields(self
):
48 def add_subtree(self
, model
, iter, grey
):
55 "Returns True on success."
56 if not hasattr(self
, 'add_edit_widgets'):
57 rox
.alert('Sorry, MIME-Editor does not support editing fields of this type')
61 box
.set_has_separator(False)
62 vbox
= g
.VBox(False, 4)
63 vbox
.set_border_width(4)
64 box
.vbox
.pack_start(vbox
, True, True, 0)
65 self
.add_edit_widgets(vbox
)
66 box
.add_button(g
.STOCK_CANCEL
, g
.RESPONSE_CANCEL
)
67 box
.add_button(g
.STOCK_OK
, g
.RESPONSE_OK
)
68 box
.set_default_response(g
.RESPONSE_OK
)
73 if resp
== g
.RESPONSE_OK
:
82 rox
.report_exception()
86 def delete_from_node(self
, type_node
):
87 raise Invalid("TODO: Can't delete/edit fields of this type yet")
89 def add_to_node(self
, node
):
90 raise Invalid("TODO: Can't add/edit fields of this type yet")
94 doc
, node
= override
.get_override_type(self
.type.get_name())
95 self
.delete_from_node(node
)
96 override
.write_override(doc
)
98 def commit_edit(self
, box
):
99 doc
, node
= override
.get_override_type(self
.type.get_name())
101 self
.delete_from_node(node
)
102 self
.add_to_node(node
)
103 override
.write_override(doc
)
105 class Comment(Field
):
106 def get_blank_item(self
):
107 return (None, 'Unknown format')
110 lang
, data
= self
.item
112 lang
= '[' + lang
+ '] '
117 def add_edit_widgets(self
, vbox
):
119 g
.Label("Enter a brief description of the type, eg 'HTML Page'.\n"
120 "Leave the language blank unless this is a translation, in \n"
121 "which case enter the country code (eg 'fr')."),
124 self
.lang
= g
.Entry()
125 self
.lang
.set_text(self
.item
[0] or '')
126 self
.lang
.set_activates_default(True)
127 pair(vbox
, 'Language', self
.lang
)
129 self
.entry
= g
.Entry()
130 self
.entry
.set_text(self
.item
[1])
131 self
.entry
.grab_focus()
132 self
.entry
.set_activates_default(True)
133 pair(vbox
, 'Description', self
.entry
)
135 def delete_from_node(self
, node
):
136 lang
= self
.item
[0] or ''
137 for x
in node
.childNodes
:
138 if x
.nodeType
!= Node
.ELEMENT_NODE
: continue
139 if x
.localName
== 'comment' and x
.namespaceURI
== FREE_NS
:
140 if (x
.getAttributeNS(XML_NAMESPACE
, 'lang') or '') == lang
and \
141 data(x
) == self
.item
[1]:
142 x
.parentNode
.removeChild(x
)
145 raise Exception("Can't find this comment in Override.xml!")
147 def add_to_node(self
, node
):
148 new_lang
= self
.lang
.get_text()
149 new
= self
.entry
.get_text()
151 raise Invalid("Comment can't be empty")
152 comment
= node
.ownerDocument
.createElementNS(FREE_NS
, 'comment')
154 comment
.setAttributeNS(XML_NAMESPACE
, 'xml:lang', new_lang
)
155 data
= node
.ownerDocument
.createTextNode(new
)
156 comment
.appendChild(data
)
157 node
.appendChild(comment
)
160 def get_blank_item(self
):
164 return "Match '%s'" % self
.item
166 def add_edit_widgets(self
, vbox
):
168 g
.Label("Enter a glob pattern which matches files of this type.\n"
169 "Special characters are:\n"
170 "? - any one character\n"
171 "* - zero or more characters\n"
172 "[abc] - any character between the brackets\n"
173 "Example: '*.html' matches all files ending in '.html'"),
175 self
.entry
= g
.Entry()
176 self
.entry
.set_text(self
.item
)
177 vbox
.pack_start(self
.entry
, False, True, 0)
178 self
.entry
.set_activates_default(True)
180 def delete_from_node(self
, node
):
181 for x
in node
.childNodes
:
182 if x
.nodeType
!= Node
.ELEMENT_NODE
: continue
183 if x
.localName
== 'glob' and x
.namespaceURI
== FREE_NS
:
184 if x
.getAttributeNS(None, 'pattern') == self
.item
:
185 x
.parentNode
.removeChild(x
)
188 raise Exception("Can't find this pattern in Override.xml!")
190 def add_to_node(self
, node
):
191 new
= self
.entry
.get_text()
193 raise Invalid("Pattern can't be empty")
194 glob
= node
.ownerDocument
.createElementNS(FREE_NS
, 'glob')
195 glob
.setAttributeNS(None, 'pattern', new
)
196 node
.appendChild(glob
)
199 def __init__(self
, type, item
= None):
201 prio
, match
, user
= item
202 if prio
is None or prio
is '':
206 item
= (int(prio
), match
, user
)
207 Field
.__init
__(self
, type, item
)
208 self
.match
= Match(self
.type, (self
, self
.item
[1], self
.item
[1].user
))
210 def get_blank_item(self
):
211 return (50, type.Match(None, True))
214 prio
, match
= self
.item
215 return "Match with priority %d" % prio
217 def add_sub_field(self
):
218 self
.match
.add_sub_field()
220 def get_sub_fields(self
):
221 return self
.match
.get_sub_fields()
223 def add_edit_widgets(self
, vbox
):
225 g
.Label("The priority is from 0 (low) to 100 (high).\n"
226 "High priority matches take precedence over low ones."),
229 self
.adj
= g
.Adjustment(prio
, lower
= 0, upper
= 100, step_incr
= 1)
230 spinner
= g
.SpinButton(self
.adj
, 1, 0)
231 vbox
.pack_start(spinner
, False, True, 0)
232 spinner
.set_activates_default(True)
234 def add_to_node(self
, node
, child_edit
= False):
235 prio
, match
= self
.item
240 new
= int(self
.adj
.value
)
242 magic_node
= node
.ownerDocument
.createElementNS(FREE_NS
, 'magic')
244 magic_node
.setAttributeNS(None, 'priority', str(new
))
245 node
.appendChild(magic_node
)
246 match
.write_xml(magic_node
)
248 def equals_node(self
, node
):
249 prio
, match
= self
.item
250 node_prio
= node
.getAttributeNS(None, 'priority')
251 if node_prio
is None or node_prio
is '':
254 node_prio
= int(node_prio
)
255 if node_prio
!= prio
:
257 return match
.equals_node(node
)
259 def delete_from_node(self
, node
):
260 for x
in node
.childNodes
:
261 if x
.nodeType
!= Node
.ELEMENT_NODE
: continue
262 if x
.localName
== 'magic' and x
.namespaceURI
== FREE_NS
:
263 if self
.equals_node(x
):
264 x
.parentNode
.removeChild(x
)
267 raise Exception("Can't find this magic in Override.xml!")
270 # Note, this is a different class to type.Match!
271 def get_blank_item(self
):
272 match
= type.Match(None, True)
273 match
.type = 'string'
279 def add_sub_field(self
):
280 new
= Match(self
.type)
281 new
.item
[0] = self
.item
[0]
282 new
.item
[1].parent
= self
.item
[1]
285 def get_sub_fields(self
):
286 magic
, match
= self
.item
287 return [Match(self
.type, (magic
, m
, m
.user
)) for m
in match
.matches
]
289 def add_edit_widgets(self
, vbox
):
290 magic
, match
= self
.item
293 g
.Label("Offset is the position in the file to check at. It can be a\n"
294 "single number, or a range in the form 'first:last'\n"),
298 for t
in match_types
:
301 self
.match_type
= g
.OptionMenu()
302 self
.match_type
.set_menu(menu
)
303 self
.match_type
.set_history(match_types
.index(match
.type))
304 pair(vbox
, 'Type', self
.match_type
)
306 self
.offset
= g
.Entry()
307 pair(vbox
, 'Offset(s)', self
.offset
)
308 self
.offset
.set_activates_default(True)
309 self
.offset
.set_text(match
.offset
)
310 self
.offset
.grab_focus()
312 self
.value
= g
.Entry()
313 pair(vbox
, 'Value', self
.value
)
314 self
.value
.set_text(match
.value
)
315 self
.value
.set_activates_default(True)
317 self
.mask
= g
.Entry()
318 pair(vbox
, 'Mask', self
.mask
)
319 self
.mask
.set_text(match
.mask
or '')
320 self
.mask
.set_activates_default(True)
322 def delete_from_node(self
, node
):
323 magic
, match
= self
.item
326 magic
.delete_from_node(node
)
328 match
.parent
.matches
.remove(match
)
330 magic
.add_to_node(node
, child_edit
= True)
332 def commit_edit(self
, box
):
333 magic
, match
= self
.item
335 offset
= self
.offset
.get_text()
336 value
= self
.value
.get_text()
338 if not offset
or not value
:
339 raise Invalid('Missing offset or value')
341 doc
, node
= override
.get_override_type(self
.type.get_name())
342 magic
.delete_from_node(node
)
344 match
.type = match_types
[self
.match_type
.get_history()]
345 match
.offset
= offset
347 match
.mask
= self
.mask
.get_text() or None
349 if match
not in match
.parent
.matches
:
350 match
.parent
.matches
.append(match
)
352 magic
.add_to_node(node
, child_edit
= True)
353 override
.write_override(doc
)
357 text
= '%s at %s = %s' % (m
.type, m
.offset
, m
.value
)
359 text
+= ' masked with ' + m
.mask
363 def get_blank_item(self
):
364 return ('http://example.com', 'documentElement')
367 return "<%s> with namespace '%s'" % (self
.item
[1], self
.item
[0])
369 def add_edit_widgets(self
, vbox
):
371 g
.Label("Enter the namespace URI and element name of the root element."),
375 self
.ns
.set_text(self
.item
[0])
376 self
.ns
.set_activates_default(True)
377 pair(vbox
, 'Namespace', self
.ns
)
379 self
.entry
= g
.Entry()
380 self
.entry
.set_text(self
.item
[1])
381 self
.entry
.set_activates_default(True)
382 pair(vbox
, 'Local name', self
.entry
)
384 def delete_from_node(self
, node
):
386 localName
= self
.item
[1]
387 for x
in node
.childNodes
:
388 if x
.nodeType
!= Node
.ELEMENT_NODE
: continue
389 if x
.localName
== 'root-XML' and x
.namespaceURI
== FREE_NS
:
390 if (x
.getAttributeNS(None, 'namespaceURI') == ns
and \
391 x
.getAttributeNS(None, 'localName') == localName
):
392 x
.parentNode
.removeChild(x
)
395 raise Exception("Can't find this root-XML in Override.xml!")
397 def add_to_node(self
, node
):
398 new_ns
= self
.ns
.get_text()
399 new
= self
.entry
.get_text()
400 if (not new
) and (not new_ns
):
401 raise Invalid("Name and namespace can't both be empty")
402 if ' ' in new
or ' ' in new_ns
:
403 raise Invalid("Name and namespace can't contain spaces")
404 xmlroot
= node
.ownerDocument
.createElementNS(FREE_NS
, 'root-XML')
405 xmlroot
.setAttributeNS(None, 'namespaceURI', new_ns
)
406 xmlroot
.setAttributeNS(None, 'localName', new
)
407 node
.appendChild(xmlroot
)
410 def can_edit(self
): return False