#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2004  Donald N. Allingham
#
# 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$

#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import os
import string
import urlparse
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
import gnome
import gnome.ui
import gnome.canvas
import gtk.glade

#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import const
import Utils
import GrampsCfg
import Plugins
import RelLib
import RelImage
import ListModel
import SelectObject
import GrampsMime
import Sources

from QuestionDialog import ErrorDialog
from gettext import gettext as _

_IMAGEX = 140
_IMAGEY = 150
_PAD = 5

_last_path = ""
_iconlist_refs = []

#-------------------------------------------------------------------------
#
# ImageSelect class
#
#-------------------------------------------------------------------------
class ImageSelect:

    def __init__(self, path, db, parent, parent_window=None):
        """Creates an edit window.  Associates a person with the window."""
        self.path        = path;
        self.db          = db
        self.dataobj     = None
        self.parent      = parent
        self.parent_window = parent_window
        self.canvas_list = {}
        self.p_map       = {}
        self.canvas      = None
        
    def add_thumbnail(self, photo):
        "should be overrridden"
        pass

    def load_images(self):
        "should be overrridden"
        pass

    def create_add_dialog(self):
        """Create the gnome dialog for selecting a new photo and entering
        its description.""" 

        if self.path == '':
            return
            
        self.glade       = gtk.glade.XML(const.imageselFile,"imageSelect","gramps")
        self.window      = self.glade.get_widget("imageSelect")

        self.fname       = self.glade.get_widget("fname")
        self.image       = self.glade.get_widget("image")
        self.description = self.glade.get_widget("photoDescription")
        self.temp_name   = ""

        Utils.set_titles(self.window,self.glade.get_widget('title'),
                         _('Select a media object'))
        
        self.glade.signal_autoconnect({
            "on_fname_update_preview" : self.on_name_changed,
            "on_help_imagesel_clicked" : self.on_help_imagesel_clicked,
            })

        if os.path.isdir(_last_path):
            self.fname.set_current_folder(_last_path)

        if self.parent_window:
            self.window.set_transient_for(self.parent_window)
        self.window.show()
        self.val = self.window.run()
        if self.val == gtk.RESPONSE_OK:
            self.on_savephoto_clicked()
        self.window.destroy()

    def on_help_imagesel_clicked(self,obj):
        """Display the relevant portion of GRAMPS manual"""
        gnome.help_display('gramps-manual','gramps-edit-quick')
        self.val = self.window.run()

    def on_name_changed(self, obj):
        """The filename has changed.  Verify it and load the picture."""
        filename = unicode(self.fname.get_filename())

        basename = os.path.basename(filename)
        (root,ext) = os.path.splitext(basename)
        old_title  = unicode(self.description.get_text())

        if old_title == "" or old_title == self.temp_name:
            self.description.set_text(root)
        self.temp_name = root
        
        if os.path.isfile(filename):
            type = GrampsMime.get_type(filename)
            if type[0:5] == "image":
                image = RelImage.scale_image(filename,const.thumbScale)
                self.image.set_from_pixbuf(image)
            else:
                i = gtk.gdk.pixbuf_new_from_file(Utils.find_icon(type))
                self.image.set_from_pixbuf(i)

    def on_savephoto_clicked(self):
        """Save the photo in the dataobj object.  (Required function)"""
        global _last_path
        
        filename = self.fname.get_filename()
        _last_path = os.path.dirname(filename)
        
        description = unicode(self.description.get_text())

        if os.path.exists(filename) == 0:
            msgstr = _("Cannot import %s")
            msgstr2 = _("The filename supplied could not be found.")
            ErrorDialog(msgstr % filename, msgstr2)
            return

        already_imported = None

        trans = self.db.start_transaction()
        for o_id in self.db.get_object_keys():
            o = self.db.try_to_find_object_from_handle(o_id)
            if o.get_path() == filename:
                already_imported = o
                break

        # fix referenes here
        # dna
        
        if (already_imported):
            oref = RelLib.MediaRef()
            oref.set_reference_handle(already_imported.get_handle())
            self.dataobj.add_media_reference(oref)
            self.add_thumbnail(oref)
        else:
            type = GrampsMime.get_type(filename)
            mobj = RelLib.MediaObject()
            if description == "":
                description = os.path.basename(filename)
            mobj.set_description(description)
            mobj.set_mime_type(type)
            self.savephoto(mobj)
            mobj.set_path(filename)
            self.db.commit_media_object(mobj,trans)

        self.db.add_transaction(trans,'Edit Media Objects')
            
        self.parent.lists_changed = 1
        self.load_images()

    def savephoto(self, photo):
        """Save the photo in the dataobj object - must be overridden"""
    	pass

_drag_targets = [
    ('STRING', 0, 0),
    ('text/plain',0,0),
    ('text/uri-list',0,2),
    ('application/x-rootwin-drop',0,1)]

#-------------------------------------------------------------------------
#
# Gallery class - This class handles all the logic underlying a
# picture gallery.  This class does not load or contain the widget
# data structure to actually display the gallery.
#
#-------------------------------------------------------------------------
class Gallery(ImageSelect):
    def __init__(self, dataobj, commit, path, icon_list, db, parent, parent_window=None):
        ImageSelect.__init__(self, path, db, parent, parent_window)

        self.commit = commit
        if path:
            icon_list.drag_dest_set(gtk.DEST_DEFAULT_ALL, _drag_targets,
                                    gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
            icon_list.connect('event',self.item_event)
            icon_list.connect("drag_data_received",
                              self.on_photolist_drag_data_received)
            icon_list.connect("drag_data_get",
                              self.on_photolist_drag_data_get)
            icon_list.connect("drag_begin", self.on_drag_begin)

        _iconlist_refs.append(icon_list)
        self.in_event = 0
	
        # Remember arguments
        self.path      = path;
        self.dataobj   = dataobj;
        self.iconlist = icon_list;
        self.root = self.iconlist.root()
        self.old_media_list = [RelLib.MediaRef(ref) for ref in self.dataobj.get_media_list()]
        
        # Local object variables
        self.y = 0
        self.remember_x = -1
        self.remember_y = -1
        self.button = None
        self.drag_item = None
        self.sel = None
        self.photo = None

    def close(self,ok=0):
        self.iconlist.hide()
        if self.canvas_list:
            for a in self.canvas_list.values():
                a[0].destroy()
                a[1].destroy()
                a[2].destroy()
        self.p_map = None
        self.canvas_list = None
        # restore old photo list, in case we removed some and then 
        # hit cancel button or closed the window
        if not ok:
            if self.old_media_list is not None:
                self.dataobj.set_media_list(self.old_media_list)
                trans = self.db.start_transaction()
                self.commit(self.dataobj,trans)
                self.db.add_transaction(trans,_("Edit Media Object"))
        
    def on_canvas1_event(self,obj,event):
        """
        Handle resize events over the canvas, redrawing if the size changes
        """
        pass

    def on_drag_begin(self,obj,context):
        if const.dnd_images:
            id = self.sel_obj.get_reference_handle()
            obj = self.db.try_to_find_object_from_handle(id)
            mtype = obj.get_mime_type()
            name = Utils.thumb_path(self.db.get_save_path(),obj)
            pix = gtk.gdk.pixbuf_new_from_file(name)
            context.set_icon_pixbuf(pix,0,0)

    def item_event(self, widget, event=None):

        if self.in_event:
            return
        self.in_event = 1
        if self.button and event.type == gtk.gdk.MOTION_NOTIFY :
            if widget.drag_check_threshold(int(self.remember_x),int(self.remember_y),
                                           int(event.x),int(event.y)):
                self.drag_item = widget.get_item_at(self.remember_x,
                                                    self.remember_y)
                icon_index = self.get_index(widget,event.x,event.y)-1
                self.sel_obj = self.dataobj.get_media_list()[icon_index]
                if self.drag_item:
                    widget.drag_begin(_drag_targets,
                                      gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE,
                                      self.button, event)
                    
            self.in_event = 0
            return gtk.TRUE

        style = self.iconlist.get_style()
        
        if event.type == gtk.gdk.BUTTON_PRESS:
            if event.button == 1:
                # Remember starting position.

                item = widget.get_item_at(event.x,event.y)
                if item:
                    (i,t,b,self.photo,oid) = self.p_map[item]
                    t.set(fill_color_gdk=style.fg[gtk.STATE_SELECTED])
                    b.set(fill_color_gdk=style.bg[gtk.STATE_SELECTED])
                    if self.sel:
                        (i,t,b,photo,oid) = self.p_map[self.sel]
                        t.set(fill_color_gdk=style.fg[gtk.STATE_NORMAL])
                        b.set(fill_color_gdk=style.bg[gtk.STATE_NORMAL])
                        
                    self.sel = item

                self.remember_x = event.x
                self.remember_y = event.y
                self.button = event.button
                self.in_event = 0
                return gtk.TRUE

            elif event.button == 3:
                item = widget.get_item_at(event.x,event.y)
                if item:
                    (i,t,b,self.photo,oid) = self.p_map[item]
                    self.show_popup(self.photo,event)
                self.in_event = 0
                return gtk.TRUE
        elif event.type == gtk.gdk.BUTTON_RELEASE:
            self.button = 0
#         elif event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
#             item = widget.get_item_at(event.x,event.y)
#             if item:
#                 (i,t,b,self.photo,oid) = self.p_map[item]
#                 LocalMediaProperties(self.photo,self.path,self,self.parent_window)
#             self.in_event = 0
#             return gtk.TRUE
        elif event.type == gtk.gdk.MOTION_NOTIFY:
            if event.state & gtk.gdk.BUTTON1_MASK:
                # Get the new position and move by the difference
                new_x = event.x
                new_y = event.y

                self.remember_x = new_x
                self.remember_y = new_y

                self.in_event = 0
                return gtk.TRUE
            
        if event.type == gtk.gdk.EXPOSE:
            self.load_images()

        self.in_event = 0
        return gtk.FALSE

    def savephoto(self, photo):
        """Save the photo in the dataobj object.  (Required function)"""
        self.db.add_object(photo,None)
        oref = RelLib.MediaRef()
        oref.set_reference_handle(photo.get_handle())
        self.dataobj.add_media_reference(oref)

    def add_thumbnail(self, photo):
        """Scale the image and add it to the IconList."""
        oid = photo.get_reference_handle()
        object = self.db.try_to_find_object_from_handle(oid)
        if self.canvas_list.has_key(oid):
            (grp,item,text,x,y) = self.canvas_list[oid]
            if x != self.cx or y != self.cy:
                grp.move(self.cx-x,self.cy-y)
        else:
            import gobject
            
            name = Utils.thumb_path(self.db.get_save_path(),object)

            description = object.get_description()
            if len(description) > 20:
                description = "%s..." % description[0:20]

            try:
                image = gtk.gdk.pixbuf_new_from_file(name)
            except gobject.GError,msg:
                ErrorDialog(str(msg))
                image = gtk.gdk.pixbuf_new_from_file(const.icon)
            except:
                ErrorDialog(_("Thumbnail %s could not be found") % name)
                image = gtk.gdk.pixbuf_new_from_file(const.icon)
            
            x = image.get_width()
            y = image.get_height()

            grp = self.root.add(gnome.canvas.CanvasGroup,x=self.cx,y=self.cy)

            xloc = (_IMAGEX-x)/2
            yloc = (_IMAGEY-y)/2

            style = self.iconlist.get_style()

            box = grp.add(gnome.canvas.CanvasRect,x1=0,x2=_IMAGEX,y1=_IMAGEY-20,
                          y2=_IMAGEY, fill_color_gdk=style.bg[gtk.STATE_NORMAL])
            item = grp.add(gnome.canvas.CanvasPixbuf,
                           pixbuf=image,x=xloc, y=yloc)
            text = grp.add(gnome.canvas.CanvasText, x=_IMAGEX/2, 
                           anchor=gtk.ANCHOR_CENTER,
                           justification=gtk.JUSTIFY_CENTER,
                           y=_IMAGEY-10, text=description)

            # make sure that the text string doesn't exceed the size of the box

            bnds = text.get_bounds()
            while bnds[0] <0:
                description = description[0:-4] + "..."
                text.set(text=description)
                bnds = text.get_bounds()

            for i in [ item, text, box, grp ] :
                self.p_map[i] = (item,text,box,photo,oid)
                i.show()
            
        self.canvas_list[oid] = (grp,item,text,self.cx,self.cy)

        self.cx += _PAD + _IMAGEX
        
        if self.cx + _PAD + _IMAGEX > self.x:
            self.cx = _PAD
            self.cy += _PAD + _IMAGEY
        
    def load_images(self):
        """clears the currentImages list to free up any cached 
        Imlibs.  Then add each photo in the place's list of photos to the 
        photolist window."""

        self.pos = 0
        self.cx = _PAD
        self.cy = _PAD
        
        (self.x,self.y) = self.iconlist.get_size()

        self.max = (self.x)/(_IMAGEX+_PAD)

        for photo in self.dataobj.get_media_list():
            self.add_thumbnail(photo)

        if self.cy > self.y:
            self.iconlist.set_scroll_region(0,0,self.x,self.cy)
        else:
            self.iconlist.set_scroll_region(0,0,self.x,self.y)
        
        if self.dataobj.get_media_list():
            Utils.bold_label(self.parent.gallery_label)
        else:
            Utils.unbold_label(self.parent.gallery_label)

    def get_index(self,obj,x,y):
        x_offset = x/(_IMAGEX+_PAD)
        y_offset = y/(_IMAGEY+_PAD)
        index = (y_offset*(1+self.max))+x_offset
        return min(index,len(self.dataobj.get_media_list()))

    def on_photolist_drag_data_received(self,w, context, x, y, data, info, time):
        if data and data.format == 8:
            icon_index = self.get_index(w,x,y)
            d = string.strip(string.replace(data.data,'\0',' '))
            protocol,site,file, j,k,l = urlparse.urlparse(d)
            if protocol == "file":
                name = file
                mime = GrampsMime.get_type(name)
                photo = RelLib.MediaObject()
                photo.set_path(name)
                photo.set_mime_type(mime)
                basename = os.path.basename(name)
                (root,ext) = os.path.splitext(basename)
                photo.set_description(root)
                self.savephoto(photo)
                if GrampsCfg.get_media_reference() == 0:
                    name = RelImage.import_media_object(name,self.path,photo.get_handle())
                    photo.set_path(name)
                self.parent.lists_changed = 1
                if GrampsCfg.get_media_global():
                    GlobalMediaProperties(self.db,photo,None,
                                                self,self.parent_window)
            elif protocol != "":
                import urllib
                u = urllib.URLopener()
                try:
                    tfile,headers = u.retrieve(d)
                except (IOError,OSError), msg:
                    t = _("Could not import %s") % d
                    ErrorDialog(t,str(msg))
                    return
                mime = GrampsMime.get_type(tfile)
                photo = RelLib.MediaObject()
                photo.set_mime_type(mime)
                photo.set_description(d)
                photo.set_path(tfile)
                self.db.add_object(photo,None)
                oref = RelLib.MediaRef()
                oref.set_reference_handle(photo.get_handle())
                self.dataobj.add_media_reference(oref)
                try:
                    id = photo.get_handle()
                    name = RelImage.import_media_object(tfile,self.path,id)
                    photo.set_path(name)
                except:
                    photo.set_path(tfile)
                    return
                self.add_thumbnail(oref)
                self.parent.lists_changed = 1
                if GrampsCfg.get_media_global():
                    GlobalMediaProperties(self.db,photo,None,
                                                self,self.parent_window)
            else:
                if self.db.has_object_handle(data.data):
                    icon_index = self.get_index(w,x,y)
                    index = 0
                    for p in self.dataobj.get_media_list():
                        if data.data == p.get_reference_handle():
                            if index == icon_index or icon_index == -1:
                                return
                            else:
                                nl = self.dataobj.get_media_list()
                                item = nl[index]
                                if icon_index == 0:
                                    del nl[index]
                                    nl = [item] + nl
                                else:
                                    del nl[index]
                                    nl = nl[0:icon_index] + [item] + nl[icon_index:]
                                self.dataobj.set_media_list(nl)
                                self.parent.lists_changed = 1
                                self.load_images()
                                return
                        index = index + 1
                    oref = RelLib.MediaRef()
                    oref.set_reference_handle(data.data)
                    self.dataobj.add_media_reference(oref)
                    self.add_thumbnail(oref)
                    self.parent.lists_changed = 1
                    if GrampsCfg.get_media_global():
                        LocalMediaProperties(oref,self.path,self,self.parent_window)
                
    def on_photolist_drag_data_get(self,w, context, selection_data, info, time):
        if info == 1:
            return
        id = self.p_map[self.drag_item]
        selection_data.set(selection_data.target, 8, id[4])
        self.drag_item = None
        
    def on_add_media_clicked(self, obj):
        """User wants to add a new photo.  Create a dialog to find out
        which photo they want."""
        self.create_add_dialog()

    def on_select_media_clicked(self,obj):
        """User wants to add a new object that is already in a database.  
        Create a dialog to find out which object they want."""

        s_o = SelectObject.SelectObject(self.db,_("Select an Object"))
        object = s_o.run()
        if not object:
            return
        oref = RelLib.MediaRef()
        oref.set_reference_handle(object.get_handle())
        self.dataobj.add_media_reference(oref)
        self.add_thumbnail(oref)

        self.parent.lists_changed = 1
        self.load_images()

    def on_delete_media_clicked(self, obj):
        """User wants to delete a new photo. Remove it from the displayed
        thumbnails, and remove it from the dataobj photo list."""

        if self.sel:
            (i,t,b,photo,oid) = self.p_map[self.sel]
            val = self.canvas_list[photo.get_reference_handle()]
            val[0].hide()
            val[1].hide()
            val[2].hide()

            l = self.dataobj.get_media_list()
            l.remove(photo)
            self.dataobj.set_media_list(l)
            self.parent.lists_changed = 1
            self.load_images()

    def on_edit_media_clicked(self, obj):
        """User wants to delete a new photo. Remove it from the displayed
        thumbnails, and remove it from the dataobj photo list."""

        if self.sel:
            (i,t,b,photo,oid) = self.p_map[self.sel]
            LocalMediaProperties(photo,self.path,self,self.parent_window)
        
    def show_popup(self, photo, event):
        """Look for right-clicks on a picture and create a popup
        menu of the available actions."""
        
        menu = gtk.Menu()
        menu.set_title(_("Media Object"))
        object = self.db.try_to_find_object_from_handle(photo.get_reference_handle())
        mtype = object.get_mime_type()
        progname = GrampsMime.get_application(mtype)
        
        if progname and len(progname) > 1:
            Utils.add_menuitem(menu,_("Open in %s") % progname[1],
                               photo,self.popup_view_photo)
        if mtype[0:5] == "image":
            Utils.add_menuitem(menu,_("Edit with the GIMP"),
                               photo,self.popup_edit_photo)
        Utils.add_menuitem(menu,_("Edit Object Properties"),photo,
                           self.popup_change_description)
        menu.popup(None,None,None,event.button,event.time)
            
    def popup_view_photo(self, obj):
        """Open this picture in a picture viewer"""
        photo = obj.get_data('o')
        Utils.view_photo(self.db.try_to_find_object_from_handle(photo.get_reference_handle()))
    
    def popup_edit_photo(self, obj):
        """Open this picture in a picture editor"""
        photo = obj.get_data('o')
        if os.fork() == 0:
            obj = self.db.try_to_find_object_from_handle(photo.get_reference_handle())
            os.execvp(const.editor,[const.editor, obj.get_path()])
    
    def popup_convert_to_private(self, obj):
        """Copy this picture into gramps private database instead of
        leaving it as an external data object."""
        photo = obj.get_data('o')
        object = self.db.try_to_find_object_from_handle(photo.get_reference_handle())
        name = RelImage.import_media_object(object.get_path(),self.path,
                                            object.get_handle())
        object.set_path(name)

    def popup_change_description(self, obj):
        """Bring up a window allowing the user to edit the description
        of a picture."""
        photo = obj.get_data('o')
        LocalMediaProperties(photo,self.path,self)

#-------------------------------------------------------------------------
#
# LocalMediaProperties
#
#-------------------------------------------------------------------------
class LocalMediaProperties:

    def __init__(self,photo,path,parent,parent_window=None):
        self.parent = parent
        if photo:
            if self.parent.parent.child_windows.has_key(photo):
                self.parent.parent.child_windows[photo].present(None)
                return
            else:
                self.win_key = photo
        else:
            self.win_key = self
        self.child_windows = {}
        self.photo = photo
        self.db = parent.db
        self.object = self.db.try_to_find_object_from_handle(photo.get_reference_handle())
        self.alist = photo.get_attribute_list()[:]
        self.lists_changed = 0
        
        fname = self.object.get_path()
        self.change_dialog = gtk.glade.XML(const.imageselFile,"change_description","gramps")

        title = _('Media Reference Editor')
        self.window = self.change_dialog.get_widget('change_description')
        Utils.set_titles(self.window,
                         self.change_dialog.get_widget('title'), title)
        
        descr_window = self.change_dialog.get_widget("description")
        self.pixmap = self.change_dialog.get_widget("pixmap")
        self.attr_type = self.change_dialog.get_widget("attr_type")
        self.attr_value = self.change_dialog.get_widget("attr_value")
        self.attr_details = self.change_dialog.get_widget("attr_details")

        self.attr_list = self.change_dialog.get_widget("attr_list")
        titles = [(_('Attribute'),0,150),(_('Value'),0,100)]

        self.attr_label = self.change_dialog.get_widget("attr_local")
        self.notes_label = self.change_dialog.get_widget("notes_local")
        self.flowed = self.change_dialog.get_widget("flowed")
        self.preform = self.change_dialog.get_widget("preform")

        self.atree = ListModel.ListModel(self.attr_list,titles,
                                         self.on_attr_list_select_row,
                                         self.on_update_attr_clicked)
        
        self.slist  = self.change_dialog.get_widget("src_list")
        self.sources_label = self.change_dialog.get_widget("source_label")
        if self.object:
            self.srcreflist = [RelLib.SourceRef(ref) for ref in self.photo.get_source_references()]
        else:
            self.srcreflist = []
    
        self.sourcetab = Sources.SourceTab(self.srcreflist,self,
                                 self.change_dialog,
                                 self.window, self.slist,
                                 self.change_dialog.get_widget('add_src'),
                                 self.change_dialog.get_widget('edit_src'),
                                 self.change_dialog.get_widget('del_src'))

        descr_window.set_text(self.object.get_description())
        mtype = self.object.get_mime_type()

        thumb = Utils.thumb_path(path,self.object)
        if os.path.isfile(thumb):
            self.pix = gtk.gdk.pixbuf_new_from_file(thumb)
            self.pixmap.set_from_pixbuf(self.pix)

        self.change_dialog.get_widget("private").set_active(photo.get_privacy())
        self.change_dialog.get_widget("gid").set_text(self.object.get_handle())

        self.change_dialog.get_widget("path").set_text(fname)

        mt = Utils.get_mime_description(mtype)
        self.change_dialog.get_widget("type").set_text(mt)
        self.notes = self.change_dialog.get_widget("notes")
        if self.photo.get_note():
            self.notes.get_buffer().set_text(self.photo.get_note())
            Utils.bold_label(self.notes_label)
            if self.photo.get_note_format() == 1:
                self.preform.set_active(1)
            else:
                self.flowed.set_active(1)

        self.change_dialog.signal_autoconnect({
            "on_add_attr_clicked": self.on_add_attr_clicked,
            "on_notebook_switch_page": self.on_notebook_switch_page,
            "on_update_attr_clicked": self.on_update_attr_clicked,
            "on_delete_attr_clicked" : self.on_delete_attr_clicked,
            "on_help_clicked" : self.on_help_clicked,
            "on_ok_clicked" : self.on_ok_clicked,
            "on_cancel_clicked" : self.close,
            "on_local_delete_event" : self.on_delete_event,
            })
        self.redraw_attr_list()
        if parent_window:
            self.window.set_transient_for(parent_window)
        self.add_itself_to_menu()
        self.window.show()

    def on_delete_event(self,obj,b):
        self.close_child_windows()
        self.remove_itself_from_menu()

    def close(self,obj):
        self.close_child_windows()
        self.remove_itself_from_menu()
        self.window.destroy()

    def close_child_windows(self):
        for child_window in self.child_windows.values():
            child_window.close(None)
        self.child_windows = {}

    def add_itself_to_menu(self):
        self.parent.parent.child_windows[self.win_key] = self
        label = _('Media Reference')
        self.parent_menu_item = gtk.MenuItem(label)
        self.parent_menu_item.set_submenu(gtk.Menu())
        self.parent_menu_item.show()
        self.parent.parent.winsmenu.append(self.parent_menu_item)
        self.winsmenu = self.parent_menu_item.get_submenu()
        self.menu_item = gtk.MenuItem(_('Reference Editor'))
        self.menu_item.connect("activate",self.present)
        self.menu_item.show()
        self.winsmenu.append(self.menu_item)

    def remove_itself_from_menu(self):
        del self.parent.parent.child_windows[self.win_key]
        self.menu_item.destroy()
        self.winsmenu.destroy()
        self.parent_menu_item.destroy()

    def present(self,obj):
        self.window.present()

    def redraw_attr_list(self):
        self.atree.clear()
        self.amap = {}
        for attr in self.alist:
            d = [attr.get_type(),attr.get_value()]
            iter = self.atree.add(d,attr)
            self.amap[str(attr)] = iter
        if self.alist:
            Utils.bold_label(self.attr_label)
        else:
            Utils.unbold_label(self.attr_label)
        
    def on_notebook_switch_page(self,obj,junk,page):
        t = self.notes.get_buffer()
        text = unicode(t.get_text(t.get_start_iter(),t.get_end_iter(),gtk.FALSE))
        if text:
            Utils.bold_label(self.notes_label)
        else:
            Utils.unbold_label(self.notes_label)
            
    def on_apply_clicked(self):
        priv = self.change_dialog.get_widget("private").get_active()

        t = self.notes.get_buffer()
        text = unicode(t.get_text(t.get_start_iter(),t.get_end_iter(),gtk.FALSE))
        note = self.photo.get_note()
        format = self.preform.get_active()
        if text != note or priv != self.photo.get_privacy():
            self.photo.set_note(text)
            self.photo.set_privacy(priv)
            self.parent.lists_changed = 1
            self.parent.parent.lists_changed = 1
        if format != self.photo.get_note_format():
            self.photo.set_note_format(format)
        if self.lists_changed:
            self.photo.set_attribute_list(self.alist)
            self.photo.set_source_reference_list(self.srcreflist)
            self.parent.lists_changed = 1
            self.parent.parent.lists_changed = 1

        trans = self.db.start_transaction()
        self.db.commit_media_object(self.object,trans)
        self.db.add_transaction(trans,_("Edit Media Object"))

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        gnome.help_display('gramps-manual','gramps-edit-complete')
        
    def on_ok_clicked(self,obj):
        self.on_apply_clicked()
        self.close(obj)
        
    def on_attr_list_select_row(self,obj):
        store,iter = self.atree.get_selected()
        if iter:
            attr = self.atree.get_object(iter)

            self.attr_type.set_label(attr.get_type())
            self.attr_value.set_text(attr.get_value())
        else:
            self.attr_type.set_label('')
            self.attr_value.set_text('')

    def attr_callback(self,attr):
        self.redraw_attr_list()
        self.atree.select_iter(self.amap[str(attr)])
        
    def on_update_attr_clicked(self,obj):
        import AttrEdit

        store,iter = self.atree.get_selected()
        if iter:
            attr = self.atree.get_object(iter)
            AttrEdit.AttributeEditor(self,attr,"Media Object",
                                     Plugins.get_image_attributes(),
                                     self.attr_callback)

    def on_delete_attr_clicked(self,obj):
        if Utils.delete_selected(obj,self.alist):
            self.lists_changed = 1
            self.redraw_attr_list()

    def on_add_attr_clicked(self,obj):
        import AttrEdit
        AttrEdit.AttributeEditor(self,None,"Media Object",
                                 Plugins.get_image_attributes(),
                                 self.attr_callback)

#-------------------------------------------------------------------------
#
# GlobalMediaProperties
#
#-------------------------------------------------------------------------
class GlobalMediaProperties:

    def __init__(self,db,object,update,parent,parent_window=None):
        self.parent = parent
        if object:
            if self.parent.parent.child_windows.has_key(object.get_handle()):
                self.parent.parent.child_windows[object.get_handle()].present(None)
                return
            else:
                self.win_key = object.get_handle()
        else:
            self.win_key = self
        self.child_windows = {}
        self.object = object
        self.alist = self.object.get_attribute_list()[:]
        self.lists_changed = 0
        self.db = db
        self.update = update
        self.refs = 0
    
        self.path = self.db.get_save_path()
        self.change_dialog = gtk.glade.XML(const.imageselFile,"change_global","gramps")

        title = _('Media Properties Editor')

        self.window = self.change_dialog.get_widget('change_global')
        Utils.set_titles(self.window,
                         self.change_dialog.get_widget('title'),title)
        
        self.descr_window = self.change_dialog.get_widget("description")
        self.notes = self.change_dialog.get_widget("notes")
        self.pixmap = self.change_dialog.get_widget("pixmap")
        self.attr_type = self.change_dialog.get_widget("attr_type")
        self.attr_value = self.change_dialog.get_widget("attr_value")
        self.attr_details = self.change_dialog.get_widget("attr_details")

        self.attr_list = self.change_dialog.get_widget("attr_list")

        self.attr_label = self.change_dialog.get_widget("attrGlobal")
        self.notes_label = self.change_dialog.get_widget("notesGlobal")
        self.refs_label = self.change_dialog.get_widget("refsGlobal")
        self.flowed = self.change_dialog.get_widget("global_flowed")
        self.preform = self.change_dialog.get_widget("global_preform")

        titles = [(_('Attribute'),0,150),(_('Value'),1,100)]

        self.atree = ListModel.ListModel(self.attr_list,titles,
                                         self.on_attr_list_select_row,
                                         self.on_update_attr_clicked)
        
        self.slist  = self.change_dialog.get_widget("src_list")
        self.sources_label = self.change_dialog.get_widget("sourcesGlobal")
        if self.object:
            self.srcreflist = [RelLib.SourceRef(ref) for ref in self.object.get_source_references()]
        else:
            self.srcreflist = []
    
        self.sourcetab = Sources.SourceTab(self.srcreflist,self,
                                           self.change_dialog,
                                           self.window, self.slist,
                                           self.change_dialog.get_widget('gl_add_src'),
                                           self.change_dialog.get_widget('gl_edit_src'),
                                           self.change_dialog.get_widget('gl_del_src'))

        self.descr_window.set_text(self.object.get_description())
        mtype = self.object.get_mime_type()
        pb = gtk.gdk.pixbuf_new_from_file(Utils.thumb_path(self.path,self.object))
        self.pixmap.set_from_pixbuf(pb)

        self.change_dialog.get_widget("gid").set_text(self.object.get_handle())
        self.makelocal = self.change_dialog.get_widget("makelocal")

        self.update_info()
        
        self.change_dialog.get_widget("type").set_text(Utils.get_mime_description(mtype))
        if self.object.get_note():
            self.notes.get_buffer().set_text(self.object.get_note())
            Utils.bold_label(self.notes_label)
            if self.object.get_note_format() == 1:
                self.preform.set_active(1)
            else:
                self.flowed.set_active(1)

        self.change_dialog.signal_autoconnect({
            "on_cancel_clicked"      : self.close,
            "on_up_clicked"          : self.on_up_clicked,
            "on_down_clicked"        : self.on_down_clicked,
            "on_ok_clicked"          : self.on_ok_clicked,
            "on_apply_clicked"       : self.on_apply_clicked,
            "on_add_attr_clicked"    : self.on_add_attr_clicked,
            "on_notebook_switch_page": self.on_notebook_switch_page,
            "on_delete_attr_clicked" : self.on_delete_attr_clicked,
            "on_update_attr_clicked" : self.on_update_attr_clicked,
            "on_help_clicked"        : self.on_help_clicked,
            "on_global_delete_event" : self.on_delete_event,
            })

        self.redraw_attr_list()
        self.display_refs()
        if parent_window:
            self.window.set_transient_for(parent_window)
        self.add_itself_to_menu()
        self.window.show()

    def on_delete_event(self,obj,b):
        self.close_child_windows()
        self.remove_itself_from_menu()

    def close(self,obj):
        self.close_child_windows()
        self.remove_itself_from_menu()
        self.window.destroy()

    def close_child_windows(self):
        for child_window in self.child_windows.values():
            child_window.close(None)
        self.child_windows = {}

    def add_itself_to_menu(self):
        self.parent.parent.child_windows[self.win_key] = self
        label = _('Media Object')
        self.parent_menu_item = gtk.MenuItem(label)
        self.parent_menu_item.set_submenu(gtk.Menu())
        self.parent_menu_item.show()
        self.parent.parent.winsmenu.append(self.parent_menu_item)
        self.winsmenu = self.parent_menu_item.get_submenu()
        self.menu_item = gtk.MenuItem(_('Properties Editor'))
        self.menu_item.connect("activate",self.present)
        self.menu_item.show()
        self.winsmenu.append(self.menu_item)

    def remove_itself_from_menu(self):
        del self.parent.parent.child_windows[self.win_key]
        self.menu_item.destroy()
        self.winsmenu.destroy()
        self.parent_menu_item.destroy()

    def present(self,obj):
        self.window.present()

    def on_up_clicked(self,obj):
        store,iter = self.atree.get_selected()
        if iter:
            row = self.atree.get_row(iter)
            if row != 0:
                self.atree.select_row(row-1)

    def on_down_clicked(self,obj):
        model,iter = self.atree.get_selected()
        if not iter:
            return
        row = self.atree.get_row(iter)
        self.atree.select_row(row+1)

    def update_info(self):
        fname = self.object.get_path()
        self.change_dialog.get_widget("path").set_text(fname)

    def redraw_attr_list(self):
        self.atree.clear()
        self.amap = {}
        for attr in self.alist:
            d = [attr.get_type(),attr.get_value()]
            iter = self.atree.add(d,attr)
            self.amap[str(attr)] = iter
        if self.alist:
            Utils.bold_label(self.attr_label)
        else:
            Utils.unbold_label(self.attr_label)

    def button_press(self,obj):
        store,iter = self.refmodel.selection.get_selected()
        if not iter:
            return
            
    def display_refs(self):
        if self.refs == 1:
            return
        self.refs = 1

        titles = [(_('Type'),0,150),(_('ID'),1,75),(_('Value'),2,100)]
        self.refmodel = ListModel.ListModel(self.change_dialog.get_widget("refinfo"),
                                            titles,event_func=self.button_press)
        any = 0
        for key in self.db.get_person_keys():
            p = self.db.get_person(key)
            for o in p.get_media_list():
                if o.get_reference_handle() == self.object.get_handle():
                    self.refmodel.add([_("Person"),p.get_handle(),GrampsCfg.get_nameof()(p)])
                    any = 1
        for key in self.db.get_family_keys():
            p = self.db.find_family_from_handle(key)
            for o in p.get_media_list():
                if o.get_reference_handle() == self.object.get_handle():
                    self.refmodel.add([_("Family"),p.get_handle(),Utils.family_name(p,self.db)])
                    any = 1
        for key in self.db.get_source_keys():
            p = self.db.try_to_find_source_from_handle(key)
            for o in p.get_media_list():
                if o.get_reference_handle() == self.object.get_handle():
                    self.refmodel.add([_("Source"),p.get_handle(),p.get_title()])
                    any = 1
        for key in self.db.get_place_handle_keys():
            p = self.db.try_to_find_place_from_handle(key)
            for o in p.get_media_list():
                if o.get_reference_handle() == self.object.get_handle():
                    self.refmodel.add([_("Place"),p.get_handle(),p.get_title()])
                    any = 1
        if any:
            Utils.bold_label(self.refs_label)
        else:
            Utils.unbold_label(self.refs_label)
        
    def on_notebook_switch_page(self,obj,junk,page):
        if page == 3:
            self.display_refs()
        t = self.notes.get_buffer()
        text = unicode(t.get_text(t.get_start_iter(),t.get_end_iter(),gtk.FALSE))
        if text:
            Utils.bold_label(self.notes_label)
        else:
            Utils.unbold_label(self.notes_label)
            
    def on_apply_clicked(self, obj):
        t = self.notes.get_buffer()
        text = unicode(t.get_text(t.get_start_iter(),t.get_end_iter(),gtk.FALSE))
        desc = unicode(self.descr_window.get_text())
        note = self.object.get_note()
        format = self.preform.get_active()
        if text != note or desc != self.object.get_description():
            self.object.set_note(text)
            self.object.set_description(desc)
        if format != self.object.get_note_format():
            self.object.set_note_format(format)
        if self.lists_changed:
            self.object.set_attribute_list(self.alist)
            self.object.set_source_reference_list(self.srcreflist)
        if self.update != None:
            self.update()
        trans = self.db.start_transaction()
        self.db.commit_media_object(self.object,trans)
        self.db.add_transaction(trans,_("Edit Media Object"))

    def on_help_clicked(self, obj):
        """Display the relevant portion of GRAMPS manual"""
        gnome.help_display('gramps-manual','gramps-edit-complete')
        
    def on_ok_clicked(self, obj):
        self.on_apply_clicked(obj)
        self.close(obj)

    def on_attr_list_select_row(self,obj):
        store,iter = self.atree.get_selected()
        if iter:
            attr = self.atree.get_object(iter)

            self.attr_type.set_label(attr.get_type())
            self.attr_value.set_text(attr.get_value())
        else:
            self.attr_type.set_label('')
            self.attr_value.set_text('')

    def attr_callback(self,attr):
        self.redraw_attr_list()
        self.atree.select_iter(self.amap[str(attr)])

    def on_update_attr_clicked(self,obj):
        import AttrEdit

        store,iter = self.atree.get_selected()
        if iter:
            attr = self.atree.get_object(iter)
            AttrEdit.AttributeEditor(self,attr,"Media Object",
                                     Plugins.get_image_attributes(),
                                     self.attr_callback)

    def on_delete_attr_clicked(self,obj):
        if Utils.delete_selected(obj,self.alist):
            self.lists_changed = 1
            self.redraw_attr_list()

    def on_add_attr_clicked(self,obj):
        import AttrEdit
        AttrEdit.AttributeEditor(self,None,"Media Object",
                                 Plugins.get_image_attributes(),
                                 self.attr_callback)

class DeleteMediaQuery:

    def __init__(self,media,db,update):
        self.db = db
        self.media = media
        self.update = update
        
    def query_response(self):
        trans = self.db.start_transaction()
        
        for key in self.db.get_person_keys():
            p = self.db.get_person(key)
            nl = []
            change = 0
            for photo in p.get_media_list():
                if photo.get_reference_handle() != self.media.get_handle():
                    nl.append(photo)
                else:
                    change = 1
            if change:
                p.set_media_list(nl)
                self.db.commit_person(p,trans)

        for fid in self.db.get_family_keys():
            p = self.db.find_family_from_handle(fid)
            nl = []
            change = 0
            for photo in p.get_media_list():
                if photo.get_reference_handle() != self.media.get_handle():
                    nl.append(photo)
                else:
                    change = 1
            if change:
                p.set_media_list(nl)
                self.db.commit_family(p,trans)

        for key in self.db.get_source_keys():
            sid = self.db.try_to_find_source_from_handle(key)
            nl = []
            change = 0
            for photo in p.get_media_list():
                if photo.get_reference_handle() != self.media.get_handle():
                    nl.append(photo)
                else:
                    change = 1
            if change:
                p.set_media_list(nl)
                self.db.commit_source(p,trans)

        for key in self.db.get_place_handle_keys():
            p = self.db.try_to_find_place_from_handle(key)
            nl = []
            change = 0
            for photo in p.get_media_list():
                if photo.get_reference_handle() != self.media.get_handle():
                    nl.append(photo)
                else:
                    change = 1
            if change:
                p.set_media_list(nl)
                self.db.commit_place(p,trans)

        self.db.remove_object(self.media.get_handle(),trans)
        self.db.add_transaction(trans,_("Remove Media Object"))
        if self.update:
            self.update()

