[geary/mjog/invert-folder-class-hierarchy: 17/72] Geary: Flip folder class hierarchy so remote extends local, not vice-versa




commit fa0d037fa762061f59031cacece5afdce0b3525e
Author: Michael Gratton <mike vee net>
Date:   Sat Sep 12 15:04:02 2020 +1000

    Geary: Flip folder class hierarchy so remote extends local, not vice-versa
    
    Add new `Geary.RemoteFolder` class that extends `Geary.Folder`. Remove
    remote-related API from the base class (including `open_async` and
    `close_async`) and add a minimal, abstract API for working with remotes
    to the new class.
    
    Remove `AbstractLocalFolder` since that's now redundant.

 po/POTFILES.in                                     |   2 +-
 .../plugin/mail-merge/mail-merge-folder.vala       |  23 +-
 src/engine/api/geary-abstract-local-folder.vala    |  69 -----
 src/engine/api/geary-folder.vala                   | 319 +--------------------
 src/engine/api/geary-remote-folder.vala            | 112 ++++++++
 src/engine/meson.build                             |   2 +-
 test/mock/mock-folder.vala                         |  35 ---
 7 files changed, 129 insertions(+), 433 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a5804402b..c0710e59d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -148,7 +148,6 @@ src/client/util/util-migrate.vala
 src/client/web-process/web-process-extension.vala
 src/console/main.vala
 src/engine/api/geary.vala
-src/engine/api/geary-abstract-local-folder.vala
 src/engine/api/geary-account-information.vala
 src/engine/api/geary-account.vala
 src/engine/api/geary-aggregated-folder-properties.vala
@@ -182,6 +181,7 @@ src/engine/api/geary-named-flag.vala
 src/engine/api/geary-named-flags.vala
 src/engine/api/geary-problem-report.vala
 src/engine/api/geary-progress-monitor.vala
+src/engine/api/geary-remote-folder.vala
 src/engine/api/geary-revokable.vala
 src/engine/api/geary-search-query.vala
 src/engine/api/geary-service-information.vala
diff --git a/src/client/plugin/mail-merge/mail-merge-folder.vala 
b/src/client/plugin/mail-merge/mail-merge-folder.vala
index 5c5a50c65..7d2dbd1e2 100644
--- a/src/client/plugin/mail-merge/mail-merge-folder.vala
+++ b/src/client/plugin/mail-merge/mail-merge-folder.vala
@@ -8,7 +8,7 @@
 /**
  * Plugin to Fill in and send email templates using a spreadsheet.
  */
-public class MailMerge.Folder : Geary.AbstractLocalFolder {
+public class MailMerge.Folder : Geary.Folder {
 
 
     private class EmailIdentifier : Geary.EmailIdentifier {
@@ -172,6 +172,12 @@ public class MailMerge.Folder : Geary.AbstractLocalFolder {
     }
 
 
+    /** Cancels loading if in progress and stops sending. */
+    public void close() {
+        this.loading.cancel();
+        set_sending(false);
+    }
+
     /** Starts or stops the folder sending mail. */
     public void set_sending(bool is_sending) {
         if (is_sending && !this.is_sending) {
@@ -183,17 +189,6 @@ public class MailMerge.Folder : Geary.AbstractLocalFolder {
         }
     }
 
-    /** {@inheritDoc} */
-    public override async bool close_async(GLib.Cancellable? cancellable = null)
-        throws GLib.Error {
-        var is_closing = yield base.close_async(cancellable);
-        if (is_closing) {
-            this.loading.cancel();
-            set_sending(false);
-        }
-        return is_closing;
-    }
-
     /** {@inheritDoc} */
     public override async Gee.Collection<Geary.EmailIdentifier> contains_identifiers(
         Gee.Collection<Geary.EmailIdentifier> ids,
@@ -212,7 +207,6 @@ public class MailMerge.Folder : Geary.AbstractLocalFolder {
                           Geary.Folder.ListFlags flags,
                           GLib.Cancellable? cancellable = null)
         throws GLib.Error {
-        check_open();
         var email = this.email.get(id);
         if (email == null) {
             throw new Geary.EngineError.NOT_FOUND(
@@ -229,8 +223,6 @@ public class MailMerge.Folder : Geary.AbstractLocalFolder {
                                Geary.Folder.ListFlags flags,
                                GLib.Cancellable? cancellable = null)
         throws GLib.Error {
-        check_open();
-
         var initial = initial_id as EmailIdentifier;
         if (initial_id != null && initial == null) {
             throw new Geary.EngineError.BAD_PARAMETERS(
@@ -278,7 +270,6 @@ public class MailMerge.Folder : Geary.AbstractLocalFolder {
                                       Geary.Folder.ListFlags flags,
                                       GLib.Cancellable? cancellable = null)
         throws GLib.Error {
-        check_open();
         Gee.List<Geary.Email> list = new Gee.ArrayList<Geary.Email>();
         foreach (var id in ids) {
             var email = this.email.get(id);
diff --git a/src/engine/api/geary-folder.vala b/src/engine/api/geary-folder.vala
index ed11a7af4..ceacafd88 100644
--- a/src/engine/api/geary-folder.vala
+++ b/src/engine/api/geary-folder.vala
@@ -18,41 +18,16 @@
  * sending), or as a representation of those found in a mailbox on a
  * remote mail server, such as those provided by an IMAP server. Email
  * messages are represented by the {@link Email} class, and many
- * folder methods will return collections of these. For folders that
- * represent a remote mailbox, the mailbox's email are cached locally,
- * and the set of cached messages may be a subset of those available
- * in the mailbox, depending on an account's settings. Email messages
- * may be partially cached, in the case of a new message having just
+ * folder methods will return collections of these.
+ *
+ * Folders that represent a remote folder extend {@link
+ * RemoteFolder}. These cache the remote folder's email locally, and
+ * the set of cached messages may be a subset of those available in
+ * the mailbox, depending on an account's settings. Email messages may
+ * be partially cached, in the case of a new message having just
  * arrived or a message with many large attachments that was not
  * completely downloaded.
  *
- * Folder objects must be opened (with {@link open_async} before using
- * most of its methods and should be closed with {@link close_async}
- * when completed, even if a previous method call has failed with an
- * IOError. Folders offer various open states indicating when its
- * "local" (disk or database) connection and "remote" (network)
- * connections are ready.  Generally the local connection opens first
- * and the remote connection takes time to establish. When in this
- * state, Folder's methods still operate, but will only return locally
- * stored information.
- *
- * The set of locally stored messages is called the folder's
- * ''vector'', and contains generally the most recent message in the
- * mailbox at the upper end, back through to some older message at the
- * start or lower end of the vector. Thus the ordering of the vector
- * is the ''natural'' ordering, based on the order in which messages
- * were appended to the folder, not when messages were sent or some
- * other criteria. For remote-backed folders, the engine will maintain
- * the vector in accordance with the value of {@link
- * AccountInformation.prefetch_period_days}, however the start of the
- * vector will be extended back past that over time and in response to
- * certain operations that cause the vector to be ''expanded'' ---
- * that is for additional messages to be loaded from the remote
- * server, extending the vector. The upper end of the vector is
- * similarly extended as new messages are appended to the folder by
- * another on the server or in response to user operations such as
- * moving a message.
- *
  * This class only offers a small selection of guaranteed
  * functionality (in particular, the ability to list its {@link
  * Email}).  Additional functionality for Folders is indicated by the
@@ -120,73 +95,6 @@ public abstract class Geary.Folder : BaseObject, Logging.Source {
 
     }
 
-
-    /**
-     * Indicates if a folder has been opened, and if so in which way.
-     */
-    public enum OpenState {
-
-        /**
-         * Indicates the folder has not been opened.
-         *
-         * Either no call to {@link open_async} has yet been made, or
-         * an equal number of calls to {@link close_async} have also
-         * been made.
-         */
-        CLOSED,
-
-        /**
-         * Indicates the folder has been opened locally only.
-         *
-         * The folder has been opened by a call to {@link open_async},
-         * but if the folder is backed by a remote mailbox, a
-         * connection to the remote mailbox has not yet been
-         * established.
-         */
-        LOCAL,
-
-        /**
-         * Indicates the folder has been opened with a remote connection.
-         *
-         * The folder has been opened by a call to {@link open_async},
-         * and a connection to the remote mailbox has also been
-         * made. Local-only folders will never reach this state.
-         */
-        REMOTE;
-    }
-
-    public enum OpenFailed {
-        LOCAL_ERROR,
-        REMOTE_ERROR,
-    }
-
-    /**
-     * Provides the reason why the folder is closing or closed when the {@link closed} signal
-     * is fired.
-     *
-     * The closed signal will be fired multiple times after a Folder is opened.  It is fired
-     * after the remote and local sessions close for various reasons, and fires once and only
-     * once when the folder is completely closed.
-     *
-     * LOCAL_CLOSE or LOCAL_ERROR is only called once, depending on the situation determining the
-     * value.  The same is true for REMOTE_CLOSE and REMOTE_ERROR.  A REMOTE_ERROR can trigger
-     * a LOCAL_CLOSE and vice-versa.  The values may be called in any order.
-     *
-     * When the local and remote stores have closed (either normally or due to errors), FOLDER_CLOSED
-     * will be sent.
-     */
-    public enum CloseReason {
-        LOCAL_CLOSE,
-        LOCAL_ERROR,
-        REMOTE_CLOSE,
-        REMOTE_ERROR,
-        FOLDER_CLOSED;
-
-        public bool is_error() {
-            return (this == LOCAL_ERROR) || (this == REMOTE_ERROR);
-        }
-    }
-
     [Flags]
     public enum CountChangeReason {
         NONE = 0,
@@ -195,36 +103,6 @@ public abstract class Geary.Folder : BaseObject, Logging.Source {
         REMOVED
     }
 
-    /**
-     * Flags that modify the behavior of {@link open_async}.
-     */
-    [Flags]
-    public enum OpenFlags {
-        /** If only //NONE// is set, the folder will be opened normally. */
-        NONE = 0,
-
-        /**
-         * Do not delay opening a connection to the server.
-         *
-         * This has no effect for folders that are not backed by a
-         * remote server.
-         *
-         * @see open_async
-         */
-        NO_DELAY;
-
-        /** Determines if any one of the given //flags// are set. */
-        public bool is_any_set(OpenFlags flags) {
-            return (this & flags) != 0;
-        }
-
-        /** Determines all of the given //flags// are set. */
-        public bool is_all_set(OpenFlags flags) {
-            return (this & flags) == flags;
-        }
-
-    }
-
     /**
      * Flags modifying how email is retrieved.
      */
@@ -301,69 +179,11 @@ public abstract class Geary.Folder : BaseObject, Logging.Source {
      */
     public abstract SpecialUse used_as { get; }
 
-    /** Monitor for notifying of progress when opening the folder. */
-    public abstract Geary.ProgressMonitor opening_monitor { get; }
-
     /** {@inheritDoc} */
     public Logging.Source? logging_parent {
         get { return this.account; }
     }
 
-    /**
-     * Fired when the folder moves through stages of being opened.
-     *
-     * It will fire at least once if the folder successfully opens,
-     * with the {@link OpenState} indicating what has been opened and
-     * the count indicating the number of messages in the folder. it
-     * may fire additional times as remote sessions are established
-     * and re-established after being lost.
-     *
-     * If //state// is {@link OpenState.LOCAL}, the local store for
-     * the folder has opened and the count reflects the number of
-     * messages in the local store.
-     *
-     * If //state// is {@link OpenState.REMOTE}, it indicates both the
-     * local store and a remote session has been established, and the
-     * count reflects the number of messages on the remote. This
-     * signal will not be fired with this value for a local-only folder.
-     *
-     * This signal will never fire with {@link OpenState.CLOSED} as a
-     * parameter.
-     *
-     * @see get_open_state
-     */
-    public signal void opened(OpenState state, int count);
-
-    /**
-     * Fired when {@link open_async} fails for one or more reasons.
-     *
-     * See open_async and {@link opened} for more information on how
-     * opening a Folder works, in particular how open_async may return
-     * immediately although the remote has not completely opened.
-     * This signal may be called in the context of, or after
-     * completion of, open_async.  It will ''not'' be called after
-     * {@link close_async} has completed, however.
-     *
-     * Note that this signal may be fired ''and'' open_async throw an
-     * Error.
-     *
-     * This signal may be fired more than once before the Folder is
-     * closed, especially in the case of a remote session
-     */
-    public signal void open_failed(OpenFailed failure, Error? err);
-
-    /**
-     * Fired when the Folder is closed, either by the caller or due to
-     * errors in the local or remote store(s).
-     *
-     * It will fire a number of times: to report how the local store
-     * closed (gracefully or due to error), how the remote closed
-     * (similarly) and finally with {@link CloseReason.FOLDER_CLOSED}.
-     * The first two may come in either order; the third is always the
-     * last.
-     */
-    public signal void closed(CloseReason reason);
-
     /**
      * Fired when email has been appended to the folder.
      *
@@ -435,131 +255,8 @@ public abstract class Geary.Folder : BaseObject, Logging.Source {
     public signal void use_changed(SpecialUse old_use, SpecialUse new_use);
 
 
-    /** Determines if a folder has been opened, and if so in which way. */
-    public abstract OpenState get_open_state();
-
     /**
-     * Marks the folder's operations as being required for use.
-     *
-     * A folder object must be opened before most operations may be
-     * performed on it. Depending on the folder implementation this
-     * might entail opening a network connection or setting the
-     * connection to a particular state, opening a file or database,
-     * and so on. In general, a Folder's local store should open
-     * immediately, hence if this call returns with error, {@link
-     * get_open_state} should return {@link OpenState.LOCAL}.
-     *
-     * For folders that are backed by a remote mailbox, it may take
-     * time for a remote connection to be established (if ever), and
-     * so it is possible for this method to complete even though a
-     * remote connection is not available. In this case the folder's
-     * state and the email messages the its contains are backed by a
-     * local cache, and may not reflect the full state of the remote
-     * mailbox. Hence both folder and email state may subsequently be
-     * changed (such as their position) after the remote connection
-     * has been established and the local and remote stores have been
-     * synchronised. Use signals such as {@link email_appended} to be
-     * notified of such changes.
-     *
-     * Connecting to the {@link opened} signal can be used to be
-     * notified when a remote connection has been established. Making
-     * a method call on a folder that requires accessing the remote
-     * mailbox before {@link OpenState.REMOTE} has been sent via this
-     * signal will result in that call blocking until the remote is
-     * open, the folder closes, or an error occurs. However it is also
-     * possible for some methods to return early without waiting,
-     * depending on prior information of the folder. See {@link
-     * list_email_by_id_async} for special notes on its
-     * operation.
-     *
-     * In some cases, establishing a remote connection may be
-     * performed lazily, that is only when first needed. If however
-     * {@link OpenFlags.NO_DELAY} is passed as an argument it will
-     * instead force an immediate opening of the remote
-     * connection. This still will not occur in the context of the
-     * this method all call, but it will ensure the a connection is
-     * initiated immediately. Since establishing remote connections is
-     * costly, use this only when it's known that remote calls or
-     * remote notifications to the Folder are imminent or monitoring
-     * the Folder is vital (such as with the Inbox).
-     *
-     * If the Folder has been opened by a call to this method
-     * previously, an internal open count is incremented and the
-     * method returns. There are no other side-effects. This means
-     * it's possible for the open_flags parameter to be ignored. See
-     * the returned result for more information.
-     *
-     * A Folder may safely be reopened after it has been closed. This
-     * allows for Folder objects to be emitted by the Account object
-     * cheaply, but the client should only have a few open at a time,
-     * as each may represent an expensive resource (such as a network
-     * connection).
-     *
-     * If there is an error while opening, "open-failed" will be
-     * fired.  (See that signal for more information on how many times
-     * it may fire, and when.)  To prevent the Folder from going into
-     * a halfway state, it will immediately schedule a close_async()
-     * to cleanup, and those associated signals will be fired as well.
-     *
-     * Returns false if already opened.
-     */
-    public abstract async bool open_async(OpenFlags open_flags,
-                                          Cancellable? cancellable = null)
-        throws Error;
-
-    /**
-     * Marks one use of the folder's operations as being completed.
-     *
-     * The folder must be closed when operations on it are concluded.
-     * Depending on the implementation this might entail closing a
-     * network connection or reverting it to another state, or closing
-     * file handles or database connections.
-     *
-     * If the folder is open, an internal open count is decremented.
-     * If it remains above zero, the method returns with no other
-     * side-effects.  If it decrements to zero, the folder will start
-     * to close tearing down network connections, closing files, and
-     * so-forth. The {@link closed} signal can be used to be notified
-     * of progress closing the folder.  Use {@link
-     * wait_for_close_async} to block until the folder is completely
-     * closed.
-     *
-     * Returns true if the open count decrements to zero and the
-     * folder is closing, or if it is already closed.
-     *
-     * @see open_async
-     */
-    public abstract async bool close_async(Cancellable? cancellable = null) throws Error;
-
-    /**
-     * Wait for the {@link Folder} to fully close.
-     *
-     * This will ''always'' block until the folder is closed, even if
-     * it's not open.
-     */
-    public abstract async void wait_for_close_async(Cancellable? cancellable = null) throws Error;
-
-    /**
-     * Synchronises the local folder with the remote mailbox.
-     *
-     * If backed by a remote folder, this ensures that the end of the
-     * vector is up to date with the end of the remote mailbox, and
-     * that all messages in the vector satisfy the minimum
-     * requirements for being used by the engine.
-     *
-     * The folder must be opened prior to attempting this operation.
-     */
-    public abstract async void synchronise_remote(GLib.Cancellable? cancellable)
-        throws GLib.Error;
-
-    /**
-     * Determines the email identifiers that are contained in the folder.
-     *
-     * The returned collection will be a subset of the given input
-     * collection that contains an input identifier only if that
-     * identifier belongs to an email contained by the folder.
-     *
-     * The Folder must be opened prior to attempting this operation.
+     * Determines which of the given identifiers are contained by the folder.
      */
     public abstract async Gee.Collection<EmailIdentifier> contains_identifiers(
         Gee.Collection<EmailIdentifier> ids,
diff --git a/src/engine/api/geary-remote-folder.vala b/src/engine/api/geary-remote-folder.vala
new file mode 100644
index 000000000..de3597df7
--- /dev/null
+++ b/src/engine/api/geary-remote-folder.vala
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2016 Software Freedom Conservancy Inc.
+ * Copyright © 2018-2020 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * A folder that is backed by a remote email service.
+ *
+ * While {@link Folder} provides a means to access and manipulate
+ * locally stored email, this class provides a means to update and
+ * synchronise with a folder that exists on a remote email service.
+ *
+ * The set of locally stored messages is called the folder's
+ * ''vector'', and contains generally the most recent message in the
+ * mailbox at the upper end, back through to some older message at the
+ * start or lower end of the vector. The vector may not contain all
+ * email present in the remote folder, but it should generally always
+ * contain the most recent. The ordering of the vector is the
+ * ''natural'' ordering, based on the order in which messages were
+ * appended to the folder, not when messages were sent or some other
+ * criteria.
+ *
+ * Several operations cause the vector to be updated. Both {@link
+ * start_monitoring} and {@link synchronise} will ensure that the
+ * vector's upper end is up-to-date with the remote, so that it
+ * contains the most recent email found in the remote folder. The
+ * engine will automatically maintain the lower end of the vector in
+ * accordance with the value of {@link
+ * AccountInformation.prefetch_period_days}, however the start of the
+ * vector can be extended back past that over time via {@link
+ * expand_vector}, causing the lower end of the vector to be
+ * temporarily ''expanded''.
+ */
+public abstract class Geary.RemoteFolder : Folder {
+
+
+    /**
+     * Determines if the folder is checking for remote changes to email.
+     *
+     * @see start_monitoring
+     * @see stop_monitoring
+     */
+    public abstract bool is_monitoring { get; }
+
+    /**
+     * Determines if the folder's local vector contains all remote email.
+     *
+     * This property is not guaranteed to be accurate at all times. It
+     * is only updated whenever a connection to the remote folder is
+     * established, i.e. by {@link start_monitoring}, {@link
+     * synchronise}, {@link expand_vector} and others.
+     */
+    public abstract bool is_fully_expanded { get; }
+
+
+    /**
+     * Starts the folder checking for remote changes to email.
+     *
+     * Depending on the implementation, this may require opening a
+     * connection to the server, having the remote folder selected,
+     * and so on.
+     *
+     * This method does not wait for any remote connection to be made,
+     * it simply flags that monitoring should occur. If the host is
+     * online, a connection to the remote folder will be established
+     * in the background and an implicit call to {@link synchronise}
+     * will be made. If the host is offline or if it goes offline
+     * sometime later, the folder will wait until being back online
+     * before re-connecting and re-sync'ing.
+     *
+     * @see stop_monitoring
+     */
+    public abstract void start_monitoring();
+
+    /**
+     * Stops the folder checking for remote changes to email.
+     *
+     * @see start_monitoring
+     */
+    public abstract void stop_monitoring();
+
+    /**
+     * Synchronises the folder's contents with the remote.
+     *
+     * Depending on the implementation, this may require opening a
+     * connection to the server, having the remote folder open, and so
+     * on.
+     *
+     * This method requires the host is online, an error will be
+     * thrown if the remote server cannot be reached.
+     */
+    public abstract async void synchronise(GLib.Cancellable? cancellable)
+        throws GLib.Error;
+
+    /**
+     * Extends the lower, start of the folder back past the usual
+     * limit.
+     *
+     * Depending on the implementation, this may require opening a
+     * connection to the server, having the remote folder open, and so
+     * on.
+     *
+     * This method requires the host is online, an error will be
+     * thrown if the remote server cannot be reached.
+     */
+    public abstract async void expand_vector(GLib.Cancellable? cancellable)
+        throws GLib.Error;
+
+}
diff --git a/src/engine/meson.build b/src/engine/meson.build
index a29daf0b0..a5e86fd6c 100644
--- a/src/engine/meson.build
+++ b/src/engine/meson.build
@@ -1,7 +1,6 @@
 # Geary engine
 engine_vala_sources = files(
   'api/geary.vala',
-  'api/geary-abstract-local-folder.vala',
   'api/geary-account.vala',
   'api/geary-account-information.vala',
   'api/geary-aggregated-folder-properties.vala',
@@ -35,6 +34,7 @@ engine_vala_sources = files(
   'api/geary-named-flags.vala',
   'api/geary-problem-report.vala',
   'api/geary-progress-monitor.vala',
+  'api/geary-remote-folder.vala',
   'api/geary-revokable.vala',
   'api/geary-search-query.vala',
   'api/geary-service-information.vala',
diff --git a/test/mock/mock-folder.vala b/test/mock/mock-folder.vala
index 59e5a220d..ebf73f218 100644
--- a/test/mock/mock-folder.vala
+++ b/test/mock/mock-folder.vala
@@ -26,10 +26,6 @@ public class Mock.Folder : Geary.Folder,
         get { return this._used_as; }
     }
 
-    public override Geary.ProgressMonitor opening_monitor {
-        get { return this._opening_monitor; }
-    }
-
     protected Gee.Queue<ValaUnit.ExpectedCall> expected {
         get; set; default = new Gee.LinkedList<ValaUnit.ExpectedCall>();
     }
@@ -54,37 +50,6 @@ public class Mock.Folder : Geary.Folder,
         this._opening_monitor = monitor;
     }
 
-    public override Geary.Folder.OpenState get_open_state() {
-        return Geary.Folder.OpenState.CLOSED;
-    }
-
-    public override async bool open_async(Geary.Folder.OpenFlags open_flags,
-                                          GLib.Cancellable? cancellable = null)
-        throws GLib.Error {
-        return yield boolean_call_async(
-            "open_async",
-            { int_arg(open_flags), cancellable },
-            false
-        );
-    }
-
-    public override async bool close_async(GLib.Cancellable? cancellable = null)
-        throws GLib.Error {
-        return yield boolean_call_async(
-            "close_async", { cancellable }, false
-        );
-    }
-
-    public override async void wait_for_close_async(GLib.Cancellable? cancellable = null)
-    throws GLib.Error {
-        throw new Geary.EngineError.UNSUPPORTED("Mock method");
-    }
-
-    public override async void synchronise_remote(GLib.Cancellable? cancellable)
-        throws GLib.Error {
-        void_call("synchronise_remote", { cancellable });
-    }
-
     public override async Gee.Collection<Geary.EmailIdentifier> contains_identifiers(
         Gee.Collection<Geary.EmailIdentifier> ids,
         GLib.Cancellable? cancellable = null)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]