From f604d2d988b3c8ab9cd3c294701e640da2090339 Mon Sep 17 00:00:00 2001 From: Eric Gregory Date: Fri, 8 Feb 2013 11:59:27 -0800 Subject: [PATCH] Closes #6334 Show and set "From:" field in composer --- CMakeLists.txt | 5 +- src/CMakeLists.txt | 1 + .../account-dialog-remove-fail-pane.vala | 20 ++++ src/client/accounts/account-dialog.vala | 31 +++++- src/client/composer/composer-window.vala | 83 +++++++++++++- src/client/geary-application.vala | 4 + src/client/geary-controller.vala | 33 ++++-- src/engine/api/geary-account-information.vala | 7 ++ ui/CMakeLists.txt | 1 + ui/account_cannot_remove.glade | 103 ++++++++++++++++++ ui/composer.glade | 92 +++++++++++----- 11 files changed, 334 insertions(+), 46 deletions(-) create mode 100644 src/client/accounts/account-dialog-remove-fail-pane.vala create mode 100644 ui/account_cannot_remove.glade diff --git a/CMakeLists.txt b/CMakeLists.txt index 6252aed5..05a106b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e23f80a2..2c3d91c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/client/accounts/account-dialog-remove-fail-pane.vala b/src/client/accounts/account-dialog-remove-fail-pane.vala new file mode 100644 index 00000000..8dccefef --- /dev/null +++ b/src/client/accounts/account-dialog-remove-fail-pane.vala @@ -0,0 +1,20 @@ +/* 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(); }); + } +} + diff --git a/src/client/accounts/account-dialog.vala b/src/client/accounts/account-dialog.vala index ba67316a..8af040a9 100644 --- a/src/client/accounts/account-dialog.vala +++ b/src/client/accounts/account-dialog.vala @@ -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? 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) { diff --git a/src/client/composer/composer-window.vala b/src/client/composer/composer-window.vala index 2e17991c..258c5c1e 100644 --- a/src/client/composer/composer-window.vala +++ b/src/client/composer/composer-window.vala @@ -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 attachment_files = new Gee.HashSet(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 = "
" + 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 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);
+            }
+        }
+    }
 }
 
diff --git a/src/client/geary-application.vala b/src/client/geary-application.vala
index 277cdfcf..cff3a9e0 100644
--- a/src/client/geary-application.vala
+++ b/src/client/geary-application.vala
@@ -418,5 +418,9 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
             }
         }
     }
+    
+    public Gee.List? get_composer_windows_for_account(Geary.AccountInformation account) {
+        return controller.get_composer_windows_for_account(account);
+    }
 }
 
diff --git a/src/client/geary-controller.vala b/src/client/geary-controller.vala
index 734c25f6..0b117c72 100644
--- a/src/client/geary-controller.vala
+++ b/src/client/geary-controller.vala
@@ -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? get_composer_windows_for_account(Geary.AccountInformation account) {
+        Gee.List ret = new Gee.LinkedList();
+        foreach (ComposerWindow cw in composer_windows) {
+            if (cw.account.information == account)
+                ret.add(cw);
+        }
+        
+        return ret.size >= 1 ? ret : null;
     }
 }
 
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index 642c6396..d3da824d 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -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);
+    }
 }
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index 221a01d4..6affe7de 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -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})
diff --git a/ui/account_cannot_remove.glade b/ui/account_cannot_remove.glade
new file mode 100644
index 00000000..75c04c01
--- /dev/null
+++ b/ui/account_cannot_remove.glade
@@ -0,0 +1,103 @@
+
+
+  
+  
+    
+      
+        gtk-ok
+      
+    
+  
+  
+    True
+    False
+    1
+    
+      
+        True
+        False
+        0
+        gtk-dialog-error
+        6
+      
+      
+        False
+        True
+        6
+        0
+      
+    
+    
+      
+        True
+        False
+        vertical
+        
+          
+            True
+            False
+            20
+            0
+            <span weight="bold" size="larger">Cannot remove account</span> 
+            True
+            True
+          
+          
+            False
+            True
+            0
+          
+        
+        
+          
+            True
+            False
+            0
+            0
+            A composer window associated with this account is currently open. Send or discard the message and try again.
+            True
+          
+          
+            True
+            True
+            6
+            1
+          
+        
+        
+          
+            True
+            False
+            12
+            end
+            
+              
+                _Remove
+                ok_action
+                True
+                True
+                True
+                True
+              
+              
+                False
+                True
+                1
+              
+            
+          
+          
+            False
+            True
+            2
+          
+        
+      
+      
+        False
+        True
+        1
+      
+    
+  
+
diff --git a/ui/composer.glade b/ui/composer.glade
index 64b28497..1c442b24 100644
--- a/ui/composer.glade
+++ b/ui/composer.glade
@@ -179,7 +179,7 @@
                   
                   
                     0
-                    0
+                    1
                     1
                     1
                   
@@ -196,7 +196,7 @@
                   
                   
                     0
-                    1
+                    2
                     1
                     1
                   
@@ -209,7 +209,7 @@
                   
                   
                     1
-                    0
+                    1
                     1
                     1
                   
@@ -222,7 +222,7 @@
                   
                   
                     1
-                    1
+                    2
                     1
                     1
                   
@@ -237,7 +237,7 @@
                   
                   
                     1
-                    3
+                    4
                     1
                     1
                   
@@ -254,7 +254,7 @@
                   
                   
                     0
-                    3
+                    4
                     1
                     1
                   
@@ -271,7 +271,7 @@
                   
                   
                     0
-                    2
+                    3
                     1
                     1
                   
@@ -284,7 +284,62 @@
                   
                   
                     1
-                    2
+                    3
+                    1
+                    1
+                  
+                
+                
+                  
+                    True
+                    False
+                    1
+                    6
+                    From:
+                    right
+                    to
+                  
+                  
+                    0
+                    0
+                    1
+                    1
+                  
+                
+                
+                  
+                    True
+                    False
+                    vertical
+                    
+                      
+                        True
+                        False
+                        0
+                      
+                      
+                        False
+                        True
+                        0
+                      
+                    
+                    
+                      
+                        True
+                        False
+                        0
+                        1
+                      
+                      
+                        False
+                        True
+                        1
+                      
+                    
+                  
+                  
+                    1
+                    0
                     1
                     1
                   
@@ -366,7 +421,6 @@
             True
             False
             Bold
-            bold
             Bold
             True
           
@@ -381,7 +435,6 @@
             True
             False
             Italic
-            italic
             Italic
             True
           
@@ -396,7 +449,6 @@
             True
             False
             Underline
-            underline
             Underline
             True
           
@@ -411,7 +463,6 @@
             True
             False
             Strikethrough
-            strikethrough
             Strikethrough
             True
           
@@ -422,10 +473,8 @@
         
         
           
-            False
             True
             False
-            False
           
           
             False
@@ -438,7 +487,6 @@
             True
             False
             Indent
-            indent
             Indent
             True
           
@@ -453,7 +501,6 @@
             True
             False
             Un-indent
-            outdent
             Un-indent
             True
           
@@ -464,10 +511,8 @@
         
         
           
-            False
             True
             False
-            False
           
           
             False
@@ -480,7 +525,6 @@
             True
             False
             Fonts
-            font
             Fonts
             True
           
@@ -495,7 +539,6 @@
             True
             False
             Font size
-            fontsize
             Font size
             True
           
@@ -510,7 +553,6 @@
             True
             False
             Color
-            color
             Color
             True
           
@@ -525,7 +567,6 @@
             True
             False
             Link
-            insertlink
             Link
             True
           
@@ -540,7 +581,6 @@
             True
             False
             Remove formatting
-            removeformat
             Remove formatting
             True
           
@@ -616,13 +656,11 @@
         
           
             _Attach File
-            False
             True
             True
             True
             start
             center
-            False
             True
           
           
@@ -634,11 +672,9 @@
         
           
             gtk-cancel
-            False
             True
             True
             True
-            False
             True
           
           
@@ -653,11 +689,9 @@
         
           
             _Send
-            False
             True
             True
             True
-            False
             True