diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2023-06-14 20:36:37 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2023-06-14 20:36:37 +0200 |
commit | bb80d3feebdc9acc52e3f4ad24084d8425f043a2 (patch) | |
tree | 2084a84c39f159c6aea254775dc0880d52579d45 /src/camera/ImportPage.vala | |
parent | b26ff0798252a1a8072dd2c7a67f6205de9fde11 (diff) | |
parent | 31804433d72460cbe0a39f9f8ea5e76058d84cda (diff) |
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'src/camera/ImportPage.vala')
-rw-r--r-- | src/camera/ImportPage.vala | 162 |
1 files changed, 71 insertions, 91 deletions
diff --git a/src/camera/ImportPage.vala b/src/camera/ImportPage.vala index 84d7cbe..a5d3b4e 100644 --- a/src/camera/ImportPage.vala +++ b/src/camera/ImportPage.vala @@ -21,13 +21,13 @@ abstract class ImportSource : ThumbnailSource, Indexable { private string folder; private string filename; private ulong file_size; - private time_t modification_time; + private DateTime modification_time; private Gdk.Pixbuf? preview = null; private string? indexable_keywords = null; protected ImportSource(string camera_name, GPhoto.Camera camera, int fsid, string folder, - string filename, ulong file_size, time_t modification_time) { - this.camera_name = camera_name; + string filename, ulong file_size, DateTime modification_time) { + this.camera_name =camera_name; this.camera = camera; this.fsid = fsid; this.folder = folder; @@ -65,7 +65,7 @@ abstract class ImportSource : ThumbnailSource, Indexable { return file_size; } - public time_t get_modification_time() { + public DateTime get_modification_time() { return modification_time; } @@ -73,7 +73,7 @@ abstract class ImportSource : ThumbnailSource, Indexable { return preview; } - public virtual time_t get_exposure_time() { + public virtual DateTime get_exposure_time() { return get_modification_time(); } @@ -110,7 +110,7 @@ abstract class ImportSource : ThumbnailSource, Indexable { class VideoImportSource : ImportSource { public VideoImportSource(string camera_name, GPhoto.Camera camera, int fsid, string folder, - string filename, ulong file_size, time_t modification_time) { + string filename, ulong file_size, DateTime modification_time) { base(camera_name, camera, fsid, folder, filename, file_size, modification_time); } @@ -159,7 +159,7 @@ class PhotoImportSource : ImportSource { private PhotoImportSource? associated = null; // JPEG source for RAW+JPEG public PhotoImportSource(string camera_name, GPhoto.Camera camera, int fsid, string folder, - string filename, ulong file_size, time_t modification_time, PhotoFileFormat file_format) { + string filename, ulong file_size, DateTime modification_time, PhotoFileFormat file_format) { base(camera_name, camera, fsid, folder, filename, file_size, modification_time); this.file_format = file_format; } @@ -200,7 +200,7 @@ class PhotoImportSource : ImportSource { this.exif_md5 = exif_md5; } - public override time_t get_exposure_time() { + public override DateTime get_exposure_time() { if (metadata == null) return get_modification_time(); @@ -340,10 +340,10 @@ class ImportPreview : MediaSourceItem { if (duplicated_photo_id.is_valid()) { // Check exposure timestamp LibraryPhoto duplicated_photo = LibraryPhoto.global.fetch(duplicated_photo_id); - time_t photo_exposure_time = photo_import_source.get_exposure_time(); - time_t duplicated_photo_exposure_time = duplicated_photo.get_exposure_time(); + DateTime photo_exposure_time = photo_import_source.get_exposure_time(); + DateTime duplicated_photo_exposure_time = duplicated_photo.get_exposure_time(); - if (photo_exposure_time == duplicated_photo_exposure_time) { + if (photo_exposure_time.equal(duplicated_photo_exposure_time)) { duplicated_file = DuplicatedFile.create_from_photo_id( LibraryPhoto.global.get_basename_filesize_duplicate( get_import_source().get_filename(), (int64) filesize)); @@ -485,7 +485,7 @@ public class ImportPage : CheckerboardPage { private string filename; private uint64 filesize; private PhotoMetadata metadata; - private time_t exposure_time; + private DateTime exposure_time; private CameraImportJob? associated = null; private BackingPhotoRow? associated_file = null; private DuplicatedFile? duplicated_file; @@ -503,12 +503,13 @@ public class ImportPage : CheckerboardPage { assert(fulldir != null); filename = import_file.get_filename(); filesize = import_file.get_filesize(); - metadata = (import_file is PhotoImportSource) ? - (import_file as PhotoImportSource).get_metadata() : null; + var photo_import_source = import_file as PhotoImportSource; + metadata = (photo_import_source != null) ? + photo_import_source.get_metadata() : null; exposure_time = import_file.get_exposure_time(); } - public time_t get_exposure_time() { + public DateTime get_exposure_time() { return exposure_time; } @@ -516,8 +517,8 @@ public class ImportPage : CheckerboardPage { return duplicated_file; } - public override time_t get_exposure_time_override() { - return (import_file is VideoImportSource) ? get_exposure_time() : 0; + public override DateTime? get_exposure_time_override() { + return (import_file is VideoImportSource) ? get_exposure_time() : null; } public override string get_dest_identifier() { @@ -682,16 +683,13 @@ public class ImportPage : CheckerboardPage { private Gtk.Label camera_label = new Gtk.Label(null); private Gtk.CheckButton hide_imported; private Gtk.ProgressBar progress_bar = new Gtk.ProgressBar(); - private GPhoto.Camera camera; - private string uri; + private DiscoveredCamera dcamera; private bool busy = false; private bool refreshed = false; private GPhoto.Result refresh_result = GPhoto.Result.OK; private string refresh_error = null; - private string camera_name; private VolumeMonitor volume_monitor = null; private ImportPage? local_ref = null; - private string? icon; private ImportPageSearchViewFilter search_filter = new ImportPageSearchViewFilter(); private HideImportedViewFilter hide_imported_filter = new HideImportedViewFilter(); private CameraViewTracker tracker; @@ -707,28 +705,15 @@ public class ImportPage : CheckerboardPage { LIBRARY_ERROR } - public ImportPage(GPhoto.Camera camera, string uri, string? display_name = null, string? icon = null) { + public ImportPage(DiscoveredCamera dcamera) { base(_("Camera")); - this.camera = camera; - this.uri = uri; - this.import_sources = new ImportSourceCollection("ImportSources for %s".printf(uri)); - this.icon = icon; + this.dcamera = dcamera; + this.import_sources = new ImportSourceCollection("ImportSources for %s".printf(dcamera.uri)); tracker = new CameraViewTracker(get_view()); - // Get camera name. - if (null != display_name) { - camera_name = display_name; - } else { - GPhoto.CameraAbilities abilities; - GPhoto.Result res = camera.get_abilities(out abilities); - if (res != GPhoto.Result.OK) { - debug("Unable to get camera abilities: %s", res.to_full_string()); - camera_name = _("Camera"); - } - } - camera_label.set_text(camera_name); - set_page_name(camera_name); + camera_label.set_text(dcamera.display_name); + set_page_name(dcamera.display_name); // Mount.unmounted signal is *only* fired when a VolumeMonitor has been instantiated. this.volume_monitor = VolumeMonitor.get(); @@ -846,6 +831,14 @@ public class ImportPage : CheckerboardPage { return tracker; } + protected override string get_view_empty_icon() { + if (this.dcamera.icon != null) { + return this.dcamera.icon; + } + + return "camera-photo-symbolic"; + } + protected override string get_view_empty_message() { return _("The camera seems to be empty. No photos/videos found to import"); } @@ -855,8 +848,8 @@ public class ImportPage : CheckerboardPage { } private static int64 preview_comparator(void *a, void *b) { - return ((ImportPreview *) a)->get_import_source().get_exposure_time() - - ((ImportPreview *) b)->get_import_source().get_exposure_time(); + return nullsafe_date_time_comperator(((ImportPreview *) a)->get_import_source().get_exposure_time(), + ((ImportPreview *) b)->get_import_source().get_exposure_time()); } private static bool preview_comparator_predicate(DataObject object, Alteration alteration) { @@ -864,7 +857,7 @@ public class ImportPage : CheckerboardPage { } private int64 import_job_comparator(void *a, void *b) { - return ((CameraImportJob *) a)->get_exposure_time() - ((CameraImportJob *) b)->get_exposure_time(); + return nullsafe_date_time_comperator(((CameraImportJob *) a)->get_exposure_time(), ((CameraImportJob *) b)->get_exposure_time()); } protected override void init_collect_ui_filenames(Gee.List<string> ui_filenames) { @@ -896,11 +889,11 @@ public class ImportPage : CheckerboardPage { } public GPhoto.Camera get_camera() { - return camera; + return dcamera.gcamera; } public string get_uri() { - return uri; + return dcamera.uri; } public bool is_busy() { @@ -998,27 +991,9 @@ public class ImportPage : CheckerboardPage { } // if locked because it's mounted, offer to unmount - debug("Checking if %s is mounted…", uri); + debug("Checking if %s is mounted…", dcamera.uri); - File uri = File.new_for_uri(uri); - - Mount mount = null; - try { - mount = uri.find_enclosing_mount(null); - } catch (Error err) { - // error means not mounted - } - - // Could not find mount for gphoto2://, re-try with mtp:// - // It seems some devices are mounted using MTP and not gphoto2 daemon - if (mount == null && this.uri.has_prefix("gphoto2")) { - uri = File.new_for_uri("mtp" + this.uri.substring(7)); - try { - mount = uri.find_enclosing_mount(null); - } catch (Error err) { - // error means not mounted - } - } + var mount = dcamera.get_mount(); if (mount != null) { // it's mounted, offer to unmount for the user @@ -1128,7 +1103,7 @@ public class ImportPage : CheckerboardPage { * @param search_target The name of the directory to look for. */ private bool check_directory_exists(int fsid, string dir, string search_target) { - string? fulldir = get_fulldir(camera, camera_name, fsid, dir); + string? fulldir = get_fulldir(dcamera.gcamera, dcamera.display_name, fsid, dir); GPhoto.Result result; GPhoto.CameraList folders; @@ -1138,7 +1113,7 @@ public class ImportPage : CheckerboardPage { return false; } - result = camera.list_folders(fulldir, folders, spin_idle_context.context); + result = dcamera.gcamera.list_folders(fulldir, folders, spin_idle_context.context); if (result != GPhoto.Result.OK) { // fetching the list failed - can't determine whether specified dir is present return false; @@ -1167,7 +1142,7 @@ public class ImportPage : CheckerboardPage { update_status(busy, false); refresh_error = null; - refresh_result = camera.init(spin_idle_context.context); + refresh_result = dcamera.gcamera.init(spin_idle_context.context); // If we fail to claim the device, we might have run into a conflict // with gvfs-gphoto2-volume-monitor. Back off, try again after @@ -1209,7 +1184,7 @@ public class ImportPage : CheckerboardPage { Gee.ArrayList<ImportSource> import_list = new Gee.ArrayList<ImportSource>(); GPhoto.CameraStorageInformation[] sifs = null; - refresh_result = camera.get_storageinfo(out sifs, spin_idle_context.context); + refresh_result = dcamera.gcamera.get_storageinfo(out sifs, spin_idle_context.context); if (refresh_result == GPhoto.Result.OK) { for (int fsid = 0; fsid < sifs.length; fsid++) { // Check well-known video and image paths first to prevent accidental @@ -1302,7 +1277,7 @@ public class ImportPage : CheckerboardPage { progress_bar.set_text(""); progress_bar.set_fraction(0.0); - GPhoto.Result res = camera.exit(spin_idle_context.context); + GPhoto.Result res = dcamera.gcamera.exit(spin_idle_context.context); if (res != GPhoto.Result.OK) { // log but don't fail warning("Unable to unlock camera: %s", res.to_full_string()); @@ -1386,7 +1361,7 @@ public class ImportPage : CheckerboardPage { } private bool enumerate_files(int fsid, string dir, Gee.ArrayList<ImportSource> import_list) { - string? fulldir = get_fulldir(camera, camera_name, fsid, dir); + string? fulldir = get_fulldir(dcamera.gcamera, dcamera.display_name, fsid, dir); if (fulldir == null) { warning("Skipping enumerating %s: invalid folder name", dir); @@ -1401,7 +1376,7 @@ public class ImportPage : CheckerboardPage { return false; } - refresh_result = camera.list_files(fulldir, files, spin_idle_context.context); + refresh_result = dcamera.gcamera.list_files(fulldir, files, spin_idle_context.context); if (refresh_result != GPhoto.Result.OK) { warning("Unable to list files in %s: %s", fulldir, refresh_result.to_full_string()); @@ -1424,7 +1399,7 @@ public class ImportPage : CheckerboardPage { try { GPhoto.CameraFileInfo info; - if (!GPhoto.get_info(spin_idle_context.context, camera, fulldir, filename, out info)) { + if (!GPhoto.get_info(spin_idle_context.context, dcamera.gcamera, fulldir, filename, out info)) { warning("Skipping import of %s/%s: name too long", fulldir, filename); continue; @@ -1438,8 +1413,8 @@ public class ImportPage : CheckerboardPage { } if (VideoReader.is_supported_video_filename(filename)) { - VideoImportSource video_source = new VideoImportSource(camera_name, camera, - fsid, dir, filename, info.file.size, info.file.mtime); + VideoImportSource video_source = new VideoImportSource(dcamera.display_name, dcamera.gcamera, + fsid, dir, filename, info.file.size, new DateTime.from_unix_utc(info.file.mtime)); import_list.add(video_source); } else { // determine file format from type, and then from file extension @@ -1454,8 +1429,8 @@ public class ImportPage : CheckerboardPage { continue; } } - import_list.add(new PhotoImportSource(camera_name, camera, fsid, dir, filename, - info.file.size, info.file.mtime, file_format)); + import_list.add(new PhotoImportSource(dcamera.display_name, dcamera.gcamera, fsid, dir, filename, + info.file.size, new DateTime.from_unix_utc(info.file.mtime), file_format)); } progress_bar.pulse(); @@ -1479,7 +1454,7 @@ public class ImportPage : CheckerboardPage { return false; } - refresh_result = camera.list_folders(fulldir, folders, spin_idle_context.context); + refresh_result = dcamera.gcamera.list_folders(fulldir, folders, spin_idle_context.context); if (refresh_result != GPhoto.Result.OK) { warning("Unable to list folders in %s: %s", fulldir, refresh_result.to_full_string()); @@ -1498,8 +1473,12 @@ public class ImportPage : CheckerboardPage { return false; } - if (!enumerate_files(fsid, append_path(dir, subdir), import_list)) - return false; + if (subdir.has_prefix(".")) { + debug("Skipping hidden sub-folder %s in %s", subdir, dir); + } else { + if (!enumerate_files(fsid, append_path(dir, subdir), import_list)) + return false; + } } return true; @@ -1575,7 +1554,7 @@ public class ImportPage : CheckerboardPage { PhotoMetadata? metadata = null; if (!VideoReader.is_supported_video_filename(filename)) { try { - metadata = GPhoto.load_metadata(spin_idle_context.context, camera, fulldir, + metadata = GPhoto.load_metadata(spin_idle_context.context, dcamera.gcamera, fulldir, filename); } catch (Error err) { warning("Unable to fetch metadata for %s/%s: %s", fulldir, filename, @@ -1604,7 +1583,7 @@ public class ImportPage : CheckerboardPage { preview_fulldir = associated.get_fulldir(); preview_filename = associated.get_filename(); } - preview = GPhoto.load_preview(spin_idle_context.context, camera, preview_fulldir, + preview = GPhoto.load_preview(spin_idle_context.context, dcamera.gcamera, preview_fulldir, preview_filename, out preview_md5); } catch (Error err) { // only issue the warning message if we're not reading a video. GPhoto is capable @@ -1621,17 +1600,18 @@ public class ImportPage : CheckerboardPage { debug("camera MD5 %s: exif=%s preview=%s", filename, exif_only_md5, preview_md5); #endif - if (import_source is VideoImportSource) - (import_source as VideoImportSource).update(preview); + var video_import_source = import_source as VideoImportSource; + if (video_import_source != null) + video_import_source.update(preview); - if (import_source is PhotoImportSource) - (import_source as PhotoImportSource).update(preview, preview_md5, metadata, - exif_only_md5); + var photo_import_source = import_source as PhotoImportSource; + if (photo_import_source != null) + photo_import_source.update(preview, preview_md5, metadata, exif_only_md5); if (associated != null) { try { PhotoMetadata? associated_metadata = GPhoto.load_metadata(spin_idle_context.context, - camera, associated.get_fulldir(), associated.get_filename()); + dcamera.gcamera, associated.get_fulldir(), associated.get_filename()); associated.update(preview, preview_md5, associated_metadata, null); } catch (Error err) { warning("Unable to fetch metadata for %s/%s: %s", associated.get_fulldir(), @@ -1671,7 +1651,7 @@ public class ImportPage : CheckerboardPage { } private void import(Gee.Iterable<DataObject> items) { - GPhoto.Result res = camera.init(spin_idle_context.context); + GPhoto.Result res = dcamera.gcamera.init(spin_idle_context.context); if (res != GPhoto.Result.OK) { AppWindow.error_message(_("Unable to lock camera: %s").printf(res.to_full_string())); @@ -1712,14 +1692,14 @@ public class ImportPage : CheckerboardPage { jobs.add(import_job); } - debug("Importing %d files from %s", jobs.size, camera_name); + debug("Importing %d files from %s", jobs.size, dcamera.display_name); if (jobs.size > 0) { // see import_reporter() to see why this is held during the duration of the import assert(local_ref == null); local_ref = this; - BatchImport batch_import = new BatchImport(jobs, camera_name, import_reporter, + BatchImport batch_import = new BatchImport(jobs, dcamera.display_name, import_reporter, null, already_imported); batch_import.import_job_failed.connect(on_import_job_failed); batch_import.import_complete.connect(close_import); @@ -1811,7 +1791,7 @@ public class ImportPage : CheckerboardPage { } private void close_import() { - GPhoto.Result res = camera.exit(spin_idle_context.context); + GPhoto.Result res = dcamera.gcamera.exit(spin_idle_context.context); if (res != GPhoto.Result.OK) { // log but don't fail message("Unable to unlock camera: %s", res.to_full_string()); |