diff --git a/README.md b/README.md index f6caec73d..84b936408 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Requirements The following packages **MUST** be installed in order for Gramps to work: * **Python** 3.2 or greater - The programming language used by Gramps. https://www.python.org/ -* **GTK** 3.10 or greater - A cross-platform widget toolkit for creating graphical user interfaces. http://www.gtk.org/ +* **GTK** 3.12 or greater - A cross-platform widget toolkit for creating graphical user interfaces. http://www.gtk.org/ * **pygobject** 3.12 or greater - Python Bindings for GLib/GObject/GIO/GTK+ https://wiki.gnome.org/Projects/PyGObject The following three packages with GObject Introspection bindings (the gi packages) diff --git a/gramps/grampsapp.py b/gramps/grampsapp.py index 3e7feb5df..97f737275 100644 --- a/gramps/grampsapp.py +++ b/gramps/grampsapp.py @@ -459,12 +459,12 @@ def run(): if argpars.need_gui(): LOG.debug("A GUI is needed, set it up") try: - from .gui.grampsgui import startgtkloop + from .gui.grampsgui import startgramps # no DISPLAY is a RuntimeError in an older pygtk (e.g. F14's 2.17) except RuntimeError as msg: error += [(_("Configuration error:"), str(msg))] return error - startgtkloop(error, argpars) + startgramps(error, argpars) else: # CLI use of Gramps argpars.print_help() diff --git a/gramps/gui/actiongroup.py b/gramps/gui/actiongroup.py deleted file mode 100644 index f24c73a6f..000000000 --- a/gramps/gui/actiongroup.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2015 Nick Hall -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -""" -A replacement ActionGroup that correctly loads named icons from an icon theme. -""" - -from gi.repository import Gtk - -class ActionGroup(Gtk.ActionGroup): - - def add_actions(self, action_list, **kwargs): - Gtk.ActionGroup.add_actions(self, action_list, **kwargs) - self.fix_icon_name(action_list) - - def add_toggle_actions(self, action_list, **kwargs): - Gtk.ActionGroup.add_toggle_actions(self, action_list, **kwargs) - self.fix_icon_name(action_list) - - def add_radio_actions(self, action_list, **kwargs): - Gtk.ActionGroup.add_radio_actions(self, action_list, **kwargs) - self.fix_icon_name(action_list) - - def fix_icon_name(self, action_list): - for action_tuple in action_list: - if action_tuple[1]: - action = self.get_action(action_tuple[0]) - action.set_icon_name(action_tuple[1]) diff --git a/gramps/gui/displaystate.py b/gramps/gui/displaystate.py index 936bc9d60..758f9a824 100644 --- a/gramps/gui/displaystate.py +++ b/gramps/gui/displaystate.py @@ -28,6 +28,7 @@ #------------------------------------------------------------------------- import os from io import StringIO +import html #------------------------------------------------------------------------- # @@ -65,6 +66,7 @@ from .glade import Glade from gramps.gen.utils.db import navigation_label from .widgets.progressdialog import ProgressMonitor, GtkProgressDialog from .dialog import ErrorDialog +from .uimanager import ActionGroup DISABLED = -1 @@ -246,14 +248,34 @@ class History(Callback): # #------------------------------------------------------------------------- -_RCT_TOP = '' -_RCT_BTM = '' +_RCT_TOP = '' +_RCT_MENU = ''' + + win.%s + %s + ''' +_RCT_BTM = '\n \n' +_RCT_BAR_TOP = ('\n' + 'True\n' + 'False') +_RCT_BAR = ''' + + + win.%s + %s + False + True + +''' +_RCT_BAR_BTM = '\n\n' + from gramps.gen.recentfiles import RecentFiles class RecentDocsMenu: def __init__(self, uistate, state, fileopen): - self.action_group = Gtk.ActionGroup(name='RecentFiles') + self.ui_xml = [] + self.action_group = ActionGroup('RecentFiles') self.active = DISABLED self.uistate = uistate self.uimanager = uistate.uimanager @@ -268,55 +290,52 @@ class RecentDocsMenu: ErrorDialog(_('Cannot load database'), str(err), parent=self.uistate.window) - def build(self): - buf = StringIO() - buf.write(_RCT_TOP) + def build(self, update_menu=True): gramps_rf = RecentFiles() count = 0 if self.active != DISABLED: - self.uimanager.remove_ui(self.active) + self.uimanager.remove_ui(self.ui_xml) self.uimanager.remove_action_group(self.action_group) - self.action_group = Gtk.ActionGroup(name='RecentFiles') self.active = DISABLED - actions = [] + actionlist = [] + menu = _RCT_TOP + bar = _RCT_BAR_TOP rfiles = gramps_rf.gramps_recent_files rfiles.sort(key=lambda x: x.get_time(), reverse=True) - new_menu = Gtk.Menu() + #new_menu = Gtk.Menu() + #new_menu.set_tooltip_text(_("Connect to a recent database")) for item in rfiles: try: - title = item.get_name() + title = html.escape(item.get_name()) filename = os.path.basename(item.get_path()) action_id = "RecentMenu%d" % count - buf.write('' % action_id) - actions.append((action_id, None, title, None, None, - make_callback(item, self.load))) - mitem = Gtk.MenuItem(label=title, use_underline=False) - mitem.connect('activate', make_callback(item, self.load)) - mitem.show() - new_menu.append(mitem) + # add the menuitem for this file + menu += _RCT_MENU % (action_id, title) + # add the action for this file + actionlist.append((action_id, make_callback(item, self.load))) + # add the toolbar menuitem + bar += _RCT_BAR % (action_id, title) except RuntimeError: # ignore no longer existing files _LOG.info("Ignoring the RecentItem %s (%s)" % (title, filename)) count += 1 - buf.write(_RCT_BTM) - self.action_group.add_actions(actions) - self.uimanager.insert_action_group(self.action_group, 1) - self.active = self.uimanager.add_ui_from_string(buf.getvalue()) - self.uimanager.ensure_update() - buf.close() - - if len(rfiles) > 0: - new_menu.show() - self.uistate.set_open_recent_menu(new_menu) + menu += _RCT_BTM + bar += _RCT_BAR_BTM + self.ui_xml = [menu, bar] + self.action_group.add_actions(actionlist) + self.uimanager.insert_action_group(self.action_group) + self.active = self.uimanager.add_ui_from_string(self.ui_xml) + if update_menu: + self.uimanager.update_menu() def make_callback(val, func): - return lambda x: func(val) + return lambda x, y: func(val) from .logger import RotateHandler diff --git a/gramps/gui/editors/editnote.py b/gramps/gui/editors/editnote.py index a80c2682b..7b2756d31 100644 --- a/gramps/gui/editors/editnote.py +++ b/gramps/gui/editors/editnote.py @@ -180,7 +180,6 @@ class EditNote(EditPrimary): self.set_window(win, None, self.get_menu_title()) self.setup_configs('interface.note', 700, 500) - vboxnote = self.top.get_object('vbox131') notebook = self.top.get_object('note_notebook') #recreate start page as GrampsTab @@ -271,7 +270,9 @@ class EditNote(EditPrimary): # create a formatting toolbar if not self.dbstate.db.readonly: vbox = self.top.get_object('container') - vbox.pack_start(self.texteditor.get_toolbar(), False, False, 0) + toolbar, self.action_group = self.texteditor.create_toolbar( + self.uistate.uimanager, self.window) + vbox.pack_start(toolbar, False, False, 0) self.texteditor.set_transient_parent(self.window) # setup initial values for textview and textbuffer diff --git a/gramps/gui/editors/editperson.py b/gramps/gui/editors/editperson.py index cd8276a52..c54c31e86 100644 --- a/gramps/gui/editors/editperson.py +++ b/gramps/gui/editors/editperson.py @@ -676,33 +676,33 @@ class EditPerson(EditPrimary): EditMediaRef(self.dbstate, self.uistate, self.track, media_obj, media_ref, self.load_photo) - def _top_contextmenu(self): + def _top_contextmenu(self, prefix): """ Override from base class, the menuitems and actiongroups for the top of context menu. """ - self.all_action = Gtk.ActionGroup(name="/PersonAll") - self.home_action = Gtk.ActionGroup(name="/PersonHome") - self.track_ref_for_deletion("all_action") - self.track_ref_for_deletion("home_action") + if self.added: + # Don't add items if not a real person yet + return '', [] - self.all_action.add_actions([ - ('ActivePerson', None, _("Make Active Person"), - None, None, self._make_active), - ]) - self.home_action.add_actions([ - ('HomePerson', 'go-home', _("Make Home Person"), - None, None, self._make_home_person), - ]) + _actions = [('ActivePerson', self._make_active), + ('HomePerson', self._make_home_person)] - self.all_action.set_visible(not self.added) - self.home_action.set_visible(not self.added) + ui_top_cm = ( + ''' + + {prefix}.ActivePerson + Make Active Person''' + ''' + + + {prefix}.HomePerson + Make Home Person''' + ''' + + '''.format(prefix=prefix)) - ui_top_cm = ''' - - ''' - - return ui_top_cm, [self.all_action, self.home_action] + return ui_top_cm, _actions def _top_drag_data_get(self, widget, context, sel_data, info, time): if info == DdTargets.PERSON_LINK.app_id: @@ -713,17 +713,21 @@ class EditPerson(EditPrimary): """ Override base class, make inactive home action if not needed. """ + if self.added: + return + home_action = self.uistate.uimanager.get_action(self.action_group, + 'HomePerson') if (self.dbstate.db.get_default_person() and self.obj.get_handle() == self.dbstate.db.get_default_person().get_handle()): - self.home_action.set_sensitive(False) + home_action.set_enabled(False) else: - self.home_action.set_sensitive(True) + home_action.set_enabled(True) - def _make_active(self, obj): + def _make_active(self, obj, value): self.uistate.set_active(self.obj.get_handle(), 'Person') - def _make_home_person(self, obj): + def _make_home_person(self, obj, value): handle = self.obj.get_handle() if handle: self.dbstate.db.set_default_person_handle(handle) diff --git a/gramps/gui/editors/editprimary.py b/gramps/gui/editors/editprimary.py index 567ddb77a..4a8083281 100644 --- a/gramps/gui/editors/editprimary.py +++ b/gramps/gui/editors/editprimary.py @@ -32,6 +32,7 @@ import abc # #------------------------------------------------------------------------- from gi.repository import Gtk +from gi.repository.Gio import SimpleActionGroup #------------------------------------------------------------------------- # @@ -49,6 +50,8 @@ from ..display import display_help from ..dialog import SaveDialog from gramps.gen.lib import PrimaryObject from ..dbguielement import DbGUIElement +from ..uimanager import ActionGroup + class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta): @@ -75,6 +78,7 @@ class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta): self.get_from_gramps_id = get_from_gramps_id self.contexteventbox = None self.__tabs = [] + self.action_group = None ManagedWindow.__init__(self, uistate, track, obj) DbGUIElement.__init__(self, self.db) @@ -184,6 +188,8 @@ class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta): self.dbstate.disconnect(self.dbstate_connect_key) self._cleanup_connects() self._cleanup_on_exit() + if self.action_group: + self.uistate.uimanager.remove_action_group(self.action_group) self.get_from_handle = None self.get_from_gramps_id = None ManagedWindow.close(self) @@ -283,48 +289,62 @@ class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta): return False #build the possible popup menu - self._build_popup_ui() + menu_model = self._build_popup_ui() + if not menu_model: + return False #set or unset sensitivity in popup self._post_build_popup_ui() - menu = self.popupmanager.get_widget('/Popup') - if menu: - menu.popup(None, None, None, None, event.button, event.time) - return True + menu = Gtk.Menu.new_from_model(menu_model) + menu.attach_to_widget(obj, None) + menu.show_all() + if Gtk.MINOR_VERSION < 22: + # ToDo The following is reported to work poorly with Wayland + menu.popup(None, None, None, None, + event.button, event.time) + else: + menu.popup_at_pointer(event) + return True return False def _build_popup_ui(self): """ Create actions and ui of context menu + If you don't need a popup, override this and return None """ from ..plug.quick import create_quickreport_menu - self.popupmanager = Gtk.UIManager() - #add custom actions - (ui_top, action_groups) = self._top_contextmenu() - for action in action_groups : - self.popupmanager.insert_action_group(action, -1) + prefix = str(id(self)) + #get custom ui and actions + (ui_top, actions) = self._top_contextmenu(prefix) #see which quick reports are available now: ui_qr = '' if self.QR_CATEGORY > -1 : - (ui_qr, reportactions) = create_quickreport_menu(self.QR_CATEGORY, - self.dbstate, self.uistate, - self.obj, track=self.track) - self.report_action = Gtk.ActionGroup(name="/PersonReport") - self.report_action.add_actions(reportactions) - self.report_action.set_visible(True) - self.popupmanager.insert_action_group(self.report_action, -1) + (ui_qr, reportactions) = create_quickreport_menu( + self.QR_CATEGORY, self.dbstate, self.uistate, + self.obj, prefix, track=self.track) + actions.extend(reportactions) - popupui = ''' - - ''' + ui_top + ''' - ''' + ui_qr + ''' - - ''' + popupui = ''' + + ''' + ui_top + ''' +
+ ''' + ui_qr + ''' +
+
+
''' - self.popupmanager.add_ui_from_string(popupui) + builder = Gtk.Builder.new_from_string(popupui, -1) - def _top_contextmenu(self): + self.action_group = ActionGroup('EditPopup' + prefix, actions, + prefix) + act_grp = SimpleActionGroup() + self.window.insert_action_group(prefix, act_grp) + self.window.set_application(self.uistate.uimanager.app) + self.uistate.uimanager.insert_action_group(self.action_group, act_grp) + return builder.get_object('Popup') + + def _top_contextmenu(self, prefix): """ Derived class can create a ui with menuitems and corresponding list of actiongroups diff --git a/gramps/gui/grampsgui.py b/gramps/gui/grampsgui.py index a1d273b15..7d01e55ab 100644 --- a/gramps/gui/grampsgui.py +++ b/gramps/gui/grampsgui.py @@ -3,6 +3,7 @@ # # Copyright (C) 2000-2006 Donald N. Allingham # Copyright (C) 2009 Benny Malengier +# Copyright (C) 2018 Paul Culley # # 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 @@ -50,7 +51,365 @@ _ = glocale.translation.gettext MIN_PYGOBJECT_VERSION = (3, 12, 0) PYGOBJ_ERR = False -MIN_GTK_VERSION = (3, 10) +MIN_GTK_VERSION = (3, 12) +UIDEFAULT = ( + ''' + + + + + True + False + + + + 1 + GTK_TOOLBAR_ICONS + + + + gramps + win.Open + ''' + '''Manage databases + _Family Trees + True + + + False + + + + + + + ''' + '''Connect to a recent database + OpenBtnMenu + GTK_RELIEF_NONE + + + + + + + + + + + + + edit-paste + win.Clipboard + ''' + '''Open the Clipboard dialog + Clip_board + True + + + False + + + + + + + + gramps-config + win.ConfigView + ''' + '''Configure the active view + _Configure... + True + + + False + + + + + + + + + + + + gramps-reports + win.Reports + ''' + '''Open the reports dialog + _Reports + True + + + False + + + + + gramps-tools + win.Tools + ''' + '''Open the tools dialog + _Tools + True + + + False + + + + + + + + + + +''') try: #import gnome introspection, part of pygobject @@ -235,9 +594,8 @@ class Gramps: process. It may spawn several windows and control several databases. """ - def __init__(self, argparser): + def __init__(self, argparser, app): from gramps.gen.dbstate import DbState - from . import viewmanager from .viewmanager import ViewManager from gramps.cli.arghandler import ArgHandler from .tipofday import TipOfDay @@ -248,7 +606,7 @@ class Gramps: theme.append_search_path(IMAGE_DIR) dbstate = DbState() - self._vm = ViewManager(dbstate, + self._vm = ViewManager(app, dbstate, config.get("interface.view-categories")) if (lin() @@ -303,68 +661,18 @@ class Gramps: # #------------------------------------------------------------------------- -def __startgramps(errors, argparser): +def startgramps(errors, argparser): """ Main startup function started via GObject.timeout_add First action inside the gtk loop """ - try: - from .dialog import ErrorDialog - #handle first existing errors in GUI fashion - if errors: - for error in errors: - ErrorDialog(error[0], error[1]) # TODO no-parent - Gtk.main_quit() - sys.exit(1) - - if argparser.errors: - for error in argparser.errors: - ErrorDialog(error[0], error[1]) # TODO no-parent - Gtk.main_quit() - sys.exit(1) - - # add gui logger - from .logger import RotateHandler, GtkHandler - form = logging.Formatter( - fmt="%(relativeCreated)d: %(levelname)s: " - "%(filename)s: line %(lineno)d: %(message)s") - # Create the log handlers - rot_h = RotateHandler(capacity=20) - rot_h.setFormatter(form) - # Only error and critical log records should - # trigger the GUI handler. - gtkh = GtkHandler(rotate_handler=rot_h) - gtkh.setFormatter(form) - gtkh.setLevel(logging.ERROR) - logger = logging.getLogger() - logger.addHandler(rot_h) - logger.addHandler(gtkh) - - except: - #make sure there is a clean exit if there is an error in above steps - quit_now = True - exit_code = 1 - LOG.error(_("\nGramps failed to start. " - "Please report a bug about this.\n" - "This could be because of an error " - "in a (third party) View on startup.\n" - "To use another view, don't load a Family Tree, " - "change view, and then load your Family Tree.\n" - "You can also change manually " - "the startup view in the gramps.ini file \n" - "by changing the last-view parameter.\n" - ), exc_info=True) - - # start Gramps, errors stop the gtk loop + app = GrampsApplication(errors, argparser) try: quit_now = False exit_code = 0 - if has_display(): - Gramps(argparser) - else: + if app.run(): print(_("Gramps terminated because of no DISPLAY")) - quit_now = True - exit_code = 1 + except SystemExit as err: quit_now = True if err.code: @@ -395,18 +703,85 @@ def __startgramps(errors, argparser): ), exc_info=True) if quit_now: - #stop gtk loop and quit - Gtk.main_quit() + app.quit() sys.exit(exit_code) - #function finished, return False to stop the timeout_add function calls return False -def startgtkloop(errors, argparser): - """ - We start the gtk loop and run the function to start up Gramps - """ - GLib.timeout_add(100, __startgramps, errors, argparser, priority=100) - if os.path.exists(os.path.join(DATA_DIR, "gramps.accel")): - Gtk.AccelMap.load(os.path.join(DATA_DIR, "gramps.accel")) - Gtk.main() +# we do the following import here to avoid the Gtk require version warning +from .uimanager import UIManager + + +class GrampsApplication(Gtk.Application): + + def __init__(self, errors, argparser): + super().__init__(application_id="org.gramps-project.Gramps") + self.window = None + self.errors = errors + self.argparser = argparser + + def do_startup(self): + Gtk.Application.do_startup(self) + self.uimanager = UIManager(self, UIDEFAULT) + self.uimanager.update_menu(init=True) + + if os.path.exists(os.path.join(DATA_DIR, "gramps.accel")): + self.uimanager.load_accels(os.path.join(DATA_DIR, "gramps.accel")) + try: + from .dialog import ErrorDialog + #handle first existing errors in GUI fashion + if self.errors: + for error in self.errors: + ErrorDialog(error[0], error[1]) # TODO no-parent + Gtk.main_quit() + sys.exit(1) + + if self.argparser.errors: + for error in self.argparser.errors: + ErrorDialog(error[0], error[1]) # TODO no-parent + Gtk.main_quit() + sys.exit(1) + + # add gui logger + from .logger import RotateHandler, GtkHandler + form = logging.Formatter( + fmt="%(relativeCreated)d: %(levelname)s: " + "%(filename)s: line %(lineno)d: %(message)s") + # Create the log handlers + rot_h = RotateHandler(capacity=20) + rot_h.setFormatter(form) + # Only error and critical log records should + # trigger the GUI handler. + gtkh = GtkHandler(rotate_handler=rot_h) + gtkh.setFormatter(form) + gtkh.setLevel(logging.ERROR) + logger = logging.getLogger() + logger.addHandler(rot_h) + logger.addHandler(gtkh) + + except: + #make sure there is a clean exit if error in above steps + exit_code = 1 + LOG.error(_("\nGramps failed to start. " + "Please report a bug about this.\n" + "This could be because of an error " + "in a (third party) View on startup.\n" + "To use another view, don't load a Family Tree, " + "change view, and then load your Family Tree.\n" + "You can also change manually " + "the startup view in the gramps.ini file \n" + "by changing the last-view parameter.\n" + ), exc_info=True) + #stop gtk loop and quit + self.quit() + sys.exit(exit_code) + + def do_activate(self): + # We only allow a single window and raise any existing ones + if not self.window: + # Windows are associated with the application + # when the last one is closed the application shuts down + Gramps(self.argparser, self) + else: + print('Gramps is already running.') + self.window.present() diff --git a/gramps/gui/managedwindow.py b/gramps/gui/managedwindow.py index a6b41a1af..7aa8d0997 100644 --- a/gramps/gui/managedwindow.py +++ b/gramps/gui/managedwindow.py @@ -31,7 +31,7 @@ the create/deletion of dialog windows. #------------------------------------------------------------------------- import os from io import StringIO - +import html #------------------------------------------------------------------------- # # GNOME/GTK @@ -49,6 +49,7 @@ from gramps.gen.const import GLADE_FILE, ICON from gramps.gen.errors import WindowActiveError from gramps.gen.config import config from gramps.gen.constfunc import is_quartz +from .uimanager import ActionGroup from .glade import Glade #------------------------------------------------------------------------- @@ -57,8 +58,8 @@ from .glade import Glade # #------------------------------------------------------------------------- -_win_top = '' -_win_btm = '' +_win_top = '
\n' +_win_btm = '
\n' DISABLED = -1 #----------------------------------------------------------------------- @@ -108,7 +109,7 @@ class GrampsWindowManager: self.uimanager = uimanager self.window_tree = [] self.id2item = {} - self.action_group = Gtk.ActionGroup(name='WindowManger') + self.action_group = ActionGroup(name='WindowManger') self.active = DISABLED self.ui = _win_top + _win_btm @@ -125,9 +126,9 @@ class GrampsWindowManager: """ Enables the UI and action groups """ - self.uimanager.insert_action_group(self.action_group, 1) - self.active = self.uimanager.add_ui_from_string(self.ui) - self.uimanager.ensure_update() + self.uimanager.insert_action_group(self.action_group) + self.active = self.uimanager.add_ui_from_string([self.ui]) + self.uimanager.update_menu() def get_item_from_track(self, track): # Recursively find an item given track sequence @@ -270,31 +271,35 @@ class GrampsWindowManager: def call_back_factory(self, item): if not isinstance(item, list): - def func(obj): + def func(*obj): if item.window_id and self.id2item.get(item.window_id): self.id2item[item.window_id]._present() else: - def func(obj): + def func(*obj): pass return func def generate_id(self, item): - return str(item.window_id) + return 'wm/' + str(item.window_id) def display_menu_list(self, data, action_data, mlist): + menuitem = ('\n' + 'win.%s\n' + '' + '%s...\n' + '\n') if isinstance(mlist, (list, tuple)): i = mlist[0] idval = self.generate_id(i) - data.write('' % idval) - action_data.append(("M:"+idval, None, i.submenu_label, - None, None, None)) + data.write('\n%s\n' % + html.escape(i.submenu_label)) else: i = mlist idval = self.generate_id(i) - data.write('' % idval) - action_data.append((idval, None, i.menu_label, None, None, - self.call_back_factory(i))) + data.write(menuitem % (idval, html.escape(i.menu_label))) + action_data.append((idval, self.call_back_factory(i))) if isinstance(mlist, (list, tuple)) and (len(mlist) > 1): for i in mlist[1:]: @@ -302,20 +307,17 @@ class GrampsWindowManager: self.display_menu_list(data, action_data, i) else: idval = self.generate_id(i) - data.write('' - % self.generate_id(i)) - action_data.append((idval, None, i.menu_label, - None, None, - self.call_back_factory(i))) + data.write(menuitem % (idval, html.escape(i.menu_label))) + action_data.append((idval, self.call_back_factory(i))) if isinstance(mlist, (list, tuple)): - data.write('') + data.write('\n') def build_windows_menu(self): if self.active != DISABLED: self.uimanager.remove_ui(self.active) self.uimanager.remove_action_group(self.action_group) - self.action_group = Gtk.ActionGroup(name='WindowManger') + self.action_group = ActionGroup(name='WindowManger') action_data = [] data = StringIO() diff --git a/gramps/gui/navigator.py b/gramps/gui/navigator.py index 36a86e997..830a466d9 100644 --- a/gramps/gui/navigator.py +++ b/gramps/gui/navigator.py @@ -38,22 +38,21 @@ from gi.repository import Gdk #------------------------------------------------------------------------- from gramps.gen.plug import (START, END) from .pluginmanager import GuiPluginManager -from .actiongroup import ActionGroup +from .uimanager import ActionGroup #------------------------------------------------------------------------- # # Constants # #------------------------------------------------------------------------- -UICATEGORY = ''' - - - %s - - - - -''' +UICATEGORY = '''
+ %s +
+ ''' +UICATAGORYBAR = ''' + %s + + ''' CATEGORY_ICON = { 'Dashboard': 'gramps-gramplet', @@ -88,7 +87,6 @@ class Navigator: self.active_view = None self.ui_category = {} - self.view_toggle_actions = {} self.cat_view_group = None self.merge_ids = [] @@ -139,13 +137,35 @@ class Navigator: """ Load the sidebar plugins. """ + menuitem = ''' + + win.ViewInCatagory + %s + %d %d + + ''' + baritem = ''' + + + win.ViewInCatagory + '%d %d' + %s + %s + %s + + + False + + + ''' + plugman = GuiPluginManager.get_instance() categories = [] views = {} for cat_num, cat_views in enumerate(self.viewmanager.get_views()): uimenuitems = '' - self.view_toggle_actions[cat_num] = [] + uibaritems = '' for view_num, page in enumerate(cat_views): if view_num == 0: @@ -156,26 +176,26 @@ class Navigator: cat_icon = 'gramps-view' categories.append([cat_num, cat_name, cat_icon]) - pageid = 'page_%i_%i' % (cat_num, view_num) - uimenuitems += '\n' % pageid - # id, stock, button text, UI, tooltip, page if view_num < 9: - modifier = "%d" % ((view_num % 9) + 1) - else: - modifier = "" + accel = "%d" % ((view_num % 9) + 1) + self.viewmanager.uimanager.app.set_accels_for_action( + "win.ViewInCatagory('%d %d')" % (cat_num, view_num), + [accel]) + uimenuitems += menuitem % (page[0].name, cat_num, view_num) stock_icon = page[0].stock_icon if stock_icon is None: stock_icon = cat_icon - self.view_toggle_actions[cat_num].append((pageid, - stock_icon, - page[0].name, modifier, page[0].name, view_num)) + uibaritems += baritem % (view_num, cat_num, view_num, + stock_icon, page[0].name, + page[0].name) views[cat_num].append((view_num, page[0].name, stock_icon)) if len(cat_views) > 1: #allow for switching views in a category - self.ui_category[cat_num] = UICATEGORY % uimenuitems + self.ui_category[cat_num] = [UICATEGORY % uimenuitems, + UICATAGORYBAR % uibaritems] for pdata in plugman.get_reg_sidebars(): module = plugman.load_plugin(pdata) @@ -229,12 +249,10 @@ class Navigator: list(map(uimanager.remove_ui, self.merge_ids)) if cat_num in self.ui_category: - self.cat_view_group = ActionGroup(name='viewmenu') - self.cat_view_group.add_radio_actions( - self.view_toggle_actions[cat_num], value=view_num, - on_change=self.cb_view_clicked, user_data=cat_num) - self.cat_view_group.set_sensitive(True) - uimanager.insert_action_group(self.cat_view_group, 1) + action = ('ViewInCatagory', self.cb_view_clicked, '', + str(cat_num) + ' ' + str(view_num)) + self.cat_view_group = ActionGroup('viewmenu', [action]) + uimanager.insert_action_group(self.cat_view_group) mergeid = uimanager.add_ui_from_string(self.ui_category[cat_num]) self.merge_ids.append(mergeid) @@ -245,12 +263,12 @@ class Navigator: return sidebar.view_changed(cat_num, view_num) - def cb_view_clicked(self, radioaction, current, cat_num): + def cb_view_clicked(self, radioaction, value): """ Called when a view is selected from the menu. """ - view_num = radioaction.get_current_value() - self.viewmanager.goto_page(cat_num, view_num) + cat_num, view_num = value.get_string().split() + self.viewmanager.goto_page(int(cat_num), int(view_num)) def __menu_button_pressed(self, button, event): """ diff --git a/gramps/gui/plug/quick/_quickreports.py b/gramps/gui/plug/quick/_quickreports.py index de4d7b6bb..d5c926114 100644 --- a/gramps/gui/plug/quick/_quickreports.py +++ b/gramps/gui/plug/quick/_quickreports.py @@ -63,6 +63,12 @@ from gramps.gen.plug import (CATEGORY_QR_PERSON, CATEGORY_QR_FAMILY, CATEGORY_QR from ._textbufdoc import TextBufDoc from gramps.gen.simple import make_basic_stylesheet +MENUITEM = ('\n' + '{prefix}.{action}\n' + '' + '{label}\n' + '\n') + def flatten(L): """ Flattens a possibly nested list. Removes None results, too. @@ -77,7 +83,7 @@ def flatten(L): retval.append(L) return retval -def create_web_connect_menu(dbstate, uistate, nav_group, handle): +def create_web_connect_menu(dbstate, uistate, nav_group, handle, prefix): """ This functions querries the registered web connects. It collects the connects of the requested category, which must be one of @@ -88,12 +94,12 @@ def create_web_connect_menu(dbstate, uistate, nav_group, handle): handle as input method. A tuple is returned, containing the ui string of the menu, and its associated actions. """ + top = ("\n" + '' + 'Web Connection\n') actions = [] ofile = StringIO() - ofile.write('') - actions.append(('WebConnect', None, _("Web Connect"), None, None, None)) - menu = Gtk.Menu() - menu.show() + ofile.write(top) #select the web connects to show showlst = [] pmgr = GuiPluginManager.get_instance() @@ -109,16 +115,17 @@ def create_web_connect_menu(dbstate, uistate, nav_group, handle): connections.sort(key=lambda plug: plug.name) actions = [] for connect in connections: - ofile.write('' % connect.key) - actions.append((connect.key, None, connect.name, None, None, - connect(dbstate, uistate, nav_group, handle))) - ofile.write('') - retval = [ofile.getvalue()] - retval.extend(actions) - return retval + action = connect.key.replace(' ', '-') + ofile.write(MENUITEM.format(prefix=prefix, action=action, + label=connect.name)) + callback = connect(dbstate, uistate, nav_group, handle) + actions.append((action, + lambda x, y: callback(x))) + ofile.write('\n') + return (ofile.getvalue(), actions) -def create_quickreport_menu(category, dbstate, uistate, handle, track=[]): +def create_quickreport_menu(category, dbstate, uistate, handle, prefix, track=[]): """ This functions querries the registered quick reports with quick_report_list of _PluginMgr.py It collects the reports of the requested category, which must be one of @@ -132,39 +139,35 @@ def create_quickreport_menu(category, dbstate, uistate, handle, track=[]): A tuple is returned, containing the ui string of the quick report menu, and its associated actions """ - + top = ("\n" + '' + 'Quick View\n') actions = [] ofile = StringIO() - ofile.write('') - - actions.append(('QuickReport', None, _("Quick View"), None, None, None)) - - menu = Gtk.Menu() - menu.show() + ofile.write(top) #select the reports to show showlst = [] pmgr = GuiPluginManager.get_instance() for pdata in pmgr.get_reg_quick_reports(): if pdata.supported and pdata.category == category : - #add tuple function, translated name, name, status showlst.append(pdata) showlst.sort(key=lambda x: x.name) for pdata in showlst: new_key = pdata.id.replace(' ', '-') - ofile.write('' % new_key) - actions.append((new_key, None, pdata.name, None, None, - make_quick_report_callback(pdata, category, dbstate, - uistate, handle, track=track))) - ofile.write('') + ofile.write(MENUITEM.format(prefix=prefix, action=new_key, + label=pdata.name)) + actions.append((new_key, make_quick_report_callback( + pdata, category, dbstate, uistate, handle, track=track))) + ofile.write('\n') return (ofile.getvalue(), actions) def make_quick_report_callback(pdata, category, dbstate, uistate, handle, track=[]): - return lambda x: run_report(dbstate, uistate, category, handle, pdata, - track=track) + return lambda x, y: run_report(dbstate, uistate, category, handle, pdata, + track=track) def get_quick_report_list(qv_category=None): """ diff --git a/gramps/gui/uimanager.py b/gramps/gui/uimanager.py new file mode 100644 index 000000000..c272bccc6 --- /dev/null +++ b/gramps/gui/uimanager.py @@ -0,0 +1,514 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2018 Paul Culley +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" +A replacement UIManager and ActionGroup. +""" + +import copy +import sys +import logging +import xml.etree.ElementTree as ET + +from gi.repository import GLib, Gio, Gtk + +from ..gen.config import config + + +LOG = logging.getLogger('gui.uimanager') + + +ACTION_NAME = 0 # tuple index for action name +ACTION_CB = 1 # tuple index for action callback +ACTION_ACC = 2 # tuple index for action accelerator +ACTION_ST = 3 # tuple index for action state + + +class ActionGroup(): + """ This class represents a group of actions that con be manipulated + together. + """ + def __init__(self, name, actionlist=None, prefix='win'): + """ + @param name: the action group name, used to match to the 'groups' + attribute in the ui xml. + @type name: string + @type actionlist: list + @param actionlist: the list of actions to add + The list contains tuples with the following contents: + string: Action Name + method: signal callback function. + None if just adding an accelerator + string: accelerator ex: 'Enter' or '' for no accelerator. + optional for non-stateful actions. + state: initial state for stateful actions. + 'True' or 'False': the action is interpreted as a checkbox. + 'None': non stateful action (optional) + 'string': the action is interpreted as a Radio button + @type prefix: str + @param prefix: the prefix used by this group. If not provided, 'win' + is assumed. + """ + self.name = name + self.actionlist = actionlist if actionlist else [] + self.prefix = prefix + '.' + self.act_group = None + self.sensitive = True + + def add_actions(self, actionlist): + """ Add a list of actions to the current list + @type actionlist: list + @param actionlist: the list of actions to add + """ + self.actionlist.extend(actionlist) + + +class UIManager(): + """ + This is Gramps UIManager, it is designed to replace the deprecated Gtk + UIManager. The replacement is not exact, but performs similar + functions, in some case with the same method names and parameters. + It is designed to be a singleton. The menu portion of this is responsible + only for Gramps main window menus and toolbar. + This was implemented to extend Gtk.Builder functions to allow editing + (merging) of the original builder XML with additional XML fragments during + operations. This allows changing of the menus and toolbar when the tree is + loaded, views are changed etc. + + The ActionGroup portions can also be used by other windows. Other windows + needing menus or toolbars can create them via Gtk.Builder. + """ + + def __init__(self, app, initial_xml): + """ + @param app: Gramps Gtk.Application reference + @type app: Gtk.Application + @param initial_xml: Initial (primary) XML string for Gramps menus and + toolbar + @type changexml: string + + The xml is basically Gtk Builder xml, in particular the various menu + and toolbar elements. It is possible to add other elements as well. + The xml this supports has been extended in two ways; + 1) there is an added "groups=" attribute to elements. This + attribute associates the element with one or more named ActionGroups + for making the element visible or not. If 'groups' is missing, the + element will be shown as long as enclosing elements are shown. The + element will be shown if the group is present and considered visible + by the uimanager. If more than one group is needed, they should be + separated by a space. + 2) there is an added tag supported; this is used to mark + a place where merged UI XML can be inserted. During the update_menu + processing, elements enclosed in this tag pair are promoted to the + level of the placeholder tag, and the placeholder tag is removed. + + Note that any elements can be merged (replaced) by the + add_ui_from_string method, not just placeholders. This works by + matching the "id=" attribute on the element, and replacing the + original element with the one from the add method. + + Note that when added elements are removed by the remove_ui method, they + are replaced by the containing xml (with the 'id=') only, so don't put + anything inside of the containing xml to start with as it will be lost + during editing. + """ + self.app = app # the Gtk.Application of Gramps + self.et_xml = ET.fromstring(initial_xml) + self.builder = None + self.toolbar = None + self.action_groups = [] # current list of action groups + self.show_groups = ['RW', 'RO'] # groups to show at the moment + self.accel_dict = {} # used to store accel overrides from file + + def update_menu(self, init=False): + """ This updates the menus and toolbar when there is a change in the + ui; any addition or removal or set_visible operation needs to call + this. It is best to make the call only once, at the end, if multiple + changes are to be made. + It starts with the ET xml stored in self, cleans it up to meet the + Gtk.Builder specifications, and then updates the ui. + + @param init: When True, this is first call and we set the builder + toolbar and menu to the application. + When False, we update the menus and toolbar + @type init: bool + """ + + def iterator(parents): + """ This recursively goes through the ET xml and deals with the + 'groups' attribute and tags, which are not valid for + builder. Empty submenus are also removed. + Groups processing removes elements that are not shown, as well as + the 'groups' attribute itself. + tags are removed and their enclosed elements are + promoted to the level of the placeholder. + + @param parents: the current element to recursively process + @type parents: ET element + """ + indx = 0 + while indx < len(parents): + child = parents[indx] + if len(child) >= 1: + # Recurse until we have a stand-alone child + iterator(child) + if((len(child) == 1 and child.tag == "submenu") or + (len(child) == 0 and child.tag == "section")): + # remove empty submenus and sections + # print('del', child.tag, child.attrib) + del parents[indx] + continue + # print(child.attrib) + groups = child.get('groups') + if not groups: + indx += 1 + continue + del child.attrib['groups'] + for group in groups.split(' '): + if group in self.show_groups: + indx += 1 + break + else: + #print('del', child.tag, child.attrib, parents.tag, + # parents.attrib) + del parents[indx] + break + # The following looks for 'placeholder' elements and if found, + # promotes any children to the same level as the placeholder. + # this allows the user to insert elements without using a section. + indx = 0 + while indx < len(parents): + if parents[indx].tag == "placeholder": + subtree = parents[indx] + #print('placholder del', parents[indx].tag, + # parents[indx].attrib, parents.tag, parents.attrib) + del parents[indx] + for child in subtree: + parents.insert(indx, child) + indx += 1 + else: + indx += 1 + + if self.builder: + toolbar = self.builder.get_object("ToolBar") # previous toolbar + + # need to copy the tree so we can preserve original for later edits. + editable = copy.deepcopy(self.et_xml) + iterator(editable) # clean up tree to builder specifications + xml_str = ET.tostring(editable, encoding="unicode") + #print(xml_str) + self.builder = Gtk.Builder.new_from_string(xml_str, -1) + if init: + self.app.menubar = self.builder.get_object("menubar") + self.app.set_menubar(self.app.menubar) + return + # The following is the only way I have found to update the menus. + # app.set_menubar can apparently only be used once, before + # ApplicationWindow creation, further uses do NOT cause the menus to + # update. + self.app.menubar.remove_all() + section = self.builder.get_object('menubar-update') + self.app.menubar.append_section(None, section) + + # the following updates the toolbar from the new builder + toolbar_parent = toolbar.get_parent() + tb_show = toolbar.get_visible() + toolbar_parent.remove(toolbar) + toolbar = self.builder.get_object("ToolBar") # new toolbar + toolbar_parent.pack_start(toolbar, False, True, 0) + if tb_show: + toolbar.show_all() + else: + toolbar.hide() + #print('*** Update ui') + + def add_ui_from_string(self, changexml): + """ This performs a merge operation on the xml elements that have + matching 'id's between the current ui xml and change xml strings. + The 'changexml' is a list of xml fragment strings used to replace + matching elements in the current xml. + + There MUST one and only one matching id in the orig xml. + @param changexml: list of xml fragments to merge into main + @type changexml: list + @return: changexml + """ + try: + for xml in changexml: + if not xml: + # allow an xml fragment to be an empty string + continue + update = ET.fromstring(xml) + el_id = update.attrib['id'] + # find the parent of the id'd element in original xml + parent = self.et_xml.find(".//*[@id='%s'].." % el_id) + if parent: + # we found it, now delete original, inset updated + for indx in range(len(parent)): + if parent[indx].get('id') == el_id: + del parent[indx] + parent.insert(indx, update) + else: + # updated item not present in original, just add it + # This allow addition of popups etc. + self.et_xml.append(update) + #results = ET.tostring(self.et_xml, encoding="unicode") + #print(results) + #print ('*** Add ui') + return changexml + except: + # the following is only here to assist debug + print('*****', sys.exc_info()) + print(xml) + print(changexml) + assert False + + def remove_ui(self, change_xml): + """ This removes the 'change_xml' from the current ui xml. It works on + any element with matching 'id', the actual element remains but any + children are removed. + The 'change_xml' is a list of xml strings originally used to replace + matching elements in the current ui xml. + @param change_xml: list of xml fragments to remove from main + @type change_xml: list + """ +# if not change_xml: +# import pydevd +# pydevd.settrace() + for xml in change_xml: + if not xml: + continue + update = ET.fromstring(xml) + el_id = update.attrib['id'] + # find parent of id'd element + element = self.et_xml.find(".//*[@id='%s']" % el_id) + if element: # element may have already been deleted + for dummy in range(len(element)): + del element[0] + #results = ET.tostring(self.et_xml, encoding="unicode") + #print(results) + #print ('*** Remove ui') + return + + def get_widget(self, obj): + """ Get the object from the builder. + @param obj: the widget to get + @type obj: string + @return: the object + """ + return self.builder.get_object(obj) + + def insert_action_group(self, group, gio_group=None): + """ + This inserts (actually overwrites any matching actions) the action + group's actions to the app. + By default (with no gio_group), the action group is added to the main + Gramps window and the group assumes a 'win' prefix. + If not using the main window, the window MUST have the 'application' + property set for the accels to work. In this case the actiongroups + must be created like the following: + + # create Gramps ActionGroup + self.action_group = ActionGroup('name', actions, 'prefix') + # create Gio action group + act_grp = SimpleActionGroup() + # associate window with Gio group and its prefix + window.insert_action_group('prefix', act_grp) + # make the window 'application' aware + window.set_application(uimanager.app) + # tell the uimanager about the groups. + uimanager.insert_action_group(self.action_group, act_grp) + + @param group: the action group + @type group: ActionGroup + @param gio_group: the Gio action group associated with a window. + @type gio_group: Gio.SimpleActionGroup + """ + try: + assert isinstance(group.actionlist, list) + if gio_group: + window_group = group.act_group = gio_group + elif group.act_group: + window_group = group.act_group + else: + window_group = group.act_group = self.app.window + for item in group.actionlist: + # deal with accelerator overrides from a file + accel = self.accel_dict.get(group.prefix + item[ACTION_NAME]) + if accel: + self.app.set_accels_for_action( + group.prefix + item[ACTION_NAME], [accel]) + elif len(item) > 2 and item[ACTION_ACC]: + # deal with accelerators defined in the group + accels = self.app.get_actions_for_accel(item[ACTION_ACC]) + if accels: + # diagnostic printout; a duplicate accelerator may be + # a problem if both are valid for the same window at + # the same time. If the actions are for a different + # window, this is not an error. Here we assume a + # different prefix is used for different windows. + for accel in accels: + if group.prefix in accel: + LOG.warning('**Duplicate Accelerator %s', + item[ACTION_ACC]) + self.app.set_accels_for_action( + group.prefix + item[ACTION_NAME], [item[ACTION_ACC]]) + if len(item) <= 3: + # Normal stateless actions + action = Gio.SimpleAction.new(item[ACTION_NAME], None) + if item[ACTION_CB]: # in case we have only accelerator + action.connect("activate", item[ACTION_CB]) + elif isinstance(item[ACTION_ST], str): + # Radio Actions + action = Gio.SimpleAction.new_stateful( + item[ACTION_NAME], GLib.VariantType.new("s"), + GLib.Variant("s", item[ACTION_ST])) + action.connect("change-state", item[ACTION_CB]) + elif isinstance(item[ACTION_ST], bool): + # Checkbox actions + action = Gio.SimpleAction.new_stateful( + item[ACTION_NAME], None, + GLib.Variant.new_boolean(item[ACTION_ST])) + action.connect("change-state", item[ACTION_CB]) + window_group.add_action(action) + self.action_groups.append(group) + # if action sensitivity was set prior to actually inserting into + # UIManager, we need to do it now that we have the action + if not group.sensitive: + self.set_actions_sensitive(group, False) + except: + # the following is only to assist in debug + print(group.name, item) + assert False + + def remove_action_group(self, group): + """ This removes the ActionGroup from the UIManager + + @param group: the action group + @type group: ActionGroup + """ + if group.act_group: + window_group = group.act_group + else: + window_group = self.app.window + for item in group.actionlist: + window_group.remove_action(item[ACTION_NAME]) + self.app.set_accels_for_action(group.prefix + item[ACTION_NAME], + []) + self.action_groups.remove(group) + + def get_action_groups(self): + """ This returns a list of action Groups installed into the UIManager. + @return: list of groups + """ + return self.action_groups + + def set_actions_sensitive(self, group, value): + """ This sets an ActionGroup enabled or disabled. A disabled action + will be greyed out in the UI. + + @param group: the action group + @type group: ActionGroup + @param value: the state of the group + @type value: bool + """ + if group.act_group: + for item in group.actionlist: + action = group.act_group.lookup_action(item[ACTION_NAME]) + if action: + # We check in case the group has not been inserted into + # UIManager yet + action.set_enabled(value) + group.sensitive = value + + def get_actions_sensitive(self, group): + """ This gets an ActionGroup sensitive setting. A disabled action + will be greyed out in the UI. + We assume that the first action represents the group. + + @param group: the action group + @type group: ActionGroup + @return: the state of the group + """ + item = group.actionlist[0] + action = group.act_group.lookup_action(item[ACTION_NAME]) + return action.get_enabled() + + def set_actions_visible(self, group, value): + """ This sets an ActionGroup visible and enabled or invisible and + disabled. Make sure that the menuitems or sections and toolbar items + have the 'groups=' xml attribute matching the group name for this to + work correctly. + + @param group: the action group + @type group: ActionGroup + @param value: the state of the group + @type value: bool + """ + self.set_actions_sensitive(group, value) + if value: + if group.name not in self.show_groups: + self.show_groups.append(group.name) + else: + if group.name in self.show_groups: + self.show_groups.remove(group.name) + + def get_action(self, group, actionname): + """ Return a single action from the group. + @param group: the action group + @type group: ActionGroup + @param actionname: the action name + @type actionname: string + @return: Gio.Action + """ + return group.act_group.lookup_action(actionname) + + def dump_all_accels(self): + ''' A function used diagnostically to see what accels are present. + This will only dump the current accel set, if other non-open windows + or views have accels, you will need to open them and run this again + and manually merge the result files. The results are in a + 'gramps.accel' file located in the current working directory.''' + out_dict = {} + for group in self.action_groups: + for item in group.actionlist: + act = group.prefix + item[ACTION_NAME] + accels = self.app.get_accels_for_action( + group.prefix + item[ACTION_NAME]) + out_dict[act] = accels[0] if accels else '' + import json + with open('gramps.accel', 'w', ) as hndl: + accels = json.dumps(out_dict, indent=0).replace('\n"', '\n# "') + hndl.write(accels) + + def load_accels(self, filename): + """ This function loads accels from a file such as created by + dump_all_accels. The file contents is basically a Python dict + definition. As such it contains a line for each dict element. + These elements can be commented out with '#' at the beginning of the + line. + + If used, this file overrides the accels defined in other Gramps code. + As such it must be loaded before any insert_action_group calls. + """ + import ast + with open(filename, 'r') as hndl: + accels = hndl.read() + self.accel_dict = ast.literal_eval(accels) diff --git a/gramps/gui/viewmanager.py b/gramps/gui/viewmanager.py index b314fa6e9..a1bb0a7fd 100644 --- a/gramps/gui/viewmanager.py +++ b/gramps/gui/viewmanager.py @@ -40,6 +40,7 @@ import datetime from io import StringIO import posixpath import gc +import html #------------------------------------------------------------------------- # @@ -92,7 +93,7 @@ from .configure import GrampsPreferences from .aboutdialog import GrampsAboutDialog from .navigator import Navigator from .views.tags import Tags -from .actiongroup import ActionGroup +from .uimanager import ActionGroup from gramps.gen.lib import (Person, Surname, Family, Media, Note, Place, Source, Repository, Citation, Event, EventType, ChildRef) @@ -107,148 +108,20 @@ from .managedwindow import ManagedWindow # Constants # #------------------------------------------------------------------------- -if is_quartz(): - try: - import gi - gi.require_version('GtkosxApplication', '1.0') - from gi.repository import GtkosxApplication as QuartzApp - _GTKOSXAPPLICATION = True - except: - print("Failed to import gtk_osxapplication") - _GTKOSXAPPLICATION = False -else: - _GTKOSXAPPLICATION = False +# if is_quartz(): + # try: + # import gi + # gi.require_version('GtkosxApplication', '1.0') + # from gi.repository import GtkosxApplication as QuartzApp + # _GTKOSXAPPLICATION = True + # except: + # print("Failed to import gtk_osxapplication") + # _GTKOSXAPPLICATION = False +# else: + # _GTKOSXAPPLICATION = False _UNSUPPORTED = ("Unsupported", _("Unsupported")) -UIDEFAULT = ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' - WIKI_HELP_PAGE_FAQ = '%s_-_FAQ' % URL_MANUAL_PAGE WIKI_HELP_PAGE_KEY = '%s_-_Keybindings' % URL_MANUAL_PAGE WIKI_HELP_PAGE_MAN = '%s' % URL_MANUAL_PAGE @@ -289,18 +162,19 @@ class ViewManager(CLIManager): """ - def __init__(self, dbstate, view_category_order, user=None): + def __init__(self, app, dbstate, view_category_order, user=None): """ The viewmanager is initialised with a dbstate on which Gramps is working, and a fixed view_category_order, which is the order in which the view categories are accessible in the sidebar. """ CLIManager.__init__(self, dbstate, setloader=False, user=user) - if _GTKOSXAPPLICATION: - self.macapp = QuartzApp.Application() - self.macapp.set_use_quartz_accelerators(False) + # if _GTKOSXAPPLICATION: + # self.macapp = QuartzApp.Application() + # self.macapp.set_use_quartz_accelerators(False) self.view_category_order = view_category_order + self.app = app #set pluginmanager to GUI one self._pmgr = GuiPluginManager.get_instance() @@ -329,8 +203,8 @@ class ViewManager(CLIManager): uistate=self.uistate, dbstate=self.dbstate) self.__connect_signals() - if _GTKOSXAPPLICATION: - self.macapp.ready() + # if _GTKOSXAPPLICATION: + # self.macapp.ready() self.do_reg_plugins(self.dbstate, self.uistate) #plugins loaded now set relationship class @@ -391,7 +265,8 @@ class ViewManager(CLIManager): horiz_position = config.get('interface.main-window-horiz-position') vert_position = config.get('interface.main-window-vert-position') - self.window = Gtk.Window() + self.window = Gtk.ApplicationWindow(application=self.app) + self.app.window = self.window self.window.set_icon_from_file(ICON) self.window.set_default_size(width, height) self.window.move(horiz_position, vert_position) @@ -419,14 +294,12 @@ class ViewManager(CLIManager): self.__build_ui_manager() hpane.add2(self.notebook) - self.menubar = self.uimanager.get_widget('/MenuBar') - self.toolbar = self.uimanager.get_widget('/ToolBar') - self.__attach_menubar(vbox) - vbox.pack_start(self.toolbar, False, True, 0) - vbox.pack_start(hpane, True, True, 0) + toolbar = self.uimanager.get_widget('ToolBar') self.statusbar = Statusbar() self.statusbar.show() vbox.pack_end(self.statusbar, False, True, 0) + vbox.pack_start(toolbar, False, True, 0) + vbox.pack_end(hpane, True, True, 0) vbox.show() self.uistate = DisplayState(self.window, self.statusbar, @@ -441,28 +314,21 @@ class ViewManager(CLIManager): self.tags = Tags(self.uistate, self.dbstate) - self.sidebar_menu = self.uimanager.get_widget( - '/MenuBar/ViewMenu/Sidebar/') - - # handle OPEN button, insert it into the toolbar. Unfortunately, - # UIManager has no built in support for and Open Recent button - - openbtn = self.__build_open_button() - self.uistate.set_open_widget(openbtn) - self.toolbar.insert(openbtn, 0) - + # handle OPEN Recent Menu, insert it into the toolbar. self.recent_manager = RecentDocsMenu( self.uistate, self.dbstate, self._read_recent_file) - self.recent_manager.build() + self.recent_manager.build(update_menu=False) self.db_loader = DbLoader(self.dbstate, self.uistate) self.__setup_navigator() + # need to get toolbar again, because it is a new object now. + toolbar = self.uimanager.get_widget('ToolBar') if self.show_toolbar: - self.toolbar.show() + toolbar.show() else: - self.toolbar.hide() + toolbar.hide() if self.fullscreen: self.window.fullscreen() @@ -480,185 +346,110 @@ class ViewManager(CLIManager): else: self.ebox.hide() - def __build_open_button(self): - """ - Build the OPEN button. Since GTK's UIManager does not have support for - the Open Recent button, we must build in on our own. - """ - openbtn = Gtk.MenuToolButton() - openbtn.set_icon_name('gramps') - openbtn.connect('clicked', self.__open_activate) - openbtn.set_sensitive(False) - openbtn.set_tooltip_text(_("Connect to a recent database")) - openbtn.show() - return openbtn - def __connect_signals(self): """ Connects the signals needed """ self.window.connect('delete-event', self.quit) self.notebook.connect('switch-page', self.view_changed) - if _GTKOSXAPPLICATION: - self.macapp.connect('NSApplicationWillTerminate', self.quit) + # if _GTKOSXAPPLICATION: + # self.macapp.connect('NSApplicationWillTerminate', self.quit) def __init_lists(self): """ Initialize the actions lists for the UIManager """ self._file_action_list = [ - ('FileMenu', None, _('_Family Trees')), - ('Open', 'gramps-db', _('_Manage Family Trees...'), "o", - _("Manage databases"), self.__open_activate), - ('OpenRecent', None, _('Open _Recent'), None, - _("Open an existing database")), - ('Quit', 'application-exit', _('_Quit'), "q", None, - self.quit), - ('ViewMenu', None, _('_View')), - ('EditMenu', None, _('_Edit')), - ('Preferences', 'preferences-system', _('_Preferences...'), None, - None, self.preferences_activate), - ('HelpMenu', None, _('_Help')), - ('HomePage', None, _('Gramps _Home Page'), None, None, - home_page_activate), - ('MailingLists', None, _('Gramps _Mailing Lists'), None, None, - mailing_lists_activate), - ('ReportBug', None, _('_Report a Bug'), None, None, - report_bug_activate), - ('ExtraPlugins', None, _('_Extra Reports/Tools'), None, None, - extra_plugins_activate), - ('About', 'help-about', _('_About'), None, None, - self.display_about_box), - ('PluginStatus', None, _('_Plugin Manager'), None, None, - self.__plugin_status), - ('FAQ', None, _('_FAQ'), None, None, faq_activate), - ('KeyBindings', None, _('_Key Bindings'), None, None, key_bindings), - ('UserManual', 'help-browser', _('_User Manual'), 'F1', None, - manual_activate), - ('TipOfDay', None, _('Tip of the Day'), None, None, - self.tip_of_day_activate), - ] + #('FileMenu', None, _('_Family Trees')), + ('Open', self.__open_activate, "o"), + #('OpenRecent'_("Open an existing database")), + ('Quit', self.quit, "q"), + #('ViewMenu', None, _('_View')), + ('Navigator', self.navigator_toggle, "m", + self.show_navigator), + ('Toolbar', self.toolbar_toggle, '', self.show_toolbar), + ('Fullscreen', self.fullscreen_toggle, "F11", self.fullscreen), + #('EditMenu', None, _('_Edit')), + ('Preferences', self.preferences_activate), + #('HelpMenu', None, _('_Help')), + ('HomePage', home_page_activate), + ('MailingLists', mailing_lists_activate), + ('ReportBug', report_bug_activate), + ('ExtraPlugins', extra_plugins_activate), + ('About', self.display_about_box), + ('PluginStatus', self.__plugin_status), + ('FAQ', faq_activate), + ('KeyBindings', key_bindings), + ('UserManual', manual_activate, 'F1'), + ('TipOfDay', self.tip_of_day_activate), ] self._readonly_action_list = [ - ('Close', None, _('_Close'), "w", - _("Close the current database"), self.close_database), - ('Export', 'gramps-export', _('_Export...'), "e", None, - self.export_data), - ('Backup', None, _("Make Backup..."), None, - _("Make a Gramps XML backup of the database"), self.quick_backup), - ('Abandon', 'document-revert', - _('_Abandon Changes and Quit'), None, None, self.abort), - ('Reports', 'gramps-reports', _('_Reports'), None, - _("Open the reports dialog"), self.reports_clicked), - ('GoMenu', None, _('_Go')), - ('ReportsMenu', None, _('_Reports')), - ('Books', None, _('Books...'), None, None, self.run_book), - ('WindowsMenu', None, _('_Windows')), - ('F2', None, 'F2', "F2", None, self.__keypress), - ('F3', None, 'F3', "F3", None, self.__keypress), - ('F4', None, 'F4', "F4", None, self.__keypress), - ('F5', None, 'F5', "F5", None, self.__keypress), - ('F6', None, 'F6', "F6", None, self.__keypress), - ('F7', None, 'F7', "F7", None, self.__keypress), - ('F8', None, 'F9', "F8", None, self.__keypress), - ('F9', None, 'F9', "F9", None, self.__keypress), - ('F11', None, 'F11', "F11", None, self.__keypress), - ('1', None, '1', "1", None, - self.__gocat), - ('2', None, '2', "2", None, - self.__gocat), - ('3', None, '3', "3", None, - self.__gocat), - ('4', None, '4', "4", None, - self.__gocat), - ('5', None, '5', "5", None, - self.__gocat), - ('6', None, '6', "6", None, - self.__gocat), - ('7', None, '7', "7", None, - self.__gocat), - ('8', None, '8', "8", None, - self.__gocat), - ('9', None, '9', "9", None, - self.__gocat), - ('0', None, '0', "0", None, - self.__gocat), - # NOTE: CTRL+ALT+NUMBER is set in src/plugins/sidebar/cat...py - ('BackSpace', None, 'BackSpace', - "BackSpace", None, self.__keypress), - ('Delete', None, 'Delete', - "Delete", None, self.__keypress), - ('Insert', None, 'Insert', - "Insert", None, self.__keypress), - ('F12', None, 'F12', "F12", None, self.__keypress), - ('J', None, 'J', - "J", None, self.__keypress), - ('N', None, 'N', "N", None, - self.__next_view), - ('P', None, 'P', "P", None, - self.__prev_view), - ] + ('Close', self.close_database, "w"), + ('Export', self.export_data, "e"), + ('Backup', self.quick_backup), + ('Abandon', self.abort), + ('Reports', self.reports_clicked), + #('GoMenu', None, _('_Go')), + #('ReportsMenu', None, _('_Reports')), + ('Books', self.run_book), + #('WindowsMenu', None, _('_Windows')), + #('F2', self.__keypress, 'F2'), #pedigreeview + #('F3', self.__keypress, 'F3'), # timelinepedigreeview + #('F4', self.__keypress, 'F4'), # timelinepedigreeview + #('F5', self.__keypress, 'F5'), # timelinepedigreeview + #('F6', self.__keypress, 'F6'), # timelinepedigreeview + #('F7', self.__keypress, 'F7'), + #('F8', self.__keypress, 'F8'), + #('F9', self.__keypress, 'F9'), + #('F11', self.__keypress, 'F11'), # used to go full screen + #('F12', self.__keypress, 'F12'), + #('BackSpace', self.__keypress, 'BackSpace'), + #('Delete', self.__keypress, 'Delete'), + #('Insert', self.__keypress, 'Insert'), + #('J', self.__keypress, 'J'), + ('PRIMARY-1', self.__gocat, '1'), + ('PRIMARY-2', self.__gocat, '2'), + ('PRIMARY-3', self.__gocat, '3'), + ('PRIMARY-4', self.__gocat, '4'), + ('PRIMARY-5', self.__gocat, '5'), + ('PRIMARY-6', self.__gocat, '6'), + ('PRIMARY-7', self.__gocat, '7'), + ('PRIMARY-8', self.__gocat, '8'), + ('PRIMARY-9', self.__gocat, '9'), + ('PRIMARY-0', self.__gocat, '0'), + # NOTE: CTRL+ALT+NUMBER is set in gramps.gui.navigator + ('PRIMARY-N', self.__next_view, 'N'), + # the following conflicts with PrintView!!! + ('PRIMARY-P', self.__prev_view, 'P'), ] self._action_action_list = [ - ('Clipboard', 'edit-paste', _('Clip_board'), "b", - _("Open the Clipboard dialog"), self.clipboard), - ('AddMenu', None, _('_Add')), + ('Clipboard', self.clipboard, "b"), + #('AddMenu', None, _('_Add')), #('AddNewMenu', None, _('New')), - ('PersonAdd', None, _('Person'), "p", None, - self.add_new_person), - ('FamilyAdd', None, _('Family'), "f", None, - self.add_new_family), - ('EventAdd', None, _('Event'), "e", None, - self.add_new_event), - ('PlaceAdd', None, _('Place'), "l", None, - self.add_new_place), - ('SourceAdd', None, _('Source'), "s", None, - self.add_new_source), - ('CitationAdd', None, _('Citation'), "c", None, - self.add_new_citation), - ('RepositoryAdd', None, _('Repository'), "r", None, - self.add_new_repository), - ('MediaAdd', None, _('Media'), "m", None, - self.add_new_media), - ('NoteAdd', None, _('Note'), "n", None, - self.add_new_note), + ('PersonAdd', self.add_new_person, "p"), + ('FamilyAdd', self.add_new_family, "f"), + ('EventAdd', self.add_new_event, "e"), + ('PlaceAdd', self.add_new_place, "l"), + ('SourceAdd', self.add_new_source, "s"), + ('CitationAdd', self.add_new_citation, "c"), + ('RepositoryAdd', self.add_new_repository, "r"), + ('MediaAdd', self.add_new_media, "m"), + ('NoteAdd', self.add_new_note, "n"), + ('UndoHistory', self.undo_history, "H"), #-------------------------------------- - ('Import', 'gramps-import', _('_Import...'), "i", None, - self.import_data), - ('Tools', 'gramps-tools', _('_Tools'), None, - _("Open the tools dialog"), self.tools_clicked), - ('BookMenu', None, _('_Bookmarks')), - ('ToolsMenu', None, _('_Tools')), - ('ConfigView', 'gramps-config', _('_Configure...'), - 'c', _('Configure the active view'), - self.config_view), - ] - - self._file_toggle_action_list = [ - ('Navigator', None, _('_Navigator'), "m", None, - self.navigator_toggle, self.show_navigator), - ('Toolbar', None, _('_Toolbar'), None, None, self.toolbar_toggle, - self.show_toolbar), - ('Fullscreen', None, _('F_ull Screen'), "F11", None, - self.fullscreen_toggle, self.fullscreen), - ] + ('Import', self.import_data, "i"), + ('Tools', self.tools_clicked), + #('BookMenu', None, _('_Bookmarks')), + #('ToolsMenu', None, _('_Tools')), + ('ConfigView', self.config_view, 'c'), ] self._undo_action_list = [ - ('Undo', 'edit-undo', _('_Undo'), 'z', None, - self.undo), - ] + ('Undo', self.undo, 'z'), ] self._redo_action_list = [ - ('Redo', 'edit-redo', _('_Redo'), 'z', None, - self.redo), - ] + ('Redo', self.redo, 'z'), ] - self._undo_history_action_list = [ - ('UndoHistory', 'gramps-undo-history', - _('Undo History...'), "H", None, self.undo_history), - ] - - def run_book(self, action): + def run_book(self, *action): """ Run a book. """ @@ -667,20 +458,7 @@ class ViewManager(CLIManager): except WindowActiveError: return - def __keypress(self, action): - """ - Callback that is called on a keypress. It works by extracting the - name of the associated action, and passes that to the active page - (current view) so that it can take the associated action. - """ - name = action.get_name() - try: - self.active_page.call_function(name) - except Exception: - self.uistate.push_message(self.dbstate, - _("Key %s is not bound") % name) - - def __gocat(self, action): + def __gocat(self, action, value): """ Callback that is called on ctrl+number press. It moves to the requested category like __next_view/__prev_view. 0 is 10 @@ -694,7 +472,7 @@ class ViewManager(CLIManager): return False self.goto_page(cat, None) - def __next_view(self, action): + def __next_view(self, action, value): """ Callback that is called when the next category action is selected. It selects the next category as the active category. If we reach the end, @@ -712,7 +490,7 @@ class ViewManager(CLIManager): else: self.goto_page(cat_num+1, None) - def __prev_view(self, action): + def __prev_view(self, action, value): """ Callback that is called when the previous category action is selected. It selects the previous category as the active category. If we reach @@ -743,25 +521,18 @@ class ViewManager(CLIManager): self.goto_page(defaults[0], defaults[1]) - self.fileactions.set_sensitive(False) + self.uimanager.set_actions_sensitive(self.fileactions, False) self.__build_tools_menu(self._pmgr.get_reg_tools()) self.__build_report_menu(self._pmgr.get_reg_reports()) self._pmgr.connect('plugins-reloaded', self.__rebuild_report_and_tool_menus) - self.fileactions.set_sensitive(True) - self.uistate.widget.set_sensitive(True) + self.uimanager.set_actions_sensitive(self.fileactions, True) if not self.file_loaded: - self.actiongroup.set_sensitive(False) - self.readonlygroup.set_sensitive(False) - self.undoactions.set_sensitive(False) - self.redoactions.set_sensitive(False) - self.undohistoryactions.set_sensitive(False) - self.actiongroup.set_visible(False) - self.readonlygroup.set_visible(False) - self.undoactions.set_visible(False) - self.redoactions.set_visible(False) - self.undohistoryactions.set_visible(False) - self.uimanager.ensure_update() + self.uimanager.set_actions_visible(self.actiongroup, False) + self.uimanager.set_actions_visible(self.readonlygroup, False) + self.uimanager.set_actions_visible(self.undoactions, False) + self.uimanager.set_actions_visible(self.redoactions, False) + self.uimanager.update_menu() config.connect("interface.statusbar", self.__statusbar_key_update) def __statusbar_key_update(self, client, cnxn_id, entry, data): @@ -777,7 +548,7 @@ class ViewManager(CLIManager): """ self.window.show() if not self.dbstate.is_open() and show_manager: - self.__open_activate(None) + self.__open_activate(None, None) def do_reg_plugins(self, dbstate, uistate, rescan=False): """ @@ -829,9 +600,9 @@ class ViewManager(CLIManager): config.set('interface.main-window-horiz-position', horiz_position) config.set('interface.main-window-vert-position', vert_position) config.save() - Gtk.main_quit() + self.app.quit() - def abort(self, obj=None): + def abort(self, *obj): """ Abandon changes and quit. """ @@ -861,56 +632,43 @@ class ViewManager(CLIManager): """ Initialize an action group for the UIManager """ - new_group = ActionGroup(name=name) - new_group.add_actions(actions) - if toggles: - new_group.add_toggle_actions(toggles) - new_group.set_sensitive(sensitive) - self.uimanager.insert_action_group(new_group, 1) + new_group = ActionGroup(name, actions) + self.uimanager.insert_action_group(new_group) + self.uimanager.set_actions_sensitive(new_group, sensitive) return new_group def __build_ui_manager(self): """ - Builds the UIManager, and the associated action groups + Builds the action groups """ - self.uimanager = Gtk.UIManager() - - accelgroup = self.uimanager.get_accel_group() + self.uimanager = self.app.uimanager self.actiongroup = self.__init_action_group( - 'MainWindow', self._action_action_list) + 'RW', self._action_action_list) self.readonlygroup = self.__init_action_group( - 'AllMainWindow', self._readonly_action_list) - self.undohistoryactions = self.__init_action_group( - 'UndoHistory', self._undo_history_action_list) + 'RO', self._readonly_action_list) self.fileactions = self.__init_action_group( - 'FileWindow', self._file_action_list, - toggles=self._file_toggle_action_list) + 'FileWindow', self._file_action_list) self.undoactions = self.__init_action_group( 'Undo', self._undo_action_list, sensitive=False) self.redoactions = self.__init_action_group( 'Redo', self._redo_action_list, sensitive=False) - self.window.add_accel_group(accelgroup) - self.uimanager.add_ui_from_string(UIDEFAULT) - self.uimanager.ensure_update() +# def __attach_menubar(self, vbox): +# """ +# Attach the menubar +# """ +# vbox.pack_start(self.menubar, False, True, 0) +# if _GTKOSXAPPLICATION: +# self.menubar.hide() +# quit_item = self.uimanager.get_widget("Quit") +# about_item = self.uimanager.get_widget("About") +# prefs_item = self.uimanager.get_widget("Preferences") +# self.macapp.set_menu_bar(self.menubar) +# self.macapp.insert_app_menu_item(about_item, 0) +# self.macapp.insert_app_menu_item(prefs_item, 1) - def __attach_menubar(self, vbox): - """ - Attach the menubar - """ - vbox.pack_start(self.menubar, False, True, 0) - if _GTKOSXAPPLICATION: - self.menubar.hide() - quit_item = self.uimanager.get_widget("/MenuBar/FileMenu/Quit") - about_item = self.uimanager.get_widget("/MenuBar/HelpMenu/About") - prefs_item = self.uimanager.get_widget( - "/MenuBar/EditMenu/Preferences") - self.macapp.set_menu_bar(self.menubar) - self.macapp.insert_app_menu_item(about_item, 0) - self.macapp.insert_app_menu_item(prefs_item, 1) - - def preferences_activate(self, obj): + def preferences_activate(self, *obj): """ Open the preferences dialog. """ @@ -919,7 +677,7 @@ class ViewManager(CLIManager): except WindowActiveError: return - def tip_of_day_activate(self, obj): + def tip_of_day_activate(self, *obj): """ Display Tip of the day """ @@ -935,12 +693,13 @@ class ViewManager(CLIManager): except WindowActiveError: pass - def navigator_toggle(self, obj, data=None): + def navigator_toggle(self, action, value): """ Set the sidebar based on the value of the toggle button. Save the results in the configuration settings """ - if obj.get_active(): + action.set_state(value) + if value.get_boolean(): self.ebox.show() config.set('interface.view', True) self.show_navigator = True @@ -950,25 +709,28 @@ class ViewManager(CLIManager): self.show_navigator = False config.save() - def toolbar_toggle(self, obj, data=None): + def toolbar_toggle(self, action, value): """ Set the toolbar based on the value of the toggle button. Save the results in the configuration settings """ - if obj.get_active(): - self.toolbar.show() + action.set_state(value) + toolbar = self.uimanager.get_widget('ToolBar') + if value.get_boolean(): + toolbar.show_all() config.set('interface.toolbar-on', True) else: - self.toolbar.hide() + toolbar.hide() config.set('interface.toolbar-on', False) config.save() - def fullscreen_toggle(self, obj, data=None): + def fullscreen_toggle(self, action, value): """ - Set the main Granps window fullscreen based on the value of the + Set the main Gramps window fullscreen based on the value of the toggle button. Save the setting in the config file. """ - if obj.get_active(): + action.set_state(value) + if value.get_boolean(): self.window.fullscreen() config.set('interface.fullscreen', True) else: @@ -1051,17 +813,10 @@ class ViewManager(CLIManager): hbox.show_all() page_num = self.notebook.append_page(page.get_display(), hbox) if not self.file_loaded: - self.actiongroup.set_sensitive(False) - self.readonlygroup.set_sensitive(False) - self.undoactions.set_sensitive(False) - self.redoactions.set_sensitive(False) - self.undohistoryactions.set_sensitive(False) - self.actiongroup.set_visible(False) - self.readonlygroup.set_visible(False) - self.undoactions.set_visible(False) - self.redoactions.set_visible(False) - self.undohistoryactions.set_visible(False) - self.uimanager.ensure_update() + self.uimanager.set_actions_visible(self.actiongroup, False) + self.uimanager.set_actions_visible(self.readonlygroup, False) + self.uimanager.set_actions_visible(self.undoactions, False) + self.uimanager.set_actions_visible(self.redoactions, False) return page def view_changed(self, notebook, page, page_num): @@ -1103,12 +858,14 @@ class ViewManager(CLIManager): self.__disconnect_previous_page() self.active_page = self.pages[page_num] - self.active_page.set_active() self.__connect_active_page(page_num) + self.active_page.set_active() + while Gtk.events_pending(): + Gtk.main_iteration() - self.uimanager.ensure_update() - if _GTKOSXAPPLICATION: - self.macapp.sync_menubar() + self.uimanager.update_menu() + # if _GTKOSXAPPLICATION: + # self.macapp.sync_menubar() while Gtk.events_pending(): Gtk.main_iteration() @@ -1143,7 +900,7 @@ class ViewManager(CLIManager): into the UIManager """ for grp in self.active_page.get_actions(): - self.uimanager.insert_action_group(grp, 1) + self.uimanager.insert_action_group(grp) uidef = self.active_page.ui_definition() self.merge_ids = [self.uimanager.add_ui_from_string(uidef)] @@ -1152,13 +909,14 @@ class ViewManager(CLIManager): mergeid = self.uimanager.add_ui_from_string(uidef) self.merge_ids.append(mergeid) - configaction = self.actiongroup.get_action('ConfigView') + configaction = self.uimanager.get_action(self.actiongroup, + 'ConfigView') if self.active_page.can_configure(): - configaction.set_sensitive(True) + configaction.set_enabled(True) else: - configaction.set_sensitive(False) + configaction.set_enabled(False) - def import_data(self, obj): + def import_data(self, *obj): """ Imports a file """ @@ -1170,7 +928,7 @@ class ViewManager(CLIManager): parent=self.window) self.__post_load() - def __open_activate(self, obj): + def __open_activate(self, obj, value): """ Called when the Open button is clicked, opens the DbManager """ @@ -1208,8 +966,8 @@ class ViewManager(CLIManager): """ self.dbstate.db.undo_callback = self.__change_undo_label self.dbstate.db.redo_callback = self.__change_redo_label - self.__change_undo_label(None) - self.__change_redo_label(None) + self.__change_undo_label(None, update_menu=False) + self.__change_redo_label(None, update_menu=False) self.dbstate.db.undo_history_callback = self.undo_history_update self.undo_history_close() @@ -1241,16 +999,10 @@ class ViewManager(CLIManager): self.uistate.window.set_title(msg) self.__change_page(self.notebook.get_current_page()) - self.actiongroup.set_visible(rw) - self.readonlygroup.set_visible(True) - self.undoactions.set_visible(rw) - self.redoactions.set_visible(rw) - self.undohistoryactions.set_visible(rw) - self.actiongroup.set_sensitive(rw) - self.readonlygroup.set_sensitive(True) - self.undoactions.set_sensitive(rw) - self.redoactions.set_sensitive(rw) - self.undohistoryactions.set_sensitive(rw) + self.uimanager.set_actions_visible(self.actiongroup, rw) + self.uimanager.set_actions_visible(self.readonlygroup, True) + self.uimanager.set_actions_visible(self.undoactions, rw) + self.uimanager.set_actions_visible(self.redoactions, rw) self.recent_manager.build() @@ -1263,17 +1015,13 @@ class ViewManager(CLIManager): """ self.undo_history_close() self.uistate.window.set_title("%s - Gramps" % _('No Family Tree')) - self.actiongroup.set_sensitive(False) - self.readonlygroup.set_sensitive(False) - self.undohistoryactions.set_sensitive(False) self.uistate.clear_filter_results() self.__disconnect_previous_page() - self.actiongroup.set_visible(False) - self.readonlygroup.set_visible(False) - self.undoactions.set_visible(False) - self.redoactions.set_visible(False) - self.undohistoryactions.set_visible(False) - self.uimanager.ensure_update() + self.uimanager.set_actions_visible(self.actiongroup, False) + self.uimanager.set_actions_visible(self.readonlygroup, False) + self.uimanager.set_actions_visible(self.undoactions, False) + self.uimanager.set_actions_visible(self.redoactions, False) + self.uimanager.update_menu() config.set('paths.recent-file', '') config.save() @@ -1286,67 +1034,81 @@ class ViewManager(CLIManager): """ if not enable: self.action_st = ( - self.actiongroup.get_sensitive(), - self.readonlygroup.get_sensitive(), - self.undoactions.get_sensitive(), - self.redoactions.get_sensitive(), - self.undohistoryactions.get_sensitive(), - self.fileactions.get_sensitive(), - self.toolactions.get_sensitive(), - self.reportactions.get_sensitive(), - self.recent_manager.action_group.get_sensitive()) - self.actiongroup.set_sensitive(enable) - self.readonlygroup.set_sensitive(enable) - self.undoactions.set_sensitive(enable) - self.redoactions.set_sensitive(enable) - self.undohistoryactions.set_sensitive(enable) - self.fileactions.set_sensitive(enable) - self.toolactions.set_sensitive(enable) - self.reportactions.set_sensitive(enable) - self.recent_manager.action_group.set_sensitive(enable) + self.uimanager.get_actions_sensitive(self.actiongroup), + self.uimanager.get_actions_sensitive(self.readonlygroup), + self.uimanager.get_actions_sensitive(self.undoactions), + self.uimanager.get_actions_sensitive(self.redoactions), + self.uimanager.get_actions_sensitive(self.fileactions), + self.uimanager.get_actions_sensitive(self.toolactions), + self.uimanager.get_actions_sensitive(self.reportactions), + self.uimanager.get_actions_sensitive( + self.recent_manager.action_group)) + self.uimanager.set_actions_sensitive(self.actiongroup, enable) + self.uimanager.set_actions_sensitive(self.readonlygroup, enable) + self.uimanager.set_actions_sensitive(self.undoactions, enable) + self.uimanager.set_actions_sensitive(self.redoactions, enable) + self.uimanager.set_actions_sensitive(self.fileactions, enable) + self.uimanager.set_actions_sensitive(self.toolactions, enable) + self.uimanager.set_actions_sensitive(self.reportactions, enable) + self.uimanager.set_actions_sensitive( + self.recent_manager.action_group, enable) else: - self.actiongroup.set_sensitive(self.action_st[0]) - self.readonlygroup.set_sensitive(self.action_st[1]) - self.undoactions.set_sensitive(self.action_st[2]) - self.redoactions.set_sensitive(self.action_st[3]) - self.undohistoryactions.set_sensitive(self.action_st[4]) - self.fileactions.set_sensitive(self.action_st[5]) - self.toolactions.set_sensitive(self.action_st[6]) - self.reportactions.set_sensitive(self.action_st[7]) - self.recent_manager.action_group.set_sensitive(self.action_st[8]) + self.uimanager.set_actions_sensitive( + self.actiongroup, self.action_st[0]) + self.uimanager.set_actions_sensitive( + self.readonlygroup, self.action_st[1]) + self.uimanager.set_actions_sensitive( + self.undoactions, self.action_st[2]) + self.uimanager.set_actions_sensitive( + self.redoactions, self.action_st[3]) + self.uimanager.set_actions_sensitive( + self.fileactions, self.action_st[4]) + self.uimanager.set_actions_sensitive( + self.toolactions, self.action_st[5]) + self.uimanager.set_actions_sensitive( + self.reportactions, self.action_st[6]) + self.uimanager.set_actions_sensitive( + self.recent_manager.action_group, self.action_st[7]) - def __change_undo_label(self, label): + def __change_undo_label(self, label, update_menu=True): """ Change the UNDO label """ - self.uimanager.remove_action_group(self.undoactions) - self.undoactions = Gtk.ActionGroup(name='Undo') - if label: - self.undoactions.add_actions([ - ('Undo', 'edit-undo', label, 'z', None, self.undo)]) + _menu = ''' + + win.Undo + %s + + + ''' + if not label: + label = _('_Undo') + self.uimanager.set_actions_sensitive(self.undoactions, False) else: - self.undoactions.add_actions([ - ('Undo', 'edit-undo', _('_Undo'), - 'z', None, self.undo)]) - self.undoactions.set_sensitive(False) - self.uimanager.insert_action_group(self.undoactions, 1) + self.uimanager.set_actions_sensitive(self.undoactions, True) + self.uimanager.add_ui_from_string([_menu % html.escape(label)]) + if update_menu: + self.uimanager.update_menu() - def __change_redo_label(self, label): + def __change_redo_label(self, label, update_menu=True): """ Change the REDO label """ - self.uimanager.remove_action_group(self.redoactions) - self.redoactions = Gtk.ActionGroup(name='Redo') - if label: - self.redoactions.add_actions([ - ('Redo', 'edit-redo', label, 'z', - None, self.redo)]) + _menu = ''' + + win.Redo + %s + + + ''' + if not label: + label = _('_Redo') + self.uimanager.set_actions_sensitive(self.redoactions, False) else: - self.redoactions.add_actions([ - ('Redo', 'edit-undo', _('_Redo'), - 'z', None, self.redo)]) - self.redoactions.set_sensitive(False) - self.uimanager.insert_action_group(self.redoactions, 1) + self.uimanager.set_actions_sensitive(self.redoactions, True) + self.uimanager.add_ui_from_string([_menu % html.escape(label)]) + if update_menu: + self.uimanager.update_menu() def undo_history_update(self): """ @@ -1373,7 +1135,7 @@ class ViewManager(CLIManager): # Let it go: history window does not exist return - def quick_backup(self, obj): + def quick_backup(self, *obj): """ Make a quick XML back with or without media. """ @@ -1413,7 +1175,7 @@ class ViewManager(CLIManager): filename = os.path.join(backup_path, backup_name) writer.write(filename) - def reports_clicked(self, obj): + def reports_clicked(self, *obj): """ Displays the Reports dialog """ @@ -1422,7 +1184,7 @@ class ViewManager(CLIManager): except WindowActiveError: return - def tools_clicked(self, obj): + def tools_clicked(self, *obj): """ Displays the Tools dialog """ @@ -1431,7 +1193,7 @@ class ViewManager(CLIManager): except WindowActiveError: return - def clipboard(self, obj): + def clipboard(self, *obj): """ Displays the Clipboard """ @@ -1442,7 +1204,7 @@ class ViewManager(CLIManager): return # ---------------Add new xxx -------------------------------- - def add_new_person(self, obj): + def add_new_person(self, *obj): """ Add a new person to the database. (Global keybinding) """ @@ -1456,7 +1218,7 @@ class ViewManager(CLIManager): except WindowActiveError: pass - def add_new_family(self, obj): + def add_new_family(self, *obj): """ Add a new family to the database. (Global keybinding) """ @@ -1466,7 +1228,7 @@ class ViewManager(CLIManager): except WindowActiveError: pass - def add_new_event(self, obj): + def add_new_event(self, *obj): """ Add a new custom/unknown event (Note you type first letter of event) """ @@ -1477,28 +1239,28 @@ class ViewManager(CLIManager): except WindowActiveError: pass - def add_new_place(self, obj): + def add_new_place(self, *obj): """Add a new place to the place list""" try: EditPlace(self.dbstate, self.uistate, [], Place()) except WindowActiveError: pass - def add_new_source(self, obj): + def add_new_source(self, *obj): """Add a new source to the source list""" try: EditSource(self.dbstate, self.uistate, [], Source()) except WindowActiveError: pass - def add_new_repository(self, obj): + def add_new_repository(self, *obj): """Add a new repository to the repository list""" try: EditRepository(self.dbstate, self.uistate, [], Repository()) except WindowActiveError: pass - def add_new_citation(self, obj): + def add_new_citation(self, *obj): """ Add a new citation """ @@ -1507,14 +1269,14 @@ class ViewManager(CLIManager): except WindowActiveError: pass - def add_new_media(self, obj): + def add_new_media(self, *obj): """Add a new media object to the media list""" try: EditMedia(self.dbstate, self.uistate, [], Media()) except WindowActiveError: pass - def add_new_note(self, obj): + def add_new_note(self, *obj): """Add a new note to the note list""" try: EditNote(self.dbstate, self.uistate, [], Note()) @@ -1522,13 +1284,13 @@ class ViewManager(CLIManager): pass # ------------------------------------------------------------------------ - def config_view(self, obj): + def config_view(self, *obj): """ Displays the configuration dialog for the active view """ self.active_page.configure() - def undo(self, obj): + def undo(self, *obj): """ Calls the undo function on the database """ @@ -1536,7 +1298,7 @@ class ViewManager(CLIManager): self.dbstate.db.undo() self.uistate.set_busy_cursor(False) - def redo(self, obj): + def redo(self, *obj): """ Calls the redo function on the database """ @@ -1544,7 +1306,7 @@ class ViewManager(CLIManager): self.dbstate.db.redo() self.uistate.set_busy_cursor(False) - def undo_history(self, obj): + def undo_history(self, *obj): """ Displays the Undo history window """ @@ -1553,7 +1315,7 @@ class ViewManager(CLIManager): except WindowActiveError: return - def export_data(self, obj): + def export_data(self, *obj): """ Calls the ExportAssistant to export data """ @@ -1579,14 +1341,13 @@ class ViewManager(CLIManager): if self.toolactions: self.uistate.uimanager.remove_action_group(self.toolactions) self.uistate.uimanager.remove_ui(self.tool_menu_ui_id) - self.toolactions = Gtk.ActionGroup(name='ToolWindow') + self.toolactions = ActionGroup(name='ToolWindow') (uidef, actions) = self.build_plugin_menu( 'ToolsMenu', tool_menu_list, tool.tool_categories, make_plugin_callback) self.toolactions.add_actions(actions) self.tool_menu_ui_id = self.uistate.uimanager.add_ui_from_string(uidef) - self.uimanager.insert_action_group(self.toolactions, 1) - self.uistate.uimanager.ensure_update() + self.uimanager.insert_action_group(self.toolactions) def __build_report_menu(self, report_menu_list): """ @@ -1595,26 +1356,27 @@ class ViewManager(CLIManager): if self.reportactions: self.uistate.uimanager.remove_action_group(self.reportactions) self.uistate.uimanager.remove_ui(self.report_menu_ui_id) - self.reportactions = Gtk.ActionGroup(name='ReportWindow') + self.reportactions = ActionGroup(name='ReportWindow') (udef, actions) = self.build_plugin_menu( 'ReportsMenu', report_menu_list, standalone_categories, make_plugin_callback) self.reportactions.add_actions(actions) self.report_menu_ui_id = self.uistate.uimanager.add_ui_from_string(udef) - self.uimanager.insert_action_group(self.reportactions, 1) - self.uistate.uimanager.ensure_update() + self.uimanager.insert_action_group(self.reportactions) def build_plugin_menu(self, text, item_list, categories, func): """ Builds a new XML description for a menu based on the list of plugindata """ + menuitem = ('\n' + 'win.%s\n' + '' + '%s...\n' + '\n') + actions = [] ofile = StringIO() - ofile.write('' - '' % (text, 'P_'+ text)) - - menu = Gtk.Menu() - menu.show() + ofile.write('
' % ('P_' + text)) hash_data = defaultdict(list) for pdata in item_list: @@ -1628,39 +1390,36 @@ class ViewManager(CLIManager): catlist = sorted(item for item in hash_data if item != _UNSUPPORTED) for key in catlist: - new_key = key[0].replace(' ', '-') - ofile.write('' % new_key) - actions.append((new_key, None, key[1])) + ofile.write('\n%s\n' % key[1]) pdatas = hash_data[key] pdatas.sort(key=lambda x: x.name) for pdata in pdatas: new_key = pdata.id.replace(' ', '-') - menu_name = ("%s...") % pdata.name - ofile.write('' % new_key) - actions.append((new_key, None, menu_name, None, None, - func(pdata, self.dbstate, self.uistate))) - ofile.write('') + ofile.write(menuitem % (new_key, pdata.name)) + actions.append((new_key, func(pdata, self.dbstate, + self.uistate))) + ofile.write('\n') # If there are any unsupported items we add separator # and the unsupported category at the end of the menu if _UNSUPPORTED in hash_data: - ofile.write('') - ofile.write('' % _UNSUPPORTED[0]) - actions.append((_UNSUPPORTED[0], None, _UNSUPPORTED[1])) + ofile.write('\n%s\n' % + _UNSUPPORTED[1]) pdatas = hash_data[_UNSUPPORTED] pdatas.sort(key=lambda x: x.name) for pdata in pdatas: new_key = pdata.id.replace(' ', '-') - menu_name = ("%s...") % pdata.name - ofile.write('' % new_key) - actions.append((new_key, None, menu_name, None, None, - func(pdata, self.dbstate, self.uistate))) - ofile.write('') + ofile.write(menuitem % (new_key, pdata.name)) + actions.append((new_key, func(pdata, self.dbstate, + self.uistate))) + ofile.write('\n') - ofile.write('
') - return (ofile.getvalue(), actions) + ofile.write('\n') + return ([ofile.getvalue()], actions) - def display_about_box(self, obj): + def display_about_box(self, *obj): """Display the About box.""" about = GrampsAboutDialog(self.uistate.window) about.run() @@ -1720,43 +1479,43 @@ class ViewManager(CLIManager): if viewstoshow[cat] not in resultorder) return resultorder -def key_bindings(obj): +def key_bindings(*obj): """ Display key bindings """ display_help(webpage=WIKI_HELP_PAGE_KEY) -def manual_activate(obj): +def manual_activate(*obj): """ Display the Gramps manual """ display_help(webpage=WIKI_HELP_PAGE_MAN) -def report_bug_activate(obj): +def report_bug_activate(*obj): """ Display the bug tracker web site """ display_url(URL_BUGTRACKER) -def home_page_activate(obj): +def home_page_activate(*obj): """ Display the Gramps home page """ display_url(URL_HOMEPAGE) -def mailing_lists_activate(obj): +def mailing_lists_activate(*obj): """ Display the mailing list web page """ display_url(URL_MAILINGLIST) -def extra_plugins_activate(obj): +def extra_plugins_activate(*obj): """ Display the wiki page with extra plugins """ display_url(URL_WIKISTRING+WIKI_EXTRAPLUGINS) -def faq_activate(obj): +def faq_activate(*obj): """ Display FAQ """ @@ -1815,7 +1574,7 @@ def make_plugin_callback(pdata, dbstate, uistate): """ Makes a callback for a report/tool menu item """ - return lambda x: run_plugin(pdata, dbstate, uistate) + return lambda x, y: run_plugin(pdata, dbstate, uistate) def views_to_show(views, use_last=True): """ diff --git a/gramps/gui/views/bookmarks.py b/gramps/gui/views/bookmarks.py index a29da9b5a..0fa57e439 100644 --- a/gramps/gui/views/bookmarks.py +++ b/gramps/gui/views/bookmarks.py @@ -28,6 +28,7 @@ #------------------------------------------------------------------------- from abc import ABCMeta, abstractmethod from io import StringIO +import html #------------------------------------------------------------------------- # @@ -51,6 +52,7 @@ from gi.repository import Gtk from ..display import display_help from ..listmodel import ListModel from ..managedwindow import ManagedWindow +from ..uimanager import ActionGroup from gramps.gen.utils.db import navigation_label from gramps.gen.const import URL_MANUAL_PAGE from gramps.gen.const import GRAMPS_LOCALE as glocale @@ -71,9 +73,6 @@ WIKI_HELP_SEC = _('manual|Bookmarks') # #------------------------------------------------------------------------- -TOP = '''''' -BTM = '''''' - DISABLED = -1 class Bookmarks(metaclass=ABCMeta): @@ -93,7 +92,7 @@ class Bookmarks(metaclass=ABCMeta): if self.dbstate.is_open(): self.update_bookmarks() self.active = DISABLED - self.action_group = Gtk.ActionGroup(name='Bookmarks') + self.action_group = ActionGroup(name='Bookmarks') if self.dbstate.is_open(): self.connect_signals() self.dbstate.connect('database-changed', self.db_changed) @@ -129,7 +128,8 @@ class Bookmarks(metaclass=ABCMeta): """ Redraw the display. """ - self.redraw() + # used by navigationview; other updates follow + self.redraw(update_menu=False) def undisplay(self): """ @@ -138,8 +138,7 @@ class Bookmarks(metaclass=ABCMeta): if self.active != DISABLED: self.uistate.uimanager.remove_ui(self.active) self.uistate.uimanager.remove_action_group(self.action_group) - self.action_group = Gtk.ActionGroup(name='Bookmarks') - self.uistate.uimanager.ensure_update() + self.action_group = ActionGroup(name='Bookmarks') self.active = DISABLED def redraw_and_report_change(self): @@ -147,10 +146,14 @@ class Bookmarks(metaclass=ABCMeta): self.dbstate.db.report_bm_change() self.redraw() - def redraw(self): + def redraw(self, update_menu=True): """Create the pulldown menu.""" + menuitem = ('\n' + 'win.%s\n' + '' + '%s\n' + '\n') text = StringIO() - text.write(TOP) self.undisplay() @@ -158,24 +161,25 @@ class Bookmarks(metaclass=ABCMeta): count = 0 if self.dbstate.is_open() and len(self.bookmarks.get()) > 0: - text.write('') + text.write('
\n') for item in self.bookmarks.get(): try: label, dummy_obj = self.make_label(item) func = self.callback(item) - action_id = "BM:%s" % item - actions.append((action_id, None, label, None, None, func)) - text.write('' % action_id) + action_id = "BM.%s" % item + actions.append((action_id, func)) + text.write(menuitem % (action_id, html.escape(label))) count += 1 except AttributeError: pass - text.write('') + text.write('
\n') - text.write(BTM) self.action_group.add_actions(actions) - self.uistate.uimanager.insert_action_group(self.action_group, 1) - self.active = self.uistate.uimanager.add_ui_from_string(text.getvalue()) - self.uistate.uimanager.ensure_update() + self.uistate.uimanager.insert_action_group(self.action_group) + self.active = self.uistate.uimanager.add_ui_from_string( + [text.getvalue()]) + if update_menu: + self.uistate.uimanager.update_menu() text.close() @abstractmethod @@ -538,4 +542,4 @@ def make_callback(handle, function): """ Build a unique call to the function with the associated handle. """ - return lambda x: function(handle) + return lambda x, y: function(handle) diff --git a/gramps/gui/views/listview.py b/gramps/gui/views/listview.py index 84255bdb6..6c7a49681 100644 --- a/gramps/gui/views/listview.py +++ b/gramps/gui/views/listview.py @@ -55,7 +55,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale _ = glocale.translation.sgettext from .pageview import PageView from .navigationview import NavigationView -from ..actiongroup import ActionGroup +from ..uimanager import ActionGroup from ..columnorder import ColumnOrder from gramps.gen.config import config from gramps.gen.errors import WindowActiveError, FilterError, HandleError @@ -64,6 +64,7 @@ from ..widgets.menuitem import add_menuitem from gramps.gen.const import CUSTOM_FILTERS from gramps.gen.utils.debug import profile from gramps.gen.utils.string import data_recover_msg +from gramps.gen.plug import CATEGORY_QR_PERSON from ..dialog import QuestionDialog, QuestionDialog2, ErrorDialog from ..editors import FilterEditor from ..ddtargets import DdTargets @@ -122,6 +123,8 @@ class ListView(NavigationView): self.generic_filter = None dbstate.connect('database-changed', self.change_db) self.connect_signals() + self.at_popup_action = None + self.at_popup_menu = None def no_database(self): ## TODO GTK3: This is never called!! Dbguielement disconnects @@ -206,24 +209,19 @@ class ListView(NavigationView): NavigationView.define_actions(self) - self.edit_action = ActionGroup(name=self.title + '/ChangeOrder') + self.edit_action = ActionGroup(name=self.title + '/Edits') self.edit_action.add_actions([ - ('Add', 'list-add', _("_Add..."), "Insert", - self.ADD_MSG, self.add), - ('Remove', 'list-remove', _("_Delete"), "Delete", - self.DEL_MSG, self.remove), - ('Merge', 'gramps-merge', _('_Merge...'), None, - self.MERGE_MSG, self.merge), - ('ExportTab', None, _('Export View...'), None, None, - self.export), - ]) + ('Add', self.add, 'Insert'), + ('Remove', self.remove, 'Delete'), + ('PRIMARY-BackSpace', self.remove, 'BackSpace'), + ('Merge', self.merge), ]) self._add_action_group(self.edit_action) - - self._add_action('Edit', 'gtk-edit', _("action|_Edit..."), - accel="Return", - tip=self.EDIT_MSG, - callback=self.edit) + self.action_list.extend([ + ('ExportTab', self.export), + ('Edit', self.edit, 'Return'), + ('PRIMARY-J', self.jump, 'J'), + ('FilterEdit', self.filter_editor)]) def build_columns(self): list(map(self.list.remove_column, self.columns)) @@ -291,7 +289,7 @@ class ListView(NavigationView): Called when the page is displayed. """ NavigationView.set_active(self) - self.uistate.viewmanager.tags.tag_enable() + self.uistate.viewmanager.tags.tag_enable(update_menu=False) self.uistate.show_filter_results(self.dbstate, self.model.displayed(), self.model.total()) @@ -303,9 +301,6 @@ class ListView(NavigationView): NavigationView.set_inactive(self) self.uistate.viewmanager.tags.tag_disable() - def __build_tree(self): - profile(self._build_tree) - def build_tree(self, force_sidebar=False): if self.active: cput0 = time.clock() @@ -372,7 +367,7 @@ class ListView(NavigationView): """ return 'gramps-tree-list' - def filter_editor(self, obj): + def filter_editor(self, *obj): try: FilterEditor(self.FILTER_TYPE , CUSTOM_FILTERS, self.dbstate, self.uistate) @@ -441,7 +436,7 @@ class ListView(NavigationView): self.uistate.push_message(self.dbstate, _("Active object not visible")) - def add_bookmark(self, obj): + def add_bookmark(self, *obj): mlist = [] self.selection.selected_foreach(self.blist, mlist) @@ -851,6 +846,7 @@ class ListView(NavigationView): """ if not self.dbstate.is_open(): return False + menu = self.uimanager.get_widget('Popup') if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1: if self.model.get_flags() & Gtk.TreeModelFlags.LIST_ONLY: self.edit(obj) @@ -866,49 +862,54 @@ class ListView(NavigationView): else: self.edit(obj) return True - elif is_right_click(event): - menu = self.uistate.uimanager.get_widget('/Popup') - if menu: - # Quick Reports - qr_menu = self.uistate.uimanager.\ - get_widget('/Popup/QuickReport') - if qr_menu and self.QR_CATEGORY > -1 : - (ui, qr_actions) = create_quickreport_menu( - self.QR_CATEGORY, - self.dbstate, - self.uistate, - self.first_selected()) - self.__build_menu(qr_menu, qr_actions) + elif is_right_click(event) and menu: + prefix = 'win' + self.at_popup_menu = [] + actions = [] + # Quick Reports + if self.QR_CATEGORY > -1: + (qr_ui, qr_actions) = create_quickreport_menu( + self.QR_CATEGORY, self.dbstate, self.uistate, + self.first_selected(), prefix) + if self.get_active() and qr_actions: + actions.extend(qr_actions) + qr_ui = ("%s" % + qr_ui) + self.at_popup_menu.append(qr_ui) - # Web Connects - web_menu = self.uistate.uimanager.\ - get_widget('/Popup/WebConnect') - if web_menu: - web_actions = create_web_connect_menu( - self.dbstate, - self.uistate, - self.navigation_type(), - self.first_selected()) - self.__build_menu(web_menu, web_actions) + # Web Connects + if self.QR_CATEGORY == CATEGORY_QR_PERSON: + (web_ui, web_actions) = create_web_connect_menu( + self.dbstate, self.uistate, self.navigation_type(), + self.first_selected(), prefix) + if self.get_active() and web_actions: + actions.extend(web_actions) + self.at_popup_menu.append(web_ui) - menu.popup(None, None, None, None, event.button, event.time) - return True + if self.at_popup_action: + self.uimanager.remove_ui(self.at_popup_menu) + self.uimanager.remove_action_group(self.at_popup_action) + self.at_popup_action = ActionGroup('AtPopupActions', + actions) + self.uimanager.insert_action_group(self.at_popup_action) + self.at_popup_menu = self.uimanager.add_ui_from_string( + self.at_popup_menu) + self.uimanager.update_menu() + + menu = self.uimanager.get_widget('Popup') + popup_menu = Gtk.Menu.new_from_model(menu) + popup_menu.attach_to_widget(obj, None) + popup_menu.show_all() + if Gtk.MINOR_VERSION < 22: + # ToDo The following is reported to work poorly with Wayland + popup_menu.popup(None, None, None, None, + event.button, event.time) + else: + popup_menu.popup_at_pointer(event) + return True return False - def __build_menu(self, menu, actions): - """ - Build a submenu for quick reports and web connects - """ - if self.get_active() and len(actions) > 1: - sub_menu = Gtk.Menu() - for action in actions[1:]: - add_menuitem(sub_menu, action[2], None, action[5]) - menu.set_submenu(sub_menu) - menu.show() - else: - menu.hide() - def _key_press(self, obj, event): """ Called when a key is pressed on a listview @@ -1002,9 +1003,6 @@ class ListView(NavigationView): return True return False - def key_delete(self): - self.remove(None) - def change_page(self): """ Called when a page is changed. @@ -1014,8 +1012,9 @@ class ListView(NavigationView): self.uistate.show_filter_results(self.dbstate, self.model.displayed(), self.model.total()) - self.edit_action.set_visible(True) - self.edit_action.set_sensitive(not self.dbstate.db.readonly) + self.uimanager.set_actions_visible(self.edit_action, True) + self.uimanager.set_actions_sensitive(self.edit_action, + not self.dbstate.db.readonly) def on_delete(self): """ @@ -1038,7 +1037,7 @@ class ListView(NavigationView): #################################################################### # Export data #################################################################### - def export(self, obj): + def export(self, *obj): chooser = Gtk.FileChooserDialog( _("Export View as Spreadsheet"), self.uistate.window, @@ -1140,25 +1139,25 @@ class ListView(NavigationView): # Template functions #################################################################### @abstractmethod - def edit(self, obj, data=None): + def edit(self, *obj): """ Template function to allow the editing of the selected object """ @abstractmethod - def remove(self, handle, data=None): + def remove(self, *obj): """ Template function to allow the removal of an object by its handle """ @abstractmethod - def add(self, obj, data=None): + def add(self, *obj): """ Template function to allow the adding of a new object """ @abstractmethod - def merge(self, obj, data=None): + def merge(self, *obj): """ Template function to allow the merger of two objects. """ @@ -1169,7 +1168,7 @@ class ListView(NavigationView): Template function to allow the removal of an object by its handle """ - def open_all_nodes(self, obj): + def open_all_nodes(self, *obj): """ Method for Treeviews to open all groups obj: for use of method in event callback @@ -1182,14 +1181,14 @@ class ListView(NavigationView): self.uistate.set_busy_cursor(False) self.uistate.modify_statusbar(self.dbstate) - def close_all_nodes(self, obj): + def close_all_nodes(self, *obj): """ Method for Treeviews to close all groups obj: for use of method in event callback """ self.list.collapse_all() - def open_branch(self, obj): + def open_branch(self, *obj): """ Expand the selected branches and all children. obj: for use of method in event callback @@ -1204,7 +1203,7 @@ class ListView(NavigationView): self.uistate.set_busy_cursor(False) self.uistate.modify_statusbar(self.dbstate) - def close_branch(self, obj): + def close_branch(self, *obj): """ Collapse the selected branches. :param obj: not used, present only to allow the use of the method in diff --git a/gramps/gui/views/navigationview.py b/gramps/gui/views/navigationview.py index df4fd3e3b..0194c3164 100644 --- a/gramps/gui/views/navigationview.py +++ b/gramps/gui/views/navigationview.py @@ -29,6 +29,7 @@ Provide the base classes for GRAMPS' DataView classes # #---------------------------------------------------------------- from abc import abstractmethod +import html import logging _LOG = logging.getLogger('.navigationview') @@ -49,7 +50,7 @@ from gi.repository import Gtk from gramps.gen.const import GRAMPS_LOCALE as glocale _ = glocale.translation.sgettext from .pageview import PageView -from ..actiongroup import ActionGroup +from ..uimanager import ActionGroup from gramps.gen.utils.db import navigation_label from gramps.gen.constfunc import mod_key from ..utils import match_primary_mask @@ -57,19 +58,9 @@ from ..utils import match_primary_mask DISABLED = -1 MRU_SIZE = 10 -MRU_TOP = [ - '' - '' - '' - '' - ] +MRU_TOP = '
' +MRU_BTM = '
' -MRU_BTM = [ - '
' - '
' - '
' - '
' - ] #------------------------------------------------------------------------------ # # NavigationView @@ -94,6 +85,7 @@ class NavigationView(PageView): self.mru_signal = None self.nav_group = nav_group self.mru_active = DISABLED + self.uimanager = uistate.uimanager self.uistate.register(state, self.navigation_type(), self.nav_group) @@ -122,8 +114,8 @@ class NavigationView(PageView): """ PageView.disable_action_group(self) - self.fwd_action.set_visible(False) - self.back_action.set_visible(False) + self.uimanager.set_actions_visible(self.fwd_action, False) + self.uimanager.set_actions_visible(self.back_action, False) def enable_action_group(self, obj): """ @@ -133,20 +125,25 @@ class NavigationView(PageView): """ PageView.enable_action_group(self, obj) - self.fwd_action.set_visible(True) - self.back_action.set_visible(True) + self.uimanager.set_actions_visible(self.fwd_action, True) + self.uimanager.set_actions_visible(self.back_action, True) hobj = self.get_history() - self.fwd_action.set_sensitive(not hobj.at_end()) - self.back_action.set_sensitive(not hobj.at_front()) + self.uimanager.set_actions_sensitive(self.fwd_action, + not hobj.at_end()) + self.uimanager.set_actions_sensitive(self.back_action, + not hobj.at_front()) def change_page(self): """ Called when the page changes. """ hobj = self.get_history() - self.fwd_action.set_sensitive(not hobj.at_end()) - self.back_action.set_sensitive(not hobj.at_front()) - self.other_action.set_sensitive(not self.dbstate.db.readonly) + self.uimanager.set_actions_sensitive(self.fwd_action, + not hobj.at_end()) + self.uimanager.set_actions_sensitive(self.back_action, + not hobj.at_front()) + self.uimanager.set_actions_sensitive(self.other_action, + not self.dbstate.db.readonly) self.uistate.modify_statusbar(self.dbstate) def set_active(self): @@ -159,7 +156,7 @@ class NavigationView(PageView): hobj = self.get_history() self.active_signal = hobj.connect('active-changed', self.goto_active) self.mru_signal = hobj.connect('mru-changed', self.update_mru_menu) - self.update_mru_menu(hobj.mru) + self.update_mru_menu(hobj.mru, update_menu=False) self.goto_active(None) @@ -199,8 +196,10 @@ class NavigationView(PageView): self.goto_handle(active_handle) hobj = self.get_history() - self.fwd_action.set_sensitive(not hobj.at_end()) - self.back_action.set_sensitive(not hobj.at_front()) + self.uimanager.set_actions_sensitive(self.fwd_action, + not hobj.at_end()) + self.uimanager.set_actions_sensitive(self.back_action, + not hobj.at_front()) def get_active(self): """ @@ -238,7 +237,7 @@ class NavigationView(PageView): #################################################################### # BOOKMARKS #################################################################### - def add_bookmark(self, obj): + def add_bookmark(self, *obj): """ Add a bookmark to the list. """ @@ -259,7 +258,7 @@ class NavigationView(PageView): "no one was selected."), parent=self.uistate.window) - def edit_bookmarks(self, obj): + def edit_bookmarks(self, *obj): """ Call the bookmark editor. """ @@ -271,12 +270,8 @@ class NavigationView(PageView): """ self.book_action = ActionGroup(name=self.title + '/Bookmark') self.book_action.add_actions([ - ('AddBook', 'gramps-bookmark-new', _('_Add Bookmark'), - 'd', None, self.add_bookmark), - ('EditBook', 'gramps-bookmark-edit', - _("%(title)s...") % {'title': _("Organize Bookmarks")}, - 'D', None, - self.edit_bookmarks), + ('AddBook', self.add_bookmark, 'd'), + ('EditBook', self.edit_bookmarks, 'D'), ]) self._add_action_group(self.book_action) @@ -290,35 +285,25 @@ class NavigationView(PageView): """ # add the Forward action group to handle the Forward button self.fwd_action = ActionGroup(name=self.title + '/Forward') - self.fwd_action.add_actions([ - ('Forward', 'go-next', _("_Forward"), - "%sRight" % mod_key(), _("Go to the next object in the history"), - self.fwd_clicked) - ]) + self.fwd_action.add_actions([('Forward', self.fwd_clicked, + "%sRight" % mod_key())]) # add the Backward action group to handle the Forward button self.back_action = ActionGroup(name=self.title + '/Backward') - self.back_action.add_actions([ - ('Back', 'go-previous', _("_Back"), - "%sLeft" % mod_key(), _("Go to the previous object in the history"), - self.back_clicked) - ]) + self.back_action.add_actions([('Back', self.back_clicked, + "%sLeft" % mod_key())]) - self._add_action('HomePerson', 'go-home', _("_Home"), - accel="%sHome" % mod_key(), - tip=_("Go to the default person"), callback=self.home) + self._add_action('HomePerson', self.home, "%sHome" % mod_key()) self.other_action = ActionGroup(name=self.title + '/PersonOther') self.other_action.add_actions([ - ('SetActive', 'go-home', _("Set _Home Person"), None, - None, self.set_default_person), - ]) + ('SetActive', self.set_default_person)]) self._add_action_group(self.back_action) self._add_action_group(self.fwd_action) self._add_action_group(self.other_action) - def set_default_person(self, obj): + def set_default_person(self, *obj): """ Set the default person. """ @@ -326,7 +311,7 @@ class NavigationView(PageView): if active: self.dbstate.db.set_default_person_handle(active) - def home(self, obj): + def home(self, *obj): """ Move to the default person. """ @@ -342,7 +327,7 @@ class NavigationView(PageView): "via the menu Edit ->Set Home Person."), parent=self.uistate.window) - def jump(self): + def jump(self, *obj): """ A dialog to move to a Gramps ID entered by the user. """ @@ -383,7 +368,7 @@ class NavigationView(PageView): """ pass - def fwd_clicked(self, obj): + def fwd_clicked(self, *obj): """ Move forward one object in the history. """ @@ -392,11 +377,12 @@ class NavigationView(PageView): if not hobj.at_end(): hobj.forward() self.uistate.modify_statusbar(self.dbstate) - self.fwd_action.set_sensitive(not hobj.at_end()) - self.back_action.set_sensitive(True) + self.uimanager.set_actions_sensitive(self.fwd_action, + not hobj.at_end()) + self.uimanager.set_actions_sensitive(self.back_action, True) hobj.lock = False - def back_clicked(self, obj): + def back_clicked(self, *obj): """ Move backward one object in the history. """ @@ -405,8 +391,9 @@ class NavigationView(PageView): if not hobj.at_front(): hobj.back() self.uistate.modify_statusbar(self.dbstate) - self.back_action.set_sensitive(not hobj.at_front()) - self.fwd_action.set_sensitive(True) + self.uimanager.set_actions_sensitive(self.back_action, + not hobj.at_front()) + self.uimanager.set_actions_sensitive(self.fwd_action, True) hobj.lock = False #################################################################### @@ -418,44 +405,52 @@ class NavigationView(PageView): Remove the UI and action groups for the MRU list. """ if self.mru_active != DISABLED: - self.uistate.uimanager.remove_ui(self.mru_active) - self.uistate.uimanager.remove_action_group(self.mru_action) + self.uimanager.remove_ui(self.mru_active) + self.uimanager.remove_action_group(self.mru_action) self.mru_active = DISABLED - def mru_enable(self): + def mru_enable(self, update_menu=False): """ Enables the UI and action groups for the MRU list. """ if self.mru_active == DISABLED: - self.uistate.uimanager.insert_action_group(self.mru_action, 1) - self.mru_active = self.uistate.uimanager.add_ui_from_string(self.mru_ui) - self.uistate.uimanager.ensure_update() + self.uimanager.insert_action_group(self.mru_action) + self.mru_active = self.uimanager.add_ui_from_string(self.mru_ui) + if update_menu: + self.uimanager.update_menu() - def update_mru_menu(self, items): + def update_mru_menu(self, items, update_menu=True): """ Builds the UI and action group for the MRU list. """ + menuitem = ''' + win.%s%02d + %s + + ''' + menus = '' self.mru_disable() nav_type = self.navigation_type() hobj = self.get_history() menu_len = min(len(items) - 1, MRU_SIZE) - entry = '' - data = [entry % (nav_type, index) for index in range(0, menu_len)] - self.mru_ui = "".join(MRU_TOP) + "".join(data) + "".join(MRU_BTM) + for index in range(0, menu_len): + name, obj = navigation_label(self.dbstate.db, nav_type, + items[index]) + menus += menuitem % (nav_type, index, html.escape(name)) + self.mru_ui = [MRU_TOP + menus + MRU_BTM] mitems = items[-MRU_SIZE - 1:-1] # Ignore current handle mitems.reverse() data = [] for index, handle in enumerate(mitems): - name, obj = navigation_label(self.dbstate.db, nav_type, handle) - data.append(('%s%02d'%(nav_type, index), None, name, - "%s%d" % (mod_key(), index), None, - make_callback(hobj.push, handle))) + data.append(('%s%02d'%(nav_type, index), + make_callback(hobj.push, handle), + "%s%d" % (mod_key(), index))) self.mru_action = ActionGroup(name=self.title + '/MRU') self.mru_action.add_actions(data) - self.mru_enable() + self.mru_enable(update_menu) #################################################################### # Template functions @@ -503,4 +498,4 @@ def make_callback(func, handle): """ Generates a callback function based off the passed arguments """ - return lambda x: func(handle) + return lambda x, y: func(handle) diff --git a/gramps/gui/views/pageview.py b/gramps/gui/views/pageview.py index 6fde0810b..1f510aead 100644 --- a/gramps/gui/views/pageview.py +++ b/gramps/gui/views/pageview.py @@ -51,7 +51,7 @@ from ..dbguielement import DbGUIElement from ..widgets.grampletbar import GrampletBar from ..configure import ConfigureDialog from gramps.gen.config import config -from ..actiongroup import ActionGroup +from ..uimanager import ActionGroup #------------------------------------------------------------------------------ # @@ -97,25 +97,24 @@ class PageView(DbGUIElement, metaclass=ABCMeta): self.uistate = uistate self.action_list = [] self.action_toggle_list = [] - self.action_toolmenu_list = [] - self.action_toolmenu = {} #easy access to toolmenuaction and proxies self.action_group = None self.additional_action_groups = [] self.additional_uis = [] - self.ui_def = ''' - - - - - - - - - ''' + self.ui_def = [''' + + + win.Sidebar + _Sidebar + + + win.Bottombar + _Bottombar + + + '''] self.dirty = True self.active = False self._dirty_on_change_inactive = True - self.func_list = {} if isinstance(self.pdata.category, tuple): self.category, self.translated_category = self.pdata.category @@ -201,24 +200,24 @@ class PageView(DbGUIElement, metaclass=ABCMeta): """ self._config.set(setting, widget.get_position()) - def __sidebar_toggled(self, action): + def __sidebar_toggled(self, action, value): """ Called when the sidebar is toggled. """ - active = action.get_active() - if active: + action.set_state(value) # change GUI + if value.get_boolean(): self.sidebar.show() self.sidebar_toggled(True) else: self.sidebar.hide() self.sidebar_toggled(False) - def __bottombar_toggled(self, action): + def __bottombar_toggled(self, action, value): """ Called when the bottombar is toggled. """ - active = action.get_active() - if active: + action.set_state(value) # change GUI + if value.get_boolean(): self.bottombar.show() else: self.bottombar.hide() @@ -312,12 +311,6 @@ class PageView(DbGUIElement, metaclass=ABCMeta): return True return False - def call_function(self, key): - """ - Calls the function associated with the key value - """ - self.func_list.get(key)() - def post(self): """ Called after a page is created. @@ -373,14 +366,15 @@ class PageView(DbGUIElement, metaclass=ABCMeta): Turns off the visibility of the View's action group, if defined """ if self.action_group: - self.action_group.set_visible(False) + self.uistate.uimanager.set_actions_visible(self.action_group, + False) def enable_action_group(self, obj): """ Turns on the visibility of the View's action group, if defined """ if self.action_group: - self.action_group.set_visible(True) + self.uistate.uimanager.set_actions_visible(self.action_group, True) def get_stock(self): """ @@ -438,11 +432,9 @@ class PageView(DbGUIElement, metaclass=ABCMeta): View. The user typically defines self.action_list and self.action_toggle_list in this function. """ - self._add_toggle_action('Sidebar', None, _('_Sidebar'), - "R", None, self.__sidebar_toggled, + self._add_toggle_action('Sidebar', self.__sidebar_toggled, '', self.sidebar.get_property('visible')) - self._add_toggle_action('Bottombar', None, _('_Bottombar'), - "B", None, self.__bottombar_toggled, + self._add_toggle_action('Bottombar', self.__bottombar_toggled, '', self.bottombar.get_property('visible')) def __build_action_group(self): @@ -455,31 +447,19 @@ class PageView(DbGUIElement, metaclass=ABCMeta): if len(self.action_list) > 0: self.action_group.add_actions(self.action_list) if len(self.action_toggle_list) > 0: - self.action_group.add_toggle_actions(self.action_toggle_list) + self.action_group.add_actions(self.action_toggle_list) - def _add_action(self, name, icon_name, label, accel=None, tip=None, - callback=None): + def _add_action(self, name, callback=None, accel=None): """ Add an action to the action list for the current view. """ - self.action_list.append((name, icon_name, label, accel, tip, - callback)) + self.action_list.append((name, callback, accel)) - def _add_toggle_action(self, name, icon_name, label, accel=None, - tip=None, callback=None, value=False): + def _add_toggle_action(self, name, callback=None, accel= None, value=False): """ Add a toggle action to the action list for the current view. """ - self.action_toggle_list.append((name, icon_name, label, accel, - tip, callback, value)) - - def _add_toolmenu_action(self, name, label, tooltip, callback, - arrowtooltip): - """ - Add a menu action to the action list for the current view. - """ - self.action_toolmenu_list.append((name, label, tooltip, callback, - arrowtooltip)) + self.action_toggle_list.append((name, callback, accel, value)) def get_actions(self): """ diff --git a/gramps/gui/views/tags.py b/gramps/gui/views/tags.py index 3c677c64c..0206ae611 100644 --- a/gramps/gui/views/tags.py +++ b/gramps/gui/views/tags.py @@ -50,7 +50,7 @@ from gramps.gen.const import URL_MANUAL_PAGE from ..display import display_help from ..dialog import ErrorDialog, QuestionDialog2 import gramps.gui.widgets.progressdialog as progressdlg -from ..actiongroup import ActionGroup +from ..uimanager import ActionGroup from ..managedwindow import ManagedWindow #------------------------------------------------------------------------- @@ -58,29 +58,54 @@ from ..managedwindow import ManagedWindow # Constants # #------------------------------------------------------------------------- -TAG_1 = ''' - - - - -''' +TAG_1 = ''' +
+ + Tag + %s + +
+ ''' -TAG_2 = ''' -
-
-
-
- - - +TAG_2 = ( + ''' + + + gramps-tag + win.TagButton + ''' + '''Tag selected rows + Tag + + + False + + - - -''' + ''') TAG_3 = ''' - -
''' + + %s + ''' + +TAG_MENU = ( + '''
+ + win.NewTag + ''' + '''New Tag... + + + win.OrganizeTags + ''' + '''Organize Tags... + +
+
+ %s +
+ ''') WIKI_HELP_PAGE = '%s_-_Filters' % \ URL_MANUAL_PAGE @@ -119,13 +144,14 @@ class Tags(DbGUIElement): self._build_tag_menu() - def tag_enable(self): + def tag_enable(self, update_menu=True): """ Enables the UI and action groups for the tag menu. """ - self.uistate.uimanager.insert_action_group(self.tag_action, 1) + self.uistate.uimanager.insert_action_group(self.tag_action) self.tag_id = self.uistate.uimanager.add_ui_from_string(self.tag_ui) - self.uistate.uimanager.ensure_update() + if update_menu: + self.uistate.uimanager.update_menu() def tag_disable(self): """ @@ -134,7 +160,6 @@ class Tags(DbGUIElement): if self.tag_id is not None: self.uistate.uimanager.remove_ui(self.tag_id) self.uistate.uimanager.remove_action_group(self.tag_action) - self.uistate.uimanager.ensure_update() self.tag_id = None def _db_changed(self, db): @@ -209,46 +234,55 @@ class Tags(DbGUIElement): actions = [] if not self.dbstate.is_open(): - self.tag_ui = '' + self.tag_ui = [''] self.tag_action = ActionGroup(name='Tag') return - tag_menu = '' - tag_menu += '' - tag_menu += '' + tag_menu = '' + menuitem = ''' + + win.TAG_%s + %s + ''' + for tag_name, handle in self.__tag_list: - tag_menu += '' % handle - actions.append(('TAG_%s' % handle, None, tag_name, None, None, - make_callback(self.tag_selected_rows, handle))) + tag_menu += menuitem % (handle, tag_name) + actions.append(('TAG_%s' % handle, + make_callback(self.tag_selected_rows, handle))) + tag_menu = TAG_MENU % tag_menu - self.tag_ui = TAG_1 + tag_menu + TAG_2 + tag_menu + TAG_3 + self.tag_ui = [TAG_1 % tag_menu, TAG_2, TAG_3 % tag_menu] - actions.append(('Tag', 'gramps-tag', _('Tag'), None, None, None)) - actions.append(('NewTag', 'gramps-tag-new', _('New Tag...'), None, None, - self.cb_new_tag)) - actions.append(('OrganizeTags', None, _('Organize Tags...'), None, None, - self.cb_organize_tags)) - actions.append(('TagButton', 'gramps-tag', _('Tag'), None, - _('Tag selected rows'), self.cb_tag_button)) + actions.append(('NewTag', self.cb_new_tag)) + actions.append(('OrganizeTags', self.cb_organize_tags)) + actions.append(('TagButton', self.cb_tag_button)) self.tag_action = ActionGroup(name='Tag') self.tag_action.add_actions(actions) - def cb_tag_button(self, action): + def cb_tag_button(self, *args): """ Display the popup menu when the toolbar button is clicked. """ - menu = self.uistate.uimanager.get_widget('/TagPopup') - button = self.uistate.uimanager.get_widget('/ToolBar/TagTool/TagButton') - menu.popup(None, None, cb_menu_position, button, 0, 0) + menu = self.uistate.uimanager.get_widget('TagPopup') + button = self.uistate.uimanager.get_widget('TagButton') + popup_menu = Gtk.Menu.new_from_model(menu) + popup_menu.attach_to_widget(button, None) + popup_menu.show_all() + if Gtk.MINOR_VERSION < 22: + # ToDo The following is reported to work poorly with Wayland + popup_menu.popup(None, None, cb_menu_position, button, 0, 0) + else: + popup_menu.popup_at_widget(button, Gdk.Gravity.SOUTH, + Gdk.Gravity.NORTH_WEST, None) - def cb_organize_tags(self, action): + def cb_organize_tags(self, *action): """ Display the Organize Tags dialog. """ OrganizeTagsDialog(self.db, self.uistate, []) - def cb_new_tag(self, action): + def cb_new_tag(self, *action): """ Create a new tag and tag the selected objects. """ @@ -304,7 +338,7 @@ def make_callback(func, tag_handle): """ Generates a callback function based off the passed arguments """ - return lambda x: func(tag_handle) + return lambda x, y: func(tag_handle) #------------------------------------------------------------------------- # diff --git a/gramps/gui/widgets/__init__.py b/gramps/gui/widgets/__init__.py index 71489981f..b12eec59b 100644 --- a/gramps/gui/widgets/__init__.py +++ b/gramps/gui/widgets/__init__.py @@ -34,16 +34,12 @@ from .monitoredwidgets import * from .selectionwidget import SelectionWidget, Region from .shadebox import * from .shortlistcomboentry import * -from .springseparator import * from .statusbar import Statusbar from .styledtextbuffer import * from .styledtexteditor import * -from .toolcomboentry import * from .undoablebuffer import * from .undoableentry import * from .undoablestyledbuffer import * from .validatedcomboentry import * from .validatedmaskedentry import * -from .valueaction import * -from .valuetoolitem import * from .placewithin import * diff --git a/gramps/gui/widgets/grampletpane.py b/gramps/gui/widgets/grampletpane.py index bc09d987f..2d3042d60 100644 --- a/gramps/gui/widgets/grampletpane.py +++ b/gramps/gui/widgets/grampletpane.py @@ -49,7 +49,7 @@ from gramps.gen.const import URL_MANUAL_PAGE, VERSION_DIR, COLON from ..editors import EditPerson, EditFamily from ..managedwindow import ManagedWindow from ..utils import is_right_click, match_primary_mask, get_link_color -from .menuitem import add_menuitem +from ..uimanager import ActionGroup from ..plug import make_gui_option from ..plug.quick import run_quick_report_by_name from ..display import display_help, display_url @@ -189,6 +189,13 @@ def logical_true(value): """ return value in ["True", True, 1, "1"] +def make_callback(func, arg): + """ + Generates a callback function based off the passed arguments + """ + return lambda x, y: func(arg) + + class LinkTag(Gtk.TextTag): """ Class for keeping track of link data. @@ -999,6 +1006,8 @@ class GrampletPane(Gtk.ScrolledWindow): self.pageview = pageview self.pane = self self._popup_xy = None + self.at_popup_action = None + self.at_popup_menu = None user_gramplets = self.load_gramplets() # build the GUI: msg = _("Right click to add gramplets") @@ -1349,8 +1358,7 @@ class GrampletPane(Gtk.ScrolledWindow): self.place_gramplets(recolumn=True) self.show() - def restore_gramplet(self, obj): - name = obj.get_child().get_label() + def restore_gramplet(self, name): ############### First kind: from current session for gramplet in self.closed_gramplets: if gramplet.title == name: @@ -1392,8 +1400,7 @@ class GrampletPane(Gtk.ScrolledWindow): else: self.drop_widget(self, gramplet, 0, 0, 0) - def add_gramplet(self, obj): - tname = obj.get_child().get_label() + def add_gramplet(self, tname): all_opts = get_gramplet_options_by_tname(tname) name = all_opts["name"] if all_opts is None: @@ -1437,39 +1444,73 @@ class GrampletPane(Gtk.ScrolledWindow): LOG.warning("Can't make gramplet of type '%s'.", name) def _button_press(self, obj, event): + ui_def = ( + ''' + + win.AddGramplet + Add a gramplet + %s + + + win.RestoreGramplet + ''' + '''Restore a gramplet + %s + + + ''') + menuitem = ('\n' + 'win.%s\n' + '' + '%s\n' + '\n') + if is_right_click(event): self._popup_xy = (event.x, event.y) uiman = self.uistate.uimanager - ag_menu = uiman.get_widget('/GrampletPopup/AddGramplet') - if ag_menu: - qr_menu = ag_menu.get_submenu() - qr_menu = Gtk.Menu() - names = [gplug.name for gplug in PLUGMAN.get_reg_gramplets() - if gplug.navtypes == [] - or 'Dashboard' in gplug.navtypes] - names.sort() + actions = [] + r_menuitems = '' + a_menuitems = '' + names = [gplug.name for gplug in PLUGMAN.get_reg_gramplets() + if gplug.navtypes == [] + or 'Dashboard' in gplug.navtypes] + names.sort() + for name in names: + action_name = name.replace(' ', '-') + a_menuitems += menuitem % (action_name, name) + actions.append((action_name, + make_callback(self.add_gramplet, name))) + names = [gramplet.title for gramplet in self.closed_gramplets] + names.extend(opts["title"] for opts in self.closed_opts) + names.sort() + if len(names) > 0: for name in names: - add_menuitem(qr_menu, name, None, - self.add_gramplet) - ag_menu.set_submenu(qr_menu) - rg_menu = uiman.get_widget('/GrampletPopup/RestoreGramplet') - if rg_menu: - qr_menu = rg_menu.get_submenu() - if qr_menu is not None: - rg_menu.set_submenu(None) - names = [gramplet.title for gramplet in self.closed_gramplets] - names.extend(opts["title"] for opts in self.closed_opts) - names.sort() - if len(names) > 0: - qr_menu = Gtk.Menu() - for name in names: - add_menuitem(qr_menu, name, None, - self.restore_gramplet) - rg_menu.set_submenu(qr_menu) - self.menu = uiman.get_widget('/GrampletPopup') - if self.menu: - #GTK3 does not show the popup, workaround: menu as attribute - self.menu.popup(None, None, None, None, event.button, event.time) + action_name = name.replace(' ', '-') + r_menuitems += menuitem % (action_name, name) + actions.append((action_name, + make_callback(self.restore_gramplet, + name))) + + if self.at_popup_action: + uiman.remove_ui(self.at_popup_menu) + uiman.remove_action_group(self.at_popup_action) + self.at_popup_action = ActionGroup('AtPopupActions', + actions) + uiman.insert_action_group(self.at_popup_action) + self.at_popup_menu = uiman.add_ui_from_string([ + ui_def % (a_menuitems, r_menuitems)]) + uiman.update_menu() + + menu = uiman.get_widget('Popup') + popup_menu = Gtk.Menu.new_from_model(menu) + popup_menu.attach_to_widget(obj, None) + popup_menu.show_all() + if Gtk.MINOR_VERSION < 22: + # ToDo The following is reported to work poorly with Wayland + popup_menu.popup(None, None, None, None, + event.button, event.time) + else: + popup_menu.popup_at_pointer(event) return True return False diff --git a/gramps/gui/widgets/shortlistcomboentry.py b/gramps/gui/widgets/shortlistcomboentry.py index 48411e0cb..a4766a8ec 100644 --- a/gramps/gui/widgets/shortlistcomboentry.py +++ b/gramps/gui/widgets/shortlistcomboentry.py @@ -70,7 +70,10 @@ class ShortlistComboEntry(ValidatedComboEntry): """ __gtype_name__ = "ShortlistComboEntry" - def __init__(self, items, shortlist=True, validator=None): + def __init__(self): + pass + + def init(self, items, shortlist=True, validator=None): if not items: raise ValueError diff --git a/gramps/gui/widgets/springseparator.py b/gramps/gui/widgets/springseparator.py deleted file mode 100644 index 0504007c9..000000000 --- a/gramps/gui/widgets/springseparator.py +++ /dev/null @@ -1,76 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2008 Zsolt Foldvari -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -"Separator classes used for Toolbar." - -__all__ = ["SpringSeparatorAction", "SpringSeparatorToolItem"] - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -import logging -_LOG = logging.getLogger(".widgets.springseparator") - -#------------------------------------------------------------------------- -# -# GTK modules -# -#------------------------------------------------------------------------- -from gi.repository import Gtk - -#------------------------------------------------------------------------- -# -# SpringSeparatorToolItem class -# -#------------------------------------------------------------------------- -class SpringSeparatorToolItem(Gtk.SeparatorToolItem): - """Custom separator toolitem. - - Its only purpose is to push following tool items to the right end - of the toolbar. - - """ - __gtype_name__ = "SpringSeparatorToolItem" - - def __init__(self): - Gtk.SeparatorToolItem.__init__(self) - - self.set_draw(False) - self.set_expand(True) - -#------------------------------------------------------------------------- -# -# SpringSeparatorAction class -# -#------------------------------------------------------------------------- -class SpringSeparatorAction(Gtk.Action): - """Custom Action to hold a SpringSeparatorToolItem.""" - - __gtype_name__ = "SpringSeparatorAction" - - def __init__(self, name, label, tooltip, stock_id): - Gtk.Action.__init__(self, name=name, label=label, - tooltip=tooltip, stock_id=stock_id) - -## TODO GTK3, How to connect these? Used in styledtexteditor -##SpringSeparatorToolItem.set_related_action(SpringSeparatorAction) -##deprecated: SpringSeparatorAction.set_tool_item_type(SpringSeparatorToolItem) diff --git a/gramps/gui/widgets/styledtexteditor.py b/gramps/gui/widgets/styledtexteditor.py index 4b8460659..9502184cf 100644 --- a/gramps/gui/widgets/styledtexteditor.py +++ b/gramps/gui/widgets/styledtexteditor.py @@ -43,6 +43,8 @@ from gi.repository import GObject from gi.repository import Gdk from gi.repository import Gtk from gi.repository import Pango +from gi.repository.Gio import SimpleActionGroup +from gi.repository.GLib import Variant #------------------------------------------------------------------------- # @@ -55,15 +57,12 @@ from .styledtextbuffer import (ALLOWED_STYLES, MATCH_FLAVOR, MATCH_STRING, LinkTag) from .undoablestyledbuffer import UndoableStyledBuffer -from .valueaction import ValueAction -from .toolcomboentry import ToolComboEntry -from .springseparator import SpringSeparatorAction from ..spell import Spell from ..display import display_url from ..utils import SystemFonts, match_primary_mask, get_link_color from gramps.gen.config import config from gramps.gen.constfunc import has_display, mac -from ..actiongroup import ActionGroup +from ..uimanager import ActionGroup #------------------------------------------------------------------------- # @@ -75,33 +74,141 @@ if has_display(): HAND_CURSOR = Gdk.Cursor.new_for_display(display, Gdk.CursorType.HAND2) REGULAR_CURSOR = Gdk.Cursor.new_for_display(display, Gdk.CursorType.XTERM) -FORMAT_TOOLBAR = ''' - - - - - - - - - - - - - - - - -''' % (StyledTextTagType.ITALIC, - StyledTextTagType.BOLD, - StyledTextTagType.UNDERLINE, - StyledTextTagType.FONTFACE, - StyledTextTagType.FONTSIZE, - StyledTextTagType.FONTCOLOR, - StyledTextTagType.HIGHLIGHT, - StyledTextTagType.LINK, - ) - +FORMAT_TOOLBAR = ( + ''' + + + True + GTK_TOOLBAR_ICONS + + + + format-text-italic + ste.ITALIC + Italic + + + False + + + + + format-text-bold + ste.BOLD + Bold + + + False + + + + + format-text-underline + ste.UNDERLINE + Underline + + + False + + + + + Font family + + + + + + + + Font size + + + + + + + + edit-undo + ste.STUndo + Undo + Undo + + + False + + + + + edit-redo + ste.STRedo + Redo + Redo + + + False + + + + + gramps-font-color + ste.FONTCOLOR + Font Color + Font Color + + + False + + + + + gramps-font-bgcolor + ste.HIGHLIGHT + ''' + '''Background Color + Background Color + + + False + + + + + go-jump + ste.LINK + Link + Link + + + False + + + + + False + True + + + True + + + + + edit-clear + ste.CLEAR + ''' + '''Clear Markup + Clear Markup + + + False + + + + +''') FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 40, 48, 56, 64, 72] @@ -182,6 +289,7 @@ class StyledTextEditor(Gtk.TextView): self.undo_disabled = self.textbuffer.undo_disabled # see bug 7097 self.textbuffer.connect('style-changed', self._on_buffer_style_changed) self.textbuffer.connect('changed', self._on_buffer_changed) + self.undo_action = self.redo_action = None Gtk.TextView.__init__(self) self.set_buffer(self.textbuffer) @@ -194,9 +302,9 @@ class StyledTextEditor(Gtk.TextView): self._init_url_match() self.url_match = None - self.toolbar = self._create_toolbar() self.spellcheck = Spell(self) self._internal_style_change = False + self.uimanager = None self._connect_signals() @@ -236,30 +344,6 @@ class StyledTextEditor(Gtk.TextView): window.set_cursor(REGULAR_CURSOR) self.url_match = None - def on_key_press_event(self, widget, event): - """Signal handler. - - Handle formatting shortcuts. - - """ - if ((Gdk.keyval_name(event.keyval) == 'Z') and - match_primary_mask(event.get_state(), Gdk.ModifierType.SHIFT_MASK)): - self.redo() - return True - elif ((Gdk.keyval_name(event.keyval) == 'z') and - match_primary_mask(event.get_state())): - self.undo() - return True - else: - for accel, accel_name in self.action_accels.items(): - key, mod = Gtk.accelerator_parse(accel) - if ((event.keyval == key) and (event.get_state() & mod)): - action_name = accel_name - action = self.action_group.get_action(action_name) - action.activate() - return True - return False - def on_insert_at_cursor(self, widget, string): """Signal handler. for debugging only.""" _LOG.debug("Textview insert '%s'" % string) @@ -423,14 +507,13 @@ class StyledTextEditor(Gtk.TextView): Reset the undoable buffer """ self.textbuffer.reset() - self.undo_action.set_sensitive(False) - self.redo_action.set_sensitive(False) + self.undo_action.set_enabled(False) + self.redo_action.set_enabled(False) # private methods def _connect_signals(self): """Connect to several signals of the super class Gtk.TextView.""" - self.connect('key-press-event', self.on_key_press_event) self.connect('insert-at-cursor', self.on_insert_at_cursor) self.connect('delete-from-cursor', self.on_delete_from_cursor) self.connect('paste-clipboard', self.on_paste_clipboard) @@ -439,104 +522,74 @@ class StyledTextEditor(Gtk.TextView): self.connect('button-release-event', self.on_button_release_event) self.connect('populate-popup', self.on_populate_popup) - def _create_toolbar(self): + def create_toolbar(self, uimanager, window): """ Create a formatting toolbar. :returns: toolbar containing text formatting toolitems. :rtype: Gtk.Toolbar """ + self.uimanager = uimanager + # build the toolbar + builder = Gtk.Builder.new_from_string(FORMAT_TOOLBAR, -1) # define the actions... - # ...first the toggle actions, which have a ToggleToolButton as proxy - format_toggle_actions = [ - (str(StyledTextTagType.ITALIC), 'format-text-italic', None, None, - _('Italic'), self._on_toggle_action_activate), - (str(StyledTextTagType.BOLD), 'format-text-bold', None, None, - _('Bold'), self._on_toggle_action_activate), - (str(StyledTextTagType.UNDERLINE), 'format-text-underline', None, - None, _('Underline'), self._on_toggle_action_activate), + _actions = [ + ('ITALIC', self._on_toggle_action_activate, 'i', False), + ('BOLD', self._on_toggle_action_activate, 'b', False), + ('UNDERLINE', self._on_toggle_action_activate, 'u', + False), + ('FONTCOLOR', self._on_action_activate), + ('HIGHLIGHT', self._on_action_activate), + ('LINK', self._on_link_activate), + ('CLEAR', self._format_clear_cb), + ('STUndo', self.undo, 'z'), + ('STRedo', self.redo, 'z'), ] - self.toggle_actions = [action[0] for action in format_toggle_actions] - - # ...then the normal actions, which have a ToolButton as proxy - format_actions = [ - (str(StyledTextTagType.FONTCOLOR), 'gramps-font-color', - _('Font Color'), None, _('Font Color'), self._on_action_activate), - (str(StyledTextTagType.HIGHLIGHT), 'gramps-font-bgcolor', - _('Background Color'), None, _('Background Color'), - self._on_action_activate), - (str(StyledTextTagType.LINK), 'go-jump', _('Link'), None, - _('Link'), self._on_link_activate), - ('clear', 'edit-clear', _('Clear Markup'), None, - _('Clear Markup'), self._format_clear_cb), - ] - - # ...last the custom actions, which have custom proxies - default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTFACE] + # the following are done manually rather than using actions fonts = SystemFonts() - fontface_action = ValueAction(str(StyledTextTagType.FONTFACE), - _("Font family"), - default, - ToolComboEntry, - fonts.get_system_fonts(), - False, #editable - True, #shortlist - None) # validator - fontface_action.connect('changed', self._on_valueaction_changed) + fontface = builder.get_object('Fontface') + fontface.init(fonts.get_system_fonts(), shortlist=True, validator=None) + fontface.set_entry_editable(False) + fontface.connect('changed', make_cb( + self._on_valueaction_changed, StyledTextTagType.FONTFACE)) + # set initial value + default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTFACE] + self.fontface = fontface.get_child() + self.fontface.set_text(str(default)) + fontface.show() items = FONT_SIZES + fontsize = builder.get_object('Fontsize') + fontsize.init(items, shortlist=False, validator=is_valid_fontsize) + fontsize.set_entry_editable(True) + fontsize.connect('changed', make_cb( + self._on_valueaction_changed, StyledTextTagType.FONTSIZE)) + # set initial value default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTSIZE] - fontsize_action = ValueAction(str(StyledTextTagType.FONTSIZE), - _("Font size"), - default, - ToolComboEntry, - items, - True, #editable - False, #shortlist - is_valid_fontsize) #validator - fontsize_action.connect('changed', self._on_valueaction_changed) - - spring = SpringSeparatorAction("spring", "", "", None) - - # action accelerators - self.action_accels = { - 'i': str(StyledTextTagType.ITALIC), - 'b': str(StyledTextTagType.BOLD), - 'u': str(StyledTextTagType.UNDERLINE), - } + self.fontsize = fontsize.get_child() + self.fontsize.set_text(str(default)) + fontsize.show() # create the action group and insert all the actions - self.action_group = ActionGroup(name='Format') - self.action_group.add_toggle_actions(format_toggle_actions) - self.undo_action = Gtk.Action(name="Undo", label=_('Undo'), - tooltip=_('Undo')) - self.undo_action.set_icon_name('edit-undo') - self.undo_action.connect('activate', self.undo) - self.redo_action = Gtk.Action.new(name="Redo", label=_('Redo'), - tooltip=_('Redo')) - self.redo_action.set_icon_name('edit-redo') - self.redo_action.connect('activate', self.redo) - self.action_group.add_action(self.undo_action) - self.action_group.add_action(self.redo_action) - self.action_group.add_actions(format_actions) - self.action_group.add_action(fontface_action) - self.action_group.add_action(fontsize_action) - self.action_group.add_action(spring) + self.action_group = ActionGroup('Format', _actions, 'ste') + act_grp = SimpleActionGroup() + window.insert_action_group('ste', act_grp) + window.set_application(uimanager.app) + uimanager.insert_action_group(self.action_group, act_grp) - # define the toolbar and create the proxies via ensure_update() - uimanager = Gtk.UIManager() - uimanager.insert_action_group(self.action_group, 0) - uimanager.add_ui_from_string(FORMAT_TOOLBAR) - uimanager.ensure_update() + self.undo_action = uimanager.get_action(self.action_group, "STUndo") + self.redo_action = uimanager.get_action(self.action_group, "STRedo") + # allow undo/redo to see actions if editable. + self.textbuffer.connect('changed', self._on_buffer_changed) + # undo/redo are initially greyed out, until something is changed + self.undo_action.set_enabled(False) + self.redo_action.set_enabled(False) # get the toolbar and set it's style - toolbar = uimanager.get_widget('/ToolBar') - toolbar.set_style(Gtk.ToolbarStyle.ICONS) - self.undo_action.set_sensitive(False) - self.redo_action.set_sensitive(False) + toolbar = builder.get_object('ToolBar') - return toolbar + return toolbar, self.action_group def set_transient_parent(self, parent=None): self.transient_parent = parent @@ -582,21 +635,22 @@ class StyledTextEditor(Gtk.TextView): # Callback functions - def _on_toggle_action_activate(self, action): + def _on_toggle_action_activate(self, action, value): """ Toggle a style. Toggle styles are e.g. 'bold', 'italic', 'underline'. """ + action.set_state(value) if self._internal_style_change: return - style = int(action.get_name()) - value = action.get_active() - _LOG.debug("applying style '%d' with value '%s'" % (style, str(value))) - self.textbuffer.apply_style(style, value) + style = action.get_name() + value = value.get_boolean() + _LOG.debug("applying style '%s' with value '%s'" % (style, str(value))) + self.textbuffer.apply_style(getattr(StyledTextTagType, style), value) - def _on_link_activate(self, action): + def _on_link_activate(self, action, value): """ Create a link of a selected region of text. """ @@ -633,10 +687,9 @@ class StyledTextEditor(Gtk.TextView): else: tag.data = uri - - def _on_action_activate(self, action): + def _on_action_activate(self, action, value): """Apply a format set from a Gtk.Action type of action.""" - style = int(action.get_name()) + style = getattr(StyledTextTagType, action.get_name()) current_value = self.textbuffer.get_style_at_cursor(style) if style == StyledTextTagType.FONTCOLOR: @@ -668,14 +721,12 @@ class StyledTextEditor(Gtk.TextView): (style, str(value))) self.textbuffer.apply_style(style, value) - def _on_valueaction_changed(self, action): - """Apply a format set by a ValueAction type of action.""" + def _on_valueaction_changed(self, obj, style): + """Apply a format set by a ShortListComboEntry.""" if self._internal_style_change: return - style = int(action.get_name()) - - value = action.get_value() + value = obj.get_active_data() try: value = StyledTextTagType.STYLE_TYPE[style](value) _LOG.debug("applying style '%d' with value '%s'" % @@ -685,7 +736,7 @@ class StyledTextEditor(Gtk.TextView): _LOG.debug("unable to convert '%s' to '%s'" % (value, StyledTextTagType.STYLE_TYPE[style])) - def _format_clear_cb(self, action): + def _format_clear_cb(self, action, value): """ Remove all formats from the selection or from all. @@ -709,24 +760,27 @@ class StyledTextEditor(Gtk.TextView): def _on_buffer_changed(self, buffer): """synchronize the undo/redo buttons with what is possible""" - self.undo_action.set_sensitive(self.textbuffer.can_undo) - self.redo_action.set_sensitive(self.textbuffer.can_redo) + if self.undo_action: + self.undo_action.set_enabled(self.textbuffer.can_undo) + self.redo_action.set_enabled(self.textbuffer.can_redo) def _on_buffer_style_changed(self, buffer, changed_styles): """Synchronize actions as the format changes at the buffer's cursor.""" + if not self.uimanager: + return # never initialized a toolbar, not editable + types = [StyledTextTagType.ITALIC, StyledTextTagType.BOLD, + StyledTextTagType.UNDERLINE] + self._internal_style_change = True for style, style_value in changed_styles.items(): - if str(style) in self.toggle_actions: - action = self.action_group.get_action(str(style)) - self._internal_style_change = True - action.set_active(style_value) - self._internal_style_change = False - - if ((style == StyledTextTagType.FONTFACE) or - (style == StyledTextTagType.FONTSIZE)): - action = self.action_group.get_action(str(style)) - self._internal_style_change = True - action.set_value(style_value) - self._internal_style_change = False + if style in types: + action = self.uimanager.get_action( + self.action_group, str(StyledTextTagType(style)).upper()) + action.change_state(Variant.new_boolean(style_value)) + elif (style == StyledTextTagType.FONTFACE): + self.fontface.set_text(style_value) + elif style == StyledTextTagType.FONTSIZE: + self.fontsize.set_text(str(style_value)) + self._internal_style_change = False def _spell_change_cb(self, menuitem, spellcheck): """Set spell checker spellcheck according to user selection.""" @@ -818,20 +872,17 @@ class StyledTextEditor(Gtk.TextView): start, end = self.textbuffer.get_bounds() return self.textbuffer.get_text(start, end, True) - def get_toolbar(self): - """ - Get the formatting toolbar of the editor. - - :returns: toolbar widget to use as formatting GUI. - :rtype: Gtk.Toolbar - """ - return self.toolbar - - def undo(self, obj=None): + def undo(self, *obj): self.textbuffer.undo() - def redo(self, obj=None): + def redo(self, *obj): self.textbuffer.redo() +#------------------------------------------------------------------------- +# +# Module functions +# +#------------------------------------------------------------------------- + def uri_dialog(self, uri, callback): """ @@ -851,12 +902,14 @@ def uri_dialog(self, uri, callback): uri = "gramps://%s/handle/%s" % (object_class, handle) EditLink(obj.dbstate, obj.uistate, obj.track, uri, callback) -#------------------------------------------------------------------------- -# -# Module functions -# -#------------------------------------------------------------------------- def is_valid_fontsize(size): """Validator function for font size selector widget.""" return (size > 0) and (size < 73) + + +def make_cb(func, value): + """ + Generates a callback function based off the passed arguments + """ + return lambda x: func(x, value) diff --git a/gramps/gui/widgets/toolcomboentry.py b/gramps/gui/widgets/toolcomboentry.py deleted file mode 100644 index 124c3a19d..000000000 --- a/gramps/gui/widgets/toolcomboentry.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2008 Zsolt Foldvari -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -"ToolComboEntry class." - -__all__ = ["ToolComboEntry"] - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -import logging -_LOG = logging.getLogger(".widgets.toolcomboentry") - -#------------------------------------------------------------------------- -# -# GTK modules -# -#------------------------------------------------------------------------- -#from gi.repository import GObject -from gi.repository import Gtk - -#------------------------------------------------------------------------- -# -# Gramps modules -# -#------------------------------------------------------------------------- -from .valuetoolitem import ValueToolItem -from .shortlistcomboentry import ShortlistComboEntry - -#------------------------------------------------------------------------- -# -# ToolComboEntry class -# -#------------------------------------------------------------------------- -class ToolComboEntry(ValueToolItem): - """Tool bar item containing a ShortlistComboEntry widget.""" - __gtype_name__ = "ToolComboEntry" - - def _create_widget(self, items, editable, shortlist=True, validator=None): - self.set_border_width(2) - self.set_homogeneous(False) - self.set_expand(False) - - combo = ShortlistComboEntry(items, shortlist, validator) - if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) < (3, 20): - combo.set_focus_on_click(False) - else: - Gtk.Widget.set_focus_on_click(combo, False) - combo.set_entry_editable(editable) - combo.show() - self.add(combo) - - combo.connect('changed', self._on_widget_changed) - - def set_value(self, value): - self.get_child().set_active_data(value) - - def get_value(self): - return self.get_child().get_active_data() diff --git a/gramps/gui/widgets/validatedcomboentry.py b/gramps/gui/widgets/validatedcomboentry.py index 17a535ae6..e2520251a 100644 --- a/gramps/gui/widgets/validatedcomboentry.py +++ b/gramps/gui/widgets/validatedcomboentry.py @@ -65,7 +65,8 @@ class ValidatedComboEntry(Gtk.ComboBox): __gtype_name__ = "ValidatedComboEntry" def __init__(self, datatype, model=None, column=-1, validator=None, width=-1): - Gtk.ComboBox.__init__(self, model=model) + Gtk.ComboBox.__init__(self) + self.set_model(model) self._entry = Gtk.Entry() self._entry.set_width_chars(width) @@ -201,6 +202,9 @@ class ValidatedComboEntry(Gtk.ComboBox): self._internal_change = True new_iter = self._is_in_model(new_data) if new_iter is None: + if self.get_active_iter() is None: + # allows response when changing between two non-model values + self.set_active(0) self.set_active(-1) else: self.set_active_iter(new_iter) diff --git a/gramps/gui/widgets/valueaction.py b/gramps/gui/widgets/valueaction.py deleted file mode 100644 index 68e629252..000000000 --- a/gramps/gui/widgets/valueaction.py +++ /dev/null @@ -1,169 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2008 Zsolt Foldvari -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -"ValueAction class." - -__all__ = ["ValueAction"] - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -import logging -_LOG = logging.getLogger(".widgets.valueaction") - -#------------------------------------------------------------------------- -# -# GTK modules -# -#------------------------------------------------------------------------- -from gi.repository import GObject -from gi.repository import Gtk - -#------------------------------------------------------------------------- -# -# Gramps modules -# -#------------------------------------------------------------------------- -from .valuetoolitem import ValueToolItem - -#------------------------------------------------------------------------- -# -# ValueAction class -# -#------------------------------------------------------------------------- -class ValueAction(Gtk.Action): - """ - Value action class. - - (A ValueAction with menu item doesn't make any sense.) - """ - __gtype_name__ = "ValueAction" - - __gsignals__ = { - 'changed': (GObject.SignalFlags.RUN_FIRST, - None, #return value - ()), # arguments - } - - def __init__(self, name, tooltip, default, itemtype, *args): - """ - Create a new ValueAction instance. - - :param name: the name of the action - :type name: str - :param tooltip: tooltip string - :type tooltip: str - :param default: default value for the action, it will set the type of - the action and thus the type of all the connected - proxies. - :type default: set by itemtype - :param itemtype: default tool item class - :type itemtype: :class:`.ValueToolItem` subclass - :param args: arguments to be passed to the default toolitem class - at creation. see: :meth:`do_create_tool_item` - :type args: list - """ - Gtk.Action.__init__(self, name=name, label='', tooltip=tooltip, - stock_id=None) - - self._value = default - self._data_type = type(default) - - # have to be remembered, because we can't access - # GtkAction->toolbar_item_type later. - self._default_toolitem_type = itemtype -##TODO GTK3: following is deprecated, must be replaced by -## itemtype.set_related_action(ValueAction) in calling class? -## self.set_tool_item_type(itemtype) - self._args_for_toolitem = args - - self._handlers = {} - - def do_changed(self): - """ - Default signal handler for 'changed' signal. - - Synchronize all the proxies with the active value. - """ - for proxy in self.get_proxies(): - proxy.handler_block(self._handlers[proxy]) - proxy.set_value(self._value) - proxy.handler_unblock(self._handlers[proxy]) - - def do_create_tool_item(self): - """ - Create a 'default' toolbar item widget. - - Override the default method, to be able to pass the required - parameters to the proxy's constructor. - - This method is called from Gtk.UIManager.ensure_update(), when a - 'toolitem' is found in the UI definition with a name refering to a - ValueAction. Thus, to use the action via the UIManager a 'default' - toolitem type has to be set with the Gtk.Action.set_tool_item_type() - method, before invoking the Gtk.UIManager.ensure_update() method. - - Widgets other than the default type has to be created and added - manually with the Gtk.Action.connect_proxy() method. - - :returns: a toolbar item connected to the action. - :rtype: :class:`.ValueToolItem` subclass - """ - proxy = self._default_toolitem_type(self._data_type, - self._args_for_toolitem) - self.connect_proxy(proxy) - return proxy - - def _on_proxy_changed(self, proxy): - """Signal handler for the proxies' 'changed' signal.""" - value = proxy.get_value() - if value is not None: - self.set_value(value) - - def connect_proxy(self, proxy): - """ - Connect a widget to an action object as a proxy. - - :param proxy: widget to be connected - :type proxy: :class:`.ValueToolItem` subclass - """ - if not isinstance(proxy, ValueToolItem): - raise TypeError - - # do this before connecting, so that we don't call the handler - proxy.set_value(self._value) - self._handlers[proxy] = proxy.connect('changed', self._on_proxy_changed) - - # if this is called the proxy will appear on the proxy list twice. why? - #Gtk.Action.connect_proxy(self, proxy) - - def set_value(self, value): - """Set value to action.""" - if not isinstance(value, self._data_type): - raise TypeError - - self._value = value - self.emit('changed') - - def get_value(self): - """Get the value from the action.""" - return self._value diff --git a/gramps/gui/widgets/valuetoolitem.py b/gramps/gui/widgets/valuetoolitem.py deleted file mode 100644 index 0c8d355b0..000000000 --- a/gramps/gui/widgets/valuetoolitem.py +++ /dev/null @@ -1,92 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2008 Zsolt Foldvari -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -"ValueToolItem class." - -__all__ = ["ValueToolItem"] - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -import logging -_LOG = logging.getLogger(".widgets.valuetoolitem") - -#------------------------------------------------------------------------- -# -# GTK modules -# -#------------------------------------------------------------------------- -from gi.repository import GObject -from gi.repository import Gtk - - -#------------------------------------------------------------------------- -# -# ValueToolItem class -# -#------------------------------------------------------------------------- -class ValueToolItem(Gtk.ToolItem): - """ValueToolItem is an abstract toolbar proxy for ValueAction. - - For each kind of widget a separete tool item proxy has to be - subclassed from this ValueToolItem. - - """ - __gtype_name__ = "ValueToolItem" - - __gsignals__ = { - 'changed': (GObject.SignalFlags.RUN_FIRST, - None, #return value - ()), # arguments - } - - def __init__(self, data_type, args): - Gtk.ToolItem.__init__(self) - - self._data_type = data_type - - self._create_widget(*args) - - def _on_widget_changed(self, widget): - self.emit('changed') - - def _create_widget(self, args): - """Create the apropriate widget for the actual proxy.""" - raise NotImplementedError - - def set_value(self, value): - """Set new value for the proxied widget. - - The method is responsible converting the data type between action and - widget. - - """ - raise NotImplementedError - - def get_value(self): - """Get value from the proxied widget. - - The method is responsible converting the data type between action and - widget. - - """ - raise NotImplementedError diff --git a/gramps/plugins/lib/libpersonview.py b/gramps/plugins/lib/libpersonview.py index 58579f90a..4a91dccc8 100644 --- a/gramps/plugins/lib/libpersonview.py +++ b/gramps/plugins/lib/libpersonview.py @@ -48,7 +48,7 @@ _LOG = logging.getLogger(".gui.personview") from gramps.gen.lib import Person, Surname from gramps.gen.db import DbTxn from gramps.gui.views.listview import ListView, TEXT, MARKUP, ICON -from gramps.gui.actiongroup import ActionGroup +from gramps.gui.uimanager import ActionGroup from gramps.gen.utils.string import data_recover_msg from gramps.gen.display.name import displayer as name_displayer from gramps.gui.dialog import ErrorDialog, MultiSelectDialog, QuestionDialog @@ -152,15 +152,10 @@ class BasePersonView(ListView): multiple=True, filter_class=PersonSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - uistate.connect('nameformat-changed', self.build_tree) uistate.connect('placeformat-changed', self.build_tree) - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def navigation_type(self): """ @@ -187,70 +182,226 @@ class BasePersonView(ListView): """ return 'gramps-person' - def additional_ui(self): - """ - Defines the UI string for UIManager - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.SetActive + ''' + '''Set _Home Person + + + win.FilterEdit + ''' + '''Person Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + + + win.HomePerson + _Home + + + win.SetActive + ''' + '''Set _Home Person + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + + + +
+
+ ''' % _('action|_Edit...') # to use sgettext() + ] def get_handle_from_gramps_id(self, gid): """ @@ -262,7 +413,7 @@ class BasePersonView(ListView): else: return None - def add(self, obj): + def add(self, *obj): """ Add a new person to the database. """ @@ -276,7 +427,7 @@ class BasePersonView(ListView): except WindowActiveError: pass - def edit(self, obj): + def edit(self, *obj): """ Edit an existing person in the database. """ @@ -287,7 +438,7 @@ class BasePersonView(ListView): except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): """ Remove a person from the database. """ @@ -373,53 +524,7 @@ class BasePersonView(ListView): ListView.define_actions(self) - self.all_action = ActionGroup(name=self.title + "/PersonAll") - self.edit_action = ActionGroup(name=self.title + "/PersonEdit") - - self.all_action.add_actions([ - ('FilterEdit', None, _('Person Filter Editor'), None, None, - self.filter_editor), - ('Edit', 'gtk-edit', _("action|_Edit..."), - "Return", self.EDIT_MSG, self.edit), - ('QuickReport', None, _("Quick View"), None, None, None), - ('WebConnect', None, _("Web Connection"), None, None, None), - ]) - - - self.edit_action.add_actions( - [ - ('Add', 'list-add', _("_Add..."), "Insert", - self.ADD_MSG, self.add), - ('Remove', 'list-remove', _("_Delete"), "Delete", - self.DEL_MSG, self.remove), - ('Merge', 'gramps-merge', _('_Merge...'), None, - self.MERGE_MSG, self.merge), - ('ExportTab', None, _('Export View...'), None, None, - self.export), - ]) - - self._add_action_group(self.edit_action) - self._add_action_group(self.all_action) - - def enable_action_group(self, obj): - """ - Turns on the visibility of the View's action group. - """ - ListView.enable_action_group(self, obj) - self.all_action.set_visible(True) - self.edit_action.set_visible(True) - self.edit_action.set_sensitive(not self.dbstate.db.readonly) - - def disable_action_group(self): - """ - Turns off the visibility of the View's action group. - """ - ListView.disable_action_group(self) - - self.all_action.set_visible(False) - self.edit_action.set_visible(False) - - def merge(self, obj): + def merge(self, *obj): """ Merge the selected people. """ diff --git a/gramps/plugins/lib/libplaceview.py b/gramps/plugins/lib/libplaceview.py index 21f88df22..32ec7dd00 100644 --- a/gramps/plugins/lib/libplaceview.py +++ b/gramps/plugins/lib/libplaceview.py @@ -39,7 +39,6 @@ from gi.repository import Gtk #------------------------------------------------------------------------- from gramps.gen.lib import Place from gramps.gui.views.listview import ListView, TEXT, ICON -from gramps.gui.widgets.menuitem import add_menuitem from gramps.gen.errors import WindowActiveError from gramps.gui.views.bookmarks import PlaceBookmarks from gramps.gen.config import config @@ -51,6 +50,7 @@ from gramps.gui.filters.sidebar import PlaceSidebarFilter from gramps.gui.merge import MergePlace from gramps.gen.plug import CATEGORY_QR_PLACE from gramps.gen.utils.location import located_in +from gramps.gui.uimanager import ActionGroup #------------------------------------------------------------------------- # @@ -58,7 +58,7 @@ from gramps.gen.utils.location import located_in # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext #------------------------------------------------------------------------- @@ -117,6 +117,7 @@ class PlaceBaseView(ListView): self.mapservice = config.get('interface.mapservice') self.mapservicedata = {} + self.map_action_group = None ListView.__init__( self, title, pdata, dbstate, uistate, @@ -125,42 +126,17 @@ class PlaceBaseView(ListView): multiple=True, filter_class=PlaceSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - self.maptoolbtn = None - uistate.connect('placeformat-changed', self.build_tree) - self.additional_uis.append(self.additional_ui()) + _ui = self.__create_maps_menu_actions() + self.additional_uis.append(_ui) def navigation_type(self): return 'Place' def define_actions(self): ListView.define_actions(self) - self._add_toolmenu_action('MapsList', _('Loading...'), - _("Attempt to see selected locations with a Map " - "Service (OpenstreetMap, Google Maps, ...)"), - self.gotomap, - _('Select a Map Service')) - self._add_action('GotoMap', 'go-jump', - _('_Look up with Map Service'), - callback=self.gotomap, - tip=_("Attempt to see this location with a Map " - "Service (OpenstreetMap, Google Maps, ...)")) - self._add_action('FilterEdit', None, _('Place Filter Editor'), - callback=self.filter_editor) - self._add_action('QuickReport', None, _("Quick View"), None, None, None) - - def set_inactive(self): - """called by viewmanager when moving away from the page - Here we need to remove the menutoolbutton from the menu - """ - tb = self.uistate.viewmanager.uimanager.get_widget('/ToolBar') - tb.remove(self.maptoolbtn) - ListView.set_inactive(self) + self._add_action('GotoMap', self.gotomap) def change_page(self): """ @@ -173,39 +149,6 @@ class PlaceBaseView(ListView): 5. store label so it can be changed when selection changes """ ListView.change_page(self) - #menutoolbutton has to be made and added in correct place on toolbar - if not self.maptoolbtn: - self.maptoolbtn = Gtk.MenuToolButton() - self.maptoolbtn.set_icon_name('go-jump') - self.maptoolbtn.connect('clicked', self.gotomap) - self.mmenu = self.__create_maps_menu_actions() - self.maptoolbtn.set_menu(self.mmenu) - self.maptoolbtn.show() - tb = self.uistate.viewmanager.uimanager.get_widget('/ToolBar') - ind = tb.get_item_index(self.uistate.viewmanager.uimanager.get_widget( - '/ToolBar/CommonEdit/Merge')) - tb.insert(self.maptoolbtn, ind+1) - widget = self.maptoolbtn - - if not self.mapservicedata: - return - - self.mapslistlabel = [] - if not self.mapservice in self.mapservicedata: - #stored val no longer exists, use the first key instead - self.set_mapservice(list(self.mapservicedata.keys())[0]) - - #store all gtk labels to be able to update label on selection change_('Loading...'), - widget.set_menu(self.mmenu) - widget.set_arrow_tooltip_text(_('Select a Map Service')) - widget.set_tooltip_text( - _("Attempt to see selected locations with a Map " - "Service (OpenstreetMap, Google Maps, ...)")) - lbl = Gtk.Label(label=self.mapservice_label()) - lbl.show() - self.mapslistlabel.append(lbl) - widget.set_label_widget(self.mapslistlabel[-1]) - widget.set_icon_name('go-jump') if self.drag_info(): self.list.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [], @@ -222,30 +165,52 @@ class PlaceBaseView(ListView): Function creating a menu and actions that are used as dropdown menu from the menutoolbutton """ - menu = Gtk.Menu() + _bar = ''' + + win.MapChoice + %s + %s + + ''' + menu = '' #select the map services to show self.mapservicedata = {} servlist = GuiPluginManager.get_instance().get_reg_mapservices() - for i, pdata in enumerate(servlist): + for pdata in servlist: key = pdata.id.replace(' ', '-') - add_menuitem(menu, pdata.name, None, - make_callback(self.set_mapservice, key)) + menu += _bar % (key, pdata.name) self.mapservicedata[key] = pdata - return menu + if not self.mapservicedata: + return self.additional_ui + if self.mapservice not in self.mapservicedata: + #stored val no longer exists, use the most recent key instead + self.set_mapservice(None, key) - def set_mapservice(self, mapkey): + self._add_toggle_action('MapChoice', self.set_mapservice, '', + self.mapservice) + + label = self.mapservice_label() + _ui = self.additional_ui[:] + _ui.append(self.map_ui_menu % menu) + _ui.append(self.map_ui % label) + return _ui + + def set_mapservice(self, action, value): """ change the service that runs on click of the menutoolbutton used as callback menu on menu clicks """ - self.mapservice = mapkey - for label in self.mapslistlabel: - label.set_label(self.mapservice_label()) - label.show() + if action: + action.set_state(value) + self.mapservice = mapkey = value.get_string() config.set('interface.mapservice', mapkey) config.save() + _ui = self.__create_maps_menu_actions() + self.uimanager.add_ui_from_string(_ui) + self.uimanager.update_menu() + return False def mapservice_label(self): """ @@ -253,7 +218,7 @@ class PlaceBaseView(ListView): """ return self.mapservicedata[self.mapservice].name - def gotomap(self, obj): + def gotomap(self, *obj): """ Run the map service """ @@ -295,72 +260,245 @@ class PlaceBaseView(ListView): def get_stock(self): return 'gramps-place' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + # + # Defines the UI string for UIManager + # + additional_ui = [ + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Place Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+ + win.GotoMap + ''' + '''_Look up with Map Service + +
+
+''' % _('action|_Edit...')] # to use sgettext() - def add(self, obj): + map_ui_menu = ''' + + %s + + ''' + + map_ui = ( + ''' + + + go-jump + win.GotoMap + ''' + '''Attempt to see selected locations with a Map Service ''' + '''(OpenstreetMap, Google Maps, ...) + %s + True + + + False + + + + + + + ''' + '''Select a Map Service + MapBtnMenu + GTK_RELIEF_NONE + False + + + + + + ''') + + def add(self, *obj): try: EditPlace(self.dbstate, self.uistate, [], Place()) except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): for handle in self.selected_handles(): for link in self.dbstate.db.find_backlink_handles(handle,['Place']): msg = _("Cannot delete place.") @@ -390,7 +528,7 @@ class PlaceBaseView(ListView): is_used = len(person_list) + len(family_list) + len(event_list) > 0 return (query, is_used, object) - def edit(self, obj): + def edit(self, *obj): for handle in self.selected_handles(): place = self.dbstate.db.get_place_from_handle(handle) try: @@ -398,7 +536,7 @@ class PlaceBaseView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected places. """ @@ -468,5 +606,6 @@ class PlaceBaseView(ListView): "Place Notes", "Place Backlinks")) + def make_callback(func, val): - return lambda x: func(val) + return lambda x, y: func(val) diff --git a/gramps/plugins/lib/maps/geography.py b/gramps/plugins/lib/maps/geography.py index f2b625b95..3fca483cd 100644 --- a/gramps/plugins/lib/maps/geography.py +++ b/gramps/plugins/lib/maps/geography.py @@ -191,7 +191,7 @@ class GeoGraphyView(OsmGps, NavigationView): self.clearmap = None self.nbplaces = 0 - def add_bookmark(self, menu): + def add_bookmark(self, *menu): """ Add the place to the bookmark """ @@ -300,16 +300,7 @@ class GeoGraphyView(OsmGps, NavigationView): another method. """ NavigationView.define_actions(self) - self.define_print_actions() - - def define_print_actions(self): - """ - Associate the print button to the PrintView action. - """ - self._add_action('PrintView', 'document-print', _("_Print..."), - accel="P", - tip=_("Print or save the Map"), - callback=self.printview) + self._add_action('PrintView', self.printview, 'P') def config_connect(self): """ @@ -345,7 +336,6 @@ class GeoGraphyView(OsmGps, NavigationView): """ self.menu = Gtk.Menu() menu = self.menu - menu.set_title(_('Map Menu')) if config.get("geography.show_cross"): title = _('Remove cross hair') @@ -876,7 +866,7 @@ class GeoGraphyView(OsmGps, NavigationView): # Printing functionalities # #------------------------------------------------------------------------- - def printview(self, obj): + def printview(self, *obj): """ Print or save the view that is currently shown """ diff --git a/gramps/plugins/sidebar/categorysidebar.py b/gramps/plugins/sidebar/categorysidebar.py index c4458ca23..29ce50b4d 100644 --- a/gramps/plugins/sidebar/categorysidebar.py +++ b/gramps/plugins/sidebar/categorysidebar.py @@ -88,14 +88,6 @@ class CategorySidebar(BaseSidebar): button.drag_dest_set(0, [], 0) button.connect('drag_motion', self.cb_switch_page_on_dnd, cat_num) - # toollbar buttons for switching views in a category - uitoolitems = '' - for view_num, view_name, view_icon in views[cat_num]: - pageid = 'page_%i_%i' % (cat_num, view_num) - uitoolitems += '\n' % pageid - if len(views[cat_num]) > 1: - self.ui_category[cat_num] = UICATEGORY % uitoolitems - vbox.show_all() def get_top(self): diff --git a/gramps/plugins/view/citationlistview.py b/gramps/plugins/view/citationlistview.py index 297a36a67..c2bfab321 100644 --- a/gramps/plugins/view/citationlistview.py +++ b/gramps/plugins/view/citationlistview.py @@ -62,7 +62,7 @@ from gramps.gui.merge import MergeCitation # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext #------------------------------------------------------------------------- @@ -146,12 +146,7 @@ class CitationListView(ListView): multiple=True, filter_class=CitationSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def navigation_type(self): return 'Citation' @@ -159,94 +154,196 @@ class CitationListView(ListView): def drag_info(self): return DdTargets.CITATION_LINK - def define_actions(self): - """ - This defines the possible actions for the citation views. - Possible actions are: - add: Add a new citation and a new source (this can also be done - by source view add a source, then citation view add a new - citation to an existing source) - edit: Edit a citation. - merge: Merge the selected citations. - remove: Delete the selected citations. - - - """ - ListView.define_actions(self) - - self.all_action = Gtk.ActionGroup(name=self.title + "/CitationAll") - self.edit_action = Gtk.ActionGroup(name=self.title + "/CitationEdit") - - self._add_action('FilterEdit', None, _('Citation Filter Editor'), - callback=self.filter_editor,) - self._add_action('QuickReport', None, _("Quick View"), None, None, None) - - self._add_action_group(self.edit_action) - self._add_action_group(self.all_action) - def get_stock(self): return 'gramps-citation' - def additional_ui(self): - """ - Defines the UI string for UIManager - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Citation Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+''' % _('action|_Edit...') # to use sgettext() +] - def add(self, obj): + def add(self, *obj): """ add: Add a new citation and a new source (this can also be done by source view add a source, then citation view add a new @@ -269,7 +366,7 @@ class CitationListView(ListView): except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): self.remove_selected_objects() def remove_object_from_handle(self, handle): @@ -280,7 +377,7 @@ class CitationListView(ListView): is_used = any(the_lists) return (query, is_used, object) - def edit(self, obj): + def edit(self, *obj): """ Edit a Citation """ @@ -301,7 +398,7 @@ class CitationListView(ListView): "the same citation is being edited.\n\nTo edit this " "citation, you need to close the object.") - def merge(self, obj): + def merge(self, *obj): """ Merge the selected citations. """ diff --git a/gramps/plugins/view/citationtreeview.py b/gramps/plugins/view/citationtreeview.py index 8121e9620..2cc1c0699 100644 --- a/gramps/plugins/view/citationtreeview.py +++ b/gramps/plugins/view/citationtreeview.py @@ -65,7 +65,7 @@ from gramps.gui.merge import MergeCitation, MergeSource # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext #------------------------------------------------------------------------- # @@ -147,12 +147,7 @@ class CitationTreeView(ListView): multiple=True, filter_class=SourceSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) # Override change_active from NavigationView, so that only Citations can be # put in the history list for the CitationTreeView @@ -298,100 +293,241 @@ class CitationTreeView(ListView): """ ListView.define_actions(self) - self._add_action('Add source', 'gramps-source', _("Add source..."), - accel=None, - tip=self.ADD_SOURCE_MSG, - callback=self.add_source) - self._add_action('Add citation', 'gramps-citation', - _("Add citation..."), - accel=None, - tip=self.ADD_CITATION_MSG, - callback=self.share) + self.action_list.extend([ + ('AddSource', self.add_source), + ('AddCitation', self.share), + ('OpenAllNodes', self.open_all_nodes), + ('CloseAllNodes', self.close_all_nodes), ]) - self.all_action = Gtk.ActionGroup(name=self.title + "/CitationAll") - self.edit_action = Gtk.ActionGroup(name=self.title + "/CitationEdit") + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.AddSource + Add source... + + + win.AddCitation + Add citation... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Citation Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gramps-source + win.AddSource + %s + Add source... + + + False + + + + + gramps-citation + win.AddCitation + %s + Add citation... + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, ADD_SOURCE_MSG, ADD_CITATION_MSG, EDIT_MSG, DEL_MSG, + MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+ + win.OpenAllNodes + ''' + '''Expand all Nodes + + + win.CloseAllNodes + ''' + '''Collapse all Nodes + +
+
+ + win.Add + _Add... + + + win.AddCitation + ''' + '''Add citation... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+''' % _('action|_Edit...') # to use sgettext() +] - self._add_action('FilterEdit', None, _('Citation Filter Editor'), - callback=self.filter_editor,) - self._add_action('QuickReport', None, _("Quick View"), None, None, None) - - self._add_action_group(self.edit_action) - self._add_action_group(self.all_action) - - self.all_action.add_actions([ - ('OpenAllNodes', None, _("Expand all Nodes"), None, None, - self.open_all_nodes), - ('CloseAllNodes', None, _("Collapse all Nodes"), None, None, - self.close_all_nodes), - ]) - - def additional_ui(self): - """ - Defines the UI string for UIManager - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' - - def add_source(self, obj): + def add_source(self, *obj): """ add_source: Add a new source (this is also available from the source view) @@ -412,7 +548,7 @@ class CitationTreeView(ListView): except WindowActiveError: pass - def add(self, obj): + def add(self, *obj): """ add: Add a new citation and a new source (this can also be done by source view add a source, then citation view add a new @@ -435,7 +571,7 @@ class CitationTreeView(ListView): except WindowActiveError: pass - def share(self, obj): + def share(self, *obj): """ share: Add a new citation to an existing source (when a source is selected) @@ -455,7 +591,7 @@ class CitationTreeView(ListView): self.__blocked_text(), parent=self.uistate.window) # - def remove(self, obj): + def remove(self, *obj): self.remove_selected_objects() def remove_object_from_handle(self, handle): @@ -477,7 +613,7 @@ class CitationTreeView(ListView): is_used = any(the_lists) return (query, is_used, source) - def edit(self, obj): + def edit(self, *obj): """ Edit either a Source or a Citation, depending on user selection """ @@ -518,7 +654,7 @@ class CitationTreeView(ListView): "source is being edited.\n\nTo edit this " "source, you need to close the object.") - def merge(self, obj): + def merge(self, *obj): """ Merge the selected citations. """ diff --git a/gramps/plugins/view/dashboardview.py b/gramps/plugins/view/dashboardview.py index a54a8f26f..a004227cb 100644 --- a/gramps/plugins/view/dashboardview.py +++ b/gramps/plugins/view/dashboardview.py @@ -49,12 +49,7 @@ class DashboardView(PageView): Create a DashboardView, with the current dbstate and uistate """ PageView.__init__(self, _('Dashboard'), pdata, dbstate, uistate) - self.ui_def = ''' - - - - - ''' + self.ui_def = [] # No special menu for Dashboard, Popup in GrampletPane def build_interface(self): """ @@ -101,10 +96,11 @@ class DashboardView(PageView): def define_actions(self): """ - Defines the UIManager actions. + Defines the UIManager actions. Called by the ViewManager to set up the + View. The user typically defines self.action_list and + self.action_toggle_list in this function. """ - self._add_action("AddGramplet", 'list-add', _("Add a gramplet")) - self._add_action("RestoreGramplet", None, _("Restore a gramplet")) + pass def set_inactive(self): self.active = False diff --git a/gramps/plugins/view/eventview.py b/gramps/plugins/view/eventview.py index b403fe9e5..f940a7022 100644 --- a/gramps/plugins/view/eventview.py +++ b/gramps/plugins/view/eventview.py @@ -38,7 +38,7 @@ _LOG = logging.getLogger(".plugins.eventview") # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext from gramps.gui.dialog import ErrorDialog, MultiSelectDialog, QuestionDialog from gramps.gen.errors import WindowActiveError @@ -126,15 +126,10 @@ class EventView(ListView): multiple=True, filter_class=EventSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - uistate.connect('nameformat-changed', self.build_tree) uistate.connect('placeformat-changed', self.build_tree) - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def person_update(self, hndl_list): """ Deal with person updates thay may effect the Main Participants @@ -176,71 +171,191 @@ class EventView(ListView): """ return 'gramps-event' - def additional_ui(self): - """ - Defines the UI string for UIManager - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' - - def define_actions(self): - ListView.define_actions(self) - self._add_action('FilterEdit', None, - _('Event Filter Editor'), callback=self.filter_editor) - self._add_action('QuickReport', None, - _("Quick View"), None, None, None) + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Event Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+''' % _('action|_Edit...') # to use sgettext() + ] def get_handle_from_gramps_id(self, gid): obj = self.dbstate.db.get_event_from_gramps_id(gid) @@ -249,13 +364,13 @@ class EventView(ListView): else: return None - def add(self, obj): + def add(self, *obj): try: EditEvent(self.dbstate, self.uistate, [], Event()) except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): """ Method called when deleting event(s) from the event view. """ @@ -310,7 +425,7 @@ class EventView(ListView): """ pass - def edit(self, obj): + def edit(self, *obj): for handle in self.selected_handles(): event = self.dbstate.db.get_event_from_handle(handle) try: @@ -318,7 +433,7 @@ class EventView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected events. """ diff --git a/gramps/plugins/view/familyview.py b/gramps/plugins/view/familyview.py index 3c3f71730..f046e5069 100644 --- a/gramps/plugins/view/familyview.py +++ b/gramps/plugins/view/familyview.py @@ -29,7 +29,7 @@ Family View. # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext import logging _LOG = logging.getLogger(".plugins.eventview") #------------------------------------------------------------------------- @@ -120,14 +120,9 @@ class FamilyView(ListView): multiple=True, filter_class=FamilySidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - uistate.connect('nameformat-changed', self.build_tree) - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def navigation_type(self): return 'Family' @@ -135,84 +130,214 @@ class FamilyView(ListView): def get_stock(self): return 'gramps-family' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Family Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + win.MakeFatherActive + ''' + '''Make Father Active Person + + + win.MakeMotherActive + ''' + '''Make Mother Active Person + +
+
+ + +
+
+''' % _('action|_Edit...') # to use sgettext() + ] def define_actions(self): """Add the Forward action group to handle the Forward button.""" ListView.define_actions(self) - self._add_action('FilterEdit', None, _('Family Filter Editor'), - callback=self.filter_editor,) + self.action_list.extend([ + ('MakeFatherActive', self._make_father_active), + ('MakeMotherActive', self._make_mother_active), ]) - self.all_action = Gtk.ActionGroup(name=self.title + "/FamilyAll") - self.all_action.add_actions([ - ('MakeFatherActive', None, _("Make Father Active Person"), - None, None, self._make_father_active), - ('MakeMotherActive', None, _("Make Mother Active Person"), - None, None, self._make_mother_active), - ('QuickReport', None, _("Quick View"), None, None, None), - ]) - self._add_action_group(self.all_action) - - def add_bookmark(self, obj): + def add_bookmark(self, *obj): mlist = self.selected_handles() if mlist: self.bookmarks.add(mlist[0]) @@ -223,14 +348,14 @@ class FamilyView(ListView): _("A bookmark could not be set because " "no one was selected."), parent=self.uistate.window) - def add(self, obj): + def add(self, *obj): family = Family() try: EditFamily(self.dbstate, self.uistate, [], family) except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): """ Method called when deleting a family from a family view. """ @@ -289,7 +414,7 @@ class FamilyView(ListView): """ pass - def edit(self, obj): + def edit(self, *obj): for handle in self.selected_handles(): family = self.dbstate.db.get_family_from_handle(handle) try: @@ -297,7 +422,7 @@ class FamilyView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected families. """ @@ -312,7 +437,7 @@ class FamilyView(ListView): else: MergeFamily(self.dbstate, self.uistate, [], mlist[0], mlist[1]) - def _make_father_active(self, obj): + def _make_father_active(self, *obj): """ Make the father of the family the active person. """ @@ -322,7 +447,7 @@ class FamilyView(ListView): if family: self.uistate.set_active(family.father_handle, 'Person') - def _make_mother_active(self, obj): + def _make_mother_active(self, *obj): """ Make the mother of the family the active person. """ diff --git a/gramps/plugins/view/fanchart2wayview.py b/gramps/plugins/view/fanchart2wayview.py index 00c670744..9a7ab7fc3 100644 --- a/gramps/plugins/view/fanchart2wayview.py +++ b/gramps/plugins/view/fanchart2wayview.py @@ -47,6 +47,7 @@ import gramps.gui.widgets.fanchart2way as fanchart2way from gramps.gui.views.navigationview import NavigationView from gramps.gui.views.bookmarks import PersonBookmarks from gramps.gui.utils import SystemFonts +from gramps.plugins.view.fanchartview import FanChartView # the print settings to remember between print sessions PRINT_SETTINGS = None @@ -101,13 +102,9 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView): dbstate.connect('active-changed', self.active_changed) dbstate.connect('database-changed', self.change_db) - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(FanChartView.additional_ui) self.allfonts = [x for x in enumerate(SystemFonts().get_system_fonts())] - self.func_list.update({ - 'J' : self.jump, - }) - def navigation_type(self): return 'Person' @@ -144,43 +141,6 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView): """ return 'gramps-fanchart' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' - def define_actions(self): """ Required define_actions function for PageView. Builds the action @@ -188,10 +148,9 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView): """ NavigationView.define_actions(self) - self._add_action('PrintView', Gtk.STOCK_PRINT, _("_Print..."), - accel="P", - tip=_("Print or save the Fan Chart View"), - callback=self.printview) + self._add_action('PrintView', self.printview, "P") + self._add_action('PRIMARY-J', self.jump, 'J') + def build_tree(self): """ Generic method called by PageView to construct the view. @@ -249,7 +208,7 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView): if self.active: self.bookmarks.redraw() - def printview(self, obj): + def printview(self, *obj): """ Print or save the view that is currently shown """ diff --git a/gramps/plugins/view/fanchartdescview.py b/gramps/plugins/view/fanchartdescview.py index 23e636327..51093acae 100644 --- a/gramps/plugins/view/fanchartdescview.py +++ b/gramps/plugins/view/fanchartdescview.py @@ -46,6 +46,7 @@ import gramps.gui.widgets.fanchartdesc as fanchartdesc from gramps.gui.views.navigationview import NavigationView from gramps.gui.views.bookmarks import PersonBookmarks from gramps.gui.utils import SystemFonts +from gramps.plugins.view.fanchartview import FanChartView # the print settings to remember between print sessions PRINT_SETTINGS = None @@ -96,13 +97,9 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView): dbstate.connect('active-changed', self.active_changed) dbstate.connect('database-changed', self.change_db) - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(FanChartView.additional_ui) self.allfonts = [x for x in enumerate(SystemFonts().get_system_fonts())] - self.func_list.update({ - 'J' : self.jump, - }) - def navigation_type(self): return 'Person' @@ -139,43 +136,6 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView): """ return 'gramps-fanchart' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' - def define_actions(self): """ Required define_actions function for PageView. Builds the action @@ -183,10 +143,9 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView): """ NavigationView.define_actions(self) - self._add_action('PrintView', 'document-print', _("_Print..."), - accel="P", - tip=_("Print or save the Fan Chart View"), - callback=self.printview) + self._add_action('PrintView', self.printview, "P") + self._add_action('PRIMARY-J', self.jump, 'J') + def build_tree(self): """ Generic method called by PageView to construct the view. @@ -244,7 +203,7 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView): if self.active: self.bookmarks.redraw() - def printview(self, obj): + def printview(self, *obj): """ Print or save the view that is currently shown """ diff --git a/gramps/plugins/view/fanchartview.py b/gramps/plugins/view/fanchartview.py index bf1b86cda..65b3f557b 100644 --- a/gramps/plugins/view/fanchartview.py +++ b/gramps/plugins/view/fanchartview.py @@ -34,7 +34,7 @@ from gi.repository import Gdk from gi.repository import Gtk import cairo from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext #------------------------------------------------------------------------- # @@ -93,13 +93,9 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView): dbstate.connect('active-changed', self.active_changed) dbstate.connect('database-changed', self.change_db) - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) self.allfonts = [x for x in enumerate(SystemFonts().get_system_fonts())] - self.func_list.update({ - 'J' : self.jump, - }) - def navigation_type(self): return 'Person' @@ -135,42 +131,107 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView): """ return 'gramps-fanchart' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + additional_ui = [ # Defines the UI string for UIManager ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' +
+ + win.PrintView + _Print... + +
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + +''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Fan Chart View + _Print... + True + + + False + + + + '''] def define_actions(self): """ @@ -179,10 +240,9 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView): """ NavigationView.define_actions(self) - self._add_action('PrintView', 'document-print', _("_Print..."), - accel="P", - tip=_("Print or save the Fan Chart View"), - callback=self.printview) + self._add_action('PrintView', self.printview, "P") + self._add_action('PRIMARY-J', self.jump, 'J') + def build_tree(self): """ Generic method called by PageView to construct the view. @@ -240,7 +300,7 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView): if self.active: self.bookmarks.redraw() - def printview(self, obj): + def printview(self, *obj): """ Print or save the view that is currently shown """ diff --git a/gramps/plugins/view/geoclose.py b/gramps/plugins/view/geoclose.py index f831a9c01..f029cdaf3 100644 --- a/gramps/plugins/view/geoclose.py +++ b/gramps/plugins/view/geoclose.py @@ -54,12 +54,12 @@ from gramps.gen.datehandler import displayer, get_date from gramps.gen.display.name import displayer as _nd from gramps.gen.display.place import displayer as _pd from gramps.gen.utils.place import conv_lat_lon -from gramps.gui.views.navigationview import NavigationView from gramps.gui.views.bookmarks import PersonBookmarks from gramps.plugins.lib.maps import constants from gramps.plugins.lib.maps.geography import GeoGraphyView from gramps.gui.selectors import SelectorFactory from gramps.gen.utils.db import (get_birth_or_fallback, get_death_or_fallback) +from gramps.gui.uimanager import ActionGroup #------------------------------------------------------------------------- # @@ -67,43 +67,120 @@ from gramps.gen.utils.db import (get_birth_or_fallback, get_death_or_fallback) # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [ + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+ ''', + ''' +
+ + win.PrintView + _Print... + +
+ ''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+ ''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + + + gramps-person + win.RefPerson + ''' + '''Select the person which is the reference for life ways + reference _Person + True + + + False + + + + ''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Map + _Print... + True + + + False + + + + '''] # pylint: disable=no-member # pylint: disable=unused-argument @@ -291,18 +368,10 @@ class GeoClose(GeoGraphyView): """ Define action for the reference person button. """ - NavigationView.define_actions(self) + GeoGraphyView.define_actions(self) + self._add_action('RefPerson', self.select_person) - self.define_print_actions() - self.ref_person = Gtk.ActionGroup(name=self.title + '/Selection') - self.ref_person.add_actions([ - ('RefPerson', 'gramps-person', _('reference _Person'), None, - _("Select the person which is the reference for life ways"), - self.select_person), - ]) - self._add_action_group(self.ref_person) - - def select_person(self, obj): + def select_person(self, *obj): """ Open a selection box to choose the ref person. """ diff --git a/gramps/plugins/view/geoevents.py b/gramps/plugins/view/geoevents.py index fcf54eb94..1a6f28284 100644 --- a/gramps/plugins/view/geoevents.py +++ b/gramps/plugins/view/geoevents.py @@ -64,39 +64,84 @@ from gramps.gui.utils import ProgressMeter # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ ''', + ''' +
+ + win.PrintView + _Print... + +
+ ''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+ ''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + Go to the next object in the history + _Forward + True + + + False + + + + ''', + ''' + + + + document-print + win.PrintView + Print or save the Map + _Print... + True + + + False + + + + '''] # pylint: disable=unused-argument # pylint: disable=no-member diff --git a/gramps/plugins/view/geofamclose.py b/gramps/plugins/view/geofamclose.py index 266ff6d81..fca0c28e4 100644 --- a/gramps/plugins/view/geofamclose.py +++ b/gramps/plugins/view/geofamclose.py @@ -65,43 +65,120 @@ from gramps.gui.selectors import SelectorFactory # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [ + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' +
+ + win.PrintView + _Print... + +
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + + + gramps-family + win.RefFamily + ''' + '''Select the family which is the reference for life ways + reference _Family + True + + + False + + + +''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Map + _Print... + True + + + False + + + + '''] # pylint: disable=no-member # pylint: disable=unused-variable @@ -287,18 +364,10 @@ class GeoFamClose(GeoGraphyView): """ Define action for the reference family button. """ - NavigationView.define_actions(self) + GeoGraphyView.define_actions(self) + self._add_action('RefFamily', self.select_family) - self.define_print_actions() - self.ref_family = Gtk.ActionGroup(self.title + '/Selection') - self.ref_family.add_actions([ - ('RefFamily', 'gramps-family', _('reference _Family'), None, - _("Select the family which is the reference for life ways"), - self.select_family), - ]) - self._add_action_group(self.ref_family) - - def select_family(self, obj): + def select_family(self, *obj): """ Open a selection box to choose the ref family. """ diff --git a/gramps/plugins/view/geofamily.py b/gramps/plugins/view/geofamily.py index 977fc9af6..42fcac16d 100644 --- a/gramps/plugins/view/geofamily.py +++ b/gramps/plugins/view/geofamily.py @@ -63,39 +63,88 @@ from gramps.plugins.lib.maps.geography import GeoGraphyView # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [ + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.PrintView + _Print... + +
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ... + ...Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Map + _Print... + True + + + False + + + + '''] # pylint: disable=no-member # pylint: disable=unused-variable diff --git a/gramps/plugins/view/geomoves.py b/gramps/plugins/view/geomoves.py index 6855c4e14..00234c764 100644 --- a/gramps/plugins/view/geomoves.py +++ b/gramps/plugins/view/geomoves.py @@ -64,42 +64,107 @@ from gramps.plugins.lib.maps.geography import GeoGraphyView # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [ + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' +
+ + win.PrintView + _Print... + +
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + +''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Map + _Print... + True + + + False + + + + '''] # pylint: disable=no-member # pylint: disable=unused-variable diff --git a/gramps/plugins/view/geoperson.py b/gramps/plugins/view/geoperson.py index b0648fc2f..2c5e09c3f 100644 --- a/gramps/plugins/view/geoperson.py +++ b/gramps/plugins/view/geoperson.py @@ -65,42 +65,107 @@ from gramps.plugins.lib.maps.geography import GeoGraphyView # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [ + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' +
+ + win.PrintView + _Print... + +
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + +''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Map + reference _Family + True + + + False + + + + '''] # pylint: disable=no-member # pylint: disable=maybe-no-member diff --git a/gramps/plugins/view/geoplaces.py b/gramps/plugins/view/geoplaces.py index 9a4cb6423..d2832b927 100644 --- a/gramps/plugins/view/geoplaces.py +++ b/gramps/plugins/view/geoplaces.py @@ -65,39 +65,88 @@ from gramps.gui.utils import ProgressMeter # #------------------------------------------------------------------------- -_UI_DEF = '''\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -''' +_UI_DEF = [ + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.PrintView + _Print... + +
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + document-print + win.PrintView + ''' + '''Print or save the Map + _Print... + True + + + False + + + + '''] # pylint: disable=no-member # pylint: disable=maybe-no-member diff --git a/gramps/plugins/view/mediaview.py b/gramps/plugins/view/mediaview.py index 2644af1a3..bcc22a013 100644 --- a/gramps/plugins/view/mediaview.py +++ b/gramps/plugins/view/mediaview.py @@ -30,7 +30,7 @@ Media View. # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext import os from urllib.parse import urlparse from urllib.request import url2pathname @@ -133,12 +133,7 @@ class MediaView(ListView): filter_class=MediaSidebarFilter, multiple=True) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) self.uistate = uistate def navigation_type(self): @@ -206,19 +201,10 @@ class MediaView(ListView): """ ListView.define_actions(self) - self._add_action('FilterEdit', None, _('Media Filter Editor'), - callback=self.filter_editor) - self._add_action('OpenMedia', 'gramps-viewmedia', _('View'), - tip=_("View in the default viewer"), - callback=self.view_media) - self._add_action('OpenContainingFolder', None, - _('Open Containing _Folder'), - tip=_("Open the folder containing the media file"), - callback=self.open_containing_folder) + self._add_action('OpenMedia', self.view_media) + self._add_action('OpenContainingFolder', self.open_containing_folder) - self._add_action('QuickReport', None, _("Quick View"), None, None, None) - - def view_media(self, obj): + def view_media(self, *obj): """ Launch external viewers for the selected objects. """ @@ -227,7 +213,7 @@ class MediaView(ListView): mpath = media_path_full(self.dbstate.db, ref_obj.get_path()) open_file_with_default_application(mpath, self.uistate) - def open_containing_folder(self, obj): + def open_containing_folder(self, *obj): """ Launch external viewers for the selected objects. """ @@ -244,78 +230,225 @@ class MediaView(ListView): """ return 'gramps-media' - def additional_ui(self): - """ - Return the UIManager XML description of the menus - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Media Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + + + + gramps-viewmedia + win.OpenMedia + ''' + '''View in the default viewer + View + + + False + + + +''', + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+ + win.OpenMedia + View + + + win.OpenContainingFolder + ''' + '''Open Containing _Folder + +
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+''' % _('action|_Edit...') # to use sgettext() + ] - def add(self, obj): + def add(self, *obj): """Add a new media object to the media list""" try: EditMedia(self.dbstate, self.uistate, [], Media()) except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): self.remove_selected_objects() def remove_object_from_handle(self, handle): @@ -329,7 +462,7 @@ class MediaView(ListView): is_used = any(the_lists) return (query, is_used, object) - def edit(self, obj): + def edit(self, *obj): """ Edit the selected objects in the EditMedia dialog """ @@ -340,7 +473,7 @@ class MediaView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected objects. """ diff --git a/gramps/plugins/view/noteview.py b/gramps/plugins/view/noteview.py index 2002c2414..e295f52e1 100644 --- a/gramps/plugins/view/noteview.py +++ b/gramps/plugins/view/noteview.py @@ -28,7 +28,7 @@ Note View. # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext import logging _LOG = logging.getLogger(".plugins.noteview") @@ -113,12 +113,7 @@ class NoteView(ListView): filter_class=NoteSidebarFilter, multiple=True) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def navigation_type(self): return 'Note' @@ -135,70 +130,191 @@ class NoteView(ListView): """ return 'gramps-notes' - def additional_ui(self): - """ - Defines the UI string for UIManager - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' - - def define_actions(self): - ListView.define_actions(self) - self._add_action('FilterEdit', None, _('Note Filter Editor'), - callback=self.filter_editor,) - self._add_action('QuickReport', None, _("Quick View"), None, None, None) + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Note Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+ ''' % _('action|_Edit...') # to use sgettext() + ] def get_handle_from_gramps_id(self, gid): obj = self.dbstate.db.get_note_from_gramps_id(gid) @@ -207,13 +323,13 @@ class NoteView(ListView): else: return None - def add(self, obj): + def add(self, *obj): try: EditNote(self.dbstate, self.uistate, [], Note()) except WindowActiveError: pass - def remove(self, obj): + def remove(self, *obj): self.remove_selected_objects() def remove_object_from_handle(self, handle): @@ -223,7 +339,7 @@ class NoteView(ListView): is_used = any(the_lists) return (query, is_used, object) - def edit(self, obj): + def edit(self, *obj): for handle in self.selected_handles(): note = self.dbstate.db.get_note_from_handle(handle) try: @@ -231,7 +347,7 @@ class NoteView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected notes. """ diff --git a/gramps/plugins/view/pedigreeview.py b/gramps/plugins/view/pedigreeview.py index 6bb65d8d4..3529d3279 100644 --- a/gramps/plugins/view/pedigreeview.py +++ b/gramps/plugins/view/pedigreeview.py @@ -63,7 +63,6 @@ from gramps.gui.ddtargets import DdTargets from gramps.gen.config import config from gramps.gui.views.bookmarks import PersonBookmarks from gramps.gen.const import CUSTOM_FILTERS -from gramps.gen.constfunc import is_quartz, win from gramps.gui.dialog import RunDatabaseRepair, ErrorDialog from gramps.gui.utils import color_graph_box, hex_to_rgb_float, is_right_click from gramps.gen.constfunc import lin @@ -528,11 +527,6 @@ class PedigreeView(NavigationView): NavigationView.__init__(self, _('Pedigree'), pdata, dbstate, uistate, PersonBookmarks, nav_group) - self.func_list.update({ - 'F2' : self.kb_goto_home, - 'J' : self.jump, - }) - self.dbstate = dbstate self.dbstate.connect('database-changed', self.change_db) uistate.connect('nameformat-changed', self.person_rebuild) @@ -551,7 +545,7 @@ class PedigreeView(NavigationView): self.scrolledwindow = None self.table = None - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) # Automatic resize self.force_size = self._config.get('interface.pedview-tree-size') @@ -572,10 +566,6 @@ class PedigreeView(NavigationView): self.show_unknown_people = self._config.get( 'interface.pedview-show-unknown-people') - self.func_list.update({ - 'J' : self.jump, - }) - def get_handle_from_gramps_id(self, gid): """ returns the handle of the specified object @@ -642,41 +632,91 @@ class PedigreeView(NavigationView): return self.scrolledwindow - def additional_ui(self): - """ - Specifies the UIManager XML code that defines the menus and buttons - associated with the interface. - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + + + win.FilterEdit + ''' + '''Person Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + + '''] def define_actions(self): """ @@ -693,10 +733,11 @@ class PedigreeView(NavigationView): """ NavigationView.define_actions(self) - self._add_action('FilterEdit', None, _('Person Filter Editor'), - callback=self.cb_filter_editor) + self._add_action('FilterEdit', self.cb_filter_editor) + self._add_action('F2', self.kb_goto_home, 'F2') + self._add_action('PRIMARY-J', self.jump, 'J') - def cb_filter_editor(self, obj): + def cb_filter_editor(self, *obj): """ Display the person filter editor. """ @@ -1520,7 +1561,7 @@ class PedigreeView(NavigationView): else: self.scroll_direction = False - def kb_goto_home(self): + def kb_goto_home(self, *obj): """Goto home person from keyboard.""" self.cb_home(None) diff --git a/gramps/plugins/view/persontreeview.py b/gramps/plugins/view/persontreeview.py index f13c39a17..bf7d93a0b 100644 --- a/gramps/plugins/view/persontreeview.py +++ b/gramps/plugins/view/persontreeview.py @@ -78,82 +78,28 @@ class PersonTreeView(BasePersonView): """ BasePersonView.define_actions(self) - self.all_action.add_actions([ - ('OpenAllNodes', None, _("Expand all Nodes"), None, None, - self.open_all_nodes), - ('CloseAllNodes', None, _("Collapse all Nodes"), None, None, - self.close_all_nodes), - ]) + self.action_list.extend([ + ('OpenAllNodes', self.open_all_nodes), + ('CloseAllNodes', self.close_all_nodes)]) - def additional_ui(self): - """ - Defines the UI string for UIManager - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = BasePersonView.additional_ui[:] + additional_ui.append( # Defines the UI string for UIManager + ''' +
+ + win.OpenAllNodes + ''' + '''Expand all Nodes + + + win.CloseAllNodes + ''' + '''Collapse all Nodes + +
+ ''') - def add(self, obj): + def add(self, *obj): person = Person() # attempt to get the current surname diff --git a/gramps/plugins/view/placetreeview.py b/gramps/plugins/view/placetreeview.py index 35d48d917..c6c650394 100644 --- a/gramps/plugins/view/placetreeview.py +++ b/gramps/plugins/view/placetreeview.py @@ -67,80 +67,39 @@ class PlaceTreeView(PlaceBaseView): """ PlaceBaseView.define_actions(self) - self._add_action('OpenBranch', None, _("Expand this Entire Group"), - callback=self.open_branch) - self._add_action('CloseBranch', None, _("Collapse this Entire Group"), - callback=self.close_branch) - self._add_action('OpenAllNodes', None, _("Expand all Nodes"), - callback=self.open_all_nodes) - self._add_action('CloseAllNodes', None, _("Collapse all Nodes"), - callback=self.close_all_nodes) + self._add_action('OpenBranch', self.open_branch) + self._add_action('CloseBranch', self.close_branch) + self._add_action('OpenAllNodes', self.open_all_nodes) + self._add_action('CloseAllNodes', self.close_all_nodes) - def additional_ui(self): - """ - A user interface definition including tree specific actions. - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = PlaceBaseView.additional_ui[:] + additional_ui.append( + ''' +
+ + win.OpenBranch + ''' + '''Expand this Entire Group + + + win.CloseBranch + ''' + '''Collapse this Entire Group + + + win.OpenAllNodes + ''' + '''Expand all Nodes + + + win.CloseAllNodes + ''' + '''Collapse all Nodes + +
+ ''') - def add(self, obj): + def add(self, *obj): """ Add a new place. Use the currently selected rows as parent places. """ diff --git a/gramps/plugins/view/relview.py b/gramps/plugins/view/relview.py index e752c3a59..3c5b5d87b 100644 --- a/gramps/plugins/view/relview.py +++ b/gramps/plugins/view/relview.py @@ -60,7 +60,7 @@ from gramps.gen.lib import (ChildRef, EventRoleType, EventType, Family, from gramps.gen.lib.date import Today from gramps.gen.db import DbTxn from gramps.gui.views.navigationview import NavigationView -from gramps.gui.actiongroup import ActionGroup +from gramps.gui.uimanager import ActionGroup from gramps.gui.editors import EditPerson, EditFamily from gramps.gui.editors import FilterEditor from gramps.gen.display.name import displayer as name_displayer @@ -138,10 +138,6 @@ class RelationshipView(NavigationView): PersonBookmarks, nav_group) - self.func_list.update({ - 'J' : self.jump, - }) - dbstate.connect('database-changed', self.change_db) uistate.connect('nameformat-changed', self.build_tree) uistate.connect('placeformat-changed', self.build_tree) @@ -153,7 +149,7 @@ class RelationshipView(NavigationView): self.reorder_sensitive = False self.collapsed_items = {} - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) self.show_siblings = self._config.get('preferences.family-siblings') self.show_details = self._config.get('preferences.family-details') @@ -335,102 +331,205 @@ class RelationshipView(NavigationView): container.show_all() return container - def additional_ui(self): - """ - Specifies the UIManager XML code that defines the menus and buttons - associated with the interface. - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + +
+ + win.Back + _Add Bookmark + + + win.Forward + ''' + '''Organize Bookmarks... + +
+
+ + win.HomePerson + _Home + +
+
+''', + ''' + + + win.Edit + Edit... + + + win.AddParents + ''' + '''Add New Parents... + + + win.ShareFamily + ''' + '''Add Existing Parents... + + + win.AddSpouse + Add Partner... + + + win.ChangeOrder + _Reorder + + + win.FilterEdit + ''' + '''Person Filter Editor + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + + + go-home + win.HomePerson + ''' + '''Go to the default person + _Home + True + + + False + + + +''', + ''' + + + + gtk-edit + win.Edit + ''' + '''Edit the active person + Edit... + + + False + + + + + gramps-parents-add + win.AddParents + ''' + '''Add a new set of parents + Add + + + False + + + + + gramps-parents-open + win.ShareFamily + ''' + '''Add person as child to an existing family + Share + + + False + + + + + gramps-spouse + win.AddSpouse + ''' + '''Add a new family with person as parent + Partner + + + False + + + + + view-sort-ascending + win.ChangeOrder + ''' + '''Change order of parents and families + _Reorder + True + + + False + + + + '''] def define_actions(self): NavigationView.define_actions(self) self.order_action = ActionGroup(name=self.title + '/ChangeOrder') self.order_action.add_actions([ - ('ChangeOrder', 'view-sort-ascending', _('_Reorder'), None , - _("Change order of parents and families"), self.reorder), - ]) + ('ChangeOrder', self.reorder)]) self.family_action = ActionGroup(name=self.title + '/Family') self.family_action.add_actions([ - ('Edit', 'gtk-edit', _('Edit...'), "Return", - _("Edit the active person"), self.edit_active), - ('AddSpouse', 'gramps-spouse', _('Partner'), None , - _("Add a new family with person as parent"), self.add_spouse), - ('AddSpouseMenu', 'gramps-spouse', _('Add Partner...'), None , - _("Add a new family with person as parent"), self.add_spouse), - ('AddParents', 'gramps-parents-add', _('Add'), None , - _("Add a new set of parents"), self.add_parents), - ('AddParentsMenu', 'gramps-parents-add', _('Add New Parents...'), - None, _("Add a new set of parents"), self.add_parents), - ('ShareFamily', 'gramps-parents-open', _('Share'), - None , _("Add person as child to an existing family"), - self.select_parents), - ('ShareFamilyMenu', 'gramps-parents-open', - _('Add Existing Parents...'), None , - _("Add person as child to an existing family"), - self.select_parents), - ]) + ('Edit', self.edit_active, "Return"), + ('AddSpouse', self.add_spouse), + ('AddParents', self.add_parents), + ('ShareFamily', self.select_parents)]) - self._add_action('FilterEdit', None, _('Person Filter Editor'), - callback=self.filter_editor) + self._add_action('FilterEdit', callback=self.filter_editor) + self._add_action('PRIMARY-J', self.jump, 'J') self._add_action_group(self.order_action) self._add_action_group(self.family_action) - self.order_action.set_sensitive(self.reorder_sensitive) - self.family_action.set_sensitive(False) + self.uimanager.set_actions_sensitive(self.order_action, + self.reorder_sensitive) + self.uimanager.set_actions_sensitive(self.family_action, False) - def filter_editor(self, obj): + def filter_editor(self, *obj): try: FilterEditor('Person', CUSTOM_FILTERS, self.dbstate, self.uistate) @@ -505,11 +604,11 @@ class RelationshipView(NavigationView): if obj: person = self.dbstate.db.get_person_from_handle(obj) if not person: - self.family_action.set_sensitive(False) - self.order_action.set_sensitive(False) + self.uimanager.set_actions_sensitive(self.family_action, False) + self.uimanager.set_actions_sensitive(self.order_action, False) self.redrawing = False return - self.family_action.set_sensitive(True) + self.uimanager.set_actions_sensitive(self.family_action, True) self.write_title(person) @@ -549,7 +648,8 @@ class RelationshipView(NavigationView): self.redrawing = False self.uistate.modify_statusbar(self.dbstate) - self.order_action.set_sensitive(self.reorder_sensitive) + self.uimanager.set_actions_sensitive(self.order_action, + self.reorder_sensitive) self.dirty = False return True @@ -1488,7 +1588,7 @@ class RelationshipView(NavigationView): except WindowActiveError: pass - def add_spouse(self, obj): + def add_spouse(self, *obj): family = Family() person = self.dbstate.db.get_person_from_handle(self.get_active()) @@ -1505,7 +1605,7 @@ class RelationshipView(NavigationView): except WindowActiveError: pass - def edit_active(self, obj): + def edit_active(self, obj, value): phandle = self.get_active() self.edit_person(obj, phandle) @@ -1576,7 +1676,7 @@ class RelationshipView(NavigationView): self.dbstate.db.add_child_to_family(family, child) - def select_parents(self, obj): + def select_parents(self, *obj): SelectFamily = SelectorFactory('Family') phandle = self.get_active() @@ -1592,7 +1692,7 @@ class RelationshipView(NavigationView): self.dbstate.db.add_child_to_family(family, child) - def add_parents(self, obj): + def add_parents(self, *obj): family = Family() person = self.dbstate.db.get_person_from_handle(self.get_active()) @@ -1637,7 +1737,7 @@ class RelationshipView(NavigationView): if button_activated(event, _LEFT_BUTTON): self.reorder(obj) - def reorder(self, obj, dumm1=None, dummy2=None): + def reorder(self, *obj): if self.get_active(): try: Reorder(self.dbstate, self.uistate, [], self.get_active()) diff --git a/gramps/plugins/view/repoview.py b/gramps/plugins/view/repoview.py index 47b546f47..204452323 100644 --- a/gramps/plugins/view/repoview.py +++ b/gramps/plugins/view/repoview.py @@ -53,7 +53,7 @@ from gramps.gen.plug import CATEGORY_QR_REPOSITORY # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext #------------------------------------------------------------------------- @@ -132,12 +132,7 @@ class RepositoryView(ListView): multiple=True, filter_class=RepoSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def navigation_type(self): return 'Repository' @@ -145,76 +140,199 @@ class RepositoryView(ListView): def drag_info(self): return DdTargets.REPO_LINK - def define_actions(self): - ListView.define_actions(self) - self._add_action('FilterEdit', None, _('Repository Filter Editor'), - callback=self.filter_editor,) - self._add_action('QuickReport', None, - _("Quick View"), None, None, None) - def get_stock(self): return 'gramps-repository' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Repository Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+ ''' % _('action|_Edit...') # to use sgettext() + ] - def add(self, obj): + def add(self, *obj): EditRepository(self.dbstate, self.uistate, [], Repository()) - def remove(self, obj): + def remove(self, *obj): self.remove_selected_objects() def remove_object_from_handle(self, handle): @@ -227,7 +345,7 @@ class RepositoryView(ListView): is_used = len(source_list) > 0 return (query, is_used, object) - def edit(self, obj): + def edit(self, *obj): for handle in self.selected_handles(): repos = self.dbstate.db.get_repository_from_handle(handle) try: @@ -235,7 +353,7 @@ class RepositoryView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected repositories. """ diff --git a/gramps/plugins/view/sourceview.py b/gramps/plugins/view/sourceview.py index 858c6a97b..c34ccabc9 100644 --- a/gramps/plugins/view/sourceview.py +++ b/gramps/plugins/view/sourceview.py @@ -57,7 +57,7 @@ from gramps.gen.plug import CATEGORY_QR_SOURCE # #------------------------------------------------------------------------- from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext +_ = glocale.translation.sgettext #------------------------------------------------------------------------- @@ -118,12 +118,7 @@ class SourceView(ListView): multiple=True, filter_class=SourceSidebarFilter) - self.func_list.update({ - 'J' : self.jump, - 'BackSpace' : self.key_delete, - }) - - self.additional_uis.append(self.additional_ui()) + self.additional_uis.append(self.additional_ui) def navigation_type(self): return 'Source' @@ -131,75 +126,199 @@ class SourceView(ListView): def drag_info(self): return DdTargets.SOURCE_LINK - def define_actions(self): - ListView.define_actions(self) - self._add_action('FilterEdit', None, _('Source Filter Editor'), - callback=self.filter_editor,) - self._add_action('QuickReport', None, _("Quick View"), None, None, None) - def get_stock(self): return 'gramps-source' - def additional_ui(self): - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' + additional_ui = [ # Defines the UI string for UIManager + ''' + + + win.ExportTab + Export View... + + +''', + ''' +
+ + win.AddBook + _Add Bookmark + + + win.EditBook + %s... + +
+''' % _('Organize Bookmarks'), + ''' + +
+ + win.Back + _Back + + + win.Forward + _Forward + +
+
+''', + ''' +
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+''' % _("action|_Edit..."), # to use sgettext() + ''' + + + win.FilterEdit + ''' + '''Source Filter Editor + + +''', # Following are the Toolbar items + ''' + + + + go-previous + win.Back + ''' + '''Go to the previous object in the history + _Back + True + + + False + + + + + go-next + win.Forward + ''' + '''Go to the next object in the history + _Forward + True + + + False + + + +''', + ''' + + + + list-add + win.Add + %s + _Add... + True + + + False + + + + + gtk-edit + win.Edit + %s + Edit... + True + + + False + + + + + list-remove + win.Remove + %s + _Delete + True + + + False + + + + + gramps-merge + win.Merge + %s + _Merge... + True + + + False + + + +''' % (ADD_MSG, EDIT_MSG, DEL_MSG, MERGE_MSG), + ''' + +
+ + win.Back + _Back + + + win.Forward + Forward + +
+
+
+
+ + win.Add + _Add... + + + win.Edit + %s + + + win.Remove + _Delete + + + win.Merge + _Merge... + +
+
+ + +
+
+ ''' % _('action|_Edit...') # to use sgettext() + ] - def add(self, obj): + def add(self, *obj): EditSource(self.dbstate, self.uistate, [], Source()) - def remove(self, obj): + def remove(self, *obj): self.remove_selected_objects() def remove_object_from_handle(self, handle): @@ -211,7 +330,7 @@ class SourceView(ListView): is_used = any(the_lists) return (query, is_used, object) - def edit(self, obj): + def edit(self, *obj): for handle in self.selected_handles(): source = self.dbstate.db.get_source_from_handle(handle) try: @@ -219,7 +338,7 @@ class SourceView(ListView): except WindowActiveError: pass - def merge(self, obj): + def merge(self, *obj): """ Merge the selected sources. """ diff --git a/mac/gramps.accel b/mac/gramps.accel index d4bdbc9a8..13556f181 100644 --- a/mac/gramps.accel +++ b/mac/gramps.accel @@ -1,149 +1,85 @@ -; Gramps.py GtkAccelMap rc-file -*- scheme -*- -; this file is an automated accelerator map dump -; -; (gtk_accel_path "/ToolWindow/relcalc" "") -; (gtk_accel_path "/ReportWindow/place_report" "") -; (gtk_accel_path "/ToolWindow/mediaman" "") - (gtk_accel_path "/MainWindow/SourceAdd" "s") -; (gtk_accel_path "/ReportWindow/summary" "") -; (gtk_accel_path "/ToolWindow/rebuild_refmap" "") -; (gtk_accel_path "/Redo/Redo" "z") -; (gtk_accel_path "/ToolWindow/ToolAnExp" "") -; (gtk_accel_path "/FileWindow/Toolbar" "") -; (gtk_accel_path "/ToolWindow/editowner" "") -; (gtk_accel_path "/FileWindow/Preferences" "") - (gtk_accel_path "/MainWindow/MediaAdd" "m") -; (gtk_accel_path "/ToolWindow/sortevents" "") -; (gtk_accel_path "/AllMainWindow/Delete" "Delete") -; (gtk_accel_path "/FileWindow/ReportBug" "") -; (gtk_accel_path "/ReportWindow/hourglass_graph" "") -; (gtk_accel_path "/Undo/Undo" "z") -; (gtk_accel_path "/ToolWindow/reorder_ids" "") -; (gtk_accel_path "/ReportWindow/rel_graph" "") -; (gtk_accel_path "/MainWindow/ConfigView" "c") -; (gtk_accel_path "/ReportWindow/descend_report" "") -; (gtk_accel_path "/ReportWindow/ancestor_chart" "") -; (gtk_accel_path "/MainWindow/Clipboard" "b") -; (gtk_accel_path "/FileWindow/MailingLists" "") -; (gtk_accel_path "/AllMainWindow/GoMenu" "") -; (gtk_accel_path "/ToolWindow/verify" "") -; (gtk_accel_path "/ToolWindow/mergecitations" "") -; (gtk_accel_path "/FileWindow/HomePage" "") -; (gtk_accel_path "/ToolWindow/populatesources" "") -; (gtk_accel_path "/FileWindow/Open" "o") -; (gtk_accel_path "/ReportWindow/endofline_report" "") - (gtk_accel_path "/MainWindow/CitationAdd" "c") - (gtk_accel_path "/UndoHistory/UndoHistory" "h") -; (gtk_accel_path "/ReportWindow/family_descend_chart" "") - (gtk_accel_path "/AllMainWindow/Close" "w") -; (gtk_accel_path "/FileWindow/HelpMenu" "") -; (gtk_accel_path "/ToolWindow/loop" "") -; (gtk_accel_path "/ReportWindow/descend_chart" "") - (gtk_accel_path "/MainWindow/EventAdd" "e") -; (gtk_accel_path "/FileWindow/ExtraPlugins" "") - (gtk_accel_path "/MainWindow/RepositoryAdd" "r") -; (gtk_accel_path "/MainWindow/BookMenu" "") -; (gtk_accel_path "/ToolWindow/ToolProc" "") - (gtk_accel_path "/MainWindow/NoteAdd" "n") - (gtk_accel_path "/MainWindow/PlaceAdd" "l") -; (gtk_accel_path "/ReportWindow/navwebpage" "") -; (gtk_accel_path "/ReportWindow/birthday_report" "") -; (gtk_accel_path "/RecentFiles/RecentMenu8" "") -; (gtk_accel_path "/FileWindow/ViewMenu" "") -; (gtk_accel_path "/ReportWindow/fan_chart" "") -; (gtk_accel_path "/RecentFiles/RecentMenu7" "") -; (gtk_accel_path "/ReportWindow/calendar" "") -; (gtk_accel_path "/RecentFiles/RecentMenu6" "") -; (gtk_accel_path "/RecentFiles/RecentMenu5" "") -; (gtk_accel_path "/RecentFiles/RecentMenu4" "") -; (gtk_accel_path "/RecentFiles/RecentMenu3" "") -; (gtk_accel_path "/RecentFiles/RecentMenu2" "") -; (gtk_accel_path "/RecentFiles/RecentMenu1" "") -; (gtk_accel_path "/RecentFiles/RecentMenu0" "") -; (gtk_accel_path "/ReportWindow/RepWeb" "") -; (gtk_accel_path "/ReportWindow/indiv_complete" "") -; (gtk_accel_path "/ToolWindow/rebuild_genstats" "") -; (gtk_accel_path "/FileWindow/FAQ" "") -; (gtk_accel_path "/ReportWindow/det_ancestor_report" "") -; (gtk_accel_path "/ReportWindow/timeline" "") -; (gtk_accel_path "/ToolWindow/eventcmp" "") -; (gtk_accel_path "/AllMainWindow/ReportsMenu" "") -; (gtk_accel_path "/FileWindow/EditMenu" "") - (gtk_accel_path "/MainWindow/FamilyAdd" "f") -; (gtk_accel_path "/ToolWindow/chname" "") -; (gtk_accel_path "/AllMainWindow/Insert" "Insert") -; (gtk_accel_path "/AllMainWindow/F9" "F9") -; (gtk_accel_path "/AllMainWindow/F8" "F8") -; (gtk_accel_path "/AllMainWindow/F7" "F7") -; (gtk_accel_path "/AllMainWindow/F6" "F6") -; (gtk_accel_path "/AllMainWindow/F5" "F5") -; (gtk_accel_path "/AllMainWindow/F4" "F4") -; (gtk_accel_path "/AllMainWindow/F3" "F3") -; (gtk_accel_path "/AllMainWindow/F2" "F2") -; (gtk_accel_path "/FileWindow/Navigator" "m") -; (gtk_accel_path "/FileWindow/PluginStatus" "") -; (gtk_accel_path "/AllMainWindow/F12" "F12") -; (gtk_accel_path "/AllMainWindow/F11" "F11") -; (gtk_accel_path "/ToolWindow/ToolUtil" "") -; (gtk_accel_path "/MainWindow/Import" "i") -; (gtk_accel_path "/ReportWindow/statistics_chart" "") -; (gtk_accel_path "/FileWindow/UserManual" "F1") -; (gtk_accel_path "/AllMainWindow/Books" "") -; (gtk_accel_path "/FileWindow/OpenRecent" "") -; (gtk_accel_path "/Dashboard/RestoreGramplet" "") -; (gtk_accel_path "/WindowManger/4722902520" "") -; (gtk_accel_path "/ReportWindow/RepGraph" "") -; (gtk_accel_path "/ReportWindow/familylines_graph" "") -; (gtk_accel_path "/ReportWindow/kinship_report" "") -; (gtk_accel_path "/ToolWindow/testcasegenerator" "") -; (gtk_accel_path "/FileWindow/KeyBindings" "") -; (gtk_accel_path "/ReportWindow/tag_report" "") -; (gtk_accel_path "/ToolWindow/dgenstats" "") -; (gtk_accel_path "/FileWindow/Quit" "q") -; (gtk_accel_path "/FileWindow/TipOfDay" "") -; (gtk_accel_path "/ReportWindow/ancestor_report" "") -; (gtk_accel_path "/ToolWindow/check" "") -; (gtk_accel_path "/FileWindow/Fullscreen" "F11") - (gtk_accel_path "/MainWindow/PersonAdd" "p") -; (gtk_accel_path "/AllMainWindow/P" "p") -; (gtk_accel_path "/ToolWindow/remove_unused" "") -; (gtk_accel_path "/AllMainWindow/N" "n") -; (gtk_accel_path "/ReportWindow/WebCal" "") -; (gtk_accel_path "/ReportWindow/records" "") -; (gtk_accel_path "/AllMainWindow/J" "j") -; (gtk_accel_path "/ReportWindow/number_of_ancestors" "") -; (gtk_accel_path "/ToolWindow/evname" "") -; (gtk_accel_path "/Dashboard/AddGramplet" "") -; (gtk_accel_path "/ReportWindow/notelinkreport" "") -; (gtk_accel_path "/ReportWindow/det_descendant_report" "") -; (gtk_accel_path "/MainWindow/AddMenu" "") -; (gtk_accel_path "/AllMainWindow/WindowsMenu" "") -; (gtk_accel_path "/ToolWindow/test_for_date_parser_and_displayer" "") -; (gtk_accel_path "/AllMainWindow/Abandon" "") -; (gtk_accel_path "/ReportWindow/family_group" "") -; (gtk_accel_path "/AllMainWindow/9" "9") -; (gtk_accel_path "/AllMainWindow/8" "8") -; (gtk_accel_path "/ToolWindow/not_related" "") -; (gtk_accel_path "/AllMainWindow/7" "7") -; (gtk_accel_path "/AllMainWindow/6" "6") -; (gtk_accel_path "/AllMainWindow/5" "5") -; (gtk_accel_path "/AllMainWindow/4" "4") -; (gtk_accel_path "/AllMainWindow/3" "3") -; (gtk_accel_path "/AllMainWindow/2" "2") -; (gtk_accel_path "/AllMainWindow/1" "1") -; (gtk_accel_path "/AllMainWindow/0" "0") -; (gtk_accel_path "/WindowManger/M:4722902520" "") -; (gtk_accel_path "/FileWindow/About" "") -; (gtk_accel_path "/MainWindow/ToolsMenu" "") -; (gtk_accel_path "/FileWindow/FileMenu" "") -; (gtk_accel_path "/AllMainWindow/BackSpace" "BackSpace") -; (gtk_accel_path "/AllMainWindow/Export" "e") -; (gtk_accel_path "/AllMainWindow/Backup" "") -; (gtk_accel_path "/ToolWindow/ToolDebug" "") -; (gtk_accel_path "/ReportWindow/Graphs" "") -; (gtk_accel_path "/ReportWindow/RepText" "") -; (gtk_accel_path "/ToolWindow/dupfind" "") -; (gtk_accel_path "/ToolWindow/rebuild" "") -; (gtk_accel_path "/ToolWindow/patchnames" "") -; (gtk_accel_path "/ToolWindow/chtype" "") -; (gtk_accel_path "/ToolWindow/ToolRep" "") +{ +# this file was generated wih UIManager.dump_all_accels and then manually +# edited to fix up some accels for MAC OSX. +# "win.Clipboard": "b", + "win.PersonAdd": "p", + "win.FamilyAdd": "f", + "win.EventAdd": "e", + "win.PlaceAdd": "l", + "win.SourceAdd": "s", + "win.CitationAdd": "c", + "win.RepositoryAdd": "r", + "win.MediaAdd": "m", + "win.NoteAdd": "n", +# "win.UndoHistory": "h", +# "win.Import": "i", +# "win.Tools": "", +# "win.ConfigView": "c", +# "win.Close": "w", +# "win.Export": "e", +# "win.Backup": "", +# "win.Abandon": "", +# "win.Reports": "", +# "win.Books": "", +# "win.F3": "F3", +# "win.F4": "F4", +# "win.F5": "F5", +# "win.F6": "F6", +# "win.F7": "F7", +# "win.F8": "F8", +# "win.F9": "F9", +# "win.F12": "F12", +# "win.PRIMARY-1": "1", +# "win.PRIMARY-2": "2", +# "win.PRIMARY-3": "3", +# "win.PRIMARY-4": "4", +# "win.PRIMARY-5": "5", +# "win.PRIMARY-6": "6", +# "win.PRIMARY-7": "7", +# "win.PRIMARY-8": "8", +# "win.PRIMARY-9": "9", +# "win.PRIMARY-0": "0", +# "win.PRIMARY-N": "n", +# "win.PRIMARY-P": "p", +# "win.Open": "o", +# "win.Quit": "q", +# "win.Navigator": "m", +# "win.Toolbar": "", +# "win.Fullscreen": "F11", +# "win.Preferences": "", +# "win.HomePage": "", +# "win.MailingLists": "", +# "win.ReportBug": "", +# "win.ExtraPlugins": "", +# "win.About": "", +# "win.PluginStatus": "", +# "win.FAQ": "", +# "win.KeyBindings": "", +# "win.UserManual": "F1", +# "win.TipOfDay": "", +# "win.Undo": "z", +# "win.Redo": "z", +# "win.ViewInCatagory": "", +# "win.HomePerson": "Home", +# "win.ExportTab": "", +# "win.Edit": "Return", +# "win.PRIMARY-J": "j", +# "win.FilterEdit": "", +# "win.OpenAllNodes": "", +# "win.CloseAllNodes": "", +# "win.Sidebar": "", +# "win.Bottombar": "", +# "win.AddBook": "d", +# "win.EditBook": "d", +# "win.Back": "Left", +# "win.Forward": "Right", +# "win.SetActive": "", +# "win.Add": "Insert", +# "win.Remove": "Delete", +# "win.PRIMARY-BackSpace": "BackSpace", +# "win.Merge": "", +# "win.NewTag": "", +# "win.OrganizeTags": "", +# "win.TagButton": "", +# "win.Person00": "0" +} diff --git a/po/POTFILES.skip b/po/POTFILES.skip index ed6c8b5bf..0cd786dcd 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -298,7 +298,6 @@ gramps/gen/utils/test/place_test.py # gui - GUI code # gramps/gui/__init__.py -gramps/gui/actiongroup.py gramps/gui/basesidebar.py gramps/gui/dbguielement.py gramps/gui/ddtargets.py @@ -308,6 +307,7 @@ gramps/gui/listmodel.py gramps/gui/managedwindow.py gramps/gui/navigator.py gramps/gui/pluginmanager.py +gramps/gui/uimanager.py gramps/gui/user.py gramps/gui/utilscairo.py # @@ -444,15 +444,11 @@ gramps/gui/widgets/placeentry.py gramps/gui/widgets/selectionwidget.py gramps/gui/widgets/shadebox.py gramps/gui/widgets/shortlistcomboentry.py -gramps/gui/widgets/springseparator.py gramps/gui/widgets/statusbar.py -gramps/gui/widgets/toolcomboentry.py gramps/gui/widgets/undoablebuffer.py gramps/gui/widgets/undoableentry.py gramps/gui/widgets/undoablestyledbuffer.py gramps/gui/widgets/validatedcomboentry.py -gramps/gui/widgets/valueaction.py -gramps/gui/widgets/valuetoolitem.py # # plugins #