summaryrefslogtreecommitdiff
path: root/src/core/SourceCollection.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SourceCollection.vala')
-rw-r--r--src/core/SourceCollection.vala221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/core/SourceCollection.vala b/src/core/SourceCollection.vala
new file mode 100644
index 0000000..020df0e
--- /dev/null
+++ b/src/core/SourceCollection.vala
@@ -0,0 +1,221 @@
+/* Copyright 2011-2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+public abstract class SourceCollection : DataCollection {
+ private class DestroyCounter : Object {
+ public Marker remove_marker;
+ public Gee.ArrayList<DataSource> notify_list = new Gee.ArrayList<DataSource>();
+ public Gee.ArrayList<MediaSource> not_removed = new Gee.ArrayList<MediaSource>();
+
+ public DestroyCounter(Marker remove_marker) {
+ this.remove_marker = remove_marker;
+ }
+ }
+
+ // When this signal is fired, the items are about to be unlinked from the collection. The
+ // appropriate remove signals will follow.
+ public virtual signal void items_unlinking(Gee.Collection<DataSource> unlinking) {
+ }
+
+ // When this signal is fired, the items are being relinked to the collection. The appropriate
+ // add signals have already been fired.
+ public virtual signal void items_relinked(Gee.Collection<DataSource> relinked) {
+ }
+
+ // When this signal is fired, the item is still part of the collection but its own destroy()
+ // has already been called.
+ public virtual signal void item_destroyed(DataSource source) {
+ }
+
+ // When this signal is fired, the item is still part of the collection but its own destroy()
+ // has already been called.
+ public virtual signal void items_destroyed(Gee.Collection<DataSource> destroyed) {
+ }
+
+ // When this signal is fired, the unlinked item has been unlinked from the collection previously
+ // and its destroy() has been called.
+ public virtual signal void unlinked_destroyed(DataSource source) {
+ }
+
+ // When this signal is fired, the backlink to the ContainerSource has already been removed.
+ public virtual signal void backlink_removed(SourceBacklink backlink,
+ Gee.Collection<DataSource> sources) {
+ }
+
+ private Gee.MultiMap<SourceBacklink, DataSource>? backlinks = null;
+
+ public SourceCollection(string name) {
+ base (name);
+ }
+
+ public abstract bool holds_type_of_source(DataSource source);
+
+ protected virtual void notify_items_unlinking(Gee.Collection<DataSource> unlinking) {
+ items_unlinking(unlinking);
+ }
+
+ protected virtual void notify_items_relinked(Gee.Collection<DataSource> relinked) {
+ items_relinked(relinked);
+ }
+
+ protected virtual void notify_item_destroyed(DataSource source) {
+ item_destroyed(source);
+ }
+
+ protected virtual void notify_items_destroyed(Gee.Collection<DataSource> destroyed) {
+ items_destroyed(destroyed);
+ }
+
+ // This is only called by DataSource.
+ public virtual void notify_unlinked_destroyed(DataSource unlinked) {
+ unlinked_destroyed(unlinked);
+ }
+
+ protected virtual void notify_backlink_removed(SourceBacklink backlink,
+ Gee.Collection<DataSource> sources) {
+ backlink_removed(backlink, sources);
+ }
+
+ protected override bool valid_type(DataObject object) {
+ return object is DataSource;
+ }
+
+ // Destroy all marked items and optionally have them delete their backing. Returns the
+ // number of items which failed to delete their backing (if delete_backing is true) or zero.
+ public int destroy_marked(Marker marker, bool delete_backing, ProgressMonitor? monitor = null,
+ Gee.List<MediaSource>? not_removed = null) {
+ DestroyCounter counter = new DestroyCounter(start_marking());
+
+ if (delete_backing)
+ act_on_marked(marker, destroy_and_delete_source, monitor, counter);
+ else
+ act_on_marked(marker, destroy_source, monitor, counter);
+
+ // notify of destruction
+ foreach (DataSource source in counter.notify_list)
+ notify_item_destroyed(source);
+ notify_items_destroyed(counter.notify_list);
+
+ // remove once all destroyed
+ remove_marked(counter.remove_marker);
+
+ if (null != not_removed) {
+ not_removed.add_all(counter.not_removed);
+ }
+
+ return counter.not_removed.size;
+ }
+
+ private bool destroy_and_delete_source(DataObject object, Object? user) {
+ bool success = false;
+ try {
+ success = ((DataSource) object).internal_delete_backing();
+ } catch (Error err) {
+ success = false;
+ }
+
+ if (!success && object is MediaSource) {
+ ((DestroyCounter) user).not_removed.add((MediaSource) object);
+ }
+
+ return destroy_source(object, user) && success;
+ }
+
+ private bool destroy_source(DataObject object, Object? user) {
+ DataSource source = (DataSource) object;
+
+ source.internal_mark_for_destroy();
+ source.destroy();
+
+ ((DestroyCounter) user).remove_marker.mark(source);
+ ((DestroyCounter) user).notify_list.add(source);
+
+ return true;
+ }
+
+ // This is only called by DataSource.
+ public void internal_backlink_set(DataSource source, SourceBacklink backlink) {
+ if (backlinks == null) {
+ backlinks = new Gee.HashMultiMap<SourceBacklink, DataSource>(SourceBacklink.hash_func,
+ SourceBacklink.equal_func);
+ }
+
+ backlinks.set(backlink, source);
+ }
+
+ // This is only called by DataSource.
+ public void internal_backlink_removed(DataSource source, SourceBacklink backlink) {
+ assert(backlinks != null);
+
+ bool removed = backlinks.remove(backlink, source);
+ assert(removed);
+ }
+
+ public virtual bool has_backlink(SourceBacklink backlink) {
+ return backlinks != null ? backlinks.contains(backlink) : false;
+ }
+
+ public Gee.Collection<DataSource>? unlink_marked(Marker marker, ProgressMonitor? monitor = null) {
+ Gee.ArrayList<DataSource> list = new Gee.ArrayList<DataSource>();
+ act_on_marked(marker, prepare_for_unlink, monitor, list);
+
+ if (list.size == 0)
+ return null;
+
+ notify_items_unlinking(list);
+
+ remove_marked(mark_many(list));
+
+ return list;
+ }
+
+ private bool prepare_for_unlink(DataObject object, Object? user) {
+ DataSource source = (DataSource) object;
+
+ source.notify_unlinking(this);
+ ((Gee.List<DataSource>) user).add(source);
+
+ return true;
+ }
+
+ public void relink(DataSource source) {
+ source.notify_relinking(this);
+
+ add(source);
+ notify_items_relinked((Gee.Collection<DataSource>) get_singleton(source));
+
+ source.notify_relinked();
+ }
+
+ public void relink_many(Gee.Collection<DataSource> relink) {
+ if (relink.size == 0)
+ return;
+
+ foreach (DataSource source in relink)
+ source.notify_relinking(this);
+
+ add_many(relink);
+ notify_items_relinked(relink);
+
+ foreach (DataSource source in relink)
+ source.notify_relinked();
+ }
+
+ public virtual void remove_backlink(SourceBacklink backlink) {
+ if (backlinks == null)
+ return;
+
+ // create copy because the DataSources will be removing the backlinks
+ Gee.ArrayList<DataSource> sources = new Gee.ArrayList<DataSource>();
+ sources.add_all(backlinks.get(backlink));
+
+ foreach (DataSource source in sources)
+ source.remove_backlink(backlink);
+
+ notify_backlink_removed(backlink, sources);
+ }
+}
+