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