summaryrefslogtreecommitdiff
path: root/src/core/util.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/util.vala')
-rw-r--r--src/core/util.vala196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/core/util.vala b/src/core/util.vala
new file mode 100644
index 0000000..1846380
--- /dev/null
+++ b/src/core/util.vala
@@ -0,0 +1,196 @@
+/* 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.
+ */
+
+// SingletonCollection is a read-only collection designed to hold exactly one item in it. This
+// is far more efficient than creating a dummy collection (such as ArrayList) merely to pass around
+// a single item, particularly for signals which require Iterables and Collections.
+//
+// This collection cannot be used to store null.
+
+public class SingletonCollection<G> : Gee.AbstractCollection<G> {
+ private class SingletonIterator<G> : Object, Gee.Traversable<G>, Gee.Iterator<G> {
+ private SingletonCollection<G> c;
+ private bool done = false;
+ private G? current = null;
+
+ public SingletonIterator(SingletonCollection<G> c) {
+ this.c = c;
+ }
+
+ public bool read_only {
+ get { return done; }
+ }
+
+ public bool valid {
+ get { return done; }
+ }
+
+ public bool foreach(Gee.ForallFunc<G> f) {
+ return f(c.object);
+ }
+
+ public new G? get() {
+ return current;
+ }
+
+ public bool has_next() {
+ return false;
+ }
+
+ public bool next() {
+ if (done)
+ return false;
+
+ done = true;
+ current = c.object;
+
+ return true;
+ }
+
+ public void remove() {
+ if (!done) {
+ c.object = null;
+ current = null;
+ }
+
+ done = true;
+ }
+ }
+
+ private G? object;
+
+ public SingletonCollection(G object) {
+ this.object = object;
+ }
+
+ public override bool read_only {
+ get { return false; }
+ }
+
+ public override bool add(G object) {
+ warning("Cannot add to SingletonCollection");
+
+ return false;
+ }
+
+ public override void clear() {
+ object = null;
+ }
+
+ public override bool contains(G object) {
+ return this.object == object;
+ }
+
+ public override Gee.Iterator<G> iterator() {
+ return new SingletonIterator<G>(this);
+ }
+
+ public override bool remove(G item) {
+ if (item == object) {
+ object = null;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public override int size {
+ get {
+ return (object != null) ? 1 : 0;
+ }
+ }
+}
+
+// A Marker is an object for marking (selecting) DataObjects in a DataCollection to then perform
+// an action on all of them. This mechanism allows for performing mass operations in a generic
+// way, as well as dealing with the (perpetual) issue of removing items from a Collection within
+// an iterator.
+public interface Marker : Object {
+ public abstract void mark(DataObject object);
+
+ public abstract void unmark(DataObject object);
+
+ public abstract bool toggle(DataObject object);
+
+ public abstract void mark_many(Gee.Collection<DataObject> list);
+
+ public abstract void unmark_many(Gee.Collection<DataObject> list);
+
+ public abstract void mark_all();
+
+ // Returns the number of marked items, or the number of items when the marker was frozen
+ // and used.
+ public abstract int get_count();
+
+ // Returns a copy of the collection of marked items.
+ public abstract Gee.Collection<DataObject> get_all();
+}
+
+// MarkedAction is a callback to perform an action on the marked DataObject. Return false to
+// end iterating.
+public delegate bool MarkedAction(DataObject object, Object? user);
+
+// A ProgressMonitor allows for notifications of progress on operations on multiple items (via
+// the marked interfaces). Return false if the operation is cancelled and should end immediately.
+public delegate bool ProgressMonitor(uint64 current, uint64 total, bool do_event_loop = true);
+
+// UnknownTotalMonitor is useful when an interface cannot report the total count to a ProgressMonitor,
+// only a count, but the total is known by the caller.
+public class UnknownTotalMonitor {
+ private uint64 total;
+ private unowned ProgressMonitor wrapped_monitor;
+
+ public UnknownTotalMonitor(uint64 total, ProgressMonitor wrapped_monitor) {
+ this.total = total;
+ this.wrapped_monitor = wrapped_monitor;
+ }
+
+ public bool monitor(uint64 count, uint64 total) {
+ return wrapped_monitor(count, this.total);
+ }
+}
+
+// AggregateProgressMonitor is useful when several discrete operations are being performed against
+// a single ProgressMonitor.
+public class AggregateProgressMonitor {
+ private uint64 grand_total;
+ private unowned ProgressMonitor wrapped_monitor;
+ private uint64 aggregate_count = 0;
+ private uint64 last_count = uint64.MAX;
+
+ public AggregateProgressMonitor(uint64 grand_total, ProgressMonitor wrapped_monitor) {
+ this.grand_total = grand_total;
+ this.wrapped_monitor = wrapped_monitor;
+ }
+
+ public void next_step(string name) {
+ debug("next step: %s (%s/%s)", name, aggregate_count.to_string(), grand_total.to_string());
+ last_count = uint64.MAX;
+ }
+
+ public bool monitor(uint64 count, uint64 total) {
+ // add the difference from the last, unless a new step has started
+ aggregate_count += (last_count != uint64.MAX) ? (count - last_count) : count;
+ if (aggregate_count > grand_total)
+ aggregate_count = grand_total;
+
+ // save for next time
+ last_count = count;
+
+ return wrapped_monitor(aggregate_count, grand_total);
+ }
+}
+
+// Useful when debugging.
+public bool null_progress_monitor(uint64 count, uint64 total) {
+ return true;
+}
+
+
+double degrees_to_radians(double theta) {
+ return (theta * (GLib.Math.PI / 180.0));
+}