[geary/wip/713739-inline: 2/37] Separate composer widget from composer window
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/713739-inline: 2/37] Separate composer widget from composer window
- Date: Tue, 20 May 2014 20:15:49 +0000 (UTC)
commit 8da7a73c027824d56ddf65a11158f9268fe3d6c5
Author: Robert Schroll <rschroll gmail com>
Date: Tue Feb 11 01:31:45 2014 -0500
Separate composer widget from composer window
In anticipation of inline composition, we need the composer widget to be
separate from the window in which it lives. We introduce a new
interface, ComposerContainer, that the thing that holds to
ComposerWidget must implement.
src/CMakeLists.txt | 2 +
src/client/accounts/account-dialog.vala | 16 +++---
src/client/application/geary-controller.vala | 51 +++++++++-----------
src/client/composer/composer-container.vala | 13 +++++
src/client/composer/composer-toolbar.vala | 18 ++++----
src/client/composer/composer-widget.vala | 66 +++++++++++++-------------
src/client/composer/composer-window.vala | 44 +++++++++++++++++
7 files changed, 133 insertions(+), 77 deletions(-)
---
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b992514..4cfa0a9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -322,7 +322,9 @@ client/components/pill-toolbar.vala
client/components/status-bar.vala
client/components/stock.vala
+client/composer/composer-container.vala
client/composer/composer-toolbar.vala
+client/composer/composer-widget.vala
client/composer/composer-window.vala
client/composer/contact-entry-completion.vala
client/composer/contact-list-store.vala
diff --git a/src/client/accounts/account-dialog.vala b/src/client/accounts/account-dialog.vala
index daa8e84..6070dea 100644
--- a/src/client/accounts/account-dialog.vala
+++ b/src/client/accounts/account-dialog.vala
@@ -126,22 +126,22 @@ public class AccountDialog : Gtk.Dialog {
return;
// Check for open composer windows.
- bool composer_window_found = false;
- Gee.List<ComposerWindow>? windows =
- GearyApplication.instance.controller.get_composer_windows_for_account(account);
+ bool composer_widget_found = false;
+ Gee.List<ComposerWidget>? widgets =
+ GearyApplication.instance.controller.get_composer_widgets_for_account(account);
- if (windows != null) {
- foreach (ComposerWindow cw in windows) {
+ if (widgets != null) {
+ foreach (ComposerWidget cw in widgets) {
if (cw.account.information == account &&
- cw.compose_type != ComposerWindow.ComposeType.NEW_MESSAGE) {
- composer_window_found = true;
+ cw.compose_type != ComposerWidget.ComposeType.NEW_MESSAGE) {
+ composer_widget_found = true;
break;
}
}
}
- if (composer_window_found) {
+ if (composer_widget_found) {
// Warn user that account cannot be deleted until composer is closed.
remove_fail_pane.present();
} else {
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 01b2d47..416d102 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -91,7 +91,7 @@ public class GearyController : Geary.BaseObject {
= new Gee.HashMap<Geary.Account, Cancellable>();
private Gee.Set<Geary.App.Conversation> selected_conversations = new
Gee.HashSet<Geary.App.Conversation>();
private Geary.App.Conversation? last_deleted_conversation = null;
- private Gee.LinkedList<ComposerWindow> composer_windows = new Gee.LinkedList<ComposerWindow>();
+ private Gee.LinkedList<ComposerWidget> composer_widgets = new Gee.LinkedList<ComposerWidget>();
private File? last_save_directory = null;
private NewMessagesMonitor? new_messages_monitor = null;
private NewMessagesIndicator? new_messages_indicator = null;
@@ -109,7 +109,7 @@ public class GearyController : Geary.BaseObject {
private Gee.List<string> pending_mailtos = new Gee.ArrayList<string>();
// List of windows we're waiting to close before Geary closes.
- private Gee.List<ComposerWindow> waiting_to_close = new Gee.ArrayList<ComposerWindow>();
+ private Gee.List<ComposerWidget> waiting_to_close = new Gee.ArrayList<ComposerWidget>();
/**
* Fired when the currently selected account has changed.
@@ -1153,7 +1153,7 @@ public class GearyController : Geary.BaseObject {
}
private void on_edit_draft(Geary.Email draft) {
- create_compose_window(ComposerWindow.ComposeType.NEW_MESSAGE, draft, null, true);
+ create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE, draft, null, true);
}
private void on_special_folder_type_changed(Geary.Folder folder, Geary.SpecialFolderType old_type,
@@ -1761,11 +1761,11 @@ public class GearyController : Geary.BaseObject {
}
private bool close_composition_windows() {
- Gee.List<ComposerWindow> composers_to_destroy = new Gee.ArrayList<ComposerWindow>();
+ Gee.List<ComposerWidget> composers_to_destroy = new Gee.ArrayList<ComposerWidget>();
bool quit_cancelled = false;
// If there's composer windows open, give the user a chance to save or cancel.
- foreach(ComposerWindow cw in composer_windows) {
+ foreach(ComposerWidget cw in composer_widgets) {
// Check if we should close the window immediately, or if we need to wait.
if (!cw.should_close()) {
if (cw.delayed_close) {
@@ -1788,7 +1788,7 @@ public class GearyController : Geary.BaseObject {
}
// Safely destroy windows.
- foreach(ComposerWindow cw in composers_to_destroy)
+ foreach(ComposerWidget cw in composers_to_destroy)
cw.destroy();
// If we cancelled the quit we can bail here.
@@ -1809,19 +1809,19 @@ public class GearyController : Geary.BaseObject {
return true;
}
- private void create_compose_window(ComposerWindow.ComposeType compose_type,
+ private void create_compose_widget(ComposerWidget.ComposeType compose_type,
Geary.Email? referred = null, string? mailto = null, bool is_draft = false) {
- create_compose_window_async.begin(compose_type, referred, mailto, is_draft);
+ create_compose_widget_async.begin(compose_type, referred, mailto, is_draft);
}
- private async void create_compose_window_async(ComposerWindow.ComposeType compose_type,
+ private async void create_compose_widget_async(ComposerWidget.ComposeType compose_type,
Geary.Email? referred = null, string? mailto = null, bool is_draft = false) {
if (current_account == null)
return;
- ComposerWindow window;
+ ComposerWidget widget;
if (mailto != null) {
- window = new ComposerWindow.from_mailto(current_account, mailto);
+ widget = new ComposerWidget.from_mailto(current_account, mailto);
} else {
Geary.Email? full = null;
if (referred != null) {
@@ -1834,22 +1834,19 @@ public class GearyController : Geary.BaseObject {
}
}
- window = new ComposerWindow(current_account, compose_type, full, is_draft);
+ widget = new ComposerWidget(current_account, compose_type, full, is_draft);
}
- window.set_position(Gtk.WindowPosition.CENTER);
// We want to keep track of the open composer windows, so we can allow the user to cancel
// an exit without losing their data.
- composer_windows.add(window);
- window.destroy.connect(on_composer_window_destroy);
-
- window.show_all();
+ composer_widgets.add(widget);
+ widget.destroy.connect(on_composer_widget_destroy);
}
- private void on_composer_window_destroy(Gtk.Widget sender) {
- composer_windows.remove((ComposerWindow) sender);
+ private void on_composer_widget_destroy(Gtk.Widget sender) {
+ composer_widgets.remove((ComposerWidget) sender);
- if (waiting_to_close.remove((ComposerWindow) sender)) {
+ if (waiting_to_close.remove((ComposerWidget) sender)) {
// If we just removed the last window in the waiting to close list, it's time to exit!
if (waiting_to_close.size == 0)
GearyApplication.instance.exit();
@@ -1857,11 +1854,11 @@ public class GearyController : Geary.BaseObject {
}
private void on_new_message() {
- create_compose_window(ComposerWindow.ComposeType.NEW_MESSAGE);
+ create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE);
}
private void on_reply_to_message(Geary.Email message) {
- create_compose_window(ComposerWindow.ComposeType.REPLY, message);
+ create_compose_widget(ComposerWidget.ComposeType.REPLY, message);
}
private void on_reply_to_message_action() {
@@ -1871,7 +1868,7 @@ public class GearyController : Geary.BaseObject {
}
private void on_reply_all_message(Geary.Email message) {
- create_compose_window(ComposerWindow.ComposeType.REPLY_ALL, message);
+ create_compose_widget(ComposerWidget.ComposeType.REPLY_ALL, message);
}
private void on_reply_all_message_action() {
@@ -1881,7 +1878,7 @@ public class GearyController : Geary.BaseObject {
}
private void on_forward_message(Geary.Email message) {
- create_compose_window(ComposerWindow.ComposeType.FORWARD, message);
+ create_compose_widget(ComposerWidget.ComposeType.FORWARD, message);
}
private void on_forward_message_action() {
@@ -2130,12 +2127,12 @@ public class GearyController : Geary.BaseObject {
return;
}
- create_compose_window(ComposerWindow.ComposeType.NEW_MESSAGE, null, mailto);
+ create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE, null, mailto);
}
// Returns a list of composer windows for an account, or null if none.
- public Gee.List<ComposerWindow>? get_composer_windows_for_account(Geary.AccountInformation account) {
- Gee.LinkedList<ComposerWindow> ret = Geary.traverse<ComposerWindow>(composer_windows)
+ public Gee.List<ComposerWidget>? get_composer_widgets_for_account(Geary.AccountInformation account) {
+ Gee.LinkedList<ComposerWidget> ret = Geary.traverse<ComposerWidget>(composer_widgets)
.filter(w => w.account.information == account)
.to_linked_list();
diff --git a/src/client/composer/composer-container.vala b/src/client/composer/composer-container.vala
new file mode 100644
index 0000000..966bd25
--- /dev/null
+++ b/src/client/composer/composer-container.vala
@@ -0,0 +1,13 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+public interface ComposerContainer {
+ public abstract Gtk.Window top_window { get; }
+
+ public abstract void present();
+ public abstract unowned Gtk.Widget get_focus();
+ public abstract void close();
+}
diff --git a/src/client/composer/composer-toolbar.vala b/src/client/composer/composer-toolbar.vala
index c389972..8896e08 100644
--- a/src/client/composer/composer-toolbar.vala
+++ b/src/client/composer/composer-toolbar.vala
@@ -11,27 +11,27 @@ public class ComposerToolbar : PillToolbar {
Gee.List<Gtk.Button> insert = new Gee.ArrayList<Gtk.Button>();
// Font formatting.
- insert.add(create_toggle_button(null, ComposerWindow.ACTION_BOLD));
- insert.add(create_toggle_button(null, ComposerWindow.ACTION_ITALIC));
- insert.add(create_toggle_button(null, ComposerWindow.ACTION_UNDERLINE));
- insert.add(create_toggle_button(null, ComposerWindow.ACTION_STRIKETHROUGH));
+ insert.add(create_toggle_button(null, ComposerWidget.ACTION_BOLD));
+ insert.add(create_toggle_button(null, ComposerWidget.ACTION_ITALIC));
+ insert.add(create_toggle_button(null, ComposerWidget.ACTION_UNDERLINE));
+ insert.add(create_toggle_button(null, ComposerWidget.ACTION_STRIKETHROUGH));
Gtk.ToolItem font_format_item = create_pill_buttons(insert, false, true);
add(font_format_item);
// Indent level.
insert.clear();
- insert.add(create_toolbar_button(null, ComposerWindow.ACTION_INDENT));
- insert.add(create_toolbar_button(null, ComposerWindow.ACTION_OUTDENT));
+ insert.add(create_toolbar_button(null, ComposerWidget.ACTION_INDENT));
+ insert.add(create_toolbar_button(null, ComposerWidget.ACTION_OUTDENT));
add(create_pill_buttons(insert, false));
// Link.
insert.clear();
- insert.add(create_toolbar_button(null, ComposerWindow.ACTION_INSERT_LINK));
+ insert.add(create_toolbar_button(null, ComposerWidget.ACTION_INSERT_LINK));
add(create_pill_buttons(insert));
// Remove formatting.
insert.clear();
- insert.add(create_toolbar_button(null, ComposerWindow.ACTION_REMOVE_FORMAT));
+ insert.add(create_toolbar_button(null, ComposerWidget.ACTION_REMOVE_FORMAT));
add(create_pill_buttons(insert));
// Spacer.
@@ -39,7 +39,7 @@ public class ComposerToolbar : PillToolbar {
// Menu.
insert.clear();
- insert.add(create_menu_button(null, menu, ComposerWindow.ACTION_MENU));
+ insert.add(create_menu_button(null, menu, ComposerWidget.ACTION_MENU));
add(create_pill_buttons(insert));
}
}
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 85efee8..580ec06 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -4,8 +4,8 @@
* (version 2.1 or later). See the COPYING file in this distribution.
*/
-// Window for sending messages.
-public class ComposerWindow : Gtk.Window {
+// Widget for sending messages.
+public class ComposerWidget : Gtk.EventBox {
public enum ComposeType {
NEW_MESSAGE,
REPLY,
@@ -37,7 +37,6 @@ public class ComposerWindow : Gtk.Window {
public const string ACTION_COMPOSE_AS_HTML = "compose as html";
public const string ACTION_CLOSE = "close";
- private const string DEFAULT_TITLE = _("New Message");
private const string DRAFT_SAVED_TEXT = _("Saved");
private const string DRAFT_SAVING_TEXT = _("Saving");
private const string DRAFT_ERROR_TEXT = _("Error saving");
@@ -147,7 +146,7 @@ public class ComposerWindow : Gtk.Window {
private EmailEntry to_entry;
private EmailEntry cc_entry;
private EmailEntry bcc_entry;
- private Gtk.Entry subject_entry;
+ public Gtk.Entry subject_entry;
private Gtk.Button close_button;
private Gtk.Button send_button;
private Gtk.Label message_overlay_label;
@@ -189,10 +188,13 @@ public class ComposerWindow : Gtk.Window {
// We need to keep a reference to the edit-fixer in composer-window, so it doesn't get
// garbage-collected.
private WebViewEditFixer edit_fixer;
- private Gtk.UIManager ui;
+ public Gtk.UIManager ui;
+ private ComposerContainer container {
+ get { return (ComposerContainer) parent; }
+ }
- public ComposerWindow(Geary.Account account, ComposeType compose_type,
- Geary.Email? referred = null, bool is_referred_draft = false) {
+ public ComposerWidget(Geary.Account account, ComposeType compose_type,
+ Geary.Email? referred = null, bool is_referred_draft = false, bool in_window = true) {
this.account = account;
this.compose_type = compose_type;
@@ -266,7 +268,6 @@ public class ComposerWindow : Gtk.Window {
message_overlay_label.valign = Gtk.Align.END;
message_overlay.add_overlay(message_overlay_label);
- title = DEFAULT_TITLE;
subject_entry.changed.connect(on_subject_changed);
to_entry.changed.connect(validate_send_button);
cc_entry.changed.connect(validate_send_button);
@@ -316,7 +317,6 @@ public class ComposerWindow : Gtk.Window {
ui = new Gtk.UIManager();
ui.insert_action_group(actions, 0);
- add_accel_group(ui.get_accel_group());
GearyApplication.instance.load_ui_file_for_manager(ui, "composer_accelerators.ui");
add_extra_accelerators();
@@ -460,9 +460,12 @@ public class ComposerWindow : Gtk.Window {
// the drafts folder will be opened by on_from_changed().
if (!from_multiple.visible)
open_drafts_folder_async.begin(cancellable_drafts);
+
+ if (in_window)
+ new ComposerWindow(this);
}
- public ComposerWindow.from_mailto(Geary.Account account, string mailto) {
+ public ComposerWidget.from_mailto(Geary.Account account, string mailto) {
this(account, ComposeType.NEW_MESSAGE);
Gee.HashMultiMap<string, string> headers = new Gee.HashMultiMap<string, string>();
@@ -662,7 +665,6 @@ public class ComposerWindow : Gtk.Window {
}
public override void show_all() {
- set_default_size(680, 600);
base.show_all();
update_from_field();
}
@@ -675,18 +677,18 @@ public class ComposerWindow : Gtk.Window {
public bool should_close() {
bool try_to_save = can_save();
- present();
+ container.present();
AlertDialog dialog;
if (drafts_folder == null && try_to_save) {
- dialog = new ConfirmationDialog(this,
+ dialog = new ConfirmationDialog(container.top_window,
_("Do you want to discard the unsaved message?"), null, Stock._DISCARD);
} else if (try_to_save) {
- dialog = new TernaryConfirmationDialog(this,
+ dialog = new TernaryConfirmationDialog(container.top_window,
_("Do you want to discard this message?"), null, Stock._KEEP, Stock._DISCARD,
Gtk.ResponseType.CLOSE);
} else {
- dialog = new ConfirmationDialog(this,
+ dialog = new ConfirmationDialog(container.top_window,
_("Do you want to discard this message?"), null, Stock._DISCARD);
}
@@ -776,7 +778,7 @@ public class ComposerWindow : Gtk.Window {
confirmation = _("Send message without an attachment?");
}
if (confirmation != null) {
- ConfirmationDialog dialog = new ConfirmationDialog(this,
+ ConfirmationDialog dialog = new ConfirmationDialog(container.top_window,
confirmation, null, Stock._OK);
if (dialog.run() != Gtk.ResponseType.OK)
return false;
@@ -943,7 +945,7 @@ public class ComposerWindow : Gtk.Window {
// ComposerWindow, but as a GtkBin subclass a ComposerWindow can
// only contain one widget at a time;
// it already contains a widget of type GtkBox
- dialog = new AttachmentDialog(this);
+ dialog = new AttachmentDialog(container.top_window);
} while (!dialog.is_finished(add_attachment));
}
@@ -964,7 +966,7 @@ public class ComposerWindow : Gtk.Window {
}
private void attachment_failed(string msg) {
- ErrorDialog dialog = new ErrorDialog(this, _("Cannot add attachment"), msg);
+ ErrorDialog dialog = new ErrorDialog(container.top_window, _("Cannot add attachment"), msg);
dialog.run();
}
@@ -1057,9 +1059,6 @@ public class ComposerWindow : Gtk.Window {
}
private void on_subject_changed() {
- title = Geary.String.is_empty(subject_entry.text.strip()) ? DEFAULT_TITLE :
- subject_entry.text.strip();
-
reset_draft_timer();
}
@@ -1086,17 +1085,17 @@ public class ComposerWindow : Gtk.Window {
}
private void on_cut() {
- if (get_focus() == editor)
+ if (container.get_focus() == editor)
editor.cut_clipboard();
- else if (get_focus() is Gtk.Editable)
- ((Gtk.Editable) get_focus()).cut_clipboard();
+ else if (container.get_focus() is Gtk.Editable)
+ ((Gtk.Editable) container.get_focus()).cut_clipboard();
}
private void on_copy() {
- if (get_focus() == editor)
+ if (container.get_focus() == editor)
editor.copy_clipboard();
- else if (get_focus() is Gtk.Editable)
- ((Gtk.Editable) get_focus()).copy_clipboard();
+ else if (container.get_focus() is Gtk.Editable)
+ ((Gtk.Editable) container.get_focus()).copy_clipboard();
}
private void on_copy_link() {
@@ -1168,14 +1167,14 @@ public class ComposerWindow : Gtk.Window {
}
private void on_paste() {
- if (get_focus() == editor)
+ if (container.get_focus() == editor)
get_clipboard(Gdk.SELECTION_CLIPBOARD).request_text(on_clipboard_text_received);
- else if (get_focus() is Gtk.Editable)
- ((Gtk.Editable) get_focus()).paste_clipboard();
+ else if (container.get_focus() is Gtk.Editable)
+ ((Gtk.Editable) container.get_focus()).paste_clipboard();
}
private void on_paste_with_formatting() {
- if (get_focus() == editor)
+ if (container.get_focus() == editor)
editor.paste_clipboard();
}
@@ -1281,7 +1280,8 @@ public class ComposerWindow : Gtk.Window {
private void on_select_color() {
if (compose_as_html) {
- Gtk.ColorChooserDialog dialog = new Gtk.ColorChooserDialog(_("Select Color"), this);
+ Gtk.ColorChooserDialog dialog = new Gtk.ColorChooserDialog(_("Select Color"),
+ container.top_window);
if (dialog.run() == Gtk.ResponseType.OK)
editor.get_dom_document().exec_command("forecolor", false, dialog.get_rgba().to_string());
@@ -1327,7 +1327,7 @@ public class ComposerWindow : Gtk.Window {
}
private static void on_link_clicked(WebKit.DOM.Element element, WebKit.DOM.Event event,
- ComposerWindow composer) {
+ ComposerWidget composer) {
try {
composer.editor.get_dom_document().get_default_view().get_selection().
select_all_children(element);
diff --git a/src/client/composer/composer-window.vala b/src/client/composer/composer-window.vala
new file mode 100644
index 0000000..55df8f7
--- /dev/null
+++ b/src/client/composer/composer-window.vala
@@ -0,0 +1,44 @@
+/* Copyright 2011-2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+// Window for sending messages.
+public class ComposerWindow : Gtk.Window, ComposerContainer {
+
+ private const string DEFAULT_TITLE = _("New Message");
+
+ public ComposerWindow(ComposerWidget composer) {
+ Object(type: Gtk.WindowType.TOPLEVEL);
+
+ add(composer);
+ composer.subject_entry.changed.connect(() => {
+ title = Geary.String.is_empty(composer.subject_entry.text.strip()) ? DEFAULT_TITLE :
+ composer.subject_entry.text.strip();
+ });
+ composer.subject_entry.changed();
+
+ add_accel_group(composer.ui.get_accel_group());
+ show_all();
+ set_position(Gtk.WindowPosition.CENTER);
+ }
+
+ public Gtk.Window top_window {
+ get { return this; }
+ }
+
+ public override void show_all() {
+ set_default_size(680, 600);
+ base.show_all();
+ }
+
+ public override bool delete_event(Gdk.EventAny event) {
+ return !((ComposerWidget) get_child()).should_close();
+ }
+
+ public new void close() {
+ destroy();
+ }
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]