#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007  Donald N. Allingham
# Copyright (C) 2011       Tim G L Lyons
#
# 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: citationembedlist.py 18696 2012-01-03 21:00:13Z m_d_n $
 
#-------------------------------------------------------------------------
#
# Python classes
#
#-------------------------------------------------------------------------
from gen.ggettext import gettext as _
import logging
LOG = logging.getLogger(".citation")
 
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gobject
 
#-------------------------------------------------------------------------
#
# GRAMPS classes
#
#-------------------------------------------------------------------------
import Errors
import gen.lib
from gen.lib import Source, Citation
from gui.dbguielement import DbGUIElement
from gui.selectors import SelectorFactory
from citationrefmodel import CitationRefModel
from embeddedlist import EmbeddedList
from DdTargets import DdTargets
 
#-------------------------------------------------------------------------
#
# CitationEmbedList
#
#-------------------------------------------------------------------------
class CitationEmbedList(EmbeddedList, DbGUIElement):
    """
    Citation List display tab for edit dialogs. 
 
    Derives from the EmbeddedList class.
    """
 
    _HANDLE_COL = 4  # Column number from CitationRefModel
    _DND_TYPE = DdTargets.CITATION_LINK
    _DND_EXTRA = DdTargets.SOURCE_LINK
 
    _MSG = {
        'add'   : _('Create and add a new citation and new source'),
        'del'   : _('Remove the existing citation'),
        'edit'  : _('Edit the selected citation'),
        'share' : _('Add an existing citation or source'),
        'up'    : _('Move the selected citation upwards'),
        'down'  : _('Move the selected citation downwards'),
    }
 
    #index = column in model. Value =
    #  (name, sortcol in model, width, markup/text, weigth_col
    _column_names = [
        (_('Title'),  0, 200, 0, -1), 
        (_('Author'), 1, 125, 0, -1), 
        (_('Page'),   2, 100, 0, -1), 
        (_('ID'),     3, 75, 0, -1), 
    ]
 
    def __init__(self, dbstate, uistate, track, data, callertitle=None):
        self.data = data
        self.callertitle = callertitle
        EmbeddedList.__init__(self, dbstate, uistate, track, 
                              _("_Source Citations"), CitationRefModel, 
                              share_button=True, move_buttons=True)
        DbGUIElement.__init__(self, dbstate.db)
        self.callman.register_handles({'citation': self.data})
 
    def _connect_db_signals(self):
        """
        Implement base class DbGUIElement method
        """
        #citation: citation-rebuild closes the editors, so no need to connect 
        # to it
        self.callman.register_callbacks(
           {'citation-delete': self.citation_delete,
            'citation-update': self.citation_update,
           })
        self.callman.connect_all(keys=['citation'])
 
    def get_icon_name(self):
        """
        Return the stock-id icon name associated with the display tab
        """
        return 'gramps-source'
 
    def get_data(self):
        """
        Return the data associated with display tab
        """
        return self.data
 
    def column_order(self):
        """
        Return the column order of the columns in the display tab.
        """
        return ((1, 0), (1, 1), (1, 2), (1, 3))
 
    def add_button_clicked(self, obj):
        """
        Create a new Citation instance and call the EditCitation editor with 
        the 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.
        """
        try:
            from gui.editors import EditCitation
            EditCitation(self.dbstate, self.uistate, self.track,
                         gen.lib.Citation(), gen.lib.Source(),
                         self.add_callback, self.callertitle)
        except Errors.WindowActiveError:
            pass
 
    def add_callback(self, value):
        """
        Called to update the screen when a new citation is added
        """
        data = self.get_data()
        data.append(value)
        self.callman.register_handles({'citation': [value]})
        self.changed = True
        self.rebuild()
        gobject.idle_add(self.tree.scroll_to_cell, len(data) - 1)
 
    def share_button_clicked(self, obj):
        SelectCitation = SelectorFactory('Citation')
 
        sel = SelectCitation(self.dbstate, self.uistate, self.track)
        object = sel.run()
        LOG.debug("selected object: %s" % object)
        # the object returned should either be a Source or a Citation
        if object:
            if isinstance(object, Source):
                try:
                    from gui.editors import EditCitation
                    EditCitation(self.dbstate, self.uistate, self.track, 
                                 gen.lib.Citation(), object, 
                                 callback=self.add_callback, 
                                 callertitle=self.callertitle)
                except Errors.WindowActiveError:
                    from QuestionDialog import WarningDialog
                    WarningDialog(_("Cannot share this reference"),
                                  self.__blocked_text())
            elif isinstance(object, Citation):
                try:
                    from gui.editors import EditCitation
                    EditCitation(self.dbstate, self.uistate, self.track, 
                                 object, callback=self.add_callback, 
                                 callertitle=self.callertitle)
                except Errors.WindowActiveError:
                    from QuestionDialog import WarningDialog
                    WarningDialog(_("Cannot share this reference"),
                                  self.__blocked_text())
            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 
        with the citation. 
 
        Called when the Edit 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.
        """
        handle = self.get_selected()
        if handle:
            citation = self.dbstate.db.get_citation_from_handle(handle)
            try:
                from gui.editors import EditCitation
                EditCitation(self.dbstate, self.uistate, self.track, citation,
                             callertitle = self.callertitle)
            except Errors.WindowActiveError:
                pass
 
    def citation_delete(self, del_citation_handle_list):
        """
        Outside of this tab citation objects have been deleted. Check if tab
        and object must be changed.
        Note: delete of object will cause reference on database to be removed,
            so this method need not do this
        """
        rebuild = False
        for handle in del_citation_handle_list :
            while self.data.count(handle) > 0:
                self.data.remove(handle)
                rebuild = True
        if rebuild:
            self.rebuild()
 
    def citation_update(self, upd_citation_handle_list):
        """
        Outside of this tab citation objects have been updated. Check if tab
        and object must be updated.
        """
        for handle in upd_citation_handle_list :
            if handle in self.data:
                self.rebuild()
                break
 
    def _handle_drag(self, row, handle):
        """
        A CITATION_LINK has been dragged
        """
        if handle:
            object = self.dbstate.db.get_citation_from_handle(handle)
            if isinstance(object, Citation):
                try:
                    from gui.editors import EditCitation
                    EditCitation(self.dbstate, self.uistate, self.track, 
                                 object, callback=self.add_callback, 
                                 callertitle=self.callertitle)
                except Errors.WindowActiveError:
                    from QuestionDialog import WarningDialog
                    WarningDialog(_("Cannot share this reference"),
                                  self.__blocked_text())
            else:
                raise ValueError("selection must be either source or citation")
 
    def handle_extra_type(self, objtype, handle):
        """
        A SOURCE_LINK object has been dragged
        """
        if handle:
            object = self.dbstate.db.get_source_from_handle(handle)
            if isinstance(object, Source):
                try:
                    from gui.editors import EditCitation
                    EditCitation(self.dbstate, self.uistate, self.track, 
                                 gen.lib.Citation(), object, 
                                 callback=self.add_callback, 
                                 callertitle=self.callertitle)
                except Errors.WindowActiveError:
                    from QuestionDialog import WarningDialog
                    WarningDialog(_("Cannot share this reference"),
                                  self.__blocked_text())
            else:
                raise ValueError("selection must be either source or citation")