Allow the user to directly input a Gramps ID in selectors
When a selector is focused, presso Ctrl-O to trigger an input dialog and insert a Gramps ID directly. The Gramps ID, if valid, will be used to populate the reference, bypassing the usual tree model loading mechanism of selection dialogs. This is a proof-of-concept commit. At a minimum, the feature should be made available as a button on selector dialogs, as currently the only way to access it is to know the "magic shortcut" Ctrl-O.
This commit is contained in:
parent
d04174cb99
commit
80cf4f0cb2
@ -25,6 +25,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Pango
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -32,12 +33,19 @@ from gi.repository import Pango
|
||||
# gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.gettext
|
||||
from ..managedwindow import ManagedWindow
|
||||
from ..filters import SearchBar
|
||||
from ..glade import Glade
|
||||
from ..widgets.interactivesearchbox import InteractiveSearchBox
|
||||
from ..display import display_help
|
||||
from gramps.gen.const import URL_MANUAL_PAGE
|
||||
from ..utils import match_primary_mask
|
||||
from ..dialog import InputDialog
|
||||
|
||||
# keyboard shortcut for direct ID input (see BaseSelector._direct_id_input)
|
||||
_OPEN = Gdk.keyval_from_name("o")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -55,11 +63,13 @@ class BaseSelector(ManagedWindow):
|
||||
IMAGE = 2
|
||||
|
||||
def __init__(self, dbstate, uistate, track=[], filter=None, skip=set(),
|
||||
show_search_bar = True, default=None):
|
||||
show_search_bar=True, default=None, direct_id_input=True):
|
||||
"""Set up the dialog with the dbstate and uistate, track of parent
|
||||
windows for ManagedWindow, initial filter for the model, skip with
|
||||
set of handles to skip in the view, and search_bar to show the
|
||||
SearchBar at the top or not.
|
||||
windows for ManagedWindow, initial filter for the model, skip with
|
||||
set of handles to skip in the view, and search_bar to show the
|
||||
SearchBar at the top or not. direct_id_input enables a keyboard
|
||||
shortcut to allow the user to directly input an object ID for this
|
||||
selection.
|
||||
"""
|
||||
self.filter = (2, filter, False)
|
||||
|
||||
@ -92,9 +102,9 @@ class BaseSelector(ManagedWindow):
|
||||
self.glade.get_object('help'), self.WIKI_HELP_PAGE,
|
||||
self.WIKI_HELP_SEC)
|
||||
|
||||
# connect to signal for custom interactive-search
|
||||
# connect to signal for shortcuts and custom interactive-search
|
||||
self.searchbox = InteractiveSearchBox(self.tree)
|
||||
self.tree.connect('key-press-event', self.searchbox.treeview_keypress)
|
||||
self.tree.connect('key-press-event', self._key_pressed)
|
||||
|
||||
#add the search bar
|
||||
self.search_bar = SearchBar(dbstate, uistate, self.build_tree, apply_clear=self.apply_clear)
|
||||
@ -136,6 +146,9 @@ class BaseSelector(ManagedWindow):
|
||||
if default:
|
||||
self.goto_handle(default)
|
||||
|
||||
self.can_direct_id_input = direct_id_input
|
||||
self.direct_id_selection = None
|
||||
|
||||
def goto_handle(self, handle):
|
||||
"""
|
||||
Goto the correct row.
|
||||
@ -209,6 +222,12 @@ class BaseSelector(ManagedWindow):
|
||||
if id_list and id_list[0]:
|
||||
result = self.get_from_handle_func()(id_list[0])
|
||||
self.close()
|
||||
elif val == Gtk.ResponseType.APPLY:
|
||||
# user has invoked the direct selection dialog and typed a valid id,
|
||||
# direct_id_input() has populated self.direct_id_selection and
|
||||
# emitted an APPLY response to signal we're done.
|
||||
result = self.direct_id_selection
|
||||
self.close()
|
||||
elif val != Gtk.ResponseType.DELETE_EVENT:
|
||||
self.close()
|
||||
return result
|
||||
@ -240,6 +259,9 @@ class BaseSelector(ManagedWindow):
|
||||
def get_from_handle_func(self):
|
||||
assert False, "Must be defined in the subclass"
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
assert False, "Must be defined in the subclass"
|
||||
|
||||
def set_show_search_bar(self, value):
|
||||
"""make the search bar at the top shown
|
||||
"""
|
||||
@ -338,6 +360,29 @@ class BaseSelector(ManagedWindow):
|
||||
self.tree.set_model(self.model)
|
||||
self.tree.grab_focus()
|
||||
|
||||
def direct_id_input(self):
|
||||
"""Handles "direct ID input" - in other words, directly accepts an
|
||||
object ID from the user and selects it in the list.
|
||||
"""
|
||||
id_input = InputDialog(_('Enter the object ID'), None,
|
||||
self.window).run()
|
||||
if id_input is not None:
|
||||
obj = self.get_from_gramps_id_func()(id_input)
|
||||
if obj is not None:
|
||||
# instead of selecting the object in the tree, we bypass the
|
||||
# tree altogether, to avoid an expensive rebuild in case the
|
||||
# selected object is not loaded
|
||||
self.direct_id_selection = obj
|
||||
self.window.response(Gtk.ResponseType.APPLY)
|
||||
|
||||
def _key_pressed(self, obj, event):
|
||||
if self.can_direct_id_input and event.keyval in (_OPEN,) and \
|
||||
match_primary_mask(event.get_state()):
|
||||
self.direct_id_input()
|
||||
else:
|
||||
# fallback to "interactive search" if the event is not more specific
|
||||
self.searchbox.treeview_keypress(obj, event)
|
||||
|
||||
def clear_model(self):
|
||||
if self.model:
|
||||
self.tree.set_model(None)
|
||||
|
@ -74,10 +74,20 @@ class SelectCitation(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 6),
|
||||
]
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.get_source_or_citation
|
||||
def get_from_gramps_id_func(self):
|
||||
return self._get_source_or_citation_by_gramps_id
|
||||
|
||||
def get_source_or_citation(self, handle):
|
||||
def get_from_handle_func(self):
|
||||
return self._get_source_or_citation_by_handle
|
||||
|
||||
def _get_source_or_citation_by_gramps_id(self, gramps_id):
|
||||
source = self.db.get_source_from_gramps_id(gramps_id)
|
||||
if source is not None:
|
||||
return source
|
||||
else:
|
||||
return self.db.get_citation_from_gramps_id(gramps_id)
|
||||
|
||||
def _get_source_or_citation_by_handle(self, handle):
|
||||
if self.db.has_source_handle(handle):
|
||||
return self.db.get_source_from_handle(handle)
|
||||
else:
|
||||
|
@ -72,6 +72,9 @@ class SelectEvent(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 7)
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_event_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_event_from_handle
|
||||
|
||||
|
@ -69,6 +69,9 @@ class SelectFamily(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 7),
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_family_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_family_from_handle
|
||||
|
||||
|
@ -75,6 +75,9 @@ class SelectNote(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 5),
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_note_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_note_from_handle
|
||||
|
||||
|
@ -69,6 +69,9 @@ class SelectObject(BaseSelector):
|
||||
def get_model_class(self):
|
||||
return MediaModel
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_media_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_media_from_handle
|
||||
|
||||
|
@ -98,6 +98,9 @@ class SelectPerson(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 14)
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_person_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_person_from_handle
|
||||
|
||||
|
@ -71,6 +71,9 @@ class SelectPlace(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 9),
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_place_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_place_from_handle
|
||||
|
||||
|
@ -68,6 +68,9 @@ class SelectRepository(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 14),
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_repository_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_repository_from_handle
|
||||
|
||||
|
@ -70,6 +70,9 @@ class SelectSource(BaseSelector):
|
||||
(_('Last Change'), 150, BaseSelector.TEXT, 7),
|
||||
]
|
||||
|
||||
def get_from_gramps_id_func(self):
|
||||
return self.db.get_source_from_gramps_id
|
||||
|
||||
def get_from_handle_func(self):
|
||||
return self.db.get_source_from_handle
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user