Make it easier to obtain folders from path objects from Geary.Account

Replace async folder accessors with sync versions, add a means of
obtaining a folder path from its serialised form.
This commit is contained in:
Michael Gratton 2019-04-14 20:57:31 +10:00 committed by Michael James Gratton
parent 01a154bc5f
commit f7488453d0
7 changed files with 115 additions and 93 deletions

View file

@ -320,6 +320,48 @@ public abstract class Geary.Account : BaseObject {
public abstract EmailIdentifier to_email_identifier(GLib.Variant serialised)
throws EngineError.BAD_PARAMETERS;
/**
* Returns the folder path from its serialised form.
*
* This is useful for converting a string representation of a
* folder path back into an actual instance of a path. This does
* not guarantee that the folder represented by the path will
* exist.
*
* @see FolderPath.to_variant
* @throws EngineError.BAD_PARAMETERS when the variant is not the
* have the correct type or if no folder root with an appropriate
* label exists.
*/
public abstract FolderPath to_folder_path(GLib.Variant serialised)
throws EngineError.BAD_PARAMETERS;
/**
* Determines if a folder is known to the engine.
*
* This method only considers currently known folders, it does not
* check the remote to see if a previously folder exists.
*/
public virtual bool has_folder(FolderPath path) {
try {
get_folder(path);
return true;
} catch (EngineError.NOT_FOUND err) {
return false;
}
}
/**
* Returns the folder represented by a specific path.
*
* This method only considers currently known folders, it does not
* check the remote to see if a previously folder exists.
*
* @throws EngineError.NOT_FOUND if the folder does not exist.
*/
public abstract Folder get_folder(FolderPath path)
throws EngineError.NOT_FOUND;
/**
* Lists all the currently-available folders found under the parent path
* unless it's null, in which case it lists all the root folders. If the
@ -347,26 +389,6 @@ public abstract class Geary.Account : BaseObject {
*/
public abstract Geary.ContactStore get_contact_store();
/**
* Returns true if the folder exists.
*
* This method never throws EngineError.NOT_FOUND.
*/
public abstract async bool folder_exists_async(Geary.FolderPath path, Cancellable? cancellable = null)
throws Error;
/**
* Fetches a Folder object corresponding to the supplied path. If the backing medium does
* not have a record of a folder at the path, EngineError.NOT_FOUND will be thrown.
*
* The same Geary.Folder object (instance) will be returned if the same path is submitted
* multiple times. This means that multiple callers may be holding references to the same
* Folders. This is important when thinking of opening and closing folders and signal
* notifications.
*/
public abstract async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error;
/**
* Returns the folder representing the given special folder type. If no such folder exists,
* null is returned.

View file

@ -41,7 +41,7 @@ public class Geary.App.EmailStore : BaseObject {
foreach (Geary.FolderPath path in folders.get(email)) {
Geary.Folder folder;
try {
folder = yield account.fetch_folder_async(path, cancellable);
folder = account.get_folder(path);
} catch (Error e) {
debug("Error getting a folder from path %s: %s", path.to_string(), e.message);
continue;
@ -108,33 +108,23 @@ public class Geary.App.EmailStore : BaseObject {
emails, cancellable);
}
private async Gee.HashMap<Geary.FolderPath, Geary.Folder> get_folder_instances_async(
Gee.Collection<Geary.FolderPath> paths, Cancellable? cancellable) throws Error {
Gee.HashMap<Geary.FolderPath, Geary.Folder> folders
= new Gee.HashMap<Geary.FolderPath, Geary.Folder>();
foreach (Geary.FolderPath path in paths) {
Geary.Folder folder = yield account.fetch_folder_async(path, cancellable);
folders.set(path, folder);
}
return folders;
}
private Geary.FolderPath? next_folder_for_operation(AsyncFolderOperation operation,
Gee.MultiMap<Geary.FolderPath, Geary.EmailIdentifier> folders_to_ids,
Gee.Map<Geary.FolderPath, Geary.Folder> folders) throws Error {
private FolderPath?
next_folder_for_operation(AsyncFolderOperation operation,
Gee.MultiMap<FolderPath,EmailIdentifier> folders_to_ids)
throws GLib.Error {
bool best_is_open = false;
int best_count = 0;
Geary.FolderPath? best = null;
foreach (Geary.FolderPath path in folders_to_ids.get_keys()) {
assert(folders.has_key(path));
if (!folders.get(path).get_type().is_a(operation.folder_type))
Folder folder = this.account.get_folder(path);
if (!folder.get_type().is_a(operation.folder_type))
continue;
int count = folders_to_ids.get(path).size;
if (count == 0)
continue;
if (folders.get(path).get_open_state() == Geary.Folder.OpenState.REMOTE) {
if (folder.get_open_state() == Geary.Folder.OpenState.REMOTE) {
if (!best_is_open) {
best_is_open = true;
best_count = 0;
@ -167,12 +157,9 @@ public class Geary.App.EmailStore : BaseObject {
Gee.MultiMap<Geary.FolderPath, Geary.EmailIdentifier> folders_to_ids
= Geary.Collection.reverse_multi_map<Geary.EmailIdentifier, Geary.FolderPath>(ids_to_folders);
Gee.HashMap<Geary.FolderPath, Geary.Folder> folders
= yield get_folder_instances_async(folders_to_ids.get_keys(), cancellable);
Geary.FolderPath? path;
while ((path = next_folder_for_operation(operation, folders_to_ids, folders)) != null) {
Geary.Folder folder = folders.get(path);
while ((path = next_folder_for_operation(operation, folders_to_ids)) != null) {
Geary.Folder folder = this.account.get_folder(path);
Gee.Collection<Geary.EmailIdentifier> ids = folders_to_ids.get(path);
assert(ids.size > 0);

View file

@ -336,7 +336,7 @@ private class Geary.ImapDB.SearchFolder : Geary.SearchFolder, Geary.FolderSuppor
= Geary.Collection.reverse_multi_map<Geary.EmailIdentifier, Geary.FolderPath>(ids_to_folders);
foreach (Geary.FolderPath path in folders_to_ids.get_keys()) {
Geary.Folder folder = yield account.fetch_folder_async(path, cancellable);
Geary.Folder folder = account.get_folder(path);
Geary.FolderSupport.Remove? remove = folder as Geary.FolderSupport.Remove;
if (remove == null)
continue;

View file

@ -434,6 +434,34 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
throw new EngineError.BAD_PARAMETERS("Unknown serialised type: %c", type);
}
/** {@inheritDoc} */
public override FolderPath to_folder_path(GLib.Variant serialised)
throws EngineError.BAD_PARAMETERS {
FolderPath? path = null;
try {
path = this.local.imap_folder_root.from_variant(serialised);
} catch (EngineError.BAD_PARAMETERS err) {
path = this.local_folder_root.from_variant(serialised);
}
return path;
}
/** {@inheritDoc} */
public override Folder get_folder(FolderPath path)
throws EngineError.NOT_FOUND {
Folder? folder = this.folder_map.get(path);
if (folder == null) {
folder = this.local_only.get(path);
if (folder == null) {
throw new EngineError.NOT_FOUND(
"Folder not found: %s", path.to_string()
);
}
}
return folder;
}
/** {@inheritDoc} */
public override Gee.Collection<Geary.Folder> list_matching_folders(Geary.FolderPath? parent)
throws Error {
check_open();
@ -461,33 +489,6 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
return local.contact_store;
}
/** {@inheritDoc} */
public override async bool folder_exists_async(Geary.FolderPath path,
Cancellable? cancellable = null)
throws Error {
check_open();
return this.local_only.has_key(path) || this.folder_map.has_key(path);
}
/** {@inheritDoc} */
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null)
throws Error {
check_open();
Geary.Folder? folder = this.local_only.get(path);
if (folder == null) {
folder = this.folder_map.get(path);
if (folder == null) {
throw new EngineError.NOT_FOUND(
"Folder not found: %s", path.to_string()
);
}
}
return folder;
}
public override async Geary.Folder get_required_special_folder_async(Geary.SpecialFolderType special,
Cancellable? cancellable) throws Error {
if (!(special in get_supported_special_folders())) {
@ -1125,9 +1126,7 @@ internal class Geary.ImapEngine.LoadFolders : AccountOperation {
path = this.local.imap_folder_root.copy(path);
if (path != null) {
try {
Geary.Folder target = yield generic.fetch_folder_async(
path, cancellable
);
Geary.Folder target = generic.get_folder(path);
added_specials.set(type, target);
} catch (Error err) {
debug(

View file

@ -1272,7 +1272,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
Geary.FolderPath destination,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
Geary.Folder target = yield this._account.fetch_folder_async(destination);
Geary.Folder target = this._account.get_folder(destination);
yield copy_email_uids_async(to_copy, destination, cancellable);
this._account.update_folder(target);
}
@ -1321,7 +1321,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
if (prepare.prepared_for_move == null || prepare.prepared_for_move.size == 0)
return null;
Geary.Folder target = yield this._account.fetch_folder_async(destination);
Geary.Folder target = this._account.get_folder(destination);
return new RevokableMove(
_account, this, target, prepare.prepared_for_move
);

View file

@ -40,7 +40,7 @@ private class Geary.ImapEngine.RevokableCommittedMove : Revokable {
notify_revoked();
Geary.Folder target = yield this.account.fetch_folder_async(this.destination);
Geary.Folder target = this.account.get_folder(this.destination);
this.account.update_folder(target);
} finally {
if (session != null) {

View file

@ -135,6 +135,36 @@ public class Geary.MockAccount : Account, MockObject {
}
}
public override FolderPath to_folder_path(GLib.Variant serialised)
throws EngineError.BAD_PARAMETERS {
try {
return object_or_throw_call(
"to_folder_path",
{ box_arg(serialised) },
new EngineError.BAD_PARAMETERS("Mock error")
);
} catch (EngineError.BAD_PARAMETERS err) {
throw err;
} catch (GLib.Error err) {
return new FolderRoot("#mock", false);
}
}
public override Folder get_folder(FolderPath path)
throws EngineError.NOT_FOUND {
try {
return object_or_throw_call(
"get_folder",
{ path },
new EngineError.NOT_FOUND("Mock error")
);
} catch (EngineError.NOT_FOUND err) {
throw err;
} catch (GLib.Error err) {
return new MockFolder(null, null, null, SpecialFolderType.NONE, null);
}
}
public override Gee.Collection<Folder> list_folders() throws Error {
return object_call<Gee.Collection<Folder>>(
"list_folders", {}, Gee.List.empty<Folder>()
@ -145,22 +175,6 @@ public class Geary.MockAccount : Account, MockObject {
return new MockContactStore();
}
public override async bool folder_exists_async(FolderPath path,
Cancellable? cancellable = null)
throws Error {
return boolean_call("folder_exists_async", {path, cancellable}, false);
}
public override async Folder fetch_folder_async(FolderPath path,
Cancellable? cancellable = null)
throws Error {
return object_or_throw_call<Folder>(
"fetch_folder_async",
{path, cancellable},
new EngineError.NOT_FOUND("Mock call")
);
}
public override Folder? get_special_folder(SpecialFolderType special)
throws Error {
return object_call<Folder?>(