Sophie

Sophie

distrib > Fedora > 16 > i386 > by-pkgid > e73bedbb114357090e4e8b92530aa6fa > files > 6

cinnamon-1.4.0-8.UP1.fc16.src.rpm

--- a/files/usr/bin/cinnamon-menu-editor
+++ b/files/usr/bin/cinnamon-menu-editor
@@ -12,7 +12,7 @@ def main():
 	except:
 		datadir = '.'
 		version = '0.9'
-	app = MainWindow.MainWindow(datadir, version, sys.argv)
+	app = MainWindow.MainWindow(datadir, version)
 	app.run()
 
 if __name__ == '__main__':
--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/config.py
+++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/config.py
@@ -5,5 +5,5 @@ pkgdatadir="/usr/share/alacarte"
 libdir="/usr/lib"
 libexecdir="/usr/lib/alacarte"
 PACKAGE="alacarte"
-VERSION="0.13.2"
+VERSION="3.5.4"
 GETTEXT_PACKAGE="alacarte"
--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/MainWindow.py
+++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/MainWindow.py
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+# vim: set noexpandtab:
 #   Alacarte Menu Editor - Simple fd.o Compliant Menu Editor
 #   Copyright (C) 2006  Travis Watkins
 #
@@ -16,614 +17,437 @@
 #   License along with this library; if not, write to the Free Software
 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-import gtk, gmenu, gobject, gio
-import cgi, os
-import gettext, locale
+from gi.repository import Gtk, GObject, Gio, GdkPixbuf, Gdk, GMenu, GLib
+import cgi
+import os
+import gettext
 import subprocess
-import urllib
-try:
-	from Alacarte import config
-	gettext.bindtextdomain(config.GETTEXT_PACKAGE,config.localedir)
-	gettext.textdomain(config.GETTEXT_PACKAGE)
-	locale.bind_textdomain_codeset(config.GETTEXT_PACKAGE,'UTF-8')
-except:
-	pass
+
+from Alacarte import config
+gettext.bindtextdomain(config.GETTEXT_PACKAGE, config.localedir)
+gettext.textdomain(config.GETTEXT_PACKAGE)
+
 _ = gettext.gettext
 from Alacarte.MenuEditor import MenuEditor
 from Alacarte import util
 
-class MainWindow:
-	timer = None
-	#hack to make editing menu properties work
-	allow_update = True
-	#drag-and-drop stuff
-	dnd_items = [('ALACARTE_ITEM_ROW', gtk.TARGET_SAME_APP, 0), ('text/plain', 0, 1)]
-	dnd_menus = [('ALACARTE_MENU_ROW', gtk.TARGET_SAME_APP, 0)]
-	dnd_both = [dnd_items[0],] + dnd_menus
-	drag_data = None
-	edit_pool = []
-
-	def __init__(self, datadir, version, argv):
-		self.file_path = datadir
-		self.version = version
-		self.editor = MenuEditor()
-		gtk.window_set_default_icon_name('alacarte')
-		self.tree = gtk.Builder()
-		self.tree.set_translation_domain(config.GETTEXT_PACKAGE)
-		self.tree.add_from_file('/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui')
-		self.tree.connect_signals(self)
-		self.setupMenuTree()
-		self.setupItemTree()
-		self.tree.get_object('edit_delete').set_sensitive(False)
-		self.tree.get_object('edit_revert_to_original').set_sensitive(False)
-		self.tree.get_object('edit_properties').set_sensitive(False)
-		self.tree.get_object('move_up_button').set_sensitive(False)
-		self.tree.get_object('move_down_button').set_sensitive(False)
-		self.tree.get_object('new_separator_button').set_sensitive(False)
-		accelgroup = gtk.AccelGroup()
-		keyval, modifier = gtk.accelerator_parse('<Ctrl>Z')
-		accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_undo)
-		keyval, modifier = gtk.accelerator_parse('<Ctrl><Shift>Z')
-		accelgroup.connect_group(keyval, modifier, gtk.ACCEL_VISIBLE, self.on_mainwindow_redo)		
-		self.tree.get_object('mainwindow').add_accel_group(accelgroup)
-
-	def run(self):
-		self.loadMenus()
-		self.editor.applications.tree.add_monitor(self.menuChanged, None)
-		self.tree.get_object('mainwindow').show_all()
-		gtk.main()
-
-	def menuChanged(self, *a):
-		if self.timer:
-			gobject.source_remove(self.timer)
-			self.timer = None
-		self.timer = gobject.timeout_add(3, self.loadUpdates)
-
-	def loadUpdates(self):
-		if not self.allow_update:
-			return False
-		menu_tree = self.tree.get_object('menu_tree')
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		update_items = False
-		item_id, separator_path = None, None
-		if iter:
-			update_items = True
-			if items[iter][3].get_type() == gmenu.TYPE_DIRECTORY:
-				item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
-				update_items = True
-			elif items[iter][3].get_type() == gmenu.TYPE_ENTRY:
-				item_id = items[iter][3].get_desktop_file_id()
-				update_items = True
-			elif items[iter][3].get_type() == gmenu.TYPE_SEPARATOR:
-				item_id = items.get_path(iter)
-				update_items = True
-		menus, iter = menu_tree.get_selection().get_selected()
-		update_menus = False
-		menu_id = None
-		if iter:
-			if menus[iter][2].get_desktop_file_path():
-				menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
-			else:
-				menu_id = menus[iter][2].get_menu_id()
-			update_menus = True
-		self.loadMenus()
-		#find current menu in new tree
-		if update_menus:
-			menu_tree.get_model().foreach(self.findMenu, menu_id)
-			menus, iter = menu_tree.get_selection().get_selected()
-			if iter:
-				self.on_menu_tree_cursor_changed(menu_tree)
-		#find current item in new list
-		if update_items:
-			i = 0
-			for item in item_tree.get_model():
-				found = False
-				if item[3].get_type() == gmenu.TYPE_ENTRY and item[3].get_desktop_file_id() == item_id:
-					found = True
-				if item[3].get_type() == gmenu.TYPE_DIRECTORY and item[3].get_desktop_file_path():
-					if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
-						found = True
-				if item[3].get_type() == gmenu.TYPE_SEPARATOR:
-					if not isinstance(item_id, tuple):
-						continue
-					#separators have no id, have to find them manually
-					#probably won't work with two separators together
-					if (item_id[0] - 1,) == (i,):
-						found = True
-					elif (item_id[0] + 1,) == (i,):
-						found = True
-					elif (item_id[0],) == (i,):
-						found = True
-				if found:
-					item_tree.get_selection().select_path((i,))
-					self.on_item_tree_cursor_changed(item_tree)
-					break
-				i += 1
-		return False
-
-	def findMenu(self, menus, path, iter, menu_id):
-		if not menus[path][2].get_desktop_file_path():
-			if menu_id == menus[path][2].get_menu_id():
-				menu_tree = self.tree.get_object('menu_tree')
-				menu_tree.expand_to_path(path)
-				menu_tree.get_selection().select_path(path)
-				return True
-			return False
-		if os.path.split(menus[path][2].get_desktop_file_path())[1] == menu_id:
-			menu_tree = self.tree.get_object('menu_tree')
-			menu_tree.expand_to_path(path)
-			menu_tree.get_selection().select_path(path)
-			return True
-
-	def setupMenuTree(self):
-		self.menu_store = gtk.TreeStore(gtk.gdk.Pixbuf, str, object)
-		menus = self.tree.get_object('menu_tree')
-		column = gtk.TreeViewColumn(_("Name"))
-		column.set_spacing(4)
-		cell = gtk.CellRendererPixbuf()
-		column.pack_start(cell, False)
-		column.set_attributes(cell, pixbuf=0)
-		cell = gtk.CellRendererText()
-		cell.set_fixed_size(-1, 25)
-		column.pack_start(cell, True)
-		column.set_attributes(cell, markup=1)
-		column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
-		menus.append_column(column)
-		menus.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_menus, gtk.gdk.ACTION_COPY)
-		menus.enable_model_drag_dest(self.dnd_both, gtk.gdk.ACTION_PRIVATE)
-
-	def setupItemTree(self):
-		items = self.tree.get_object('item_tree')
-		column = gtk.TreeViewColumn(_("Show"))
-		cell = gtk.CellRendererToggle()
-		cell.connect('toggled', self.on_item_tree_show_toggled)
-		column.pack_start(cell, True)
-		column.set_attributes(cell, active=0)
-		#hide toggle for separators
-		column.set_cell_data_func(cell, self._cell_data_toggle_func)
-		items.append_column(column)
-		column = gtk.TreeViewColumn(_("Item"))
-		column.set_spacing(4)
-		cell = gtk.CellRendererPixbuf()
-		column.pack_start(cell, False)
-		column.set_attributes(cell, pixbuf=1)
-		cell = gtk.CellRendererText()
-		cell.set_fixed_size(-1, 25)
-		column.pack_start(cell, True)
-		column.set_attributes(cell, markup=2)
-		items.append_column(column)
-		self.item_store = gtk.ListStore(bool, gtk.gdk.Pixbuf, str, object)
-		items.set_model(self.item_store)
-		items.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.dnd_items, gtk.gdk.ACTION_COPY)
-		items.enable_model_drag_dest(self.dnd_items, gtk.gdk.ACTION_PRIVATE)
-
-	def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter):
-		if model[treeiter][3].get_type() == gmenu.TYPE_SEPARATOR:
-			renderer.set_property('visible', False)
-		else:
-			renderer.set_property('visible', True)
-
-	def loadMenus(self):
-		self.menu_store.clear()
-		for menu in self.editor.getMenus():
-			iters = [None]*20
-			self.loadMenu(iters, menu)
-		menu_tree = self.tree.get_object('menu_tree')
-		menu_tree.set_model(self.menu_store)
-		for menu in self.menu_store:
-			#this might not work for some reason
-			try:
-				menu_tree.expand_to_path(menu.path)
-			except:
-				pass
-		menu_tree.get_selection().select_path((0,))
-		self.on_menu_tree_cursor_changed(menu_tree)
-
-	def loadMenu(self, iters, parent, depth=0):
-		if depth == 0:
-			icon = util.getIcon(parent)
-			iters[depth] = self.menu_store.append(None, (icon, cgi.escape(parent.get_name()), parent))
-		depth += 1
-		for menu, show in self.editor.getMenus(parent):
-			if show:
-				name = cgi.escape(menu.get_name())
-			else:
-				name = '<small><i>' + cgi.escape(menu.get_name()) + '</i></small>'
-			icon = util.getIcon(menu)
-			iters[depth] = self.menu_store.append(iters[depth-1], (icon, name, menu))
-			self.loadMenu(iters, menu, depth)
-		depth -= 1
-
-	def loadItems(self, menu, menu_path):
-		self.item_store.clear()
-		for item, show in self.editor.getItems(menu):
-			menu_icon = None
-			if item.get_type() == gmenu.TYPE_SEPARATOR:
-				name = '---'
-				icon = None
-			elif item.get_type() == gmenu.TYPE_ENTRY:
-				if show:
-					name = cgi.escape(item.get_display_name())
-				else:
-					name = '<small><i>' + cgi.escape(item.get_display_name()) + '</i></small>'
-				icon = util.getIcon(item)
-			else:
-				if show:
-					name = cgi.escape(item.get_name())
-				else:
-					name = '<small><i>' + cgi.escape(item.get_name()) + '</i></small>'
-				icon = util.getIcon(item)
-			self.item_store.append((show, icon, name, item))
-
-	#this is a little timeout callback to insert new items after
-	#gnome-desktop-item-edit has finished running
-	def waitForNewItemProcess(self, process, parent, file_path):
-		if process.poll() != None:
-			if os.path.isfile(file_path):
-				self.editor.insertExternalItem(os.path.split(file_path)[1], parent)
-			return False
-		return True
-
-	def waitForNewMenuProcess(self, process, parent_id, file_path):
-		if process.poll() != None:
-			#hack for broken gnome-desktop-item-edit
-			broken_path = os.path.join(os.path.split(file_path)[0], '.directory')
-			if os.path.isfile(broken_path):
-				os.rename(broken_path, file_path)
-			if os.path.isfile(file_path):
-				self.editor.insertExternalMenu(os.path.split(file_path)[1], parent_id)
-			return False
-		return True
-
-	#this callback keeps you from editing the same item twice
-	def waitForEditProcess(self, process, file_path):
-		if process.poll() != None:
-			self.edit_pool.remove(file_path)
-			return False
-		return True
-
-	def on_new_menu_button_clicked(self, button):
-		menu_tree = self.tree.get_object('menu_tree')
-		menus, iter = menu_tree.get_selection().get_selected()
-		if not iter:
-			parent = menus[(0,)][2]
-			menu_tree.expand_to_path((0,))
-			menu_tree.get_selection().select_path((0,))
-		else:
-			parent = menus[iter][2]
-		file_path = os.path.join(util.getUserDirectoryPath(), util.getUniqueFileId('alacarte-made', '.directory'))
-		process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
-		gobject.timeout_add(100, self.waitForNewMenuProcess, process, parent.menu_id, file_path)
-
-	def on_new_item_button_clicked(self, button):
-		menu_tree = self.tree.get_object('menu_tree')
-		menus, iter = menu_tree.get_selection().get_selected()
-		if not iter:
-			parent = menus[(0,)][2]
-			menu_tree.expand_to_path((0,))
-			menu_tree.get_selection().select_path((0,))
-		else:
-			parent = menus[iter][2]
-		file_path = os.path.join(util.getUserItemPath(), util.getUniqueFileId('alacarte-made', '.desktop'))
-		process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
-		gobject.timeout_add(100, self.waitForNewItemProcess, process, parent, file_path)
-
-	def on_new_separator_button_clicked(self, button):
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		if not iter:
-			return
-		else:
-			after = items[iter][3]
-			menu_tree = self.tree.get_object('menu_tree')
-			menus, iter = menu_tree.get_selection().get_selected()
-			parent = menus[iter][2]
-			self.editor.createSeparator(parent, after=after)
-
-	def on_edit_delete_activate(self, menu):
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		if not iter:
-			return
-		item = items[iter][3]
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			self.editor.deleteItem(item)
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			self.editor.deleteMenu(item)
-		elif item.get_type() == gmenu.TYPE_SEPARATOR:
-			self.editor.deleteSeparator(item)
-
-	def on_edit_revert_to_original_activate(self, menu):
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		if not iter:
-			return
-		item = items[iter][3]
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			self.editor.revertItem(item)
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			self.editor.revertMenu(item)
-
-	def on_edit_properties_activate(self, menu):
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		if not iter:
-			return
-		item = items[iter][3]
-		if item.get_type() not in (gmenu.TYPE_ENTRY, gmenu.TYPE_DIRECTORY):
-			return
-
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
-			file_type = 'Item'
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			if item.get_desktop_file_path() == None:
-				file_path = util.getUniqueFileId('alacarte-made', '.directory')
-				parser = util.DesktopParser(file_path, 'Directory')
-				parser.set('Name', item.get_name())
-				parser.set('Comment', item.get_comment())
-				parser.set('Icon', item.get_icon())
-				parser.write(open(file_path))
-			else:
-				file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
-			file_type = 'Menu'
-
-		if not os.path.isfile(file_path):
-			data = open(item.get_desktop_file_path()).read()
-			open(file_path, 'w').write(data)
-			self.editor._MenuEditor__addUndo([(file_type, os.path.split(file_path)[1]),])
-		else:
-			self.editor._MenuEditor__addUndo([item,])
-		if file_path not in self.edit_pool:
-			self.edit_pool.append(file_path)
-			process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
-			gobject.timeout_add(100, self.waitForEditProcess, process, file_path)
-
-	def on_menu_tree_cursor_changed(self, treeview):
-		menus, iter = treeview.get_selection().get_selected()
-		menu_path = menus.get_path(iter)
-		item_tree = self.tree.get_object('item_tree')
-		item_tree.get_selection().unselect_all()
-		self.loadItems(self.menu_store[menu_path][2], menu_path)
-		self.tree.get_object('edit_delete').set_sensitive(False)
-		self.tree.get_object('edit_revert_to_original').set_sensitive(False)
-		self.tree.get_object('edit_properties').set_sensitive(False)
-		self.tree.get_object('move_up_button').set_sensitive(False)
-		self.tree.get_object('move_down_button').set_sensitive(False)
-		self.tree.get_object('new_separator_button').set_sensitive(False)
-		self.tree.get_object('properties_button').set_sensitive(False)
-		self.tree.get_object('delete_button').set_sensitive(False)
-
-	def on_menu_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
-		menus, iter = treeview.get_selection().get_selected()
-		self.drag_data = menus[iter][2]
-
-	def on_menu_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
-		menus = treeview.get_model()
-		drop_info = treeview.get_dest_row_at_pos(x, y)
-		if drop_info:
-			path, position = drop_info
-			types = (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_AFTER)
-			if position not in types:
-				context.finish(False, False, etime)
-				return False
-			if selection.target in ('ALACARTE_ITEM_ROW', 'ALACARTE_MENU_ROW'):
-				if self.drag_data == None:
-					return False
-				item = self.drag_data
-				new_parent = menus[path][2]
-				treeview.get_selection().select_path(path)
-				if item.get_type() == gmenu.TYPE_ENTRY:
-					self.editor.copyItem(item, new_parent)
-				elif item.get_type() == gmenu.TYPE_DIRECTORY:
-					if self.editor.moveMenu(item, new_parent) == False:
-						self.loadUpdates()
-				else:
-					context.finish(False, False, etime) 
-				context.finish(True, True, etime)
-		self.drag_data = None
-
-	def on_item_tree_show_toggled(self, cell, path):
-		item = self.item_store[path][3]
-		if item.get_type() == gmenu.TYPE_SEPARATOR:
-			return
-		if self.item_store[path][0]:
-			self.editor.setVisible(item, False)
-		else:
-			self.editor.setVisible(item, True)
-		self.item_store[path][0] = not self.item_store[path][0]
-
-	def on_item_tree_cursor_changed(self, treeview):
-		items, iter = treeview.get_selection().get_selected()
-		if iter is None:
-			return
-		item = items[iter][3]
-		self.tree.get_object('edit_delete').set_sensitive(True)
-		self.tree.get_object('new_separator_button').set_sensitive(True)
-		self.tree.get_object('delete_button').set_sensitive(True)
-		if self.editor.canRevert(item):
-			self.tree.get_object('edit_revert_to_original').set_sensitive(True)
-		else:
-			self.tree.get_object('edit_revert_to_original').set_sensitive(False)
-		if not item.get_type() == gmenu.TYPE_SEPARATOR:
-			self.tree.get_object('edit_properties').set_sensitive(True)
-			self.tree.get_object('properties_button').set_sensitive(True)
-		else:
-			self.tree.get_object('edit_properties').set_sensitive(False)
-			self.tree.get_object('properties_button').set_sensitive(False)
-
-		# If first item...
-		if items.get_path(iter)[0] == 0:
-			self.tree.get_object('move_up_button').set_sensitive(False)
-		else:
-			self.tree.get_object('move_up_button').set_sensitive(True)
-
-		# If last item...
-		if items.get_path(iter)[0] == (len(items)-1):
-			self.tree.get_object('move_down_button').set_sensitive(False)
-		else:
-			self.tree.get_object('move_down_button').set_sensitive(True)
-
-	def on_item_tree_row_activated(self, treeview, path, column):
-		self.on_edit_properties_activate(None)
-
-	def on_item_tree_popup_menu(self, item_tree, event=None):
-		model, iter = item_tree.get_selection().get_selected()
-		if event:
-			#don't show if it's not the right mouse button
-			if event.button != 3:
-				return
-			button = event.button
-			event_time = event.time
-			info = item_tree.get_path_at_pos(int(event.x), int(event.y))
-			if info != None:
-				path, col, cellx, celly = info
-				item_tree.grab_focus()
-				item_tree.set_cursor(path, col, 0)
-		else:
-			path = model.get_path(iter)
-			button = 0
-			event_time = 0
-			item_tree.grab_focus()
-			item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
-		popup = self.tree.get_object('edit_menu')
-		popup.popup(None, None, None, button, event_time)
-		#without this shift-f10 won't work
-		return True
-
-	def on_item_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
-		items, iter = treeview.get_selection().get_selected()
-		self.drag_data = items[iter][3]
-
-	def on_item_tree_drag_data_received(self, treeview, context, x, y, selection, info, etime):
-		items = treeview.get_model()
-		types = (gtk.TREE_VIEW_DROP_BEFORE,	gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)
-		if selection.target == 'ALACARTE_ITEM_ROW':
-			drop_info = treeview.get_dest_row_at_pos(x, y)
-			before = None
-			after = None
-			if self.drag_data == None:
-				return False
-			item = self.drag_data
-			if drop_info:
-				path, position = drop_info
-				if position in types:
-					before = items[path][3]
-				else:
-					after = items[path][3]
-			else:
-				path = (len(items) - 1,)
-				after = items[path][3]
-			if item.get_type() == gmenu.TYPE_ENTRY:
-				self.editor.moveItem(item, item.get_parent(), before, after)
-			elif item.get_type() == gmenu.TYPE_DIRECTORY:
-				if self.editor.moveMenu(item, item.get_parent(), before, after) == False:
-					self.loadUpdates()
-			elif item.get_type() == gmenu.TYPE_SEPARATOR:
-				self.editor.moveSeparator(item, item.get_parent(), before, after)
-			context.finish(True, True, etime)
-		elif selection.target == 'text/plain':
-			if selection.data == None:
-				return False
-			menus, iter = self.tree.get_object('menu_tree').get_selection().get_selected()
-			parent = menus[iter][2]
-			drop_info = treeview.get_dest_row_at_pos(x, y)
-			before = None
-			after = None
-			if drop_info:
-				path, position = drop_info
-				if position in types:
-					before = items[path][3]
-				else:
-					after = items[path][3]
-			else:
-				path = (len(items) - 1,)
-				after = items[path][3]
-			file_path = urllib.unquote(selection.data).strip()
-			if not file_path.startswith('file:'):
-				return
-			myfile = gio.File(uri=file_path)
-			file_info = myfile.query_info(gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)
-			content_type = file_info.get_content_type()
-			if content_type == 'application/x-desktop':
-				input_stream = myfile.read()
-				open('/tmp/alacarte-dnd.desktop', 'w').write(input_stream.read())
-				parser = util.DesktopParser('/tmp/alacarte-dnd.desktop')
-				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)
-			elif content_type in ('application/x-shellscript', 'application/x-executable'):
-				self.editor.createItem(parent, None, os.path.split(file_path)[1].strip(), None, file_path.replace('file://', '').strip(), False, before, after)
-		self.drag_data = None
-
-	def on_item_tree_key_press_event(self, item_tree, event):
-		if event.keyval == gtk.keysyms.Delete:
-			self.on_edit_delete_activate(item_tree)
-
-	def on_move_up_button_clicked(self, button):
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		if not iter:
-			return
-		path = items.get_path(iter)
-		#at top, can't move up
-		if path[0] == 0:
-			return
-		item = items[path][3]
-		before = items[(path[0] - 1,)][3]
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			self.editor.moveItem(item, item.get_parent(), before=before)
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			self.editor.moveMenu(item, item.get_parent(), before=before)
-		elif item.get_type() == gmenu.TYPE_SEPARATOR:
-			self.editor.moveSeparator(item, item.get_parent(), before=before)
-
-	def on_move_down_button_clicked(self, button):
-		item_tree = self.tree.get_object('item_tree')
-		items, iter = item_tree.get_selection().get_selected()
-		if not iter:
-			return
-		path = items.get_path(iter)
-		#at bottom, can't move down
-		if path[0] == (len(items) - 1):
-			return
-		item = items[path][3]
-		after = items[path][3]
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			self.editor.moveItem(item, item.get_parent(), after=after)
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			self.editor.moveMenu(item, item.get_parent(), after=after)
-		elif item.get_type() == gmenu.TYPE_SEPARATOR:
-			self.editor.moveSeparator(item, item.get_parent(), after=after)
-
-	def on_mainwindow_undo(self, accelgroup, window, keyval, modifier):
-		self.editor.undo()
-
-	def on_mainwindow_redo(self, accelgroup, window, keyval, modifier):
-		self.editor.redo()	
-
-	def on_revert_button_clicked(self, button):
-		dialog = self.tree.get_object('revertdialog')
-		dialog.set_transient_for(self.tree.get_object('mainwindow'))
-		dialog.show_all()
-		if dialog.run() == gtk.RESPONSE_YES:
-			self.editor.revert()
-		dialog.hide()
-
-	def on_close_button_clicked(self, button):
-		try:
-			self.tree.get_object('mainwindow').hide()
-		except:
-			pass
-		gobject.timeout_add(10, self.quit)
-
-	def on_properties_button_clicked(self, button):
-		self.on_edit_properties_activate(None)
-	def on_delete_button_clicked(self, button):
-		self.on_edit_delete_activate(None)
-
-	def on_style_set(self, *args):
-		self.loadUpdates()
-
-	def quit(self):
-		self.editor.quit()
-		gtk.main_quit()		
+class MainWindow(object):
+    timer = None
+    #hack to make editing menu properties work
+    edit_pool = []
+
+    def __init__(self, datadir, version):
+        self.file_path = datadir
+        self.version = version
+        self.editor = MenuEditor()
+        self.editor.tree.connect("changed", self.menuChanged)
+        Gtk.Window.set_default_icon_name('alacarte')
+        self.tree = Gtk.Builder()
+        self.tree.set_translation_domain(config.GETTEXT_PACKAGE)
+        self.tree.add_from_file('/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui')
+        self.tree.connect_signals(self)
+        self.setupMenuTree()
+        self.setupItemTree()
+        self.tree.get_object('edit_delete').set_sensitive(False)
+        self.tree.get_object('edit_properties').set_sensitive(False)
+        self.tree.get_object('move_up_button').set_sensitive(False)
+        self.tree.get_object('move_down_button').set_sensitive(False)
+        self.tree.get_object('new_separator_button').set_sensitive(False)
+        accelgroup = Gtk.AccelGroup()
+        keyval, modifier = Gtk.accelerator_parse('F1')
+        accelgroup.connect(keyval, modifier, Gtk.AccelFlags.VISIBLE, self.on_help_button_clicked)
+        self.tree.get_object('mainwindow').add_accel_group(accelgroup)
+
+    def run(self):
+        self.loadMenus()
+        self.tree.get_object('mainwindow').show_all()
+        Gtk.main()
+
+    def menuChanged(self, *a):
+        self.loadUpdates()
+
+    def loadUpdates(self):
+        menu_tree = self.tree.get_object('menu_tree')
+        item_tree = self.tree.get_object('item_tree')
+        items, iter = item_tree.get_selection().get_selected()
+        update_items = False
+        update_type = None
+        item_id = None
+        if iter:
+            update_items = True
+            if isinstance(items[iter][3], GMenu.TreeEntry):
+                item_id = items[iter][3].get_desktop_file_id()
+                update_type = GMenu.TreeItemType.ENTRY
+            elif isinstance(items[iter][3], GMenu.TreeDirectory):
+                item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
+                update_type = GMenu.TreeItemType.DIRECTORY
+            elif isinstance(items[iter][3], GMenu.TreeSeparator):
+                item_id = items.get_path(iter)
+                update_type = GMenu.TreeItemType.SEPARATOR
+        menus, iter = menu_tree.get_selection().get_selected()
+        update_menus = False
+        menu_id = None
+        if iter:
+            if menus[iter][2].get_desktop_file_path():
+                menu_id = os.path.split(menus[iter][2].get_desktop_file_path())[1]
+            else:
+                menu_id = menus[iter][2].get_menu_id()
+            update_menus = True
+        self.loadMenus()
+        #find current menu in new tree
+        if update_menus:
+            menu_tree.get_model().foreach(self.findMenu, menu_id)
+            menus, iter = menu_tree.get_selection().get_selected()
+            if iter:
+                self.on_menu_tree_cursor_changed(menu_tree)
+        #find current item in new list
+        if update_items:
+            i = 0
+            for item in item_tree.get_model():
+                found = False
+                if update_type != GMenu.TreeItemType.SEPARATOR:
+                    if isinstance (item[3], GMenu.TreeEntry) and item[3].get_desktop_file_id() == item_id:
+                        found = True
+                    if isinstance (item[3], GMenu.TreeDirectory) and item[3].get_desktop_file_path() and update_type == GMenu.TreeItemType.DIRECTORY:
+                        if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
+                            found = True
+                if isinstance(item[3], GMenu.TreeSeparator):
+                    if not isinstance(item_id, tuple):
+                        #we may not skip the increment via "continue"
+                        i += 1
+                        continue
+                    #separators have no id, have to find them manually
+                    #probably won't work with two separators together
+                    if (item_id[0] - 1,) == (i,):
+                        found = True
+                    elif (item_id[0] + 1,) == (i,):
+                        found = True
+                    elif (item_id[0],) == (i,):
+                        found = True
+                if found:
+                    item_tree.get_selection().select_path((i,))
+                    self.on_item_tree_cursor_changed(item_tree)
+                    break
+                i += 1
+        return False
+
+    def findMenu(self, menus, path, iter, menu_id):
+        if not menus[path][2].get_desktop_file_path():
+            if menu_id == menus[path][2].get_menu_id():
+                menu_tree = self.tree.get_object('menu_tree')
+                menu_tree.expand_to_path(path)
+                menu_tree.get_selection().select_path(path)
+                return True
+            return False
+        if os.path.split(menus[path][2].get_desktop_file_path())[1] == menu_id:
+            menu_tree = self.tree.get_object('menu_tree')
+            menu_tree.expand_to_path(path)
+            menu_tree.get_selection().select_path(path)
+            return True
+
+    def setupMenuTree(self):
+        self.menu_store = Gtk.TreeStore(GdkPixbuf.Pixbuf, str, object)
+        menus = self.tree.get_object('menu_tree')
+        column = Gtk.TreeViewColumn(_('Name'))
+        column.set_spacing(4)
+        cell = Gtk.CellRendererPixbuf()
+        column.pack_start(cell, False)
+        column.add_attribute(cell, 'pixbuf', 0)
+        cell = Gtk.CellRendererText()
+        column.pack_start(cell, True)
+        column.add_attribute(cell, 'markup', 1)
+        menus.append_column(column)
+        menus.get_selection().set_mode(Gtk.SelectionMode.BROWSE)
+
+    def setupItemTree(self):
+        items = self.tree.get_object('item_tree')
+        column = Gtk.TreeViewColumn(_('Show'))
+        cell = Gtk.CellRendererToggle()
+        cell.connect('toggled', self.on_item_tree_show_toggled)
+        column.pack_start(cell, True)
+        column.add_attribute(cell, 'active', 0)
+        #hide toggle for separators
+        column.set_cell_data_func(cell, self._cell_data_toggle_func)
+        items.append_column(column)
+        column = Gtk.TreeViewColumn(_('Item'))
+        column.set_spacing(4)
+        cell = Gtk.CellRendererPixbuf()
+        column.pack_start(cell, False)
+        column.add_attribute(cell, 'pixbuf', 1)
+        cell = Gtk.CellRendererText()
+        column.pack_start(cell, True)
+        column.add_attribute(cell, 'markup', 2)
+        items.append_column(column)
+        self.item_store = Gtk.ListStore(bool, GdkPixbuf.Pixbuf, str, object)
+        items.set_model(self.item_store)
+
+    def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter, data=None):
+        if isinstance(model[treeiter][3], GMenu.TreeSeparator):
+            renderer.set_property('visible', False)
+        else:
+            renderer.set_property('visible', True)
+
+    def loadMenus(self):
+        self.menu_store.clear()
+        self.loadMenu({ None: None })
+
+        menu_tree = self.tree.get_object('menu_tree')
+        menu_tree.set_model(self.menu_store)
+        for menu in self.menu_store:
+            menu_tree.expand_to_path(menu.path)
+        menu_tree.get_selection().select_path((0,))
+        self.on_menu_tree_cursor_changed(menu_tree)
+
+    def loadMenu(self, iters, parent=None):
+        for menu, show in self.editor.getMenus(parent):
+            name = cgi.escape(menu.get_name())
+            if not show:
+                name = "<small><i>%s</i></small>" % (name,)
+
+            icon = util.getIcon(menu)
+            iters[menu] = self.menu_store.append(iters[parent], (icon, name, menu))
+            self.loadMenu(iters, menu)
+
+    def loadItems(self, menu):
+        self.item_store.clear()
+        for item, show in self.editor.getItems(menu):
+            icon = util.getIcon(item)
+            if isinstance(item, GMenu.TreeDirectory):
+                name = item.get_name()
+            elif isinstance(item, GMenu.TreeEntry):
+                name = item.get_app_info().get_display_name()
+            elif isinstance(item, GMenu.TreeSeparator):
+                name = '---'
+            else:
+                assert False, 'should not be reached'
+
+            name = cgi.escape(name)
+            if not show:
+                name = "<small><i>%s</i></small>" % (name,)
+
+            self.item_store.append((show, icon, name, item))
+
+    #this is a little timeout callback to insert new items after
+    #gnome-desktop-item-edit has finished running
+    def waitForNewItemProcess(self, process, parent_id, file_path):
+        if process.poll() is not None:
+            if os.path.isfile(file_path):
+                self.editor.insertExternalItem(os.path.split(file_path)[1], parent_id)
+            return False
+        return True
+
+    def waitForNewMenuProcess(self, process, parent_id, file_path):
+        if process.poll() is not None:
+            if os.path.isfile(file_path):
+                self.editor.insertExternalMenu(os.path.split(file_path)[1], parent_id)
+            return False
+        return True
+
+    #this callback keeps you from editing the same item twice
+    def waitForEditProcess(self, process, file_path):
+        if process.poll() is not None:
+            self.edit_pool.remove(file_path)
+            return False
+        return True
+
+    def on_new_menu_button_clicked(self, button):
+        menu_tree = self.tree.get_object('menu_tree')
+        menus, iter = menu_tree.get_selection().get_selected()
+        if not iter:
+            parent = menus[(0,)][2]
+            menu_tree.expand_to_path((0,))
+            menu_tree.get_selection().select_path((0,))
+        else:
+            parent = menus[iter][2]
+        file_path = os.path.join(util.getUserDirectoryPath(), util.getUniqueFileId('alacarte-made', '.directory'))
+        process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
+        GObject.timeout_add(100, self.waitForNewMenuProcess, process, parent.get_menu_id(), file_path)
+
+    def on_new_item_button_clicked(self, button):
+        menu_tree = self.tree.get_object('menu_tree')
+        menus, iter = menu_tree.get_selection().get_selected()
+        if not iter:
+            parent = menus[(0,)][2]
+            menu_tree.expand_to_path((0,))
+            menu_tree.get_selection().select_path((0,))
+        else:
+            parent = menus[iter][2]
+        file_path = os.path.join(util.getUserItemPath(), util.getUniqueFileId('alacarte-made', '.desktop'))
+        process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
+        GObject.timeout_add(100, self.waitForNewItemProcess, process, parent.get_menu_id(), file_path)
+
+    def on_new_separator_button_clicked(self, button):
+        item_tree = self.tree.get_object('item_tree')
+        items, iter = item_tree.get_selection().get_selected()
+        if not iter:
+            return
+        else:
+            after = items[iter][3]
+            menu_tree = self.tree.get_object('menu_tree')
+            menus, iter = menu_tree.get_selection().get_selected()
+            parent = menus[iter][2]
+            self.editor.createSeparator(parent, after=after)
+
+    def on_edit_delete_activate(self, menu):
+        item_tree = self.tree.get_object('item_tree')
+        items, iter = item_tree.get_selection().get_selected()
+        if not iter:
+            return
+        item = items[iter][3]
+        if isinstance(item, GMenu.TreeEntry):
+            self.editor.deleteItem(item)
+        elif isinstance(item, GMenu.TreeDirectory):
+            self.editor.deleteMenu(item)
+        elif isinstance(item, GMenu.TreeSeparator):
+            self.editor.deleteSeparator(item)
+
+    def on_edit_properties_activate(self, menu):
+        item_tree = self.tree.get_object('item_tree')
+        items, iter = item_tree.get_selection().get_selected()
+        if not iter:
+            return
+        item = items[iter][3]
+        if not isinstance(item, GMenu.TreeEntry) and not isinstance(item, GMenu.TreeDirectory):
+            return
+
+        if isinstance(item, GMenu.TreeEntry):
+            file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
+            file_type = 'Item'
+        elif isinstance(item, GMenu.TreeDirectory):
+            file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
+            file_type = 'Menu'
+
+        if not os.path.isfile(file_path):
+            data = open(item.get_desktop_file_path()).read()
+            open(file_path, 'w').write(data)
+
+        if file_path not in self.edit_pool:
+            self.edit_pool.append(file_path)
+            process = subprocess.Popen(['gnome-desktop-item-edit', file_path], env=os.environ)
+            GObject.timeout_add(100, self.waitForEditProcess, process, file_path)
+
+    def on_menu_tree_cursor_changed(self, treeview):
+        selection = treeview.get_selection()
+        if selection is None:
+            return
+        menus, iter = selection.get_selected()
+        if iter is None:
+            return
+        menu_path = menus.get_path(iter)
+        item_tree = self.tree.get_object('item_tree')
+        item_tree.get_selection().unselect_all()
+        self.loadItems(self.menu_store[menu_path][2])
+        self.tree.get_object('edit_delete').set_sensitive(False)
+        self.tree.get_object('edit_properties').set_sensitive(False)
+        self.tree.get_object('move_up_button').set_sensitive(False)
+        self.tree.get_object('move_down_button').set_sensitive(False)
+        self.tree.get_object('new_separator_button').set_sensitive(False)
+        self.tree.get_object('properties_button').set_sensitive(False)
+        self.tree.get_object('delete_button').set_sensitive(False)
+
+    def on_item_tree_show_toggled(self, cell, path):
+        item = self.item_store[path][3]
+        if isinstance(item, GMenu.TreeSeparator):
+            return
+        if self.item_store[path][0]:
+            self.editor.setVisible(item, False)
+        else:
+            self.editor.setVisible(item, True)
+        self.item_store[path][0] = not self.item_store[path][0]
+
+    def on_item_tree_cursor_changed(self, treeview):
+        selection = treeview.get_selection()
+        if selection is None:
+            return
+        items, iter = selection.get_selected()
+        if iter is None:
+            return
+
+        item = items[iter][3]
+        self.tree.get_object('edit_delete').set_sensitive(True)
+        self.tree.get_object('new_separator_button').set_sensitive(True)
+        self.tree.get_object('delete_button').set_sensitive(True)
+
+        can_edit = not isinstance(item, GMenu.TreeSeparator)
+        self.tree.get_object('edit_properties').set_sensitive(can_edit)
+        self.tree.get_object('properties_button').set_sensitive(can_edit)
+
+        index = items.get_path(iter).get_indices()[0]
+        can_go_up = index > 0
+        can_go_down = index < len(items) - 1
+        self.tree.get_object('move_up_button').set_sensitive(can_go_up)
+        self.tree.get_object('move_down_button').set_sensitive(can_go_down)
+
+    def on_item_tree_row_activated(self, treeview, path, column):
+        self.on_edit_properties_activate(None)
+
+    def on_item_tree_popup_menu(self, item_tree, event=None):
+        model, iter = item_tree.get_selection().get_selected()
+        if event:
+            #don't show if it's not the right mouse button
+            if event.button != 3:
+                return
+            button = event.button
+            event_time = event.time
+            info = item_tree.get_path_at_pos(int(event.x), int(event.y))
+            if info is not None:
+                path, col, cellx, celly = info
+                item_tree.grab_focus()
+                item_tree.set_cursor(path, col, 0)
+        else:
+            path = model.get_path(iter)
+            button = 0
+            event_time = 0
+            item_tree.grab_focus()
+            item_tree.set_cursor(path, item_tree.get_columns()[0], 0)
+        popup = self.tree.get_object('edit_menu')
+        popup.popup(None, None, None, None, button, event_time)
+        #without this shift-f10 won't work
+        return True
+
+    def on_item_tree_key_press_event(self, item_tree, event):
+        if event.keyval == Gdk.KEY_Delete:
+            self.on_edit_delete_activate(item_tree)
+
+    def on_move_up_button_clicked(self, button):
+        item_tree = self.tree.get_object('item_tree')
+        items, iter = item_tree.get_selection().get_selected()
+        if not iter:
+            return
+        path = items.get_path(iter)
+        #at top, can't move up
+        if path.get_indices()[0] == 0:
+            return
+        item = items[path][3]
+        before = items[(path.get_indices()[0] - 1,)][3]
+        self.editor.moveItem(item.get_parent(), item, before=before)
+
+    def on_move_down_button_clicked(self, button):
+        item_tree = self.tree.get_object('item_tree')
+        items, iter = item_tree.get_selection().get_selected()
+        if not iter:
+            return
+        path = items.get_path(iter)
+        #at bottom, can't move down
+        if path.get_indices()[0] == (len(items) - 1):
+            return
+        item = items[path][3]
+        after = items[path][3]
+        self.editor.moveItem(item.get_parent(), item, after=after)
+
+    def on_help_button_clicked(self, *args):
+        Gtk.show_uri(Gdk.Screen.get_default(), "ghelp:user-guide#menu-editor", Gtk.get_current_event_time())
+
+    def on_restore_button_clicked(self, button):
+        self.editor.restoreToSystem()
+
+    def on_close_button_clicked(self, button):
+        self.quit()
+
+    def on_properties_button_clicked(self, button):
+        self.on_edit_properties_activate(None)
+    def on_delete_button_clicked(self, button):
+        self.on_edit_delete_activate(None)
+
+    def quit(self):
+        Gtk.main_quit()
--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/MenuEditor.py
+++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/MenuEditor.py
@@ -16,731 +16,555 @@
 #   License along with this library; if not, write to the Free Software
 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-import os, re, xml.dom.minidom, locale
-import gmenu
+import os
+import xml.dom.minidom
+import xml.parsers.expat
+from gi.repository import GMenu, GLib
 from Alacarte import util
 
-class Menu:
-	tree = None
-	visible_tree = None
-	path = None
-	dom = None
-
-class MenuEditor:
-	#lists for undo/redo functionality
-	__undo = []
-	__redo = []
-
-	def __init__(self):
-		self.locale = locale.getdefaultlocale()[0]
-		self.__loadMenus()
-
-	def __loadMenus(self):
-		self.applications = Menu()
-		self.applications.tree = gmenu.lookup_tree('cinnamon-applications.menu', gmenu.FLAGS_SHOW_EMPTY|gmenu.FLAGS_INCLUDE_EXCLUDED|gmenu.FLAGS_INCLUDE_NODISPLAY|gmenu.FLAGS_SHOW_ALL_SEPARATORS)
-		self.applications.visible_tree = gmenu.lookup_tree('cinnamon-applications.menu')
-		self.applications.tree.sort_key = gmenu.SORT_DISPLAY_NAME
-		self.applications.visible_tree.sort_key = gmenu.SORT_DISPLAY_NAME
-		self.applications.path = os.path.join(util.getUserMenuPath(), self.applications.tree.get_menu_file())
-		if not os.path.isfile(self.applications.path):
-			self.applications.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.applications.tree))
-		else:
-			self.applications.dom = xml.dom.minidom.parse(self.applications.path)
-		self.__remove_whilespace_nodes(self.applications.dom)
-
-		self.save(True)
-
-	def save(self, from_loading=False):
-		for menu in ('applications',):
-			fd = open(getattr(self, menu).path, 'w')
-			fd.write(re.sub("\n[\s]*([^\n<]*)\n[\s]*</", "\\1</", getattr(self, menu).dom.toprettyxml().replace('<?xml version="1.0" ?>\n', '')))
-			fd.close()
-		if not from_loading:
-			self.__loadMenus()
-
-	def quit(self):
-		for file_name in os.listdir(util.getUserItemPath()):
-			if file_name[-6:-2] in ('redo', 'undo'):
-				file_path = os.path.join(util.getUserItemPath(), file_name)
-				os.unlink(file_path)
-		for file_name in os.listdir(util.getUserDirectoryPath()):
-			if file_name[-6:-2] in ('redo', 'undo'):
-				file_path = os.path.join(util.getUserDirectoryPath(), file_name)
-				os.unlink(file_path)
-		for file_name in os.listdir(util.getUserMenuPath()):
-			if file_name[-6:-2] in ('redo', 'undo'):
-				file_path = os.path.join(util.getUserMenuPath(), file_name)
-				os.unlink(file_path)
-
-	def revert(self):
-		for name in ('applications',):
-			menu = getattr(self, name)
-			self.revertTree(menu.tree.root)
-			path = os.path.join(util.getUserMenuPath(), menu.tree.get_menu_file())
-			try:
-				os.unlink(path)
-			except OSError:
-				pass
-			#reload DOM for each menu
-			if not os.path.isfile(menu.path):
-				menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree))
-			else:
-				menu.dom = xml.dom.minidom.parse(menu.path)
-			self.__remove_whilespace_nodes(menu.dom)
-		#reset undo/redo, no way to recover from this
-		self.__undo, self.__redo = [], []
-		self.save()
-
-	def revertTree(self, menu):
-		for child in menu.get_contents():
-			if child.get_type() == gmenu.TYPE_DIRECTORY:
-				self.revertTree(child)
-			elif child.get_type() == gmenu.TYPE_ENTRY:
-				self.revertItem(child)
-		self.revertMenu(menu)
-
-	def undo(self):
-		if len(self.__undo) == 0:
-			return
-		files = self.__undo.pop()
-		redo = []
-		for file_path in files:
-			new_path = file_path.rsplit('.', 1)[0]
-			redo_path = util.getUniqueRedoFile(new_path)
-			data = open(new_path).read()
-			open(redo_path, 'w').write(data)
-			data = open(file_path).read()
-			open(new_path, 'w').write(data)
-			os.unlink(file_path)
-			redo.append(redo_path)
-		#reload DOM to make changes stick
-		for name in ('applications',):
-			menu = getattr(self, name)
-			if not os.path.isfile(menu.path):
-				menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree))
-			else:
-				menu.dom = xml.dom.minidom.parse(menu.path)
-			self.__remove_whilespace_nodes(menu.dom)
-		self.__redo.append(redo)
-
-	def redo(self):
-		if len(self.__redo) == 0:
-			return
-		files = self.__redo.pop()
-		undo = []
-		for file_path in files:
-			new_path = file_path.rsplit('.', 1)[0]
-			undo_path = util.getUniqueUndoFile(new_path)
-			data = open(new_path).read()
-			open(undo_path, 'w').write(data)
-			data = open(file_path).read()
-			open(new_path, 'w').write(data)
-			os.unlink(file_path)
-			undo.append(undo_path)
-		#reload DOM to make changes stick
-		for name in ('applications',):
-			menu = getattr(self, name)
-			if not os.path.isfile(menu.path):
-				menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree))
-			else:
-				menu.dom = xml.dom.minidom.parse(menu.path)
-			self.__remove_whilespace_nodes(menu.dom)
-		self.__undo.append(undo)
-
-	def getMenus(self, parent=None):
-		if parent == None:
-			yield self.applications.tree.root
-		else:
-			for menu in parent.get_contents():
-				if menu.get_type() == gmenu.TYPE_DIRECTORY:
-					yield (menu, self.__isVisible(menu))
-
-	def getItems(self, menu):
-		for item in menu.get_contents():
-			if item.get_type() == gmenu.TYPE_SEPARATOR:
-				yield (item, True)
-			else:
-				if item.get_type() == gmenu.TYPE_ENTRY and item.get_desktop_file_id()[-19:] == '-usercustom.desktop':
-					continue
-				yield (item, self.__isVisible(item))
-
-	def canRevert(self, item):
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			if util.getItemPath(item.get_desktop_file_id()):
-				path = util.getUserItemPath()
-				if os.path.isfile(os.path.join(path, item.get_desktop_file_id())):
-					return True
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			if item.get_desktop_file_path():
-				file_id = os.path.split(item.get_desktop_file_path())[1]
-			else:
-				file_id = item.get_menu_id() + '.directory'
-			if util.getDirectoryPath(file_id):
-				path = util.getUserDirectoryPath()
-				if os.path.isfile(os.path.join(path, file_id)):
-					return True
-		return False
-
-	def setVisible(self, item, visible):
-		dom = self.__getMenu(item).dom
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			self.__addUndo([self.__getMenu(item), item])
-			menu_xml = self.__getXmlMenu(self.__getPath(item.get_parent()), dom, dom)
-			if visible:
-				self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Include')
-				self.__writeItem(item, no_display=False)
-			else:
-				self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude')
-			self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
-		elif item.get_type() == gmenu.TYPE_DIRECTORY:
-			self.__addUndo([self.__getMenu(item), item])
-			#don't mess with it if it's empty
-			if len(item.get_contents()) == 0:
-				return
-			menu_xml = self.__getXmlMenu(self.__getPath(item), dom, dom)
-			for node in self.__getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml):
-				node.parentNode.removeChild(node)
-			if visible:
-				self.__writeMenu(item, no_display=False)
-			else:
-				self.__writeMenu(item, no_display=True)
-			self.__addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
-		self.save()
-
-	def createItem(self, parent, icon, name, comment, command, use_term, before=None, after=None):
-		file_id = self.__writeItem(None, icon, name, comment, command, use_term)
-		self.insertExternalItem(file_id, parent, before, after)
-
-	def insertExternalItem(self, file_id, parent, before=None, after=None):
-		dom = self.__getMenu(parent).dom
-		self.__addItem(parent, file_id, dom)
-		self.__positionItem(parent, ('Item', file_id), before, after)
-		self.__addUndo([self.__getMenu(parent), ('Item', file_id)])
-		self.save()
-
-	def createMenu(self, parent, icon, name, comment, before=None, after=None):
-		file_id = self.__writeMenu(None, icon, name, comment)
-		self.insertExternalMenu(file_id, parent.menu_id, before, after)
-
-	def insertExternalMenu(self, file_id, parent_id, before=None, after=None):
-		menu_id = file_id.rsplit('.', 1)[0]
-		parent = self.__findMenu(parent_id)
-		dom = self.__getMenu(parent).dom
-		self.__addXmlDefaultLayout(self.__getXmlMenu(self.__getPath(parent), dom, dom) , dom)
-		menu_xml = self.__getXmlMenu(self.__getPath(parent) + '/' + menu_id, dom, dom)
-		self.__addXmlTextElement(menu_xml, 'Directory', file_id, dom)
-		self.__positionItem(parent, ('Menu', menu_id), before, after)
-		self.__addUndo([self.__getMenu(parent), ('Menu', file_id)])
-		self.save()
-
-	def createSeparator(self, parent, before=None, after=None):
-		self.__positionItem(parent, ('Separator',), before, after)
-		self.__addUndo([self.__getMenu(parent), ('Separator',)])
-		self.save()
-
-	def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True):
-		#if nothing changed don't make a user copy
-		if icon == item.get_icon() and name == item.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal():
-			return
-		#hack, item.get_parent() seems to fail a lot
-		if not parent:
-			parent = item.get_parent()
-		if final:
-			self.__addUndo([self.__getMenu(parent), item])
-		self.__writeItem(item, icon, name, comment, command, use_term)
-		if final:
-			dom = self.__getMenu(parent).dom
-			menu_xml = self.__getXmlMenu(self.__getPath(parent), dom, dom)
-			self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
-		self.save()
-
-	def editMenu(self, menu, icon, name, comment, final=True):
-		#if nothing changed don't make a user copy
-		if icon == menu.get_icon() and name == menu.get_name() and comment == menu.get_comment():
-			return
-		#we don't use this, we just need to make sure the <Menu> exists
-		#otherwise changes won't show up
-		dom = self.__getMenu(menu).dom
-		menu_xml = self.__getXmlMenu(self.__getPath(menu), dom, dom)
-		file_id = self.__writeMenu(menu, icon, name, comment)
-		if final:
-			self.__addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
-			self.__addUndo([self.__getMenu(menu), menu])
-		self.save()
-
-	def copyItem(self, item, new_parent, before=None, after=None):
-		dom = self.__getMenu(new_parent).dom
-		file_path = item.get_desktop_file_path()
-		keyfile = util.DesktopParser(file_path)
-		#erase Categories in new file
-		keyfile.set('Categories', ('',))
-		keyfile.set('Hidden', False)
-		file_id = util.getUniqueFileId(item.get_name(), '.desktop')
-		out_path = os.path.join(util.getUserItemPath(), file_id)
-		keyfile.write(open(out_path, 'w'))
-		self.__addItem(new_parent, file_id, dom)
-		self.__positionItem(new_parent, ('Item', file_id), before, after)
-		self.__addUndo([self.__getMenu(new_parent), ('Item', file_id)])
-		self.save()
-		return file_id
-
-	def moveItem(self, item, new_parent, before=None, after=None):
-		undo = []
-		if item.get_parent() != new_parent:
-			#hide old item
-			self.deleteItem(item)
-			undo.append(item)
-			file_id = self.copyItem(item, new_parent)
-			item = ('Item', file_id)
-			undo.append(item)
-		self.__positionItem(new_parent, item, before, after)
-		undo.append(self.__getMenu(new_parent))
-		self.__addUndo(undo)
-		self.save()
-
-	def moveMenu(self, menu, new_parent, before=None, after=None):
-		parent = new_parent
-		#don't move a menu into it's child
-		while parent.get_parent():
-			parent = parent.get_parent()
-			if parent == menu:
-				return False
-
-		#don't move a menu into itself
-		if new_parent == menu:
-			return False
-
-		#can't move between top-level menus
-		if self.__getMenu(menu) != self.__getMenu(new_parent):
-			return False
-		if menu.get_parent() != new_parent:
-			dom = self.__getMenu(menu).dom
-			root_path = self.__getPath(menu).split('/', 1)[0]
-			xml_root = self.__getXmlMenu(root_path, dom, dom)
-			old_path = self.__getPath(menu).split('/', 1)[1]
-			#root menu's path has no /
-			if '/' in self.__getPath(new_parent):
-				new_path = self.__getPath(new_parent).split('/', 1)[1] + '/' + menu.get_menu_id()
-			else:
-				new_path = menu.get_menu_id()
-			self.__addXmlMove(xml_root, old_path, new_path, dom)
-		self.__positionItem(new_parent, menu, before, after)
-		self.__addUndo([self.__getMenu(new_parent),])
-		self.save()
-
-	def moveSeparator(self, separator, new_parent, before=None, after=None):
-		self.__positionItem(new_parent, separator, before, after)
-		self.__addUndo([self.__getMenu(new_parent),])
-		self.save()
-
-	def deleteItem(self, item):
-		self.__addUndo([item,])
-		self.__writeItem(item, hidden=True)
-		self.save()
-
-	def deleteMenu(self, menu):
-		dom = self.__getMenu(menu).dom
-		menu_xml = self.__getXmlMenu(self.__getPath(menu), dom, dom)
-		self.__addDeleted(menu_xml, dom)
-		self.__addUndo([self.__getMenu(menu),])
-		self.save()
-
-	def deleteSeparator(self, item):
-		parent = item.get_parent()
-		contents = parent.get_contents()
-		contents.remove(item)
-		layout = self.__createLayout(contents)
-		dom = self.__getMenu(parent).dom
-		menu_xml = self.__getXmlMenu(self.__getPath(parent), dom, dom)
-		self.__addXmlLayout(menu_xml, layout, dom)
-		self.__addUndo([self.__getMenu(item.get_parent()),])
-		self.save()
-
-	def revertItem(self, item):
-		if not self.canRevert(item):
-			return
-		self.__addUndo([item,])
-		try:
-			os.remove(item.get_desktop_file_path())
-		except OSError:
-			pass
-		self.save()
-
-	def revertMenu(self, menu):
-		if not self.canRevert(menu):
-			return
-		#wtf happened here? oh well, just bail
-		if not menu.get_desktop_file_path():
-			return
-		self.__addUndo([menu,])
-		file_id = os.path.split(menu.get_desktop_file_path())[1]
-		path = os.path.join(util.getUserDirectoryPath(), file_id)
-		try:
-			os.remove(path)
-		except OSError:
-			pass
-		self.save()
-
-	#private stuff
-	def __addUndo(self, items):
-		self.__undo.append([])
-		for item in items:
-			if isinstance(item, Menu):
-				file_path = item.path
-			elif isinstance(item, tuple):
-				if item[0] == 'Item':
-					file_path = os.path.join(util.getUserItemPath(), item[1])
-					if not os.path.isfile(file_path):
-						file_path = util.getItemPath(item[1])
-				elif item[0] == 'Menu':
-					file_path = os.path.join(util.getUserDirectoryPath(), item[1])
-					if not os.path.isfile(file_path):
-						file_path = util.getDirectoryPath(item[1])
-				else:
-					continue
-			elif item.get_type() == gmenu.TYPE_DIRECTORY:
-				if item.get_desktop_file_path() == None:
-					continue
-				file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
-				if not os.path.isfile(file_path):
-					file_path = item.get_desktop_file_path()
-			elif item.get_type() == gmenu.TYPE_ENTRY:
-				file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
-				if not os.path.isfile(file_path):
-					file_path = item.get_desktop_file_path()
-			else:
-				continue
-			data = open(file_path).read()
-			undo_path = util.getUniqueUndoFile(file_path)
-			open(undo_path, 'w').write(data)
-			self.__undo[-1].append(undo_path)
-
-	def __getMenu(self, item):
-		return self.applications
-
-	def __findMenu(self, menu_id, parent=None):
-		if parent == None:
-			return self.__findMenu(menu_id, self.applications.tree.root)
-		if menu_id == self.applications.tree.root.menu_id:
-			return self.applications.tree.root
-		for item in parent.get_contents():
-			if item.get_type() == gmenu.TYPE_DIRECTORY:
-				if item.menu_id == menu_id:
-					return item
-				menu = self.__findMenu(menu_id, item)
-				if menu != None:
-					return menu
-
-	def __isVisible(self, item):
-		if item.get_type() == gmenu.TYPE_ENTRY:
-			return not (item.get_is_excluded() or item.get_is_nodisplay())
-		menu = self.__getMenu(item)
-		if menu == self.applications:
-			root = self.applications.visible_tree.root
-		if item.get_type() == gmenu.TYPE_DIRECTORY:
-			if self.__findMenu(item.menu_id, root) == None:
-				return False
-		return True
-
-	def __getPath(self, menu, path=None):
-		if not path:
-                        path = menu.tree.root.get_menu_id()
-		if menu.get_parent():
-			path = self.__getPath(menu.get_parent(), path)
-			path += '/'
-			path += menu.menu_id
-		return path
-
-	def __getXmlMenu(self, path, element, dom):
-		if '/' in path:
-			(name, path) = path.split('/', 1)
-		else:
-			name = path
-			path = ''
-
-		found = None
-		for node in self.__getXmlNodesByName('Menu', element):
-			for child in self.__getXmlNodesByName('Name', node):
-				if child.childNodes[0].nodeValue == name:
-					if path:
-						found = self.__getXmlMenu(path, node, dom)
-					else:
-						found = node
-					break
-			if found:
-				break
-		if not found:
-			node = self.__addXmlMenuElement(element, name, dom)
-			if path:
-				found = self.__getXmlMenu(path, node, dom)
-			else:
-				found = node
-
-		return found
-
-	def __addXmlMenuElement(self, element, name, dom):
-		node = dom.createElement('Menu')
-		self.__addXmlTextElement(node, 'Name', name, dom)
-		return element.appendChild(node)
-
-	def __addXmlTextElement(self, element, name, text, dom):
-		for temp in element.childNodes:
-			if temp.nodeName == name:
-				if temp.childNodes[0].nodeValue == text:
-					return
-		node = dom.createElement(name)
-		text = dom.createTextNode(text)
-		node.appendChild(text)
-		return element.appendChild(node)
-
-	def __addXmlFilename(self, element, dom, filename, type = 'Include'):
-		# remove old filenames
-		for node in self.__getXmlNodesByName(['Include', 'Exclude'], element):
-			if node.childNodes[0].nodeName == 'Filename' and node.childNodes[0].childNodes[0].nodeValue == filename:
-				element.removeChild(node)
-
-		# add new filename
-		node = dom.createElement(type)
-		node.appendChild(self.__addXmlTextElement(node, 'Filename', filename, dom))
-		return element.appendChild(node)
-
-	def __addDeleted(self, element, dom):
-		node = dom.createElement('Deleted')
-		return element.appendChild(node)
-
-	def __writeItem(self, item=None, icon=None, name=None, comment=None, command=None, use_term=None, no_display=None, startup_notify=None, hidden=None):
-		if item:
-			file_path = item.get_desktop_file_path()
-			file_id = item.get_desktop_file_id()
-			keyfile = util.DesktopParser(file_path)
-		elif item == None and name == None:
-			raise Exception('New menu items need a name')
-		else:
-			file_id = util.getUniqueFileId(name, '.desktop')
-			keyfile = util.DesktopParser()
-		if icon:
-			keyfile.set('Icon', icon)
-			keyfile.set('Icon', icon, self.locale)
-		if name:
-			keyfile.set('Name', name)
-			keyfile.set('Name', name, self.locale)
-		if comment:
-			keyfile.set('Comment', comment)
-			keyfile.set('Comment', comment, self.locale)
-		if command:
-			keyfile.set('Exec', command)
-		if use_term != None:
-			keyfile.set('Terminal', use_term)
-		if no_display != None:
-			keyfile.set('NoDisplay', no_display)
-		if startup_notify != None:
-			keyfile.set('StartupNotify', startup_notify)
-		if hidden != None:
-			keyfile.set('Hidden', hidden)
-		out_path = os.path.join(util.getUserItemPath(), file_id)
-		keyfile.write(open(out_path, 'w'))
-		return file_id
-
-	def __writeMenu(self, menu=None, icon=None, name=None, comment=None, no_display=None):
-		if menu:
-			file_id = os.path.split(menu.get_desktop_file_path())[1]
-			file_path = menu.get_desktop_file_path()
-			keyfile = util.DesktopParser(file_path)
-		elif menu == None and name == None:
-			raise Exception('New menus need a name')
-		else:
-			file_id = util.getUniqueFileId(name, '.directory')
-			keyfile = util.DesktopParser(file_type='Directory')
-		if icon:
-			keyfile.set('Icon', icon)
-		if name:
-			keyfile.set('Name', name)
-			keyfile.set('Name', name, self.locale)
-		if comment:
-			keyfile.set('Comment', comment)
-			keyfile.set('Comment', comment, self.locale)
-		if no_display != None:
-			keyfile.set('NoDisplay', no_display)
-		out_path = os.path.join(util.getUserDirectoryPath(), file_id)
-		keyfile.write(open(out_path, 'w'))
-		return file_id
-
-	def __getXmlNodesByName(self, name, element):
-		for	child in element.childNodes:
-			if child.nodeType == xml.dom.Node.ELEMENT_NODE:
-				if isinstance(name, str) and child.nodeName == name:
-					yield child
-				elif isinstance(name, list) or isinstance(name, tuple):
-					if child.nodeName in name:
-						yield child
-
-	def __remove_whilespace_nodes(self, node):
-		remove_list = []
-		for child in node.childNodes:
-			if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
-				child.data = child.data.strip()
-				if not child.data.strip():
-					remove_list.append(child)
-			elif child.hasChildNodes():
-				self.__remove_whilespace_nodes(child)
-		for node in remove_list:
-			node.parentNode.removeChild(node)
-
-	def __addXmlMove(self, element, old, new, dom):
-		if not self.__undoMoves(element, old, new, dom):
-			node = dom.createElement('Move')
-			node.appendChild(self.__addXmlTextElement(node, 'Old', old, dom))
-			node.appendChild(self.__addXmlTextElement(node, 'New', new, dom))
-			#are parsed in reverse order, need to put at the beginning
-			return element.insertBefore(node, element.firstChild)
-
-	def __addXmlLayout(self, element, layout, dom):
-		# remove old layout
-		for node in self.__getXmlNodesByName('Layout', element):
-			element.removeChild(node)
-
-		# add new layout
-		node = dom.createElement('Layout')
-		for order in layout.order:
-			if order[0] == 'Separator':
-				child = dom.createElement('Separator')
-				node.appendChild(child)
-			elif order[0] == 'Filename':
-				child = self.__addXmlTextElement(node, 'Filename', order[1], dom)
-			elif order[0] == 'Menuname':
-				child = self.__addXmlTextElement(node, 'Menuname', order[1], dom)
-			elif order[0] == 'Merge':
-				child = dom.createElement('Merge')
-				child.setAttribute('type', order[1])
-				node.appendChild(child)
-		return element.appendChild(node)
-
-	def __addXmlDefaultLayout(self, element, dom):
-		# remove old default layout
-		for node in self.__getXmlNodesByName('DefaultLayout', element):
-			element.removeChild(node)
-
-		# add new layout
-		node = dom.createElement('DefaultLayout')
-		node.setAttribute('inline', 'false')
-		return element.appendChild(node)
-
-	def __createLayout(self, items):
-		layout = Layout()
-		layout.order = []
-
-		layout.order.append(['Merge', 'menus'])
-		for item in items:
-			if isinstance(item, tuple):
-				if item[0] == 'Separator':
-					layout.parseSeparator()
-				elif item[0] == 'Menu':
-					layout.parseMenuname(item[1])
-				elif item[0] == 'Item':
-					layout.parseFilename(item[1])
-			elif item.get_type() == gmenu.TYPE_DIRECTORY:
-				layout.parseMenuname(item.get_menu_id())
-			elif item.get_type() == gmenu.TYPE_ENTRY:
-				layout.parseFilename(item.get_desktop_file_id())
-			elif item.get_type() == gmenu.TYPE_SEPARATOR:
-				layout.parseSeparator()
-		layout.order.append(['Merge', 'files'])
-		return layout
-
-	def __addItem(self, parent, file_id, dom):
-		xml_parent = self.__getXmlMenu(self.__getPath(parent), dom, dom)
-		self.__addXmlFilename(xml_parent, dom, file_id, 'Include')
-
-	def __deleteItem(self, parent, file_id, dom, before=None, after=None):
-		xml_parent = self.__getXmlMenu(self.__getPath(parent), dom, dom)
-		self.__addXmlFilename(xml_parent, dom, file_id, 'Exclude')
-
-	def __positionItem(self, parent, item, before=None, after=None):
-		if not before and not after:
-			return
-		current = parent.contents.index(item)
-		if after:
-			index = parent.contents.index(after)
-			if current > index:
-				index += 1
-		elif before:
-			index = parent.contents.index(before)
-			if current < index:
-				index -= 1
-		contents = parent.contents
-		#if this is a move to a new parent you can't remove the item
-		try:
-			contents.remove(item)
-		except:
-			pass
-		contents.insert(index, item)
-		layout = self.__createLayout(contents)
-		dom = self.__getMenu(parent).dom
-		menu_xml = self.__getXmlMenu(self.__getPath(parent), dom, dom)
-		self.__addXmlLayout(menu_xml, layout, dom)
-
-	def __undoMoves(self, element, old, new, dom):
-		nodes = []
-		matches = []
-		original_old = old
-		final_old = old
-		#get all <Move> elements
-		for node in self.__getXmlNodesByName(['Move'], element):
-			nodes.insert(0, node)
-		#if the <New> matches our old parent we've found a stage to undo
-		for node in nodes:
-			xml_old = node.getElementsByTagName('Old')[0]
-			xml_new = node.getElementsByTagName('New')[0]
-			if xml_new.childNodes[0].nodeValue == old:
-				matches.append(node)
-				#we should end up with this path when completed
-				final_old = xml_old.childNodes[0].nodeValue
-		#undoing <Move>s
-		for node in matches:
-			element.removeChild(node)
-		if len(matches) > 0:
-			for node in nodes:
-				xml_old = node.getElementsByTagName('Old')[0]
-				xml_new = node.getElementsByTagName('New')[0]
-				path = os.path.split(xml_new.childNodes[0].nodeValue)
-				if path[0] == original_old:
-					element.removeChild(node)
-					for node in dom.getElementsByTagName('Menu'):
-						name_node = node.getElementsByTagName('Name')[0]
-						name = name_node.childNodes[0].nodeValue
-						if name == os.path.split(new)[1]:
-							#copy app and dir directory info from old <Menu>
-							root_path = dom.getElementsByTagName('Menu')[0].getElementsByTagName('Name')[0].childNodes[0].nodeValue
-							xml_menu = self.__getXmlMenu(root_path + '/' + new, dom, dom)
-							for app_dir in node.getElementsByTagName('AppDir'):
-								xml_menu.appendChild(app_dir)
-							for dir_dir in node.getElementsByTagName('DirectoryDir'):
-								xml_menu.appendChild(dir_dir)
-							parent = node.parentNode
-							parent.removeChild(node)
-					node = dom.createElement('Move')
-					node.appendChild(self.__addXmlTextElement(node, 'Old', xml_old.childNodes[0].nodeValue, dom))
-					node.appendChild(self.__addXmlTextElement(node, 'New', os.path.join(new, path[1]), dom))
-					element.appendChild(node)
-			if final_old == new:
-				return True
-			node = dom.createElement('Move')
-			node.appendChild(self.__addXmlTextElement(node, 'Old', final_old, dom))
-			node.appendChild(self.__addXmlTextElement(node, 'New', new, dom))
-			return element.appendChild(node)
-
-class Layout:
-	def __init__(self, node=None):
-		self.order = []
-
-	def parseMenuname(self, value):
-		self.order.append(['Menuname', value])
-
-	def parseSeparator(self):
-		self.order.append(['Separator'])
-
-	def parseFilename(self, value):
-		self.order.append(['Filename', value])
-
-	def parseMerge(self, merge_type='all'):
-		self.order.append(['Merge', merge_type])
+class MenuEditor(object):
+    def __init__(self, name='cinnamon-applications.menu'):
+        self.name = name
+
+        self.tree = GMenu.Tree.new(name, GMenu.TreeFlags.SHOW_EMPTY|GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.INCLUDE_NODISPLAY|GMenu.TreeFlags.SHOW_ALL_SEPARATORS|GMenu.TreeFlags.SORT_DISPLAY_NAME)
+        self.tree.connect('changed', self.menuChanged)
+        self.load()
+
+        self.path = os.path.join(util.getUserMenuPath(), self.tree.props.menu_basename)
+        self.loadDOM()
+
+    def loadDOM(self):
+        try:
+            self.dom = xml.dom.minidom.parse(self.path)
+        except (IOError, xml.parsers.expat.ExpatError), e:
+            self.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.tree))
+        util.removeWhitespaceNodes(self.dom)
+
+    def load(self):
+        if not self.tree.load_sync():
+            raise ValueError("can not load menu tree %r" % (self.name,))
+
+    def menuChanged(self, *a):
+        self.load()
+
+    def save(self):
+        fd = open(self.path, 'w')
+        fd.write(self.dom.toprettyxml())
+        fd.close()
+
+    def restoreToSystem(self):
+        self.restoreTree(self.tree.get_root_directory())
+        path = os.path.join(util.getUserMenuPath(), os.path.basename(self.tree.get_canonical_menu_path()))
+        try:
+            os.unlink(path)
+        except OSError:
+            pass
+
+        self.loadDOM()
+        self.save()
+
+    def restoreTree(self, menu):
+        item_iter = menu.iter()
+        item_type = item_iter.next()
+        while item_type != GMenu.TreeItemType.INVALID:
+            if item_type == GMenu.TreeItemType.DIRECTORY:
+                item = item_iter.get_directory()
+                self.restoreTree(item)
+            elif item_type == GMenu.TreeItemType.ENTRY:
+                item = item_iter.get_entry()
+                self.restoreItem(item)
+            item_type = item_iter.next()
+        self.restoreMenu(menu)
+
+    def restoreItem(self, item):
+        if not self.canRevert(item):
+            return
+        try:
+            os.remove(item.get_desktop_file_path())
+        except OSError:
+            pass
+        self.save()
+
+    def restoreMenu(self, menu):
+        if not self.canRevert(menu):
+            return
+        #wtf happened here? oh well, just bail
+        if not menu.get_desktop_file_path():
+            return
+        file_id = os.path.split(menu.get_desktop_file_path())[1]
+        path = os.path.join(util.getUserDirectoryPath(), file_id)
+        try:
+            os.remove(path)
+        except OSError:
+            pass
+        self.save()
+
+    def getMenus(self, parent):
+        if parent is None:
+            yield (self.tree.get_root_directory(), True)
+            return
+
+        item_iter = parent.iter()
+        item_type = item_iter.next()
+        while item_type != GMenu.TreeItemType.INVALID:
+            if item_type == GMenu.TreeItemType.DIRECTORY:
+                item = item_iter.get_directory()
+                yield (item, self.isVisible(item))
+            item_type = item_iter.next()
+
+    def getContents(self, item):
+        contents = []
+        item_iter = item.iter()
+        item_type = item_iter.next()
+
+        while item_type != GMenu.TreeItemType.INVALID:
+            item = None
+            if item_type == GMenu.TreeItemType.DIRECTORY:
+                item = item_iter.get_directory()
+            elif item_type == GMenu.TreeItemType.ENTRY:
+                item = item_iter.get_entry()
+            elif item_type == GMenu.TreeItemType.HEADER:
+                item = item_iter.get_header()
+            elif item_type == GMenu.TreeItemType.ALIAS:
+                item = item_iter.get_alias()
+            elif item_type == GMenu.TreeItemType.SEPARATOR:
+                item = item_iter.get_separator()
+            if item:
+                contents.append(item)
+            item_type = item_iter.next()
+        return contents
+
+    def getItems(self, menu):
+        item_iter = menu.iter()
+        item_type = item_iter.next()
+        while item_type != GMenu.TreeItemType.INVALID:
+            item = None
+            if item_type == GMenu.TreeItemType.ENTRY:
+                item = item_iter.get_entry()
+            elif item_type == GMenu.TreeItemType.DIRECTORY:
+                item = item_iter.get_directory()
+            elif item_type == GMenu.TreeItemType.HEADER:
+                item = item_iter.get_header()
+            elif item_type == GMenu.TreeItemType.ALIAS:
+                item = item_iter.get_alias()
+            elif item_type == GMenu.TreeItemType.SEPARATOR:
+                item = item_iter.get_separator()
+            yield (item, self.isVisible(item))
+            item_type = item_iter.next()
+
+    def canRevert(self, item):
+        if isinstance(item, GMenu.TreeEntry):
+            if util.getItemPath(item.get_desktop_file_id()) is not None:
+                path = util.getUserItemPath()
+                if os.path.isfile(os.path.join(path, item.get_desktop_file_id())):
+                    return True
+        elif isinstance(item, GMenu.TreeDirectory):
+            if item.get_desktop_file_path():
+                file_id = os.path.split(item.get_desktop_file_path())[1]
+            else:
+                file_id = item.get_menu_id() + '.directory'
+            if util.getDirectoryPath(file_id) is not None:
+                path = util.getUserDirectoryPath()
+                if os.path.isfile(os.path.join(path, file_id)):
+                    return True
+        return False
+
+    def setVisible(self, item, visible):
+        dom = self.dom
+        if isinstance(item, GMenu.TreeEntry):
+            menu_xml = self.getXmlMenu(self.getPath(item.get_parent()), dom.documentElement, dom)
+            if visible:
+                self.addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Include')
+                self.writeItem(item, NoDisplay=False)
+            else:
+                self.addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude')
+            self.addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
+        elif isinstance(item, GMenu.TreeDirectory):
+            item_iter = item.iter()
+            first_child_type = item_iter.next()
+            #don't mess with it if it's empty
+            if first_child_type == GMenu.TreeItemType.INVALID:
+                return
+            menu_xml = self.getXmlMenu(self.getPath(item), dom.documentElement, dom)
+            for node in self.getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml):
+                node.parentNode.removeChild(node)
+            self.writeMenu(item, NoDisplay=not visible)
+            self.addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
+        self.save()
+
+    def createItem(self, parent, before, after, **kwargs):
+        file_id = self.writeItem(None, **kwargs)
+        self.insertExternalItem(file_id, parent.get_menu_id(), before, after)
+
+    def insertExternalItem(self, file_id, parent_id, before=None, after=None):
+        parent = self.findMenu(parent_id)
+        dom = self.dom
+        self.addItem(parent, file_id, dom)
+        self.positionItem(parent, ('Item', file_id), before, after)
+        self.save()
+
+    def insertExternalMenu(self, file_id, parent_id, before=None, after=None):
+        menu_id = file_id.rsplit('.', 1)[0]
+        parent = self.findMenu(parent_id)
+        dom = self.dom
+        self.addXmlDefaultLayout(self.getXmlMenu(self.getPath(parent), dom.documentElement, dom) , dom)
+        menu_xml = self.getXmlMenu(self.getPath(parent) + [menu_id], dom.documentElement, dom)
+        self.addXmlTextElement(menu_xml, 'Directory', file_id, dom)
+        self.positionItem(parent, ('Menu', menu_id), before, after)
+        self.save()
+
+    def createSeparator(self, parent, before=None, after=None):
+        self.positionItem(parent, ('Separator',), before, after)
+        self.save()
+
+    def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True):
+        #if nothing changed don't make a user copy
+        app_info = item.get_app_info()
+        if icon == app_info.get_icon() and name == app_info.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal():
+            return
+        #hack, item.get_parent() seems to fail a lot
+        if not parent:
+            parent = item.get_parent()
+        self.writeItem(item, Icon=icon, Name=name, Comment=comment, Exec=command, Terminal=use_term)
+        if final:
+            dom = self.dom
+            menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
+            self.addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
+        self.save()
+
+    def editMenu(self, menu, icon, name, comment, final=True):
+        #if nothing changed don't make a user copy
+        if icon == menu.get_icon() and name == menu.get_name() and comment == menu.get_comment():
+            return
+        #we don't use this, we just need to make sure the <Menu> exists
+        #otherwise changes won't show up
+        dom = self.dom
+        menu_xml = self.getXmlMenu(self.getPath(menu), dom.documentElement, dom)
+        self.writeMenu(menu, Icon=icon, Name=name, Comment=comment)
+        if final:
+            self.addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom)
+        self.save()
+
+    def copyItem(self, item, new_parent, before=None, after=None):
+        dom = self.dom
+        file_path = item.get_desktop_file_path()
+        keyfile = GLib.KeyFile()
+        keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS)
+
+        util.fillKeyFile(keyfile, dict(Categories=[], Hidden=False))
+
+        app_info = item.get_app_info()
+        file_id = util.getUniqueFileId(app_info.get_name().replace(os.sep, '-'), '.desktop')
+        out_path = os.path.join(util.getUserItemPath(), file_id)
+
+        contents, length = keyfile.to_data()
+
+        f = open(out_path, 'w')
+        f.write(contents)
+        f.close()
+
+        self.addItem(new_parent, file_id, dom)
+        self.positionItem(new_parent, ('Item', file_id), before, after)
+        self.save()
+        return file_id
+
+    def deleteItem(self, item):
+        self.writeItem(item, Hidden=True)
+        self.save()
+
+    def deleteMenu(self, menu):
+        dom = self.dom
+        menu_xml = self.getXmlMenu(self.getPath(menu), dom.documentElement, dom)
+        self.addDeleted(menu_xml, dom)
+        self.save()
+
+    def deleteSeparator(self, item):
+        parent = item.get_parent()
+        contents = self.getContents(parent)
+        contents.remove(item)
+        layout = self.createLayout(contents)
+        dom = self.dom
+        menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
+        self.addXmlLayout(menu_xml, layout, dom)
+        self.save()
+
+    def findMenu(self, menu_id, parent=None):
+        if parent is None:
+            parent = self.tree.get_root_directory()
+
+        if menu_id == parent.get_menu_id():
+            return parent
+
+        item_iter = parent.iter()
+        item_type = item_iter.next()
+        while item_type != GMenu.TreeItemType.INVALID:
+            if item_type == GMenu.TreeItemType.DIRECTORY:
+                item = item_iter.get_directory()
+                if item.get_menu_id() == menu_id:
+                    return item
+                menu = self.findMenu(menu_id, item)
+                if menu is not None:
+                    return menu
+            item_type = item_iter.next()
+
+    def isVisible(self, item):
+        if isinstance(item, GMenu.TreeEntry):
+            app_info = item.get_app_info()
+            return not (item.get_is_excluded() or app_info.get_nodisplay())
+        elif isinstance(item, GMenu.TreeDirectory):
+            return not item.get_is_nodisplay()
+        return True
+
+    def getPath(self, menu):
+        names = []
+        current = menu
+        while current is not None:
+            names.append(current.get_menu_id())
+            current = current.get_parent()
+
+        # XXX - don't append root menu name, alacarte doesn't
+        # expect it. look into this more.
+        names.pop(-1)
+        return names[::-1]
+
+    def getXmlMenuPart(self, element, name):
+        for node in self.getXmlNodesByName('Menu', element):
+            for child in self.getXmlNodesByName('Name', node):
+                if child.childNodes[0].nodeValue == name:
+                    return node
+        return None
+
+    def getXmlMenu(self, path, element, dom):
+        for name in path:
+            found = self.getXmlMenuPart(element, name)
+            if found is not None:
+                element = found
+            else:
+                element = self.addXmlMenuElement(element, name, dom)
+        return element
+
+    def addXmlMenuElement(self, element, name, dom):
+        node = dom.createElement('Menu')
+        self.addXmlTextElement(node, 'Name', name, dom)
+        return element.appendChild(node)
+
+    def addXmlTextElement(self, element, name, text, dom):
+        for temp in element.childNodes:
+            if temp.nodeName == name:
+                if temp.childNodes[0].nodeValue == text:
+                    return
+        node = dom.createElement(name)
+        text = dom.createTextNode(text)
+        node.appendChild(text)
+        return element.appendChild(node)
+
+    def addXmlFilename(self, element, dom, filename, type = 'Include'):
+        # remove old filenames
+        for node in self.getXmlNodesByName(['Include', 'Exclude'], element):
+            if node.childNodes[0].nodeName == 'Filename' and node.childNodes[0].childNodes[0].nodeValue == filename:
+                element.removeChild(node)
+
+        # add new filename
+        node = dom.createElement(type)
+        node.appendChild(self.addXmlTextElement(node, 'Filename', filename, dom))
+        return element.appendChild(node)
+
+    def addDeleted(self, element, dom):
+        node = dom.createElement('Deleted')
+        return element.appendChild(node)
+
+    def makeKeyFile(self, file_path, kwargs):
+        if 'KeyFile' in kwargs:
+            return kwargs['KeyFile']
+
+        keyfile = GLib.KeyFile()
+
+        if file_path is not None:
+            keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS)
+
+        util.fillKeyFile(keyfile, kwargs)
+        return keyfile
+
+    def writeItem(self, item, **kwargs):
+        if item is not None:
+            file_path = item.get_desktop_file_path()
+        else:
+            file_path = None
+
+        keyfile = self.makeKeyFile(file_path, kwargs)
+
+        if item is not None:
+            file_id = item.get_desktop_file_id()
+        else:
+            file_id = util.getUniqueFileId(keyfile.get_string(GLib.KEY_FILE_DESKTOP_GROUP, 'Name'), '.desktop')
+
+        contents, length = keyfile.to_data()
+
+        f = open(os.path.join(util.getUserItemPath(), file_id), 'w')
+        f.write(contents)
+        f.close()
+        return file_id
+
+    def writeMenu(self, menu, **kwargs):
+        if menu is not None:
+            file_id = os.path.split(menu.get_desktop_file_path())[1]
+            file_path = menu.get_desktop_file_path()
+            keyfile = GLib.KeyFile()
+            keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS)
+        elif menu is None and 'Name' not in kwargs:
+            raise Exception('New menus need a name')
+        else:
+            file_id = util.getUniqueFileId(kwargs['Name'], '.directory')
+            keyfile = GLib.KeyFile()
+
+        util.fillKeyFile(keyfile, kwargs)
+
+        contents, length = keyfile.to_data()
+
+        f = open(os.path.join(util.getUserDirectoryPath(), file_id), 'w')
+        f.write(contents)
+        f.close()
+        return file_id
+
+    def getXmlNodesByName(self, name, element):
+        for child in element.childNodes:
+            if child.nodeType == xml.dom.Node.ELEMENT_NODE:
+                if isinstance(name, str) and child.nodeName == name:
+                    yield child
+                elif isinstance(name, list) or isinstance(name, tuple):
+                    if child.nodeName in name:
+                        yield child
+
+    def addXmlMove(self, element, old, new, dom):
+        if not self.undoMoves(element, old, new, dom):
+            node = dom.createElement('Move')
+            node.appendChild(self.addXmlTextElement(node, 'Old', old, dom))
+            node.appendChild(self.addXmlTextElement(node, 'New', new, dom))
+            #are parsed in reverse order, need to put at the beginning
+            return element.insertBefore(node, element.firstChild)
+
+    def addXmlLayout(self, element, layout, dom):
+        # remove old layout
+        for node in self.getXmlNodesByName('Layout', element):
+            element.removeChild(node)
+
+        # add new layout
+        node = dom.createElement('Layout')
+        for order in layout:
+            if order[0] == 'Separator':
+                child = dom.createElement('Separator')
+                node.appendChild(child)
+            elif order[0] == 'Filename':
+                child = self.addXmlTextElement(node, 'Filename', order[1], dom)
+            elif order[0] == 'Menuname':
+                child = self.addXmlTextElement(node, 'Menuname', order[1], dom)
+            elif order[0] == 'Merge':
+                child = dom.createElement('Merge')
+                child.setAttribute('type', order[1])
+                node.appendChild(child)
+        return element.appendChild(node)
+
+    def addXmlDefaultLayout(self, element, dom):
+        # remove old default layout
+        for node in self.getXmlNodesByName('DefaultLayout', element):
+            element.removeChild(node)
+
+        # add new layout
+        node = dom.createElement('DefaultLayout')
+        node.setAttribute('inline', 'false')
+        return element.appendChild(node)
+
+    def createLayout(self, items):
+        layout = []
+        layout.append(('Merge', 'menus'))
+        for item in items:
+            if isinstance(item, GMenu.TreeDirectory):
+                layout.append(('Menuname', item.get_menu_id()))
+            elif isinstance(item, GMenu.TreeEntry):
+                layout.append(('Filename', item.get_desktop_file_id()))
+            elif isinstance(item, GMenu.TreeSeparator):
+                layout.append(('Separator',))
+            else:
+                layout.append(item)
+        layout.append(('Merge', 'files'))
+        return layout
+
+    def addItem(self, parent, file_id, dom):
+        xml_parent = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
+        self.addXmlFilename(xml_parent, dom, file_id, 'Include')
+
+    def moveItem(self, parent, item, before=None, after=None):
+        self.positionItem(parent, item, before=before, after=after)
+        self.save()
+
+    def positionItem(self, parent, item, before=None, after=None):
+        contents = self.getContents(parent)
+        if after:
+            index = contents.index(after) + 1
+        elif before:
+            index = contents.index(before)
+        else:
+            # append the item to the list
+            index = len(contents)
+        #if this is a move to a new parent you can't remove the item
+        if item in contents:
+            # decrease the destination index, if we shorten the list
+            if (before and (contents.index(item) < index)) \
+                    or (after and (contents.index(item) < index - 1)):
+                index -= 1
+            contents.remove(item)
+        contents.insert(index, item)
+        layout = self.createLayout(contents)
+        dom = self.dom
+        menu_xml = self.getXmlMenu(self.getPath(parent), dom.documentElement, dom)
+        self.addXmlLayout(menu_xml, layout, dom)
+
+    def undoMoves(self, element, old, new, dom):
+        nodes = []
+        matches = []
+        original_old = old
+        final_old = old
+        #get all <Move> elements
+        for node in self.getXmlNodesByName(['Move'], element):
+            nodes.insert(0, node)
+        #if the <New> matches our old parent we've found a stage to undo
+        for node in nodes:
+            xml_old = node.getElementsByTagName('Old')[0]
+            xml_new = node.getElementsByTagName('New')[0]
+            if xml_new.childNodes[0].nodeValue == old:
+                matches.append(node)
+                #we should end up with this path when completed
+                final_old = xml_old.childNodes[0].nodeValue
+        #undoing <Move>s
+        for node in matches:
+            element.removeChild(node)
+        if len(matches) > 0:
+            for node in nodes:
+                xml_old = node.getElementsByTagName('Old')[0]
+                xml_new = node.getElementsByTagName('New')[0]
+                path = os.path.split(xml_new.childNodes[0].nodeValue)
+                if path[0] == original_old:
+                    element.removeChild(node)
+                    for node in dom.getElementsByTagName('Menu'):
+                        name_node = node.getElementsByTagName('Name')[0]
+                        name = name_node.childNodes[0].nodeValue
+                        if name == os.path.split(new)[1]:
+                            #copy app and dir directory info from old <Menu>
+                            root_path = dom.getElementsByTagName('Menu')[0].getElementsByTagName('Name')[0].childNodes[0].nodeValue
+                            xml_menu = self.getXmlMenu(root_path + '/' + new, dom.documentElement, dom)
+                            for app_dir in node.getElementsByTagName('AppDir'):
+                                xml_menu.appendChild(app_dir)
+                            for dir_dir in node.getElementsByTagName('DirectoryDir'):
+                                xml_menu.appendChild(dir_dir)
+                            parent = node.parentNode
+                            parent.removeChild(node)
+                    node = dom.createElement('Move')
+                    node.appendChild(self.addXmlTextElement(node, 'Old', xml_old.childNodes[0].nodeValue, dom))
+                    node.appendChild(self.addXmlTextElement(node, 'New', os.path.join(new, path[1]), dom))
+                    element.appendChild(node)
+            if final_old == new:
+                return True
+            node = dom.createElement('Move')
+            node.appendChild(self.addXmlTextElement(node, 'Old', final_old, dom))
+            node.appendChild(self.addXmlTextElement(node, 'New', new, dom))
+            return element.appendChild(node)
--- a/files/usr/lib/cinnamon-menu-editor/Alacarte/util.py
+++ b/files/usr/lib/cinnamon-menu-editor/Alacarte/util.py
@@ -17,228 +17,158 @@
 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 import os
-import gtk, gmenu
-from ConfigParser import ConfigParser
-
-class DesktopParser(ConfigParser):
-	def __init__(self, filename=None, file_type='Application'):
-		ConfigParser.__init__(self)
-		self.filename = filename
-		self.file_type = file_type
-		if filename:
-			if len(self.read(filename)) == 0:
-				#file doesn't exist
-				self.add_section('Desktop Entry')
-		else:
-			self.add_section('Desktop Entry')
-		self._list_separator = ';'
-
-	def optionxform(self, option):
-		#makes keys not be lowercase
-		return option
-
-	def get(self, option, locale=None):
-		locale_option = option + '[%s]' % locale
-		try:
-			value = ConfigParser.get(self, 'Desktop Entry', locale_option)
-		except:
-			try:
-				value = ConfigParser.get(self, 'Desktop Entry', option)
-			except:
-				return None
-		if self._list_separator in value:
-			value = value.split(self._list_separator)
-		if value == 'true':
-			value = True
-		if value == 'false':
-			value = False
-		return value
-
-	def set(self, option, value, locale=None):
-		if locale:
-			option = option + '[%s]' % locale
-		if value == True:
-			value = 'true'
-		if value == False:
-			value = 'false'
-		if isinstance(value, tuple) or isinstance(value, list):
-			value = self._list_separator.join(value) + ';'
-		ConfigParser.set(self, 'Desktop Entry', option, value)
-
-	def write(self, file_object):
-		file_object.write('[Desktop Entry]\n')
-		items = []
-		if not self.filename:
-			file_object.write('Encoding=UTF-8\n')
-			file_object.write('Type=' + str(self.file_type) + '\n')
-		for item in self.items('Desktop Entry'):
-			items.append(item)
-		items.sort()
-		for item in items:
-			file_object.write(item[0] + '=' + item[1] + '\n')
+import xml.dom.minidom
+from collections import Sequence
+from gi.repository import Gtk, GdkPixbuf, GMenu, GLib
+
+# XXX: look into pygobject error marshalling
+from gi._glib import GError
+
+DESKTOP_GROUP = GLib.KEY_FILE_DESKTOP_GROUP
+KEY_FILE_FLAGS = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
+
+def fillKeyFile(keyfile, items):
+    for key, item in items.iteritems():
+        if item is None:
+            continue
+
+        if isinstance(item, bool):
+            keyfile.set_boolean(DESKTOP_GROUP, key, item)
+        elif isinstance(item, Sequence):
+            keyfile.set_string_list(DESKTOP_GROUP, key, item)
+        elif isinstance(item, basestring):
+            keyfile.set_string(DESKTOP_GROUP, key, item)
 
 def getUniqueFileId(name, extension):
-	append = 0
-	while 1:
-		if append == 0:
-			filename = name + extension
-		else:
-			filename = name + '-' + str(append) + extension
-		if extension == '.desktop':
-			path = getUserItemPath()
-			if not os.path.isfile(os.path.join(path, filename)) and not getItemPath(filename):
-				break
-		elif extension == '.directory':
-			path = getUserDirectoryPath()
-			if not os.path.isfile(os.path.join(path, filename)) and not getDirectoryPath(filename):
-				break
-		append += 1
-	return filename
+    append = 0
+    while 1:
+        if append == 0:
+            filename = name + extension
+        else:
+            filename = name + '-' + str(append) + extension
+        if extension == '.desktop':
+            path = getUserItemPath()
+            if not os.path.isfile(os.path.join(path, filename)) and not getItemPath(filename):
+                break
+        elif extension == '.directory':
+            path = getUserDirectoryPath()
+            if not os.path.isfile(os.path.join(path, filename)) and not getDirectoryPath(filename):
+                break
+        append += 1
+    return filename
 
 def getUniqueRedoFile(filepath):
-	append = 0
-	while 1:
-		new_filepath = filepath + '.redo-' + str(append)
-		if not os.path.isfile(new_filepath):
-			break
-		else:
-			append += 1
-	return new_filepath
+    append = 0
+    while 1:
+        new_filepath = filepath + '.redo-' + str(append)
+        if not os.path.isfile(new_filepath):
+            break
+        else:
+            append += 1
+    return new_filepath
 
 def getUniqueUndoFile(filepath):
-	filename, extension = os.path.split(filepath)[1].rsplit('.', 1)
-	append = 0
-	while 1:
-		if extension == 'desktop':
-			path = getUserItemPath()
-		elif extension == 'directory':
-			path = getUserDirectoryPath()
-		elif extension == 'menu':
-			path = getUserMenuPath()
-		new_filepath = os.path.join(path, filename + '.' + extension + '.undo-' + str(append))
-		if not os.path.isfile(new_filepath):
-			break
-		else:
-			append += 1
-	return new_filepath
-
-def getUserMenuPath():
-	menu_dir = None
-	if os.environ.has_key('XDG_CONFIG_HOME'):
-		menu_dir = os.path.join(os.environ['XDG_CONFIG_HOME'], 'menus')
-	else:
-		menu_dir = os.path.join(os.environ['HOME'], '.config', 'menus')
-	#move .config out of the way if it's not a dir, it shouldn't be there
-	if os.path.isfile(os.path.split(menu_dir)[0]):
-		os.rename(os.path.split(menu_dir)[0], os.path.split(menu_dir)[0] + '.old')
-	if not os.path.isdir(menu_dir):
-		os.makedirs(menu_dir)
-	return menu_dir
+    filename, extension = os.path.split(filepath)[1].rsplit('.', 1)
+    append = 0
+    while 1:
+        if extension == 'desktop':
+            path = getUserItemPath()
+        elif extension == 'directory':
+            path = getUserDirectoryPath()
+        elif extension == 'menu':
+            path = getUserMenuPath()
+        new_filepath = os.path.join(path, filename + '.' + extension + '.undo-' + str(append))
+        if not os.path.isfile(new_filepath):
+            break
+        else:
+            append += 1
+    return new_filepath
 
 def getItemPath(file_id):
-	if os.environ.has_key('XDG_DATA_DIRS'):
-		for system_path in os.environ['XDG_DATA_DIRS'].split(':'):
-			file_path = os.path.join(system_path, 'applications', file_id)
-			if os.path.isfile(file_path):
-				return file_path
-	file_path = os.path.join('/', 'usr', 'share', 'applications', file_id)
-	if os.path.isfile(file_path):
-		return file_path
-	return False
+    for path in GLib.get_system_data_dirs():
+        file_path = os.path.join(path, 'applications', file_id)
+        if os.path.isfile(file_path):
+            return file_path
+    return None
 
 def getUserItemPath():
-	item_dir = None
-	if os.environ.has_key('XDG_DATA_HOME'):
-		item_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'applications')
-	else:
-		item_dir = os.path.join(os.environ['HOME'], '.local', 'share', 'applications')
-	if not os.path.isdir(item_dir):
-		os.makedirs(item_dir)
-	return item_dir
+    item_dir = os.path.join(GLib.get_user_data_dir(), 'applications')
+    if not os.path.isdir(item_dir):
+        os.makedirs(item_dir)
+    return item_dir
 
 def getDirectoryPath(file_id):
-	home = getUserDirectoryPath()
-	file_path = os.path.join(home, file_id)
-	if os.path.isfile(file_path):
-		return file_path
-	if os.environ.has_key('XDG_DATA_DIRS'):
-		for system_path in os.environ['XDG_DATA_DIRS'].split(':'):
-			file_path = os.path.join(system_path, 'desktop-directories', file_id)
-			if os.path.isfile(file_path):
-				return file_path
-	file_path = os.path.join('/', 'usr', 'share', 'desktop-directories', file_id)
-	if os.path.isfile(file_path):
-		return file_path
-	return False
+    for path in GLib.get_system_data_dirs():
+        file_path = os.path.join(path, 'desktop-directories', file_id)
+        if os.path.isfile(file_path):
+            return file_path
+    return None
 
 def getUserDirectoryPath():
-	menu_dir = None
-	if os.environ.has_key('XDG_DATA_HOME'):
-		menu_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'desktop-directories')
-	else:
-		menu_dir = os.path.join(os.environ['HOME'], '.local', 'share', 'desktop-directories')
-	if not os.path.isdir(menu_dir):
-		os.makedirs(menu_dir)
-	return menu_dir
-
-def getSystemMenuPath(file_name):
-	if os.environ.has_key('XDG_CONFIG_DIRS'):
-		for system_path in os.environ['XDG_CONFIG_DIRS'].split(':'):
-			file_path = os.path.join(system_path, 'menus', file_name)
-			if os.path.isfile(file_path):
-				return file_path
-	file_path = os.path.join('/', 'etc', 'xdg', 'menus', file_name)
-	if os.path.isfile(file_path):
-		return file_path
-	return False
+    menu_dir = os.path.join(GLib.get_user_data_dir(), 'desktop-directories')
+    if not os.path.isdir(menu_dir):
+        os.makedirs(menu_dir)
+    return menu_dir
+
+def getUserMenuPath():
+    menu_dir = os.path.join(GLib.get_user_config_dir(), 'menus')
+    if not os.path.isdir(menu_dir):
+        os.makedirs(menu_dir)
+    return menu_dir
+
+def getSystemMenuPath(file_id):
+    for path in GLib.get_system_config_dirs():
+        file_path = os.path.join(path, 'menus', file_id)
+        if os.path.isfile(file_path):
+            return file_path
+    return None
 
 def getUserMenuXml(tree):
-	system_file = getSystemMenuPath(tree.get_menu_file())
-	name = tree.root.get_menu_id()
-	menu_xml = "<!DOCTYPE Menu PUBLIC '-//freedesktop//DTD Menu 1.0//EN' 'http://standards.freedesktop.org/menu-spec/menu-1.0.dtd'>\n"
-	menu_xml += "<Menu>\n  <Name>" + name + "</Name>\n  "
-	menu_xml += "<MergeFile type=\"parent\">" + system_file +	"</MergeFile>\n</Menu>\n"
-	return menu_xml
-
-def getIcon(item, for_properties=False):
-	pixbuf, path = None, None
-	if item == None:
-		if for_properties:
-			return None, None
-		return None
-	if isinstance(item, str):
-		iconName = item
-	else:
-		iconName = item.get_icon()
-	if iconName and not '/' in iconName and iconName[-3:] in ('png', 'svg', 'xpm'):
-		iconName = iconName[:-4]
-	icon_theme = gtk.icon_theme_get_default()
-	try:
-		pixbuf = icon_theme.load_icon(iconName, 24, 0)
-		path = icon_theme.lookup_icon(iconName, 24, 0).get_filename()
-	except:
-		if iconName and '/' in iconName:
-			try:
-				pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(iconName, 24, 24)
-				path = iconName
-			except:
-				pass
-		if pixbuf == None:
-			if for_properties:
-				return None, None
-			if item.get_type() == gmenu.TYPE_DIRECTORY:
-				iconName = 'gnome-fs-directory'
-			elif item.get_type() == gmenu.TYPE_ENTRY:
-				iconName = 'application-default-icon'
-			try:
-				pixbuf = icon_theme.load_icon(iconName, 24, 0)
-				path = icon_theme.lookup_icon(iconName, 24, 0).get_filename()
-			except:
-				return None
-	if pixbuf == None:
-		return None
-	if pixbuf.get_width() != 24 or pixbuf.get_height() != 24:
-		pixbuf = pixbuf.scale_simple(24, 24, gtk.gdk.INTERP_HYPER)
-	if for_properties:
-		return pixbuf, path
-	return pixbuf
+    system_file = getSystemMenuPath(os.path.basename(tree.get_canonical_menu_path()))
+    name = tree.get_root_directory().get_menu_id()
+    menu_xml = "<!DOCTYPE Menu PUBLIC '-//freedesktop//DTD Menu 1.0//EN' 'http://standards.freedesktop.org/menu-spec/menu-1.0.dtd'>\n"
+    menu_xml += "<Menu>\n  <Name>" + name + "</Name>\n  "
+    menu_xml += "<MergeFile type=\"parent\">" + system_file +    "</MergeFile>\n</Menu>\n"
+    return menu_xml
+
+def getIcon(item):
+    pixbuf = None
+    if item is None:
+        return None
+
+    if isinstance(item, GMenu.TreeDirectory):
+        gicon = item.get_icon()
+    elif isinstance(item, GMenu.TreeEntry):
+        app_info = item.get_app_info()
+        gicon = app_info.get_icon()
+    else:
+        return None
+
+    if gicon is None:
+        return None
+
+    icon_theme = Gtk.IconTheme.get_default()
+    info = icon_theme.lookup_by_gicon(gicon, 24, 0)
+    if info is None:
+        return None
+    try:
+        pixbuf = info.load_icon()
+    except GError:
+        return None
+    if pixbuf is None:
+        return None
+    if pixbuf.get_width() != 24 or pixbuf.get_height() != 24:
+        pixbuf = pixbuf.scale_simple(24, 24, GdkPixbuf.InterpType.HYPER)
+    return pixbuf
+
+def removeWhitespaceNodes(node):
+    remove_list = []
+    for child in node.childNodes:
+        if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
+            child.data = child.data.strip()
+            if not child.data.strip():
+                remove_list.append(child)
+        elif child.hasChildNodes():
+            removeWhitespaceNodes(child)
+    for node in remove_list:
+        node.parentNode.removeChild(node)
--- a/files/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui
+++ b/files/usr/lib/cinnamon-menu-editor/cinnamon-menu-editor.ui
@@ -8,22 +8,14 @@
           <object class="GtkAction" id="edit_properties">
             <property name="stock_id">gtk-properties</property>
             <property name="name">edit_properties</property>
-            <signal handler="on_edit_properties_activate" last_modification_time="Sun, 23 Apr 2006 02:16:34 GMT" name="activate"/>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_revert_to_original">
-            <property name="stock_id">gtk-revert-to-saved</property>
-            <property name="name">edit_revert_to_original</property>
-            <property name="label" translatable="yes">_Revert to Original</property>
-            <signal handler="on_edit_revert_to_original_activate" last_modification_time="Sun, 23 Apr 2006 02:16:34 GMT" name="activate"/>
+            <signal handler="on_edit_properties_activate" name="activate"/>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="edit_delete">
             <property name="stock_id">gtk-delete</property>
             <property name="name">edit_delete</property>
-            <signal handler="on_edit_delete_activate" last_modification_time="Sun, 23 Apr 2006 02:16:34 GMT" name="activate"/>
+            <signal handler="on_edit_delete_activate" name="activate"/>
           </object>
         </child>
       </object>
@@ -31,8 +23,6 @@
     <ui>
       <popup name="edit_menu">
         <menuitem action="edit_properties"/>
-        <menuitem action="edit_revert_to_original"/>
-        <separator/>
         <menuitem action="edit_delete"/>
       </popup>
     </ui>
@@ -49,8 +39,8 @@
 </object>
   <object class="GtkDialog" id="mainwindow">
     <property name="border_width">5</property>
-    <property name="width_request">675</property>
-    <property name="height_request">530</property>
+    <property name="default_width">675</property>
+    <property name="default_height">530</property>
     <property name="visible">True</property>
     <property name="title" translatable="yes">Main Menu</property>
     <property name="type">GTK_WINDOW_TOPLEVEL</property>
@@ -65,10 +55,8 @@
     <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
     <property name="focus_on_map">True</property>
     <property name="urgency_hint">False</property>
-    <property name="has_separator">False</property>
-    <signal handler="on_close_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:46:45 GMT" name="close"/>
-    <signal handler="on_close_button_clicked" last_modification_time="Fri, 28 Apr 2006 10:49:37 GMT" name="destroy"/>
-    <signal handler="on_style_set" name="style-set"/>
+    <signal handler="on_close_button_clicked" name="close"/>
+    <signal handler="on_close_button_clicked" name="destroy"/>
     <accelerator key="Escape" modifiers="0" signal="close"/>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox5">
@@ -78,18 +66,30 @@
         <child internal-child="action_area">
           <object class="GtkHButtonBox" id="dialog-action_area5">
             <property name="visible">True</property>
-            <property name="layout_style">GTK_BUTTONBOX_END</property>            
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <object class="GtkButton" id="help_button">
+                <property name="visible">True</property>
+                <property name="can_default">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">gtk-help</property>
+                <property name="use_stock">True</property>
+                <property name="relief">GTK_RELIEF_NORMAL</property>
+                <property name="focus_on_click">True</property>
+                <signal handler="on_help_button_clicked" name="clicked"/>
+              </object>
+            </child>
             <child>
-              <object class="GtkButton" id="revert_button">
+              <object class="GtkButton" id="restore_button">
                 <property name="visible">True</property>
                 <property name="tooltip-text" translatable="yes">Restore the default menu layout</property>
                 <property name="can_default">True</property>
                 <property name="can_focus">True</property>
-                <property name="label">gtk-revert-to-saved</property>
+                <property name="label" translatable="yes">Restore System Configuration</property>
                 <property name="use_stock">True</property>
                 <property name="relief">GTK_RELIEF_NORMAL</property>
                 <property name="focus_on_click">True</property>
-                <signal handler="on_revert_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:38:17 GMT" name="clicked"/>
+                <signal handler="on_restore_button_clicked" name="clicked"/>
               </object>
             </child>
             <child>
@@ -102,7 +102,7 @@
                 <property name="use_stock">True</property>
                 <property name="relief">GTK_RELIEF_NORMAL</property>
                 <property name="focus_on_click">True</property>
-                <signal handler="on_close_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:38:03 GMT" name="clicked"/>
+                <signal handler="on_close_button_clicked" name="clicked"/>
               </object>
             </child>
           </object>
@@ -140,31 +140,6 @@
                         <property name="homogeneous">False</property>
                         <property name="spacing">6</property>
                         <child>
-                          <object class="GtkLabel" id="label20">
-                            <property name="visible">True</property>
-                            <property name="label" translatable="yes">_Menus:</property>
-                            <property name="use_underline">True</property>
-                            <property name="use_markup">False</property>
-                            <property name="justify">GTK_JUSTIFY_LEFT</property>
-                            <property name="wrap">False</property>
-                            <property name="selectable">False</property>
-                            <property name="xalign">0</property>
-                            <property name="yalign">0.5</property>
-                            <property name="xpad">0</property>
-                            <property name="ypad">0</property>
-                            <property name="mnemonic_widget">menu_tree</property>
-                            <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                            <property name="width_chars">-1</property>
-                            <property name="single_line_mode">True</property>
-                            <property name="angle">0</property>
-                          </object>
-                          <packing>
-                            <property name="padding">0</property>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                          </packing>
-                        </child>
-                        <child>
                           <object class="GtkScrolledWindow" id="scrolledwindow3">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
@@ -185,8 +160,6 @@
                                 <property name="hover_selection">False</property>
                                 <property name="hover_expand">False</property>
                                 <signal handler="on_menu_tree_cursor_changed" name="cursor-changed"/>
-                                <signal handler="on_menu_tree_drag_data_received" last_modification_time="Tue, 18 Apr 2006 01:13:34 GMT" name="drag_data_received"/>
-                                <signal handler="on_menu_tree_drag_data_get" last_modification_time="Tue, 18 Apr 2006 23:58:24 GMT" name="drag_data_get"/>
                               </object>
                             </child>
                           </object>
@@ -208,31 +181,6 @@
                         <property name="homogeneous">False</property>
                         <property name="spacing">6</property>
                         <child>
-                          <object class="GtkLabel" id="label21">
-                            <property name="visible">True</property>
-                            <property name="label" translatable="yes">It_ems:</property>
-                            <property name="use_underline">True</property>
-                            <property name="use_markup">False</property>
-                            <property name="justify">GTK_JUSTIFY_LEFT</property>
-                            <property name="wrap">False</property>
-                            <property name="selectable">False</property>
-                            <property name="xalign">0</property>
-                            <property name="yalign">0.5</property>
-                            <property name="xpad">0</property>
-                            <property name="ypad">0</property>
-                            <property name="mnemonic_widget">item_tree</property>
-                            <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                            <property name="width_chars">-1</property>
-                            <property name="single_line_mode">True</property>
-                            <property name="angle">0</property>
-                          </object>
-                          <packing>
-                            <property name="padding">0</property>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                          </packing>
-                        </child>
-                        <child>
                           <object class="GtkHBox" id="hbox16">
                             <property name="visible">True</property>
                             <property name="homogeneous">False</property>
@@ -259,11 +207,9 @@
                                     <signal handler="on_item_tree_row_activated" name="row-activated"/>
                                     <signal handler="on_item_tree_popup_menu" name="popup-menu"/>
                                     <signal handler="on_item_tree_cursor_changed" name="cursor-changed"/>
-                                    <signal handler="on_item_tree_popup_menu" last_modification_time="Thu, 06 Apr 2006 01:25:48 GMT" name="button_press_event"/>
-                                    <signal handler="on_item_tree_drag_data_get" last_modification_time="Tue, 18 Apr 2006 01:13:21 GMT" name="drag_data_get"/>
-                                    <signal handler="on_item_tree_cursor_changed" last_modification_time="Tue, 18 Apr 2006 15:32:26 GMT" name="cursor_changed"/>
-                                    <signal handler="on_item_tree_drag_data_received" last_modification_time="Tue, 18 Apr 2006 23:58:15 GMT" name="drag_data_received"/>
-                                    <signal handler="on_item_tree_key_press_event" last_modification_time="Sun, 23 Apr 2006 02:21:53 GMT" name="key_press_event"/>
+                                    <signal handler="on_item_tree_popup_menu" name="button_press_event"/>
+                                    <signal handler="on_item_tree_cursor_changed" name="cursor_changed"/>
+                                    <signal handler="on_item_tree_key_press_event" name="key_press_event"/>
                                   </object>
                                 </child>
                               </object>
@@ -285,142 +231,28 @@
                                     <property name="spacing">6</property>
                                     <child>
                                       <object class="GtkButton" id="new_menu_button">
+                                        <property name="label" translatable="yes">_New Menu</property>
+                                        <property name="use_underline">True</property>
                                         <property name="visible">True</property>
                                         <property name="can_default">True</property>
                                         <property name="can_focus">True</property>
                                         <property name="relief">GTK_RELIEF_NORMAL</property>
                                         <property name="focus_on_click">True</property>
-                                        <signal handler="on_new_menu_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:04:38 GMT" name="clicked"/>
-                                        <child>
-                                          <object class="GtkAlignment" id="alignment7">
-                                            <property name="visible">True</property>
-                                            <property name="xalign">0.5</property>
-                                            <property name="yalign">0.5</property>
-                                            <property name="xscale">0</property>
-                                            <property name="yscale">0</property>
-                                            <property name="top_padding">0</property>
-                                            <property name="bottom_padding">0</property>
-                                            <property name="left_padding">0</property>
-                                            <property name="right_padding">0</property>
-                                            <child>
-                                              <object class="GtkHBox" id="hbox14">
-                                                <property name="visible">True</property>
-                                                <property name="homogeneous">False</property>
-                                                <property name="spacing">2</property>
-                                                <child>
-                                                  <object class="GtkImage" id="image21">
-                                                    <property name="visible">True</property>
-                                                    <property name="stock">gtk-new</property>
-                                                    <property name="icon_size">4</property>
-                                                    <property name="xalign">0.5</property>
-                                                    <property name="yalign">0.5</property>
-                                                    <property name="xpad">0</property>
-                                                    <property name="ypad">0</property>
-                                                  </object>
-                                                  <packing>
-                                                    <property name="padding">0</property>
-                                                    <property name="expand">False</property>
-                                                    <property name="fill">False</property>
-                                                  </packing>
-                                                </child>
-                                                <child>
-                                                  <object class="GtkLabel" id="label18">
-                                                    <property name="visible">True</property>
-                                                    <property name="label" translatable="yes">_New Menu</property>
-                                                    <property name="use_underline">True</property>
-                                                    <property name="use_markup">False</property>
-                                                    <property name="justify">GTK_JUSTIFY_LEFT</property>
-                                                    <property name="wrap">False</property>
-                                                    <property name="selectable">False</property>
-                                                    <property name="xalign">0.5</property>
-                                                    <property name="yalign">0.5</property>
-                                                    <property name="xpad">0</property>
-                                                    <property name="ypad">0</property>
-                                                    <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                                                    <property name="width_chars">-1</property>
-                                                    <property name="single_line_mode">False</property>
-                                                    <property name="angle">0</property>
-                                                  </object>
-                                                  <packing>
-                                                    <property name="padding">0</property>
-                                                    <property name="expand">False</property>
-                                                    <property name="fill">False</property>
-                                                  </packing>
-                                                </child>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
+                                        <property name="image">new_menu_image</property>
+                                        <signal handler="on_new_menu_button_clicked" name="clicked"/>
                                       </object>
                                     </child>
                                     <child>
                                       <object class="GtkButton" id="new_item_button">
+                                        <property name="label" translatable="yes">Ne_w Item</property>
+                                        <property name="use_underline">True</property>
                                         <property name="visible">True</property>
                                         <property name="can_default">True</property>
                                         <property name="can_focus">True</property>
                                         <property name="relief">GTK_RELIEF_NORMAL</property>
                                         <property name="focus_on_click">True</property>
-                                        <signal handler="on_new_item_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:04:43 GMT" name="clicked"/>
-                                        <child>
-                                          <object class="GtkAlignment" id="alignment8">
-                                            <property name="visible">True</property>
-                                            <property name="xalign">0.5</property>
-                                            <property name="yalign">0.5</property>
-                                            <property name="xscale">0</property>
-                                            <property name="yscale">0</property>
-                                            <property name="top_padding">0</property>
-                                            <property name="bottom_padding">0</property>
-                                            <property name="left_padding">0</property>
-                                            <property name="right_padding">0</property>
-                                            <child>
-                                              <object class="GtkHBox" id="hbox15">
-                                                <property name="visible">True</property>
-                                                <property name="homogeneous">False</property>
-                                                <property name="spacing">2</property>
-                                                <child>
-                                                  <object class="GtkImage" id="image22">
-                                                    <property name="visible">True</property>
-                                                    <property name="stock">gtk-add</property>
-                                                    <property name="icon_size">4</property>
-                                                    <property name="xalign">0.5</property>
-                                                    <property name="yalign">0.5</property>
-                                                    <property name="xpad">0</property>
-                                                    <property name="ypad">0</property>
-                                                  </object>
-                                                  <packing>
-                                                    <property name="padding">0</property>
-                                                    <property name="expand">False</property>
-                                                    <property name="fill">False</property>
-                                                  </packing>
-                                                </child>
-                                                <child>
-                                                  <object class="GtkLabel" id="label19">
-                                                    <property name="visible">True</property>
-                                                    <property name="label" translatable="yes">Ne_w Item</property>
-                                                    <property name="use_underline">True</property>
-                                                    <property name="use_markup">False</property>
-                                                    <property name="justify">GTK_JUSTIFY_LEFT</property>
-                                                    <property name="wrap">False</property>
-                                                    <property name="selectable">False</property>
-                                                    <property name="xalign">0.5</property>
-                                                    <property name="yalign">0.5</property>
-                                                    <property name="xpad">0</property>
-                                                    <property name="ypad">0</property>
-                                                    <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                                                    <property name="width_chars">-1</property>
-                                                    <property name="single_line_mode">False</property>
-                                                    <property name="angle">0</property>
-                                                  </object>
-                                                  <packing>
-                                                    <property name="padding">0</property>
-                                                    <property name="expand">False</property>
-                                                    <property name="fill">False</property>
-                                                  </packing>
-                                                </child>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
+                                        <property name="image">new_item_image</property>
+                                        <signal handler="on_new_item_button_clicked" name="clicked"/>
                                       </object>
                                     </child>
                                     <child>
@@ -432,7 +264,7 @@
                                         <property name="use_underline">True</property>
                                         <property name="relief">GTK_RELIEF_NORMAL</property>
                                         <property name="focus_on_click">True</property>
-                                        <signal handler="on_new_separator_button_clicked" last_modification_time="Wed, 26 Apr 2006 18:04:48 GMT" name="clicked"/>
+                                        <signal handler="on_new_separator_button_clicked" name="clicked"/>
                                       </object>
                                     </child>
                                   </object>
@@ -460,174 +292,58 @@
                                         <property name="spacing">6</property>
                                         <child>
                                           <object class="GtkButton" id="move_up_button">
+                                            <property name="label" translatable="yes">Move Up</property>
                                             <property name="visible">True</property>
                                             <property name="can_default">True</property>
                                             <property name="can_focus">True</property>
                                             <property name="relief">GTK_RELIEF_NORMAL</property>
                                             <property name="focus_on_click">True</property>
-                                            <signal handler="on_move_up_button_clicked" last_modification_time="Wed, 26 Apr 2006 22:09:11 GMT" name="clicked"/>
-                                            <child>
-                                              <object class="GtkAlignment" id="alignment10">
-                                                <property name="visible">True</property>
-                                                <property name="xalign">0.5</property>
-                                                <property name="yalign">0.5</property>
-                                                <property name="xscale">0</property>
-                                                <property name="yscale">0</property>
-                                                <property name="top_padding">0</property>
-                                                <property name="bottom_padding">0</property>
-                                                <property name="left_padding">0</property>
-                                                <property name="right_padding">0</property>
-                                                <child>
-                                                  <object class="GtkHBox" id="hbox17">
-                                                    <property name="visible">True</property>
-                                                    <property name="homogeneous">False</property>
-                                                    <property name="spacing">2</property>
-                                                    <child>
-                                                      <object class="GtkImage" id="image23">
-                                                        <property name="visible">True</property>
-                                                        <property name="stock">gtk-go-up</property>
-                                                        <property name="icon_size">4</property>
-                                                        <property name="xalign">0.5</property>
-                                                        <property name="yalign">0.5</property>
-                                                        <property name="xpad">0</property>
-                                                        <property name="ypad">0</property>
-                                                      </object>
-                                                      <packing>
-                                                        <property name="padding">0</property>
-                                                        <property name="expand">False</property>
-                                                        <property name="fill">False</property>
-                                                      </packing>
-                                                    </child>
-                                                    <child>
-                                                      <object class="GtkLabel" id="label22">
-                                                        <property name="visible">True</property>
-                                                        <property name="label" translatable="yes">Move Up</property>
-                                                        <property name="use_underline">True</property>
-                                                        <property name="use_markup">False</property>
-                                                        <property name="justify">GTK_JUSTIFY_LEFT</property>
-                                                        <property name="wrap">False</property>
-                                                        <property name="selectable">False</property>
-                                                        <property name="xalign">0.5</property>
-                                                        <property name="yalign">0.5</property>
-                                                        <property name="xpad">0</property>
-                                                        <property name="ypad">0</property>
-                                                        <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                                                        <property name="width_chars">-1</property>
-                                                        <property name="single_line_mode">False</property>
-                                                        <property name="angle">0</property>
-                                                      </object>
-                                                      <packing>
-                                                        <property name="padding">0</property>
-                                                        <property name="expand">False</property>
-                                                        <property name="fill">False</property>
-                                                      </packing>
-                                                    </child>
-                                                  </object>
-                                                </child>
-                                              </object>
-                                            </child>
+                                            <property name="image">move_up_image</property>
+                                            <signal handler="on_move_up_button_clicked" name="clicked"/>
                                           </object>
                                         </child>
                                         <child>
                                           <object class="GtkButton" id="move_down_button">
+                                            <property name="label" translatable="yes">Move Down</property>
                                             <property name="visible">True</property>
                                             <property name="can_default">True</property>
                                             <property name="can_focus">True</property>
                                             <property name="relief">GTK_RELIEF_NORMAL</property>
                                             <property name="focus_on_click">True</property>
-                                            <signal handler="on_move_down_button_clicked" last_modification_time="Wed, 26 Apr 2006 22:09:15 GMT" name="clicked"/>
-                                            <child>
-                                              <object class="GtkAlignment" id="alignment11">
-                                                <property name="visible">True</property>
-                                                <property name="xalign">0.5</property>
-                                                <property name="yalign">0.5</property>
-                                                <property name="xscale">0</property>
-                                                <property name="yscale">0</property>
-                                                <property name="top_padding">0</property>
-                                                <property name="bottom_padding">0</property>
-                                                <property name="left_padding">0</property>
-                                                <property name="right_padding">0</property>
-                                                <child>
-                                                  <object class="GtkHBox" id="hbox18">
-                                                    <property name="visible">True</property>
-                                                    <property name="homogeneous">False</property>
-                                                    <property name="spacing">2</property>
-                                                    <child>
-                                                      <object class="GtkImage" id="image24">
-                                                        <property name="visible">True</property>
-                                                        <property name="stock">gtk-go-down</property>
-                                                        <property name="icon_size">4</property>
-                                                        <property name="xalign">0.5</property>
-                                                        <property name="yalign">0.5</property>
-                                                        <property name="xpad">0</property>
-                                                        <property name="ypad">0</property>
-                                                      </object>
-                                                      <packing>
-                                                        <property name="padding">0</property>
-                                                        <property name="expand">False</property>
-                                                        <property name="fill">False</property>
-                                                      </packing>
-                                                    </child>
-                                                    <child>
-                                                      <object class="GtkLabel" id="label23">
-                                                        <property name="visible">True</property>
-                                                        <property name="label" translatable="yes">Move Down</property>
-                                                        <property name="use_underline">True</property>
-                                                        <property name="use_markup">False</property>
-                                                        <property name="justify">GTK_JUSTIFY_LEFT</property>
-                                                        <property name="wrap">False</property>
-                                                        <property name="selectable">False</property>
-                                                        <property name="xalign">0.5</property>
-                                                        <property name="yalign">0.5</property>
-                                                        <property name="xpad">0</property>
-                                                        <property name="ypad">0</property>
-                                                        <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                                                        <property name="width_chars">-1</property>
-                                                        <property name="single_line_mode">False</property>
-                                                        <property name="angle">0</property>
-                                                      </object>
-                                                      <packing>
-                                                        <property name="padding">0</property>
-                                                        <property name="expand">False</property>
-                                                        <property name="fill">False</property>
-                                                      </packing>
-                                                    </child>
-                                                  </object>
-                                                </child>
-                                              </object>
-                                            </child>
+                                            <property name="image">move_down_image</property>
+                                            <signal handler="on_move_down_button_clicked" name="clicked"/>
                                           </object>
                                         </child>
                                         <child>
-                                          <object class="GtkButton" id="properties_button">
-                                            <property name="label" translatable="no">gtk-properties</property>
+                                          <object class="GtkButton" id="delete_button">
+                                            <property name="label" translatable="no">gtk-delete</property>
                                             <property name="visible">True</property>
                                             <property name="can_focus">True</property>
                                             <property name="receives_default">True</property>
                                             <property name="use_stock">True</property>
-					    <signal handler="on_properties_button_clicked" name="clicked"/>
+					    <signal handler="on_delete_button_clicked" name="clicked"/>
                                           </object>
                                           <packing>
                                             <property name="expand">False</property>
                                             <property name="fill">False</property>
                                             <property name="position">2</property>
                                           </packing>
-                                        </child>
+					</child>
                                         <child>
-                                          <object class="GtkButton" id="delete_button">
-                                            <property name="label" translatable="no">gtk-delete</property>
+                                          <object class="GtkButton" id="properties_button">
+                                            <property name="label" translatable="no">gtk-properties</property>
                                             <property name="visible">True</property>
                                             <property name="can_focus">True</property>
                                             <property name="receives_default">True</property>
                                             <property name="use_stock">True</property>
-					    <signal handler="on_delete_button_clicked" name="clicked"/>
+					    <signal handler="on_properties_button_clicked" name="clicked"/>
                                           </object>
                                           <packing>
                                             <property name="expand">False</property>
                                             <property name="fill">False</property>
                                             <property name="position">3</property>
                                           </packing>
-					</child>
+                                        </child>
                                       </object>
                                     </child>
                                   </object>
@@ -675,124 +391,26 @@
         </child>
       </object>
     </child>
-    <action-widgets>      
-      <action-widget response="0">revert_button</action-widget>
+    <action-widgets>
+      <action-widget response="-11">help_button</action-widget>
+      <action-widget response="0">restore_button</action-widget>
       <action-widget response="-7">close_button</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkDialog" id="revertdialog">
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Revert Changes?</property>
-    <property name="type">GTK_WINDOW_TOPLEVEL</property>
-    <property name="window_position">GTK_WIN_POS_NONE</property>
-    <property name="modal">False</property>
-    <property name="resizable">False</property>
-    <property name="destroy_with_parent">False</property>
-    <property name="decorated">True</property>
-    <property name="skip_taskbar_hint">False</property>
-    <property name="skip_pager_hint">False</property>
-    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-    <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-    <property name="focus_on_map">True</property>
-    <property name="urgency_hint">False</property>
-    <property name="has_separator">False</property>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox6">
-        <property name="visible">True</property>
-        <property name="homogeneous">False</property>
-        <property name="spacing">2</property>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area6">
-            <property name="visible">True</property>
-            <property name="layout_style">GTK_BUTTONBOX_END</property>
-            <child>
-              <object class="GtkButton" id="cancel_revert_button">
-                <property name="visible">True</property>
-                <property name="can_default">True</property>
-                <property name="can_focus">True</property>
-                <property name="label">gtk-cancel</property>
-                <property name="use_stock">True</property>
-                <property name="relief">GTK_RELIEF_NORMAL</property>
-                <property name="focus_on_click">True</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkButton" id="button2">
-                <property name="visible">True</property>
-                <property name="can_default">True</property>
-                <property name="can_focus">True</property>
-                <property name="label">gtk-revert-to-saved</property>
-                <property name="use_stock">True</property>
-                <property name="relief">GTK_RELIEF_NORMAL</property>
-                <property name="focus_on_click">True</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="padding">0</property>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="pack_type">GTK_PACK_END</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkHBox" id="hbox19">
-            <property name="border_width">5</property>
-            <property name="visible">True</property>
-            <property name="homogeneous">False</property>
-            <property name="spacing">8</property>
-            <child>
-              <object class="GtkImage" id="image25">
-                <property name="visible">True</property>
-                <property name="icon_size">6</property>
-                <property name="icon_name">gtk-dialog-question</property>
-                <property name="xalign">0</property>
-                <property name="yalign">0.5</property>
-                <property name="xpad">0</property>
-                <property name="ypad">0</property>
-              </object>
-              <packing>
-                <property name="padding">0</property>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="label24">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">Revert all menus to original settings?</property>
-                <property name="use_underline">False</property>
-                <property name="use_markup">False</property>
-                <property name="justify">GTK_JUSTIFY_LEFT</property>
-                <property name="wrap">False</property>
-                <property name="selectable">False</property>
-                <property name="xalign">0</property>
-                <property name="yalign">0</property>
-                <property name="xpad">0</property>
-                <property name="ypad">0</property>
-                <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                <property name="width_chars">-1</property>
-                <property name="single_line_mode">False</property>
-                <property name="angle">0</property>
-              </object>
-              <packing>
-                <property name="padding">0</property>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="padding">0</property>
-            <property name="expand">True</property>
-            <property name="fill">True</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="-6">cancel_revert_button</action-widget>
-      <action-widget response="-8">button2</action-widget>
-    </action-widgets>
+  <object class="GtkImage" id="new_menu_image">
+    <property name="visible">True</property>
+    <property name="stock">gtk-new</property>
+  </object>
+  <object class="GtkImage" id="new_item_image">
+    <property name="visible">True</property>
+    <property name="stock">gtk-add</property>
+  </object>
+  <object class="GtkImage" id="move_down_image">
+    <property name="visible">True</property>
+    <property name="stock">gtk-go-down</property>
+  </object>
+  <object class="GtkImage" id="move_up_image">
+    <property name="visible">True</property>
+    <property name="stock">gtk-go-up</property>
   </object>
 </interface>