13 class Editor(rox
.Dialog
):
15 rox
.Dialog
.__init
__(self
)
16 self
.set_default_size(600, 400)
17 self
.set_has_separator(False)
21 self
.add_button(g
.STOCK_ADD
, ADD
)
22 self
.add_button(g
.STOCK_DELETE
, DELETE
)
23 self
.add_button(g
.STOCK_PROPERTIES
, EDIT
)
24 self
.add_button(g
.STOCK_CLOSE
, g
.RESPONSE_CANCEL
)
26 self
.set_default_response(g
.RESPONSE_CANCEL
)
28 swin
= g
.ScrolledWindow()
29 swin
.set_border_width(4)
30 swin
.set_policy(g
.POLICY_NEVER
, g
.POLICY_ALWAYS
)
31 swin
.set_shadow_type(g
.SHADOW_IN
)
32 self
.vbox
.pack_start(swin
, True, True, 0)
34 self
.mime_model
= g
.TreeStore(str, str)
35 view
= g
.TreeView(self
.mime_model
)
38 view
.set_search_column(1)
40 cell
= g
.CellRendererText()
41 column
= g
.TreeViewColumn('MIME-Type', cell
, text
= 0)
42 view
.append_column(column
)
43 column
.set_sort_column_id(0)
45 cell
= g
.CellRendererText()
46 column
= g
.TreeViewColumn('Description', cell
, text
= 1)
47 view
.append_column(column
)
48 column
.set_sort_column_id(1)
50 view
.connect('row-activated', self
.activate
)
54 def response(self
, resp
):
56 self
.edit_selected(view
.get_selection())
58 self
.delete_type(view
)
61 self
.add_type
.present()
63 self
.add_type
= NewType()
64 def destroyed(widget
): self
.add_type
= None
65 self
.add_type
.connect('destroy', destroyed
)
69 self
.connect('response', response
)
71 def changed(selection
):
72 model
, iter = selection
.get_selected()
73 self
.set_response_sensitive(EDIT
, iter != None)
74 self
.set_response_sensitive(DELETE
, iter != None)
75 selection
= view
.get_selection()
76 selection
.connect('changed', changed
)
79 def delete_type(self
, view
):
80 model
, iter = view
.get_selection().get_selected()
82 rox
.alert('Nothing selected')
84 type_name
= model
.get_value(iter, 0)
85 type.delete_type(type_name
)
88 self
.set_title('Scanning... please wait')
93 self
.mime_model
.clear()
98 return cmp(a
[1], b
[1])
100 return a
[:1].upper() + a
[1:]
101 items
= [(t
, caps(t
.get_comment())) for t
in type.types
.values()]
102 items
.sort(items_cmp
)
104 iter = self
.mime_model
.append(None)
105 self
.mime_model
.set(iter, 1, c
, 0, t
.get_name())
107 self
.set_title('MIME-Editor')
109 for b
in edit_boxes
.values():
110 if b
.mime_type
in type.types
:
115 def activate(self
, view
, path
, column
):
116 iter = self
.mime_model
.get_iter(path
)
117 type_name
= self
.mime_model
.get_value(iter, 0)
120 def edit(self
, type_name
):
121 if type_name
in edit_boxes
:
122 edit_boxes
[type_name
].present()
124 box
= EditBox(type_name
)
125 edit_boxes
[type_name
] = box
126 def destroy(dialog
): del edit_boxes
[type_name
]
127 box
.connect('destroy', destroy
)
130 def edit_selected(self
, selection
):
131 model
, iter = selection
.get_selected()
133 rox
.alert('You need to select a type to edit first')
135 type_name
= model
.get_value(iter, 0)
138 def show_type(self
, type_name
):
139 model
= self
.mime_model
140 iter = model
.get_iter_first()
142 name
= model
.get_value(iter, 0)
143 if name
== type_name
:
144 path
= model
.get_path(iter)
145 self
.view
.set_cursor(path
, None, False)
147 iter = model
.iter_next(iter)
149 class EditBox(rox
.Dialog
):
150 def __init__(self
, type_name
):
151 rox
.Dialog
.__init
__(self
)
152 self
.set_has_separator(False)
153 self
.set_default_size(-1, 400)
154 self
.mime_type
= type_name
156 self
.set_title('MIME-Editor: %s' % type_name
)
158 swin
= g
.ScrolledWindow()
159 swin
.set_border_width(4)
160 swin
.set_shadow_type(g
.SHADOW_IN
)
161 self
.vbox
.pack_start(swin
, True, True, 0)
163 self
.model
= g
.TreeStore(str, object, g
.gdk
.Color
)
164 view
= g
.TreeView(self
.model
)
168 cell
= g
.CellRendererText()
169 column
= g
.TreeViewColumn(type_name
, cell
, text
= 0, foreground_gdk
= 2)
170 view
.append_column(column
)
172 swin
.set_policy(g
.POLICY_NEVER
, g
.POLICY_AUTOMATIC
)
175 self
.add_button(g
.STOCK_ADD
, ADD
)
176 self
.add_button(g
.STOCK_DELETE
, DELETE
)
177 self
.add_button(g
.STOCK_PROPERTIES
, EDIT
)
178 self
.add_button(g
.STOCK_CLOSE
, g
.RESPONSE_CANCEL
)
179 def response(w
, resp
):
183 self
.delete_field(view
)
185 self
.edit_field(view
)
188 self
.connect('response', response
)
190 def changed(selection
):
191 model
, iter = selection
.get_selected()
194 path
= model
.get_path(iter)
195 on_field
= len(path
) > 1
196 self
.set_response_sensitive(ADD
, iter != None)
197 self
.set_response_sensitive(EDIT
, on_field
)
198 self
.set_response_sensitive(DELETE
, on_field
)
199 selection
= view
.get_selection()
200 selection
.connect('changed', changed
)
201 def may_change(path
):
202 "Prevent selecting greyed-out lines"
203 iter = self
.model
.get_iter(path
)
204 if self
.model
.get_value(iter, 2):
207 selection
.set_select_function(may_change
)
210 def activate(view
, path
, column
):
211 iter = self
.model
.get_iter(path
)
212 if self
.model
.get_value(iter, 2):
214 field
= self
.model
.get_value(iter, 1)
216 self
.add_new_field(field
)
219 view
.connect('row-activated', activate
)
221 self
.set_default_response(g
.RESPONSE_CANCEL
)
223 label
= g
.Label("Shaded entries are provided by system packages and cannot "
224 "be edited or deleted. However, any information you add will "
225 "take precedence over them.")
226 label
.set_line_wrap(True)
227 self
.vbox
.pack_start(label
, False, True, 0)
232 grey
= self
.get_style().fg
[g
.STATE_INSENSITIVE
]
233 def build(parent
, fields
):
234 fields
.sort(lambda a
, b
: cmp(str(a
), str(b
)))
236 iter = self
.model
.append(parent
)
238 self
.model
.set(iter, 0, str(field
), 1, field
)
240 self
.model
.set(iter, 0, str(field
), 1, field
, 2, grey
)
241 build(iter, field
.get_sub_fields())
242 t
= type.get_type(self
.mime_type
)
244 for aspect
, getter
, klass
in [('Name matching', t
.get_globs
, fields
.Glob
),
245 ('Contents matching', t
.get_magic
, fields
.Magic
),
246 ('XML namespace matching', t
.get_xml
, fields
.XML
),
247 ('Others', t
.get_others
, None),
248 ('Descriptions', t
.get_comments
, fields
.Comment
)]:
249 iter = self
.model
.append(None)
251 self
.model
.set(iter, 0, aspect
, 1, klass
)
253 self
.model
.set(iter, 0, aspect
, 1, klass
, 2, grey
)
254 build(iter, getter())
255 self
.view
.expand_all()
257 def add_new_field(self
, klass
):
259 new
= klass(type.get_type(self
.mime_type
))
262 def add_field(self
, view
):
263 model
, iter = view
.get_selection().get_selected()
265 rox
.alert('You need to select a group, so I know what kind of thing to add')
267 path
= model
.get_path(iter)
268 field
= model
.get_value(model
.get_iter(path
), 1)
269 if isinstance(field
, fields
.Field
) and hasattr(field
, 'add_sub_field'):
270 field
.add_sub_field() # For magic
272 field
= model
.get_value(model
.get_iter(path
[:1]), 1)
273 self
.add_new_field(field
)
275 def delete_field(self
, view
):
276 model
, iter = view
.get_selection().get_selected()
278 rox
.alert("Nothing selected!")
279 field
= model
.get_value(iter, 1)
283 def edit_field(self
, view
):
284 model
, iter = view
.get_selection().get_selected()
286 rox
.alert("Nothing selected!")
287 field
= model
.get_value(iter, 1)
291 class NewType(rox
.Dialog
):
293 rox
.Dialog
.__init
__(self
)
294 self
.set_title('Add new MIME type')
296 self
.add_button(g
.STOCK_CANCEL
, g
.RESPONSE_CANCEL
)
297 self
.add_button(g
.STOCK_ADD
, g
.RESPONSE_OK
)
298 self
.set_default_response(g
.RESPONSE_OK
)
300 vbox
= g
.VBox(False, 4)
301 self
.vbox
.pack_start(vbox
, True, True, 0)
302 vbox
.set_border_width(4)
304 hbox
= g
.HBox(False, 4)
305 vbox
.pack_start(hbox
, False, True, 0)
306 label
= g
.Label("Media type:")
307 hbox
.pack_start(label
, False, True, 0)
309 combo
.set_popdown_strings(["text", "application", "image", "audio",
310 "video", "message", "model"])
311 hbox
.pack_start(combo
, True, True, 0)
313 hbox
= g
.HBox(False, 4)
314 vbox
.pack_start(hbox
, False, True, 0)
315 label
= g
.Label("Subtype:")
316 hbox
.pack_start(label
, False, True, 0)
318 entry
.set_text('x-my-type')
319 hbox
.pack_start(entry
, True, True, 0)
320 entry
.set_activates_default(True)
322 label
= g
.Label("Note: the 'text' group should only be used for types that can be "
323 "viewed in a normal text editor. For example, HTML is text/html, "
324 "but Word documents are in the 'application' group.\n"
325 "Unoffical types should start with 'x-'.")
326 label
.set_line_wrap(True)
327 vbox
.pack_start(label
, False, True, 0)
331 def response(w
, resp
):
332 if resp
== g
.RESPONSE_OK
:
333 type_name
= combo
.entry
.get_text() + '/' + entry
.get_text()
334 if type_name
.count('/') != 1 or type_name
.count(' '):
335 rox
.alert("Invalid MIME type name '%s'" % type_name
)
337 if type_name
in type.types
:
338 rox
.alert("Type '%s' already exists!" % type_name
)
340 __main__
.box
.show_type(type_name
)
342 type.add_type(type_name
)
344 self
.connect('response', response
)