home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / Alacarte / MainWindow.py < prev    next >
Encoding:
Python Source  |  2009-03-17  |  22.8 KB  |  628 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, gio
  20. import cgi, os
  21. import gettext
  22. import subprocess
  23. import urllib
  24. try:
  25.     from Alacarte import config
  26.     gettext.bindtextdomain('alacarte',config.localedir)
  27.     gettext.textdomain('alacarte')
  28.     gtk.glade.bindtextdomain('alacarte',config.localedir)
  29. except:
  30.     pass
  31. gtk.glade.textdomain('alacarte')
  32. _ = gettext.gettext
  33. from Alacarte.MenuEditor import MenuEditor
  34. from Alacarte import util
  35.  
  36. class MainWindow:
  37.     timer = None
  38.     #hack to make editing menu properties work
  39.     allow_update = True
  40.     #drag-and-drop stuff
  41.     dnd_items = [('ALACARTE_ITEM_ROW', gtk.TARGET_SAME_APP, 0), ('text/plain', 0, 1)]
  42.     dnd_menus = [('ALACARTE_MENU_ROW', gtk.TARGET_SAME_APP, 0)]
  43.     dnd_both = [dnd_items[0],] + dnd_menus
  44.     drag_data = None
  45.     edit_pool = []
  46.  
  47.     def __init__(self, datadir, version, argv):
  48.         self.file_path = datadir
  49.         self.version = version
  50.         self.editor = MenuEditor()
  51.         gtk.window_set_default_icon_name('alacarte')
  52.         self.tree = gtk.glade.XML(os.path.join(self.file_path, 'alacarte.glade'))
  53.         signals = {}
  54.         for attr in dir(self):
  55.             signals[attr] = getattr(self, attr)
  56.         self.tree.signal_autoconnect(signals)
  57.         self.setupMenuTree()
  58.         self.setupItemTree()
  59.         self.tree.get_widget('edit_delete').set_sensitive(False)
  60.         self.tree.get_widget('edit_revert_to_original').set_sensitive(False)
  61.         self.tree.get_widget('edit_properties').set_sensitive(False)
  62.         self.tree.get_widget('move_up_button').set_sensitive(False)
  63.         self.tree.get_widget('move_down_button').set_sensitive(False)
  64.         self.tree.get_widget('new_separator_button').set_sensitive(False)
  65.         accelgroup = gtk.AccelGroup()
  66.         keyval, modifier = gtk.accelerator_parse('<Ctrl>Z')
  67.         accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_undo)
  68.         keyval, modifier = gtk.accelerator_parse('<Ctrl><Shift>Z')
  69.         accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_redo)
  70.         keyval, modifier = gtk.accelerator_parse('F1')
  71.         accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_help_button_clicked)
  72.         self.tree.get_widget('mainwindow').add_accel_group(accelgroup)
  73.  
  74.     def run(self):
  75.         self.loadMenus()
  76.         self.editor.applications.tree.add_monitor(self.menuChanged, None)
  77.         self.editor.settings.tree.add_monitor(self.menuChanged, None)
  78.         self.tree.get_widget('mainwindow').show_all()
  79.         gtk.main()
  80.  
  81.     def menuChanged(self, *a):
  82.         if self.timer:
  83.             gobject.source_remove(self.timer)
  84.             self.timer = None
  85.         self.timer = gobject.timeout_add(3, self.loadUpdates)
  86.  
  87.     def loadUpdates(self):
  88.         if not self.allow_update:
  89.             return False
  90.         menu_tree = self.tree.get_widget('menu_tree')
  91.         item_tree = self.tree.get_widget('item_tree')
  92.         items, iter = item_tree.get_selection().get_selected()
  93.         update_items = False
  94.         item_id, separator_path = None, None
  95.         if iter:
  96.             update_items = True
  97.             if items[iter][3].get_type() == gmenu.TYPE_DIRECTORY:
  98.                 item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
  99.                 update_items = True
  100.             elif items[iter][3].get_type() == gmenu.TYPE_ENTRY:
  101.                 item_id = items[iter][3].get_desktop_file_id()
  102.                 update_items = True
  103.             elif items[iter][3].get_type() == gmenu.TYPE_SEPARATOR:
  104.                 item_id = items.get_path(iter)
  105.                 update_items = True
  106.         menus, iter = menu_tree.get_selection().get_selected()
  107.         update_menus = False
  108.         menu_id = None
  109.         if iter:
  110.             if menus[iter][2].get_desktop_file_path():
  111.                 menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
  112.             else:
  113.                 menu_id = menus[iter][2].get_menu_id()
  114.             update_menus = True
  115.         self.loadMenus()
  116.         #find current menu in new tree
  117.         if update_menus:
  118.             menu_tree.get_model().foreach(self.findMenu, menu_id)
  119.             menus, iter = menu_tree.get_selection().get_selected()
  120.             if iter:
  121.                 self.on_menu_tree_cursor_changed(menu_tree)
  122.         #find current item in new list
  123.         if update_items:
  124.             i = 0
  125.             for item in item_tree.get_model():
  126.                 found = False
  127.                 if item[3].get_type() == gmenu.TYPE_ENTRY and item[3].get_desktop_file_id() == item_id:
  128.                     found = True
  129.                 if item[3].get_type() == gmenu.TYPE_DIRECTORY and item[3].get_desktop_file_path():
  130.                     if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
  131.                         found = True
  132.                 if item[3].get_type() == gmenu.TYPE_SEPARATOR:
  133.                     if not isinstance(item_id, tuple):
  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
  149.  
  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_widget('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_widget('menu_tree')
  160.             menu_tree.expand_to_path(path)
  161.             menu_tree.get_selection().select_path(path)
  162.             return True
  163.  
  164.     def setupMenuTree(self):
  165.         self.menu_store = gtk.TreeStore(gtk.gdk.Pixbuf, str, object)
  166.         menus = self.tree.get_widget('menu_tree')
  167.         column = gtk.TreeViewColumn(_('Name'))
  168.         column.set_spacing(4)
  169.         cell = gtk.CellRendererPixbuf()
  170.         column.pack_start(cell, False)
  171.         column.set_attributes(cell, pixbuf=0)
  172.         cell = gtk.CellRendererText()
  173.         cell.set_fixed_size(-1, 25)
  174.         column.pack_start(cell, True)
  175.         column.set_attributes(cell, markup=1)
  176.         column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
  177.         menus.append_column(column)
  178.         menus.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_menus, gtk.gdk.ACTION_COPY)
  179.         menus.enable_model_drag_dest(self.dnd_both, gtk.gdk.ACTION_PRIVATE)
  180.  
  181.     def setupItemTree(self):
  182.         items = self.tree.get_widget('item_tree')
  183.         column = gtk.TreeViewColumn(_('Show'))
  184.         cell = gtk.CellRendererToggle()
  185.         cell.connect('toggled', self.on_item_tree_show_toggled)
  186.         column.pack_start(cell, True)
  187.         column.set_attributes(cell, active=0)
  188.         #hide toggle for separators
  189.         column.set_cell_data_func(cell, self._cell_data_toggle_func)
  190.         items.append_column(column)
  191.         column = gtk.TreeViewColumn(_('Item'))
  192.         column.set_spacing(4)
  193.         cell = gtk.CellRendererPixbuf()
  194.         column.pack_start(cell, False)
  195.         column.set_attributes(cell, pixbuf=1)
  196.         cell = gtk.CellRendererText()
  197.         cell.set_fixed_size(-1, 25)
  198.         column.pack_start(cell, True)
  199.         column.set_attributes(cell, markup=2)
  200.         items.append_column(column)
  201.         self.item_store = gtk.ListStore(bool, gtk.gdk.Pixbuf, str, object)
  202.         items.set_model(self.item_store)
  203.         items.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_items, gtk.gdk.ACTION_COPY)
  204.         items.enable_model_drag_dest(self.dnd_items, gtk.gdk.ACTION_PRIVATE)
  205.  
  206.     def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter):
  207.         if model[treeiter][3].get_type() == gmenu.TYPE_SEPARATOR:
  208.             renderer.set_property('visible', False)
  209.         else:
  210.             renderer.set_property('visible', True)
  211.  
  212.     def loadMenus(self):
  213.         self.menu_store.clear()
  214.         for menu in self.editor.getMenus():
  215.             iters = [None]*20
  216.             self.loadMenu(iters, menu)
  217.         menu_tree = self.tree.get_widget('menu_tree')
  218.         menu_tree.set_model(self.menu_store)
  219.         for menu in self.menu_store:
  220.             #this might not work for some reason
  221.             try:
  222.                 menu_tree.expand_to_path(menu.path)
  223.             except:
  224.                 pass
  225.         menu_tree.get_selection().select_path((0,))
  226.         self.on_menu_tree_cursor_changed(menu_tree)
  227.  
  228.     def loadMenu(self, iters, parent, depth=0):
  229.         if depth == 0:
  230.             icon = util.getIcon(parent)
  231.             iters[depth] = self.menu_store.append(None, (icon, cgi.escape(parent.get_name()), parent))
  232.         depth += 1
  233.         for menu, show in self.editor.getMenus(parent):
  234.             if show:
  235.                 name = cgi.escape(menu.get_name())
  236.             else:
  237.                 name = '<small><i>' + cgi.escape(menu.get_name()) + '</i></small>'
  238.             icon = util.getIcon(menu)
  239.             iters[depth] = self.menu_store.append(iters[depth-1], (icon, name, menu))
  240.             self.loadMenu(iters, menu, depth)
  241.         depth -= 1
  242.  
  243.     def loadItems(self, menu, menu_path):
  244.         self.item_store.clear()
  245.         for item, show in self.editor.getItems(menu):
  246.             menu_icon = None
  247.             if item.get_type() == gmenu.TYPE_SEPARATOR:
  248.                 name = '---'
  249.                 icon = None
  250.             else:
  251.                 if show:
  252.                     name = cgi.escape(item.get_name())
  253.                 else:
  254.                     name = '<small><i>' + cgi.escape(item.get_name()) + '</i></small>'
  255.                 icon = util.getIcon(item)
  256.             self.item_store.append((show, icon, name, item))
  257.  
  258.     #this is a little timeout callback to insert new items after
  259.     #gnome-desktop-item-edit has finished running
  260.     def waitForNewItemProcess(self, process, parent_id, file_path):
  261.         if process.poll() != None:
  262.             if os.path.isfile(file_path):
  263.                 self.editor.insertExternalItem(os.path.split(file_path)[1], parent_id)
  264.             return False
  265.         return True
  266.  
  267.     def waitForNewMenuProcess(self, process, parent_id, file_path):
  268.         if process.poll() != None:
  269.             #hack for broken gnome-desktop-item-edit
  270.             broken_path = os.path.join(os.path.split(file_path)[0], '.directory')
  271.             if os.path.isfile(broken_path):
  272.                 os.rename(broken_path, file_path)
  273.             if os.path.isfile(file_path):
  274.                 self.editor.insertExternalMenu(os.path.split(file_path)[1], parent_id)
  275.             return False
  276.         return True
  277.  
  278.     #this callback keeps you from editing the same item twice
  279.     def waitForEditProcess(self, process, file_path):
  280.         if process.poll() != None:
  281.             self.edit_pool.remove(file_path)
  282.             return False
  283.         return True
  284.  
  285.     def on_new_menu_button_clicked(self, button):
  286.         menu_tree = self.tree.get_widget('menu_tree')
  287.         menus, iter = menu_tree.get_selection().get_selected()
  288.         if not iter:
  289.             parent = menus[(0,)][2]
  290.             menu_tree.expand_to_path((0,))
  291.             menu_tree.get_selection().select_path((0,))
  292.         else:
  293.             parent = menus[iter][2]
  294.         file_path = os.path.join(util.getUserDirectoryPath(), util.getUniqueFileId('alacarte-made', '.directory'))
  295.         process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
  296.         gobject.timeout_add(100, self.waitForNewMenuProcess, process, parent.menu_id, file_path)
  297.  
  298.     def on_new_item_button_clicked(self, button):
  299.         menu_tree = self.tree.get_widget('menu_tree')
  300.         menus, iter = menu_tree.get_selection().get_selected()
  301.         if not iter:
  302.             parent = menus[(0,)][2]
  303.             menu_tree.expand_to_path((0,))
  304.             menu_tree.get_selection().select_path((0,))
  305.         else:
  306.             parent = menus[iter][2]
  307.         file_path = os.path.join(util.getUserItemPath(), util.getUniqueFileId('alacarte-made', '.desktop'))
  308.         process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
  309.         gobject.timeout_add(100, self.waitForNewItemProcess, process, parent.menu_id, file_path)
  310.  
  311.     def on_new_separator_button_clicked(self, button):
  312.         item_tree = self.tree.get_widget('item_tree')
  313.         items, iter = item_tree.get_selection().get_selected()
  314.         if not iter:
  315.             return
  316.         else:
  317.             after = items[iter][3]
  318.             menu_tree = self.tree.get_widget('menu_tree')
  319.             menus, iter = menu_tree.get_selection().get_selected()
  320.             parent = menus[iter][2]
  321.             self.editor.createSeparator(parent, after=after)
  322.  
  323.     def on_properties_button_clicked(self, button):
  324.         self.on_edit_properties_activate(None)
  325.  
  326.     def on_delete_button_clicked(self, button):
  327.         self.on_edit_delete_activate(None)
  328.  
  329.     def on_edit_delete_activate(self, menu):
  330.         item_tree = self.tree.get_widget('item_tree')
  331.         items, iter = item_tree.get_selection().get_selected()
  332.         if not iter:
  333.             return
  334.         item = items[iter][3]
  335.         if item.get_type() == gmenu.TYPE_ENTRY:
  336.             self.editor.deleteItem(item)
  337.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  338.             self.editor.deleteMenu(item)
  339.         elif item.get_type() == gmenu.TYPE_SEPARATOR:
  340.             self.editor.deleteSeparator(item)
  341.  
  342.     def on_edit_revert_to_original_activate(self, menu):
  343.         item_tree = self.tree.get_widget('item_tree')
  344.         items, iter = item_tree.get_selection().get_selected()
  345.         if not iter:
  346.             return
  347.         item = items[iter][3]
  348.         if item.get_type() == gmenu.TYPE_ENTRY:
  349.             self.editor.revertItem(item)
  350.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  351.             self.editor.revertMenu(item)
  352.  
  353.     def on_edit_properties_activate(self, menu):
  354.         item_tree = self.tree.get_widget('item_tree')
  355.         items, iter = item_tree.get_selection().get_selected()
  356.         if not iter:
  357.             return
  358.         item = items[iter][3]
  359.         if item.get_type() not in (gmenu.TYPE_ENTRY, gmenu.TYPE_DIRECTORY):
  360.             return
  361.  
  362.         if item.get_type() == gmenu.TYPE_ENTRY:
  363.             file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
  364.             file_type = 'Item'
  365.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  366.             if item.get_desktop_file_path() == None:
  367.                 file_path = util.getUniqueFileId('alacarte-made', '.directory')
  368.                 parser = util.DesktopParser(file_path, 'Directory')
  369.                 parser.set('Name', item.get_name())
  370.                 parser.set('Comment', item.get_comment())
  371.                 parser.set('Icon', item.get_icon())
  372.                 parser.write(open(file_path))
  373.             else:
  374.                 file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
  375.             file_type = 'Menu'
  376.  
  377.         if not os.path.isfile(file_path):
  378.             data = open(item.get_desktop_file_path()).read()
  379.             open(file_path, 'w').write(data)
  380.             self.editor._MenuEditor__addUndo([(file_type, os.path.split(file_path)[1]),])
  381.         else:
  382.             self.editor._MenuEditor__addUndo([item,])
  383.         if file_path not in self.edit_pool:
  384.             self.edit_pool.append(file_path)
  385.             process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
  386.             gobject.timeout_add(100, self.waitForEditProcess, process, file_path)
  387.  
  388.     def on_menu_tree_cursor_changed(self, treeview):
  389.         menus, iter = treeview.get_selection().get_selected()
  390.         menu_path = menus.get_path(iter)
  391.         item_tree = self.tree.get_widget('item_tree')
  392.         item_tree.get_selection().unselect_all()
  393.         self.loadItems(self.menu_store[menu_path][2], menu_path)
  394.         self.tree.get_widget('edit_delete').set_sensitive(False)
  395.         self.tree.get_widget('edit_revert_to_original').set_sensitive(False)
  396.         self.tree.get_widget('edit_properties').set_sensitive(False)
  397.         self.tree.get_widget('move_up_button').set_sensitive(False)
  398.         self.tree.get_widget('move_down_button').set_sensitive(False)
  399.         self.tree.get_widget('new_separator_button').set_sensitive(False)
  400.  
  401.     def on_menu_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
  402.         menus, iter = treeview.get_selection().get_selected()
  403.         self.drag_data = menus[iter][2]
  404.  
  405.     def on_menu_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
  406.         menus = treeview.get_model()
  407.         drop_info = treeview.get_dest_row_at_pos(x, y)
  408.         if drop_info:
  409.             path, position = drop_info
  410.             types = (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_AFTER)
  411.             if position not in types:
  412.                 context.finish(False, False, etime)
  413.                 return False
  414.             if selection.target in ('ALACARTE_ITEM_ROW', 'ALACARTE_MENU_ROW'):
  415.                 if self.drag_data == None:
  416.                     return False
  417.                 item = self.drag_data
  418.                 new_parent = menus[path][2]
  419.                 treeview.get_selection().select_path(path)
  420.                 if item.get_type() == gmenu.TYPE_ENTRY:
  421.                     self.editor.copyItem(item, new_parent)
  422.                 elif item.get_type() == gmenu.TYPE_DIRECTORY:
  423.                     if self.editor.moveMenu(item, new_parent) == False:
  424.                         self.loadUpdates()
  425.                 else:
  426.                     context.finish(False, False, etime) 
  427.                 context.finish(True, True, etime)
  428.         self.drag_data = None
  429.  
  430.     def on_item_tree_show_toggled(self, cell, path):
  431.         item = self.item_store[path][3]
  432.         if item.get_type() == gmenu.TYPE_SEPARATOR:
  433.             return
  434.         if self.item_store[path][0]:
  435.             self.editor.setVisible(item, False)
  436.         else:
  437.             self.editor.setVisible(item, True)
  438.         self.item_store[path][0] = not self.item_store[path][0]
  439.  
  440.     def on_item_tree_cursor_changed(self, treeview):
  441.         items, iter = treeview.get_selection().get_selected()
  442.         if iter is None:
  443.             return
  444.         item = items[iter][3]
  445.         self.tree.get_widget('edit_delete').set_sensitive(True)
  446.         self.tree.get_widget('new_separator_button').set_sensitive(True)
  447.         if self.editor.canRevert(item):
  448.             self.tree.get_widget('edit_revert_to_original').set_sensitive(True)
  449.         else:
  450.             self.tree.get_widget('edit_revert_to_original').set_sensitive(False)
  451.         if not item.get_type() == gmenu.TYPE_SEPARATOR:
  452.             self.tree.get_widget('edit_properties').set_sensitive(True)
  453.         else:
  454.             self.tree.get_widget('edit_properties').set_sensitive(False)
  455.  
  456.         # If first item...
  457.         if items.get_path(iter)[0] == 0:
  458.             self.tree.get_widget('move_up_button').set_sensitive(False)
  459.         else:
  460.             self.tree.get_widget('move_up_button').set_sensitive(True)
  461.  
  462.         # If last item...
  463.         if items.get_path(iter)[0] == (len(items)-1):
  464.             self.tree.get_widget('move_down_button').set_sensitive(False)
  465.         else:
  466.             self.tree.get_widget('move_down_button').set_sensitive(True)
  467.  
  468.     def on_item_tree_row_activated(self, treeview, path, column):
  469.         self.on_edit_properties_activate(None)
  470.  
  471.     def on_item_tree_popup_menu(self, item_tree, event=None):
  472.         model, iter = item_tree.get_selection().get_selected()
  473.         if event:
  474.             #don't show if it's not the right mouse button
  475.             if event.button != 3:
  476.                 return
  477.             button = event.button
  478.             event_time = event.time
  479.             info = item_tree.get_path_at_pos(int(event.x), int(event.y))
  480.             if info != None:
  481.                 path, col, cellx, celly = info
  482.                 item_tree.grab_focus()
  483.                 item_tree.set_cursor(path, col, 0)
  484.         else:
  485.             path = model.get_path(iter)
  486.             button = 0
  487.             event_time = 0
  488.             item_tree.grab_focus()
  489.             item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
  490.         popup = self.tree.get_widget('edit_menu')
  491.         popup.popup(None, None, None, button, event_time)
  492.         #without this shift-f10 won't work
  493.         return True
  494.  
  495.     def on_item_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
  496.         items, iter = treeview.get_selection().get_selected()
  497.         self.drag_data = items[iter][3]
  498.  
  499.     def on_item_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
  500.         items = treeview.get_model()
  501.         types = (gtk.TREE_VIEW_DROP_BEFORE,    gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)
  502.         if selection.target == 'ALACARTE_ITEM_ROW':
  503.             drop_info = treeview.get_dest_row_at_pos(x, y)
  504.             before = None
  505.             after = None
  506.             if self.drag_data == None:
  507.                 return False
  508.             item = self.drag_data
  509.             if drop_info:
  510.                 path, position = drop_info
  511.                 if position in types:
  512.                     before = items[path][3]
  513.                 else:
  514.                     after = items[path][3]
  515.             else:
  516.                 path = (len(items) - 1,)
  517.                 after = items[path][3]
  518.             if item.get_type() == gmenu.TYPE_ENTRY:
  519.                 self.editor.moveItem(item, item.get_parent(), before, after)
  520.             elif item.get_type() == gmenu.TYPE_DIRECTORY:
  521.                 if self.editor.moveMenu(item, item.get_parent(), before, after) == False:
  522.                     self.loadUpdates()
  523.             elif item.get_type() == gmenu.TYPE_SEPARATOR:
  524.                 self.editor.moveSeparator(item, item.get_parent(), before, after)
  525.             context.finish(True, True, etime)
  526.         elif selection.target == 'text/plain':
  527.             if selection.data == None:
  528.                 return False
  529.             menus, iter = self.tree.get_widget('menu_tree').get_selection().get_selected()
  530.             parent = menus[iter][2]
  531.             drop_info = treeview.get_dest_row_at_pos(x, y)
  532.             before = None
  533.             after = None
  534.             if drop_info:
  535.                 path, position = drop_info
  536.                 if position in types:
  537.                     before = items[path][3]
  538.                 else:
  539.                     after = items[path][3]
  540.             else:
  541.                 path = (len(items) - 1,)
  542.                 after = items[path][3]
  543.             file_path = urllib.unquote(selection.data).strip()
  544.             if not file_path.startswith('file:'):
  545.                 return
  546.             myfile = gio.File(uri=file_path)
  547.             file_info = myfile.query_info(gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)
  548.             content_type = file_info.get_content_type()
  549.             if content_type == 'application/x-desktop':
  550.                 input_stream = myfile.read()
  551.                 open('/tmp/alacarte-dnd.desktop', 'w').write(input_stream.read())
  552.                 parser = util.DesktopParser('/tmp/alacarte-dnd.desktop')
  553.                 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)
  554.             elif content_type in ('application/x-shellscript', 'application/x-executable'):
  555.                 self.editor.createItem(parent, None, os.path.split(file_path)[1].strip(), None, file_path.replace('file://', '').strip(), False, before, after)
  556.         self.drag_data = None
  557.  
  558.     def on_item_tree_key_press_event(self, item_tree, event):
  559.         if event.keyval == gtk.keysyms.Delete:
  560.             self.on_edit_delete_activate(item_tree)
  561.  
  562.     def on_move_up_button_clicked(self, button):
  563.         item_tree = self.tree.get_widget('item_tree')
  564.         items, iter = item_tree.get_selection().get_selected()
  565.         if not iter:
  566.             return
  567.         path = items.get_path(iter)
  568.         #at top, can't move up
  569.         if path[0] == 0:
  570.             return
  571.         item = items[path][3]
  572.         before = items[(path[0] - 1,)][3]
  573.         if item.get_type() == gmenu.TYPE_ENTRY:
  574.             self.editor.moveItem(item, item.get_parent(), before=before)
  575.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  576.             self.editor.moveMenu(item, item.get_parent(), before=before)
  577.         elif item.get_type() == gmenu.TYPE_SEPARATOR:
  578.             self.editor.moveSeparator(item, item.get_parent(), before=before)
  579.  
  580.     def on_move_down_button_clicked(self, button):
  581.         item_tree = self.tree.get_widget('item_tree')
  582.         items, iter = item_tree.get_selection().get_selected()
  583.         if not iter:
  584.             return
  585.         path = items.get_path(iter)
  586.         #at bottom, can't move down
  587.         if path[0] == (len(items) - 1):
  588.             return
  589.         item = items[path][3]
  590.         after = items[path][3]
  591.         if item.get_type() == gmenu.TYPE_ENTRY:
  592.             self.editor.moveItem(item, item.get_parent(), after=after)
  593.         elif item.get_type() == gmenu.TYPE_DIRECTORY:
  594.             self.editor.moveMenu(item, item.get_parent(), after=after)
  595.         elif item.get_type() == gmenu.TYPE_SEPARATOR:
  596.             self.editor.moveSeparator(item, item.get_parent(), after=after)
  597.  
  598.     def on_mainwindow_undo(self, accelgroup, window, keyval, modifier):
  599.         self.editor.undo()
  600.  
  601.     def on_mainwindow_redo(self, accelgroup, window, keyval, modifier):
  602.         self.editor.redo()
  603.  
  604.     def on_help_button_clicked(self, *args):
  605.         gtk.show_uri(gtk.gdk.screen_get_default(), "ghelp:user-guide#menu-editor", gtk.get_current_event_time())
  606.  
  607.     def on_revert_button_clicked(self, button):
  608.         dialog = self.tree.get_widget('revertdialog')
  609.         dialog.set_transient_for(self.tree.get_widget('mainwindow'))
  610.         dialog.show_all()
  611.         if dialog.run() == gtk.RESPONSE_YES:
  612.             self.editor.revert()
  613.         dialog.hide()
  614.  
  615.     def on_close_button_clicked(self, button):
  616.         try:
  617.             self.tree.get_widget('mainwindow').hide()
  618.         except:
  619.             pass
  620.         gobject.timeout_add(10, self.quit)
  621.  
  622.     def on_style_set(self, *args):
  623.         self.loadUpdates()
  624.  
  625.     def quit(self):
  626.         self.editor.quit()
  627.         gtk.main_quit()        
  628.