Use new-style classes, clean up
[alacarte.git] / Alacarte / MainWindow.py
blob7302833220630be7919a57b980e4001f68d4c930
1 # -*- coding: utf-8 -*-
2 # vim: set noexpandtab:
3 # Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
4 # Copyright (C) 2006 Travis Watkins
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Library General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Library General Public License for more details.
16 # You should have received a copy of the GNU Library General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 from gi.repository import Gtk, GObject, Gio, GdkPixbuf, Gdk, GMenu, GLib
21 import cgi, os
22 import gettext
23 import subprocess
24 import urllib
26 from Alacarte import config
27 gettext.bindtextdomain(config.GETTEXT_PACKAGE, config.localedir)
28 gettext.textdomain(config.GETTEXT_PACKAGE)
30 _ = gettext.gettext
31 from Alacarte.MenuEditor import MenuEditor
32 from Alacarte import util
34 class MainWindow(object):
35 timer = None
36 #hack to make editing menu properties work
37 allow_update = True
38 #drag-and-drop stuff
39 dnd_items = [('ALACARTE_ITEM_ROW', Gtk.TargetFlags.SAME_APP, 0), ('text/plain', 0, 1)]
40 dnd_menus = [('ALACARTE_MENU_ROW', Gtk.TargetFlags.SAME_APP, 0)]
41 dnd_both = [dnd_items[0],] + dnd_menus
42 drag_data = None
43 edit_pool = []
45 def __init__(self, datadir, version):
46 self.file_path = datadir
47 self.version = version
48 self.editor = MenuEditor()
49 Gtk.Window.set_default_icon_name('alacarte')
50 self.tree = Gtk.Builder()
51 self.tree.set_translation_domain(config.GETTEXT_PACKAGE)
52 self.tree.add_from_file(os.path.join(self.file_path, 'alacarte.ui'))
53 self.tree.connect_signals(self)
54 self.setupMenuTree()
55 self.setupItemTree()
56 self.tree.get_object('edit_delete').set_sensitive(False)
57 self.tree.get_object('edit_revert_to_original').set_sensitive(False)
58 self.tree.get_object('edit_properties').set_sensitive(False)
59 self.tree.get_object('move_up_button').set_sensitive(False)
60 self.tree.get_object('move_down_button').set_sensitive(False)
61 self.tree.get_object('new_separator_button').set_sensitive(False)
62 accelgroup = Gtk.AccelGroup()
63 keyval, modifier = Gtk.accelerator_parse('<Ctrl>Z')
64 accelgroup.connect(keyval, modifier, Gtk.AccelFlags.VISIBLE, self.on_mainwindow_undo)
65 keyval, modifier = Gtk.accelerator_parse('<Ctrl><Shift>Z')
66 accelgroup.connect(keyval, modifier, Gtk.AccelFlags.VISIBLE, self.on_mainwindow_redo)
67 keyval, modifier = Gtk.accelerator_parse('F1')
68 accelgroup.connect(keyval, modifier, Gtk.AccelFlags.VISIBLE, self.on_help_button_clicked)
69 self.tree.get_object('mainwindow').add_accel_group(accelgroup)
71 def run(self):
72 self.loadMenus()
73 self.editor.applications.tree.connect("changed", self.menuChanged)
74 self.tree.get_object('mainwindow').show_all()
75 Gtk.main()
77 def menuChanged(self, *a):
78 self.loadUpdates()
80 def loadUpdates(self):
81 self.editor.reloadMenus()
82 self.editor.applications.tree.connect("changed", self.menuChanged)
84 if not self.allow_update:
85 return False
86 menu_tree = self.tree.get_object('menu_tree')
87 item_tree = self.tree.get_object('item_tree')
88 items, iter = item_tree.get_selection().get_selected()
89 update_items = False
90 update_type = None
91 item_id = None
92 if iter:
93 update_items = True
94 if isinstance(items[iter][3], GMenu.TreeEntry):
95 item_id = items[iter][3].get_desktop_file_id()
96 update_type = GMenu.TreeItemType.ENTRY
97 elif isinstance(items[iter][3], GMenu.TreeDirectory):
98 item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
99 update_type = GMenu.TreeItemType.DIRECTORY
100 elif isinstance(items[iter][3], GMenu.Tree.Separator):
101 item_id = items.get_path(iter)
102 update_type = GMenu.TreeItemType.SEPARATOR
103 menus, iter = menu_tree.get_selection().get_selected()
104 update_menus = False
105 menu_id = None
106 if iter:
107 if menus[iter][2].get_desktop_file_path():
108 menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
109 else:
110 menu_id = menus[iter][2].get_menu_id()
111 update_menus = True
112 self.loadMenus()
113 #find current menu in new tree
114 if update_menus:
115 menu_tree.get_model().foreach(self.findMenu, menu_id)
116 menus, iter = menu_tree.get_selection().get_selected()
117 if iter:
118 self.on_menu_tree_cursor_changed(menu_tree)
119 #find current item in new list
120 if update_items:
121 i = 0
122 for item in item_tree.get_model():
123 found = False
124 if update_type != GMenu.TreeItemType.SEPARATOR:
125 if isinstance (item[3], GMenu.TreeEntry) and item[3].get_desktop_file_id() == item_id:
126 found = True
127 if isinstance (item[3], GMenu.TreeDirectory) and item[3].get_desktop_file_path() and update_type == GMenu.TreeItemType.DIRECTORY:
128 if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
129 found = True
130 if isinstance(item[3], GMenu.TreeSeparator):
131 if not isinstance(item_id, tuple):
132 #we may not skip the increment via "continue"
133 i += 1
134 continue
135 #separators have no id, have to find them manually
136 #probably won't work with two separators together
137 if (item_id[0] - 1,) == (i,):
138 found = True
139 elif (item_id[0] + 1,) == (i,):
140 found = True
141 elif (item_id[0],) == (i,):
142 found = True
143 if found:
144 item_tree.get_selection().select_path((i,))
145 self.on_item_tree_cursor_changed(item_tree)
146 break
147 i += 1
148 return False
150 def findMenu(self, menus, path, iter, menu_id):
151 if not menus[path][2].get_desktop_file_path():
152 if menu_id == menus[path][2].get_menu_id():
153 menu_tree = self.tree.get_object('menu_tree')
154 menu_tree.expand_to_path(path)
155 menu_tree.get_selection().select_path(path)
156 return True
157 return False
158 if os.path.split(menus[path][2].get_desktop_file_path())[1] == menu_id:
159 menu_tree = self.tree.get_object('menu_tree')
160 menu_tree.expand_to_path(path)
161 menu_tree.get_selection().select_path(path)
162 return True
164 def setupMenuTree(self):
165 self.menu_store = Gtk.TreeStore(GdkPixbuf.Pixbuf, str, object)
166 menus = self.tree.get_object('menu_tree')
167 column = Gtk.TreeViewColumn(_('Name'))
168 column.set_spacing(4)
169 cell = Gtk.CellRendererPixbuf()
170 column.pack_start(cell, False)
171 column.add_attribute(cell, 'pixbuf', 0)
172 cell = Gtk.CellRendererText()
173 column.pack_start(cell, True)
174 column.add_attribute(cell, 'markup', 1)
175 menus.append_column(column)
176 menus.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, self.dnd_menus, Gdk.DragAction.COPY)
177 menus.enable_model_drag_dest(self.dnd_both, Gdk.DragAction.PRIVATE)
178 menus.get_selection().set_mode(Gtk.SelectionMode.BROWSE)
180 def setupItemTree(self):
181 items = self.tree.get_object('item_tree')
182 column = Gtk.TreeViewColumn(_('Show'))
183 cell = Gtk.CellRendererToggle()
184 cell.connect('toggled', self.on_item_tree_show_toggled)
185 column.pack_start(cell, True)
186 column.add_attribute(cell, 'active', 0)
187 #hide toggle for separators
188 column.set_cell_data_func(cell, self._cell_data_toggle_func)
189 items.append_column(column)
190 column = Gtk.TreeViewColumn(_('Item'))
191 column.set_spacing(4)
192 cell = Gtk.CellRendererPixbuf()
193 column.pack_start(cell, False)
194 column.add_attribute(cell, 'pixbuf', 1)
195 cell = Gtk.CellRendererText()
196 column.pack_start(cell, True)
197 column.add_attribute(cell, 'markup', 2)
198 items.append_column(column)
199 self.item_store = Gtk.ListStore(bool, GdkPixbuf.Pixbuf, str, object)
200 items.set_model(self.item_store)
201 items.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, self.dnd_items, Gdk.DragAction.COPY)
202 items.enable_model_drag_dest(self.dnd_items, Gdk.DragAction.PRIVATE)
204 def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter, data=None):
205 if isinstance(model[treeiter][3], GMenu.TreeSeparator):
206 renderer.set_property('visible', False)
207 else:
208 renderer.set_property('visible', True)
210 def loadMenus(self):
211 self.menu_store.clear()
212 for menu in self.editor.getMenus():
213 iters = [None]*20
214 self.loadMenu(iters, menu)
215 menu_tree = self.tree.get_object('menu_tree')
216 menu_tree.set_model(self.menu_store)
217 for menu in self.menu_store:
218 menu_tree.expand_to_path(menu.path)
219 menu_tree.get_selection().select_path((0,))
220 self.on_menu_tree_cursor_changed(menu_tree)
222 def loadMenu(self, iters, parent, depth=0):
223 if depth == 0:
224 icon = util.getIcon(parent)
225 iters[depth] = self.menu_store.append(None, (icon, cgi.escape(parent.get_name()), parent))
226 depth += 1
227 for menu, show in self.editor.getMenus(parent):
228 if show:
229 name = cgi.escape(menu.get_name())
230 else:
231 name = '<small><i>' + cgi.escape(menu.get_name()) + '</i></small>'
232 icon = util.getIcon(menu)
233 iters[depth] = self.menu_store.append(iters[depth-1], (icon, name, menu))
234 self.loadMenu(iters, menu, depth)
235 depth -= 1
237 def loadItems(self, menu, menu_path):
238 self.item_store.clear()
239 for item, show in self.editor.getItems(menu):
240 menu_icon = None
241 if isinstance(item, GMenu.TreeSeparator):
242 name = '---'
243 icon = None
244 elif isinstance(item, GMenu.TreeEntry):
245 app_info = item.get_app_info()
246 if show:
247 name = cgi.escape(app_info.get_display_name())
248 else:
249 name = '<small><i>' + cgi.escape(app_info.get_display_name()) + '</i></small>'
250 icon = util.getIcon(item)
251 else:
252 if show:
253 name = cgi.escape(item.get_name())
254 else:
255 name = '<small><i>' + cgi.escape(item.get_name()) + '</i></small>'
256 icon = util.getIcon(item)
257 self.item_store.append((show, icon, name, item))
259 #this is a little timeout callback to insert new items after
260 #gnome-desktop-item-edit has finished running
261 def waitForNewItemProcess(self, process, parent_id, file_path):
262 if process.poll() != None:
263 if os.path.isfile(file_path):
264 self.editor.insertExternalItem(os.path.split(file_path)[1], parent_id)
265 return False
266 return True
268 def waitForNewMenuProcess(self, process, parent_id, file_path):
269 if process.poll() != None:
270 #hack for broken gnome-desktop-item-edit
271 broken_path = os.path.join(os.path.split(file_path)[0], '.directory')
272 if os.path.isfile(broken_path):
273 os.rename(broken_path, file_path)
274 if os.path.isfile(file_path):
275 self.editor.insertExternalMenu(os.path.split(file_path)[1], parent_id)
276 return False
277 return True
279 #this callback keeps you from editing the same item twice
280 def waitForEditProcess(self, process, file_path):
281 if process.poll() != None:
282 self.edit_pool.remove(file_path)
283 return False
284 return True
286 def on_new_menu_button_clicked(self, button):
287 menu_tree = self.tree.get_object('menu_tree')
288 menus, iter = menu_tree.get_selection().get_selected()
289 if not iter:
290 parent = menus[(0,)][2]
291 menu_tree.expand_to_path((0,))
292 menu_tree.get_selection().select_path((0,))
293 else:
294 parent = menus[iter][2]
295 file_path = os.path.join(util.getUserDirectoryPath(), util.getUniqueFileId('alacarte-made', '.directory'))
296 process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
297 GObject.timeout_add(100, self.waitForNewMenuProcess, process, parent.get_menu_id(), file_path)
299 def on_new_item_button_clicked(self, button):
300 menu_tree = self.tree.get_object('menu_tree')
301 menus, iter = menu_tree.get_selection().get_selected()
302 if not iter:
303 parent = menus[(0,)][2]
304 menu_tree.expand_to_path((0,))
305 menu_tree.get_selection().select_path((0,))
306 else:
307 parent = menus[iter][2]
308 file_path = os.path.join(util.getUserItemPath(), util.getUniqueFileId('alacarte-made', '.desktop'))
309 process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
310 GObject.timeout_add(100, self.waitForNewItemProcess, process, parent.get_menu_id(), file_path)
312 def on_new_separator_button_clicked(self, button):
313 item_tree = self.tree.get_object('item_tree')
314 items, iter = item_tree.get_selection().get_selected()
315 if not iter:
316 return
317 else:
318 after = items[iter][3]
319 menu_tree = self.tree.get_object('menu_tree')
320 menus, iter = menu_tree.get_selection().get_selected()
321 parent = menus[iter][2]
322 self.editor.createSeparator(parent, after=after)
324 def on_edit_delete_activate(self, menu):
325 item_tree = self.tree.get_object('item_tree')
326 items, iter = item_tree.get_selection().get_selected()
327 if not iter:
328 return
329 item = items[iter][3]
330 if isinstance(item, GMenu.TreeEntry):
331 self.editor.deleteItem(item)
332 elif isinstance(item, GMenu.TreeDirectory):
333 self.editor.deleteMenu(item)
334 elif isinstance(item, GMenu.TreeSeparator):
335 self.editor.deleteSeparator(item)
337 def on_edit_revert_to_original_activate(self, menu):
338 item_tree = self.tree.get_object('item_tree')
339 items, iter = item_tree.get_selection().get_selected()
340 if not iter:
341 return
342 item = items[iter][3]
343 if isinstance(item, GMenu.TreeEntry):
344 self.editor.revertItem(item)
345 elif isinstance(item, GMenu.TreeDirectory):
346 self.editor.revertMenu(item)
348 def on_edit_properties_activate(self, menu):
349 item_tree = self.tree.get_object('item_tree')
350 items, iter = item_tree.get_selection().get_selected()
351 if not iter:
352 return
353 item = items[iter][3]
354 if not isinstance(item, GMenu.TreeEntry) and not isinstance(item, GMenu.TreeDirectory):
355 return
357 if isinstance(item, GMenu.TreeEntry):
358 file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
359 file_type = 'Item'
360 elif isinstance(item, GMenu.TreeDirectory):
361 file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
362 file_type = 'Menu'
364 if not os.path.isfile(file_path):
365 data = open(item.get_desktop_file_path()).read()
366 open(file_path, 'w').write(data)
367 self.editor._MenuEditor__addUndo([(file_type, os.path.split(file_path)[1]),])
368 else:
369 self.editor._MenuEditor__addUndo([item,])
370 if file_path not in self.edit_pool:
371 self.edit_pool.append(file_path)
372 process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
373 GObject.timeout_add(100, self.waitForEditProcess, process, file_path)
375 def on_menu_tree_cursor_changed(self, treeview):
376 menus, iter = treeview.get_selection().get_selected()
377 menu_path = menus.get_path(iter)
378 item_tree = self.tree.get_object('item_tree')
379 item_tree.get_selection().unselect_all()
380 self.loadItems(self.menu_store[menu_path][2], menu_path)
381 self.tree.get_object('edit_delete').set_sensitive(False)
382 self.tree.get_object('edit_revert_to_original').set_sensitive(False)
383 self.tree.get_object('edit_properties').set_sensitive(False)
384 self.tree.get_object('move_up_button').set_sensitive(False)
385 self.tree.get_object('move_down_button').set_sensitive(False)
386 self.tree.get_object('new_separator_button').set_sensitive(False)
387 self.tree.get_object('properties_button').set_sensitive(False)
388 self.tree.get_object('delete_button').set_sensitive(False)
390 def on_menu_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
391 menus, iter = treeview.get_selection().get_selected()
392 self.drag_data = menus[iter][2]
394 def on_menu_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
395 menus = treeview.get_model()
396 drop_info = treeview.get_dest_row_at_pos(x, y)
397 types = (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.INTO_OR_BEFORE)
398 if drop_info:
399 path, position = drop_info
400 if position not in types:
401 context.finish(False, False, etime)
402 return False
403 if selection.target in ('ALACARTE_ITEM_ROW', 'ALACARTE_MENU_ROW'):
404 if self.drag_data == None:
405 return False
406 item = self.drag_data
407 new_parent = menus[path][2]
408 treeview.get_selection().select_path(path)
409 if isinstance(item, GMenu.TreeEntry):
410 self.editor.copyItem(item, new_parent)
411 elif isinstance(item, GMenu.TreeDirectory):
412 if self.editor.moveMenu(item, new_parent) == False:
413 self.loadUpdates()
414 elif isinstance(item, GMenu.TreeSeparator):
415 self.editor.moveSeparator(item, new_parent)
416 else:
417 context.finish(False, False, etime)
418 context.finish(True, True, etime)
419 self.drag_data = None
421 def on_item_tree_show_toggled(self, cell, path):
422 item = self.item_store[path][3]
423 if isinstance(item, GMenu.TreeSeparator):
424 return
425 if self.item_store[path][0]:
426 self.editor.setVisible(item, False)
427 else:
428 self.editor.setVisible(item, True)
429 self.item_store[path][0] = not self.item_store[path][0]
431 def on_item_tree_cursor_changed(self, treeview):
432 items, iter = treeview.get_selection().get_selected()
433 if iter is None:
434 return
435 item = items[iter][3]
436 self.tree.get_object('edit_delete').set_sensitive(True)
437 self.tree.get_object('new_separator_button').set_sensitive(True)
438 self.tree.get_object('delete_button').set_sensitive(True)
439 if self.editor.canRevert(item):
440 self.tree.get_object('edit_revert_to_original').set_sensitive(True)
441 else:
442 self.tree.get_object('edit_revert_to_original').set_sensitive(False)
443 if not isinstance(item, GMenu.TreeSeparator):
444 self.tree.get_object('edit_properties').set_sensitive(True)
445 self.tree.get_object('properties_button').set_sensitive(True)
446 else:
447 self.tree.get_object('edit_properties').set_sensitive(False)
448 self.tree.get_object('properties_button').set_sensitive(False)
450 # If first item...
451 if items.get_path(iter).get_indices()[0] == 0:
452 self.tree.get_object('move_up_button').set_sensitive(False)
453 else:
454 self.tree.get_object('move_up_button').set_sensitive(True)
456 # If last item...
457 if items.get_path(iter).get_indices()[0] == (len(items)-1):
458 self.tree.get_object('move_down_button').set_sensitive(False)
459 else:
460 self.tree.get_object('move_down_button').set_sensitive(True)
462 def on_item_tree_row_activated(self, treeview, path, column):
463 self.on_edit_properties_activate(None)
465 def on_item_tree_popup_menu(self, item_tree, event=None):
466 model, iter = item_tree.get_selection().get_selected()
467 if event:
468 #don't show if it's not the right mouse button
469 if event.button != 3:
470 return
471 button = event.button
472 event_time = event.time
473 info = item_tree.get_path_at_pos(int(event.x), int(event.y))
474 if info != None:
475 path, col, cellx, celly = info
476 item_tree.grab_focus()
477 item_tree.set_cursor(path, col, 0)
478 else:
479 path = model.get_path(iter)
480 button = 0
481 event_time = 0
482 item_tree.grab_focus()
483 item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
484 popup = self.tree.get_object('edit_menu')
485 popup.popup(None, None, None, None, button, event_time)
486 #without this shift-f10 won't work
487 return True
489 def on_item_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
490 items, iter = treeview.get_selection().get_selected()
491 self.drag_data = items[iter][3]
493 def on_item_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
494 items = treeview.get_model()
495 types_into = (Gtk.TreeViewDropPosition.INTO_OR_BEFORE, Gtk.TreeViewDropPosition.INTO_OR_AFTER)
496 types_before = (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.INTO_OR_BEFORE)
497 types_after = (Gtk.TreeViewDropPosition.AFTER, Gtk.TreeViewDropPosition.INTO_OR_AFTER)
498 if selection.target == 'ALACARTE_ITEM_ROW':
499 drop_info = treeview.get_dest_row_at_pos(x, y)
500 before = None
501 after = None
502 if self.drag_data == None:
503 return False
504 item = self.drag_data
505 # by default we assume, that the items stays in the same menu
506 destination = item.get_parent()
507 if drop_info:
508 path, position = drop_info
509 target = items[path][3]
510 # move the item to the directory, if the item was dropped into it
511 if isinstance(target, GMenu.TreeDirectory) and (position in types_into):
512 # append the selected item to the choosen menu
513 destination = target
514 elif position in types_before:
515 before = target
516 elif position in types_after:
517 after = target
518 else:
519 # this does not happen
520 pass
521 else:
522 path = (len(items) - 1,)
523 after = items[path][3]
524 if isinstance(item, GMenu.TreeEntry):
525 self.editor.moveItem(item, destination, before, after)
526 elif isinstance(item, GMenu.TreeDirectory):
527 if self.editor.moveMenu(item, destination, before, after) == False:
528 self.loadUpdates()
529 elif isinstance(item, GMenu.TreeSeparator):
530 self.editor.moveSeparator(item, destination, before, after)
531 context.finish(True, True, etime)
532 elif selection.target == 'text/plain':
533 if selection.data == None:
534 return False
535 menus, iter = self.tree.get_object('menu_tree').get_selection().get_selected()
536 parent = menus[iter][2]
537 drop_info = treeview.get_dest_row_at_pos(x, y)
538 before = None
539 after = None
540 if drop_info:
541 path, position = drop_info
542 if position in types_before:
543 before = items[path][3]
544 else:
545 after = items[path][3]
546 else:
547 path = (len(items) - 1,)
548 after = items[path][3]
549 file_path = urllib.unquote(selection.data).strip()
550 if not file_path.startswith('file:'):
551 return
552 myfile = Gio.File(uri=file_path)
553 file_info = myfile.query_info(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)
554 content_type = file_info.get_content_type()
555 if content_type == 'application/x-desktop':
556 input_stream = myfile.read()
557 keyfile = GLib.KeyFile()
558 keyfile.load_from_data(input_stream.read())
559 self.editor.createItem(parent, before, after, KeyFile=keyfile)
560 elif content_type in ('application/x-shellscript', 'application/x-executable'):
561 self.editor.createItem(parent, before, after,
562 Name=os.path.split(file_path)[1].strip(),
563 Exec=file_path.replace('file://', '').strip(),
564 Terminal=False)
565 self.drag_data = None
567 def on_item_tree_key_press_event(self, item_tree, event):
568 if event.keyval == Gdk.KEY_Delete:
569 self.on_edit_delete_activate(item_tree)
571 def on_move_up_button_clicked(self, button):
572 item_tree = self.tree.get_object('item_tree')
573 items, iter = item_tree.get_selection().get_selected()
574 if not iter:
575 return
576 path = items.get_path(iter)
577 #at top, can't move up
578 if path.get_indices()[0] == 0:
579 return
580 item = items[path][3]
581 before = items[(path.get_indices()[0] - 1,)][3]
582 if isinstance(item, GMenu.TreeEntry):
583 self.editor.moveItem(item, item.get_parent(), before=before)
584 elif isinstance(item, GMenu.TreeDirectory):
585 self.editor.moveMenu(item, item.get_parent(), before=before)
586 elif isinstance(item, GMenu.TreeSeparator):
587 self.editor.moveSeparator(item, item.get_parent(), before=before)
589 def on_move_down_button_clicked(self, button):
590 item_tree = self.tree.get_object('item_tree')
591 items, iter = item_tree.get_selection().get_selected()
592 if not iter:
593 return
594 path = items.get_path(iter)
595 #at bottom, can't move down
596 if path.get_indices()[0] == (len(items) - 1):
597 return
598 item = items[path][3]
599 after = items[path][3]
600 if isinstance(item, GMenu.TreeEntry):
601 self.editor.moveItem(item, item.get_parent(), after=after)
602 elif isinstance(item, GMenu.TreeDirectory):
603 self.editor.moveMenu(item, item.get_parent(), after=after)
604 elif isinstance(item, GMenu.TreeSeparator):
605 self.editor.moveSeparator(item, item.get_parent(), after=after)
607 def on_mainwindow_undo(self, accelgroup, window, keyval, modifier):
608 self.editor.undo()
610 def on_mainwindow_redo(self, accelgroup, window, keyval, modifier):
611 self.editor.redo()
613 def on_help_button_clicked(self, *args):
614 Gtk.show_uri(Gdk.Screen.get_default(), "ghelp:user-guide#menu-editor", Gtk.get_current_event_time())
616 def on_revert_button_clicked(self, button):
617 dialog = self.tree.get_object('revertdialog')
618 dialog.set_transient_for(self.tree.get_object('mainwindow'))
619 dialog.show_all()
620 if dialog.run() == Gtk.ResponseType.YES:
621 self.editor.revert()
622 dialog.hide()
624 def on_close_button_clicked(self, button):
625 self.quit()
627 def on_properties_button_clicked(self, button):
628 self.on_edit_properties_activate(None)
629 def on_delete_button_clicked(self, button):
630 self.on_edit_delete_activate(None)
632 def on_style_set(self, *args):
633 self.loadUpdates()
635 def quit(self):
636 self.editor.quit()
637 Gtk.main_quit()