home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / Alacarte / MainWindow.py < prev    next >
Encoding:
Python Source  |  2006-07-25  |  19.6 KB  |  540 lines

  1. # -*- coding: utf-8 -*-
  2. #   Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
  3. #   Copyright (C) 2006  Travis Watkins
  4. #
  5. #   This library is free software; you can redistribute it and/or
  6. #   modify it under the terms of the GNU Library General Public
  7. #   License as published by the Free Software Foundation; either
  8. #   version 2 of the License, or (at your option) any later version.
  9. #
  10. #   This library is distributed in the hope that it will be useful,
  11. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. #   Library General Public License for more details.
  14. #
  15. #   You should have received a copy of the GNU Library General Public
  16. #   License along with this library; if not, write to the Free Software
  17. #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19. import gtk, gtk.glade, gmenu, gobject, gnomevfs, gnome.ui
  20. import cgi, os
  21. import gettext
  22. gettext.bindtextdomain('alacarte')
  23. gettext.textdomain('alacarte')
  24. gtk.glade.bindtextdomain('alacarte')
  25. gtk.glade.textdomain('alacarte')
  26. _ = gettext.gettext
  27. from Alacarte.MenuEditor import MenuEditor
  28. from Alacarte.DialogHandler import DialogHandler
  29. from Alacarte import util
  30. import time
  31.  
  32. class MainWindow:
  33.     timer = None
  34.     #hack to make editing menu properties work
  35.     allow_update = True
  36.     #drag-and-drop stuff
  37.     dnd_items = [('ALACARTE_ITEM_ROW', gtk.TARGET_SAME_APP, 0), ('text/plain', 0, 1)]
  38.     dnd_menus = [('ALACARTE_MENU_ROW', gtk.TARGET_SAME_APP, 0)]
  39.     dnd_both = [dnd_items[0],] + dnd_menus
  40.     drag_data = None
  41.  
  42.     def __init__(self, datadir, version, argv):
  43.         self.file_path = datadir
  44.         self.version = version
  45.         self.editor = MenuEditor()
  46.         gtk.window_set_default_icon_name('alacarte')
  47.         self.tree = gtk.glade.XML(os.path.join(self.file_path, 'alacarte.glade'))
  48.         signals = {}
  49.         for attr in dir(self):
  50.             signals[attr] = getattr(self, attr)
  51.         self.tree.signal_autoconnect(signals)
  52.         self.setupMenuTree()
  53.         self.setupItemTree()
  54.         self.dialogs = DialogHandler(self.tree.get_widget('mainwindow'), self.editor, self.file_path)
  55.         self.tree.get_widget('edit_delete').set_sensitive(False)
  56.         self.tree.get_widget('edit_revert_to_original').set_sensitive(False)
  57.         self.tree.get_widget('edit_properties').set_sensitive(False)
  58.         self.tree.get_widget('move_up_button').set_sensitive(False)
  59.         self.tree.get_widget('move_down_button').set_sensitive(False)
  60.         accelgroup = gtk.AccelGroup()
  61.         keyval, modifier = gtk.accelerator_parse('<Ctrl>Z')
  62.         accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_undo)
  63.         keyval, modifier = gtk.accelerator_parse('<Ctrl><Shift>Z')
  64.         accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_redo)
  65.         self.tree.get_widget('mainwindow').add_accel_group(accelgroup)
  66.         gnome.ui.authentication_manager_init()
  67.  
  68.     def run(self):
  69.         self.loadMenus()
  70.         self.editor.applications.tree.add_monitor(self.menuChanged)
  71.         self.editor.settings.tree.add_monitor(self.menuChanged)
  72.         self.tree.get_widget('mainwindow').show_all()
  73.         gtk.main()
  74.  
  75.     def menuChanged(self, *a):
  76.         if self.timer:
  77.             gobject.source_remove(self.timer)
  78.             self.timer = None
  79.         self.timer = gobject.timeout_add(3, self.loadUpdates)
  80.  
  81.     def loadUpdates(self):
  82.         if not self.allow_update:
  83.             return False
  84.         menu_tree = self.tree.get_widget('menu_tree')
  85.         item_tree = self.tree.get_widget('item_tree')
  86.         items, iter = item_tree.get_selection().get_selected()
  87.         update_items = False
  88.         item_id, separator_path = None, None
  89.         if iter:
  90.             update_items = True
  91.             if items[iter][3].get_type() == gmenu.TYPE_DIRECTORY:
  92.                 item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
  93.                 update_items = True
  94.             elif items[iter][3].get_type() == gmenu.TYPE_ENTRY:
  95.                 item_id = items[iter][3].get_desktop_file_id()
  96.                 update_items = True
  97.             elif items[iter][3].get_type() == gmenu.TYPE_SEPARATOR:
  98.                 item_id = items.get_path(iter)
  99.                 update_items = True
  100.         menus, iter = menu_tree.get_selection().get_selected()
  101.         update_menus = False
  102.         menu_id = None
  103.         if iter:
  104.             if menus[iter][2].get_desktop_file_path():
  105.                 menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
  106.             else:
  107.                 menu_id = menus[iter][2].get_menu_id()
  108.             update_menus = True
  109.         self.loadMenus()
  110.         #find current menu in new tree
  111.         if update_menus:
  112.             menu_tree.get_model().foreach(self.findMenu, menu_id)
  113.             menus, iter = menu_tree.get_selection().get_selected()
  114.             if iter:
  115.                 self.on_menu_tree_cursor_changed(menu_tree)
  116.         #find current item in new list
  117.         if update_items:
  118.             i = 0
  119.             for item in item_tree.get_model():
  120.                 found = False
  121.                 if item[3].get_type() == gmenu.TYPE_ENTRY and item[3].get_desktop_file_id() == item_id:
  122.                     found = True
  123.                 if item[3].get_type() == gmenu.TYPE_DIRECTORY and item[3].get_desktop_file_path():
  124.                     if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
  125.                         found = True
  126.                 if item[3].get_type() == gmenu.TYPE_SEPARATOR:
  127.                     if not isinstance(item_id, tuple):
  128.                         continue
  129.                     #separators have no id, have to find them manually
  130.                     #probably won't work with two separators together
  131.                     if (item_id[0] - 1,) == (i,):
  132.                         found = True
  133.                     elif (item_id[0] + 1,) == (i,):
  134.                         found = True
  135.                     elif (item_id[0],) == (i,):
  136.                         found = True
  137.                 if found:
  138.                     item_tree.get_selection().select_path((i,))
  139.                     self.on_item_tree_cursor_changed(item_tree)
  140.                     break
  141.                 i += 1
  142.         return False
  143.  
  144.     def findMenu(self, menus, path, iter, menu_id):
  145.         if not menus[path][2].get_desktop_file_path():
  146.             if menu_id == menus[path][2].get_menu_id():
  147.                 menu_tree = self.tree.get_widget('menu_tree')
  148.                 menu_tree.expand_to_path(path)
  149.                 menu_tree.get_selection().select_path(path)
  150.                 return True
  151.             return False
  152.         if os.path.split(menus[path][2].get_desktop_file_path())[1] == menu_id:
  153.             menu_tree = self.tree.get_widget('menu_tree')
  154.             menu_tree.expand_to_path(path)
  155.             menu_tree.get_selection().select_path(path)
  156.             return True
  157.  
  158.     def setupMenuTree(self):
  159.         self.menu_store = gtk.TreeStore(gtk.gdk.Pixbuf, str, object)
  160.         menus = self.tree.get_widget('menu_tree')
  161.         column = gtk.TreeViewColumn(_('Name'))
  162.         column.set_spacing(4)
  163.         cell = gtk.CellRendererPixbuf()
  164.         column.pack_start(cell, False)
  165.         column.set_attributes(cell, pixbuf=0)
  166.         cell = gtk.CellRendererText()
  167.         cell.set_fixed_size(-1, 25)
  168.         column.pack_start(cell, True)
  169.         column.set_attributes(cell, markup=1)
  170.         column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
  171.         menus.append_column(column)
  172.         menus.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_menus, gtk.gdk.ACTION_COPY)
  173.         menus.enable_model_drag_dest(self.dnd_both, gtk.gdk.ACTION_PRIVATE)
  174.  
  175.     def setupItemTree(self):
  176.         items = self.tree.get_widget('item_tree')
  177.         column = gtk.TreeViewColumn(_('Show'))
  178.         cell = gtk.CellRendererToggle()
  179.         cell.connect('toggled', self.on_item_tree_show_toggled)
  180.         column.pack_start(cell, True)
  181.         column.set_attributes(cell, active=0)
  182.         #hide toggle for separators
  183.         column.set_cell_data_func(cell, self._cell_data_toggle_func)
  184.         items.append_column(column)
  185.         column = gtk.TreeViewColumn(_('Item'))
  186.         column.set_spacing(4)
  187.         cell = gtk.CellRendererPixbuf()
  188.         column.pack_start(cell, False)
  189.         column.set_attributes(cell, pixbuf=1)
  190.         cell = gtk.CellRendererText()
  191.         cell.set_fixed_size(-1, 25)
  192.         column.pack_start(cell, True)
  193.         column.set_attributes(cell, markup=2)
  194.         items.append_column(column)
  195.         self.item_store = gtk.ListStore(bool, gtk.gdk.Pixbuf, str, object)
  196.         items.set_model(self.item_store)
  197.         items.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_items, gtk.gdk.ACTION_COPY)
  198.         items.enable_model_drag_dest(self.dnd_items, gtk.gdk.ACTION_PRIVATE)
  199.  
  200.     def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter):
  201.         if model[treeiter][3].get_type() == gmenu.TYPE_SEPARATOR:
  202.             renderer.set_property('visible', False)
  203.         else:
  204.             renderer.set_property('visible', True)
  205.  
  206.     def loadMenus(self):
  207.         self.menu_store.clear()
  208.         for menu in self.editor.getMenus():
  209.             iters = [None]*20
  210.             self.loadMenu(iters, menu)
  211.         menu_tree = self.tree.get_widget('menu_tree')
  212.         menu_tree.set_model(self.menu_store)
  213.         for menu in self.menu_store:
  214.             menu_tree.expand_to_path(menu.path)
  215.         menu_tree.get_selection().select_path((0,))
  216.         self.on_menu_tree_cursor_changed(menu_tree)
  217.  
  218.     def loadMenu(self, iters, parent, depth=0):
  219.         if depth == 0:
  220.             icon = util.getIcon(parent)
  221.             iters[depth] = self.menu_store.append(None, (icon, cgi.escape(parent.get_name()), parent))
  222.         depth += 1
  223.         for menu, show in self.editor.getMenus(parent):
  224.             if show:
  225.                 name = cgi.escape(menu.get_name())
  226.             else:
  227.                 name = '<small><i>' + cgi.escape(menu.get_name()) + '</i></small>'
  228.             icon = util.getIcon(menu)
  229.             iters[depth] = self.menu_store.append(iters[depth-1], (icon, name, menu))
  230.             self.loadMenu(iters, menu, depth)
  231.         depth -= 1
  232.  
  233.     def loadItems(self, menu, menu_path):
  234.         self.item_store.clear()
  235.         for item, show in self.editor.getItems(menu):
  236.             menu_icon = None
  237.             if item.get_type() == gmenu.TYPE_SEPARATOR:
  238.                 name = '---'
  239.                 icon = None
  240.             else:
  241.                 if show:
  242.                     name = cgi.escape(item.get_name())
  243.                 else:
  244.                     name = '<small><i>' + cgi.escape(item.get_name()) + '</i></small>'
  245.                 icon = util.getIcon(item)
  246.             self.item_store.append((show, icon, name, item))
  247.  
  248.     def on_new_menu_button_clicked(self, button):
  249.         menu_tree = self.tree.get_widget('menu_tree')
  250.         menus, iter = menu_tree.get_selection().get_selected()
  251.         if not iter:
  252.             parent = menus[(0,)][2]
  253.             menu_tree.expand_to_path((0,))
  254.             menu_tree.get_selection().select_path((0,))
  255.         else:
  256.             parent = menus[iter][2]
  257.         values = self.dialogs.newMenuDialog()
  258.         if values:
  259.             self.editor.createMenu(parent, values[0], values[1], values[2])
  260.         #FIXME: make gnome-menus update monitors when menus are added
  261.         gobject.timeout_add(3, self.loadUpdates)
  262.  
  263.     def on_new_item_button_clicked(self, button):
  264.         menu_tree = self.tree.get_widget('menu_tree')
  265.         menus, iter = menu_tree.get_selection().get_selected()
  266.         if not iter:
  267.             parent = menus[(0,)][2]
  268.             menu_tree.expand_to_path((0,))
  269.             menu_tree.get_selection().select_path((0,))
  270.         else:
  271.             parent = menus[iter][2]
  272.         values = self.dialogs.newItemDialog()
  273.         if values:
  274.             self.editor.createItem(parent, values[0], values[1], values[2], values[3], values[4])
  275.  
  276.     def on_new_separator_button_clicked(self, button):
  277.         item_tree = self.tree.get_widget('item_tree')
  278.         items, iter = item_tree.get_selection().get_selected()
  279.         if not iter:
  280.             return
  281.         else:
  282.             after = items[iter][3]
  283.             menu_tree = self.tree.get_widget('menu_tree')
  284.             menus, iter = menu_tree.get_selection().get_selected()
  285.             parent = menus[iter][2]
  286.             self.editor.createSeparator(parent, after=after)
  287.  
  288.     def on_edit_delete_activate(self, menu):
  289.         item_tree = self.tree.get_widget('item_tree')
  290.         items, iter = item_tree.get_selection().get_selected()
  291.         if not iter:
  292.             return
  293.         item = items[iter][3]
  294.         if item.get_type() == gmenu.TYPE_ENTRY:
  295.             self.editor.deleteItem(item)
  296.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  297.             self.editor.deleteMenu(item)
  298.         elif item.get_type() == gmenu.TYPE_SEPARATOR:
  299.             self.editor.deleteSeparator(item)
  300.  
  301.     def on_edit_revert_to_original_activate(self, menu):
  302.         item_tree = self.tree.get_widget('item_tree')
  303.         items, iter = item_tree.get_selection().get_selected()
  304.         if not iter:
  305.             return
  306.         item = items[iter][3]
  307.         if item.get_type() == gmenu.TYPE_ENTRY:
  308.             self.editor.revertItem(item)
  309.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  310.             self.editor.revertMenu(item)
  311.  
  312.     def on_edit_properties_activate(self, menu):
  313.         item_tree = self.tree.get_widget('item_tree')
  314.         items, iter = item_tree.get_selection().get_selected()
  315.         if not iter:
  316.             return
  317.         item = items[iter][3]
  318.         self.allow_update = False
  319.         if item.get_type() == gmenu.TYPE_ENTRY:
  320.             self.dialogs.editItemDialog(items[iter])
  321.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  322.             self.dialogs.editMenuDialog(items[iter])
  323.         self.allow_update = True
  324.         self.loadUpdates()
  325.  
  326.     def on_menu_tree_cursor_changed(self, treeview):
  327.         menus, iter = treeview.get_selection().get_selected()
  328.         menu_path = menus.get_path(iter)
  329.         item_tree = self.tree.get_widget('item_tree')
  330.         item_tree.get_selection().unselect_all()
  331.         self.loadItems(self.menu_store[menu_path][2], menu_path)
  332.         self.tree.get_widget('edit_delete').set_sensitive(False)
  333.         self.tree.get_widget('edit_revert_to_original').set_sensitive(False)
  334.         self.tree.get_widget('edit_properties').set_sensitive(False)
  335.         self.tree.get_widget('move_up_button').set_sensitive(False)
  336.         self.tree.get_widget('move_down_button').set_sensitive(False)
  337.  
  338.     def on_menu_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
  339.         menus, iter = treeview.get_selection().get_selected()
  340.         self.drag_data = menus[iter][2]
  341.  
  342.     def on_menu_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
  343.         menus = treeview.get_model()
  344.         drop_info = treeview.get_dest_row_at_pos(x, y)
  345.         if drop_info:
  346.             path, position = drop_info
  347.             types = (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_AFTER)
  348.             if position not in types:
  349.                 context.finish(False, False, etime)
  350.                 return False
  351.             if selection.target in ('ALACARTE_ITEM_ROW', 'ALACARTE_MENU_ROW'):
  352.                 item = self.drag_data
  353.                 new_parent = menus[path][2]
  354.                 treeview.get_selection().select_path(path)
  355.                 if item.get_type() == gmenu.TYPE_ENTRY:
  356.                     self.editor.copyItem(item, new_parent)
  357.                 elif item.get_type() == gmenu.TYPE_DIRECTORY:
  358.                     if self.editor.moveMenu(item, new_parent) == False:
  359.                         self.loadUpdates()
  360.                 else:
  361.                     context.finish(False, False, etime) 
  362.                 context.finish(True, True, etime)
  363.  
  364.     def on_item_tree_show_toggled(self, cell, path):
  365.         item = self.item_store[path][3]
  366.         if item.get_type() == gmenu.TYPE_SEPARATOR:
  367.             return
  368.         if self.item_store[path][0]:
  369.             self.editor.setVisible(item, False)
  370.         else:
  371.             self.editor.setVisible(item, True)
  372.  
  373.     def on_item_tree_cursor_changed(self, treeview):
  374.         items, iter = treeview.get_selection().get_selected()
  375.         item = items[iter][3]
  376.         self.tree.get_widget('edit_delete').set_sensitive(True)
  377.         if self.editor.canRevert(item):
  378.             self.tree.get_widget('edit_revert_to_original').set_sensitive(True)
  379.         else:
  380.             self.tree.get_widget('edit_revert_to_original').set_sensitive(False)
  381.         if not item.get_type() == gmenu.TYPE_SEPARATOR:
  382.             self.tree.get_widget('edit_properties').set_sensitive(True)
  383.         else:
  384.             self.tree.get_widget('edit_properties').set_sensitive(False)
  385.         self.tree.get_widget('move_up_button').set_sensitive(True)
  386.         self.tree.get_widget('move_down_button').set_sensitive(True)
  387.  
  388.     def on_item_tree_row_activated(self, treeview, path, column):
  389.         self.on_edit_properties_activate(None)
  390.  
  391.     def on_item_tree_popup_menu(self, item_tree, event=None):
  392.         model, iter = item_tree.get_selection().get_selected()
  393.         if event:
  394.             #don't show if it's not the right mouse button
  395.             if event.button != 3:
  396.                 return
  397.             button = event.button
  398.             event_time = event.time
  399.             info = item_tree.get_path_at_pos(int(event.x), int(event.y))
  400.             if info != None:
  401.                 path, col, cellx, celly = info
  402.                 item_tree.grab_focus()
  403.                 item_tree.set_cursor(path, col, 0)
  404.         else:
  405.             path = model.get_path(iter)
  406.             button = 0
  407.             event_time = 0
  408.             item_tree.grab_focus()
  409.             item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
  410.         popup = self.tree.get_widget('edit_menu')
  411.         popup.popup(None, None, None, button, event_time)
  412.         #without this shift-f10 won't work
  413.         return True
  414.  
  415.     def on_item_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
  416.         items, iter = treeview.get_selection().get_selected()
  417.         self.drag_data = items[iter][3]
  418.  
  419.     def on_item_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
  420.         items = treeview.get_model()
  421.         types = (gtk.TREE_VIEW_DROP_BEFORE,    gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)
  422.         if selection.target == 'ALACARTE_ITEM_ROW':
  423.             drop_info = treeview.get_dest_row_at_pos(x, y)
  424.             before = None
  425.             after = None
  426.             item = self.drag_data
  427.             if drop_info:
  428.                 path, position = drop_info
  429.                 if position in types:
  430.                     before = items[path][3]
  431.                 else:
  432.                     after = items[path][3]
  433.             else:
  434.                 path = (len(items) - 1,)
  435.                 after = items[path][3]
  436.             if item.get_type() == gmenu.TYPE_ENTRY:
  437.                 self.editor.moveItem(item, item.get_parent(), before, after)
  438.             elif item.get_type() == gmenu.TYPE_DIRECTORY:
  439.                 if self.editor.moveMenu(item, item.get_parent(), before, after) == False:
  440.                     self.loadUpdates()
  441.             elif item.get_type() == gmenu.TYPE_SEPARATOR:
  442.                 self.editor.moveSeparator(item, item.get_parent(), before, after)
  443.             context.finish(True, True, etime)
  444.         elif selection.target == 'text/plain':
  445.             menus, iter = self.tree.get_widget('menu_tree').get_selection().get_selected()
  446.             parent = menus[iter][2]
  447.             drop_info = treeview.get_dest_row_at_pos(x, y)
  448.             before = None
  449.             after = None
  450.             if drop_info:
  451.                 path, position = drop_info
  452.                 if position in types:
  453.                     before = items[path][3]
  454.                 else:
  455.                     after = items[path][3]
  456.             else:
  457.                 path = (len(items) - 1,)
  458.                 after = items[path][3]
  459.             file_path = gnomevfs.unescape_string(selection.data, '').strip()
  460.             if not file_path.startswith('file:'):
  461.                 return
  462.             file_info = gnomevfs.get_file_info(
  463.                 file_path, gnomevfs.FILE_INFO_GET_MIME_TYPE|
  464.                 gnomevfs.FILE_INFO_FORCE_SLOW_MIME_TYPE|
  465.                 gnomevfs.FILE_INFO_FOLLOW_LINKS|gnomevfs.FILE_INFO_DEFAULT
  466.                 )
  467.             if file_info.mime_type == 'application/x-desktop':
  468.                 handle = gnomevfs.open(file_path)
  469.                 data = handle.read(file_info.size)
  470.                 open('/tmp/alacarte-dnd.desktop', 'w').write(data)
  471.                 parser = util.DesktopParser('/tmp/alacarte-dnd.desktop')
  472.                 self.editor.createItem(parent, parser.get('Icon'), parser.get('Name', self.editor.locale), parser.get('Comment', self.editor.locale), parser.get('Exec'), parser.get('Terminal'), before, after)
  473.             elif file_info.mime_type in ('application/x-shellscript', 'application/x-executable'):
  474.                 self.editor.createItem(parent, None, os.path.split(file_path)[1].strip(), None, file_path.replace('file://', '').strip(), False, before, after)
  475.  
  476.     def on_item_tree_key_press_event(self, item_tree, event):
  477.         if event.keyval == gtk.keysyms.Delete:
  478.             self.on_edit_delete_activate(item_tree)
  479.  
  480.     def on_move_up_button_clicked(self, button):
  481.         item_tree = self.tree.get_widget('item_tree')
  482.         items, iter = item_tree.get_selection().get_selected()
  483.         if not iter:
  484.             return
  485.         path = items.get_path(iter)
  486.         #at top, can't move up
  487.         if path[0] == 0:
  488.             return
  489.         item = items[path][3]
  490.         before = items[(path[0] - 1,)][3]
  491.         if item.get_type() == gmenu.TYPE_ENTRY:
  492.             self.editor.moveItem(item, item.get_parent(), before=before)
  493.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  494.             self.editor.moveMenu(item, item.get_parent(), before=before)
  495.         elif item.get_type() == gmenu.TYPE_SEPARATOR:
  496.             self.editor.moveSeparator(item, item.get_parent(), before=before)
  497.  
  498.     def on_move_down_button_clicked(self, button):
  499.         item_tree = self.tree.get_widget('item_tree')
  500.         items, iter = item_tree.get_selection().get_selected()
  501.         if not iter:
  502.             return
  503.         path = items.get_path(iter)
  504.         #at bottom, can't move down
  505.         if path[0] == (len(items) - 1):
  506.             return
  507.         item = items[path][3]
  508.         after = items[path][3]
  509.         if item.get_type() == gmenu.TYPE_ENTRY:
  510.             self.editor.moveItem(item, item.get_parent(), after=after)
  511.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  512.             self.editor.moveMenu(item, item.get_parent(), after=after)
  513.         elif item.get_type() == gmenu.TYPE_SEPARATOR:
  514.             self.editor.moveSeparator(item, item.get_parent(), after=after)
  515.  
  516.     def on_mainwindow_undo(self, accelgroup, window, keyval, modifier):
  517.         self.editor.undo()
  518.  
  519.     def on_mainwindow_redo(self, accelgroup, window, keyval, modifier):
  520.         self.editor.redo()
  521.  
  522.     def on_revert_button_clicked(self, button):
  523.         dialog = self.tree.get_widget('revertdialog')
  524.         dialog.set_transient_for(self.tree.get_widget('mainwindow'))
  525.         dialog.show_all()
  526.         if dialog.run() == gtk.RESPONSE_YES:
  527.             self.editor.revert()
  528.         dialog.hide()
  529.  
  530.     def on_close_button_clicked(self, button):
  531.         try:
  532.             self.tree.get_widget('mainwindow').hide()
  533.         except:
  534.             pass
  535.         gobject.timeout_add(10, self.quit)
  536.  
  537.     def quit(self):
  538.         self.editor.quit()
  539.         gtk.main_quit()        
  540.