diff options
-rw-r--r-- | filter/ChangeLog | 27 | ||||
-rw-r--r-- | filter/filter-rule.c | 12 | ||||
-rw-r--r-- | filter/rule-context.c | 28 | ||||
-rw-r--r-- | filter/rule-context.h | 1 | ||||
-rw-r--r-- | filter/rule-editor.c | 141 | ||||
-rw-r--r-- | filter/rule-editor.h | 20 |
6 files changed, 217 insertions, 12 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog index de6800abae..1e94dae79d 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,30 @@ +2001-10-28 <NotZed@Ximian.com> + + * rule-editor.c (rule_move): Add undo for move. + (rule_editor_add_undo): Add extra rank item. + (rule_editor_play_undo): handle rank case. + (rule_editor_finalise): Clean up any hanging over undo log. + (editor_clicked): Only enable 'undo' if we have + EVOLUTION_RULE_UNDO enabled. Code still a bit flakey. + (rule_editor_construct): Only enable a cancel button if + EVOLUTION_RULE_UNDO is set. + + * filter-rule.c (filter_rule_set_name): Emit a changed event if it + changes. + (filter_rule_set_source): Same. + +2001-10-26 <NotZed@Ximian.com> + + * rule-context.c (rule_context_find_rank_rule): Find a rule at a + specific rank/source. + + * rule-editor.c (add_editor_clicked): Log the added object. + (rule_editor_add_undo): New function to add an undo record to the + rule editor. + (edit_editor_clicked): Log the changed object. + (rule_delete): Add undo object. + (rule_editor_play_undo): Play an undo log back. + 2001-10-26 Jeffrey Stedfast <fejj@ximian.com> * rule-editor.c (rule_add): Desensitize the parent dialog. diff --git a/filter/filter-rule.c b/filter/filter-rule.c index 38682fc0ae..5a4b28d5f7 100644 --- a/filter/filter-rule.c +++ b/filter/filter-rule.c @@ -169,18 +169,30 @@ void filter_rule_set_name (FilterRule *fr, const char *name) { g_assert (IS_FILTER_RULE (fr)); + + if ((fr->name && name && strcmp(fr->name, name) == 0) + || (fr->name == NULL && name == NULL)) + return; g_free (fr->name); fr->name = g_strdup (name); + + filter_rule_emit_changed(fr); } void filter_rule_set_source (FilterRule *fr, const char *source) { g_assert (IS_FILTER_RULE (fr)); + + if ((fr->source && source && strcmp(fr->source, source) == 0) + || (fr->source == NULL && source == NULL)) + return; g_free (fr->source); fr->source = g_strdup (source); + + filter_rule_emit_changed(fr); } int diff --git a/filter/rule-context.c b/filter/rule-context.c index 065ed91ed4..ce83abc662 100644 --- a/filter/rule-context.c +++ b/filter/rule-context.c @@ -619,3 +619,31 @@ rule_context_get_rank_rule (RuleContext *f, FilterRule *rule, const char *source return -1; } + +FilterRule * +rule_context_find_rank_rule (RuleContext *f, int rank, const char *source) +{ + GList *node; + int i = 0; + + g_assert(f); + + d(printf("getting rule at rank %d source '%s'\n", rank, source?source:"<any>")); + + node = f->rules; + while (node) { + FilterRule *r = node->data; + + d(printf(" checking against rule '%s' rank '%d'\n", r->name, i)); + + if (source == NULL || (r->source && strcmp(r->source, source) == 0)) { + if (rank == i) + return r; + i++; + } + + node = node->next; + } + + return NULL; +} diff --git a/filter/rule-context.h b/filter/rule-context.h index 91b83d047b..05c6ccfcf4 100644 --- a/filter/rule-context.h +++ b/filter/rule-context.h @@ -100,6 +100,7 @@ FilterPart *rule_context_next_part(RuleContext *f, FilterPart *last); FilterRule *rule_context_next_rule(RuleContext *f, FilterRule *last, const char *source); FilterRule *rule_context_find_rule(RuleContext *f, const char *name, const char *source); +FilterRule *rule_context_find_rank_rule(RuleContext *f, int rank, const char *source); void rule_context_add_rule(RuleContext *f, FilterRule *new); void rule_context_add_rule_gui(RuleContext *f, FilterRule *rule, const char *title, const char *path); void rule_context_remove_rule(RuleContext *f, FilterRule *rule); diff --git a/filter/rule-editor.c b/filter/rule-editor.c index 2ff76596f3..0fdd845dd9 100644 --- a/filter/rule-editor.c +++ b/filter/rule-editor.c @@ -33,7 +33,13 @@ #include "rule-context.h" #include "filter-rule.h" -#define d(x) +/* for getenv only, remove when getenv need removed */ +#include <stdlib.h> + +void rule_editor_add_undo(RuleEditor *re, int type, FilterRule *rule, int rank, int newrank); +void rule_editor_play_undo(RuleEditor *re); + +#define d(x) x static void set_source(RuleEditor *re, const char *source); static void set_sensitive(RuleEditor *re); @@ -120,10 +126,18 @@ static void rule_editor_finalise (GtkObject *obj) { RuleEditor *re = (RuleEditor *)obj; - + RuleEditorUndo *undo, *next; + gtk_object_unref (GTK_OBJECT (re->context)); - g_free (re->priv); + + undo = re->undo_log; + while (undo) { + next = undo->next; + gtk_object_unref((GtkObject *)undo->rule); + g_free(undo); + undo = next; + } ((GtkObjectClass *)(parent_class))->finalize (obj); } @@ -204,7 +218,7 @@ add_editor_clicked (GtkWidget *dialog, int button, RuleEditor *re) GtkWidget *item; GList *l = NULL; char *string; - + switch (button) { case 0: if (!filter_rule_validate (re->edit)) { @@ -227,6 +241,9 @@ add_editor_clicked (GtkWidget *dialog, int button, RuleEditor *re) re->current = re->edit; rule_context_add_rule (re->context, re->current); + + gtk_object_ref((GtkObject *)re->current); + rule_editor_add_undo(re, RULE_EDITOR_LOG_ADD, re->current, rule_context_get_rank_rule (re->context, re->current, re->current->source), 0); case 1: default: gnome_dialog_close (GNOME_DIALOG (dialog)); @@ -263,7 +280,6 @@ rule_add (GtkWidget *widget, RuleEditor *re) gtk_widget_set_parent_window (GTK_WIDGET (re->dialog), GTK_WIDGET (re)->window); gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (re->dialog)->vbox), rules, TRUE, TRUE, 0); gtk_signal_connect (GTK_OBJECT (re->dialog), "clicked", add_editor_clicked, re); - gtk_widget_set_sensitive (GTK_WIDGET (re), FALSE); gtk_widget_show (re->dialog); @@ -289,7 +305,9 @@ edit_editor_clicked (GtkWidget *dialog, int button, RuleEditor *re) string = e_utf8_to_gtk_string (GTK_WIDGET (item), re->edit->name); gtk_label_set_text (GTK_LABEL (GTK_BIN (item)->child), string); g_free (string); - + + rule_editor_add_undo(re, RULE_EDITOR_LOG_EDIT, filter_rule_clone(re->current), pos, 0); + /* replace the old rule with the new rule */ filter_rule_copy (re->current, re->edit); } @@ -352,8 +370,11 @@ rule_delete (GtkWidget *widget, RuleEditor *re) l = g_list_append (NULL, item); gtk_list_remove_items (re->list, l); g_list_free (l); - + + rule_editor_add_undo(re, RULE_EDITOR_LOG_REMOVE, re->current, rule_context_get_rank_rule(re->context, re->current, re->current->source), 0); +#if 0 gtk_object_unref (GTK_OBJECT (re->current)); +#endif re->current = NULL; /* now select the next rule */ @@ -370,6 +391,9 @@ rule_move (RuleEditor *re, int from, int to) { GList *l; GtkListItem *item; + + gtk_object_ref((GtkObject *)re->current); + rule_editor_add_undo(re, RULE_EDITOR_LOG_RANK, re->current, rule_context_get_rank_rule(re->context, re->current, re->current->source), to); d(printf ("moving %d to %d\n", from, to)); rule_context_rank_rule (re->context, re->current, to); @@ -469,7 +493,7 @@ set_source (RuleEditor *re, const char *source) GtkWidget *item; char *s; - d(printf(" hit %s(%d)\n", rule->name, source)); + d(printf(" hit %s(%s)\n", rule->name, source)); s = e_utf8_to_gtk_string (GTK_WIDGET (re->list), U_(rule->name)); item = gtk_list_item_new_with_label (s); g_free (s); @@ -486,6 +510,95 @@ set_source (RuleEditor *re, const char *source) } void +rule_editor_add_undo(RuleEditor *re, int type, FilterRule *rule, int rank, int newrank) +{ + RuleEditorUndo *undo; + + printf("Adding udno record: %d object %p '%s'\n", type, rule, rule->name); + + if (!re->undo_active) { + undo = g_malloc0(sizeof(*undo)); + undo->rule = rule; + undo->type = type; + undo->rank = rank; + undo->newrank = newrank; + + undo->next = re->undo_log; + re->undo_log = undo; + } else { + gtk_object_unref((GtkObject *)rule); + } +} + +void +rule_editor_play_undo(RuleEditor *re) +{ + RuleEditorUndo *undo, *next; + FilterRule *rule; + + re->undo_active = TRUE; + undo = re->undo_log; + re->undo_log = NULL; + while (undo) { + next = undo->next; + switch (undo->type) { + case RULE_EDITOR_LOG_EDIT: + printf("Undoing edit on rule '%s'\n", undo->rule->name); + rule = rule_context_find_rank_rule(re->context, undo->rank, undo->rule->source); + if (rule) { + printf(" name was '%s'\n", rule->name); + filter_rule_copy(rule, undo->rule); + printf(" name is '%s'\n", rule->name); + } else { + g_warning("Could not find the right rule to undo against?\n"); + } + break; + case RULE_EDITOR_LOG_ADD: + printf("Undoing add on rule '%s'\n", undo->rule->name); + rule = rule_context_find_rank_rule(re->context, undo->rank, undo->rule->source); + if (rule) + rule_context_remove_rule(re->context, rule); + break; + case RULE_EDITOR_LOG_REMOVE: + printf("Undoing remove on rule '%s'\n", undo->rule->name); + rule_context_add_rule(re->context, undo->rule); + rule_context_rank_rule(re->context, undo->rule, undo->rank); + break; + case RULE_EDITOR_LOG_RANK: + rule = rule_context_find_rank_rule(re->context, undo->newrank, undo->rule->source); + if (rule) + rule_context_rank_rule(re->context, rule, undo->rank); + break; + } + gtk_object_unref((GtkObject *)undo->rule); + g_free(undo); + undo = next; + } + re->undo_active = FALSE; +} + +static void +editor_clicked (GtkWidget *dialog, int button, RuleEditor *re) +{ + if (button != 0) { + if (getenv("EVOLUTION_RULE_UNDO")) + rule_editor_play_undo(re); + else { + RuleEditorUndo *undo, *next; + + undo = re->undo_log; + re->undo_log = 0; + while (undo) { + next = undo->next; + gtk_object_unref((GtkObject *)undo->rule); + g_free(undo); + undo = next; + } + } + } +} + +void rule_editor_construct (RuleEditor *re, RuleContext *context, GladeXML *gui, const char *source) { GtkWidget *w; @@ -507,9 +620,13 @@ rule_editor_construct (RuleEditor *re, RuleContext *context, GladeXML *gui, cons re->list = (GtkList *) w = glade_xml_get_widget(gui, "rule_list"); gtk_signal_connect (GTK_OBJECT (w), "select_child", select_rule, re); gtk_signal_connect (GTK_OBJECT (w), "button_press_event", double_click, re); - + + gtk_signal_connect (GTK_OBJECT (re), "clicked", editor_clicked, re); rule_editor_set_source (re, source); - - gnome_dialog_append_buttons (GNOME_DIALOG (re), GNOME_STOCK_BUTTON_OK, - GNOME_STOCK_BUTTON_CANCEL, NULL); + + if (getenv("EVOLUTION_RULE_UNDO")) { + gnome_dialog_append_buttons (GNOME_DIALOG (re), GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL, NULL); + } else + gnome_dialog_append_buttons (GNOME_DIALOG (re), GNOME_STOCK_BUTTON_OK, NULL); } diff --git a/filter/rule-editor.h b/filter/rule-editor.h index b981a61b65..f054023c87 100644 --- a/filter/rule-editor.h +++ b/filter/rule-editor.h @@ -30,6 +30,7 @@ typedef struct _RuleEditor RuleEditor; typedef struct _RuleEditorClass RuleEditorClass; +typedef struct _RuleEditorUndo RuleEditorUndo; struct _RuleEditor { GnomeDialog parent; @@ -43,6 +44,9 @@ struct _RuleEditor { char *source; + struct _RuleEditorUndo *undo_log; /* cancel/undo log */ + unsigned int undo_active:1; /* we're performing undo */ + struct _RuleEditorPrivate *priv; }; @@ -58,6 +62,22 @@ struct _RuleEditorClass { /* signals */ }; +enum { + RULE_EDITOR_LOG_EDIT, + RULE_EDITOR_LOG_ADD, + RULE_EDITOR_LOG_REMOVE, + RULE_EDITOR_LOG_RANK, +}; + +struct _RuleEditorUndo { + struct _RuleEditorUndo *next; + + unsigned int type; + struct _FilterRule *rule; + int rank; + int newrank; +}; + struct _GladeXML; struct _RuleContext; |