Commit f604d2d9 authored by Eric Gregory's avatar Eric Gregory

Closes #6334 Show and set "From:" field in composer

parent 84b1c62d
......@@ -24,8 +24,9 @@ set(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME}-${VERSION})
set(ARCHIVE_FULL_NAME ${ARCHIVE_BASE_NAME}.tar.xz)
set(ARCHIVE_DEBUILD_FULL_NAME ${CMAKE_PROJECT_NAME}_${VERSION}.orig.tar.xz)
set(GLADE_FILES ui/composer.glade ui/login.glade ui/message.glade ui/password-dialog.glade
ui/preferences.glade ui/toolbar.glade)
set(GLADE_FILES ui/account_list.glade ui/account_cannot_remove.glade ui/account_spinner.glade
ui/composer.glade ui/login.glade ui/message.glade ui/password-dialog.glade ui/preferences.glade
ui/remove_confirm.glade ui/toolbar.glade)
option(DEBUG "Build for debugging." OFF)
option(ICON_UPDATE "Run gtk-update-icon-cache after the install." ON)
......
......@@ -208,6 +208,7 @@ client/accounts/account-dialog.vala
client/accounts/account-dialog-account-list-pane.vala
client/accounts/account-dialog-add-edit-pane.vala
client/accounts/account-dialog-remove-confirm-pane.vala
client/accounts/account-dialog-remove-fail-pane.vala
client/accounts/account-spinner-page.vala
client/accounts/add-edit-page.vala
client/accounts/login-dialog.vala
......
/* Copyright 2013 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.
*/
// Lets user know that account removal cannot be completed..
public class AccountDialogRemoveFailPane : Gtk.Box {
public signal void ok();
public AccountDialogRemoveFailPane() {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6);
Gtk.Builder builder = GearyApplication.instance.create_builder("account_cannot_remove.glade");
pack_end((Gtk.Box) builder.get_object("container"));
Gtk.ActionGroup actions = (Gtk.ActionGroup) builder.get_object("actions");
actions.get_action("ok_action").activate.connect(() => { ok(); });
}
}
......@@ -12,10 +12,12 @@ public class AccountDialog : Gtk.Dialog {
private AccountDialogAddEditPane add_edit_pane = new AccountDialogAddEditPane();
private AccountSpinnerPage spinner_pane = new AccountSpinnerPage();
private AccountDialogRemoveConfirmPane remove_confirm_pane = new AccountDialogRemoveConfirmPane();
private AccountDialogRemoveFailPane remove_fail_pane = new AccountDialogRemoveFailPane();
private int add_edit_page_number;
private int account_list_page_number;
private int spinner_page_number;
private int remove_confirm_page_number;
private int remove_fail_page_number;
public AccountDialog() {
set_size_request(450, -1); // Sets min size.
......@@ -29,6 +31,7 @@ public class AccountDialog : Gtk.Dialog {
add_edit_page_number = notebook.append_page(add_edit_pane, null);
spinner_page_number = notebook.append_page(spinner_pane, null);
remove_confirm_page_number = notebook.append_page(remove_confirm_pane, null);
remove_fail_page_number = notebook.append_page(remove_fail_pane, null);
// Connect signals from pages.
account_list_pane.close.connect(on_close);
......@@ -40,6 +43,7 @@ public class AccountDialog : Gtk.Dialog {
add_edit_pane.size_changed.connect(() => { resize(1, 1); });
remove_confirm_pane.ok.connect(on_delete_account_confirmed);
remove_confirm_pane.cancel.connect(on_cancel_back_to_list);
remove_fail_pane.ok.connect(on_cancel_back_to_list);
// Set default page.
notebook.set_current_page(account_list_page_number);
......@@ -97,9 +101,30 @@ public class AccountDialog : Gtk.Dialog {
if (account == null)
return;
// Send user to confirmation screen.
remove_confirm_pane.set_account(account);
notebook.set_current_page(remove_confirm_page_number);
// Check for open composer windows.
bool composer_window_found = false;
Gee.List<ComposerWindow>? windows =
GearyApplication.instance.get_composer_windows_for_account(account);
if (windows != null) {
foreach (ComposerWindow cw in windows) {
if (cw.account.information == account &&
cw.compose_type != ComposerWindow.ComposeType.NEW_MESSAGE) {
composer_window_found = true;
break;
}
}
}
if (composer_window_found) {
// Warn user that account cannot be deleted until composer is closed.
notebook.set_current_page(remove_fail_page_number);
} else {
// Send user to confirmation screen.
remove_confirm_pane.set_account(account);
notebook.set_current_page(remove_confirm_page_number);
}
}
private void on_delete_account_confirmed(Geary.AccountInformation? account) {
......
......@@ -6,6 +6,12 @@
// Window for sending messages.
public class ComposerWindow : Gtk.Window {
public enum ComposeType {
NEW_MESSAGE,
REPLY,
FORWARD
}
private const string DEFAULT_TITLE = _("New Message");
private const string ACTION_UNDO = "undo";
......@@ -95,9 +101,14 @@ public class ComposerWindow : Gtk.Window {
}
}
public ComposeType compose_type { get; private set; default = ComposeType.NEW_MESSAGE; }
private string? reply_body = null;
private Gee.Set<File> attachment_files = new Gee.HashSet<File>(File.hash, (EqualFunc) File.equal);
private Gtk.Label from_label;
private Gtk.Label from_single;
private Gtk.ComboBoxText from_multiple = new Gtk.ComboBoxText();
private EmailEntry to_entry;
private EmailEntry cc_entry;
private EmailEntry bcc_entry;
......@@ -137,9 +148,10 @@ public class ComposerWindow : Gtk.Window {
private Gtk.UIManager ui;
private ContactEntryCompletion[] contact_entry_completions;
public ComposerWindow(Geary.Account account, Geary.ContactStore? contact_store,
Geary.ComposedEmail? prefill = null) {
public ComposerWindow(Geary.Account account, ComposeType compose_type,
Geary.ContactStore? contact_store, Geary.ComposedEmail? prefill = null) {
this.account = account;
this.compose_type = compose_type;
contact_entry_completions = {
new ContactEntryCompletion(contact_store),
......@@ -171,6 +183,9 @@ public class ComposerWindow : Gtk.Window {
// TODO: It would be nicer to set the completions inside the EmailEntry constructor. But in
// testing, this can cause non-deterministic segfaults. Investigate why, and fix if possible.
from_label = (Gtk.Label) builder.get_object("from label");
from_single = (Gtk.Label) builder.get_object("from_single");
from_multiple = (Gtk.ComboBoxText) builder.get_object("from_multiple");
to_entry = new EmailEntry();
to_entry.completion = contact_entry_completions[0];
(builder.get_object("to") as Gtk.EventBox).add(to_entry);
......@@ -184,6 +199,10 @@ public class ComposerWindow : Gtk.Window {
Gtk.Alignment message_area = builder.get_object("message area") as Gtk.Alignment;
actions = builder.get_object("compose actions") as Gtk.ActionGroup;
// Listen to account signals to update from menu.
Geary.Engine.instance.account_available.connect(update_from_field);
Geary.Engine.instance.account_unavailable.connect(update_from_field);
Gtk.ScrolledWindow scroll = new Gtk.ScrolledWindow(null, null);
scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
......@@ -260,6 +279,9 @@ public class ComposerWindow : Gtk.Window {
reply_body = "<pre>" + prefill.body_text.buffer.to_string();
}
update_from_field();
from_multiple.changed.connect(on_from_changed);
editor = new WebKit.WebView();
edit_fixer = new WebViewEditFixer(editor);
......@@ -494,6 +516,7 @@ public class ComposerWindow : Gtk.Window {
public override void show_all() {
set_default_size(680, 600);
base.show_all();
update_from_field();
}
public bool should_close() {
......@@ -1073,5 +1096,61 @@ public class ComposerWindow : Gtk.Window {
action_flag = false;
}
}
private void update_from_field() {
from_single.visible = from_multiple.visible = from_label.visible = false;
Gee.Map<string, Geary.AccountInformation> accounts;
try {
accounts = Geary.Engine.instance.get_accounts();
} catch (Error e) {
debug("Could not fetch account info: %s", e.message);
return;
}
// If there's only one account, show nothing. (From fields are hidden above.)
if (accounts.size <= 1)
return;
from_label.visible = true;
if (compose_type == ComposeType.NEW_MESSAGE) {
// For new messages, show the account combo-box.
from_multiple.visible = true;
from_multiple.remove_all();
foreach (Geary.AccountInformation a in accounts.values)
from_multiple.append(a.email, a.pretty_string());
// Set the active account to the currently selected account, or failing that, set it
// to the first account in the list.
if (!from_multiple.set_active_id(account.information.email))
from_multiple.set_active(0);
} else {
// For other types of messages, just show the from account.
from_single.label = account.information.pretty_string();
from_single.visible = true;
}
}
private void on_from_changed() {
if (compose_type != ComposeType.NEW_MESSAGE)
return;
// Since we've set the combo box ID to the email addresses, we can
// fetch that and use it to grab the account from the engine.
string? id = from_multiple.get_active_id();
Geary.AccountInformation? new_account_info = null;
if (id != null) {
try {
new_account_info = Geary.Engine.instance.get_accounts().get(id);
if (new_account_info != null)
account = Geary.Engine.instance.get_account_instance(new_account_info);
} catch (Error e) {
debug("Error updating account in Composer: %s", e.message);
}
}
}
}
......@@ -418,5 +418,9 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
}
}
}
public Gee.List<ComposerWindow>? get_composer_windows_for_account(Geary.AccountInformation account) {
return controller.get_composer_windows_for_account(account);
}
}
......@@ -1055,12 +1055,14 @@ public class GearyController {
return true;
}
private void create_compose_window(Geary.ComposedEmail? prefill = null) {
private void create_compose_window(ComposerWindow.ComposeType compose_type,
Geary.ComposedEmail? prefill = null) {
if (current_account == null)
return;
Geary.ContactStore? contact_store = current_account.get_contact_store();
ComposerWindow window = new ComposerWindow(current_account, contact_store, prefill);
ComposerWindow window = new ComposerWindow(current_account, compose_type, contact_store,
prefill);
window.set_position(Gtk.WindowPosition.CENTER);
window.send.connect(on_send);
......@@ -1077,12 +1079,12 @@ public class GearyController {
}
private void on_new_message() {
create_compose_window();
create_compose_window(ComposerWindow.ComposeType.NEW_MESSAGE);
}
private void on_reply_to_message(Geary.Email message) {
create_compose_window(new Geary.ComposedEmail.as_reply(new DateTime.now_local(),
get_from(), message));
create_compose_window(ComposerWindow.ComposeType.REPLY, new Geary.ComposedEmail.as_reply(
new DateTime.now_local(), get_from(), message));
}
private void on_reply_to_message_action() {
......@@ -1092,8 +1094,8 @@ public class GearyController {
}
private void on_reply_all_message(Geary.Email message) {
create_compose_window(new Geary.ComposedEmail.as_reply_all(new DateTime.now_local(),
get_from(), message));
create_compose_window(ComposerWindow.ComposeType.REPLY, new Geary.ComposedEmail.as_reply_all(
new DateTime.now_local(), get_from(), message));
}
private void on_reply_all_message_action() {
......@@ -1103,8 +1105,8 @@ public class GearyController {
}
private void on_forward_message(Geary.Email message) {
create_compose_window(new Geary.ComposedEmail.as_forward(new DateTime.now_local(),
get_from(), message));
create_compose_window(ComposerWindow.ComposeType.FORWARD, new Geary.ComposedEmail.as_forward(
new DateTime.now_local(), get_from(), message));
}
private void on_forward_message_action() {
......@@ -1252,7 +1254,18 @@ public class GearyController {
}
public void compose_mailto(string mailto) {
create_compose_window(new Geary.ComposedEmail.from_mailto(mailto, get_from()));
create_compose_window(ComposerWindow.ComposeType.NEW_MESSAGE, new Geary.ComposedEmail.from_mailto(mailto, get_from()));
}
// 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.List<ComposerWindow> ret = new Gee.LinkedList<ComposerWindow>();
foreach (ComposerWindow cw in composer_windows) {
if (cw.account.information == account)
ret.add(cw);
}
return ret.size >= 1 ? ret : null;
}
}
......@@ -419,4 +419,11 @@ public class Geary.AccountInformation : Object {
// Delete files.
yield Files.recursive_delete_async(settings_dir, cancellable);
}
/**
* Returns a formatted string with the user's real name and email address.
*/
public string pretty_string() {
return "%s <%s>".printf(real_name, email);
}
}
......@@ -2,6 +2,7 @@ set(UI_DEST share/geary/ui)
install(FILES accelerators.ui DESTINATION ${UI_DEST})
install(FILES account_list.glade DESTINATION ${UI_DEST})
install(FILES account_cannot_remove.glade DESTINATION ${UI_DEST})
install(FILES account_spinner.glade DESTINATION ${UI_DEST})
install(FILES composer.glade DESTINATION ${UI_DEST})
install(FILES composer_accelerators.ui DESTINATION ${UI_DEST})
......
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkActionGroup" id="actions">
<child>
<object class="GtkAction" id="ok_action">
<property name="stock_id">gtk-ok</property>
</object>
</child>
</object>
<object class="GtkBox" id="container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">1</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="yalign">0</property>
<property name="stock">gtk-dialog-error</property>
<property name="icon-size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">20</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;span weight="bold" size="larger"&gt;Cannot remove account&lt;/span&gt; </property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">A composer window associated with this account is currently open. Send or discard the message and try again.</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">_Remove</property>
<property name="related_action">ok_action</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>
......@@ -179,7 +179,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -196,7 +196,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="top_attach">2</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -209,7 +209,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -222,7 +222,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="top_attach">2</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -237,7 +237,7 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
<property name="top_attach">4</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -254,7 +254,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
<property name="top_attach">4</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -271,7 +271,7 @@
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="top_attach">3</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -284,7 +284,62 @@
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
<property name="top_attach">3</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="from label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">6</property>
<property name="label" translatable="yes" comments="Geary account mail will be sent from">From:</property>
<property name="justify">right</property>
<property name="mnemonic_widget">to</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="from_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="from_single">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="from_multiple">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="entry_text_column">0</property>
<property name="id_column">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
......@@ -366,7 +421,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Bold</property>
<property name="related_action">bold</property>
<property name="label" translatable="yes">Bold</property>
<property name="use_underline">True</property>
</object>
......@@ -381,7 +435,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Italic</property>
<property name="related_action">italic</property>
<property name="label" translatable="yes">Italic</property>
<property name="use_underline">True</property>
</object>
......@@ -396,7 +449,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Underline</property>
<property name="related_action">underline</property>
<property name="label" translatable="yes">Underline</property>
<property name="use_underline">True</property>
</object>
......@@ -411,7 +463,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Strikethrough</property>
<property name="related_action">strikethrough</property>
<property name="label" translatable="yes">Strikethrough</property>
<property name="use_underline">True</property>
</object>
......@@ -422,10 +473,8 @@
</child>
<child>
<object class="GtkSeparatorToolItem" id="toolbutton5">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -438,7 +487,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Indent</property>
<property name="related_action">indent</property>
<property name="label" translatable="yes">Indent</property>
<property name="use_underline">True</property>
</object>
......@@ -453,7 +501,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Un-indent</property>
<property name="related_action">outdent</property>
<property name="label" translatable="yes">Un-indent</property>
<property name="use_underline">True</property>
</object>
......@@ -464,10 +511,8 @@
</child>
<child>
<object class="GtkSeparatorToolItem" id="toolbutton3">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -480,7 +525,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Fonts</property>
<property name="related_action">font</property>
<property name="label" translatable="yes">Fonts</property>
<property name="use_underline">True</property>
</object>
......@@ -495,7 +539,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Font size</property>
<property name="related_action">fontsize</property>
<property name="label" translatable="yes">Font size</property>
<property name="use_underline">True</property>
</object>
......@@ -510,7 +553,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Color</property>
<property name="related_action">color</property>
<property name="label" translatable="yes">Color</property>
<property name="use_underline">True</property>
</object>
......@@ -525,7 +567,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Link</property>
<property name="related_action">insertlink</property>
<property name="label" translatable="yes">Link</property>
<property name="use_underline">True</property>
</object>
......@@ -540,7 +581,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Remove formatting</property>
<property name="related_action">removeformat</property>
<property name="label" translatable="yes">Remove formatting</property>
<property name="use_underline">True</property>
</object>
......@@ -616,13 +656,11 @@
<child>
<object class="GtkButton" id="add_attachment_button">
<property name="label" translatable="yes">_Attach File</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
</object>
<packing>
......@@ -634,11 +672,9 @@
<child>
<object class="GtkButton" id="Cancel">
<property name="label">gtk-cancel</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
......@@ -653,11 +689,9 @@
<child>
<object class="GtkButton" id="Send">
<property name="label" translatable="yes">_Send</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
</object>
<packing>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment