diff --git a/gramps/gui/clipboard.py b/gramps/gui/clipboard.py index 3c3a84cd6..a063bd3f6 100644 --- a/gramps/gui/clipboard.py +++ b/gramps/gui/clipboard.py @@ -46,21 +46,20 @@ import cairo # gramps modules # #------------------------------------------------------------------------- -from gramps.gen.const import IMAGE_DIR, URL_MANUAL_PAGE -from gramps.gen.config import config +from gramps.gen.const import URL_MANUAL_PAGE from gramps.gen.lib import NoteType from gramps.gen.datehandler import get_date from gramps.gen.display.place import displayer as place_displayer +from gramps.gen.errors import WindowActiveError +from gramps.gen.constfunc import mac from .display import display_help from .managedwindow import ManagedWindow -from gramps.gen.errors import WindowActiveError -from gramps.gen.const import GRAMPS_LOCALE as glocale -_ = glocale.translation.sgettext -from gramps.gen.constfunc import mac from .glade import Glade from .ddtargets import DdTargets from .makefilter import make_filter from .utils import is_right_click, get_primary_mask +from gramps.gen.const import GRAMPS_LOCALE as glocale +_ = glocale.translation.sgettext #------------------------------------------------------------------------- # @@ -69,6 +68,7 @@ from .utils import is_right_click, get_primary_mask #------------------------------------------------------------------------- WIKI_HELP_PAGE = '%s_-_Navigation' % URL_MANUAL_PAGE WIKI_HELP_SEC = _('manual|Using_the_Clipboard') +clipdb = None # current db to avoid different transient dbs during db change #------------------------------------------------------------------------- # @@ -79,76 +79,76 @@ WIKI_HELP_SEC = _('manual|Using_the_Clipboard') theme = Gtk.IconTheme.get_default() LINK_PIC = theme.load_icon('stock_link', 16, 0) ICONS = {} -for (name, icon) in ( - ("media", "gramps-media"), - ("note", "gramps-notes"), - ("person", "gramps-person"), - ("place", "gramps-place"), - ('address', 'gramps-address'), - ('attribute', 'gramps-attribute'), - ('event', 'gramps-event'), - ('family', 'gramps-family'), - ('location', 'geo-place-link'), - ('media', 'gramps-media'), - ('name', 'geo-show-person'), - ('repository', 'gramps-repository'), - ('source', 'gramps-source'), - ('citation', 'gramps-citation'), - ('text', 'gramps-font'), - ('url', 'gramps-geo'), - ): +for (name, icon) in (("media", "gramps-media"), + ("note", "gramps-notes"), + ("person", "gramps-person"), + ("place", "gramps-place"), + ('address', 'gramps-address'), + ('attribute', 'gramps-attribute'), + ('event', 'gramps-event'), + ('family', 'gramps-family'), + ('location', 'geo-place-link'), + ('media', 'gramps-media'), + ('name', 'geo-show-person'), + ('repository', 'gramps-repository'), + ('source', 'gramps-source'), + ('citation', 'gramps-citation'), + ('text', 'gramps-font'), + ('url', 'gramps-geo')): ICONS[name] = theme.load_icon(icon, 16, 0) + #------------------------------------------------------------------------- # # Local functions # #------------------------------------------------------------------------- def map2class(target): - d = {"person-link": ClipPersonLink, - "family-link": ClipFamilyLink, - 'personref': ClipPersonRef, - 'childref': ClipChildRef, - 'source-link': ClipSourceLink, - 'citation-link': ClipCitation, - 'repo-link': ClipRepositoryLink, - 'pevent': ClipEvent, - 'eventref': ClipEventRef, - 'media': ClipMediaObj, - 'mediaref': ClipMediaRef, - 'place-link': ClipPlace, - 'placeref': ClipPlaceRef, - 'note-link': ClipNote, - 'TEXT': ClipText, - } - return d[target] if target in d else None + _d_ = {"person-link": ClipPersonLink, + "family-link": ClipFamilyLink, + 'personref': ClipPersonRef, + 'childref': ClipChildRef, + 'source-link': ClipSourceLink, + 'citation-link': ClipCitation, + 'repo-link': ClipRepositoryLink, + 'pevent': ClipEvent, + 'eventref': ClipEventRef, + 'media': ClipMediaObj, + 'mediaref': ClipMediaRef, + 'place-link': ClipPlace, + 'placeref': ClipPlaceRef, + 'note-link': ClipNote, + 'TEXT': ClipText} + return _d_[target] if target in _d_ else None + def obj2class(target): - d= {"Person": ClipPersonLink, - "Family": ClipFamilyLink, - 'Source': ClipSourceLink, - 'Citation': ClipCitation, - 'Repository': ClipRepositoryLink, - 'Event': ClipEvent, - 'Media': ClipMediaObj, - 'Place': ClipPlace, - 'Note': ClipNote, - } - return d[target] if target in d else None + _d_ = {"Person": ClipPersonLink, + "Family": ClipFamilyLink, + 'Source': ClipSourceLink, + 'Citation': ClipCitation, + 'Repository': ClipRepositoryLink, + 'Event': ClipEvent, + 'Media': ClipMediaObj, + 'Place': ClipPlace, + 'Note': ClipNote} + return _d_[target] if target in _d_ else None OBJ2TARGET = {"Person": Gdk.atom_intern('person-link', False), - "Family": Gdk.atom_intern('family-link', False), - 'Source': Gdk.atom_intern('source-link', False), - 'Citation': Gdk.atom_intern('citation-link', False), - 'Repository': Gdk.atom_intern('repo-link', False), - 'Event': Gdk.atom_intern('pevent', False), - 'Media': Gdk.atom_intern('media', False), - 'Place': Gdk.atom_intern('place-link', False), - 'Note': Gdk.atom_intern('note-link', False), - } + "Family": Gdk.atom_intern('family-link', False), + 'Source': Gdk.atom_intern('source-link', False), + 'Citation': Gdk.atom_intern('citation-link', False), + 'Repository': Gdk.atom_intern('repo-link', False), + 'Event': Gdk.atom_intern('pevent', False), + 'Media': Gdk.atom_intern('media', False), + 'Place': Gdk.atom_intern('place-link', False), + 'Note': Gdk.atom_intern('note-link', False)} + + def obj2target(target): return OBJ2TARGET[target] if target in OBJ2TARGET else None + def model_contains(model, data): """ Returns True if data is a row in model. @@ -170,6 +170,7 @@ def model_contains(model, data): return True return False + #------------------------------------------------------------------------- # # wrapper classes to provide object specific listing in the ListView @@ -178,21 +179,16 @@ def model_contains(model, data): class ClipWrapper: UNAVAILABLE_ICON = 'dialog-error' - def __init__(self, dbstate, obj): - dbstate.connect('database-changed', self.database_changed) - self.database_changed(dbstate.db) + def __init__(self, obj): self._obj = obj self._pickle = obj - self._type = _("Unknown") + self._type = _("Unknown") self._objclass = None self._handle = None self._title = _('Unavailable') self._value = _('Unavailable') - self._dbid = self._db.get_dbid() - self._dbname = self._db.get_dbname() - - def database_changed(self,db): - self._db = db + self._dbid = clipdb.get_dbid() + self._dbname = clipdb.get_dbname() def get_type(self): return self._type @@ -222,25 +218,28 @@ class ClipWrapper: "_title": self._title, "_value": self._value, "_dbid": self._dbid, - "_dbname": self._dbname, - } + "_dbname": self._dbname} return pickle.dumps(data) - else: - if isinstance(self._obj, bytes): - return self._obj - else: - ## don't know if this happens in Gramps, theoretically possible - asuni = str(self._obj) - return asuni.encode('utf-8') + if isinstance(self._obj, bytes): + return self._obj + # don't know if this happens in Gramps, theoretically possible + asuni = str(self._obj) + return asuni.encode('utf-8') def is_valid(self): + if self._objclass and obj2class(self._objclass): + # we have a primary object + data = pickle.loads(self._obj) + handle = data[2] + return clipdb.method("has_%s_handle", self._objclass)(handle) return True + class ClipHandleWrapper(ClipWrapper): - def __init__(self,dbstate, obj): - super(ClipHandleWrapper, self).__init__(dbstate, obj) - #unpack object + def __init__(self, obj): + super(ClipHandleWrapper, self).__init__(obj) + # unpack object (drag_type, idval, data, val) = pickle.loads(obj) if isinstance(data, dict): self.set_data(data) @@ -251,10 +250,11 @@ class ClipHandleWrapper(ClipWrapper): for item in data: setattr(self, item, data[item]) + class ClipObjWrapper(ClipWrapper): - def __init__(self,dbstate, obj): - super(ClipObjWrapper, self).__init__(dbstate, obj) + def __init__(self, obj): + super(ClipObjWrapper, self).__init__(obj) #unpack object (drag_type, idval, self._obj, val) = pickle.loads(obj) self._pickle = obj @@ -271,25 +271,17 @@ class ClipObjWrapper(ClipWrapper): "_title": self._title, "_value": self._value, "_dbid": self._dbid, - "_dbname": self._dbname, - } + "_dbname": self._dbname} return pickle.dumps(data) - else: - return self._pickle + return self._pickle def is_valid(self): if self._obj is None: return False - valid_func_map = {'Person': self._db.get_person_from_handle, - 'Family': self._db.get_family_from_handle, - 'Event': self._db.get_event_from_handle, - 'Place': self._db.get_place_from_handle, - 'Media': self._db.get_media_from_handle, - 'Source': self._db.get_source_from_handle} - for (classname, handle) in self._obj.get_referenced_handles_recursively(): - if classname in valid_func_map: - if not valid_func_map[classname](handle): + for (clname, handle) in self._obj.get_referenced_handles_recursively(): + if obj2class(clname): # a class we care about (not tag) + if not clipdb.method("has_%s_handle", clname)(handle): return False return True @@ -298,12 +290,12 @@ class ClipObjWrapper(ClipWrapper): class ClipAddress(ClipObjWrapper): DROP_TARGETS = [DdTargets.ADDRESS] - DRAG_TARGET = DdTargets.ADDRESS - ICON = ICONS['address'] + DRAG_TARGET = DdTargets.ADDRESS + ICON = ICONS['address'] - def __init__(self, dbstate, obj): - super(ClipAddress, self).__init__(dbstate, obj) - self._type = _("Address") + def __init__(self, obj): + super(ClipAddress, self).__init__(obj) + self._type = _("Address") self.refresh() def refresh(self): @@ -312,122 +304,101 @@ class ClipAddress(ClipObjWrapper): self._value = "%s %s %s %s" % (self._obj.get_street(), self._obj.get_city(), self._obj.get_state(), - self._obj.get_country(), - ) + self._obj.get_country()) + class ClipLocation(ClipObjWrapper): DROP_TARGETS = [DdTargets.LOCATION] - DRAG_TARGET = DdTargets.LOCATION - ICON = ICONS['location'] + DRAG_TARGET = DdTargets.LOCATION + ICON = ICONS['location'] - def __init__(self, dbstate, obj): - super(ClipLocation, self).__init__(dbstate, obj) - self._type = _("Location") + def __init__(self, obj): + super(ClipLocation, self).__init__(obj) + self._type = _("Location") self.refresh() def refresh(self): self._value = "%s %s %s" % (self._obj.get_city(), self._obj.get_state(), - self._obj.get_country(), - ) + self._obj.get_country()) + class ClipEvent(ClipHandleWrapper): DROP_TARGETS = [DdTargets.EVENT] - DRAG_TARGET = DdTargets.EVENT - ICON = ICONS["event"] + DRAG_TARGET = DdTargets.EVENT + ICON = ICONS["event"] - def __init__(self, dbstate, obj): - super(ClipEvent, self).__init__(dbstate, obj) - self._type = _("Event") + def __init__(self, obj): + super(ClipEvent, self).__init__(obj) + self._type = _("Event") self._objclass = 'Event' self.refresh() def refresh(self): if self._handle: - value = self._db.get_event_from_handle(self._handle) + value = clipdb.get_event_from_handle(self._handle) if value: self._title = str(value.get_type()) self._value = value.get_description() - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_event_from_handle(handle) - if obj: - return True - return False class ClipPlace(ClipHandleWrapper): DROP_TARGETS = [DdTargets.PLACE_LINK] - DRAG_TARGET = DdTargets.PLACE_LINK - ICON = ICONS["place"] + DRAG_TARGET = DdTargets.PLACE_LINK + ICON = ICONS["place"] - def __init__(self, dbstate, obj): - super(ClipPlace, self).__init__(dbstate, obj) - self._type = _("Place") + def __init__(self, obj): + super(ClipPlace, self).__init__(obj) + self._type = _("Place") self._objclass = 'Place' self.refresh() def refresh(self): if self._handle: - value = self._db.get_place_from_handle(self._handle) + value = clipdb.get_place_from_handle(self._handle) if value: self._title = value.gramps_id - self._value = place_displayer.display(self._db, value) + self._value = place_displayer.display(clipdb, value) - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_place_from_handle(handle) - if obj: - return True - return False class ClipNote(ClipHandleWrapper): DROP_TARGETS = [DdTargets.NOTE_LINK] - DRAG_TARGET = DdTargets.NOTE_LINK - ICON = ICONS["note"] + DRAG_TARGET = DdTargets.NOTE_LINK + ICON = ICONS["note"] - def __init__(self, dbstate, obj): - super(ClipNote, self).__init__(dbstate, obj) - self._type = _("Note") + def __init__(self, obj): + super(ClipNote, self).__init__(obj) + self._type = _("Note") self._objclass = 'Note' self.refresh() def refresh(self): - value = self._db.get_note_from_handle(self._handle) + value = clipdb.get_note_from_handle(self._handle) if value: self._title = value.get_gramps_id() note = value.get().replace('\n', ' ') - #String must be unicode for truncation to work for non - #ascii characters + # String must be unicode for truncation to work for non + # ascii characters note = str(note) if len(note) > 80: - self._value = note[:80]+"..." + self._value = note[:80] + "..." else: self._value = note - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_note_from_handle(handle) - if obj: - return True - return False class ClipFamilyEvent(ClipObjWrapper): DROP_TARGETS = [DdTargets.FAMILY_EVENT] - DRAG_TARGET = DdTargets.FAMILY_EVENT - ICON = ICONS['family'] + DRAG_TARGET = DdTargets.FAMILY_EVENT + ICON = ICONS['family'] - def __init__(self, dbstate, obj): - super(ClipFamilyEvent, self).__init__(dbstate, obj) - self._type = _("Family Event") + def __init__(self, obj): + super(ClipFamilyEvent, self).__init__(obj) + self._type = _("Family Event") self.refresh() def refresh(self): @@ -435,15 +406,16 @@ class ClipFamilyEvent(ClipObjWrapper): self._title = str(self._obj.get_type()) self._value = self._obj.get_description() + class ClipUrl(ClipObjWrapper): DROP_TARGETS = [DdTargets.URL] - DRAG_TARGET = DdTargets.URL - ICON = ICONS['url'] + DRAG_TARGET = DdTargets.URL + ICON = ICONS['url'] - def __init__(self, dbstate, obj): - super(ClipUrl, self).__init__(dbstate, obj) - self._type = _("Url") + def __init__(self, obj): + super(ClipUrl, self).__init__(obj) + self._type = _("Url") self.refresh() def refresh(self): @@ -451,30 +423,32 @@ class ClipUrl(ClipObjWrapper): self._title = self._obj.get_path() self._value = self._obj.get_description() + class ClipAttribute(ClipObjWrapper): DROP_TARGETS = [DdTargets.ATTRIBUTE] - DRAG_TARGET = DdTargets.ATTRIBUTE - ICON = ICONS['attribute'] + DRAG_TARGET = DdTargets.ATTRIBUTE + ICON = ICONS['attribute'] - def __init__(self, dbstate, obj): - super(ClipAttribute, self).__init__(dbstate, obj) - self._type = _("Attribute") + def __init__(self, obj): + super(ClipAttribute, self).__init__(obj) + self._type = _("Attribute") self.refresh() def refresh(self): self._title = str(self._obj.get_type()) self._value = self._obj.get_value() + class ClipFamilyAttribute(ClipObjWrapper): DROP_TARGETS = [DdTargets.FAMILY_ATTRIBUTE] - DRAG_TARGET = DdTargets.FAMILY_ATTRIBUTE - ICON = ICONS['attribute'] + DRAG_TARGET = DdTargets.FAMILY_ATTRIBUTE + ICON = ICONS['attribute'] - def __init__(self, dbstate, obj): - super(ClipFamilyAttribute, self).__init__(dbstate, obj) - self._type = _("Family Attribute") + def __init__(self, obj): + super(ClipFamilyAttribute, self).__init__(obj) + self._type = _("Family Attribute") self.refresh() def refresh(self): @@ -482,114 +456,110 @@ class ClipFamilyAttribute(ClipObjWrapper): self._title = str(self._obj.get_type()) self._value = self._obj.get_value() + class ClipCitation(ClipHandleWrapper): DROP_TARGETS = [DdTargets.CITATION_LINK] - DRAG_TARGET = DdTargets.CITATION_LINK - ICON = ICONS["citation"] + DRAG_TARGET = DdTargets.CITATION_LINK + ICON = ICONS["citation"] - def __init__(self, dbstate, obj): - super(ClipCitation, self).__init__(dbstate, obj) - self._type = _("Citation") + def __init__(self, obj): + super(ClipCitation, self).__init__(obj) + self._type = _("Citation") self._objclass = 'Citation' self.refresh() def refresh(self): if self._handle: - citation = self._db.get_citation_from_handle(self._handle) + citation = clipdb.get_citation_from_handle(self._handle) if citation: self._title = citation.get_gramps_id() - notelist = list(map(self._db.get_note_from_handle, - citation.get_note_list())) + notelist = list(map(clipdb.get_note_from_handle, + citation.get_note_list())) srctxtlist = [note for note in notelist - if note.get_type() == NoteType.SOURCE_TEXT] + if note.get_type() == NoteType.SOURCE_TEXT] page = citation.get_page() if not page: page = _('not available|NA') text = "" - if len(srctxtlist) > 0: + if srctxtlist: text = " ".join(srctxtlist[0].get().split()) #String must be unicode for truncation to work for non #ascii characters text = str(text) if len(text) > 60: - text = text[:60]+"..." + text = text[:60] + "..." self._value = _("Volume/Page: %(pag)s -- %(sourcetext)s") % { - 'pag' : page, - 'sourcetext' : text, - } + 'pag' : page, + 'sourcetext' : text} - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_citation_from_handle(handle) - if obj: - return True - return False class ClipRepoRef(ClipObjWrapper): DROP_TARGETS = [DdTargets.REPOREF] - DRAG_TARGET = DdTargets.REPOREF - ICON = LINK_PIC + DRAG_TARGET = DdTargets.REPOREF + ICON = LINK_PIC - def __init__(self, dbstate, obj): - super(ClipRepoRef, self).__init__(dbstate, obj) - self._type = _("Repository ref") + def __init__(self, obj): + super(ClipRepoRef, self).__init__(obj) + self._type = _("Repository ref") self.refresh() def refresh(self): if self._obj: - base = self._db.get_repository_from_handle(self._obj.ref) + base = clipdb.get_repository_from_handle(self._obj.ref) if base: self._title = str(base.get_type()) self._value = base.get_name() + class ClipEventRef(ClipObjWrapper): DROP_TARGETS = [DdTargets.EVENTREF] - DRAG_TARGET = DdTargets.EVENTREF - ICON = LINK_PIC + DRAG_TARGET = DdTargets.EVENTREF + ICON = LINK_PIC - def __init__(self, dbstate, obj): - super(ClipEventRef, self).__init__(dbstate, obj) - self._type = _("Event ref") + def __init__(self, obj): + super(ClipEventRef, self).__init__(obj) + self._type = _("Event ref") self.refresh() def refresh(self): if self._obj: - base = self._db.get_event_from_handle(self._obj.ref) + base = clipdb.get_event_from_handle(self._obj.ref) if base: self._title = base.gramps_id self._value = str(base.get_type()) + class ClipPlaceRef(ClipObjWrapper): DROP_TARGETS = [DdTargets.PLACEREF] - DRAG_TARGET = DdTargets.PLACEREF - ICON = LINK_PIC + DRAG_TARGET = DdTargets.PLACEREF + ICON = LINK_PIC - def __init__(self, dbstate, obj): - super(ClipPlaceRef, self).__init__(dbstate, obj) - self._type = _("Place ref") + def __init__(self, obj): + super(ClipPlaceRef, self).__init__(obj) + self._type = _("Place ref") self.refresh() def refresh(self): if self._obj: - base = self._db.get_place_from_handle(self._obj.ref) + base = clipdb.get_place_from_handle(self._obj.ref) if base: self._title = base.gramps_id - self._value = place_displayer.display(self._db, base) + self._value = place_displayer.display(clipdb, base) + class ClipName(ClipObjWrapper): DROP_TARGETS = [DdTargets.NAME] - DRAG_TARGET = DdTargets.NAME - ICON = ICONS['name'] + DRAG_TARGET = DdTargets.NAME + ICON = ICONS['name'] - def __init__(self, dbstate, obj): - super(ClipName, self).__init__(dbstate, obj) - self._type = _("Name") + def __init__(self, obj): + super(ClipName, self).__init__(obj) + self._type = _("Name") self.refresh() def refresh(self): @@ -597,15 +567,16 @@ class ClipName(ClipObjWrapper): self._title = str(self._obj.get_type()) self._value = self._obj.get_name() + class ClipPlaceName(ClipObjWrapper): DROP_TARGETS = [DdTargets.PLACENAME] - DRAG_TARGET = DdTargets.PLACENAME - ICON = ICONS['name'] + DRAG_TARGET = DdTargets.PLACENAME + ICON = ICONS['name'] - def __init__(self, dbstate, obj): - super(ClipPlaceName, self).__init__(dbstate, obj) - self._type = _("Place Name") + def __init__(self, obj): + super(ClipPlaceName, self).__init__(obj) + self._type = _("Place Name") self.refresh() def refresh(self): @@ -613,15 +584,16 @@ class ClipPlaceName(ClipObjWrapper): self._title = get_date(self._obj) self._value = self._obj.get_value() + class ClipSurname(ClipObjWrapper): DROP_TARGETS = [DdTargets.SURNAME] - DRAG_TARGET = DdTargets.SURNAME - ICON = ICONS['name'] + DRAG_TARGET = DdTargets.SURNAME + ICON = ICONS['name'] - def __init__(self, dbstate, obj): - super(ClipSurname, self).__init__(dbstate, obj) - self._type = _("Surname") + def __init__(self, obj): + super(ClipSurname, self).__init__(obj) + self._type = _("Surname") self.refresh() def refresh(self): @@ -629,15 +601,16 @@ class ClipSurname(ClipObjWrapper): self._title = self._obj.get_surname() self._value = self._obj.get_surname() + class ClipText(ClipWrapper): DROP_TARGETS = DdTargets.all_text() - DRAG_TARGET = DdTargets.TEXT - ICON = ICONS['text'] + DRAG_TARGET = DdTargets.TEXT + ICON = ICONS['text'] - def __init__(self, dbstate, obj): - super(ClipText, self).__init__(dbstate, obj) - self._type = _("Text") + def __init__(self, obj): + super(ClipText, self).__init__(obj) + self._type = _("Text") if isinstance(self._obj, bytes): self._pickle = str(self._obj, "utf-8") else: @@ -651,83 +624,82 @@ class ClipText(ClipWrapper): else: self._value = self._obj + class ClipMediaObj(ClipHandleWrapper): DROP_TARGETS = [DdTargets.MEDIAOBJ] - DRAG_TARGET = DdTargets.MEDIAOBJ - ICON = ICONS["media"] + DRAG_TARGET = DdTargets.MEDIAOBJ + ICON = ICONS["media"] - def __init__(self, dbstate, obj): - super(ClipMediaObj, self).__init__(dbstate, obj) - self._type = _("Media") + def __init__(self, obj): + super(ClipMediaObj, self).__init__(obj) + self._type = _("Media") self._objclass = 'Media' self.refresh() def refresh(self): if self._handle: - obj = self._db.get_media_from_handle(self._handle) + obj = clipdb.get_media_from_handle(self._handle) if obj: self._title = obj.get_description() self._value = obj.get_path() - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_media_from_handle(handle) - if obj: - return True - return False class ClipMediaRef(ClipObjWrapper): DROP_TARGETS = [DdTargets.MEDIAREF] - DRAG_TARGET = DdTargets.MEDIAREF - ICON = LINK_PIC + DRAG_TARGET = DdTargets.MEDIAREF + ICON = LINK_PIC - def __init__(self, dbstate, obj): - super(ClipMediaRef, self).__init__(dbstate, obj) - self._type = _("Media ref") + def __init__(self, obj): + super(ClipMediaRef, self).__init__(obj) + self._type = _("Media ref") self.refresh() def refresh(self): if self._obj: - base = self._db.get_media_from_handle(self._obj.get_reference_handle()) + base = clipdb.get_media_from_handle( + self._obj.get_reference_handle()) if base: self._title = base.get_description() self._value = base.get_path() + class ClipPersonRef(ClipObjWrapper): DROP_TARGETS = [DdTargets.PERSONREF] - DRAG_TARGET = DdTargets.PERSONREF - ICON = LINK_PIC + DRAG_TARGET = DdTargets.PERSONREF + ICON = LINK_PIC - def __init__(self, dbstate, obj): - super(ClipPersonRef, self).__init__(dbstate, obj) - self._type = _("Person ref") + def __init__(self, obj): + super(ClipPersonRef, self).__init__(obj) + self._type = _("Person ref") self.refresh() def refresh(self): if self._obj: - person = self._db.get_person_from_handle(self._obj.get_reference_handle()) + person = clipdb.get_person_from_handle( + self._obj.get_reference_handle()) if person: self._title = self._obj.get_relation() self._value = person.get_primary_name().get_name() + class ClipChildRef(ClipObjWrapper): DROP_TARGETS = [DdTargets.CHILDREF] - DRAG_TARGET = DdTargets.CHILDREF - ICON = LINK_PIC + DRAG_TARGET = DdTargets.CHILDREF + ICON = LINK_PIC - def __init__(self, dbstate, obj): - super(ClipChildRef, self).__init__(dbstate, obj) - self._type = _("Child ref") + def __init__(self, obj): + super(ClipChildRef, self).__init__(obj) + self._type = _("Child ref") self.refresh() def refresh(self): if self._obj: - person = self._db.get_person_from_handle(self._obj.get_reference_handle()) + person = clipdb.get_person_from_handle( + self._obj.get_reference_handle()) if person: frel = str(self._obj.get_father_relation()) mrel = str(self._obj.get_mother_relation()) @@ -735,150 +707,121 @@ class ClipChildRef(ClipObjWrapper): 'mrel': mrel} self._value = person.get_primary_name().get_name() + class ClipPersonLink(ClipHandleWrapper): DROP_TARGETS = [DdTargets.PERSON_LINK] - DRAG_TARGET = DdTargets.PERSON_LINK - ICON = ICONS["person"] + DRAG_TARGET = DdTargets.PERSON_LINK + ICON = ICONS["person"] - def __init__(self, dbstate, obj): - super(ClipPersonLink, self).__init__(dbstate, obj) - self._type = _("Person") + def __init__(self, obj): + super(ClipPersonLink, self).__init__(obj) + self._type = _("Person") self._objclass = 'Person' self.refresh() def refresh(self): if self._handle: - person = self._db.get_person_from_handle(self._handle) + person = clipdb.get_person_from_handle(self._handle) if person: self._title = person.gramps_id self._value = person.get_primary_name().get_name() - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_person_from_handle(handle) - if obj: - return True - return False - class ClipFamilyLink(ClipHandleWrapper): DROP_TARGETS = [DdTargets.FAMILY_LINK] - DRAG_TARGET = DdTargets.FAMILY_LINK - ICON = ICONS["family"] + DRAG_TARGET = DdTargets.FAMILY_LINK + ICON = ICONS["family"] - def __init__(self, dbstate, obj): - super(ClipFamilyLink, self).__init__(dbstate, obj) - self._type = _("Family") + def __init__(self, obj): + super(ClipFamilyLink, self).__init__(obj) + self._type = _("Family") self._objclass = 'Family' self.refresh() def refresh(self): from gramps.gen.simple import SimpleAccess if self._handle: - family = self._db.get_family_from_handle(self._handle) + family = clipdb.get_family_from_handle(self._handle) if family: - sa = SimpleAccess(self._db) + _sa = SimpleAccess(clipdb) self._title = family.gramps_id - self._value = sa.describe(family) + self._value = _sa.describe(family) - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_family_from_handle(handle) - if obj: - return True - return False class ClipSourceLink(ClipHandleWrapper): DROP_TARGETS = [DdTargets.SOURCE_LINK] - DRAG_TARGET = DdTargets.SOURCE_LINK - ICON = ICONS["source"] + DRAG_TARGET = DdTargets.SOURCE_LINK + ICON = ICONS["source"] - def __init__(self, dbstate, obj): - super(ClipSourceLink, self).__init__(dbstate, obj) - self._type = _("Source") + def __init__(self, obj): + super(ClipSourceLink, self).__init__(obj) + self._type = _("Source") self._objclass = 'Source' self.refresh() def refresh(self): if self._handle: - source = self._db.get_source_from_handle(self._handle) + source = clipdb.get_source_from_handle(self._handle) if source: self._title = source.get_gramps_id() self._value = source.get_title() - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_source_from_handle(handle) - if obj: - return True - return False class ClipRepositoryLink(ClipHandleWrapper): DROP_TARGETS = [DdTargets.REPO_LINK] - DRAG_TARGET = DdTargets.REPO_LINK - ICON = ICONS["repository"] + DRAG_TARGET = DdTargets.REPO_LINK + ICON = ICONS["repository"] - def __init__(self, dbstate, obj): - super(ClipRepositoryLink, self).__init__(dbstate, obj) - self._type = _("Repository") + def __init__(self, obj): + super(ClipRepositoryLink, self).__init__(obj) + self._type = _("Repository") self._objclass = 'Repository' self.refresh() def refresh(self): if self._handle: - source = self._db.get_repository_from_handle(self._handle) + source = clipdb.get_repository_from_handle(self._handle) if source: self._title = str(source.get_type()) self._value = source.get_name() - def is_valid(self): - data = pickle.loads(self._obj) - handle = data[2] - obj = self._db.get_repository_from_handle(handle) - if obj: - return True - return False - #------------------------------------------------------------------------- # # Wrapper classes to deal with lists of objects # #------------------------------------------------------------------------- + class ClipDropList: DROP_TARGETS = [DdTargets.LINK_LIST] - DRAG_TARGET = None + DRAG_TARGET = None - def __init__(self, dbstate, obj_list): - self._dbstate = dbstate + def __init__(self, obj_list): # ('link-list', id, (('person-link', handle), # ('person-link', handle), ...), 0) self._obj_list = pickle.loads(obj_list) def get_objects(self): - list_type, id, handles, timestamp = self._obj_list + list_type, _id, handles, timestamp = self._obj_list retval = [] for (target, handle) in handles: _class = map2class(target) if _class: - obj = _class(self._dbstate, pickle.dumps((target, id, handle, timestamp))) + obj = _class(pickle.dumps((target, _id, handle, timestamp))) if obj: retval.append(obj) return retval + class ClipDropRawList(ClipDropList): DROP_TARGETS = [DdTargets.RAW_LIST] - DRAG_TARGET = None + DRAG_TARGET = None - def __init__(self, dbstate, obj_list): - self._dbstate = dbstate + def __init__(self, obj_list): # ('raw-list', id, (ClipObject, ClipObject, ...), 0) self._obj_list = pickle.loads(obj_list) @@ -890,17 +833,17 @@ class ClipDropRawList(ClipDropList): target = pickle.loads(item)[0] _class = map2class(target) if _class: - obj = _class(self._dbstate, item) + obj = _class(item) if obj: retval.append(obj) return retval + class ClipDropHandleList(ClipDropList): DROP_TARGETS = [DdTargets.HANDLE_LIST] - DRAG_TARGET = None + DRAG_TARGET = None - def __init__(self, dbstate, obj_list): - self._dbstate = dbstate + def __init__(self, obj_list): # incoming: # ('handle-list', id, (('Person', '2763526751235'), # ('Source', '3786234743978'), ...), 0) @@ -914,12 +857,13 @@ class ClipDropHandleList(ClipDropList): # outgoing: # (drag_type, idval, self._handle, val) = pickle.loads(self._obj) data = (target, id(self), handle, 0) - obj = _class(self._dbstate, pickle.dumps(data)) + obj = _class(pickle.dumps(data)) retval.append(obj) return retval # FIXME: add family + #------------------------------------------------------------------------- # # ClipboardListModel class @@ -929,14 +873,13 @@ class ClipboardListModel(Gtk.ListStore): def __init__(self): Gtk.ListStore.__init__(self, - str, # 0: object type - object, # 1: object - object, # 2: tooltip callback - str, # 3: type - str, # 4: value - str, # 5: unique database id (dbid) - str, # 6: db name (may be old) - ) + str, # 0: object type + object, # 1: object + object, # 2: tooltip callback + str, # 3: type + str, # 4: value + str, # 5: unique database id (dbid) + str) # 6: db name (may be old) #------------------------------------------------------------------------- @@ -946,7 +889,7 @@ class ClipboardListModel(Gtk.ListStore): #------------------------------------------------------------------------- class ClipboardListView: - LOCAL_DRAG_TYPE = 'MY_TREE_MODEL_ROW' + LOCAL_DRAG_TYPE = 'MY_TREE_MODEL_ROW' LOCAL_DRAG_ATOM_TYPE = Gdk.atom_intern(LOCAL_DRAG_TYPE, False) LOCAL_DRAG_TARGET = (LOCAL_DRAG_ATOM_TYPE, Gtk.TargetFlags.SAME_WIDGET, 0) @@ -1008,13 +951,13 @@ class ClipboardListView: targ_data = DdTargets.all_dtype() tglist = Gtk.TargetList.new([]) tglist.add(ClipboardListView.LOCAL_DRAG_TARGET[0], - ClipboardListView.LOCAL_DRAG_TARGET[1], - ClipboardListView.LOCAL_DRAG_TARGET[2]) - for tg in targ_data: - tglist.add(tg.atom_drag_type, tg.target_flags, tg.app_id) - self._widget.enable_model_drag_dest([], - Gdk.DragAction.COPY) - #TODO GTK3: workaround here for bug https://bugzilla.gnome.org/show_bug.cgi?id=680638 + ClipboardListView.LOCAL_DRAG_TARGET[1], + ClipboardListView.LOCAL_DRAG_TARGET[2]) + for _tg in targ_data: + tglist.add(_tg.atom_drag_type, _tg.target_flags, _tg.app_id) + self._widget.enable_model_drag_dest([], Gdk.DragAction.COPY) + #TODO GTK3: workaround here for bug + # https://bugzilla.gnome.org/show_bug.cgi?id=680638 self._widget.drag_dest_set_target_list(tglist) #self._widget.drag_dest_set(Gtk.DestDefaults.ALL, targ_data, # Gdk.DragAction.COPY) @@ -1028,8 +971,11 @@ class ClipboardListView: self.register_wrapper_classes() - def database_changed(self,db): - self._db = db + def database_changed(self, db): + if not db.is_open(): + return + global clipdb + clipdb = db # Note: delete event is emitted before the delete, so checking # if valid on this is useless ! db_signals = ( @@ -1047,70 +993,69 @@ class ClipboardListView: 'event-rebuild', 'repository-update', 'repository-rebuild', - 'note-rebuild' - ) + 'note-rebuild') for signal in db_signals: - self._db.connect(signal,self.refresh_objects) + clipdb.connect(signal, self.refresh_objects) - self._db.connect('person-delete', - gen_del_obj(self.delete_object, 'person-link')) - self._db.connect('person-delete', - gen_del_obj(self.delete_object_ref, 'personref')) - self._db.connect('person-delete', - gen_del_obj(self.delete_object_ref, 'childref')) - self._db.connect('source-delete', - gen_del_obj(self.delete_object, 'source-link')) - self._db.connect('source-delete', - gen_del_obj(self.delete_object_ref, 'srcref')) - self._db.connect('repository-delete', - gen_del_obj(self.delete_object, 'repo-link')) - self._db.connect('event-delete', - gen_del_obj(self.delete_object, 'pevent')) - self._db.connect('event-delete', - gen_del_obj(self.delete_object_ref, 'eventref')) - self._db.connect('media-delete', - gen_del_obj(self.delete_object, 'media')) - self._db.connect('media-delete', - gen_del_obj(self.delete_object_ref, 'mediaref')) - self._db.connect('place-delete', - gen_del_obj(self.delete_object, 'place-link')) - self._db.connect('note-delete', - gen_del_obj(self.delete_object, 'note-link')) + clipdb.connect('person-delete', + gen_del_obj(self.delete_object, 'person-link')) + clipdb.connect('person-delete', + gen_del_obj(self.delete_object_ref, 'personref')) + clipdb.connect('person-delete', + gen_del_obj(self.delete_object_ref, 'childref')) + clipdb.connect('source-delete', + gen_del_obj(self.delete_object, 'source-link')) + clipdb.connect('source-delete', + gen_del_obj(self.delete_object_ref, 'srcref')) + clipdb.connect('repository-delete', + gen_del_obj(self.delete_object, 'repo-link')) + clipdb.connect('event-delete', + gen_del_obj(self.delete_object, 'pevent')) + clipdb.connect('event-delete', + gen_del_obj(self.delete_object_ref, 'eventref')) + clipdb.connect('media-delete', + gen_del_obj(self.delete_object, 'media')) + clipdb.connect('media-delete', + gen_del_obj(self.delete_object_ref, 'mediaref')) + clipdb.connect('place-delete', + gen_del_obj(self.delete_object, 'place-link')) + clipdb.connect('note-delete', + gen_del_obj(self.delete_object, 'note-link')) # family-delete not needed, cannot be dragged! self.refresh_objects() - def refresh_objects(self,dummy=None): + def refresh_objects(self, dummy=None): model = self._widget.get_model() if model: - for o in model: - if not o[1].is_valid(): - model.remove(o.iter) + for _ob in model: + if not _ob[1].is_valid(): + model.remove(_ob.iter) else: - o[1].refresh() - o[4] = o[1].get_value() # Force listview to update + _ob[1].refresh() + _ob[4] = _ob[1].get_value() # Force listview to update def delete_object(self, handle_list, link_type): model = self._widget.get_model() if model: - for o in model: - if o[0] == link_type: - data = pickle.loads(o[1]._obj) + for _ob in model: + if _ob[0] == link_type: + data = pickle.loads(_ob[1]._obj) if data[2] in handle_list: - model.remove(o.iter) + model.remove(_ob.iter) def delete_object_ref(self, handle_list, link_type): model = self._widget.get_model() if model: - for o in model: - if o[0] == link_type: - data = o[1]._obj.get_reference_handle() + for _ob in model: + if _ob[0] == link_type: + data = _ob[1]._obj.get_reference_handle() if data in handle_list: - model.remove(o.iter) + model.remove(_ob.iter) # Method to manage the wrapper classes. @@ -1143,40 +1088,40 @@ class ClipboardListView: self.register_wrapper_class(ClipText) self.register_wrapper_class(ClipNote) - def register_wrapper_class(self,wrapper_class): + def register_wrapper_class(self, wrapper_class): for drop_target in wrapper_class.DROP_TARGETS: - self._target_type_to_wrapper_class_map[drop_target.drag_type] = wrapper_class + self._target_type_to_wrapper_class_map[ + drop_target.drag_type] = wrapper_class # Methods for rendering the cells. def object_pixbuf(self, column, cell, model, node, user_data=None): - o = model.get_value(node, 1) - if o._dbid is not None and o._dbid != self.dbstate.db.get_dbid(): - if isinstance(o.__class__.UNAVAILABLE_ICON, str): + _ob = model.get_value(node, 1) + if _ob._dbid is not None and _ob._dbid != self.dbstate.db.get_dbid(): + if isinstance(_ob.__class__.UNAVAILABLE_ICON, str): cell.set_property('icon-name', - o.__class__.UNAVAILABLE_ICON) + _ob.__class__.UNAVAILABLE_ICON) else: cell.set_property('pixbuf', - o.__class__.UNAVAILABLE_ICON) + _ob.__class__.UNAVAILABLE_ICON) else: - cell.set_property('pixbuf', o.__class__.ICON) + cell.set_property('pixbuf', _ob.__class__.ICON) def object_type(self, column, cell, model, node, user_data=None): - o = model.get_value(node, 1) - cell.set_property('text', o.get_type()) + _ob = model.get_value(node, 1) + cell.set_property('text', _ob.get_type()) def object_title(self, column, cell, model, node, user_data=None): - o = model.get_value(node, 1) - cell.set_property('text', o.get_title()) + _ob = model.get_value(node, 1) + cell.set_property('text', _ob.get_title()) def object_value(self, column, cell, model, node, user_data=None): - o = model.get_value(node, 1) - cell.set_property('text', o.get_value()) + _ob = model.get_value(node, 1) + cell.set_property('text', _ob.get_value()) def get_dbname(self, column, cell, model, node, user_data=None): - o = model.get_value(node, 1) - cell.set_property('text', o.get_dbname()) - + _ob = model.get_value(node, 1) + cell.set_property('text', _ob.get_dbname()) # handlers for the drag and drop events. @@ -1184,23 +1129,26 @@ class ClipboardListView: tree_selection = self._widget.get_selection() model, paths = tree_selection.get_selected_rows() if len(paths) > 1: - targets = [(DdTargets.RAW_LIST.atom_drag_type, Gtk.TargetFlags.SAME_WIDGET, 0), + targets = [(DdTargets.RAW_LIST.atom_drag_type, + Gtk.TargetFlags.SAME_WIDGET, 0), ClipboardListView.LOCAL_DRAG_TARGET] else: targets = [ClipboardListView.LOCAL_DRAG_TARGET] for path in paths: node = model.get_iter(path) if node is not None: - o = model.get_value(node,1) - targets += [target.target_data_atom() for target in o.__class__.DROP_TARGETS] + _ob = model.get_value(node, 1) + targets += [target.target_data_atom() + for target in _ob.__class__.DROP_TARGETS] - #TODO GTK3: workaround here for bug https://bugzilla.gnome.org/show_bug.cgi?id=680638 - self._widget.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, - [], - Gdk.DragAction.COPY | Gdk.DragAction.MOVE) + #TODO GTK3: workaround here for bug + # https://bugzilla.gnome.org/show_bug.cgi?id=680638 + self._widget.enable_model_drag_source( + Gdk.ModifierType.BUTTON1_MASK, [], + Gdk.DragAction.COPY | Gdk.DragAction.MOVE) tglist = Gtk.TargetList.new([]) - for tg in targets: - tglist.add(tg[0], tg[1], tg[2]) + for _tg in targets: + tglist.add(_tg[0], _tg[1], _tg[2]) self._widget.drag_source_set_target_list(tglist) def object_drag_begin(self, widget, drag_context): @@ -1215,11 +1163,11 @@ class ClipboardListView: node = model.get_iter(path) target = model.get_value(node, 0) if target == "TEXT": - layout = widget.create_pango_layout(model.get_value(node,4)) + layout = widget.create_pango_layout(model.get_value(node, 4)) layout.set_alignment(Pango.Alignment.CENTER) width, height = layout.get_pixel_size() surface = cairo.ImageSurface(cairo.FORMAT_RGB24, - width, height) + width, height) ctx = cairo.Context(surface) style_ctx = self._widget.get_style_context() Gtk.render_background(style_ctx, ctx, 0, 0, width, height) @@ -1249,17 +1197,17 @@ class ClipboardListView: if len(paths) == 1: path = paths[0] node = model.get_iter(path) - o = model.get_value(node,1) + _ob = model.get_value(node, 1) if model.get_value(node, 0) == 'TEXT': - sel_data.set_text(o._value, -1) + sel_data.set_text(_ob._value, -1) else: - sel_data.set(tgs[0], 8, o.pack()) + sel_data.set(tgs[0], 8, _ob.pack()) elif len(paths) > 1: raw_list = [] for path in paths: node = model.get_iter(path) - o = model.get_value(node,1) - raw_list.append(o.pack()) + _ob = model.get_value(node, 1) + raw_list.append(_ob.pack()) sel_data.set(tgs[0], 8, pickle.dumps(raw_list)) def object_drag_data_received(self, widget, context, x, y, selection, info, @@ -1269,15 +1217,15 @@ class ClipboardListView: if hasattr(selection, "data"): sel_data = selection.data else: - sel_data = selection.get_data() # GtkSelectionData + sel_data = selection.get_data() # GtkSelectionData # In Windows time is always zero. Until that is fixed, use the seconds # of the local time to filter out double drops. - realTime = strftime("%S") + real_time = strftime("%S") # There is a strange bug that means that if there is a selection # in the list we get multiple drops of the same object. Luckily # the time values are the same so we can drop all but the first. - if (realTime == self._previous_drop_time) and (time != -1): + if (real_time == self._previous_drop_time) and (time != -1): return None # Find a wrapper class @@ -1304,49 +1252,58 @@ class ClipboardListView: tgs = context.targets else: tgs = [atm.name() for atm in context.list_targets()] - possible_wrappers = [target for target in tgs - if target in self._target_type_to_wrapper_class_map] + possible_wrappers = [ + target for target in tgs + if target in self._target_type_to_wrapper_class_map] - if len(possible_wrappers) == 0: + if not possible_wrappers: # No wrapper for this class return None # Just select the first match. wrapper_class = self._target_type_to_wrapper_class_map[ - str(possible_wrappers[0])] + str(possible_wrappers[0])] try: - o = wrapper_class(self.dbstate, sel_data) + _ob = wrapper_class(sel_data) if title: - o._title = title + _ob._title = title if value: - o._value = value + _ob._value = value if dbid: - o._dbid = dbid + _ob._dbid = dbid if dbname: - o._dbname = dbname + _ob._dbname = dbname + # If this was a ClipPersonLink with a list for a handle, we don't + # want it. Can happen in People Treeview with attemp to drag last + # name group. + if (isinstance(_ob, ClipHandleWrapper) and + isinstance(_ob._handle, list)): + return None # If the wrapper object is a subclass of ClipDropList then # the drag data was a list of objects and we need to decode # all of them. - if isinstance(o,ClipDropList): - o_list = o.get_objects() + if isinstance(_ob, ClipDropList): + o_list = _ob.get_objects() else: - o_list = [o] - for o in o_list: - if o.__class__.DRAG_TARGET is None: + o_list = [_ob] + for _ob in o_list: + if _ob.__class__.DRAG_TARGET is None: continue - data = [o.__class__.DRAG_TARGET.drag_type, o, None, - o._type, o._value, o._dbid, o._dbname] + data = [_ob.__class__.DRAG_TARGET.drag_type, _ob, None, + _ob._type, _ob._value, _ob._dbid, _ob._dbname] contains = model_contains(model, data) - if ((context.action if hasattr(context, "action") else context.get_actions()) - != Gdk.DragAction.MOVE) and contains: + if (contains and + ((context.action if hasattr(context, "action") else + context.get_actions()) != Gdk.DragAction.MOVE)): continue drop_info = widget.get_dest_row_at_pos(x, y) if drop_info: path, position = drop_info node = model.get_iter(path) - if (position == Gtk.TreeViewDropPosition.BEFORE - or position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE): + if position == Gtk.TreeViewDropPosition.BEFORE or \ + position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE: + model.insert_before(node, data) else: model.insert_after(node, data) @@ -1356,21 +1313,22 @@ class ClipboardListView: # FIXME: there is one bug here: if you multi-select and drop # on self, then it moves the first, and copies the rest. - if ((context.action if hasattr(context, "action") else context.get_actions()) == - Gdk.DragAction.MOVE): + if ((context.action if hasattr(context, "action") else + context.get_actions()) == Gdk.DragAction.MOVE): context.finish(True, True, time) # remember time for double drop workaround. - self._previous_drop_time = realTime + self._previous_drop_time = real_time return o_list except EOFError: return None # proxy methods to provide access to the real widget functions. - def set_model(self,model=None): + def set_model(self, model=None): self._widget.set_model(model) - self._widget.get_selection().connect('changed',self.on_object_select_row) + self._widget.get_selection().connect('changed', + self.on_object_select_row) self._widget.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) def get_model(self): @@ -1379,9 +1337,10 @@ class ClipboardListView: def get_selection(self): return self._widget.get_selection() - def set_search_column(self,col): + def set_search_column(self, col): return self._widget.set_search_column(col) + #------------------------------------------------------------------------- # # ClipboardWindow class @@ -1415,7 +1374,7 @@ class ClipboardWindow(ManagedWindow): def __init__(self, dbstate, uistate): """Initialize the ClipboardWindow class, and display the window""" - ManagedWindow.__init__(self,uistate,[],self.__class__) + ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.database_changed(self.dbstate.db) @@ -1433,8 +1392,8 @@ class ClipboardWindow(ManagedWindow): scrolledwindow.remove(objectlist) scrolledwindow.add(mtv) self.object_list = ClipboardListView(self.dbstate, mtv) - self.object_list.get_selection().connect('changed', - self.set_clear_btn_sensitivity) + self.object_list.get_selection().connect( + 'changed', self.set_clear_btn_sensitivity) self.object_list.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self.set_clear_btn_sensitivity(sel=self.object_list.get_selection()) @@ -1443,9 +1402,9 @@ class ClipboardWindow(ManagedWindow): self.set_clear_all_btn_sensitivity(treemodel=ClipboardWindow.otree) ClipboardWindow.otree.connect('row-deleted', - self.set_clear_all_btn_sensitivity) + self.set_clear_all_btn_sensitivity) ClipboardWindow.otree.connect('row-inserted', - self.set_clear_all_btn_sensitivity) + self.set_clear_all_btn_sensitivity) self.object_list.set_model(ClipboardWindow.otree) @@ -1456,27 +1415,27 @@ class ClipboardWindow(ManagedWindow): self.top.connect_signals({ "on_close_clipboard" : self.close, "on_clear_clicked": self.on_clear_clicked, - "on_help_clicked": self.on_help_clicked, - }) + "on_help_clicked": self.on_help_clicked}) self.clear_all_btn.connect_object('clicked', Gtk.ListStore.clear, ClipboardWindow.otree) - self.db.connect('database-changed', lambda x: ClipboardWindow.otree.clear()) + self.db.connect('database-changed', + lambda x: ClipboardWindow.otree.clear()) self.show() def build_menu_names(self, obj): - return (_('Clipboard'),None) + return (_('Clipboard'), None) - def database_changed(self,database): + def database_changed(self, database): self.db = database def set_clear_all_btn_sensitivity(self, treemodel=None, path=None, node=None, user_param1=None): - if len(treemodel) == 0: - self.clear_all_btn.set_sensitive(False) - else: + if treemodel: self.clear_all_btn.set_sensitive(True) + else: + self.clear_all_btn.set_sensitive(False) def set_clear_btn_sensitivity(self, sel=None, user_param1=None): if sel.count_selected_rows() == 0: @@ -1498,6 +1457,7 @@ class ClipboardWindow(ManagedWindow): if node: model.remove(node) + #------------------------------------------------------------------------- # # MultiTreeView class @@ -1523,7 +1483,7 @@ class MultiTreeView(Gtk.TreeView): if event.keyval == Gdk.KEY_Delete: model, paths = self.get_selection().get_selected_rows() # reverse, to delete from the end - paths.sort(key=lambda x:-x[0]) + paths.sort(key=lambda x: -x[0]) for path in paths: try: node = model.get_iter(path) @@ -1542,68 +1502,82 @@ class MultiTreeView(Gtk.TreeView): store, paths = selection.get_selected_rows() if not paths: return - tpath = paths[0] if len(paths) > 0 else None + tpath = paths[0] if paths else None node = store.get_iter(tpath) if tpath else None - o = None + _ob = None if node: - o = store.get_value(node, 1) + _ob = store.get_value(node, 1) self.newmenu = Gtk.Menu() popup = self.newmenu # --------------------------- - if o: - objclass, handle = o._objclass, o._handle + if _ob: + objclass, handle = _ob._objclass, _ob._handle else: objclass, handle = None, None - if objclass in ['Person', 'Event', 'Media', 'Source', 'Citation', - 'Repository', 'Family', 'Note', 'Place']: - menu_item = Gtk.MenuItem(label=_("the object|See %s details") % glocale.trans_objclass(objclass)) - menu_item.connect("activate", - lambda widget: self.edit_obj(objclass, handle)) - popup.append(menu_item) - menu_item.show() - # --------------------------- - menu_item = Gtk.MenuItem(label=_("the object|Make %s active") % glocale.trans_objclass(objclass)) - menu_item.connect("activate", - lambda widget: self.uistate.set_active(handle, objclass)) - popup.append(menu_item) - menu_item.show() + if obj2class(objclass): + if self.dbstate.db.method('has_%s_handle', objclass)(handle): + menu_item = Gtk.MenuItem( + label=_("the object|See %s details") % + glocale.trans_objclass(objclass)) + menu_item.connect( + "activate", + lambda widget: self.edit_obj(objclass, handle)) + popup.append(menu_item) + menu_item.show() + # --------------------------- + menu_item = Gtk.MenuItem( + label=_("the object|Make %s active") % + glocale.trans_objclass(objclass)) + menu_item.connect( + "activate", lambda widget: + self.uistate.set_active(handle, objclass)) + popup.append(menu_item) + menu_item.show() # --------------------------- gids = set() for path in paths: node = store.get_iter(path) if node: - o = store.get_value(node, 1) - if o._objclass == objclass: - my_handle = o._handle - obj = self.dbstate.db.method('get_%s_from_handle', objclass)(my_handle) - if obj: + _ob = store.get_value(node, 1) + if _ob._objclass == objclass: + my_handle = _ob._handle + if self.dbstate.db.method('has_%s_handle', + objclass)(my_handle): + obj = self.dbstate.db.method( + 'get_%s_from_handle', objclass)(my_handle) gids.add(obj.gramps_id) - menu_item = Gtk.MenuItem(label=_("the object|Create Filter from %s selected...") % glocale.trans_objclass(objclass)) - menu_item.connect("activate", - lambda widget: make_filter(self.dbstate, self.uistate, - objclass, gids, title=self.title)) - popup.append(menu_item) - menu_item.show() - # Show the popup menu: - popup.popup(None, None, None, None, 3, event.time) + if gids: + menu_item = Gtk.MenuItem( + label=_("the object|Create Filter from %s " + "selected...") % + glocale.trans_objclass(objclass)) + menu_item.connect("activate", lambda widget: make_filter( + self.dbstate, self.uistate, + objclass, gids, title=self.title)) + popup.append(menu_item) + menu_item.show() + if popup.get_children(): # Show the popup menu: + popup.popup(None, None, None, None, 3, event.time) return True elif event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1: model, paths = self.get_selection().get_selected_rows() for path in paths: node = model.get_iter(path) if node is not None: - o = model.get_value(node,1) - objclass = o._objclass - handle = o._handle + _ob = model.get_value(node, 1) + objclass = _ob._objclass + handle = _ob._handle self.edit_obj(objclass, handle) return True # otherwise: - if (target - and event.type == Gdk.EventType.BUTTON_PRESS - and not (event.get_state() & get_primary_mask(Gdk.ModifierType.SHIFT_MASK)) - and self.get_selection().path_is_selected(target[0])): + if (target and + event.type == Gdk.EventType.BUTTON_PRESS and + self.get_selection().path_is_selected(target[0]) and not + (event.get_state() & + get_primary_mask(Gdk.ModifierType.SHIFT_MASK))): # disable selection - self.get_selection().set_select_function(lambda *ignore: False, None) + self.get_selection().set_select_function( + lambda *ignore: False, None) self.defer_select = target[0] def on_button_release(self, widget, event): @@ -1611,111 +1585,52 @@ class MultiTreeView(Gtk.TreeView): self.get_selection().set_select_function(lambda *ignore: True, None) target = self.get_path_at_pos(int(event.x), int(event.y)) - if (self.defer_select and target - and self.defer_select == target[0] - and not (event.x==0 and event.y==0)): # certain drag and drop + if (self.defer_select and target and + self.defer_select == target[0] and not + (event.x == 0 and + event.y == 0)): # certain drag and drop self.set_cursor(target[0], target[1], False) - self.defer_select=False + self.defer_select = False def on_drag_end(self, widget, event): # re-enable selection self.get_selection().set_select_function(lambda *ignore: True, None) - self.defer_select=False + self.defer_select = False def edit_obj(self, objclass, handle): from .editors import (EditPerson, EditEvent, EditFamily, EditSource, EditPlace, EditRepository, EditNote, EditMedia, EditCitation) - if objclass == 'Person': - person = self.dbstate.db.get_person_from_handle(handle) - if person: + if obj2class(objclass): # make sure it is an editable object + if self.dbstate.db.method('has_%s_handle', objclass)(handle): + g_object = self.dbstate.db.method( + 'get_%s_from_handle', objclass)(handle) try: - EditPerson(self.dbstate, - self.uistate, [], person) - except WindowActiveError: - pass - elif objclass == 'Event': - event = self.dbstate.db.get_event_from_handle(handle) - if event: - try: - EditEvent(self.dbstate, - self.uistate, [], event) - except WindowActiveError: - pass - elif objclass == 'Family': - ref = self.dbstate.db.get_family_from_handle(handle) - if ref: - try: - EditFamily(self.dbstate, - self.uistate, [], ref) - except WindowActiveError: - pass - elif objclass == 'Source': - ref = self.dbstate.db.get_source_from_handle(handle) - if ref: - try: - EditSource(self.dbstate, - self.uistate, [], ref) - except WindowActiveError: - pass - elif objclass == 'Place': - ref = self.dbstate.db.get_place_from_handle(handle) - if ref: - try: - EditPlace(self.dbstate, - self.uistate, [], ref) - except WindowActiveError: - pass - elif objclass == 'Repository': - ref = self.dbstate.db.get_repository_from_handle(handle) - if ref: - try: - EditRepository(self.dbstate, - self.uistate, [], ref) - except WindowActiveError: - pass - elif objclass == 'Note': - ref = self.dbstate.db.get_note_from_handle(handle) - if ref: - try: - EditNote(self.dbstate, - self.uistate, [], ref) - except WindowActiveError: - pass - elif objclass == 'Media': - ref = self.dbstate.db.get_media_from_handle(handle) - if ref: - try: - EditMedia(self.dbstate, - self.uistate, [], ref) - except WindowActiveError: - pass - elif objclass == 'Citation': - ref = self.dbstate.db.get_citation_from_handle(handle) - if ref: - try: - EditCitation(self.dbstate, self.uistate, [], ref) + locals()['Edit' + objclass]( + self.dbstate, self.uistate, [], g_object) except WindowActiveError: pass -def short(val,size=60): +def short(val, size=60): if len(val) > size: return "%s..." % val[0:size] - else: - return val + return val + def place_title(db, event): return place_displayer.display_event(db, event) + def gen_del_obj(func, t): return lambda l : func(l, t) + #------------------------------------------------------------------------- # # # #------------------------------------------------------------------------- -def Clipboard(database,person,callback,parent=None): - ClipboardWindow(database,parent) +def Clipboard(database, person, callback, parent=None): + ClipboardWindow(database, parent)