1#
2# Gramps - a GTK+/GNOME based genealogy program
3#
4# Copyright (C) 2000-2006  Donald N. Allingham
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19#
20
21"""
22Provide the interface to allow a person to add a media object to the database.
23"""
24
25#-------------------------------------------------------------------------
26#
27# Standard python modules
28#
29#-------------------------------------------------------------------------
30import os
31
32#-------------------------------------------------------------------------
33#
34# internationalization
35#
36#-------------------------------------------------------------------------
37
38#-------------------------------------------------------------------------
39#
40# GTK/Gnome modules
41#
42#-------------------------------------------------------------------------
43from gi.repository import GdkPixbuf
44
45#-------------------------------------------------------------------------
46#
47# gramps modules
48#
49#-------------------------------------------------------------------------
50from gramps.gen.const import GRAMPS_LOCALE as glocale
51_ = glocale.translation.sgettext
52from gramps.gen.const import ICON, THUMBSCALE, USER_HOME
53from gramps.gen.config import config
54from gramps.gen.utils.file import (media_path_full, media_path, relative_path,
55                                   find_file)
56from gramps.gen.mime import get_type
57from gramps.gen.utils.thumbnails import find_mime_type_pixbuf
58from ..display import display_help
59from ..managedwindow import ManagedWindow
60from ..dialog import ErrorDialog, WarningDialog
61from ..glade import Glade
62from gramps.gen.const import URL_MANUAL_SECT2
63
64#-------------------------------------------------------------------------
65#
66# Constants
67#
68#-------------------------------------------------------------------------
69WIKI_HELP_PAGE = URL_MANUAL_SECT2
70WIKI_HELP_SEC = _('manual|Select_a_media_selector')
71
72#-------------------------------------------------------------------------
73#
74# AddMedia
75#
76#-------------------------------------------------------------------------
77class AddMedia(ManagedWindow):
78    """
79    Displays the Add Media Dialog window, allowing the user to select
80    a file from the file system, while providing a description.
81    """
82
83    def __init__(self, dbstate, uistate, track, media, callback=None):
84        """
85        Create and displays the dialog box
86
87        db - the database in which the new object is to be stored
88        The media is updated with the information, and on save, the
89        callback function is called
90        """
91        ManagedWindow.__init__(self, uistate, track, self, modal=True)
92
93        self.dbase = dbstate.db
94        self.obj = media
95        self.callback = callback
96
97        self.last_directory = config.get('behavior.addmedia-image-dir')
98        self.relative_path = config.get('behavior.addmedia-relative-path')
99
100        self.glade = Glade()
101        self.set_window(
102            self.glade.toplevel,
103            self.glade.get_object('title'),
104            _('Select a media object'))
105        self.setup_configs('interface.addmedia', 700, 500)
106
107        self.description = self.glade.get_object("photoDescription")
108        self.image = self.glade.get_object("image")
109        self.file_text = self.glade.get_object("fname")
110        if not(self.last_directory and os.path.isdir(self.last_directory)):
111            self.last_directory = USER_HOME
112        #if existing path, use dir of path
113        if not self.obj.get_path() == "":
114            fullname = media_path_full(self.dbase, self.obj.get_path())
115            dir = os.path.dirname(fullname)
116            if os.path.isdir(dir):
117                self.last_directory = dir
118                self.file_text.select_filename(fullname)
119            else:
120                self.file_text.set_current_folder(self.last_directory)
121        else:
122            self.file_text.set_current_folder(self.last_directory)
123        if not self.obj.get_description() == "":
124            self.description.set_text(self.obj.get_description())
125
126        self.relpath = self.glade.get_object('relpath')
127        self.relpath.set_active(self.relative_path)
128        self.temp_name = ""
129        self.object = None
130
131        self.glade.get_object('fname').connect('update_preview',
132                                               self.on_name_changed)
133        self.ok_button = self.glade.get_object('button79')
134        self.help_button = self.glade.get_object('button103')
135        self.cancel_button = self.glade.get_object('button81')
136        self.ok_button.connect('clicked', self.save)
137        self.ok_button.set_sensitive(not self.dbase.readonly)
138        self.help_button.connect('clicked', lambda x: display_help(
139                                     webpage=WIKI_HELP_PAGE,
140                                             section=WIKI_HELP_SEC))
141        self.cancel_button.connect('clicked', self.close)
142        self.show()
143
144    def build_menu_names(self, obj):
145        """
146        Build the menu name for the window manager.
147        """
148        return(_('Select media object'), None)
149
150    def save(self, *obj):
151        """
152        Callback function called when the save button is pressed.
153        The media object is updated, and callback called.
154        """
155        description = str(self.description.get_text())
156
157        if self.file_text.get_filename() is None:
158            msgstr = _("Import failed")
159            msgstr2 = _("The filename supplied could not be found.")
160            ErrorDialog(msgstr, msgstr2, parent=self.window)
161            return
162
163        filename = self.file_text.get_filename()
164        full_file = filename
165
166        if self.relpath.get_active():
167            pname = str(media_path(self.dbase))
168            if not os.path.exists(pname):
169                msgstr = _("Cannot import %s")
170                msgstr2 = _("Directory specified in preferences: "
171                            "Base path for relative media paths: "
172                            "%s does not exist. Change preferences "
173                            "or do not use relative path when importing")
174                ErrorDialog(msgstr % filename, msgstr2 % pname,
175                            parent=self.window)
176                return
177            filename = relative_path(filename, pname)
178
179
180        mtype = get_type(full_file)
181        description = description or os.path.basename(filename)
182
183        self.obj.set_description(description)
184        self.obj.set_mime_type(mtype)
185        name = filename
186        self.obj.set_path(name)
187
188        self.last_directory = os.path.dirname(full_file)
189        self.relative_path = self.relpath.get_active()
190
191        self._cleanup_on_exit()
192        if self.callback:
193            self.callback(self.obj)
194        self.close()
195
196    def on_name_changed(self, *obj):
197        """
198        Called anytime the filename text window changes. Checks to
199        see if the file exists. If it does, the image is loaded into
200        the preview window.
201        """
202        fname = self.file_text.get_filename()
203        if not fname:
204            return
205        filename = fname
206        basename = os.path.basename(filename)
207        (root, ext) = os.path.splitext(basename)
208        old_title = self.description.get_text()
209
210        if old_title == '' or old_title == self.temp_name:
211            self.description.set_text(root)
212        self.temp_name = root
213
214        filename = find_file( filename)
215        if filename:
216            mtype = get_type(filename)
217            if mtype and mtype.startswith("image"):
218                image = self.scale_image(filename, THUMBSCALE)
219            else:
220                image = find_mime_type_pixbuf(mtype)
221            self.image.set_from_pixbuf(image)
222
223    def _cleanup_on_exit(self):
224        config.set('behavior.addmedia-image-dir', self.last_directory)
225        config.set('behavior.addmedia-relative-path', self.relative_path)
226        config.save()
227
228    #-------------------------------------------------------------------------
229    #
230    # scale_image
231    #
232    #-------------------------------------------------------------------------
233    def scale_image(self, path, size):
234        """
235        Scales the image to the specified size
236        """
237
238        title_msg = _("Cannot display %s") % path
239        detail_msg = _('Gramps is not able to display the image file. '
240                        'This may be caused by a corrupt file.')
241
242        try:
243            image1 = GdkPixbuf.Pixbuf.new_from_file(path)
244            width = image1.get_width()
245            height = image1.get_height()
246            scale = size / float(max(width, height))
247            return image1.scale_simple(int(scale*width), int(scale*height),
248                                       GdkPixbuf.InterpType.BILINEAR)
249        except:
250            WarningDialog(title_msg, detail_msg,
251                          parent=self.window)
252            return GdkPixbuf.Pixbuf.new_from_file(ICON)
253