diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 09:06:59 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 09:06:59 +0200 |
commit | 4ea2cc3bd4a7d9b1c54a9d33e6a1cf82e7c8c21d (patch) | |
tree | d2e54377d14d604356c86862a326f64ae64dadd6 /src/core/SourceCollection.vala |
Imported Upstream version 0.18.1upstream/0.18.1
Diffstat (limited to 'src/core/SourceCollection.vala')
-rw-r--r-- | src/core/SourceCollection.vala | 221 |
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); + } +} + |