fix bug 4239, 'Preferences: Text Options Header Display modal is not modal' (sic)
[claws.git] / src / plugins / managesieve / sieve_manager.c
index 212c30a1fbb97bec61f52c09fdf31281fb0f75f9..a71abc40692cee32b7f0c4eade8525c7b893b28f 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
 #include <glib.h>
 #include <glib/gi18n.h>
 
@@ -59,16 +60,11 @@ typedef struct {
        gchar *filter_name;
 } CommandDataName;
 
-typedef struct {
-       SieveManagerPage *page;
-       gchar *filter_name;
-       SieveEditorPage *editor_page;
-       gboolean first_line;
-} CommandDataGetScript;
-
+static void filter_got_load_error(SieveSession *session, gpointer data);
 static void account_changed(GtkWidget *widget, SieveManagerPage *page);
-static void filter_activate(GtkWidget *widget, SieveManagerPage *page);
-void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page);
+static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page);
+static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
+               SieveManagerPage *page);
 static void filter_set_active(SieveManagerPage *page, gchar *filter_name);
 gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
                gchar *filter_name);
@@ -85,6 +81,13 @@ static GSList *manager_pages = NULL;
                if ((page = (SieveManagerPage *)cur->data) && \
                        page->active_session == session)
 
+void sieve_managers_done()
+{
+       GSList *list = manager_pages;
+       manager_pages = NULL;
+       g_slist_free_full(list, (GDestroyNotify)sieve_manager_done);
+}
+
 static void filters_list_clear(SieveManagerPage *page)
 {
        GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
@@ -151,6 +154,7 @@ static gchar *filters_list_get_selected_filter(GtkWidget *list_view)
 static void filter_add(GtkWidget *widget, SieveManagerPage *page)
 {
        SieveSession *session = page->active_session;
+       SieveEditorPage *editor;
        if (!session)
                return;
        gchar *filter_name = input_dialog(_("Add Sieve script"),
@@ -158,77 +162,70 @@ static void filter_add(GtkWidget *widget, SieveManagerPage *page)
        if (!filter_name || !filter_name[0])
                return;
 
-       sieve_editor_new(session, filter_name);
-       /*
-       sieve_session_add_script(session, filter_name
-                       (sieve_session_data_cb_fn)filter_added, (gpointer)page);
-                       */
+       editor = sieve_editor_get(session, filter_name);
+       if (editor) {
+               /* TODO: show error that filter already exists */
+               sieve_editor_present(editor);
+               g_free(filter_name);
+               sieve_editor_load(editor,
+                       (sieve_session_cb_fn)filter_got_load_error, page);
+       } else {
+               editor = sieve_editor_new(session, filter_name);
+               editor->is_new = TRUE;
+               sieve_editor_show(editor);
+       }
 }
 
-static void filter_got_data(SieveSession *session, gchar *contents,
-               CommandDataGetScript *cmd_data)
+static void filter_got_load_error(SieveSession *session, gpointer data)
 {
-       SieveManagerPage *page = cmd_data->page;
-       SieveEditorPage *editor;
+       SieveManagerPage *page = data;
 
-       if (!contents) {
-               g_free(cmd_data);
-               return;
-       } else if (contents == (void *)-1) {
-               got_session_error(session, _("Unable to get script contents"), page);
-               return;
-       }
-
-       if (cmd_data->first_line) {
-               cmd_data->first_line = FALSE;
-               editor = sieve_editor_new(session, cmd_data->filter_name);
-               cmd_data->editor_page = editor;
-       } else {
-               editor = cmd_data->editor_page;
-               sieve_editor_append_text(editor, "\n", 1);
-       }
-       sieve_editor_append_text(editor, contents, strlen(contents));
+       got_session_error(session, _("Unable to get script contents"), page);
 }
 
 static void filter_edit(GtkWidget *widget, SieveManagerPage *page)
 {
        SieveEditorPage *editor;
-       CommandDataGetScript *cmd_data;
        SieveSession *session = page->active_session;
+       gchar *filter_name;
+
        if (!session)
                return;
-       gchar *filter_name = filters_list_get_selected_filter(page->filters_list);
+
+       filter_name = filters_list_get_selected_filter(page->filters_list);
        if (!filter_name)
                return;
 
        editor = sieve_editor_get(session, filter_name);
        if (editor) {
                sieve_editor_present(editor);
+               g_free(filter_name);
        } else {
-               cmd_data = g_new0(CommandDataGetScript, 1);
-               cmd_data->first_line = TRUE;
-               cmd_data->filter_name = filter_name;
-               cmd_data->page = page;
-
-               sieve_session_get_script(session, filter_name,
-                       (sieve_session_data_cb_fn)filter_got_data, cmd_data);
+               editor = sieve_editor_new(session, filter_name);
+               /* filter_name becomes ownership of newly created
+                * SieveEditorPage, so we do not need to free it here. */
+               sieve_editor_load(editor,
+                       (sieve_session_cb_fn)filter_got_load_error, page);
        }
 }
 
-static void filter_renamed(SieveSession *session, gboolean success,
-               CommandDataRename *data)
+static void filter_renamed(SieveSession *session, gboolean abort,
+               gboolean success, CommandDataRename *data)
 {
        SieveManagerPage *page = data->page;
        GSList *cur;
 
-       if (!success) {
+       if (abort) {
+       } else if (!success) {
                got_session_error(session, "Unable to rename script", page);
-               return;
-       }
-
-       manager_sessions_foreach(cur, session, page) {
-               filters_list_rename_filter(page, data->name_old, data->name_new);
+       } else {
+               manager_sessions_foreach(cur, session, page) {
+                       filters_list_rename_filter(page, data->name_old,
+                                       data->name_new);
+               }
        }
+       g_free(data->name_old);
+       g_free(data->name_new);
        g_free(data);
 }
 
@@ -259,20 +256,21 @@ static void filter_rename(GtkWidget *widget, SieveManagerPage *page)
                        (sieve_session_data_cb_fn)filter_renamed, (gpointer)cmd_data);
 }
 
-static void filter_activated(SieveSession *session, gboolean success,
-               CommandDataName *cmd_data)
+static void filter_activated(SieveSession *session, gboolean abort,
+               const gchar *err, CommandDataName *cmd_data)
 {
        SieveManagerPage *page = cmd_data->page;
        GSList *cur;
 
-       if (!success) {
-               got_session_error(session, "Unable to set active script", page);
-               return;
-       }
-
-       manager_sessions_foreach(cur, session, page) {
-               filter_set_active(page, cmd_data->filter_name);
+       if (abort) {
+       } else if (err) {
+               got_session_error(session, err, page);
+       } else {
+               manager_sessions_foreach(cur, session, page) {
+                       filter_set_active(page, cmd_data->filter_name);
+               }
        }
+       g_free(cmd_data->filter_name);
        g_free(cmd_data);
 }
 
@@ -290,31 +288,23 @@ static void sieve_set_active_filter(SieveManagerPage *page, gchar *filter_name)
                        (sieve_session_data_cb_fn)filter_activated, cmd_data);
 }
 
-/*
- * activate button clicked
- */
-static void filter_activate(GtkWidget *widget, SieveManagerPage *page)
-{
-       gchar *filter_name = filters_list_get_selected_filter(page->filters_list);
-       if (!filter_name)
-               return;
-       sieve_set_active_filter(page, filter_name);
-}
-
-static void filter_deleted(SieveSession *session, const gchar *err_msg,
+static void filter_deleted(SieveSession *session, gboolean abort,
+               const gchar *err_msg,
                CommandDataName *cmd_data)
 {
        SieveManagerPage *page = cmd_data->page;
        GSList *cur;
 
-       if (err_msg) {
+       if (abort) {
+       } else if (err_msg) {
                got_session_error(session, err_msg, page);
-               return;
-       }
-
-       manager_sessions_foreach(cur, session, page) {
-               filters_list_delete_filter(page, cmd_data->filter_name);
+       } else {
+               manager_sessions_foreach(cur, session, page) {
+                       filters_list_delete_filter(page,
+                                       cmd_data->filter_name);
+               }
        }
+       g_free(cmd_data->filter_name);
        g_free(cmd_data);
 }
 
@@ -337,8 +327,8 @@ static void filter_delete(GtkWidget *widget, SieveManagerPage *page)
        g_snprintf(buf, sizeof(buf),
                   _("Do you really want to delete the filter '%s'?"), filter_name);
        if (alertpanel_full(_("Delete filter"), buf,
-                               GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, FALSE,
-                               NULL, ALERT_WARNING, G_ALERTDEFAULT) != G_ALERTALTERNATE)
+                               GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_FIRST, FALSE,
+                               NULL, ALERT_WARNING) != G_ALERTALTERNATE)
                return;
 
        cmd_data = g_new(CommandDataName, 1);
@@ -472,6 +462,7 @@ static void filters_create_list_view_columns(SieveManagerPage *page,
 {
        GtkTreeViewColumn *column;
        GtkCellRenderer *renderer;
+       GtkWidget *label;
 
        /* Name */
        renderer = gtk_cell_renderer_text_new();
@@ -494,8 +485,14 @@ static void filters_create_list_view_columns(SieveManagerPage *page,
                 NULL);
        gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
        gtk_tree_view_column_set_alignment (column, 0.5);
-       CLAWS_SET_TIP(gtk_tree_view_column_get_widget(column),
+
+       /* the column header needs a widget to have a tooltip */
+       label = gtk_label_new(gtk_tree_view_column_get_title(column));
+       gtk_widget_show(label);
+       gtk_tree_view_column_set_widget(column, label);
+       CLAWS_SET_TIP(label,
                        _("An account can only have one active script at a time."));
+
        g_signal_connect(G_OBJECT(renderer), "toggled",
                         G_CALLBACK(filter_active_toggled), page);
 
@@ -547,9 +544,19 @@ static gboolean manager_key_pressed(GtkWidget *widget, GdkEventKey *event,
        return FALSE;
 }
 
+static void size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation)
+{
+       cm_return_if_fail(allocation != NULL);
+
+       sieve_config.manager_win_width = allocation->width;
+       sieve_config.manager_win_height = allocation->height;
+}
+
 static void got_session_error(SieveSession *session, const gchar *msg,
                SieveManagerPage *page)
 {
+       if (!g_slist_find(manager_pages, page))
+               return;
        if (page->active_session != session)
                return;
        gtk_label_set_text(GTK_LABEL(page->status_text), msg);
@@ -575,9 +582,11 @@ static void sieve_manager_on_connected(SieveSession *session,
        }
 }
 
-static void got_filter_listed(SieveSession *session, SieveScript *script,
-               SieveManagerPage *page)
+static void got_filter_listed(SieveSession *session, gboolean abort,
+               SieveScript *script, SieveManagerPage *page)
 {
+       if (abort)
+               return;
        if (!script) {
                got_session_error(session, "Unable to list scripts", page);
                return;
@@ -601,6 +610,9 @@ static void account_changed(GtkWidget *widget, SieveManagerPage *page)
        PrefsAccount *account;
        SieveSession *session;
 
+       if (page->accounts_menu == NULL)
+               return;
+
        account_id = combobox_get_active_data(GTK_COMBO_BOX(page->accounts_menu));
        account = account_find_from_id(account_id);
        if (!account)
@@ -640,6 +652,8 @@ static SieveManagerPage *sieve_manager_page_new()
        SieveAccountConfig *config;
        PrefsAccount *default_account = NULL;
 
+       static GdkGeometry geometry;
+
        page = g_new0(SieveManagerPage, 1);
 
        /* Manage Window */
@@ -647,10 +661,27 @@ static SieveManagerPage *sieve_manager_page_new()
        window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "sievemanager");
        gtk_container_set_border_width (GTK_CONTAINER (window), 8);
        gtk_window_set_title (GTK_WINDOW (window), _("Manage Sieve Filters"));
-       gtk_widget_set_size_request (window, 480, 296);
+       gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
        MANAGE_WINDOW_SIGNALS_CONNECT (window);
+
        g_signal_connect (G_OBJECT (window), "key_press_event",
                        G_CALLBACK (manager_key_pressed), page);
+       g_signal_connect (G_OBJECT(window), "size_allocate",
+                        G_CALLBACK (size_allocate_cb), NULL);
+       g_signal_connect (G_OBJECT(window), "delete_event",
+                        G_CALLBACK (sieve_manager_deleted), page);
+
+       if (!geometry.min_height) {
+               geometry.min_width = 350;
+               geometry.min_height = 280;
+       }
+
+       gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
+                                     GDK_HINT_MIN_SIZE);
+       gtk_widget_set_size_request(window, sieve_config.manager_win_width,
+                       sieve_config.manager_win_height);
+       gtk_window_set_type_hint(GTK_WINDOW(window),
+                       GDK_WINDOW_TYPE_HINT_DIALOG);
 
        vbox = gtk_vbox_new (FALSE, 10);
        gtk_container_add (GTK_CONTAINER (window), vbox);
@@ -683,6 +714,7 @@ static SieveManagerPage *sieve_manager_page_new()
        if (!default_account) {
                gtk_widget_destroy(label);
                gtk_widget_destroy(accounts_menu);
+               accounts_menu = NULL;
        }
 
        /* status */
@@ -709,47 +741,41 @@ static SieveManagerPage *sieve_manager_page_new()
 
        /* Buttons */
 
-       vbox_allbuttons = gtk_vbox_new (FALSE, 0);
+       vbox_allbuttons = gtk_vbox_new (FALSE, 8);
        gtk_box_pack_start (GTK_BOX (hbox), vbox_allbuttons, FALSE, FALSE, 0);
 
-       vbox_buttons = gtk_vbox_new (FALSE, 0);
+       /* buttons that depend on there being a connection */
+       vbox_buttons = gtk_vbox_new (FALSE, 8);
        gtk_widget_set_sensitive(vbox_buttons, FALSE);
        gtk_box_pack_start (GTK_BOX (vbox_allbuttons), vbox_buttons, FALSE, FALSE, 0);
 
        /* new */
        btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
-       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
        g_signal_connect (G_OBJECT(btn), "clicked",
                          G_CALLBACK (filter_add), page);
 
        /* edit */
        btn = gtk_button_new_from_stock (GTK_STOCK_EDIT);
-       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
        g_signal_connect (G_OBJECT(btn), "clicked",
                        G_CALLBACK (filter_edit), page);
 
        /* delete */
        btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
-       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
        g_signal_connect (G_OBJECT(btn), "clicked",
                        G_CALLBACK (filter_delete), page);
 
        /* rename */
-       btn = gtk_button_new_with_label("Rename");
-       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
+       btn = gtk_button_new_with_label(_("Rename"));
+       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
        g_signal_connect (G_OBJECT(btn), "clicked",
                        G_CALLBACK (filter_rename), page);
 
-
-       /* activate */
-       btn = gtk_button_new_with_label("Activate");
-       gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 4);
-       g_signal_connect (G_OBJECT(btn), "clicked",
-                       G_CALLBACK (filter_activate), page);
-
        /* refresh */
-       btn = gtk_button_new_with_mnemonic("_Refresh");
-       gtk_box_pack_start (GTK_BOX (vbox_allbuttons), btn, FALSE, FALSE, 4);
+       btn = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
+       gtk_box_pack_end (GTK_BOX (vbox_allbuttons), btn, FALSE, FALSE, 0);
        g_signal_connect (G_OBJECT(btn), "clicked",
                        G_CALLBACK (account_changed), page);
 
@@ -783,7 +809,14 @@ static SieveManagerPage *sieve_manager_page_new()
        return page;
 }
 
-void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
+static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
+               SieveManagerPage *page)
+{
+       sieve_manager_done(page);
+       return FALSE;
+}
+
+static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
 {
        sieve_manager_done(page);
 }
@@ -791,6 +824,7 @@ void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
 void sieve_manager_done(SieveManagerPage *page)
 {
        manager_pages = g_slist_remove(manager_pages, page);
+       sieve_sessions_discard_callbacks(page);
        gtk_widget_destroy(page->window);
        g_free(page);
 }
@@ -801,3 +835,14 @@ void sieve_manager_show()
        manager_pages = g_slist_prepend(manager_pages, page);
        gtk_widget_show_all(page->window);
 }
+
+void sieve_manager_script_created(SieveSession *session, const gchar *name)
+{
+       SieveManagerPage *page;
+       SieveScript script = {.name = (gchar *)name};
+       GSList *cur;
+
+       manager_sessions_foreach(cur, session, page) {
+               filters_list_insert_filter(page, &script);
+       }
+}