Commit 589ba554 authored by William Jon McCann's avatar William Jon McCann Committed by Jasper St. Pierre

Remove the simple editor

gnome-menus is a dependency component and we don't really want it
to be installing applications as a side effect. There are other
better and maintained options for menu editing now anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=684900
parent 7d90221e
SUBDIRS = libmenu desktop-directories layout util po
SUBDIRS += simple-editor
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
......
......@@ -84,8 +84,6 @@ libmenu/libgnome-menu-3.0-uninstalled.pc
layout/Makefile
desktop-directories/Makefile
util/Makefile
simple-editor/Makefile
simple-editor/GMenuSimpleEditor/Makefile
po/Makefile.in
])
......
......@@ -16,8 +16,3 @@ desktop-directories/Utility.directory.in
desktop-directories/X-GNOME-Menu-Applications.directory.in
desktop-directories/X-GNOME-Other.directory.in
desktop-directories/X-GNOME-WebApplications.directory.in
simple-editor/gmenu-simple-editor.desktop.in
[type: gettext/glade]simple-editor/gmenu-simple-editor.ui
simple-editor/GMenuSimpleEditor/main.py
simple-editor/GMenuSimpleEditor/maindialog.py
simple-editor/GMenuSimpleEditor/menufilewriter.py
appdir = $(pyexecdir)/GMenuSimpleEditor
app_PYTHON = \
__init__.py \
main.py \
maindialog.py \
menutreemodel.py \
menufilewriter.py
nodist_app_PYTHON = config.py
config.py: config.py.in
$(AM_V_GEN)sed \
-e s!\@DATADIR\@!$(datadir)! \
-e s!\@LOCALEDIR\@!$(prefix)/$(DATADIRNAME)/locale! \
-e s!\@PACKAGE_NAME\@!$(PACKAGE_NAME)! \
-e s!\@PACKAGE_VERSION\@!$(PACKAGE_VERSION)! \
< $< > $@
EXTRA_DIST = config.py.in
CLEANFILES = config.py
-include $(top_srcdir)/git.mk
# Module init file for the gmenu.editor
#!/usr/bin/env python
#
# Copyright (C) 2005 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os.path
PACKAGE = "@PACKAGE_NAME@"
VERSION = "@PACKAGE_VERSION@"
DATADIR = "@DATADIR@"
LOCALEDIR = "@LOCALEDIR@"
UI_DIR = os.path.join (DATADIR, PACKAGE, "ui")
#
# Copyright (C) 2005 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
def main (args):
import optparse
import locale
import gettext
from gi.repository import GObject
from gi.repository import Gtk
import maindialog
import config
locale.setlocale (locale.LC_ALL, "")
gettext.install (config.PACKAGE, config.LOCALEDIR)
parser = optparse.OptionParser()
parser.add_option('--version', dest='version',
action='store_true', default=False,
help=config.VERSION)
(options, args) = parser.parse_args()
if options.version:
# Translators: %s is the version number
print _("Simple Menu Editor %s") % (config.VERSION)
else:
dialog = maindialog.MenuEditorDialog (args)
Gtk.main ()
#
# Copyright (C) 2005 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os.path
from gi.repository import Gtk
from config import *
import menutreemodel
import menufilewriter
class MenuEditorDialog:
def __init__ (self, menu_files):
ui_file = os.path.join (UI_DIR, "gmenu-simple-editor.ui")
self.ui = Gtk.Builder()
self.ui.set_translation_domain (PACKAGE)
self.ui.add_from_file(ui_file)
self.window = self.ui.get_object ("menu_editor_dialog")
self.window.connect ("destroy", self.__dialog_destroyed)
self.window.set_default_response (Gtk.ResponseType.ACCEPT)
self.window.set_icon_name ("gnome-main-menu")
self.help_button = self.ui.get_object ("help_button")
self.help_button.set_sensitive (False)
self.menus_tree = self.ui.get_object ("menus_treeview")
self.entries_list = self.ui.get_object ("applications_treeview")
self.menu_tree_model = menutreemodel.MenuTreeModel (menu_files)
self.menu_file_writer = menufilewriter.MenuFileWriter (self.menu_tree_model)
self.current_iter = None
self.current_path = None
self.__setup_menus_tree ()
self.__setup_entries_list ()
self.window.connect ("response", self.__dialog_response)
self.window.set_default_size (580, 435)
self.window.show ()
def __revert_to_system_default (self, parent_iter = None):
model = self.menu_tree_model
iter = model.iter_children (parent_iter)
while iter is not None:
if model.get_value (iter, model.COLUMN_IS_ENTRY):
visible = model.get_value (iter, model.COLUMN_SYSTEM_VISIBLE)
model.set_value (iter, model.COLUMN_USER_VISIBLE, visible)
else:
self.__revert_to_system_default (iter)
iter = model.iter_next (iter)
def __dialog_destroyed (self, dialog):
Gtk.main_quit ()
def __dialog_response (self, dialog, response_id):
if response_id == Gtk.ResponseType.REJECT:
self.__revert_to_system_default ()
iter = self.menu_tree_model.get_iter_first ()
while iter is not None:
self.menu_file_writer.queue_sync (iter)
iter = self.menu_tree_model.iter_next (iter)
return
dialog.destroy ()
def __is_menu_tree_directory (self, model, iter, data):
return not model.get_value(iter, self.menu_tree_model.COLUMN_IS_ENTRY)
def __setup_menus_tree (self):
self.menus_model = self.menu_tree_model.filter_new (None)
self.menus_model.set_visible_func (self.__is_menu_tree_directory, None)
self.menus_tree.set_model (self.menus_model)
self.menus_tree.get_selection ().set_mode (Gtk.SelectionMode.BROWSE)
self.menus_tree.get_selection ().connect ("changed", self.__menus_selection_changed)
self.menus_tree.set_headers_visible (False)
column = Gtk.TreeViewColumn (_("Name"))
column.set_spacing (6)
cell = Gtk.CellRendererPixbuf ()
column.pack_start (cell, False)
column.add_attribute (cell, 'gicon', self.menu_tree_model.COLUMN_ICON)
cell = Gtk.CellRendererText ()
column.pack_start (cell, True)
column.add_attribute (cell, 'text', self.menu_tree_model.COLUMN_NAME)
self.menus_tree.append_column (column)
self.menus_tree.expand_all ()
def __setup_entries_list (self):
self.entries_list.get_selection ().set_mode (Gtk.SelectionMode.SINGLE)
self.entries_list.set_headers_visible (True)
column = Gtk.TreeViewColumn (_("Show"))
self.entries_list.append_column (column)
cell = Gtk.CellRendererToggle ()
cell.connect ("toggled", self.__on_hide_toggled)
column.pack_start (cell, False)
column.add_attribute (cell, 'active', self.menu_tree_model.COLUMN_USER_VISIBLE)
column = Gtk.TreeViewColumn (_("Name"))
column.set_spacing (6)
self.entries_list.append_column (column)
cell = Gtk.CellRendererPixbuf ()
column.pack_start (cell, False)
column.add_attribute (cell, 'gicon', self.menu_tree_model.COLUMN_ICON)
cell = Gtk.CellRendererText ()
column.pack_start (cell, True)
column.add_attribute (cell, 'text', self.menu_tree_model.COLUMN_NAME)
def __on_hide_toggled (self, toggle, path):
def toggle_value (model, iter, column):
value = model.get_value (iter, column)
model.set_value (iter, column, not value)
real_path = Gtk.TreePath.new_from_string (path)
child_path = self.entries_model.convert_path_to_child_path (real_path)
child_iter = self.menu_tree_model.get_iter (child_path)
toggle_value (self.menu_tree_model, child_iter, self.menu_tree_model.COLUMN_USER_VISIBLE)
self.menu_file_writer.queue_sync (child_iter)
def __menus_selection_changed (self, selection):
(model, iter) = selection.get_selected ()
if iter is None:
self.entries_list.set_model (None)
return
iter = model.convert_iter_to_child_iter (iter)
self.entries_model = self.menu_tree_model.filter_new (self.menu_tree_model.get_path (iter))
self.entries_model.set_visible_column (self.menu_tree_model.COLUMN_IS_ENTRY)
self.entries_list.set_model (self.entries_model)
#
# Copyright (C) 2005 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import errno
import pwd
from gi.repository import GObject
from gi.repository import Gtk
import menutreemodel
DTD_DECLARATION = '<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"\n' \
' "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">\n\n'
class MenuFileWriterError (Exception):
pass
def get_home_dir ():
try:
pw = pwd.getpwuid (os.getuid ())
if pw.pw_dir:
return pw.pw_dir
except KeyError:
pass
if os.environ.has_key ("HOME"):
return os.environ["HOME"]
else:
raise MenuFileWriterError (_("Cannot find home directory: not set in /etc/passwd and no value for $HOME in environment"))
def get_user_menu_file_path (menu_file):
config_dir = None
if os.environ.has_key ("XDG_CONFIG_HOME"):
config_dir = os.environ["XDG_CONFIG_HOME"]
if not config_dir:
config_dir = os.path.join (get_home_dir (), ".config")
return os.path.join (config_dir, "menus", menu_file)
def write_file (filename, contents):
dir = os.path.dirname (filename)
try:
os.makedirs (dir)
except os.error, (err, str):
if err != errno.EEXIST:
raise
temp = filename + ".new"
try:
f = file (temp, "w")
except:
temp = None
f = file (filename, "w")
try:
f.write (contents)
f.close ()
except:
if temp != None:
os.remove (temp)
raise
if temp != None:
os.rename (temp, filename)
class MenuFileWriter:
def __init__ (self, menu_tree_model):
self.model = menu_tree_model
self.sync_idle_handlers = {}
def __del__ (self):
for (path, id) in self.sync_idle_handlers.items():
GObject.source_remove (id)
def __append_menu (self, contents, indent, iter, system_menu_file = None):
has_changes = False
orig_contents = contents
contents += indent + "<Menu>\n"
contents += indent + " <Name>%s</Name>\n" % self.model.get_value (iter, self.model.COLUMN_ID)
if system_menu_file:
contents += indent + ' <MergeFile type="parent">%s</MergeFile>\n' % system_menu_file
includes = []
excludes = []
child_iter = self.model.iter_children (iter)
while child_iter is not None:
if self.model.get_value (child_iter, self.model.COLUMN_IS_ENTRY):
desktop_file_id = self.model.get_value (child_iter, self.model.COLUMN_ID)
system_visible = self.model.get_value (child_iter, self.model.COLUMN_SYSTEM_VISIBLE)
user_visible = self.model.get_value (child_iter, self.model.COLUMN_USER_VISIBLE)
if not system_visible and user_visible:
includes.append (desktop_file_id)
elif system_visible and not user_visible:
excludes.append (desktop_file_id)
child_iter = self.model.iter_next (child_iter)
if len (includes) > 0:
contents += indent + " <Include>\n"
for desktop_file_id in includes:
contents += indent + " <Filename>%s</Filename>\n" % desktop_file_id
contents += indent + " </Include>\n"
has_changes = True
if len (excludes) > 0:
contents += indent + " <Exclude>\n"
for desktop_file_id in excludes:
contents += indent + " <Filename>%s</Filename>\n" % desktop_file_id
contents += indent + " </Exclude>\n"
has_changes = True
child_iter = self.model.iter_children (iter)
while child_iter is not None:
if not self.model.get_value (child_iter, self.model.COLUMN_IS_ENTRY):
(contents, subdir_has_changes) = self.__append_menu (contents,
indent + " ",
child_iter)
if not has_changes:
has_changes = subdir_has_changes
child_iter = self.model.iter_next (child_iter)
if has_changes:
return (contents + indent + "</Menu>\n", True)
else:
return (orig_contents, False)
def sync (self, iter):
menu_file = self.model.get_value (iter, self.model.COLUMN_MENU_FILE)
system_menu_file = menutreemodel.lookup_system_menu_file (menu_file)
(contents, has_changes) = self.__append_menu (DTD_DECLARATION,
"",
iter,
system_menu_file)
if not has_changes:
try:
os.remove (get_user_menu_file_path (menu_file))
except:
pass
return
write_file (get_user_menu_file_path (menu_file), contents)
def __sync_idle_handler_func (self, path):
del self.sync_idle_handlers[path]
real_path = Gtk.TreePath.new_from_string (path)
iter = self.model.get_iter(real_path)
self.sync (iter)
return False
def queue_sync (self, iter):
def find_menu_file_parent (model, iter):
if model.get_value (iter, model.COLUMN_MENU_FILE):
return iter
parent_iter = model.iter_parent (iter)
if parent_iter is None:
return None
return find_menu_file_parent (model, parent_iter)
menu_file_iter = find_menu_file_parent (self.model, iter)
if menu_file_iter is None:
return
menu_file_path = self.model.get_string_from_iter (menu_file_iter)
if self.sync_idle_handlers.has_key (menu_file_path):
return
id = GObject.idle_add (self.__sync_idle_handler_func, menu_file_path)
self.sync_idle_handlers[menu_file_path] = id
#
# Copyright (C) 2005 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import os.path
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import GMenu
def lookup_system_menu_file (menu_file):
conf_dirs = None
if os.environ.has_key ("XDG_CONFIG_DIRS"):
conf_dirs = os.environ["XDG_CONFIG_DIRS"]
if not conf_dirs:
conf_dirs = "/etc/xdg"
for conf_dir in conf_dirs.split (":"):
menu_file_path = os.path.join (conf_dir, "menus", menu_file)
if os.path.isfile (menu_file_path):
return menu_file_path
return None
class MenuTreeModel (Gtk.TreeStore):
(
COLUMN_IS_ENTRY,
COLUMN_ID,
COLUMN_NAME,
COLUMN_ICON,
COLUMN_MENU_FILE,
COLUMN_SYSTEM_VISIBLE,
COLUMN_USER_VISIBLE
) = range (7)
def __init__ (self, menu_files):
Gtk.TreeStore.__init__ (self, bool, str, str, Gio.Icon, str, bool, bool)
self.entries_list_iter = None
if (len (menu_files) < 1):
menu_files = ["applications.menu"]
for menu_file in menu_files:
if menu_file == "applications.menu" and os.environ.has_key ("XDG_MENU_PREFIX"):
menu_file = os.environ["XDG_MENU_PREFIX"] + menu_file
tree = GObject.new (GMenu.Tree, menu_basename = menu_file, flags = GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.SORT_DISPLAY_NAME)
tree.load_sync ()
self.__append_directory (tree.get_root_directory (), None, False, menu_file)
system_file = lookup_system_menu_file (menu_file)
if system_file:
system_tree = GObject.new (GMenu.Tree, menu_path = system_file, flags = GMenu.TreeFlags.INCLUDE_EXCLUDED|GMenu.TreeFlags.SORT_DISPLAY_NAME)
system_tree.load_sync ()
self.__append_directory (system_tree.get_root_directory (), None, True, menu_file)
def __append_directory (self, directory, parent_iter, system, menu_file):
if not directory:
return
iter = self.iter_children (parent_iter)
while iter is not None:
if self.get_value(iter, self.COLUMN_ID) == directory.get_menu_id ():
break
iter = self.iter_next (iter)
if iter is None:
row = (False, directory.get_menu_id (), directory.get_name (), directory.get_icon (), menu_file, False, False)
iter = self.append (parent_iter, row)
if system:
self.set_value (iter, self.COLUMN_SYSTEM_VISIBLE, True)
else:
self.set_value (iter, self.COLUMN_USER_VISIBLE, True)
dir_iter = directory.iter ()
next_type = dir_iter.next ()
while next_type != GMenu.TreeItemType.INVALID:
current_type = next_type
next_type = dir_iter.next ()
if current_type == GMenu.TreeItemType.DIRECTORY:
child_item = dir_iter.get_directory ()
self.__append_directory (child_item, iter, system, None)
if current_type != GMenu.TreeItemType.ENTRY:
continue
child_item = dir_iter.get_entry ()
child_iter = self.iter_children (iter)
while child_iter is not None:
if self.get_value(child_iter, self.COLUMN_IS_ENTRY) and \
self.get_value(child_iter, self.COLUMN_ID) == child_item.get_desktop_file_id ():
break
child_iter = self.iter_next (child_iter)
if child_iter is None:
app_info = child_item.get_app_info ()
row = (True, child_item.get_desktop_file_id (), app_info.get_display_name (), app_info.get_icon (), None, False, False)
child_iter = self.append (iter, row)
if system:
self.set_value (child_iter, self.COLUMN_SYSTEM_VISIBLE, not child_item.get_is_excluded (),)
else:
self.set_value (child_iter, self.COLUMN_USER_VISIBLE, not child_item.get_is_excluded (),)
SUBDIRS = GMenuSimpleEditor
bin_SCRIPTS = gmenu-simple-editor
gmenu-simple-editor: gmenu-simple-editor.in
$(AM_V_GEN)sed -e s!\@pyexecdir\@!@pyexecdir@! -e s!\@PYTHON\@!@PYTHON@! < $< > $@ && \
chmod a+x $@
uidir = $(pkgdatadir)/ui
ui_DATA = gmenu-simple-editor.ui
desktopdir = $(datadir)/applications
desktop_in_files = gmenu-simple-editor.desktop.in
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_DESKTOP_RULE@
EXTRA_DIST = \
gmenu-simple-editor.in \
$(desktop_in_files) \
$(ui_DATA)
CLEANFILES = \
gmenu-simple-editor \
$(desktop_DATA)
-include $(top_srcdir)/git.mk
[Desktop Entry]
Type=Application
_Name=Menu Editor
Icon=gnome-main-menu
Exec=gmenu-simple-editor
StartupNotify=true
NoDisplay=true
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-menus
X-GNOME-Bugzilla-Component=general
#!@PYTHON@
#
# Copyright (C) 2005 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
if not "@pyexecdir@" in sys.path:
sys.path.insert (0, "@pyexecdir@")
import GMenuSimpleEditor.main
GMenuSimpleEditor.main.main (sys.argv[1:])
<?xml version="1.0"?>
<!--*- mode: xml -*-->
<interface>
<object class="GtkDialog" id="menu_editor_dialog">
<property name="border_width">5</property>
<property name="title" translatable="yes">Edit Menus</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">True</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>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<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_area1">
<property name="visible">True</property>