Clean-up Sources and Citations views:

* Add icon for citations view
* disable old sourceview
* change citationtreeview to be Sources navigation view
* citationlistview is now the Citations view
* merge libcitationview into citationlistview and citationtreeview, and corrected and rationalised
* remove libcitationview
* corrected initialisation of source_handle in Citation.py
* fixes for preventing same source being edited twice
    - fixed blockedtext in citationembededlist
    - override build_window_key in editcitation.py

svn: r18211
This commit is contained in:
Tim G L Lyons 2011-09-26 19:53:18 +00:00
parent a4f9e6834d
commit a906c98439
18 changed files with 641 additions and 472 deletions

View File

@ -134,6 +134,7 @@ class _DdTargets(object):
self.SOURCE_LINK = _DdType(self, 'source-link')
self.URL = _DdType(self, 'url')
self.SURNAME = _DdType(self, 'surname')
self.CITATION_LINK = _DdType(self, 'citation-link')
# List of all types that are used between
# gramps widgets but should not be exported
@ -160,7 +161,8 @@ class _DdTargets(object):
self.SOURCEREF,
self.SOURCE_LINK,
self.URL,
self.SURNAME
self.SURNAME,
self.CITATION_LINK
]
self.CHILD = _DdType(self, 'child')

View File

@ -70,7 +70,7 @@ class Citation(MediaBase, NoteBase, PrimaryObject, DateBase):
MediaBase.__init__(self) # 7
NoteBase.__init__(self) # 6
DateBase.__init__(self) # 2
self.source_handle = None, # 5
self.source_handle = None # 5
self.page = "" # 3
self.confidence = Citation.CONF_NORMAL # 4
self.datamap = {} # 8

View File

@ -180,6 +180,16 @@ class CitationEmbedList(EmbeddedList, DbGUIElement):
else:
raise ValueError("selection must be either source or citation")
def __blocked_text(self):
"""
Return the common text used when citation cannot be edited
"""
return _("This citation cannot be created at this time. "
"Either the associated Source object is already being "
"edited, or another citation associated with the same "
"source is being edited.\n\nTo edit this "
"citation, you need to close the object.")
def edit_button_clicked(self, obj):
"""
Get the selected Citation instance and call the EditCitation editor
@ -190,10 +200,8 @@ class CitationEmbedList(EmbeddedList, DbGUIElement):
This prevents the dialog from coming up twice on the same object.
"""
handle = self.get_selected()
LOG.debug('selected handle %s' % handle)
if handle:
citation = self.dbstate.db.get_citation_from_handle(handle)
LOG.debug("selected citation: %s" % citation)
try:
from gui.editors import EditCitation
EditCitation(self.dbstate, self.uistate, self.track, citation,

View File

@ -90,6 +90,37 @@ class EditCitation(EditPrimary):
# EditCitation, not only do we need to protect obj (which will be
# a Citation, but we also need to protect the associated Source.
def build_window_key(self, obj):
"""
Return a key for the edit window that is opened.
This function overrides the build_window_key in EditPrimary.
There is a problem with database object locking. The database locking is
handled by the ManagedWindow class, which will only allow one primary
object to be edited at a time.
Normally, the window key is derived from the obj that is being edited.
However, in the case of EditCitation, there are two objects being
edited, the Citation and the Source. Both must be protected against
against the user trying to edit them twice.
What we do here is to derive the window key from the Source object, if
one exists. A Citation always points to exactly one Source object, so if
we try to edit the same Citation twice, the associated Source objects
will be the same so this will be prevented. If we try to edit a Source
object and a Citation object that refers to the same Source, then again,
the window key will be the same and this will be prevented.
"""
if obj and obj.get_reference_handle():
# citation already points to source
return obj.get_reference_handle()
elif self.source and self.source.get_handle():
# Citation doesn't yet point to source, but source exists and has a
# handle
return self.source.get_handle()
else:
return id(self)
def empty_object(self):
"""
Return an empty Citation object for comparison for changes.
@ -181,7 +212,6 @@ class EditCitation(EditPrimary):
"""Connects any signals that need to be connected.
Called by the init routine of the base class L{EditPrimary}.
"""
self.define_ok_button(self.glade.get_object('ok'), self.save)
self.define_cancel_button(self.glade.get_object('cancel'))
@ -191,7 +221,19 @@ class EditCitation(EditPrimary):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
What this code does is to check that the object edited is not deleted
whilst editing it. If the object is deleted we need to close the editor
windows and clean up. If the database emits a rebuild signal for the
database object type we also abort the edit.
The Citation editor edits two primary objects, and therefore we need to
check if either have been deleted. If the source is deleted, the
citation must have been deleted first and will emit a signal, so we
shouldn't have to connect to the source-delete signal. It should not be
necessary to connect to the source- rebuild signal for similar reasons.
"""
# FIXME: Should this be modified so that the 'close' routines
# are executed not only for the 'Citation', bit also for the 'Source'
self._add_db_signal('citation-rebuild', self._do_close)

View File

@ -151,6 +151,7 @@ def register_stock_icons ():
('gramps-zoom-out', _('Zoom Out'), gtk.gdk.CONTROL_MASK, 0, ''),
('gramps-zoom-fit-width', _('Fit Width'), gtk.gdk.CONTROL_MASK, 0, ''),
('gramps-zoom-best-fit', _('Fit Page'), gtk.gdk.CONTROL_MASK, 0, ''),
('gramps-citation', _('Citations'), gtk.gdk.CONTROL_MASK, 0, ''),
]
# the following icons are not yet in new directory structure
# they should be ported in the near future

View File

@ -19,6 +19,7 @@ dist_pkgdata_DATA = \
gramps-bookmark-edit.png \
gramps-bookmark-new.png \
gramps-bookmark.png \
gramps-citation.png \
gramps-config.png \
gramps-date.png \
gramps-date-edit.png \

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -19,6 +19,7 @@ dist_pkgdata_DATA = \
gramps-bookmark-edit.png \
gramps-bookmark-new.png \
gramps-bookmark.png \
gramps-citation.png \
gramps-config.png \
gramps-date-edit.png \
gramps-date.png \

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -19,6 +19,7 @@ dist_pkgdata_DATA = \
gramps-bookmark-edit.png \
gramps-bookmark-new.png \
gramps-bookmark.png \
gramps-citation.png \
gramps-config.png \
gramps-date-edit.png \
gramps-date.png \

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -19,6 +19,7 @@ dist_pkgdata_DATA = \
gramps-bookmark-edit.svg \
gramps-bookmark-new.svg \
gramps-bookmark.svg \
gramps-citation.png \
gramps-config.svg \
gramps-date-edit.svg \
gramps-date.svg \

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -1,427 +0,0 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2001-2006 Donald N. Allingham
# Copyright (C) 2008 Gary Burton
# Copyright (C) 2011 Tim G L Lyons, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Citation View
"""
#-------------------------------------------------------------------------
#
# python modules
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".citation")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from gui.views.listview import ListView
import Utils
import Bookmarks
import Errors
from DdTargets import DdTargets
from QuestionDialog import ErrorDialog
from gui.editors import EditCitation, DeleteCitationQuery, EditSource, \
DeleteSrcQuery
from Filters.SideBar import SourceSidebarFilter
#-------------------------------------------------------------------------
#
# internationalization
#
#-------------------------------------------------------------------------
from gen.ggettext import gettext as _
#-------------------------------------------------------------------------
#
# CitationView
#
#-------------------------------------------------------------------------
class BaseCitationView(ListView):
""" citation listview class
"""
# The configuration parameters have been moved to CitationTreeView and
# CitationListView, because they differ for the two different views.
def __init__(self, pdata, dbstate, uistate, title, model, signal_map,
nav_group=0):
ListView.__init__(
self, title, pdata, dbstate, uistate,
self.COLUMN_NAMES, len(self.COLUMN_NAMES),
model, signal_map,
dbstate.db.get_citation_bookmarks(),
Bookmarks.CitationBookmarks, nav_group,
multiple=True,
filter_class=SourceSidebarFilter)
self.func_list.update({
'<CONTROL>J' : self.jump,
'<CONTROL>BackSpace' : self.key_delete,
})
self.additional_uis.append(self.additional_ui())
def navigation_type(self):
return 'Citation'
def get_bookmarks(self):
return self.dbstate.db.get_citation_bookmarks()
def drag_info(self):
return DdTargets.SOURCE_LINK
def define_actions(self):
"""
This defines the possible actions for the citation views.
Possible actions are:
add_source: Add a new source (this is also available from the
source view)
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)
share: Add a new citation to an existing source (when a source is
selected)
edit: Edit a source or a citation.
merge: Merge the selected sources or citations.
remove: Delete the selected sources or citations.
"""
ListView.define_actions(self)
# gtk stock icons are at http://www.pygtk.org/docs/pygtk/gtk-stock-items.html
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-source', _("Add citation..."),
accel=None,
tip=self.ADD_CITATION_MSG,
callback=self.share)
self.all_action = gtk.ActionGroup(self.title + "/CitationAll")
self.edit_action = gtk.ActionGroup(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('Dummy', None, ' ', None, None, self.dummy_report)
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
This is overridden in citationtreeview because that has additional
popup items for open and close all nodes
"""
return '''<ui>
<menubar name="MenuBar">
<menu action="FileMenu">
<placeholder name="LocalExport">
<menuitem action="ExportTab"/>
</placeholder>
</menu>
<menu action="BookMenu">
<placeholder name="AddEditBook">
<menuitem action="AddBook"/>
<menuitem action="EditBook"/>
</placeholder>
</menu>
<menu action="GoMenu">
<placeholder name="CommonGo">
<menuitem action="Back"/>
<menuitem action="Forward"/>
<separator/>
</placeholder>
</menu>
<menu action="EditMenu">
<placeholder name="CommonEdit">
<menuitem action="Add"/>
<menuitem action="Add source"/>
<menuitem action="Edit"/>
<menuitem action="Remove"/>
<menuitem action="Merge"/>
</placeholder>
<menuitem action="FilterEdit"/>
</menu>
</menubar>
<toolbar name="ToolBar">
<placeholder name="CommonNavigation">
<toolitem action="Back"/>
<toolitem action="Forward"/>
</placeholder>
<placeholder name="CommonEdit">
<toolitem action="Add"/>
<toolitem action="Add source"/>
<toolitem action="Edit"/>
<toolitem action="Remove"/>
<toolitem action="Merge"/>
</placeholder>
</toolbar>
<popup name="Popup">
<menuitem action="Back"/>
<menuitem action="Forward"/>
<separator/>
<menuitem action="Add"/>
<menuitem action="Edit"/>
<menuitem action="Remove"/>
<menuitem action="Merge"/>
<separator/>
<menu name="QuickReport" action="QuickReport">
<menuitem action="Dummy"/>
</menu>
</popup>
</ui>'''
def dummy_report(self, obj):
""" For the xml UI definition of popup to work, the submenu
Quick Report must have an entry in the xml
As this submenu will be dynamically built, we offer a dummy action
"""
pass
def add_source(self, obj):
"""
add_source: Add a new source (this is also available from the
source view)
Create a new Source instance and call the EditSource editor with the
new source.
Called when the Add_source button is clicked.
If the window already exists (Errors.WindowActiveError), we ignore it.
This prevents the dialog from coming up twice on the same object.
However, since the window is identified by the Source object, and
we have just created a new one, it seems to be impossible for the
window to already exist, so this is just an extra safety measure.
"""
try:
EditSource(self.dbstate, self.uistate, [], gen.lib.Source())
except Errors.WindowActiveError:
pass
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
citation to an existing source)
Create a new Source instance and Citation instance and call the
EditSource editor with the new source.
Called when the Add button is clicked.
If the window already exists (Errors.WindowActiveError), we ignore it.
This prevents the dialog from coming up twice on the same object.
However, since the window is identified by the Source object, and
we have just created a new one, it seems to be impossible for the
window to already exist, so this is just an extra safety measure.
"""
try:
EditCitation(self.dbstate, self.uistate, [], gen.lib.Citation(),
gen.lib.Source())
except Errors.WindowActiveError:
pass
def share(self, obj):
"""
share: Add a new citation to an existing source (when a source is
selected)
"""
for handle in self.selected_handles():
# The handle will either be a Source handle or a Citation handle
source = self.dbstate.db.get_source_from_handle(handle)
citation = self.dbstate.db.get_citation_from_handle(handle)
if (not source and not citation) or (source and citation):
raise ValueError("selection must be either source or citation")
if source:
try:
EditCitation(self.dbstate, self.uistate, [],
gen.lib.Citation(), source)
except Errors.WindowActiveError:
from QuestionDialog import WarningDialog
WarningDialog(_("Cannot share this reference"),
self.__blocked_text())
else:
msg = _("Cannot add citation.")
msg2 = _("In order to add a citation to an existing source, "
" you must select a source.")
ErrorDialog(msg, msg2)
#
def remove(self, obj):
self.remove_selected_objects()
def remove_object_from_handle(self, handle):
# The handle will either be a Source handle or a Citation handle
source = self.dbstate.db.get_source_from_handle(handle)
citation = self.dbstate.db.get_citation_from_handle(handle)
if (not source and not citation) or (source and citation):
raise ValueError("selection must be either source or citation")
if citation:
the_lists = Utils.get_citation_referents(handle, self.dbstate.db)
object = self.dbstate.db.get_citation_from_handle(handle)
query = DeleteCitationQuery(self.dbstate, self.uistate, object,
the_lists)
is_used = any(the_lists)
return (query, is_used, object)
else:
# FIXME: this is copied from SourceView, because import with
# from plugins.view.sourceview import SourceView doesn't
# seem to work!
the_lists = Utils.get_source_referents(handle, self.dbstate.db)
LOG.debug('source referents %s' % [the_lists])
citation_referents_list = []
for citation in the_lists[7]:
LOG.debug('citation %s' % citation)
refs = Utils.get_citation_referents(citation, self.dbstate.db)
citation_referents_list += [(citation, refs)]
LOG.debug('citation_referents_list %s' % [citation_referents_list])
(person_list, family_list, event_list, place_list, source_list,
media_list, repo_list, citation_list) = the_lists
the_lists = (person_list, family_list, event_list, place_list,
source_list, media_list, repo_list, citation_list,
citation_referents_list)
LOG.debug('the_lists %s' % [the_lists])
object = self.dbstate.db.get_source_from_handle(handle)
query = DeleteSrcQuery(self.dbstate, self.uistate, object,
the_lists)
is_used = any(the_lists)
return (query, is_used, object)
def edit(self, obj):
"""
Edit either a Source or a Citation, depending on user selection
"""
for handle in self.selected_handles():
# The handle will either be a Source handle or a Citation handle
source = self.dbstate.db.get_source_from_handle(handle)
citation = self.dbstate.db.get_citation_from_handle(handle)
if (not source and not citation) or (source and citation):
raise ValueError("selection must be either source or citation")
if citation:
LOG.debug("citation handle %s page %s" %
(handle, citation.page))
try:
EditCitation(self.dbstate, self.uistate, [], citation)
except Errors.WindowActiveError:
pass
else:
LOG.debug("source handle %s title %s " %
(source, source.title))
EditSource(self.dbstate, self.uistate, [], source)
def __blocked_text(self):
"""
Return the common text used when citation cannot be edited
"""
return _("This citation cannot be edited at this time. "
"Either the associated citation is already being "
"edited or another object that is associated with "
"the same citation is being edited.\n\nTo edit this "
"citation, you need to close the object.")
def merge(self, obj):
"""
Merge the selected citations.
"""
mlist = self.selected_handles()
if len(mlist) != 2:
msg = _("Cannot merge citations.")
msg2 = _("Exactly two citations must be selected to perform a "
"merge. A second citation can be selected by holding "
"down the control key while clicking on the desired "
"citation.")
ErrorDialog(msg, msg2)
else:
source1 = self.dbstate.db.get_source_from_handle(mlist[0])
citation1 = self.dbstate.db.get_citation_from_handle(mlist[0])
if (not source1 and not citation1) or (source1 and citation1):
raise ValueError("selection must be either source or citation")
source2 = self.dbstate.db.get_source_from_handle(mlist[1])
citation2 = self.dbstate.db.get_citation_from_handle(mlist[1])
if (not source2 and not citation2) or (source2 and citation2):
raise ValueError("selection must be either source or citation")
if citation1 and citation2:
if not citation1.get_reference_handle() == \
citation2.get_reference_handle():
msg = _("Cannot merge citations.")
msg2 = _("The two selected citations must have the same "
"source to perform a merge. If you want to merge "
"these two citations, then you must merge the "
"sources first.")
ErrorDialog(msg, msg2)
else:
import Merge
Merge.MergeCitations(self.dbstate, self.uistate,
mlist[0], mlist[1])
elif source1 and source2:
import Merge
Merge.MergeSources(self.dbstate, self.uistate,
mlist[0], mlist[1])
else:
msg = _("Cannot perform merge.")
msg2 = _("Both objects must be of the same type, either "
"both must be sources, or both must be "
"citations.")
ErrorDialog(msg, msg2)
def get_handle_from_gramps_id(self, gid):
obj = self.dbstate.db.get_citation_from_gramps_id(gid)
if obj:
return obj.get_handle()
else:
return None
def get_default_gramplets(self):
"""
Define the default gramplets for the sidebar and bottombar.
This is overridden for the tree view to give 'Source Filter'
"""
return (("Citation Filter",),
("Citation Gallery",
"Citation Notes",
"Citation Backlinks"))

View File

@ -69,7 +69,9 @@ CATEGORY_ICON = {
'Sources': 'gramps-source',
'Repositories': 'gramps-repository',
'Media': 'gramps-media',
'Notes': 'gramps-notes'}
'Notes': 'gramps-notes',
'Citations': 'gramps-citation',
}
#-------------------------------------------------------------------------
#

View File

@ -25,14 +25,37 @@
Citation List View
"""
#-------------------------------------------------------------------------
#
# python modules
#
#-------------------------------------------------------------------------
import logging
LOG = logging.getLogger(".citation")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from libcitationview import BaseCitationView
from gui.views.treemodels.citationlistmodel import CitationListModel
from gen.plug import CATEGORY_QR_SOURCE
import gen.lib
from gui.views.listview import ListView
import Utils
import Bookmarks
import Errors
from DdTargets import DdTargets
from QuestionDialog import ErrorDialog
from gui.editors import EditCitation, DeleteCitationQuery
from Filters.SideBar import CitationSidebarFilter
#-------------------------------------------------------------------------
#
@ -47,7 +70,7 @@ from gen.ggettext import gettext as _
# CitationView
#
#-------------------------------------------------------------------------
class CitationListView(BaseCitationView):
class CitationListView(ListView):
"""
A list view of citations.
@ -69,7 +92,7 @@ class CitationListView(BaseCitationView):
COL_SRC_CHAN = 10
# name of the columns
COLUMN_NAMES = [
_('Title/Page'),
_('Volume/Page'),
_('ID'),
_('Date'),
_('Confidence'),
@ -93,8 +116,6 @@ class CitationListView(BaseCitationView):
ADD_MSG = _("Add a new citation and a new source")
ADD_SOURCE_MSG = _("Add a new source")
ADD_CITATION_MSG = _("Add a new citation to an existing source")
# Edit delete and merge messages are overridden for the tree view as
# they can apply to sources or citations
EDIT_MSG = _("Edit the selected citation")
DEL_MSG = _("Delete the selected citation")
MERGE_MSG = _("Merge the selected citations")
@ -110,8 +131,225 @@ class CitationListView(BaseCitationView):
'citation-rebuild' : self.object_build,
}
BaseCitationView.__init__(self, pdata, dbstate, uistate,
_('Citation View'), CitationListModel,
signal_map,
nav_group=nav_group)
ListView.__init__(
self, _('Citation View'), pdata, dbstate, uistate,
self.COLUMN_NAMES, len(self.COLUMN_NAMES),
CitationListModel, signal_map,
dbstate.db.get_citation_bookmarks(),
Bookmarks.CitationBookmarks, nav_group,
multiple=True,
filter_class=CitationSidebarFilter)
self.func_list.update({
'<CONTROL>J' : self.jump,
'<CONTROL>BackSpace' : self.key_delete,
})
self.additional_uis.append(self.additional_ui())
def navigation_type(self):
return 'Citation'
def get_bookmarks(self):
return self.dbstate.db.get_citation_bookmarks()
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(self.title + "/CitationAll")
self.edit_action = gtk.ActionGroup(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('Dummy', None, ' ', None, None, self.dummy_report)
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 '''<ui>
<menubar name="MenuBar">
<menu action="FileMenu">
<placeholder name="LocalExport">
<menuitem action="ExportTab"/>
</placeholder>
</menu>
<menu action="BookMenu">
<placeholder name="AddEditBook">
<menuitem action="AddBook"/>
<menuitem action="EditBook"/>
</placeholder>
</menu>
<menu action="GoMenu">
<placeholder name="CommonGo">
<menuitem action="Back"/>
<menuitem action="Forward"/>
<separator/>
</placeholder>
</menu>
<menu action="EditMenu">
<placeholder name="CommonEdit">
<menuitem action="Add"/>
<menuitem action="Edit"/>
<menuitem action="Remove"/>
<menuitem action="Merge"/>
</placeholder>
<menuitem action="FilterEdit"/>
</menu>
</menubar>
<toolbar name="ToolBar">
<placeholder name="CommonNavigation">
<toolitem action="Back"/>
<toolitem action="Forward"/>
</placeholder>
<placeholder name="CommonEdit">
<toolitem action="Add"/>
<toolitem action="Edit"/>
<toolitem action="Remove"/>
<toolitem action="Merge"/>
</placeholder>
</toolbar>
<popup name="Popup">
<menuitem action="Back"/>
<menuitem action="Forward"/>
<separator/>
<menuitem action="Add"/>
<menuitem action="Edit"/>
<menuitem action="Remove"/>
<menuitem action="Merge"/>
<separator/>
<menu name="QuickReport" action="QuickReport">
<menuitem action="Dummy"/>
</menu>
</popup>
</ui>'''
def dummy_report(self, obj):
""" For the xml UI definition of popup to work, the submenu
Quick Report must have an entry in the xml
As this submenu will be dynamically built, we offer a dummy action
"""
pass
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
citation to an existing source)
Create a new Source instance and Citation instance and call the
EditCitation editor with the new source and new citation.
Called when the Add button is clicked.
If the window already exists (Errors.WindowActiveError), we ignore it.
This prevents the dialog from coming up twice on the same object.
However, since the window is identified by the Source object, and
we have just created a new one, it seems to be impossible for the
window to already exist, so this is just an extra safety measure.
"""
try:
EditCitation(self.dbstate, self.uistate, [], gen.lib.Citation(),
gen.lib.Source())
except Errors.WindowActiveError:
pass
def remove(self, obj):
self.remove_selected_objects()
def remove_object_from_handle(self, handle):
the_lists = Utils.get_citation_referents(handle, self.dbstate.db)
object = self.dbstate.db.get_citation_from_handle(handle)
query = DeleteCitationQuery(self.dbstate, self.uistate, object,
the_lists)
is_used = any(the_lists)
return (query, is_used, object)
def edit(self, obj):
"""
Edit a Citation
"""
for handle in self.selected_handles():
citation = self.dbstate.db.get_citation_from_handle(handle)
try:
EditCitation(self.dbstate, self.uistate, [], citation)
except Errors.WindowActiveError:
pass
def __blocked_text(self):
"""
Return the common text used when citation cannot be edited
"""
return _("This citation cannot be edited at this time. "
"Either the associated citation is already being "
"edited or another object that is associated with "
"the same citation is being edited.\n\nTo edit this "
"citation, you need to close the object.")
def merge(self, obj):
"""
Merge the selected citations.
"""
mlist = self.selected_handles()
if len(mlist) != 2:
msg = _("Cannot merge citations.")
msg2 = _("Exactly two citations must be selected to perform a "
"merge. A second citation can be selected by holding "
"down the control key while clicking on the desired "
"citation.")
ErrorDialog(msg, msg2)
else:
citation1 = self.dbstate.db.get_citation_from_handle(mlist[0])
citation2 = self.dbstate.db.get_citation_from_handle(mlist[1])
if not citation1.get_reference_handle() == \
citation2.get_reference_handle():
msg = _("Cannot merge citations.")
msg2 = _("The two selected citations must have the same "
"source to perform a merge. If you want to merge "
"these two citations, then you must merge the "
"sources first.")
ErrorDialog(msg, msg2)
else:
import Merge
Merge.MergeCitations(self.dbstate, self.uistate,
mlist[0], mlist[1])
def get_handle_from_gramps_id(self, gid):
obj = self.dbstate.db.get_citation_from_gramps_id(gid)
if obj:
return obj.get_handle()
else:
return None
def get_default_gramplets(self):
"""
Define the default gramplets for the sidebar and bottombar.
This is overridden for the tree view to give 'Source Filter'
"""
return (("Citation Filter",),
("Citation Gallery",
"Citation Notes",
"Citation Backlinks"))

View File

@ -21,7 +21,8 @@
# $Id$
"""
Citation Tree View
Citation Tree View (or Source tree view).
A view showing all the Sources with child Citations
"""
#-------------------------------------------------------------------------
#
@ -31,15 +32,31 @@ Citation Tree View
import logging
LOG = logging.getLogger(".citation")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from gui.views.listview import LISTTREE
from libcitationview import BaseCitationView
from gui.views.treemodels.citationtreemodel import CitationTreeModel
from gen.plug import CATEGORY_QR_SOURCE
import gen.lib
from gui.views.listview import ListView
import Utils
import Bookmarks
import Errors
from DdTargets import DdTargets
from QuestionDialog import ErrorDialog
from gui.editors import EditCitation, DeleteCitationQuery, EditSource, \
DeleteSrcQuery
from Filters.SideBar import SourceSidebarFilter
#-------------------------------------------------------------------------
#
@ -53,9 +70,9 @@ from gen.ggettext import gettext as _
# PlaceTreeView
#
#-------------------------------------------------------------------------
class CitationTreeView(BaseCitationView):
class CitationTreeView(ListView):
"""
A hierarchical view of the top three levels of places.
A hierarchical view of sources with citations below them.
"""
# The data items here have to correspond, in order, to the items in
# src/giu.views/treemodels/citationtreemodel.py
@ -69,7 +86,7 @@ class CitationTreeView(BaseCitationView):
COL_SRC_PINFO = 7
# name of the columns
COLUMN_NAMES = [
_('Title/Page'),
_('Title or Page'),
_('ID'),
_('Date'),
_('Confidence'),
@ -80,12 +97,12 @@ class CitationTreeView(BaseCitationView):
]
# default setting with visible columns, order of the col, and their size
CONFIGSETTINGS = (
('columns.visible', [COL_TITLE_PAGE, COL_ID, COL_DATE,
COL_CONFIDENCE]),
('columns.visible', [COL_TITLE_PAGE, COL_ID, COL_SRC_AUTH,
COL_SRC_PINFO]),
('columns.rank', [COL_TITLE_PAGE, COL_ID, COL_DATE, COL_CONFIDENCE,
COL_CHAN, COL_SRC_AUTH,
COL_SRC_ABBR, COL_SRC_PINFO]),
('columns.size', [200, 75, 100, 100, 100, 75, 100, 150])
('columns.size', [200, 75, 100, 75, 100, 150, 100, 150])
)
ADD_MSG = _("Add a new citation and a new source")
ADD_SOURCE_MSG = _("Add a new source")
@ -109,17 +126,40 @@ class CitationTreeView(BaseCitationView):
'source-rebuild' : self.object_build,
}
BaseCitationView.__init__(self, pdata, dbstate, uistate,
_('Citation Tree View'), CitationTreeModel,
signal_map,
nav_group=nav_group)
ListView.__init__(
self, _('Citation Tree View'), pdata, dbstate, uistate,
self.COLUMN_NAMES, len(self.COLUMN_NAMES),
CitationTreeModel, signal_map,
dbstate.db.get_citation_bookmarks(),
Bookmarks.CitationBookmarks, nav_group,
multiple=True,
filter_class=SourceSidebarFilter)
self.func_list.update({
'<CONTROL>J' : self.jump,
'<CONTROL>BackSpace' : self.key_delete,
})
self.additional_uis.append(self.additional_ui())
def navigation_type(self):
return 'Citation'
def get_bookmarks(self):
return self.dbstate.db.get_citation_bookmarks()
def drag_info(self):
return DdTargets.SOURCE_LINK
def type_list(self):
"""
set the listtype, this governs eg keybinding
"""
return LISTTREE
def get_stock(self):
return 'gramps-citation'
def get_viewtype_stock(self):
"""
Override the default icon. Set for hierarchical view.
@ -128,9 +168,43 @@ class CitationTreeView(BaseCitationView):
def define_actions(self):
"""
Define actions for the popup menu specific to the tree view.
This defines the possible actions for the citation views.
Possible actions are:
add_source: Add a new source (this is also available from the
source view)
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)
share: Add a new citation to an existing source (when a source is
selected)
edit: Edit a source or a citation.
merge: Merge the selected sources or citations.
remove: Delete the selected sources or citations.
"""
BaseCitationView.define_actions(self)
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.all_action = gtk.ActionGroup(self.title + "/CitationAll")
self.edit_action = gtk.ActionGroup(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('Dummy', None, ' ', None, None, self.dummy_report)
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,
@ -206,3 +280,228 @@ class CitationTreeView(BaseCitationView):
</popup>
</ui>'''
def dummy_report(self, obj):
""" For the xml UI definition of popup to work, the submenu
Quick Report must have an entry in the xml
As this submenu will be dynamically built, we offer a dummy action
"""
pass
def add_source(self, obj):
"""
add_source: Add a new source (this is also available from the
source view)
Create a new Source instance and call the EditSource editor with the
new source.
Called when the Add_source button is clicked.
If the window already exists (Errors.WindowActiveError), we ignore it.
This prevents the dialog from coming up twice on the same object.
However, since the window is identified by the Source object, and
we have just created a new one, it seems to be impossible for the
window to already exist, so this is just an extra safety measure.
"""
try:
EditSource(self.dbstate, self.uistate, [], gen.lib.Source())
except Errors.WindowActiveError:
pass
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
citation to an existing source)
Create a new Source instance and Citation instance and call the
EditSource editor with the new source.
Called when the Add button is clicked.
If the window already exists (Errors.WindowActiveError), we ignore it.
This prevents the dialog from coming up twice on the same object.
However, since the window is identified by the Source object, and
we have just created a new one, it seems to be impossible for the
window to already exist, so this is just an extra safety measure.
"""
try:
EditCitation(self.dbstate, self.uistate, [], gen.lib.Citation(),
gen.lib.Source())
except Errors.WindowActiveError:
pass
def share(self, obj):
"""
share: Add a new citation to an existing source (when a source is
selected)
"""
for handle in self.selected_handles():
# The handle will either be a Source handle or a Citation handle
source = self.dbstate.db.get_source_from_handle(handle)
citation = self.dbstate.db.get_citation_from_handle(handle)
if (not source and not citation) or (source and citation):
raise ValueError("selection must be either source or citation")
if source:
try:
EditCitation(self.dbstate, self.uistate, [],
gen.lib.Citation(), source)
except Errors.WindowActiveError:
from QuestionDialog import WarningDialog
WarningDialog(_("Cannot share this reference"),
self.__blocked_text())
else:
msg = _("Cannot add citation.")
msg2 = _("In order to add a citation to an existing source, "
" you must select a source.")
ErrorDialog(msg, msg2)
#
def remove(self, obj):
self.remove_selected_objects()
def remove_object_from_handle(self, handle):
# The handle will either be a Source handle or a Citation handle
source = self.dbstate.db.get_source_from_handle(handle)
citation = self.dbstate.db.get_citation_from_handle(handle)
if (not source and not citation) or (source and citation):
raise ValueError("selection must be either source or citation")
if citation:
the_lists = Utils.get_citation_referents(handle, self.dbstate.db)
object = self.dbstate.db.get_citation_from_handle(handle)
query = DeleteCitationQuery(self.dbstate, self.uistate, object,
the_lists)
is_used = any(the_lists)
return (query, is_used, object)
else:
# FIXME: this is copied from SourceView, because import with
# from plugins.view.sourceview import SourceView
# doesn't seem to work!
the_lists = Utils.get_source_referents(handle, self.dbstate.db)
LOG.debug('source referents %s' % [the_lists])
citation_referents_list = []
for citation in the_lists[7]:
LOG.debug('citation %s' % citation)
refs = Utils.get_citation_referents(citation, self.dbstate.db)
citation_referents_list += [(citation, refs)]
LOG.debug('citation_referents_list %s' % [citation_referents_list])
(person_list, family_list, event_list, place_list, source_list,
media_list, repo_list, citation_list) = the_lists
the_lists = (person_list, family_list, event_list, place_list,
source_list, media_list, repo_list, citation_list,
citation_referents_list)
LOG.debug('the_lists %s' % [the_lists])
object = self.dbstate.db.get_source_from_handle(handle)
query = DeleteSrcQuery(self.dbstate, self.uistate, object,
the_lists)
is_used = any(the_lists)
return (query, is_used, object)
def edit(self, obj):
"""
Edit either a Source or a Citation, depending on user selection
"""
for handle in self.selected_handles():
# The handle will either be a Source handle or a Citation handle
source = self.dbstate.db.get_source_from_handle(handle)
citation = self.dbstate.db.get_citation_from_handle(handle)
if (not source and not citation) or (source and citation):
raise ValueError("selection must be either source or citation")
if citation:
try:
EditCitation(self.dbstate, self.uistate, [], citation)
except Errors.WindowActiveError:
pass
else: # FIXME need try block here
try:
EditSource(self.dbstate, self.uistate, [], source)
except Errors.WindowActiveError:
from QuestionDialog import WarningDialog
WarningDialog(_("Cannot share this reference"),
self.__blocked_text2())
def __blocked_text(self):
"""
Return the common text used when citation cannot be edited
"""
return _("This citation cannot be created at this time. "
"Either the associated Source object is already being "
"edited, or another citation associated with the same "
"source is being edited.\n\nTo edit this "
"citation, you need to close the object.")
def __blocked_text2(self):
"""
Return the common text used when citation cannot be edited
"""
return _("This source cannot be edited at this time. "
"Either the associated Source object is already being "
"edited, or another citation associated with the same "
"source is being edited.\n\nTo edit this "
"source, you need to close the object.")
def merge(self, obj):
"""
Merge the selected citations.
"""
mlist = self.selected_handles()
if len(mlist) != 2:
msg = _("Cannot merge citations.")
msg2 = _("Exactly two citations must be selected to perform a "
"merge. A second citation can be selected by holding "
"down the control key while clicking on the desired "
"citation.")
ErrorDialog(msg, msg2)
else:
source1 = self.dbstate.db.get_source_from_handle(mlist[0])
citation1 = self.dbstate.db.get_citation_from_handle(mlist[0])
if (not source1 and not citation1) or (source1 and citation1):
raise ValueError("selection must be either source or citation")
source2 = self.dbstate.db.get_source_from_handle(mlist[1])
citation2 = self.dbstate.db.get_citation_from_handle(mlist[1])
if (not source2 and not citation2) or (source2 and citation2):
raise ValueError("selection must be either source or citation")
if citation1 and citation2:
if not citation1.get_reference_handle() == \
citation2.get_reference_handle():
msg = _("Cannot merge citations.")
msg2 = _("The two selected citations must have the same "
"source to perform a merge. If you want to merge "
"these two citations, then you must merge the "
"sources first.")
ErrorDialog(msg, msg2)
else:
import Merge
Merge.MergeCitations(self.dbstate, self.uistate,
mlist[0], mlist[1])
elif source1 and source2:
import Merge
Merge.MergeSources(self.dbstate, self.uistate,
mlist[0], mlist[1])
else:
msg = _("Cannot perform merge.")
msg2 = _("Both objects must be of the same type, either "
"both must be sources, or both must be "
"citations.")
ErrorDialog(msg, msg2)
def get_handle_from_gramps_id(self, gid):
obj = self.dbstate.db.get_citation_from_gramps_id(gid)
if obj:
return obj.get_handle()
else:
return None
def get_default_gramplets(self):
"""
Define the default gramplets for the sidebar and bottombar.
"""
return (("Source Filter",),
("Citation Gallery",
"Citation Notes",
"Citation Backlinks"))

View File

@ -197,20 +197,21 @@ viewclass = 'RepositoryView',
order = START,
)
register(VIEW,
id = 'sourceview',
name = _("Source View"),
description = _("The view showing all the sources"),
version = '1.0',
gramps_target_version = '3.4',
status = STABLE,
fname = 'sourceview.py',
authors = [u"The Gramps project"],
authors_email = ["http://gramps-project.org"],
category = ("Sources", _("Sources")),
viewclass = 'SourceView',
order = START,
)
# FIXME: REDUNDANT As of gramps 3.4, sourceview.py is redundant.
#register(VIEW,
#id = 'sourceview',
#name = _("Source View"),
#description = _("The view showing all the sources"),
#version = '1.0',
#gramps_target_version = '3.4',
#status = STABLE,
#fname = 'sourceview.py',
#authors = [u"The Gramps project"],
#authors_email = ["http://gramps-project.org"],
#category = ("Sources", _("Sources")),
#viewclass = 'SourceView',
#order = START,
# )
register(VIEW,
id = 'citationlistview',
@ -237,8 +238,7 @@ status = STABLE,
fname = 'citationtreeview.py',
authors = [u"Tim G L Lyons", u"Nick Hall"],
authors_email = [""],
category = ("Citations", _("Citations")),
category = ("Sources", _("Sources")),
viewclass = 'CitationTreeView',
stock_icon = 'gramps-tree-group',
order = START,
)