Commit 9e25c861 authored by Jim Nelson's avatar Jim Nelson

#370: Photo file deleted when removed from library. User confirms with dialog.

parent 37e3b913
......@@ -9,6 +9,8 @@ public abstract class BatchImportJob {
// it into the system, including database additions, thumbnail creation, and reporting it to AppWindow
// so it's properly added to various views and events.
public class BatchImport {
public static const int IMPORT_DIRECTORY_DEPTH = 3;
private class DateComparator : Comparator<Photo> {
public override int64 compare(Photo photo_a, Photo photo_b) {
return photo_a.get_exposure_time() - photo_b.get_exposure_time();
......@@ -40,7 +42,7 @@ public class BatchImport {
Time tm = Time.local(timestamp);
// build a directory tree inside the library:
// build a directory tree inside the library, as deep as IMPORT_DIRECTORY_DEPTH:
// yyyy/mm/dd
dir = dir.get_child("%04u".printf(tm.year + 1900));
dir = dir.get_child("%02u".printf(tm.month + 1));
......@@ -81,7 +83,12 @@ public class BatchImport {
private static ImportResult copy_file(File src, out File dest) {
PhotoExif exif = new PhotoExif(src);
time_t timestamp = query_file_modified(src);
time_t timestamp = 0;
try {
timestamp = query_file_modified(src);
} catch (Error err) {
critical("Unable to access file modification for %s: %s", src.get_path(), err.message);
}
bool collision;
dest = create_library_path(src.get_basename(), exif.get_exif(), timestamp, out collision);
......
......@@ -536,6 +536,19 @@ public class CollectionPage : CheckerboardPage {
}
private void on_remove() {
Gtk.MessageDialog dialog = new Gtk.MessageDialog(AppWindow.get_instance(), Gtk.DialogFlags.MODAL,
Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO,
"Removing these photos from your library will also delete their files in your %s directory. Continue?",
AppWindow.PHOTOS_DIR);
dialog.title = "Remove photos?";
Gtk.ResponseType result = (Gtk.ResponseType) dialog.run();
dialog.destroy();
if (result != Gtk.ResponseType.YES)
return;
// iterate over selected photos and remove them from entire system .. this will result
// in on_photo_removed being called, which we don't want in this case is because it will
// remove from the list while iterating, so disconnect the signals and do the work here
......
......@@ -462,7 +462,7 @@ public class Photo : Object {
return ThumbnailCache.fetch(photo_id, scale);
}
public void remove() {
public void remove(bool remove_original = true) {
// signal all interested parties prior to removal from map
removed();
......@@ -472,9 +472,15 @@ public class Photo : Object {
// remove exportable file
remove_exportable_file();
// remove from photo table -- should be wiped from storage now
photo_table.remove(photo_id);
// remove original
if (remove_original)
remove_original_file();
// remove from photo table -- should be wiped from storage now (other classes may have added
// photo_id to other parts of the database ... it's their responsibility to remove them
// when removed() is called)
photo_table.remove(photo_id);
// remove from global map
photo_map.remove(photo_id.id);
}
......@@ -509,6 +515,40 @@ public class Photo : Object {
}
}
private void remove_original_file() {
File file = get_file();
try {
file.delete(null);
} catch (Error err) {
// log error but don't abend, as this is not fatal to operation (also, could be
// the photo is removed because it could not be found during a verify)
message("Unable to delete original photo %s: %s", file.get_path(), err.message);
}
File parent = file;
// remove empty directories corresponding to imported path
for (int depth = 0; depth < BatchImport.IMPORT_DIRECTORY_DEPTH; depth++) {
parent = parent.get_parent();
if (parent == null)
break;
if (!query_is_directory_empty(parent))
break;
try {
parent.delete(null);
debug("Deleted empty directory %s", parent.get_path());
} catch (Error err) {
// again, log error but don't abend
message("Unable to delete empty directory %s: %s", parent.get_path(),
err.message);
}
}
}
public Currency check_currency() {
FileInfo info = null;
try {
......
......@@ -175,19 +175,23 @@ public uint64 query_total_file_size(File file_or_dir) throws Error {
return total_bytes;
}
public time_t query_file_modified(File file) {
FileInfo info = null;
try {
info = file.query_info(FILE_ATTRIBUTE_TIME_MODIFIED, FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
null);
} catch (Error err) {
critical("Unable to query modified time for %s: %s", file.get_path(), err.message);
return 0;
}
public time_t query_file_modified(File file) throws Error {
FileInfo info = file.query_info(FILE_ATTRIBUTE_TIME_MODIFIED, FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
null);
TimeVal timestamp = TimeVal();
info.get_modification_time(timestamp);
return timestamp.tv_sec;
}
public bool query_is_directory_empty(File dir) throws Error {
if (dir.query_file_type(FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null) != FileType.DIRECTORY)
return false;
FileEnumerator enumerator = dir.enumerate_children("*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
if (enumerator == null)
return false;
return enumerator.next_file(null) == null;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment