summaryrefslogtreecommitdiff
path: root/src/Commands.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/Commands.vala')
-rw-r--r--src/Commands.vala218
1 files changed, 217 insertions, 1 deletions
diff --git a/src/Commands.vala b/src/Commands.vala
index 7441a50..6924f82 100644
--- a/src/Commands.vala
+++ b/src/Commands.vala
@@ -920,7 +920,6 @@ public abstract class MovePhotosCommand : Command {
}
public override void execute() {
-
// create the new event
base.execute();
@@ -2507,3 +2506,220 @@ public class FlagUnflagCommand : MultipleDataSourceAtOnceCommand {
}
}
}
+
+#if ENABLE_FACES
+public class RemoveFacesFromPhotosCommand : SimpleProxyableCommand {
+ private Gee.Map<MediaSource, string> map_source_geometry = new Gee.HashMap<MediaSource, string>();
+
+ public RemoveFacesFromPhotosCommand(Face face, Gee.Collection<MediaSource> sources) {
+ base (face,
+ Resources.remove_face_from_photos_label(face.get_name(), sources.size),
+ face.get_name());
+
+ foreach (MediaSource source in sources) {
+ FaceLocation? face_location =
+ FaceLocation.get_face_location(face.get_face_id(), ((Photo) source).get_photo_id());
+ assert(face_location != null);
+
+ this.map_source_geometry.set(source, face_location.get_serialized_geometry());
+ }
+
+ LibraryPhoto.global.item_destroyed.connect(on_source_destroyed);
+ Video.global.item_destroyed.connect(on_source_destroyed);
+ }
+
+ ~RemoveFacesFromPhotosCommand() {
+ LibraryPhoto.global.item_destroyed.disconnect(on_source_destroyed);
+ Video.global.item_destroyed.disconnect(on_source_destroyed);
+ }
+
+ public override void execute_on_source(DataSource source) {
+ ((Face) source).detach_many(map_source_geometry.keys);
+ }
+
+ public override void undo_on_source(DataSource source) {
+ Face face = (Face) source;
+
+ face.attach_many(map_source_geometry.keys);
+ foreach (Gee.Map.Entry<MediaSource, string> entry in map_source_geometry.entries)
+ FaceLocation.create(face.get_face_id(), ((Photo) entry.key).get_photo_id(), entry.value);
+ }
+
+ private void on_source_destroyed(DataSource source) {
+ if (map_source_geometry.keys.contains((MediaSource) source))
+ get_command_manager().reset();
+ }
+}
+
+public class RenameFaceCommand : SimpleProxyableCommand {
+ private string old_name;
+ private string new_name;
+
+ public RenameFaceCommand(Face face, string new_name) {
+ base (face, Resources.rename_face_label(face.get_name(), new_name), face.get_name());
+
+ old_name = face.get_name();
+ this.new_name = new_name;
+ }
+
+ protected override void execute_on_source(DataSource source) {
+ if (!((Face) source).rename(new_name))
+ AppWindow.error_message(Resources.rename_face_exists_message(new_name));
+ }
+
+ protected override void undo_on_source(DataSource source) {
+ if (!((Face) source).rename(old_name))
+ AppWindow.error_message(Resources.rename_face_exists_message(old_name));
+ }
+}
+
+public class DeleteFaceCommand : SimpleProxyableCommand {
+ private Gee.Map<PhotoID?, string> photo_geometry_map = new Gee.HashMap<PhotoID?, string>
+ ((Gee.HashDataFunc)FaceLocation.photo_id_hash, (Gee.EqualDataFunc)FaceLocation.photo_ids_equal);
+
+ public DeleteFaceCommand(Face face) {
+ base (face, Resources.delete_face_label(face.get_name()), face.get_name());
+
+ // we can't use the Gee.Map returned by FaceLocation.get_locations_by_face
+ // because it will be modified in execute_on_source
+ Gee.Map<PhotoID?, FaceLocation>? temp = FaceLocation.get_locations_by_face(face);
+ assert(temp != null);
+ foreach (Gee.Map.Entry<PhotoID?, FaceLocation> entry in temp.entries)
+ photo_geometry_map.set(entry.key, entry.value.get_serialized_geometry());
+ }
+
+ protected override void execute_on_source(DataSource source) {
+ FaceID face_id = ((Face) source).get_face_id();
+ foreach (PhotoID photo_id in photo_geometry_map.keys)
+ FaceLocation.destroy(face_id, photo_id);
+
+ Face.global.destroy_marked(Face.global.mark(source), false);
+ }
+
+ protected override void undo_on_source(DataSource source) {
+ // merely instantiating the Face will rehydrate it ... should always work, because the
+ // undo stack is cleared if the proxy ever breaks
+ assert(source is Face);
+
+ foreach (Gee.Map.Entry<PhotoID?, string> entry in photo_geometry_map.entries) {
+ Photo? photo = LibraryPhoto.global.fetch(entry.key);
+
+ if (photo != null) {
+ Face face = (Face) source;
+
+ face.attach(photo);
+ FaceLocation.create(face.get_face_id(), entry.key, entry.value);
+ }
+ }
+ }
+}
+
+public class ModifyFacesCommand : SingleDataSourceCommand {
+ private MediaSource media;
+ private Gee.ArrayList<SourceProxy> to_add = new Gee.ArrayList<SourceProxy>();
+ private Gee.ArrayList<SourceProxy> to_remove = new Gee.ArrayList<SourceProxy>();
+ private Gee.Map<SourceProxy, string> to_update = new Gee.HashMap<SourceProxy, string>();
+ private Gee.Map<SourceProxy, string> geometries = new Gee.HashMap<SourceProxy, string>();
+
+ public ModifyFacesCommand(MediaSource media, Gee.Map<Face, string> new_face_list) {
+ base (media, Resources.MODIFY_FACES_LABEL, "");
+
+ this.media = media;
+
+ // Remove any face that's in the original list but not the new one
+ Gee.Collection<Face>? original_faces = Face.global.fetch_for_source(media);
+ if (original_faces != null) {
+ foreach (Face face in original_faces) {
+ if (!new_face_list.keys.contains(face)) {
+ SourceProxy proxy = face.get_proxy();
+
+ to_remove.add(proxy);
+ proxy.broken.connect(on_proxy_broken);
+
+ FaceLocation? face_location =
+ FaceLocation.get_face_location(face.get_face_id(), ((Photo) media).get_photo_id());
+ assert(face_location != null);
+
+ geometries.set(proxy, face_location.get_serialized_geometry());
+ }
+ }
+ }
+
+ // Add any face that's in the new list but not the original
+ foreach (Gee.Map.Entry<Face, string> entry in new_face_list.entries) {
+ if (original_faces == null || !original_faces.contains(entry.key)) {
+ SourceProxy proxy = entry.key.get_proxy();
+
+ to_add.add(proxy);
+ proxy.broken.connect(on_proxy_broken);
+
+ geometries.set(proxy, entry.value);
+ } else {
+ // If it is already in the original list we need to check if it's
+ // geometry has changed.
+ FaceLocation? face_location =
+ FaceLocation.get_face_location(entry.key.get_face_id(), ((Photo) media).get_photo_id());
+ assert(face_location != null);
+
+ string old_geometry = face_location.get_serialized_geometry();
+ if (old_geometry != entry.value) {
+ SourceProxy proxy = entry.key.get_proxy();
+
+ to_update.set(proxy, entry.value);
+ proxy.broken.connect(on_proxy_broken);
+
+ geometries.set(proxy, old_geometry);
+ }
+ }
+ }
+ }
+
+ ~ModifyFacesCommand() {
+ foreach (SourceProxy proxy in to_add)
+ proxy.broken.disconnect(on_proxy_broken);
+
+ foreach (SourceProxy proxy in to_remove)
+ proxy.broken.disconnect(on_proxy_broken);
+
+ foreach (SourceProxy proxy in to_update.keys)
+ proxy.broken.disconnect(on_proxy_broken);
+ }
+
+ public override void execute() {
+ foreach (SourceProxy proxy in to_add) {
+ Face face = (Face) proxy.get_source();
+ face.attach(media);
+ FaceLocation.create(face.get_face_id(), ((Photo) media).get_photo_id(), geometries.get(proxy));
+ }
+
+ foreach (SourceProxy proxy in to_remove)
+ ((Face) proxy.get_source()).detach(media);
+
+ foreach (Gee.Map.Entry<SourceProxy, string> entry in to_update.entries) {
+ Face face = (Face) entry.key.get_source();
+ FaceLocation.create(face.get_face_id(), ((Photo) media).get_photo_id(), entry.value);
+ }
+ }
+
+ public override void undo() {
+ foreach (SourceProxy proxy in to_add)
+ ((Face) proxy.get_source()).detach(media);
+
+ foreach (SourceProxy proxy in to_remove) {
+ Face face = (Face) proxy.get_source();
+ face.attach(media);
+ FaceLocation.create(face.get_face_id(), ((Photo) media).get_photo_id(), geometries.get(proxy));
+ }
+
+ foreach (SourceProxy proxy in to_update.keys) {
+ Face face = (Face) proxy.get_source();
+ FaceLocation.create(face.get_face_id(), ((Photo) media).get_photo_id(), geometries.get(proxy));
+ }
+ }
+
+ private void on_proxy_broken() {
+ get_command_manager().reset();
+ }
+}
+
+#endif