Application.Controller, Composer.Widget: Clean up composer construction
Clean up and simplify how composers are constructed. Ensure all composers are constructed via Application.Composer. Provide a set of APIs for constructing different kinds of composers with minimal parameters, rather than having one method with eleventy different parameters. Mirror API changes in Composer.Widget by splitting `load` method up into a method for each different composer type. Clean up internals a bit as a result. Rename `ComposeType` enum and its values to `ContextType` to better reflect what it does.
This commit is contained in:
parent
a98f953237
commit
aac59ec53b
10 changed files with 417 additions and 482 deletions
|
|
@ -513,7 +513,7 @@ public class Application.Client : Gtk.Application {
|
|||
mailto.substring(B0RKED_GLIB_MAILTO_PREFIX.length)
|
||||
);
|
||||
}
|
||||
this.new_composer.begin(mailto);
|
||||
this.new_composer_mailto.begin(mailto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -725,10 +725,14 @@ public class Application.Client : Gtk.Application {
|
|||
prefs.show();
|
||||
}
|
||||
|
||||
public async void new_composer(string? mailto) {
|
||||
public async void new_composer(Geary.RFC822.MailboxAddress? to = null) {
|
||||
yield this.present();
|
||||
yield this.controller.compose_new_email(to);
|
||||
}
|
||||
|
||||
this.controller.compose(mailto);
|
||||
public async void new_composer_mailto(string? mailto) {
|
||||
yield this.present();
|
||||
yield this.controller.compose_mailto(mailto);
|
||||
}
|
||||
|
||||
public async void new_window(Geary.Folder? select_folder,
|
||||
|
|
@ -824,7 +828,7 @@ public class Application.Client : Gtk.Application {
|
|||
yield create_controller();
|
||||
|
||||
if (uri.down().has_prefix(MAILTO_URI_SCHEME_PREFIX)) {
|
||||
yield this.new_composer(uri);
|
||||
yield this.new_composer_mailto(uri);
|
||||
} else {
|
||||
string uri_ = uri;
|
||||
// Support web URLs that omit the protocol.
|
||||
|
|
@ -1146,7 +1150,7 @@ public class Application.Client : Gtk.Application {
|
|||
}
|
||||
|
||||
private void on_activate_compose() {
|
||||
this.new_composer.begin(null);
|
||||
this.new_composer.begin();
|
||||
}
|
||||
|
||||
private void on_activate_inspect() {
|
||||
|
|
@ -1155,7 +1159,7 @@ public class Application.Client : Gtk.Application {
|
|||
|
||||
private void on_activate_mailto(SimpleAction action, Variant? param) {
|
||||
if (param != null) {
|
||||
this.new_composer.begin(param.get_string());
|
||||
this.new_composer_mailto.begin(param.get_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,16 +212,6 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
this.expunge_accounts.begin();
|
||||
}
|
||||
|
||||
/** Returns a context for an account, if any. */
|
||||
internal AccountContext? get_context_for_account(Geary.AccountInformation account) {
|
||||
return this.accounts.get(account);
|
||||
}
|
||||
|
||||
/** Returns a read-only collection of contexts each active account. */
|
||||
internal Gee.Collection<AccountContext> get_account_contexts() {
|
||||
return this.accounts.values.read_only_view;
|
||||
}
|
||||
|
||||
/** Closes all windows and accounts, releasing held resources. */
|
||||
public async void close() {
|
||||
// Stop listening for account changes up front so we don't
|
||||
|
|
@ -333,20 +323,48 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Opens or queues a new composer addressed to a specific email address.
|
||||
* Opens a composer for writing a new, blank message.
|
||||
*/
|
||||
public void compose(string? mailto = null) {
|
||||
public async void compose_new_email(Geary.RFC822.MailboxAddress? to = null) {
|
||||
// If there's already an empty composer open, just use that
|
||||
foreach (Composer.Widget existing in this.composer_widgets) {
|
||||
if (existing != null &&
|
||||
existing.current_mode == PANED &&
|
||||
existing.is_blank) {
|
||||
existing.present();
|
||||
}
|
||||
}
|
||||
|
||||
var composer = new Composer.Widget(
|
||||
this.application,
|
||||
this.application.get_active_main_window().selected_account
|
||||
);
|
||||
register_composer(composer);
|
||||
show_composer(composer, null);
|
||||
try {
|
||||
yield composer.load_empty_body(to);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a composer with the given `mailto:` URL.
|
||||
*/
|
||||
public async void compose_mailto(string mailto) {
|
||||
MainWindow? window = this.application.last_active_main_window;
|
||||
if (window != null && window.selected_account != null) {
|
||||
create_compose_widget(
|
||||
window,
|
||||
window.selected_account,
|
||||
NEW_MESSAGE,
|
||||
mailto,
|
||||
null,
|
||||
null,
|
||||
false
|
||||
var composer = new Composer.Widget(
|
||||
this.application, window.selected_account
|
||||
);
|
||||
register_composer(composer);
|
||||
show_composer(composer, null);
|
||||
|
||||
try {
|
||||
yield composer.load_mailto(mailto);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
} else {
|
||||
// Schedule the send for after we have an account open.
|
||||
this.pending_mailtos.add(mailto);
|
||||
|
|
@ -355,90 +373,67 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
|
||||
/**
|
||||
* Opens new composer with an existing message as context.
|
||||
*
|
||||
* If the given type is {@link Composer.Widget.ContextType.EDIT},
|
||||
* the context is loaded to be edited (e.g. for drafts, templates,
|
||||
* sending again. Otherwise the context is treated as the email to
|
||||
* be replied to, etc.
|
||||
*/
|
||||
public void compose_with_context_email(MainWindow to_show,
|
||||
Geary.Account account,
|
||||
Composer.Widget.ComposeType type,
|
||||
Geary.Email context,
|
||||
string? quote,
|
||||
bool is_draft) {
|
||||
create_compose_widget(
|
||||
to_show, account, type, null, context, quote, is_draft
|
||||
);
|
||||
}
|
||||
public async void compose_with_context_email(Composer.Widget.ContextType type,
|
||||
Geary.Email context,
|
||||
string? quote) {
|
||||
MainWindow show_on = this.application.get_active_main_window();
|
||||
if (type == EDIT) {
|
||||
// Check all known composers since the context may be open
|
||||
// an existing composer already.
|
||||
foreach (Composer.Widget composer in this.composer_widgets) {
|
||||
if (composer.saved_id != null &&
|
||||
composer.saved_id.equal_to(context.id)) {
|
||||
composer.present();
|
||||
composer.set_focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// See whether there is already an inline message in the
|
||||
// current window that is either a reply/forward for that
|
||||
// message, or there is a quote to insert into it.
|
||||
foreach (Composer.Widget existing in this.composer_widgets) {
|
||||
if (existing.get_toplevel() == show_on &&
|
||||
(existing.current_mode == INLINE ||
|
||||
existing.current_mode == INLINE_COMPACT) &&
|
||||
(context.id in existing.get_referred_ids() ||
|
||||
quote != null)) {
|
||||
try {
|
||||
existing.append_to_email(context, quote, type);
|
||||
existing.present();
|
||||
return;
|
||||
} catch (Geary.EngineError error) {
|
||||
report_problem(new Geary.ProblemReport(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a new composer to be kept track of. */
|
||||
public void add_composer(Composer.Widget widget) {
|
||||
debug(@"Added composer of type $(widget.compose_type); $(this.composer_widgets.size) composers total");
|
||||
widget.destroy.connect_after(this.on_composer_widget_destroy);
|
||||
this.composer_widgets.add(widget);
|
||||
}
|
||||
|
||||
/** Returns a read-only collection of currently open composers .*/
|
||||
public Gee.Collection<Composer.Widget> get_composers() {
|
||||
return this.composer_widgets.read_only_view;
|
||||
}
|
||||
|
||||
/** Opens any pending composers. */
|
||||
public void process_pending_composers() {
|
||||
foreach (string? mailto in this.pending_mailtos) {
|
||||
compose(mailto);
|
||||
}
|
||||
this.pending_mailtos.clear();
|
||||
}
|
||||
|
||||
/** Queues the email in a composer for delivery. */
|
||||
public async void send_composed_email(Composer.Widget composer) {
|
||||
AccountContext? context = this.accounts.get(
|
||||
composer.account.information
|
||||
);
|
||||
if (context != null) {
|
||||
try {
|
||||
yield context.commands.execute(
|
||||
new SendComposerCommand(this.application, context, composer),
|
||||
context.cancellable
|
||||
);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
// Can't re-use an existing composer, so need to create a
|
||||
// new one. Replies must open inline in the main window,
|
||||
// so we need to ensure there are no composers open there
|
||||
// first.
|
||||
if (!show_on.close_composer(true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Saves the email in a composer as a draft on the server. */
|
||||
public async void save_composed_email(Composer.Widget composer) {
|
||||
// XXX this doesn't actually do what it says on the tin, since
|
||||
// the composer's draft manager is already saving drafts on
|
||||
// the server. Until we get that saving local-only, this will
|
||||
// only be around for pushing the composer onto the undo stack
|
||||
AccountContext? context = this.accounts.get(
|
||||
composer.account.information
|
||||
var composer = new Composer.Widget(
|
||||
this.application,
|
||||
this.application.get_active_main_window().selected_account
|
||||
);
|
||||
if (context != null) {
|
||||
try {
|
||||
yield context.commands.execute(
|
||||
new SaveComposerCommand(this, composer),
|
||||
context.cancellable
|
||||
);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
register_composer(composer);
|
||||
show_composer(composer, Geary.Collection.single(context.id));
|
||||
|
||||
/** Queues a composer to be discarded. */
|
||||
public async void discard_composed_email(Composer.Widget composer) {
|
||||
AccountContext? context = this.accounts.get(
|
||||
composer.account.information
|
||||
);
|
||||
if (context != null) {
|
||||
try {
|
||||
yield context.commands.execute(
|
||||
new DiscardComposerCommand(this, composer),
|
||||
context.cancellable
|
||||
);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
try {
|
||||
yield composer.load_context(type, context, quote);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -858,6 +853,16 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
}
|
||||
}
|
||||
|
||||
/** Returns a context for an account, if any. */
|
||||
internal AccountContext? get_context_for_account(Geary.AccountInformation account) {
|
||||
return this.accounts.get(account);
|
||||
}
|
||||
|
||||
/** Returns a read-only collection of contexts each active account. */
|
||||
internal Gee.Collection<AccountContext> get_account_contexts() {
|
||||
return this.accounts.values.read_only_view;
|
||||
}
|
||||
|
||||
internal void register_window(MainWindow window) {
|
||||
window.retry_service_problem.connect(on_retry_service_problem);
|
||||
}
|
||||
|
|
@ -866,6 +871,69 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
window.retry_service_problem.disconnect(on_retry_service_problem);
|
||||
}
|
||||
|
||||
/** Opens any pending composers. */
|
||||
internal async void process_pending_composers() {
|
||||
foreach (string? mailto in this.pending_mailtos) {
|
||||
yield compose_mailto(mailto);
|
||||
}
|
||||
this.pending_mailtos.clear();
|
||||
}
|
||||
|
||||
/** Queues the email in a composer for delivery. */
|
||||
internal async void send_composed_email(Composer.Widget composer) {
|
||||
AccountContext? context = this.accounts.get(
|
||||
composer.account.information
|
||||
);
|
||||
if (context != null) {
|
||||
try {
|
||||
yield context.commands.execute(
|
||||
new SendComposerCommand(this.application, context, composer),
|
||||
context.cancellable
|
||||
);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Saves the email in a composer as a draft on the server. */
|
||||
internal async void save_composed_email(Composer.Widget composer) {
|
||||
// XXX this doesn't actually do what it says on the tin, since
|
||||
// the composer's draft manager is already saving drafts on
|
||||
// the server. Until we get that saving local-only, this will
|
||||
// only be around for pushing the composer onto the undo stack
|
||||
AccountContext? context = this.accounts.get(
|
||||
composer.account.information
|
||||
);
|
||||
if (context != null) {
|
||||
try {
|
||||
yield context.commands.execute(
|
||||
new SaveComposerCommand(this, composer),
|
||||
context.cancellable
|
||||
);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Queues a composer to be discarded. */
|
||||
internal async void discard_composed_email(Composer.Widget composer) {
|
||||
AccountContext? context = this.accounts.get(
|
||||
composer.account.information
|
||||
);
|
||||
if (context != null) {
|
||||
try {
|
||||
yield context.commands.execute(
|
||||
new DiscardComposerCommand(this, composer),
|
||||
context.cancellable
|
||||
);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Expunges removed accounts while the controller remains open. */
|
||||
internal async void expunge_accounts() {
|
||||
try {
|
||||
|
|
@ -1330,13 +1398,8 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
|
||||
/** Displays a composer on the last active main window. */
|
||||
internal void show_composer(Composer.Widget composer,
|
||||
Gee.Collection<Geary.EmailIdentifier>? refers_to,
|
||||
MainWindow? show_on) {
|
||||
var target = show_on;
|
||||
if (target == null) {
|
||||
target = this.application.get_active_main_window();
|
||||
}
|
||||
|
||||
Gee.Collection<Geary.EmailIdentifier>? refers_to) {
|
||||
var target = this.application.get_active_main_window();
|
||||
target.show_composer(composer, refers_to);
|
||||
composer.set_focus();
|
||||
}
|
||||
|
|
@ -1352,135 +1415,17 @@ internal class Application.Controller : Geary.BaseObject {
|
|||
return do_quit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a composer widget.
|
||||
*
|
||||
* Depending on the arguments, this can be inline in the
|
||||
* conversation or as a new window.
|
||||
*
|
||||
* @param compose_type - Whether it's a new message, a reply, a
|
||||
* forwarded mail, ...
|
||||
* @param referred - The mail of which we should copy the from/to/...
|
||||
* addresses
|
||||
* @param quote - The quote after the mail body
|
||||
* @param mailto - A "mailto:"-link
|
||||
* @param is_draft - Whether we're starting from a draft (true) or
|
||||
* a new mail (false)
|
||||
*/
|
||||
private void create_compose_widget(MainWindow show_on,
|
||||
Geary.Account account,
|
||||
Composer.Widget.ComposeType compose_type,
|
||||
string? mailto,
|
||||
Geary.Email? referred,
|
||||
string? quote,
|
||||
bool is_draft) {
|
||||
// There's a few situations where we can re-use an existing
|
||||
// composer, check for these first.
|
||||
if (compose_type == NEW_MESSAGE && !is_draft) {
|
||||
// We're creating a new message that isn't a draft, if
|
||||
// there's already an empty composer open, just use
|
||||
// that
|
||||
foreach (Composer.Widget existing in this.composer_widgets) {
|
||||
if (existing != null &&
|
||||
existing.current_mode == PANED &&
|
||||
existing.is_blank) {
|
||||
existing.present();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (compose_type != NEW_MESSAGE && referred != null) {
|
||||
// A reply/forward was requested, see whether there is
|
||||
// already an inline message in the target window that is
|
||||
// either a reply/forward for that message, or there is a
|
||||
// quote to insert into it.
|
||||
foreach (Composer.Widget existing in this.composer_widgets) {
|
||||
if (existing.get_toplevel() == show_on &&
|
||||
(existing.current_mode == INLINE ||
|
||||
existing.current_mode == INLINE_COMPACT) &&
|
||||
(referred.id in existing.get_referred_ids() ||
|
||||
quote != null)) {
|
||||
try {
|
||||
existing.append_to_email(referred, quote, compose_type);
|
||||
existing.present();
|
||||
return;
|
||||
} catch (Geary.EngineError error) {
|
||||
report_problem(new Geary.ProblemReport(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can't re-use an existing composer, so need to create a
|
||||
// new one. Replies must open inline in the main window,
|
||||
// so we need to ensure there are no composers open there
|
||||
// first.
|
||||
if (!show_on.close_composer(true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Composer.Widget widget;
|
||||
if (mailto != null) {
|
||||
widget = new Composer.Widget.from_mailto(
|
||||
this.application, account, mailto
|
||||
);
|
||||
} else {
|
||||
widget = new Composer.Widget(
|
||||
this.application, account, compose_type
|
||||
);
|
||||
}
|
||||
|
||||
add_composer(widget);
|
||||
show_composer(
|
||||
widget,
|
||||
referred != null ? Geary.Collection.single(referred.id) : null,
|
||||
show_on
|
||||
);
|
||||
|
||||
this.load_composer.begin(
|
||||
account,
|
||||
widget,
|
||||
referred,
|
||||
is_draft,
|
||||
quote
|
||||
);
|
||||
}
|
||||
|
||||
private async void load_composer(Geary.Account account,
|
||||
Composer.Widget widget,
|
||||
Geary.Email? referred = null,
|
||||
bool is_draft,
|
||||
string? quote = null) {
|
||||
Geary.Email? full = null;
|
||||
GLib.Cancellable? cancellable = null;
|
||||
if (referred != null) {
|
||||
AccountContext? context = this.accounts.get(account.information);
|
||||
if (context != null) {
|
||||
cancellable = context.cancellable;
|
||||
try {
|
||||
full = yield context.emails.fetch_email_async(
|
||||
referred.id,
|
||||
Geary.ComposedEmail.REQUIRED_REPLY_FIELDS |
|
||||
Composer.Widget.REQUIRED_FIELDS,
|
||||
NONE,
|
||||
cancellable
|
||||
);
|
||||
} catch (Error e) {
|
||||
message("Could not load full message: %s", e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
yield widget.load(full, is_draft, quote, cancellable);
|
||||
} catch (GLib.Error err) {
|
||||
report_problem(new Geary.ProblemReport(err));
|
||||
}
|
||||
internal void register_composer(Composer.Widget widget) {
|
||||
debug(@"Registered composer of type $(widget.context_type); $(this.composer_widgets.size) composers total");
|
||||
widget.destroy.connect_after(this.on_composer_widget_destroy);
|
||||
this.composer_widgets.add(widget);
|
||||
}
|
||||
|
||||
private void on_composer_widget_destroy(Gtk.Widget sender) {
|
||||
Composer.Widget? composer = sender as Composer.Widget;
|
||||
if (composer != null) {
|
||||
composer_widgets.remove((Composer.Widget) sender);
|
||||
debug(@"Composer type $(composer.compose_type) destroyed; " +
|
||||
debug(@"Composer type $(composer.context_type) destroyed; " +
|
||||
@"$(this.composer_widgets.size) composers remaining");
|
||||
}
|
||||
}
|
||||
|
|
@ -2485,7 +2430,6 @@ private class Application.SendComposerCommand : ComposerCommand {
|
|||
public override async void execute(GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
Geary.ComposedEmail email = yield this.composer.get_composed_email();
|
||||
|
||||
if (this.can_undo) {
|
||||
/// Translators: The label for an in-app notification. The
|
||||
/// string substitution is a list of recipients of the email.
|
||||
|
|
@ -2510,7 +2454,9 @@ private class Application.SendComposerCommand : ComposerCommand {
|
|||
this.saved = null;
|
||||
|
||||
this.composer.set_enabled(true);
|
||||
this.application.controller.show_composer(this.composer, null, null);
|
||||
this.application.controller.show_composer(
|
||||
this.composer, this.composer.get_referred_ids()
|
||||
);
|
||||
clear_composer();
|
||||
}
|
||||
|
||||
|
|
@ -2564,7 +2510,9 @@ private class Application.SaveComposerCommand : ComposerCommand {
|
|||
if (this.composer != null) {
|
||||
this.destroy_timer.reset();
|
||||
this.composer.set_enabled(true);
|
||||
this.controller.show_composer(this.composer, null, null);
|
||||
this.controller.show_composer(
|
||||
this.composer, this.composer.get_referred_ids()
|
||||
);
|
||||
clear_composer();
|
||||
} else {
|
||||
/// Translators: A label for an in-app notification.
|
||||
|
|
@ -2622,7 +2570,9 @@ private class Application.DiscardComposerCommand : ComposerCommand {
|
|||
if (this.composer != null) {
|
||||
this.destroy_timer.reset();
|
||||
this.composer.set_enabled(true);
|
||||
this.controller.show_composer(this.composer, null, null);
|
||||
this.controller.show_composer(
|
||||
this.composer, this.composer.get_referred_ids()
|
||||
);
|
||||
clear_composer();
|
||||
} else {
|
||||
/// Translators: A label for an in-app notification.
|
||||
|
|
|
|||
|
|
@ -766,7 +766,7 @@ public class Application.MainWindow :
|
|||
);
|
||||
|
||||
yield open_conversation_monitor(this.conversations, cancellable);
|
||||
this.controller.process_pending_composers();
|
||||
yield this.controller.process_pending_composers();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -864,16 +864,6 @@ public class Application.MainWindow :
|
|||
}
|
||||
}
|
||||
|
||||
/** Displays a composer addressed to a specific email address. */
|
||||
public void open_composer_for_mailbox(Geary.RFC822.MailboxAddress to) {
|
||||
var composer = new Composer.Widget.from_mailbox(
|
||||
this.application, this.selected_folder.account, to
|
||||
);
|
||||
this.controller.add_composer(composer);
|
||||
show_composer(composer, null);
|
||||
composer.load.begin(null, false, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a composer in the window if possible, else in a new window.
|
||||
*
|
||||
|
|
@ -883,8 +873,8 @@ public class Application.MainWindow :
|
|||
* the composer's {@link Composer.Widget.get_referred_ids} will be
|
||||
* used.
|
||||
*/
|
||||
public void show_composer(Composer.Widget composer,
|
||||
Gee.Collection<Geary.EmailIdentifier>? refers_to) {
|
||||
internal void show_composer(Composer.Widget composer,
|
||||
Gee.Collection<Geary.EmailIdentifier>? refers_to) {
|
||||
if (this.has_composer) {
|
||||
composer.detach();
|
||||
} else {
|
||||
|
|
@ -923,7 +913,7 @@ public class Application.MainWindow :
|
|||
* Returns true if none were open or the user approved closing
|
||||
* them.
|
||||
*/
|
||||
public bool close_composer(bool should_prompt, bool is_shutdown = false) {
|
||||
internal bool close_composer(bool should_prompt, bool is_shutdown = false) {
|
||||
bool closed = true;
|
||||
Composer.Widget? composer = this.conversation_viewer.current_composer;
|
||||
if (composer != null &&
|
||||
|
|
@ -1547,7 +1537,7 @@ public class Application.MainWindow :
|
|||
);
|
||||
}
|
||||
|
||||
private void create_composer_from_viewer(Composer.Widget.ComposeType compose_type) {
|
||||
private void create_composer_from_viewer(Composer.Widget.ContextType type) {
|
||||
Geary.Account? account = this.selected_account;
|
||||
ConversationEmail? email_view = null;
|
||||
ConversationListBox? list_view = this.conversation_viewer.current_list;
|
||||
|
|
@ -1557,13 +1547,8 @@ public class Application.MainWindow :
|
|||
if (account != null && email_view != null) {
|
||||
email_view.get_selection_for_quoting.begin((obj, res) => {
|
||||
string? quote = email_view.get_selection_for_quoting.end(res);
|
||||
this.controller.compose_with_context_email(
|
||||
this,
|
||||
account,
|
||||
compose_type,
|
||||
email_view.email,
|
||||
quote,
|
||||
false
|
||||
this.controller.compose_with_context_email.begin(
|
||||
type, email_view.email, quote ?? ""
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -2043,7 +2028,6 @@ public class Application.MainWindow :
|
|||
list.reply_to_all_email.connect(on_email_reply_to_all);
|
||||
list.reply_to_sender_email.connect(on_email_reply_to_sender);
|
||||
list.forward_email.connect(on_email_forward);
|
||||
list.edit_email.connect(on_email_edit);
|
||||
list.trash_email.connect(on_email_trash);
|
||||
list.delete_email.connect(on_email_delete);
|
||||
}
|
||||
|
|
@ -2102,31 +2086,9 @@ public class Application.MainWindow :
|
|||
// TODO: Determine how to map between conversations
|
||||
// and drafts correctly.
|
||||
Geary.Email draft = activated.get_latest_recv_email(IN_FOLDER);
|
||||
|
||||
// Check all known composers since the draft may be
|
||||
// open in a detached composer
|
||||
bool already_open = false;
|
||||
foreach (Composer.Widget composer
|
||||
in this.controller.get_composers()) {
|
||||
if (composer.current_draft_id != null &&
|
||||
composer.current_draft_id.equal_to(draft.id)) {
|
||||
already_open = true;
|
||||
composer.present();
|
||||
composer.set_focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!already_open) {
|
||||
this.controller.compose_with_context_email(
|
||||
this,
|
||||
activated.base_folder.account,
|
||||
NEW_MESSAGE,
|
||||
draft,
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
this.controller.compose_with_context_email.begin(
|
||||
EDIT, draft, null
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2153,7 +2115,7 @@ public class Application.MainWindow :
|
|||
}
|
||||
|
||||
private void on_reply_conversation() {
|
||||
create_composer_from_viewer(REPLY);
|
||||
create_composer_from_viewer(REPLY_SENDER);
|
||||
}
|
||||
|
||||
private void on_reply_all_conversation() {
|
||||
|
|
@ -2476,37 +2438,25 @@ public class Application.MainWindow :
|
|||
}
|
||||
|
||||
private void on_email_reply_to_sender(Geary.Email target, string? quote) {
|
||||
Geary.Account? account = this.selected_account;
|
||||
if (account != null) {
|
||||
this.controller.compose_with_context_email(
|
||||
this, account, REPLY, target, quote, false
|
||||
if (this.selected_account != null) {
|
||||
this.controller.compose_with_context_email.begin(
|
||||
REPLY_SENDER, target, quote
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void on_email_reply_to_all(Geary.Email target, string? quote) {
|
||||
Geary.Account? account = this.selected_account;
|
||||
if (account != null) {
|
||||
this.controller.compose_with_context_email(
|
||||
this, account, REPLY_ALL, target, quote, false
|
||||
if (this.selected_account != null) {
|
||||
this.controller.compose_with_context_email.begin(
|
||||
REPLY_ALL, target, quote
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void on_email_forward(Geary.Email target, string? quote) {
|
||||
Geary.Account? account = this.selected_account;
|
||||
if (account != null) {
|
||||
this.controller.compose_with_context_email(
|
||||
this, account, FORWARD, target, quote, false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void on_email_edit(Geary.Email target) {
|
||||
Geary.Account? account = this.selected_account;
|
||||
if (account != null) {
|
||||
this.controller.compose_with_context_email(
|
||||
this, account, NEW_MESSAGE, target, null, true
|
||||
if (this.selected_account != null) {
|
||||
this.controller.compose_with_context_email.begin(
|
||||
FORWARD, target, quote
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,12 +183,7 @@ public class Application.PluginManager : GLib.Object {
|
|||
}
|
||||
|
||||
public void show() {
|
||||
var composer = new Composer.Widget(
|
||||
this.application, this.account.account, NEW_MESSAGE
|
||||
);
|
||||
var main_window = this.application.get_active_main_window();
|
||||
main_window.show_composer(composer, null);
|
||||
composer.load.begin(null, false, null, null);
|
||||
this.application.controller.compose_new_email.begin();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public class Composer.Embed : Gtk.EventBox, Container {
|
|||
this.composer.embed_header();
|
||||
|
||||
Widget.PresentationMode mode = INLINE_COMPACT;
|
||||
if (composer.compose_type == FORWARD ||
|
||||
if (composer.context_type == FORWARD ||
|
||||
composer.has_multiple_from_addresses) {
|
||||
mode = INLINE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ public class Composer.WebView : ClientWebView {
|
|||
public new void load_html(string body,
|
||||
string quote,
|
||||
bool top_posting,
|
||||
bool is_draft) {
|
||||
bool body_complete) {
|
||||
const string HTML_PRE = """<html><body class="%s">""";
|
||||
const string HTML_POST = """</body></html>""";
|
||||
const string BODY_PRE = """
|
||||
|
|
@ -165,7 +165,7 @@ public class Composer.WebView : ClientWebView {
|
|||
StringBuilder html = new StringBuilder();
|
||||
string body_class = (this.is_rich_text) ? "" : "plain";
|
||||
html.append(HTML_PRE.printf(body_class));
|
||||
if (!is_draft) {
|
||||
if (!body_complete) {
|
||||
html.append(BODY_PRE);
|
||||
bool have_body = !Geary.String.is_empty(body);
|
||||
if (have_body) {
|
||||
|
|
@ -185,7 +185,7 @@ public class Composer.WebView : ClientWebView {
|
|||
html.append_printf(QUOTE, quote);
|
||||
}
|
||||
} else {
|
||||
html.append(quote);
|
||||
html.append(body);
|
||||
}
|
||||
html.append(HTML_POST);
|
||||
base.load_html((string) html.data);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
* Copyright 2017-2019 Michael Gratton <mike@vee.net>
|
||||
* Copyright © 2016 Software Freedom Conservancy Inc.
|
||||
* Copyright © 2017-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.
|
||||
|
|
@ -25,15 +25,31 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
|
||||
|
||||
/** The email fields the composer requires for referred email. */
|
||||
public const Geary.Email.Field REQUIRED_FIELDS = ENVELOPE | BODY;
|
||||
public const Geary.Email.Field REQUIRED_FIELDS = ENVELOPE | HEADER | BODY;
|
||||
|
||||
/// Translators: Title for an empty composer window
|
||||
private const string DEFAULT_TITLE = _("New Message");
|
||||
|
||||
/**
|
||||
* Determines the type of the context email passed to the composer
|
||||
*
|
||||
* @see context_type
|
||||
* @see load_context
|
||||
*/
|
||||
public enum ContextType {
|
||||
/** No context mail was provided. */
|
||||
NONE,
|
||||
|
||||
public enum ComposeType {
|
||||
NEW_MESSAGE,
|
||||
REPLY,
|
||||
/** Context is an email to edited, for example a draft or template. */
|
||||
EDIT,
|
||||
|
||||
/** Context is an email being replied to the sender only. */
|
||||
REPLY_SENDER,
|
||||
|
||||
/** Context is an email being replied to all recipients. */
|
||||
REPLY_ALL,
|
||||
|
||||
/** Context is an email being forwarded. */
|
||||
FORWARD
|
||||
}
|
||||
|
||||
|
|
@ -242,17 +258,17 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
/** The account the email is being sent from. */
|
||||
public Geary.Account account { get; private set; }
|
||||
|
||||
/** The identifier of the draft this composer holds, if any. */
|
||||
public Geary.EmailIdentifier? current_draft_id {
|
||||
/** The identifier of the saved email this composer holds, if any. */
|
||||
public Geary.EmailIdentifier? saved_id {
|
||||
get; private set; default = null;
|
||||
}
|
||||
|
||||
/** Determines the type of the context email. */
|
||||
public ContextType context_type { get; private set; default = NONE; }
|
||||
|
||||
/** Determines the composer's current presentation mode. */
|
||||
public PresentationMode current_mode { get; set; default = NONE; }
|
||||
|
||||
/** Determines the type of email being composed. */
|
||||
public ComposeType compose_type { get; private set; default = ComposeType.NEW_MESSAGE; }
|
||||
|
||||
/** Determines if the composer is completely empty. */
|
||||
public bool is_blank {
|
||||
get {
|
||||
|
|
@ -431,17 +447,12 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
|
||||
private Gee.Collection<Geary.Account> accounts;
|
||||
|
||||
private string body_html = "";
|
||||
|
||||
private string? pointer_url = null;
|
||||
private string? cursor_url = null;
|
||||
private bool is_attachment_overlay_visible = false;
|
||||
private Geary.RFC822.MailboxAddresses reply_to_addresses;
|
||||
private Geary.RFC822.MailboxAddresses reply_cc_addresses;
|
||||
private string reply_subject = "";
|
||||
private string forward_subject = "";
|
||||
private bool top_posting = true;
|
||||
private string? last_quote = null;
|
||||
|
||||
// The message(s) this email is in reply to/forwarded from
|
||||
private Gee.Set<Geary.EmailIdentifier> referred_ids =
|
||||
|
|
@ -491,8 +502,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
|
||||
|
||||
public Widget(Application.Client application,
|
||||
Geary.Account initial_account,
|
||||
ComposeType compose_type) {
|
||||
Geary.Account initial_account) {
|
||||
components_reflow_box_get_type();
|
||||
base_ref();
|
||||
this.application = application;
|
||||
|
|
@ -504,8 +514,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
warning("Could not fetch account info: %s", e.message);
|
||||
}
|
||||
|
||||
this.compose_type = compose_type;
|
||||
|
||||
this.header = new Headerbar(application.config);
|
||||
this.header.expand_composer.connect(on_expand_compact_headers);
|
||||
|
||||
|
|
@ -642,18 +650,20 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
update_color_icon.begin(Util.Gtk.rgba(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
public Widget.from_mailbox(Application.Client application,
|
||||
Geary.Account initial_account,
|
||||
Geary.RFC822.MailboxAddress to) {
|
||||
this(application, initial_account, ComposeType.NEW_MESSAGE);
|
||||
this.to = to.to_full_display();
|
||||
~Widget() {
|
||||
base_unref();
|
||||
}
|
||||
|
||||
public Widget.from_mailto(Application.Client application,
|
||||
Geary.Account initial_account,
|
||||
string mailto) {
|
||||
this(application, initial_account, ComposeType.NEW_MESSAGE);
|
||||
public async void load_empty_body(Geary.RFC822.MailboxAddress? to = null)
|
||||
throws GLib.Error {
|
||||
if (to != null) {
|
||||
this.to = to.to_full_display();
|
||||
}
|
||||
yield finish_loading("", "", false, null);
|
||||
}
|
||||
|
||||
public async void load_mailto(string mailto)
|
||||
throws GLib.Error {
|
||||
Gee.HashMultiMap<string, string> headers = new Gee.HashMultiMap<string, string>();
|
||||
if (mailto.has_prefix(MAILTO_URI_PREFIX)) {
|
||||
// Parse the mailto link.
|
||||
|
|
@ -687,9 +697,14 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
if (headers.contains("subject"))
|
||||
this.subject = Geary.Collection.first(headers.get("subject"));
|
||||
|
||||
if (headers.contains("body"))
|
||||
this.body_html = Geary.HTML.preserve_whitespace(Geary.HTML.escape_markup(
|
||||
Geary.Collection.first(headers.get("body"))));
|
||||
var body = "";
|
||||
if (headers.contains("body")) {
|
||||
body = Geary.HTML.preserve_whitespace(
|
||||
Geary.HTML.escape_markup(
|
||||
Geary.Collection.first(headers.get("body"))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Gee.List<string> attachments = new Gee.LinkedList<string>();
|
||||
attachments.add_all(headers.get("attach"));
|
||||
|
|
@ -701,11 +716,75 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
attachment_failed(err.message);
|
||||
}
|
||||
}
|
||||
yield finish_loading(body, "", false, null);
|
||||
}
|
||||
}
|
||||
|
||||
~Widget() {
|
||||
base_unref();
|
||||
/**
|
||||
* Loads the message into the composer editor.
|
||||
*/
|
||||
public async void load_context(ContextType type,
|
||||
Geary.Email context,
|
||||
string? quote)
|
||||
throws GLib.Error {
|
||||
if (type == NONE) {
|
||||
throw new Geary.EngineError.BAD_PARAMETERS(
|
||||
"Invalid context type: %s", type.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
if (!context.fields.is_all_set(REQUIRED_FIELDS)) {
|
||||
throw new Geary.EngineError.INCOMPLETE_MESSAGE(
|
||||
"Required fields not met: %s", context.fields.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
this.context_type = type;
|
||||
|
||||
if (type == EDIT ||
|
||||
type == FORWARD) {
|
||||
this.pending_include = AttachPending.ALL;
|
||||
}
|
||||
|
||||
var body = "";
|
||||
var complete_quote = "";
|
||||
switch (type) {
|
||||
case EDIT:
|
||||
this.saved_id = context.id;
|
||||
yield restore_reply_to_state();
|
||||
fill_in_from_context(context);
|
||||
Geary.RFC822.Message message = context.get_message();
|
||||
body = (
|
||||
message.has_html_body()
|
||||
? message.get_html_body(null)
|
||||
: message.get_plain_body(true, null)
|
||||
);
|
||||
break;
|
||||
|
||||
case REPLY_SENDER:
|
||||
case REPLY_ALL:
|
||||
add_recipients_and_ids(this.context_type, context);
|
||||
fill_in_from_context(context);
|
||||
complete_quote = Util.Email.quote_email_for_reply(
|
||||
context, quote, this.application.config.clock_format, HTML
|
||||
);
|
||||
if (!Geary.String.is_empty(quote)) {
|
||||
this.top_posting = false;
|
||||
} else {
|
||||
this.can_delete_quote = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case FORWARD:
|
||||
add_recipients_and_ids(this.context_type, context);
|
||||
fill_in_from_context(context);
|
||||
complete_quote = Util.Email.quote_email_for_forward(
|
||||
context, quote, HTML
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
yield finish_loading(body, complete_quote, (type == EDIT), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -719,51 +798,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
return this.referred_ids.read_only_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the message into the composer editor.
|
||||
*/
|
||||
public async void load(Geary.Email? referred = null,
|
||||
bool is_draft,
|
||||
string? quote = null,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
if (referred != null &&
|
||||
!referred.fields.is_all_set(REQUIRED_FIELDS)) {
|
||||
throw new Geary.EngineError.INCOMPLETE_MESSAGE(
|
||||
"Required fields not met: %s", referred.fields.to_string()
|
||||
);
|
||||
}
|
||||
string referred_quote = "";
|
||||
this.last_quote = quote;
|
||||
if (referred != null) {
|
||||
referred_quote = fill_in_from_referred(referred, quote);
|
||||
if (is_draft ||
|
||||
compose_type == ComposeType.NEW_MESSAGE ||
|
||||
compose_type == ComposeType.FORWARD) {
|
||||
this.pending_include = AttachPending.ALL;
|
||||
}
|
||||
if (is_draft) {
|
||||
yield restore_reply_to_state();
|
||||
}
|
||||
}
|
||||
|
||||
update_attachments_view();
|
||||
update_pending_attachments(this.pending_include, true);
|
||||
|
||||
this.editor.load_html(
|
||||
this.body_html,
|
||||
referred_quote,
|
||||
this.top_posting,
|
||||
is_draft
|
||||
);
|
||||
|
||||
try {
|
||||
yield open_draft_manager(is_draft ? referred.id : null, cancellable);
|
||||
} catch (Error e) {
|
||||
debug("Could not open draft manager: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
/** Detaches the composer and opens it in a new window. */
|
||||
public void detach() {
|
||||
Gtk.Widget? focused_widget = null;
|
||||
|
|
@ -954,7 +988,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
this.header.set_sensitive(enabled);
|
||||
|
||||
if (enabled) {
|
||||
this.open_draft_manager.begin(this.current_draft_id, null);
|
||||
this.open_draft_manager.begin(this.saved_id, null);
|
||||
} else {
|
||||
if (this.container != null) {
|
||||
this.container.close();
|
||||
|
|
@ -1006,25 +1040,18 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
if (email == null)
|
||||
continue;
|
||||
|
||||
// XXX pretty sure we are calling this only to update the
|
||||
// composer's internal set of ids - we really shouldn't be
|
||||
// messing around with the draft's recipients since the
|
||||
// user may have already updated them.
|
||||
add_recipients_and_ids(this.compose_type, email, false);
|
||||
add_recipients_and_ids(this.context_type, email, false);
|
||||
|
||||
if (first_email) {
|
||||
this.reply_subject = Geary.RFC822.Utils.create_subject_for_reply(email);
|
||||
this.forward_subject = Geary.RFC822.Utils.create_subject_for_forward(email);
|
||||
first_email = false;
|
||||
}
|
||||
first_email = false;
|
||||
}
|
||||
if (first_email) // Either no referenced emails, or we don't have them. Treat as new.
|
||||
return;
|
||||
|
||||
if (this.cc == "")
|
||||
this.compose_type = ComposeType.REPLY;
|
||||
else
|
||||
this.compose_type = ComposeType.REPLY_ALL;
|
||||
if (this.cc == "") {
|
||||
this.context_type = REPLY_SENDER;
|
||||
} else {
|
||||
this.context_type = REPLY_ALL;
|
||||
}
|
||||
|
||||
if (!to_entry.addresses.equal_to(reply_to_addresses))
|
||||
this.to_entry.set_modified();
|
||||
|
|
@ -1054,18 +1081,12 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
}
|
||||
}
|
||||
|
||||
// Copies the addresses (e.g. From/To/CC) and content from referred into this one
|
||||
private string fill_in_from_referred(Geary.Email referred, string? quote) {
|
||||
string referred_quote = "";
|
||||
if (this.compose_type != ComposeType.NEW_MESSAGE) {
|
||||
add_recipients_and_ids(this.compose_type, referred);
|
||||
this.reply_subject = Geary.RFC822.Utils.create_subject_for_reply(referred);
|
||||
this.forward_subject = Geary.RFC822.Utils.create_subject_for_forward(referred);
|
||||
}
|
||||
// Copies the addresses (e.g. From/To/CC) and content from
|
||||
// referred into this one
|
||||
private void fill_in_from_context(Geary.Email referred) {
|
||||
this.pending_attachments = referred.attachments;
|
||||
switch (this.compose_type) {
|
||||
// Restoring a draft
|
||||
case ComposeType.NEW_MESSAGE:
|
||||
switch (this.context_type) {
|
||||
case EDIT:
|
||||
if (referred.from != null)
|
||||
this.from = referred.from;
|
||||
if (referred.to != null)
|
||||
|
|
@ -1084,41 +1105,26 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
this.references = referred.references.to_rfc822_string();
|
||||
if (referred.subject != null)
|
||||
this.subject = referred.subject.value ?? "";
|
||||
try {
|
||||
Geary.RFC822.Message message = referred.get_message();
|
||||
if (message.has_html_body()) {
|
||||
referred_quote = message.get_html_body(null);
|
||||
} else {
|
||||
referred_quote = message.get_plain_body(true, null);
|
||||
}
|
||||
} catch (Error error) {
|
||||
debug("Error getting draft message body: %s", error.message);
|
||||
}
|
||||
break;
|
||||
|
||||
case ComposeType.REPLY:
|
||||
case ComposeType.REPLY_ALL:
|
||||
this.subject = reply_subject;
|
||||
this.references = Geary.RFC822.Utils.reply_references(referred);
|
||||
referred_quote = Util.Email.quote_email_for_reply(referred, quote,
|
||||
this.application.config.clock_format,
|
||||
Geary.RFC822.TextFormat.HTML);
|
||||
if (!Geary.String.is_empty(quote)) {
|
||||
this.top_posting = false;
|
||||
} else {
|
||||
this.can_delete_quote = true;
|
||||
}
|
||||
case REPLY_SENDER:
|
||||
case REPLY_ALL:
|
||||
this.subject = Geary.RFC822.Utils.create_subject_for_reply(
|
||||
referred
|
||||
);
|
||||
this.references = Geary.RFC822.Utils.reply_references(
|
||||
referred
|
||||
);
|
||||
break;
|
||||
|
||||
case ComposeType.FORWARD:
|
||||
this.subject = forward_subject;
|
||||
referred_quote = Util.Email.quote_email_for_forward(referred, quote,
|
||||
Geary.RFC822.TextFormat.HTML);
|
||||
case FORWARD:
|
||||
this.subject = Geary.RFC822.Utils.create_subject_for_forward(
|
||||
referred
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
update_extended_headers();
|
||||
return referred_quote;
|
||||
}
|
||||
|
||||
public void present() {
|
||||
|
|
@ -1319,7 +1325,8 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
this.subject
|
||||
);
|
||||
|
||||
if ((this.compose_type == ComposeType.REPLY || this.compose_type == ComposeType.REPLY_ALL) &&
|
||||
if ((this.context_type == REPLY_SENDER ||
|
||||
this.context_type == REPLY_ALL) &&
|
||||
!this.in_reply_to.is_empty)
|
||||
email.set_in_reply_to(
|
||||
new Geary.RFC822.MessageIDList.from_collection(this.in_reply_to)
|
||||
|
|
@ -1359,7 +1366,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
/** Appends an email or fragment quoted into the composer. */
|
||||
public void append_to_email(Geary.Email referred,
|
||||
string? to_quote,
|
||||
ComposeType type)
|
||||
ContextType type)
|
||||
throws Geary.EngineError {
|
||||
if (!referred.fields.is_all_set(REQUIRED_FIELDS)) {
|
||||
throw new Geary.EngineError.INCOMPLETE_MESSAGE(
|
||||
|
|
@ -1371,30 +1378,29 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
add_recipients_and_ids(type, referred);
|
||||
}
|
||||
|
||||
if (this.last_quote != to_quote) {
|
||||
this.last_quote = to_quote;
|
||||
// Always use reply styling, since forward styling doesn't
|
||||
// work for inline quotes
|
||||
this.editor.insert_html(
|
||||
Util.Email.quote_email_for_reply(
|
||||
referred,
|
||||
to_quote,
|
||||
this.application.config.clock_format,
|
||||
Geary.RFC822.TextFormat.HTML
|
||||
)
|
||||
);
|
||||
}
|
||||
// Always use reply styling, since forward styling doesn't
|
||||
// work for inline quotes
|
||||
this.editor.insert_html(
|
||||
Util.Email.quote_email_for_reply(
|
||||
referred,
|
||||
to_quote,
|
||||
this.application.config.clock_format,
|
||||
Geary.RFC822.TextFormat.HTML
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void add_recipients_and_ids(ComposeType type, Geary.Email referred,
|
||||
bool modify_headers = true) {
|
||||
private void add_recipients_and_ids(ContextType type,
|
||||
Geary.Email referred,
|
||||
bool modify_headers = true) {
|
||||
Gee.List<Geary.RFC822.MailboxAddress> sender_addresses =
|
||||
account.information.sender_mailboxes;
|
||||
|
||||
// Set the preferred from address. New messages should retain
|
||||
// the account default and drafts should retain the draft's
|
||||
// from addresses, so don't update them here
|
||||
if (this.compose_type != ComposeType.NEW_MESSAGE) {
|
||||
if (this.context_type != NONE &&
|
||||
this.context_type != EDIT) {
|
||||
if (!check_preferred_from_address(sender_addresses, referred.to)) {
|
||||
if (!check_preferred_from_address(sender_addresses, referred.cc))
|
||||
if (!check_preferred_from_address(sender_addresses, referred.bcc))
|
||||
|
|
@ -1417,16 +1423,25 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
|
||||
bool recipients_modified = this.to_entry.is_modified || this.cc_entry.is_modified || this.bcc_entry.is_modified;
|
||||
if (!recipients_modified) {
|
||||
if (type == ComposeType.REPLY || type == ComposeType.REPLY_ALL)
|
||||
this.to_entry.addresses = Geary.RFC822.Utils.merge_addresses(to_entry.addresses,
|
||||
to_addresses);
|
||||
if (type == ComposeType.REPLY_ALL)
|
||||
if (type == REPLY_SENDER || type == REPLY_ALL) {
|
||||
this.to_entry.addresses = Geary.RFC822.Utils.merge_addresses(
|
||||
to_entry.addresses,
|
||||
to_addresses
|
||||
);
|
||||
}
|
||||
if (type == REPLY_ALL) {
|
||||
this.cc_entry.addresses = Geary.RFC822.Utils.remove_addresses(
|
||||
Geary.RFC822.Utils.merge_addresses(this.cc_entry.addresses, cc_addresses),
|
||||
this.to_entry.addresses);
|
||||
else
|
||||
this.cc_entry.addresses = Geary.RFC822.Utils.remove_addresses(this.cc_entry.addresses,
|
||||
this.to_entry.addresses);
|
||||
Geary.RFC822.Utils.merge_addresses(
|
||||
this.cc_entry.addresses, cc_addresses
|
||||
),
|
||||
this.to_entry.addresses
|
||||
);
|
||||
} else {
|
||||
this.cc_entry.addresses = Geary.RFC822.Utils.remove_addresses(
|
||||
this.cc_entry.addresses,
|
||||
this.to_entry.addresses
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (referred.message_id != null) {
|
||||
|
|
@ -1493,6 +1508,27 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
}
|
||||
}
|
||||
|
||||
private async void finish_loading(string body,
|
||||
string quote,
|
||||
bool is_body_complete,
|
||||
GLib.Cancellable? cancellable) {
|
||||
update_attachments_view();
|
||||
update_pending_attachments(this.pending_include, true);
|
||||
|
||||
this.editor.load_html(
|
||||
body,
|
||||
quote,
|
||||
this.top_posting,
|
||||
is_body_complete
|
||||
);
|
||||
|
||||
try {
|
||||
yield open_draft_manager(this.saved_id, cancellable);
|
||||
} catch (Error e) {
|
||||
debug("Could not open draft manager: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
private async bool should_send() {
|
||||
bool has_subject = !Geary.String.is_empty(subject.strip());
|
||||
bool has_attachment = this.attached_files.size > 0;
|
||||
|
|
@ -1626,8 +1662,8 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
this.draft_timer.reset();
|
||||
|
||||
this.draft_manager = null;
|
||||
this.saved_id = null;
|
||||
this.draft_status_text = "";
|
||||
this.current_draft_id = null;
|
||||
|
||||
old_manager.notify[Geary.App.DraftManager.PROP_DRAFT_STATE]
|
||||
.disconnect(on_draft_state_changed);
|
||||
|
|
@ -2666,7 +2702,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
|
|||
}
|
||||
|
||||
private void on_draft_id_changed() {
|
||||
this.current_draft_id = this.draft_manager.current_draft_id;
|
||||
this.saved_id = this.draft_manager.current_draft_id;
|
||||
}
|
||||
|
||||
private void on_draft_manager_fatal(Error err) {
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ public class Conversation.ContactPopover : Gtk.Popover {
|
|||
private void on_new_conversation() {
|
||||
var main = this.get_toplevel() as Application.MainWindow;
|
||||
if (main != null) {
|
||||
main.open_composer_for_mailbox(this.mailbox);
|
||||
main.application.new_composer.begin(this.mailbox);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -891,8 +891,8 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
|
|||
add(row);
|
||||
this.current_composer = row;
|
||||
|
||||
embed.composer.notify["current-draft-id"].connect(
|
||||
(id) => { this.draft_id = embed.composer.current_draft_id; }
|
||||
embed.composer.notify["saved-id"].connect(
|
||||
(id) => { this.draft_id = embed.composer.saved_id; }
|
||||
);
|
||||
embed.vanished.connect(() => {
|
||||
this.current_composer = null;
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
if (this.current_list != null) {
|
||||
this.current_list.add_embedded_composer(
|
||||
embed,
|
||||
composer.current_draft_id != null
|
||||
composer.saved_id != null
|
||||
);
|
||||
composer.update_window_title();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue