diff --git a/ChangeLog b/ChangeLog index 8ce1b59a1..098cd2c27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-02-11 Benny Malengier + * src/plugins/MediaManager.py: conversion functions of path + * src/Utils.py: general methods to convert abs to rel + * src/Editors/AddMedia.py: show existing descr and select file if pos + * src/Editors/_EditPerson.py: view photo needs db for media path + * src/Editors/_EditMedia.py: better path/mime handling + * src/DataViews/MediaView.py: use full path to view + Start of issue #1208 + 2008-02-11 Benny Malengier * src/Editors/_EditFamily.py: call editprimary correctly, double gid diff --git a/src/DataViews/MediaView.py b/src/DataViews/MediaView.py index 395ad7514..956288bc9 100644 --- a/src/DataViews/MediaView.py +++ b/src/DataViews/MediaView.py @@ -230,7 +230,8 @@ class MediaView(PageView.ListView): mime_type = ref_obj.get_mime_type() app = Mime.get_application(mime_type) if app: - Utils.launch(app[0], ref_obj.get_path()) + Utils.launch(app[0], Utils.media_path_full(self.dbstate.db, + ref_obj.get_path())) else: ErrorDialog(_("Cannot view %s") % ref_obj.get_path(), _("GRAMPS cannot find an application that can view " @@ -325,7 +326,8 @@ class MediaView(PageView.ListView): self.ttips.disable() else: obj = self.dbstate.db.get_object_from_handle(handle) - pix = ThumbNails.get_thumbnail_image(obj.get_path()) + pix = ThumbNails.get_thumbnail_image( + Utils.media_path_full(self.dbstate.db, obj.get_path())) self.image.set_from_pixbuf(pix) self.ttips.enable() diff --git a/src/Editors/AddMedia.py b/src/Editors/AddMedia.py index e38703ed1..f75687c68 100644 --- a/src/Editors/AddMedia.py +++ b/src/Editors/AddMedia.py @@ -107,9 +107,20 @@ class AddMediaObject(ManagedWindow.ManagedWindow): self.image = self.glade.get_widget("image") self.file_text = self.glade.get_widget("fname") if not(self.last_directory and os.path.isdir(self.last_directory)): - self.last_directory = const.HOME_DIR - print 'test', self.last_directory - self.file_text.set_current_folder(self.last_directory) + self.last_directory = const.USER_HOME + #if existing path, use dir of path + if not self.obj.get_path() == "": + fullname = Utils.media_path_full(self.dbase, self.obj.get_path()) + dir = os.path.dirname(fullname) + if os.path.isdir(dir): + self.last_directory = dir + self.file_text.select_filename(fullname) + else: + self.file_text.set_current_folder(self.last_directory) + else: + self.file_text.set_current_folder(self.last_directory) + if not self.obj.get_description() == "": + self.description.set_text(self.obj.get_description()) self.relpath = self.glade.get_widget('relpath') self.relpath.set_active(self.relative_path) @@ -151,10 +162,7 @@ class AddMediaObject(ManagedWindow.ManagedWindow): filename = Utils.get_unicode_path(self.file_text.get_filename()) full_file = filename - pname = self.dbase.get_save_path() - if not os.path.isdir(pname): - pname = os.path.dirname(pname) - + pname = Utils.media_path(self.dbase) if self.relpath.get_active(): filename = Utils.relative_path(filename, pname) diff --git a/src/Editors/_EditMedia.py b/src/Editors/_EditMedia.py index 6a6685cfb..0f5a89472 100644 --- a/src/Editors/_EditMedia.py +++ b/src/Editors/_EditMedia.py @@ -128,22 +128,40 @@ class EditMedia(EditPrimary): ebox.connect('button-press-event', self.button_press_event) self.mimetext = self.glade.get_widget("type") - self.draw_preview() self.setup_filepath() + self.determine_mime() + self.draw_preview() + + def determine_mime(self): + descr = Mime.get_description(self.obj.get_mime_type()) + if descr: + self.mimetext.set_text(descr) + + path = self.file_path.get_text() + path_full = Utils.media_path_full(self.db, path) + if path != self.obj.get_path() and path_full != self.obj.get_path(): + #redetermine mime + mime = Mime.get_type(Utils.find_file(path_full)) + self.obj.set_mime_type(mime) + descr = Mime.get_description(mime) + if descr: + self.mimetext.set_text(descr) + else: + self.mimetext.set_text(_('Unknown')) + #if mime type not set, is note + if not self.obj.get_mime_type(): + self.mimetext.set_text(_('Note')) def draw_preview(self): mtype = self.obj.get_mime_type() if mtype: - pb = ThumbNails.get_thumbnail_image( - Utils.find_file(self.obj.get_path()), mtype) + pb = ThumbNails.get_thumbnail_image(Utils.find_file( + Utils.media_path_full(self.db, self.obj.get_path())), + mtype) self.pixmap.set_from_pixbuf(pb) - descr = Mime.get_description(mtype) - if descr: - self.mimetext.set_text(descr) else: pb = Mime.find_mime_type_pixbuf('text/plain') self.pixmap.set_from_pixbuf(pb) - self.mimetext.set_text(_('Note')) def setup_filepath(self): self.select = self.glade.get_widget('file_select') @@ -192,9 +210,13 @@ class EditMedia(EditPrimary): mime_type = ref_obj.get_mime_type() app = Mime.get_application(mime_type) if app: - Utils.launch(app[0], ref_obj.get_path()) + Utils.launch(app[0], Utils.media_path_full(self.dbstate.db, + ref_obj.get_path())) def select_file(self, val): + self.determine_mime() + path = self.file_path.get_text() + self.obj.set_path(Utils.get_unicode_path(path)) AddMediaObject(self.dbstate, self.uistate, self.track, self.obj, self._update_addmedia) @@ -208,10 +230,12 @@ class EditMedia(EditPrimary): obj.update() fname = self.obj.get_path() self.file_path.set_text(fname) + self.determine_mime() self.draw_preview() def save(self, *obj): self.ok_button.set_sensitive(False) + if self.object_is_empty(): ErrorDialog(_("Cannot save media object"), _("No data exists for this media object. Please " @@ -233,11 +257,8 @@ class EditMedia(EditPrimary): self.ok_button.set_sensitive(True) return - path = self.glade.get_widget('path').get_text() - - if path != self.obj.get_path(): - mime = Mime.get_type(Utils.find_file(os.path.abspath(path))) - self.obj.set_mime_type(mime) + path = self.file_path.get_text() + self.determine_mime() self.obj.set_path(Utils.get_unicode_path(path)) diff --git a/src/Editors/_EditPerson.py b/src/Editors/_EditPerson.py index c74feaee2..73941f855 100644 --- a/src/Editors/_EditPerson.py +++ b/src/Editors/_EditPerson.py @@ -486,7 +486,8 @@ class EditPerson(EditPrimary): if media_list: photo = media_list[0] object_handle = photo.get_reference_handle() - Utils.view_photo(self.db.get_object_from_handle(object_handle)) + Utils.view_photo(self.db.get_object_from_handle(object_handle), + self.db) def _popup_change_description(self, obj): """ diff --git a/src/Utils.py b/src/Utils.py index 56d1b3fc3..5de0fba32 100644 --- a/src/Utils.py +++ b/src/Utils.py @@ -51,7 +51,7 @@ import gen.lib import Errors from QuestionDialog import WarningDialog -from const import TEMP_DIR +from const import TEMP_DIR, USER_HOME import shutil #------------------------------------------------------------------------- @@ -262,14 +262,17 @@ def add_menuitem(menu, msg, obj, func): # # #------------------------------------------------------------------------- -def view_photo(photo): +def view_photo(photo, db): + """ + photo is a mediaobject, this utility launches a viewing application + """ mime_type = photo.get_mime_type() try: data = Mime.get_application(mime_type) prog = data[0] except: return - launch(prog, photo.get_path()) + launch(prog, media_path_full(db, photo.get_path())) def find_file( filename): # try the filename we got @@ -937,22 +940,66 @@ def get_type_converter_by_name(val_str): return unicode def relative_path(original, base): - if not os.path.exists(original) or not os.path.isdir(base): + """ + Calculate the relative path from base to original, with base a directory, + and original an absolute path + On problems, original is returned unchanged + """ + if not os.path.isdir(base): + return original + #original and base must be absolute paths + if not os.path.isabs(base): + return original + if not os.path.isabs(original): + return original + original = os.path.normpath(original) + base = os.path.normpath(base) + + # If the db_dir and obj_dir are on different drives (win only) + # then there cannot be a relative path. Return original obj_path + (base_drive, base) = os.path.splitdrive(base) + (orig_drive, orig_name) = os.path.splitdrive(original) + if base_drive.upper() != orig_drive.upper(): return original - - base_list = (os.path.abspath(base)).split(os.sep) - target_list = (os.path.abspath(original)).split(os.sep) # Starting from the filepath root, work out how much of the filepath is # shared by base and target. - + base_list = (base).split(os.sep) + target_list = (orig_name).split(os.sep) + # make sure '/home/person' and 'c:/home/person' both give + # list ['home', 'person'] + base_list = [word for word in base_list if word] + target_list = [word for word in target_list if word] + i = -1 for i in range(min(len(base_list), len(target_list))): if base_list[i] <> target_list[i]: break else: + #if break did not happen we are here at end, and add 1. i += 1 rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:] return os.path.join(*rel_list) +def media_path(db): + """ + Given a database, return the mediapath to use as basedir for media + """ + mpath = db.get_mediapath() + if mpath is None: + #use home dir + mpath = USER_HOME + return mpath + +def media_path_full(db, filename): + """ + Given a database and a filename of a media, return the media filename + is full form, eg 'graves/tomb.png' becomes '/home/me/genea/graves/tomb.png + """ + if os.path.isabs(filename): + return filename + mpath = media_path(db) + return os.path.join(mpath, filename) + + class ProgressMeter: """ Progress meter class for GRAMPS. diff --git a/src/plugins/MediaManager.py b/src/plugins/MediaManager.py index 8b2b63d24..f9c7cfff2 100644 --- a/src/plugins/MediaManager.py +++ b/src/plugins/MediaManager.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham +# Copyright (C) 2008 B. Malengier # # 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 @@ -51,6 +52,7 @@ import Errors from gen.lib import MediaObject from BasicUtils import UpdateCallback from PluginUtils import Tool, register_tool +from Utils import media_path_full, relative_path, media_path #------------------------------------------------------------------------- # @@ -483,8 +485,9 @@ class PathChange(BatchOp): class Convert2Abs(BatchOp): title = _('Convert paths from relative to _absolute') description = _('This tool allows converting relative media paths ' - 'to the absolute ones. An absolute path allows to ' - 'fix the file location while moving the database.') + 'to the absolute ones. It does this by prepending ' + 'the base path as given in the Preferences, or if ' + 'that is not set, it prepends your home directory.') def _prepare(self): cursor = self.db.get_media_cursor() @@ -508,7 +511,7 @@ class Convert2Abs(BatchOp): self.set_total(len(self.handle_list)) for handle in self.handle_list: obj = self.db.get_object_from_handle(handle) - new_path = os.path.abspath(obj.path) + new_path = media_path_full(self.db, obj.path) obj.set_path(new_path) self.db.commit_media_object(obj,self.trans) self.update() @@ -520,8 +523,11 @@ class Convert2Abs(BatchOp): class Convert2Rel(BatchOp): title = _('Convert paths from absolute to r_elative') description = _('This tool allows converting absolute media paths ' - 'to the relative ones. A relative path allows to ' - 'tie the file location to that of the database.') + 'to the a relative path. The relative path is relative ' + 'viz-a-viz the base path as given in the Preferences, ' + 'or if that is not set, your home directory. ' + 'A relative path allows to tie the file location to a ' + 'base path that can change to your needs.') def _prepare(self): cursor = self.db.get_media_cursor() @@ -543,51 +549,15 @@ class Convert2Rel(BatchOp): if not self.prepared: self.prepare() self.set_total(len(self.handle_list)) - db_dir = os.path.normpath(os.path.dirname(self.db.full_name)) + base_dir = media_path(self.db) for handle in self.handle_list: obj = self.db.get_object_from_handle(handle) - new_path = get_rel_path(db_dir,obj.path) + new_path = relative_path(obj.path, base_dir) obj.set_path(new_path) self.db.commit_media_object(obj,self.trans) self.update() return True -#------------------------------------------------------------------------ -# -# Helper functions -# -#------------------------------------------------------------------------ -def get_rel_path(db_dir,obj_path): - obj_dir = os.path.dirname(os.path.normpath(obj_path)) - obj_name = os.path.basename(os.path.normpath(obj_path)) - - # If the db_dir and obj_dir are on different drives (win only) - # then there cannot be a relative path. Return original obj_path - (db_drive,db_dir) = os.path.splitdrive(db_dir) - (obj_drive,obj_dir) = os.path.splitdrive(obj_dir) - if db_drive.upper() != obj_drive.upper(): - return obj_path - - # Get the list of dirnames for each - db_dir_list = [word for word in db_dir.split(os.path.sep) if word] - obj_dir_list = [word for word in obj_dir.split(os.path.sep) if word] - - # The worst case scenario: nothing in common: - # we would need to go ndirs up and then use the full obj path - ndirs = len(db_dir_list) - - # Compare words in both lists - for word_ix in range(min(len(db_dir_list),len(obj_dir_list))): - # A common word reduces the trip by one '../' and one word - if db_dir_list[word_ix] == obj_dir_list[word_ix]: - ndirs -= 1 - else: - break - - up_from_db = '../'*ndirs - obj_dir_rem = os.path.sep.join(obj_dir_list[len(db_dir_list)-ndirs:]) - return os.path.join(up_from_db,obj_dir_rem,obj_name) - #------------------------------------------------------------------------ # #