[geary/mjog/invert-folder-class-hierarchy: 329/362] Geary.Folder: Make FolderProperties a remote-only concept
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/mjog/invert-folder-class-hierarchy: 329/362] Geary.Folder: Make FolderProperties a remote-only concept
- Date: Wed, 24 Feb 2021 11:54:51 +0000 (UTC)
commit 2b91cd29df22f397f7b2661669e8490ac32226f9
Author: Michael Gratton <mike vee net>
Date: Sun Feb 14 10:32:56 2021 +1100
Geary.Folder: Make FolderProperties a remote-only concept
Remove the `properties` property from `Geary.Folder`, replacing it with
just `email_total` and `email_unread` properties. Move the
`FolderProperties` class into `RemoteFolder` and convert it into an
interface.
Remove the `email_count_changed` signal since API clients can just
listen to notify signals for the two new properties, ensure
implementations of folder are update and notifying of changes to them
correctly.
po/POTFILES.in | 2 -
src/client/application/application-controller.vala | 17 +++--
.../application/application-main-window.vala | 12 +--
src/client/components/folder-popover.vala | 21 +++---
.../folder-list/folder-list-folder-entry.vala | 22 +++---
.../folder-list/folder-list-search-branch.vala | 10 +--
.../plugin/mail-merge/mail-merge-folder.vala | 44 ++++-------
src/engine/api/geary-folder-properties.vala | 88 ----------------------
src/engine/api/geary-folder-supports-create.vala | 2 +-
src/engine/api/geary-folder.vala | 28 ++-----
src/engine/api/geary-remote-folder.vala | 59 ++++++++++++++-
src/engine/app/app-conversation-monitor.vala | 2 +-
src/engine/app/app-draft-manager.vala | 3 +-
src/engine/app/app-search-folder.vala | 47 ++++--------
.../app-fill-window-operation.vala | 4 +-
src/engine/imap-db/imap-db-folder.vala | 68 ++++++++++++-----
.../imap-engine-account-synchronizer.vala | 17 ++---
.../imap-engine/imap-engine-generic-account.vala | 5 +-
.../imap-engine/imap-engine-minimal-folder.vala | 68 +++++++++++------
.../replay-ops/imap-engine-empty-folder.vala | 25 ++----
.../replay-ops/imap-engine-move-email-commit.vala | 16 ++--
.../replay-ops/imap-engine-move-email-prepare.vala | 18 +----
.../replay-ops/imap-engine-move-email-revoke.vala | 13 +---
.../replay-ops/imap-engine-remove-email.vala | 34 ++++-----
.../replay-ops/imap-engine-replay-append.vala | 4 +-
.../replay-ops/imap-engine-replay-removal.vala | 15 +---
src/engine/imap/api/imap-folder-properties.vala | 41 +++++++---
src/engine/meson.build | 2 -
src/engine/outbox/outbox-folder-properties.vala | 22 ------
src/engine/outbox/outbox-folder.vala | 88 ++++++++++------------
test/engine/app/app-conversation-monitor-test.vala | 2 -
test/engine/app/app-conversation-set-test.vala | 1 -
test/engine/app/app-conversation-test.vala | 1 -
test/meson.build | 1 -
test/mock/mock-account.vala | 4 +-
test/mock/mock-folder-properties.vala | 24 ------
test/mock/mock-folder.vala | 17 +++--
test/mock/mock-remote-folder.vala | 46 +++++++++--
38 files changed, 405 insertions(+), 488 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0aa7b8e1a..af6b5824b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -166,7 +166,6 @@ src/engine/api/geary-email.vala
src/engine/api/geary-endpoint.vala
src/engine/api/geary-engine-error.vala
src/engine/api/geary-engine.vala
-src/engine/api/geary-folder-properties.vala
src/engine/api/geary-folder-supports-archive.vala
src/engine/api/geary-folder-supports-copy.vala
src/engine/api/geary-folder-supports-create.vala
@@ -385,7 +384,6 @@ src/engine/nonblocking/nonblocking-reporting-semaphore.vala
src/engine/nonblocking/nonblocking-variants.vala
src/engine/outbox/outbox-email-identifier.vala
src/engine/outbox/outbox-email-properties.vala
-src/engine/outbox/outbox-folder-properties.vala
src/engine/outbox/outbox-folder.vala
src/engine/rfc822/rfc822-error.vala
src/engine/rfc822/rfc822-gmime-filter-blockquotes.vala
diff --git a/src/client/application/application-controller.vala
b/src/client/application/application-controller.vala
index ccb8cf2b1..8797c3710 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -26,8 +26,8 @@ internal class Application.Controller :
return (
target != null &&
target.used_as != TRASH &&
- !target.properties.is_local_only &&
- (target as Geary.FolderSupport.Move) != null
+ target is Geary.RemoteFolder &&
+ target is Geary.FolderSupport.Move
);
}
@@ -35,10 +35,13 @@ internal class Application.Controller :
private static bool should_add_folder(Gee.Collection<Geary.Folder>? all,
Geary.Folder folder) {
// if folder is openable, add it
- if (folder.properties.is_openable != Geary.Trillian.FALSE)
- return true;
- else if (folder.properties.has_children == Geary.Trillian.FALSE)
- return false;
+ var remote = folder as Geary.RemoteFolder;
+ if (remote != null) {
+ if (remote.remote_properties.is_openable != Geary.Trillian.FALSE)
+ return true;
+ else if (remote.remote_properties.has_children == Geary.Trillian.FALSE)
+ return false;
+ }
// if folder contains children, we must ensure that there is
// at least one of the same type
@@ -844,7 +847,7 @@ internal class Application.Controller :
public async void delete_conversations(Geary.FolderSupport.Remove target,
Gee.Collection<Geary.App.Conversation> conversations)
throws GLib.Error {
- var messages = target.properties.is_virtual
+ var messages = target.used_as == SEARCH
? to_all_email_ids(conversations)
: to_in_folder_email_ids(conversations);
yield delete_messages(target, conversations, messages);
diff --git a/src/client/application/application-main-window.vala
b/src/client/application/application-main-window.vala
index 0f82b6f80..40cf9d54b 100644
--- a/src/client/application/application-main-window.vala
+++ b/src/client/application/application-main-window.vala
@@ -707,7 +707,8 @@ public class Application.MainWindow :
this.selected_folder, true
);
- this.selected_folder.properties.notify.disconnect(update_headerbar);
+ this.selected_folder.notify["email-total"].disconnect(update_headerbar);
+ this.selected_folder.notify["email-unread"].disconnect(update_headerbar);
this.selected_folder = null;
}
if (this.conversations != null) {
@@ -761,7 +762,8 @@ public class Application.MainWindow :
// loading conversations.
if (to_select != null) {
- to_select.properties.notify.connect(update_headerbar);
+ to_select.notify["email-total"].connect(update_headerbar);
+ to_select.notify["email-unread"].connect(update_headerbar);
this.conversations = new Geary.App.ConversationMonitor(
to_select,
@@ -1697,11 +1699,11 @@ public class Application.MainWindow :
switch (this.selected_folder.used_as) {
case DRAFTS:
case OUTBOX:
- count = this.selected_folder.properties.email_total;
+ count = this.selected_folder.email_total;
break;
default:
- count = this.selected_folder.properties.email_unread;
+ count = this.selected_folder.email_unread;
break;
}
@@ -1850,7 +1852,7 @@ public class Application.MainWindow :
focus = this.conversation_list_view;
} else {
if (this.conversation_actions.selected_conversations == 1 &&
- this.selected_folder.properties.email_total > 0) {
+ this.selected_folder.email_total > 0) {
main_leaflet.navigate(Hdy.NavigationDirection.FORWARD);
focus = this.conversation_viewer.visible_child;
}
diff --git a/src/client/components/folder-popover.vala b/src/client/components/folder-popover.vala
index faba1df2b..60c9c0577 100644
--- a/src/client/components/folder-popover.vala
+++ b/src/client/components/folder-popover.vala
@@ -29,18 +29,15 @@ public class FolderPopover : Gtk.Popover {
}
public void add_folder(Geary.Folder folder) {
- // don't allow multiples and don't allow folders that can't be opened (that means they
- // support almost no operations and have no content)
- if (has_folder(folder) || folder.properties.is_openable.is_impossible())
- return;
-
- // also don't allow local-only or virtual folders, which also have a limited set of
- // operations
- if (folder.properties.is_local_only || folder.properties.is_virtual)
- return;
-
- list_box.add(build_row(folder));
- list_box.invalidate_sort();
+ // Only include remote-backed folders that can be opened
+ if (!has_folder(folder)) {
+ var remote = folder as Geary.RemoteFolder;
+ if (remote != null &&
+ !remote.remote_properties.is_openable.is_impossible()) {
+ list_box.add(build_row(folder));
+ list_box.invalidate_sort();
+ }
+ }
}
public void enable_disable_folder(Geary.Folder folder, bool sensitive) {
diff --git a/src/client/folder-list/folder-list-folder-entry.vala
b/src/client/folder-list/folder-list-folder-entry.vala
index ae78c1ffc..ec20de041 100644
--- a/src/client/folder-list/folder-list-folder-entry.vala
+++ b/src/client/folder-list/folder-list-folder-entry.vala
@@ -20,14 +20,14 @@ public class FolderList.FolderEntry :
this.context = context;
this.context.notify.connect(on_context_changed);
this.has_new = false;
-
this.folder.properties.notify[Geary.FolderProperties.PROP_NAME_EMAIL_TOTAL].connect(on_counts_changed);
-
this.folder.properties.notify[Geary.FolderProperties.PROP_NAME_EMAIL_UNREAD].connect(on_counts_changed);
+ this.folder.notify["email-total"].connect(on_counts_changed);
+ this.folder.notify["email-unread"].connect(on_counts_changed);
}
~FolderEntry() {
this.context.notify.disconnect(on_context_changed);
-
this.folder.properties.notify[Geary.FolderProperties.PROP_NAME_EMAIL_TOTAL].disconnect(on_counts_changed);
-
this.folder.properties.notify[Geary.FolderProperties.PROP_NAME_EMAIL_UNREAD].disconnect(on_counts_changed);
+ this.folder.notify["email-total"].disconnect(on_counts_changed);
+ this.folder.notify["email-unread"].disconnect(on_counts_changed);
}
public override string get_sidebar_name() {
@@ -39,18 +39,18 @@ public class FolderList.FolderEntry :
// messages in a folder. String substitution is the actual
// number.
string total_msg = ngettext(
- "%d message", "%d messages", folder.properties.email_total
- ).printf(folder.properties.email_total);
+ "%d message", "%d messages", folder.email_total
+ ).printf(folder.email_total);
- if (folder.properties.email_unread == 0)
+ if (folder.email_unread == 0)
return total_msg;
// Translators: Label displaying number of unread email
// messages in a folder. String substitution is the actual
// number.
string unread_msg = ngettext(
- "%d unread", "%d unread", folder.properties.email_unread
- ).printf(folder.properties.email_unread);
+ "%d unread", "%d unread", folder.email_unread
+ ).printf(folder.email_unread);
// Translators: This string represents the divider between two
// messages: "n messages" and "n unread", shown in the folder
@@ -99,10 +99,10 @@ public class FolderList.FolderEntry :
public override int get_count() {
switch (this.context.displayed_count) {
case TOTAL:
- return folder.properties.email_total;
+ return folder.email_total;
case UNREAD:
- return folder.properties.email_unread;
+ return folder.email_unread;
default:
return 0;
diff --git a/src/client/folder-list/folder-list-search-branch.vala
b/src/client/folder-list/folder-list-search-branch.vala
index f3c27ab44..e1234ad0b 100644
--- a/src/client/folder-list/folder-list-search-branch.vala
+++ b/src/client/folder-list/folder-list-search-branch.vala
@@ -35,17 +35,13 @@ public class FolderList.SearchEntry : FolderList.AbstractFolderEntry {
this.engine.account_available.connect(on_accounts_changed);
this.engine.account_unavailable.connect(on_accounts_changed);
- folder.properties.notify[
- Geary.FolderProperties.PROP_NAME_EMAIL_TOTAL
- ].connect(on_email_total_changed);
+ folder.notify["email-total"].connect(on_email_total_changed);
}
~SearchEntry() {
this.engine.account_available.disconnect(on_accounts_changed);
this.engine.account_unavailable.disconnect(on_accounts_changed);
- folder.properties.notify[
- Geary.FolderProperties.PROP_NAME_EMAIL_TOTAL
- ].disconnect(on_email_total_changed);
+ folder.notify["email-total"].disconnect(on_email_total_changed);
}
public override string get_sidebar_name() {
@@ -55,7 +51,7 @@ public class FolderList.SearchEntry : FolderList.AbstractFolderEntry {
}
public override string? get_sidebar_tooltip() {
- int total = folder.properties.email_total;
+ int total = folder.email_total;
return ngettext("%d result", "%d results", total).printf(total);
}
diff --git a/src/client/plugin/mail-merge/mail-merge-folder.vala
b/src/client/plugin/mail-merge/mail-merge-folder.vala
index 4be39dae4..44bb07fc6 100644
--- a/src/client/plugin/mail-merge/mail-merge-folder.vala
+++ b/src/client/plugin/mail-merge/mail-merge-folder.vala
@@ -75,41 +75,28 @@ public class MailMerge.Folder : Geary.BaseObject,
}
- private class FolderProperties : Geary.FolderProperties {
-
- public FolderProperties() {
- base(
- 0, 0,
- Geary.Trillian.FALSE, Geary.Trillian.FALSE, Geary.Trillian.TRUE,
- true, false, false
- );
- }
-
- public void set_total(int total) {
- this.email_total = total;
- }
-
- }
-
-
/** {@inheritDoc} */
public override Geary.Account account {
get { return this._account; }
}
private Geary.Account _account;
- /** {@inheritDoc} */
- public override Geary.FolderProperties properties {
- get { return _properties; }
- }
- private FolderProperties _properties = new FolderProperties();
-
/** {@inheritDoc} */
public override Geary.Folder.Path path {
get { return _path; }
}
private Geary.Folder.Path _path;
+ /** {@inheritDoc} */
+ public int email_total {
+ get { return this.ids.size; }
+ }
+
+ /** {@inheritDoc} */
+ public int email_unread {
+ get { return 0; }
+ }
+
/** {@inheritDoc} */
public override Geary.Folder.SpecialUse used_as {
get { return this._used_as; }
@@ -123,10 +110,7 @@ public class MailMerge.Folder : Geary.BaseObject,
public string data_display_name { get; private set; }
/** The number of email that have been sent. */
- public uint email_sent { get; private set; default = 0; }
-
- /** The number of email in total. */
- public uint email_total { get; private set; default = 0; }
+ public int email_sent { get; private set; default = 0; }
/** Specifies if the merged mail is currently being sent. */
public bool is_sending { get; private set; default = false; }
@@ -343,9 +327,8 @@ public class MailMerge.Folder : Geary.BaseObject,
this.ids.add(id);
this.composed.set(id, composed);
this.email.set(id, email);
- this._properties.set_total((int) next_id);
- this.email_total = (uint) next_id;
+ notify_property("email-total");
email_inserted(Geary.Collection.single(id));
record = yield this.data.read_record();
}
@@ -385,7 +368,8 @@ public class MailMerge.Folder : Geary.BaseObject,
this.ids.remove_at(last);
this.email.unset(id);
this.composed.unset(id);
- this._properties.set_total(last);
+
+ notify_property("email-total");
email_removed(Geary.Collection.single(id));
// Rate limit to ~30/minute for now
diff --git a/src/engine/api/geary-folder-supports-create.vala
b/src/engine/api/geary-folder-supports-create.vala
index 664e9f6c0..d947dfda3 100644
--- a/src/engine/api/geary-folder-supports-create.vala
+++ b/src/engine/api/geary-folder-supports-create.vala
@@ -30,7 +30,7 @@ public interface Geary.FolderSupport.Create : Folder {
* time to be set when saved. Like EmailFlags, this is optional
* if not applicable.
*
- * @see FolderProperties.create_never_returns_id
+ * @see RemoteFolder.RemoteProperties.create_never_returns_id
*/
public abstract async EmailIdentifier?
create_email_async(RFC822.Message rfc822,
diff --git a/src/engine/api/geary-folder.vala b/src/engine/api/geary-folder.vala
index a070264dd..4f65eb990 100644
--- a/src/engine/api/geary-folder.vala
+++ b/src/engine/api/geary-folder.vala
@@ -486,14 +486,6 @@ public interface Geary.Folder : GLib.Object, Logging.Source {
}
- [Flags]
- public enum CountChangeReason {
- NONE = 0,
- APPENDED,
- INSERTED,
- REMOVED
- }
-
/**
* Flags modifying how email is retrieved.
*/
@@ -553,12 +545,15 @@ public interface Geary.Folder : GLib.Object, Logging.Source {
/** The account that owns this folder. */
public abstract Geary.Account account { get; }
- /** Current properties for this folder. */
- public abstract Geary.FolderProperties properties { get; }
-
/** The path to this folder in the account's folder hierarchy. */
public abstract Path path { get; }
+ /** The total number of email messages in this folder. */
+ public abstract int email_total { get; }
+
+ /** The number of unread email messages in this folder. */
+ public abstract int email_unread { get; }
+
/**
* Determines the special use of this folder.
*
@@ -647,17 +642,6 @@ public interface Geary.Folder : GLib.Object, Logging.Source {
this.account.email_flags_changed_in_folder(map, this);
}
- /**
- * Fired when the total count of email in a folder has changed in any way.
- *
- * Note that this signal will fire after {@link email_appended},
- * and {@link email_removed} (although see the note at
- * email_removed).
- */
- public virtual signal void email_count_changed(
- int new_count, CountChangeReason reason
- );
-
/**
* Fired when the folder's special use has changed.
*
diff --git a/src/engine/api/geary-remote-folder.vala b/src/engine/api/geary-remote-folder.vala
index f7290d0fa..1d5497579 100644
--- a/src/engine/api/geary-remote-folder.vala
+++ b/src/engine/api/geary-remote-folder.vala
@@ -1,6 +1,6 @@
/*
* Copyright © 2016 Software Freedom Conservancy Inc.
- * Copyright © 2018-2020 Michael Gratton <mike vee net>
+ * Copyright © 2018-2021 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.
@@ -37,6 +37,63 @@
public interface Geary.RemoteFolder : Folder {
+ /** A collection of known properties about a remote mailbox. */
+ public interface RemoteProperties : GLib.Object {
+
+
+ /**
+ * The total count of email in the remote mailbox.
+ */
+ public abstract int email_total { get; protected set; }
+
+ /**
+ * The total count of unread email in the remote mailbox.
+ */
+ public abstract int email_unread { get; protected set; }
+
+ /**
+ * Indicates whether the remote mailbox has children.
+ *
+ * Note that if {@link has_children} == {@link
+ * Trillian.TRUE}, it implies {@link supports_children} ==
+ * {@link Trillian.TRUE}.
+ */
+ public abstract Trillian has_children { get; protected set; }
+
+ /**
+ * Indicates whether the remote mailbox can have children.
+ *
+ * This does ''not'' mean creating a sub-folder is guaranteed
+ * to succeed.
+ */
+ public abstract Trillian supports_children { get; protected set; }
+
+ /**
+ * Indicates whether the remote mailbox can be opened.
+ *
+ * Mailboxes that cannot be opened exist as steps in the
+ * mailbox name-space only - they do not contain email.
+ */
+ public abstract Trillian is_openable { get; protected set; }
+
+ /**
+ * Indicates whether the remote mailbox reports ids for created email.
+ *
+ * True if a folder supporting {@link FolderSupport.Create}
+ * will not to return a {@link EmailIdentifier} when a call to
+ * {@link FolderSupport.Create.create_email_async} succeeds.
+ *
+ * This is for IMAP servers that don't support UIDPLUS. Most
+ * servers support UIDPLUS, so this will usually be false.
+ */
+ public abstract bool create_never_returns_id { get; protected set; }
+
+ }
+
+
+ /** Last known remote properties for this folder. */
+ public abstract RemoteProperties remote_properties { get; }
+
/**
* Indicates if the folder is checking for remote changes to email.
*
diff --git a/src/engine/app/app-conversation-monitor.vala b/src/engine/app/app-conversation-monitor.vala
index dc54f1e38..876b75cbd 100644
--- a/src/engine/app/app-conversation-monitor.vala
+++ b/src/engine/app/app-conversation-monitor.vala
@@ -102,7 +102,7 @@ public class Geary.App.ConversationMonitor : BaseObject, Logging.Source {
public bool can_load_more {
get {
return (
- this.base_folder.properties.email_total >
+ this.base_folder.email_total >
this.folder_window_size
) && !this.fill_complete;
}
diff --git a/src/engine/app/app-draft-manager.vala b/src/engine/app/app-draft-manager.vala
index 65ebc4d9f..2a3b0a0c4 100644
--- a/src/engine/app/app-draft-manager.vala
+++ b/src/engine/app/app-draft-manager.vala
@@ -217,7 +217,8 @@ public class Geary.App.DraftManager : BaseObject {
// if drafts folder doesn't return the identifier of newly created emails, then this object
// can't do it's work ... wait until open to check for this, to be absolutely sure
- if (drafts_folder.properties.create_never_returns_id) {
+ if (drafts_folder is RemoteFolder &&
+ ((RemoteFolder) drafts_folder).remote_properties.create_never_returns_id) {
throw new EngineError.UNSUPPORTED(
"%s: Drafts folder %s does not return created mail ID",
to_string(), drafts_folder.to_string()
diff --git a/src/engine/app/app-search-folder.vala b/src/engine/app/app-search-folder.vala
index 4e9b65dfa..98a686cda 100644
--- a/src/engine/app/app-search-folder.vala
+++ b/src/engine/app/app-search-folder.vala
@@ -33,20 +33,6 @@ public class Geary.App.SearchFolder : BaseObject,
};
- private class FolderPropertiesImpl : FolderProperties {
-
-
- public FolderPropertiesImpl(int total, int unread) {
- base(total, unread, Trillian.FALSE, Trillian.FALSE, Trillian.TRUE, true, true, false);
- }
-
- public void set_total(int total) {
- this.email_total = total;
- }
-
- }
-
-
// Represents an entry in the folder. Does not implement
// Gee.Comparable since that would require extending GLib.Object
// and hence make them very heavyweight.
@@ -83,18 +69,22 @@ public class Geary.App.SearchFolder : BaseObject,
}
private weak Account _account;
- /** {@inheritDoc} */
- public FolderProperties properties {
- get { return _properties; }
- }
- private FolderPropertiesImpl _properties;
-
/** {@inheritDoc} */
public Folder.Path path {
get { return _path; }
}
private Folder.Path? _path = null;
+ /** {@inheritDoc} */
+ public int email_total {
+ get { return this.entries.size; }
+ }
+
+ /** {@inheritDoc} */
+ public int email_unread {
+ get { return 0; }
+ }
+
/**
* {@inheritDoc}
*
@@ -129,7 +119,6 @@ public class Geary.App.SearchFolder : BaseObject,
public SearchFolder(Account account, Folder.Root root) {
this._account = account;
- this._properties = new FolderPropertiesImpl(0, 0);
this._path = root.get_child(MAGIC_BASENAME, Trillian.TRUE);
account.folders_available_unavailable.connect(on_folders_available_unavailable);
@@ -187,8 +176,8 @@ public class Geary.App.SearchFolder : BaseObject,
this.entries = new_entry_set();
this.ids = new_id_map();
+ notify_property("email-total");
email_removed(old_ids.keys);
- email_count_changed(0, REMOVED);
}
/**
@@ -598,29 +587,25 @@ public class Geary.App.SearchFolder : BaseObject,
this.entries = entries;
this.ids = ids;
- this._properties.set_total(entries.size);
+ if (!added.is_empty && !removed.is_empty) {
+ notify_property("email-total");
+ }
// Note that we probably shouldn't be firing these signals from inside
// our mutex lock. Keep an eye on it, and if there's ever a case where
// it might cause problems, it shouldn't be too hard to move the
// firings outside.
- Folder.CountChangeReason reason = CountChangeReason.NONE;
- if (removed.size > 0) {
+ if (!removed.is_empty) {
email_removed(removed);
- reason |= Folder.CountChangeReason.REMOVED;
}
- if (added.size > 0) {
+ if (!added.is_empty) {
// TODO: we'd like to be able to use APPENDED here
// when applicable, but because of the potential to
// append a thousand results at once and the
// ConversationMonitor's inability to handle that
// gracefully (#7464), we always use INSERTED for now.
email_inserted(added);
- reason |= Folder.CountChangeReason.INSERTED;
- }
- if (reason != CountChangeReason.NONE) {
- email_count_changed(this.entries.size, reason);
}
debug("Processing done, entries/ids: %d/%d", entries.size, ids.size);
} else {
diff --git a/src/engine/app/conversation-monitor/app-fill-window-operation.vala
b/src/engine/app/conversation-monitor/app-fill-window-operation.vala
index 86685f5f5..53bc0fa96 100644
--- a/src/engine/app/conversation-monitor/app-fill-window-operation.vala
+++ b/src/engine/app/conversation-monitor/app-fill-window-operation.vala
@@ -52,7 +52,7 @@ private class Geary.App.FillWindowOperation : ConversationOperation {
"Filled %d of %d locally, window: %d, total: %d",
loaded, num_to_load,
this.monitor.conversations.size,
- this.monitor.base_folder.properties.email_total
+ this.monitor.base_folder.email_total
);
var remote = this.monitor.base_folder as RemoteFolder;
@@ -83,7 +83,7 @@ private class Geary.App.FillWindowOperation : ConversationOperation {
"Filled %d of %d from the remote, window: %d, total: %d",
loaded, num_to_load,
this.monitor.conversations.size,
- this.monitor.base_folder.properties.email_total
+ this.monitor.base_folder.email_total
);
}
diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
index 695f3a70b..eeed32d86 100644
--- a/src/engine/imap-db/imap-db-folder.vala
+++ b/src/engine/imap-db/imap-db-folder.vala
@@ -129,13 +129,56 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
this.properties = properties;
}
- public async int get_email_count_async(ListFlags flags, Cancellable? cancellable) throws Error {
+ public async int get_email_count_async(ListFlags flags,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
int count = 0;
- yield db.exec_transaction_async(Db.TransactionType.RO, (cx) => {
- count = do_get_email_count(cx, flags, cancellable);
+ yield db.exec_transaction_async(
+ RO,
+ (cx) => {
+ Db.Statement stmt = cx.prepare(
+ "SELECT COUNT(*) FROM MessageLocationTable WHERE folder_id=?");
+ stmt.bind_rowid(0, folder_id);
- return Db.TransactionOutcome.SUCCESS;
- }, cancellable);
+ Db.Result results = stmt.exec(cancellable);
+ if (!results.finished) {
+ count = results.int_at(0);
+ if (!flags.include_marked_for_remove()) {
+ count -= do_get_marked_removed_count(cx, cancellable);
+ }
+ }
+ return SUCCESS;
+ },
+ cancellable
+ );
+
+ return count;
+ }
+
+ public async int get_email_unread_async(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ int count = 0;
+ yield db.exec_transaction_async(
+ RO,
+ (cx) => {
+ Db.Statement stmt = cx.prepare(
+ """
+ SELECT COUNT(*) FROM MessageLocationTable
+ WHERE folder_id = ?
+ AND remove_marker <> ?
+ AND message_id IN (SELECT rowid FROM MessageSearchTable WHERE MessageSearchTable MATCH
'{flags} : UNREAD')
+ """
+ );
+ stmt.bind_rowid(0, folder_id);
+ stmt.bind_bool(1, true);
+ Db.Result results = stmt.exec(cancellable);
+ if (!results.finished) {
+ count = results.int_at(0);
+ }
+ return SUCCESS;
+ },
+ cancellable
+ );
return count;
}
@@ -1389,21 +1432,6 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
// These should only be called from within a TransactionMethod.
//
- private int do_get_email_count(Db.Connection cx, ListFlags flags, Cancellable? cancellable)
- throws Error {
- Db.Statement stmt = cx.prepare(
- "SELECT COUNT(*) FROM MessageLocationTable WHERE folder_id=?");
- stmt.bind_rowid(0, folder_id);
-
- Db.Result results = stmt.exec(cancellable);
- if (results.finished)
- return 0;
-
- int marked = !flags.include_marked_for_remove() ? do_get_marked_removed_count(cx, cancellable) : 0;
-
- return Numeric.int_floor(results.int_at(0) - marked, 0);
- }
-
private int do_get_marked_removed_count(Db.Connection cx, Cancellable? cancellable) throws Error {
Db.Statement stmt = cx.prepare(
"SELECT COUNT(*) FROM MessageLocationTable WHERE folder_id=? AND remove_marker <> ?");
diff --git a/src/engine/imap-engine/imap-engine-account-synchronizer.vala
b/src/engine/imap-engine/imap-engine-account-synchronizer.vala
index d0861546e..8ed96fd32 100644
--- a/src/engine/imap-engine/imap-engine-account-synchronizer.vala
+++ b/src/engine/imap-engine/imap-engine-account-synchronizer.vala
@@ -83,18 +83,16 @@ private class Geary.ImapEngine.AccountSynchronizer :
foreach (Folder folder in folders) {
// Only sync folders that:
- // 1. Can actually be opened (i.e. are selectable)
- // 2. Are remote backed
+ // 1. Are remote backed
+ // 2. Can actually be opened (i.e. are selectable)
//
- // All this implies the folder must be a MinimalFolder and
+ // This implies the folder must be a MinimalFolder and
// we do require that for syncing at the moment anyway,
// but keep the tests in for that one glorious day where
// we can just use a generic folder.
- MinimalFolder? imap_folder = folder as MinimalFolder;
+ var imap_folder = folder as MinimalFolder;
if (imap_folder != null &&
- folder.properties.is_openable.is_possible() &&
- !folder.properties.is_local_only &&
- !folder.properties.is_virtual) {
+ imap_folder.remote_properties.is_openable.is_possible()) {
AccountOperation? op = null;
switch (reason) {
@@ -258,7 +256,8 @@ private class Geary.ImapEngine.FullFolderSync : RefreshFolderSync {
protected override async void sync_folder(GLib.DateTime max_epoch,
GLib.Cancellable cancellable)
throws GLib.Error {
- ImapDB.Folder local_folder = ((MinimalFolder) this.folder).local_folder;
+ var imap_folder = (MinimalFolder) this.folder;
+ var local_folder = imap_folder.local_folder;
// Detach older emails outside the prefetch window
if (this.account.information.prefetch_period_days >= 0) {
@@ -313,7 +312,7 @@ private class Geary.ImapEngine.FullFolderSync : RefreshFolderSync {
debug("Fetching to: %s", next_epoch.to_string());
- if (local_count < this.folder.properties.email_total &&
+ if (local_count < imap_folder.remote_properties.email_total &&
next_epoch.compare(max_epoch) >= 0) {
if (next_epoch.compare(this.sync_max_epoch) > 0) {
current_oldest = yield expand_vector(
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 80aed7181..13bbaec3f 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -93,7 +93,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
this.imap = imap;
smtp.outbox = new Outbox.Folder(this, local_folder_root, local.db);
- smtp.report_problem.connect(notify_report_problem);
+ smtp.report_problem.connect(this.notify_report_problem);
smtp.set_logging_parent(this);
this.smtp = smtp;
@@ -1171,8 +1171,9 @@ internal class Geary.ImapEngine.StartServices : AccountOperation {
throws GLib.Error {
yield this.account.incoming.start(cancellable);
- this.account.register_local_folder(this.outbox);
+ yield this.outbox.load(cancellable);
yield this.account.outgoing.start(cancellable);
+ this.account.register_local_folder(this.outbox);
}
}
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 61bc7a72a..67be17934 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -43,26 +43,33 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
private weak GenericAccount _account;
/** {@inheritDoc} */
- public FolderProperties properties {
- get { return this._properties; }
+ public Folder.Path path {
+ get { return this.local_folder.path; }
}
- private FolderProperties _properties;
/** {@inheritDoc} */
- public Folder.Path path {
- get {
- return local_folder.path;
- }
+ public int email_total {
+ get { return this._email_total; }
}
+ private int _email_total = 0;
+
+ /** {@inheritDoc} */
+ public int email_unread {
+ get { return this._email_unread; }
+ }
+ private int _email_unread = 0;
/** {@inheritDoc} */
public Folder.SpecialUse used_as {
- get {
- return this._used_as;
- }
+ get { return this._used_as; }
}
private Folder.SpecialUse _used_as;
+ /** {@inheritDoc} */
+ public override RemoteProperties remote_properties {
+ get { return this.local_folder.properties; }
+ }
+
/** {@inheritDoc} */
public bool is_monitoring {
get { return this._is_monitoring; }
@@ -125,7 +132,6 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
this.local_folder.email_complete.connect(on_email_complete);
this._used_as = use;
- this._properties = local_folder.properties;
this.replay_queue = new ReplayQueue(this);
this.replay_queue.remotely_executed.connect(this.on_remote_status_check);
@@ -146,6 +152,7 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
this.closed_semaphore.blind_notify();
}
+ /** {@inheritDoc} */
public void set_used_as_custom(bool enabled)
throws EngineError.UNSUPPORTED {
if (enabled) {
@@ -270,6 +277,30 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
return this.remote_session;
}
+ /**
+ * Updates the email total and unread counts for the folder.
+ */
+ internal async void update_email_counts(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ int existing_total = this._email_total;
+ int new_total = yield this.local_folder.get_email_count_async(
+ NONE, cancellable
+ );
+ if (existing_total != new_total) {
+ this._email_total = new_total;
+ notify_property("email-total");
+ }
+
+ int existing_unread = this._email_unread;
+ int new_unread = yield this.local_folder.get_email_unread_async(
+ cancellable
+ );
+ if (existing_unread != new_unread) {
+ this._email_unread = new_unread;
+ notify_property("email-unread");
+ }
+ }
+
/**
* Sets the special use for this folder.
*
@@ -679,12 +710,11 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
return;
}
-
/*
* Step 5: Notify subscribers of what has happened.
*/
- Folder.CountChangeReason count_change_reason = Folder.CountChangeReason.NONE;
+ yield update_email_counts(cancellable);
if (removed_ids != null && removed_ids.size > 0) {
// there may be operations pending on the remote queue for these removed emails; notify
@@ -695,8 +725,6 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
debug("Notifying of %d removed emails since last opened",
removed_ids.size);
email_removed(removed_ids);
-
- count_change_reason |= Folder.CountChangeReason.REMOVED;
}
// notify created (new email located somewhere inside the
@@ -713,7 +741,6 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
debug("Notifying of %d inserted emails since last opened",
inserted_ids.size);
email_inserted(inserted_ids);
- count_change_reason |= Folder.CountChangeReason.INSERTED;
}
// notify appended (new email added since the folder was last opened)
@@ -721,13 +748,6 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
debug("Notifying of %d appended emails since last opened",
appended_ids.size);
email_appended(appended_ids);
- count_change_reason |= Folder.CountChangeReason.APPENDED;
- }
-
- if (count_change_reason != Folder.CountChangeReason.NONE) {
- debug("Notifying of %Xh count change reason (%d remote messages)",
- count_change_reason, remote_message_count);
- email_count_changed(remote_message_count, count_change_reason);
}
debug("Completed normalize_folder");
@@ -739,12 +759,12 @@ private class Geary.ImapEngine.MinimalFolder : BaseObject,
Geary.Email.Field.NONE, ImapDB.Folder.ListFlags.NONE, cancellable);
yield local_folder.detach_all_emails_async(cancellable);
+ yield update_email_counts(cancellable);
if (all != null && all.size > 0) {
Gee.List<EmailIdentifier> ids =
traverse<Email>(all).map<EmailIdentifier>((email) => email.id).to_array_list();
email_removed(ids);
- email_count_changed(0, Folder.CountChangeReason.REMOVED);
}
}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
b/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
index 11b0bc8ed..da2c0a634 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
@@ -13,7 +13,6 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
private MinimalFolder engine;
private Cancellable? cancellable;
private Gee.Set<ImapDB.EmailIdentifier>? removed_ids = null;
- private int original_count = 0;
public EmptyFolder(MinimalFolder engine, Cancellable? cancellable) {
base("EmptyFolder", OnError.RETRY);
@@ -23,25 +22,12 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
}
public override async ReplayOperation.Status replay_local_async() throws Error {
- this.original_count = this.engine.properties.email_total;
- // because this value is only used for reporting count changes, offer best-possible service
- if (this.original_count < 0)
- this.original_count = 0;
-
// mark everything in the folder as removed
removed_ids = yield engine.local_folder.mark_removed_async(null, true, cancellable);
-
- // if local folder is not empty, report all as being removed
- if (removed_ids != null) {
- if (removed_ids.size > 0)
- engine.email_removed(removed_ids);
-
- int new_count = Numeric.int_floor(original_count - removed_ids.size, 0);
- if (new_count != original_count) {
- engine.email_count_changed(new_count, REMOVED);
- }
+ if (removed_ids != null && !removed_ids.is_empty) {
+ yield this.engine.update_email_counts(cancellable);
+ engine.email_removed(removed_ids);
}
-
return ReplayOperation.Status.CONTINUE;
}
@@ -61,14 +47,13 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
public override async void backout_local_async() throws Error {
if (removed_ids != null && removed_ids.size > 0) {
yield engine.local_folder.mark_removed_async(removed_ids, false, cancellable);
+ yield this.engine.update_email_counts(cancellable);
engine.email_inserted(removed_ids);
}
-
- engine.email_count_changed(original_count, INSERTED);
}
public override string describe_state() {
return "removed_ids.size=%d".printf((removed_ids != null) ? removed_ids.size : 0);
}
-}
+}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
index 2db597dfc..e94512ed9 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
@@ -92,17 +92,13 @@ private class Geary.ImapEngine.MoveEmailCommit : Geary.ImapEngine.SendReplayOper
}
public override async void backout_local_async() throws Error {
- if (to_move.size == 0)
- return;
-
- yield engine.local_folder.mark_removed_async(to_move, false, cancellable);
-
- int count = this.engine.properties.email_total;
- if (count < 0) {
- count = 0;
+ if (!this.to_move.is_empty) {
+ yield this.engine.local_folder.mark_removed_async(
+ this.to_move, false, this.cancellable
+ );
+ yield this.engine.update_email_counts(this.cancellable);
+ this.engine.email_inserted(this.to_move);
}
- engine.email_inserted(to_move);
- engine.email_count_changed(count + to_move.size, INSERTED);
}
public override string describe_state() {
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
index 71930606d..a1a00c749 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
@@ -38,21 +38,11 @@ private class Geary.ImapEngine.MoveEmailPrepare : Geary.ImapEngine.SendReplayOpe
if (to_move.size <= 0)
return ReplayOperation.Status.COMPLETED;
- int count = this.engine.properties.email_total;
- // as this value is only used for reporting, offer best-possible service
- if (count < 0)
- count = to_move.size;
-
prepared_for_move = yield engine.local_folder.mark_removed_async(to_move, true, cancellable);
- if (prepared_for_move == null || prepared_for_move.size == 0)
- return ReplayOperation.Status.COMPLETED;
-
- engine.email_removed(prepared_for_move);
- engine.email_count_changed(
- Numeric.int_floor(count - prepared_for_move.size, 0),
- REMOVED
- );
-
+ if (prepared_for_move != null && !prepared_for_move.is_empty) {
+ yield this.engine.update_email_counts(this.cancellable);
+ this.engine.email_removed(prepared_for_move);
+ }
return COMPLETED;
}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
index df66828e7..73a89420b 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
@@ -33,17 +33,10 @@ private class Geary.ImapEngine.MoveEmailRevoke : Geary.ImapEngine.SendReplayOper
Gee.Set<ImapDB.EmailIdentifier>? revoked = yield engine.local_folder.mark_removed_async(
to_revoke, false, cancellable);
- if (revoked == null || revoked.size == 0)
- return ReplayOperation.Status.COMPLETED;
-
- int count = this.engine.properties.email_total;
- if (count < 0) {
- count = 0;
+ if (revoked != null && !revoked.is_empty) {
+ yield this.engine.update_email_counts(this.cancellable);
+ this.engine.email_inserted(revoked);
}
-
- engine.email_inserted(revoked);
- engine.email_count_changed(count + revoked.size, INSERTED);
-
return COMPLETED;
}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
index d20c76b48..26abbade4 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
@@ -5,11 +5,13 @@
*/
private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperation {
+
+
private MinimalFolder engine;
private Gee.List<ImapDB.EmailIdentifier> to_remove = new Gee.ArrayList<ImapDB.EmailIdentifier>();
private Cancellable? cancellable;
private Gee.Set<ImapDB.EmailIdentifier>? removed_ids = null;
- private int original_count = 0;
+
public RemoveEmail(MinimalFolder engine,
Gee.Collection<ImapDB.EmailIdentifier> to_remove,
@@ -32,22 +34,11 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
if (this.to_remove.size <= 0)
return ReplayOperation.Status.COMPLETED;
- this.original_count = this.engine.properties.email_total;
- // because this value is only used for reporting count changes, offer best-possible service
- if (this.original_count < 0)
- this.original_count = this.to_remove.size;
-
removed_ids = yield engine.local_folder.mark_removed_async(to_remove, true, cancellable);
- if (removed_ids == null || removed_ids.size == 0)
- return ReplayOperation.Status.COMPLETED;
-
- engine.email_removed(removed_ids);
-
- engine.email_count_changed(
- Numeric.int_floor(original_count - removed_ids.size, 0),
- REMOVED
- );
-
+ if (removed_ids != null && !removed_ids.is_empty) {
+ yield this.engine.update_email_counts(this.cancellable);
+ this.engine.email_removed(removed_ids);
+ }
return CONTINUE;
}
@@ -70,11 +61,13 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
}
public override async void backout_local_async() throws Error {
- if (removed_ids != null && removed_ids.size > 0) {
- yield engine.local_folder.mark_removed_async(removed_ids, false, cancellable);
- engine.email_inserted(removed_ids);
+ if (this.removed_ids != null && !this.removed_ids.is_empty) {
+ yield this.engine.local_folder.mark_removed_async(
+ this.removed_ids, false, this.cancellable
+ );
+ yield this.engine.update_email_counts(this.cancellable);
+ this.engine.email_inserted(this.removed_ids);
}
- engine.email_count_changed(original_count, INSERTED);
}
public override string describe_state() {
@@ -82,4 +75,3 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
(removed_ids != null) ? removed_ids.size : 0);
}
}
-
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
b/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
index f79c91056..0d3676a96 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
@@ -112,6 +112,8 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
}
}
+ yield this.owner.update_email_counts(this.cancellable);
+
// store the reported count, *not* the current count (which is updated outside the of
// the queue) to ensure that updates happen serially and reflect committed local changes
yield this.owner.local_folder.update_remote_selected_message_count(
@@ -127,8 +129,6 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
this.owner.email_appended(created);
}
- this.owner.email_count_changed(this.remote_count, Folder.CountChangeReason.APPENDED);
-
debug("%s do_replay_appended_message: completed, this.remote_count=%d",
to_string(), this.remote_count);
}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
b/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
index 3f5efca6d..c15fc4202 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
@@ -105,13 +105,10 @@ private class Geary.ImapEngine.ReplayRemoval : Geary.ImapEngine.ReplayOperation
to_string(), this.position.value, this.remote_count, local_position, local_count);
}
- // for debugging
- int new_local_count = -1;
try {
- new_local_count = yield this.owner.local_folder.get_email_count_async(
- ImapDB.Folder.ListFlags.INCLUDE_MARKED_FOR_REMOVE, null);
+ yield this.owner.update_email_counts(null);
} catch (Error err) {
- debug("%s do_replay_removed_message: error fetching new local count: %s", to_string(),
+ debug("%s do_replay_removed_message: unable to update remote count: %s", to_string(),
err.message);
}
@@ -134,16 +131,10 @@ private class Geary.ImapEngine.ReplayRemoval : Geary.ImapEngine.ReplayOperation
this.owner.marked_email_removed(removed);
}
- if (!marked) {
- this.owner.email_count_changed(
- this.remote_count, Folder.CountChangeReason.REMOVED
- );
- }
-
debug("%s ReplayRemoval: completed, "
+ "(this.remote_count=%d local_count=%d starting local_count=%d this.position=%lld
local_position=%lld marked=%s)",
this.owner.to_string(),
- this.remote_count, new_local_count, local_count,
+ this.remote_count, this.owner.email_total, local_count,
this.position.value, local_position, marked.to_string());
}
diff --git a/src/engine/imap/api/imap-folder-properties.vala b/src/engine/imap/api/imap-folder-properties.vala
index 54b21ce3a..6d83eaf9e 100644
--- a/src/engine/imap/api/imap-folder-properties.vala
+++ b/src/engine/imap/api/imap-folder-properties.vala
@@ -38,20 +38,42 @@
* is considered more authoritative than STATUS.
*/
-public class Geary.Imap.FolderProperties : Geary.FolderProperties {
+public class Geary.Imap.FolderProperties : BaseObject, RemoteFolder.RemoteProperties {
+
+ /** {@inheritDoc} */
+ public int email_total { get; protected set; }
+
+ /** {@inheritDoc} */
+ public int email_unread { get; protected set; }
+
+ /** {@inheritDoc} */
+ public Trillian has_children { get; protected set; }
+
+ /** {@inheritDoc} */
+ public Trillian supports_children { get; protected set; }
+
+ /** {@inheritDoc} */
+ public Trillian is_openable { get; protected set; }
+
+ /** {@inheritDoc} */
+ public bool create_never_returns_id { get; protected set; }
+
/**
* -1 if the Folder was not opened via SELECT or EXAMINE. Updated as EXISTS server data
* arrives.
*/
public int select_examine_messages { get; private set; }
+
/**
* -1 if the FolderProperties were not obtained or updated via a STATUS command
*/
public int status_messages { get; private set; }
+
/**
* -1 if the FolderProperties were not obtained or updated via a STATUS command
*/
public int unseen { get; private set; }
+
public int recent { get; internal set; }
public UIDValidity? uid_validity { get; internal set; }
public UID? uid_next { get; internal set; }
@@ -134,12 +156,12 @@ public class Geary.Imap.FolderProperties : Geary.FolderProperties {
Trillian is_openable = Trillian.from_boolean(!attrs.is_no_select);
- base(email_total, email_unread,
- has_children, supports_children, is_openable,
- false, // not local
- false, // not virtual
- !supports_uid);
-
+ this.email_total = email_total;
+ this.email_unread = email_unread;
+ this.has_children = has_children;
+ this.supports_children = supports_children;
+ this.is_openable = is_openable;
+ this.create_never_returns_id = create_never_returns_id;
this.attrs = attrs;
}
@@ -197,8 +219,9 @@ public class Geary.Imap.FolderProperties : Geary.FolderProperties {
/**
* Update an existing {@link FolderProperties} with fresh {@link StatusData}.
*
- * This will force the {@link Geary.FolderProperties.email_total} property to match the
- * {@link status_messages} value.
+ * This will force the {@link
+ * Geary.RemoteFolder.RemoteProperties.email_total} property to
+ * match the {@link status_messages} value.
*/
public void update_status(StatusData status) {
set_status_message_count(status.messages, true);
diff --git a/src/engine/meson.build b/src/engine/meson.build
index 77f6ec9d3..c7dc61ea8 100644
--- a/src/engine/meson.build
+++ b/src/engine/meson.build
@@ -20,7 +20,6 @@ engine_vala_sources = files(
'api/geary-engine-error.vala',
'api/geary-engine.vala',
'api/geary-folder.vala',
- 'api/geary-folder-properties.vala',
'api/geary-folder-supports-archive.vala',
'api/geary-folder-supports-copy.vala',
'api/geary-folder-supports-create.vala',
@@ -254,7 +253,6 @@ engine_vala_sources = files(
'outbox/outbox-email-identifier.vala',
'outbox/outbox-email-properties.vala',
'outbox/outbox-folder.vala',
- 'outbox/outbox-folder-properties.vala',
'rfc822/rfc822.vala',
'rfc822/rfc822-error.vala',
diff --git a/src/engine/outbox/outbox-folder.vala b/src/engine/outbox/outbox-folder.vala
index ce3348522..78a90c720 100644
--- a/src/engine/outbox/outbox-folder.vala
+++ b/src/engine/outbox/outbox-folder.vala
@@ -44,11 +44,8 @@ public class Geary.Outbox.Folder : BaseObject,
/** {@inheritDoc} */
- public override Account account { get { return this._account; } }
-
- /** {@inheritDoc} */
- public override Geary.FolderProperties properties {
- get { return _properties; }
+ public override Account account {
+ get { return this._account; }
}
/**
@@ -58,12 +55,21 @@ public class Geary.Outbox.Folder : BaseObject,
* with the name given by {@link MAGIC_BASENAME}.
*/
public override Geary.Folder.Path path {
- get {
- return _path;
- }
+ get { return this._path; }
}
private Geary.Folder.Path _path;
+ /** {@inheritDoc} */
+ public int email_total {
+ get { return this._email_total; }
+ }
+ private int _email_total = 0;
+
+ /** {@inheritDoc} */
+ public int email_unread {
+ get { return 0; }
+ }
+
/**
* Returns the type of this folder.
*
@@ -82,11 +88,12 @@ public class Geary.Outbox.Folder : BaseObject,
private weak Account _account;
private Db.Database db = null;
- private FolderProperties _properties = new FolderProperties(0, 0);
private int64 next_ordering = 0;
- internal Folder(Account account, Geary.Folder.Root root, Db.Database db) {
+ internal Folder(Account account,
+ Geary.Folder.Root root,
+ Db.Database db) {
this._account = account;
this._path = root.get_child(MAGIC_BASENAME, Trillian.TRUE);
this.db = db;
@@ -98,7 +105,6 @@ public class Geary.Outbox.Folder : BaseObject,
GLib.DateTime? date_received,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
- int email_count = 0;
OutboxRow? row = null;
yield db.exec_transaction_async(Db.TransactionType.WR, (cx) => {
int64 ordering = do_get_next_ordering(cx, cancellable);
@@ -113,20 +119,16 @@ public class Geary.Outbox.Folder : BaseObject,
int position = do_get_position_by_ordering(cx, ordering, cancellable);
row = new OutboxRow(new_id, position, ordering, false, null);
- email_count = do_get_email_count(cx, cancellable);
return Db.TransactionOutcome.COMMIT;
}, cancellable);
- // update properties
- _properties.set_total(yield get_email_count_async(cancellable));
-
- Gee.List<EmailIdentifier> list = new Gee.ArrayList<EmailIdentifier>();
- list.add(row.outbox_id);
+ this._email_total++;
+ notify_property("email-total");
+ var list = Geary.Collection.single(row.outbox_id);
this.account.email_added(list, this);
email_inserted(list);
- email_count_changed(email_count, CountChangeReason.APPENDED);
return row.outbox_id;
}
@@ -159,8 +161,7 @@ public class Geary.Outbox.Folder : BaseObject,
remove_email_async(Gee.Collection<Geary.EmailIdentifier> email_ids,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
- Gee.List<Geary.EmailIdentifier> removed = new Gee.ArrayList<Geary.EmailIdentifier>();
- int final_count = 0;
+ var removed = new Gee.ArrayList<Geary.EmailIdentifier>();
yield db.exec_transaction_async(Db.TransactionType.WR, (cx) => {
foreach (Geary.EmailIdentifier id in email_ids) {
// ignore anything not belonging to the outbox, but also don't report it as removed
@@ -174,20 +175,17 @@ public class Geary.Outbox.Folder : BaseObject,
// never reuse an ordering value while Geary is running.
do_get_next_ordering(cx, cancellable);
- if (do_remove_email(cx, outbox_id, cancellable))
+ if (do_remove_email(cx, outbox_id, cancellable)) {
removed.add(outbox_id);
+ }
}
-
- final_count = do_get_email_count(cx, cancellable);
-
return Db.TransactionOutcome.COMMIT;
}, cancellable);
- if (removed.size >= 0) {
- _properties.set_total(final_count);
-
+ if (!removed.is_empty) {
+ this._email_total -= removed.size;
+ notify_property("email-total");
email_removed(removed);
- email_count_changed(final_count, REMOVED);
}
}
@@ -363,6 +361,21 @@ public class Geary.Outbox.Folder : BaseObject,
return new Logging.State(this, this.path.to_string());
}
+ /** Initialises outbox state from the database */
+ internal async void load(GLib.Cancellable cancellable) throws GLib.Error {
+ yield this.db.exec_transaction_async(
+ RO, (cx) => {
+ Db.Statement stmt = cx.prepare("SELECT COUNT(*) FROM SmtpOutboxTable");
+ Db.Result results = stmt.exec(cancellable);
+ if (!results.finished) {
+ this._email_total = results.int_at(0);
+ }
+ return DONE;
+ },
+ cancellable
+ );
+ }
+
// Utility for getting an email object back from an outbox row.
private Geary.Email row_to_email(OutboxRow row) throws Error {
Geary.Email? email = null;
@@ -388,17 +401,6 @@ public class Geary.Outbox.Folder : BaseObject,
return email;
}
- private async int get_email_count_async(Cancellable? cancellable) throws Error {
- int count = 0;
- yield db.exec_transaction_async(Db.TransactionType.RO, (cx) => {
- count = do_get_email_count(cx, cancellable);
-
- return Db.TransactionOutcome.DONE;
- }, cancellable);
-
- return count;
- }
-
//
// Transaction helper methods
//
@@ -419,14 +421,6 @@ public class Geary.Outbox.Folder : BaseObject,
}
}
- private int do_get_email_count(Db.Connection cx, Cancellable? cancellable) throws Error {
- Db.Statement stmt = cx.prepare("SELECT COUNT(*) FROM SmtpOutboxTable");
-
- Db.Result results = stmt.exec(cancellable);
-
- return (!results.finished) ? results.int_at(0) : 0;
- }
-
private int do_get_position_by_ordering(Db.Connection cx, int64 ordering, Cancellable? cancellable)
throws Error {
Db.Statement stmt = cx.prepare(
diff --git a/test/engine/app/app-conversation-monitor-test.vala
b/test/engine/app/app-conversation-monitor-test.vala
index bd8c8911d..36be8abc5 100644
--- a/test/engine/app/app-conversation-monitor-test.vala
+++ b/test/engine/app/app-conversation-monitor-test.vala
@@ -59,7 +59,6 @@ class Geary.App.ConversationMonitorTest : TestCase {
);
this.other_folder = new Mock.Folder(
this.account,
- null,
this.folder_root.get_child("other"),
NONE,
null
@@ -167,7 +166,6 @@ class Geary.App.ConversationMonitorTest : TestCase {
throws GLib.Error {
var test_article = new Mock.Folder(
this.account,
- null,
this.folder_root.get_child("base"),
NONE,
null
diff --git a/test/engine/app/app-conversation-set-test.vala b/test/engine/app/app-conversation-set-test.vala
index ef84c81d3..a00daf2aa 100644
--- a/test/engine/app/app-conversation-set-test.vala
+++ b/test/engine/app/app-conversation-set-test.vala
@@ -30,7 +30,6 @@ class Geary.App.ConversationSetTest : TestCase {
public override void set_up() {
this.folder_root = new Folder.Root("#test", false);
this.base_folder = new Mock.Folder(
- null,
null,
this.folder_root.get_child("test"),
NONE,
diff --git a/test/engine/app/app-conversation-test.vala b/test/engine/app/app-conversation-test.vala
index 194f11c65..a1fff997b 100644
--- a/test/engine/app/app-conversation-test.vala
+++ b/test/engine/app/app-conversation-test.vala
@@ -30,7 +30,6 @@ class Geary.App.ConversationTest : TestCase {
public override void set_up() {
this.folder_root = new Folder.Root("#test", false);
this.base_folder = new Mock.Folder(
- null,
null,
this.folder_root.get_child("test"),
NONE,
diff --git a/test/meson.build b/test/meson.build
index de8adf0b9..973727996 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -13,7 +13,6 @@ libmock_sources = [
'mock/mock-email-identifier.vala',
'mock/mock-email-properties.vala',
'mock/mock-folder.vala',
- 'mock/mock-folder-properties.vala',
'mock/mock-remote-folder.vala',
'mock/mock-search-query.vala',
]
diff --git a/test/mock/mock-account.vala b/test/mock/mock-account.vala
index 192508922..e1f9d72a9 100644
--- a/test/mock/mock-account.vala
+++ b/test/mock/mock-account.vala
@@ -84,7 +84,7 @@ public class Mock.Account : Geary.Account,
return object_call<Folder>(
"create_personal_folder",
{ box_arg(name), box_arg(use), cancellable },
- new Folder(null, null, null, use, null)
+ new Folder(null, null, use, null)
);
}
@@ -141,7 +141,7 @@ public class Mock.Account : Geary.Account,
} catch (Geary.EngineError.NOT_FOUND err) {
throw err;
} catch (GLib.Error err) {
- return new Folder(null, null, null, NONE, null);
+ return new Folder(null, null, NONE, null);
}
}
diff --git a/test/mock/mock-folder.vala b/test/mock/mock-folder.vala
index ee274b24f..43737e1b5 100644
--- a/test/mock/mock-folder.vala
+++ b/test/mock/mock-folder.vala
@@ -16,14 +16,18 @@ public class Mock.Folder : GLib.Object,
get { return this._account; }
}
- public override Geary.FolderProperties properties {
- get { return this._properties; }
- }
-
public override Geary.Folder.Path path {
get { return this._path; }
}
+ public override int email_total {
+ get { return this._email_total; }
+ }
+
+ public override int email_unread {
+ get { return this._email_unread; }
+ }
+
public override Geary.Folder.SpecialUse used_as {
get { return this._used_as; }
}
@@ -38,19 +42,18 @@ public class Mock.Folder : GLib.Object,
private Geary.Account _account;
- private Geary.FolderProperties _properties;
private Geary.Folder.Path _path;
+ private int _email_total = 0;
+ private int _email_unread = 0;
private Geary.Folder.SpecialUse _used_as;
private Geary.ProgressMonitor _opening_monitor;
public Folder(Geary.Account? account,
- Geary.FolderProperties? properties,
Geary.Folder.Path? path,
Geary.Folder.SpecialUse used_as,
Geary.ProgressMonitor? monitor) {
this._account = account;
- this._properties = properties ?? new FolderPoperties();
this._path = path;
this._used_as = used_as;
this._opening_monitor = monitor;
diff --git a/test/mock/mock-remote-folder.vala b/test/mock/mock-remote-folder.vala
index 8b9b1fc92..9255eccf6 100644
--- a/test/mock/mock-remote-folder.vala
+++ b/test/mock/mock-remote-folder.vala
@@ -13,18 +13,52 @@ public class Mock.RemoteFolder : GLib.Object,
ValaUnit.MockObject {
+ public class RemoteProperties : GLib.Object,
+ Geary.RemoteFolder.RemoteProperties {
+
+
+ public int email_total { get; protected set; default = 0; }
+
+ public int email_unread { get; protected set; default = 0; }
+
+ public Geary.Trillian has_children {
+ get; protected set; default = Geary.Trillian.UNKNOWN;
+ }
+
+ public Geary.Trillian supports_children {
+ get; protected set; default = Geary.Trillian.UNKNOWN;
+ }
+
+ public Geary.Trillian is_openable {
+ get; protected set; default = Geary.Trillian.UNKNOWN;
+ }
+
+ public bool create_never_returns_id {
+ get; protected set; default = false;
+ }
+
+ }
+
public Geary.Account account {
get { return this._account; }
}
- public Geary.FolderProperties properties {
- get { return this._properties; }
+ public Geary.RemoteFolder.RemoteProperties remote_properties {
+ get { return this._remote_properties; }
}
public Geary.Folder.Path path {
get { return this._path; }
}
+ public override int email_total {
+ get { return this._email_total; }
+ }
+
+ public override int email_unread {
+ get { return this._email_unread; }
+ }
+
public Geary.Folder.SpecialUse used_as {
get { return this._used_as; }
}
@@ -49,21 +83,23 @@ public class Mock.RemoteFolder : GLib.Object,
private Geary.Account _account;
- private Geary.FolderProperties _properties;
+ private Geary.RemoteFolder.RemoteProperties _remote_properties;
private Geary.Folder.Path _path;
+ private int _email_total = 0;
+ private int _email_unread = 0;
private Geary.Folder.SpecialUse _used_as;
private Geary.ProgressMonitor _opening_monitor;
public RemoteFolder(Geary.Account? account,
- Geary.FolderProperties? properties,
+ Geary.RemoteFolder.RemoteProperties? remote_properties,
Geary.Folder.Path? path,
Geary.Folder.SpecialUse used_as,
Geary.ProgressMonitor? monitor,
bool is_monitoring,
bool is_fully_expanded) {
this._account = account;
- this._properties = properties ?? new FolderPoperties();
+ this._remote_properties = remote_properties ?? new RemoteProperties();
this._path = path;
this._used_as = used_as;
this._opening_monitor = monitor;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]