Added some buttons and UI stuff. Non-functional.
[mime-editor.git] / editor.py
blob693b6579343b7eba31af6279b6109b0ec04f9ca6
1 import rox
2 from rox import g
3 import os
4 import type
6 edit_boxes = {}
8 ADD = 1
9 DELETE = 2
10 EDIT = 3
12 class Editor(rox.Dialog):
13 def __init__(self):
14 rox.Dialog.__init__(self)
15 self.set_default_size(600, 400)
16 self.set_has_separator(False)
18 self.add_type = None
20 self.add_button(g.STOCK_ADD, ADD)
21 self.add_button(g.STOCK_DELETE, DELETE)
22 self.add_button(g.STOCK_PROPERTIES, EDIT)
23 self.add_button(g.STOCK_CLOSE, g.RESPONSE_CANCEL)
25 self.set_default_response(g.RESPONSE_CANCEL)
27 swin = g.ScrolledWindow()
28 swin.set_border_width(4)
29 swin.set_policy(g.POLICY_NEVER, g.POLICY_ALWAYS)
30 swin.set_shadow_type(g.SHADOW_IN)
31 self.vbox.pack_start(swin, True, True, 0)
33 self.mime_model = g.TreeStore(str, str)
34 view = g.TreeView(self.mime_model)
35 swin.add(view)
36 view.set_search_column(1)
38 cell = g.CellRendererText()
39 column = g.TreeViewColumn('MIME-Type', cell, text = 0)
40 view.append_column(column)
41 column.set_sort_column_id(0)
43 cell = g.CellRendererText()
44 column = g.TreeViewColumn('Description', cell, text = 1)
45 view.append_column(column)
46 column.set_sort_column_id(1)
48 view.connect('row-activated', self.activate)
50 self.vbox.show_all()
52 def response(self, resp):
53 if resp == EDIT:
54 self.edit_selected(view.get_selection())
55 elif resp == DELETE:
56 self.delete_type(view)
57 elif resp == ADD:
58 if self.add_type:
59 self.add_type.present()
60 else:
61 self.add_type = NewType()
62 def destroyed(widget): self.add_type = None
63 self.add_type.connect('destroy', destroyed)
64 self.add_type.show()
65 else:
66 self.destroy()
67 self.connect('response', response)
69 def changed(selection):
70 model, iter = selection.get_selected()
71 self.set_response_sensitive(EDIT, iter != None)
72 self.set_response_sensitive(DELETE, iter != None)
73 selection = view.get_selection()
74 selection.connect('changed', changed)
75 changed(selection)
77 def delete_type(self, view):
78 model, iter = view.get_selection().get_selected()
79 if not iter:
80 rox.alert('Nothing selected')
81 return
82 type_name = model.get_value(iter, 0)
83 type.delete_type(type_name)
85 def update(self):
86 self.set_title('Scanning... please wait')
87 g.gdk.flush()
89 type.init()
91 self.mime_model.clear()
93 medias = {}
95 def items_cmp(a, b):
96 return cmp(a[1], b[1])
97 def caps(a):
98 return a[:1].upper() + a[1:]
99 items = [(t, caps(t.get_comment())) for t in type.types.values()]
100 items.sort(items_cmp)
101 for t, c in items:
102 iter = self.mime_model.append(None)
103 self.mime_model.set(iter, 1, c, 0, t.get_name())
105 self.set_title('MIME-Editor')
107 for b in edit_boxes.values():
108 if b.mime_type in type.types:
109 b.update()
110 else:
111 b.destroy()
113 def activate(self, view, path, column):
114 iter = self.mime_model.get_iter(path)
115 type_name = self.mime_model.get_value(iter, 0)
116 self.edit(type_name)
118 def edit(self, type_name):
119 if type_name in edit_boxes:
120 edit_boxes[type_name].present()
121 else:
122 box = EditBox(type_name)
123 edit_boxes[type_name] = box
124 def destroy(dialog): del edit_boxes[type_name]
125 box.connect('destroy', destroy)
126 box.show()
128 def edit_selected(self, selection):
129 model, iter = selection.get_selected()
130 if not iter:
131 rox.alert('You need to select a type to edit first')
132 else:
133 type_name = model.get_value(iter, 0)
134 self.edit(type_name)
136 class EditBox(rox.Dialog):
137 def __init__(self, type_name):
138 rox.Dialog.__init__(self)
139 self.set_has_separator(False)
140 self.set_default_size(-1, 400)
141 self.mime_type = type_name
143 self.set_title('MIME-Editor: %s' % type_name)
145 swin = g.ScrolledWindow()
146 swin.set_border_width(4)
147 swin.set_shadow_type(g.SHADOW_IN)
148 self.vbox.pack_start(swin, True, True, 0)
150 self.model = g.TreeStore(str, object)
151 view = g.TreeView(self.model)
152 swin.add(view)
154 cell = g.CellRendererText()
155 column = g.TreeViewColumn(type_name, cell, text = 0)
156 view.append_column(column)
158 swin.set_policy(g.POLICY_NEVER, g.POLICY_AUTOMATIC)
159 self.update()
161 self.vbox.show_all()
162 view.expand_all()
164 self.add_button(g.STOCK_ADD, ADD)
165 self.add_button(g.STOCK_DELETE, DELETE)
166 self.add_button(g.STOCK_PROPERTIES, EDIT)
167 self.add_button(g.STOCK_CLOSE, g.RESPONSE_CANCEL)
168 def response(w, resp):
169 if resp == ADD:
170 self.add_field(view)
171 elif resp == DELETE:
172 self.delete_field(view)
173 elif resp == EDIT:
174 self.edit_field(view)
175 else:
176 self.destroy()
177 self.connect('response', response)
179 def changed(selection):
180 model, iter = selection.get_selected()
181 on_field = False
182 if iter != None:
183 path = model.get_path(iter)
184 on_field = len(path) > 1
185 self.set_response_sensitive(ADD, iter != None)
186 self.set_response_sensitive(EDIT, on_field)
187 self.set_response_sensitive(DELETE, on_field)
188 selection = view.get_selection()
189 selection.connect('changed', changed)
190 changed(selection)
192 def activate(view, path, column):
193 iter = self.model.get_iter(path)
194 field = self.model.get_value(iter, 1)
195 if len(path) == 1:
196 self.add_new_field(field)
197 else:
198 field.edit()
199 view.connect('row-activated', activate)
201 self.set_default_response(g.RESPONSE_CANCEL)
203 def update(self):
204 t = type.get_type(self.mime_type)
205 self.model.clear()
206 for aspect, getter, klass in [('Name matching', t.get_globs, type.Glob),
207 ('Contents matching', t.get_magic, type.Magic),
208 ('XML namespace matching', t.get_xml, type.XML),
209 ('Others', t.get_others, type.Other),
210 ('Descriptions', t.get_comments, type.Comment)]:
211 iter = self.model.append(None)
212 self.model.set(iter, 0, aspect, 1, klass)
213 fields = getter()
214 fields.sort(lambda a, b: cmp(str(a), str(b)))
215 last = None
216 for field in fields:
217 if field == last: continue
218 last = field
219 f = self.model.append(iter)
220 self.model.set(f, 0, str(field), 1, field)
221 field.add_subtree(self.model, f)
223 def add_new_field(self, type):
224 rox.alert("TODO: Add field of type '%s'" % type)
226 def add_field(self, view):
227 model, iter = view.get_selection().get_selected()
228 if not iter:
229 rox.alert('You need to select a group, so I know what kind of thing to add')
230 return
231 path = model.get_path(iter)
232 field = model.get_value(model.get_iter(path[:1]), 1)
233 self.add_new_field(field)
235 def delete_field(self, view):
236 model, iter = view.get_selection().get_selected()
237 if not iter:
238 rox.alert("Nothing selected!")
239 field = model.get_value(iter, 1)
240 assert field
241 field.delete()
243 def edit_field(self, view):
244 model, iter = view.get_selection().get_selected()
245 if not iter:
246 rox.alert("Nothing selected!")
247 field = model.get_value(iter, 1)
248 assert field
249 field.edit()
251 class NewType(rox.Dialog):
252 def __init__(self):
253 rox.Dialog.__init__(self)
254 self.set_title('Add new MIME type')
256 self.add_button(g.STOCK_CANCEL, g.RESPONSE_CANCEL)
257 self.add_button(g.STOCK_ADD, g.RESPONSE_OK)
258 self.set_default_response(g.RESPONSE_OK)
260 vbox = g.VBox(False, 4)
261 self.vbox.pack_start(vbox, True, True, 0)
262 vbox.set_border_width(4)
264 hbox = g.HBox(False, 4)
265 vbox.pack_start(hbox, False, True, 0)
266 label = g.Label("Media type:")
267 hbox.pack_start(label, False, True, 0)
268 combo = g.Combo()
269 combo.set_popdown_strings(["text", "application", "image", "audio",
270 "video", "message", "model"])
271 hbox.pack_start(combo, True, True, 0)
273 hbox = g.HBox(False, 4)
274 vbox.pack_start(hbox, False, True, 0)
275 label = g.Label("Subtype:")
276 hbox.pack_start(label, False, True, 0)
277 entry = g.Entry()
278 entry.set_text('x-my-type')
279 hbox.pack_start(entry, True, True, 0)
280 entry.set_activates_default(True)
282 label = g.Label("Note: the 'text' group should only be used for types that can be "
283 "viewed in a normal text editor. For example, HTML is text/html, "
284 "but Word documents are in the 'application' group.\n"
285 "Unoffical types should start with 'x-'.")
286 label.set_line_wrap(True)
287 vbox.pack_start(label, False, True, 0)
289 self.vbox.show_all()
291 def response(w, resp):
292 if resp == g.RESPONSE_OK:
293 type_name = combo.entry.get_text() + '/' + entry.get_text()
294 if type_name.count('/') != 1 or type_name.count(' '):
295 rox.alert("Invalid MIME type name '%s'" % type_name)
296 return
297 if type_name in type.types:
298 rox.alert("Type '%s' already exists!" % type_name)
299 return
300 type.add_type(type_name)
301 self.destroy()
302 self.connect('response', response)