ANNOUNCEMENT: Live Wireshark University & Allegro Packets online APAC Wireshark Training Session
July 17th, 2024 | 10:00am-11:55am SGT (UTC+8) | Online

Ethereal-dev: [Ethereal-dev] Phase two of color filters update

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Richard Urwin <richard@xxxxxxxxxxxxxxx>
Date: Thu, 14 Aug 2003 22:40:39 +0100
It's been a long time in coming, but here is phase two of the color 
filters update. Please check it in.

I am no tech writer, but I have scribbled something that might form the 
basis of a new user manual page. See color2.txt, which will also serve 
to describe the changes in detail.

Phase three will be copy-paste for colors between filters, but I'm not 
saying when. :-)

-- 
Richard Urwin
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/AUTHORS ethereal/AUTHORS
--- ethereal-0.9.14/AUTHORS	2003-07-23 03:05:35.000000000 +0100
+++ ethereal/AUTHORS	2003-08-14 22:14:53.000000000 +0100
@@ -1419,9 +1419,10 @@
 	    from the command line
 }
 
-Richard Urwin <rurwin[AT]schenck.co.uk> {
+Richard Urwin <richard[AT]soronlin.org.uk> {
 	Developer documentation fixes and updates
-	Support for a system-wide color filter file
+	Support for a system-wide color filter file and color filter
+	    import and export
 }
 
 Prabhakar Krishnan <Prabhakar.Krishnan[AT]netapp.com> {
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/color.h ethereal/color.h
--- ethereal-0.9.14/color.h	2002-09-25 02:52:55.000000000 +0100
+++ ethereal/color.h	2003-08-08 18:36:51.000000000 +0100
@@ -53,6 +53,7 @@
         dfilter_t *c_colorfilter; /* compiled filter expression */
         void      *edit_dialog;   /* if filter is being edited, dialog
                                    * box for it */
+	gboolean    marked;         /* set if the filter is marked in the color dialog box */
 } color_filter_t;
 
 /* List of all color filters. */
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/gtk/color_dlg.c ethereal/gtk/color_dlg.c
--- ethereal-0.9.14/gtk/color_dlg.c	2003-05-17 17:33:02.000000000 +0100
+++ ethereal/gtk/color_dlg.c	2003-08-14 21:53:41.000000000 +0100
@@ -44,6 +44,7 @@
 #include "ui_util.h"
 #include "dfilter_expr_dlg.h"
 #include "compat_macros.h"
+#include "file_dlg.h"
 
 static GtkWidget* colorize_dialog_new(void);
 static void add_filter_to_list(gpointer filter_arg, gpointer list_arg);
@@ -67,7 +68,7 @@
 static void color_cancel_cb(GtkWidget *widget, gpointer user_data);
 static void color_apply_cb(GtkButton *button, gpointer user_data);
 static void color_revert_cb(GtkWidget *button, gpointer user_data);
-
+static void color_import_cb(GtkButton *button, gpointer user_data );
 
 static void edit_color_filter_dialog_new(GtkWidget *color_filters,
                                          GtkWidget **colorize_filter_name,
@@ -123,6 +123,27 @@
   }
 }
 
+/* if this filter is marked count it in the given int* */
+static void
+count_this_mark(gpointer filter_arg, gpointer counter_arg)
+{
+  	color_filter_t *colorf = filter_arg;
+    int * cnt = counter_arg;
+
+    if (colorf->marked)
+      (*cnt)++;
+}
+
+/* TODO: implement count of selected filters. Plug in to file_dlg update of "export selected" checkbox. */
+int color_marked_count(void)
+{
+  int count = 0;
+
+  g_slist_foreach(filter_list, count_this_mark, &count);
+
+  return count;
+}
+
 /* Create the "Apply Color Filters" dialog. */
 static GtkWidget*
 colorize_dialog_new (void)
@@ -151,9 +172,14 @@
   GtkWidget *color_delete;
 
   GtkWidget *button_ok_hbox;
+  GtkWidget *importexport_vbox;
+  GtkWidget *okapply_vbox;
+  GtkWidget *saverevert_vbox;
   GtkWidget *color_ok;
   GtkWidget *color_apply;
   GtkWidget *color_save;
+  GtkWidget *color_export;
+  GtkWidget *color_import;
   GtkWidget *color_revert;
   GtkWidget *color_cancel;
 
@@ -236,6 +262,12 @@
   gtk_widget_show (list_vbox);
   gtk_container_add(GTK_CONTAINER(list_fr), list_vbox);
 
+  list_label = gtk_label_new (("[List is processed in order until match is found]"));
+  gtk_widget_ref (list_label);
+  OBJECT_SET_DATA_FULL(color_win, "list_label", list_label, gtk_widget_unref);
+  gtk_widget_show (list_label);
+  gtk_box_pack_start (GTK_BOX (list_vbox), list_label, FALSE, FALSE, 0);
+
   /* create the list of filters */
   scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
 #if GTK_MAJOR_VERSION >= 2
@@ -276,7 +308,9 @@
   g_slist_foreach(filter_list, add_filter_to_list, color_filters);
 #if GTK_MAJOR_VERSION >= 2
   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
-  gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+  gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+#else
+  gtk_clist_set_selection_mode    (GTK_CLIST (color_filters),GTK_SELECTION_EXTENDED);
 #endif
 
   gtk_widget_show (color_filters);
@@ -287,11 +321,6 @@
   gtk_clist_column_titles_show (GTK_CLIST (color_filters));
 #endif
 
-  list_label = gtk_label_new (("[List is processed in order until match is found]"));
-  gtk_widget_ref (list_label);
-  OBJECT_SET_DATA_FULL(color_win, "list_label", list_label, gtk_widget_unref);
-  gtk_widget_show (list_label);
-  gtk_box_pack_start (GTK_BOX (list_vbox), list_label, FALSE, FALSE, 0);
   /* end list_frame */
 
   /* edit buttons frame */
@@ -354,6 +383,12 @@
   gtk_widget_show (button_ok_hbox);
   gtk_box_pack_start (GTK_BOX (dlg_vbox), button_ok_hbox, FALSE, FALSE, 5);
 
+  okapply_vbox = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (okapply_vbox);
+  OBJECT_SET_DATA_FULL(color_win, "okapply_vbox", okapply_vbox, gtk_widget_unref);
+  gtk_widget_show (okapply_vbox);
+  gtk_box_pack_start (GTK_BOX (button_ok_hbox), okapply_vbox, TRUE, TRUE, 0);
+
 #if GTK_MAJOR_VERSION < 2
   color_ok = gtk_button_new_with_label (("OK"));
 #else
@@ -362,7 +397,7 @@
   gtk_widget_ref (color_ok);
   OBJECT_SET_DATA_FULL(color_win, "color_ok", color_ok, gtk_widget_unref);
   gtk_widget_show (color_ok);
-  gtk_box_pack_start (GTK_BOX (button_ok_hbox), color_ok, TRUE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (okapply_vbox), color_ok, FALSE, FALSE, 0);
   gtk_tooltips_set_tip (tooltips, color_ok, ("Accept filter list; apply changes"), NULL);
 
 #if GTK_MAJOR_VERSION < 2
@@ -373,9 +408,15 @@
   gtk_widget_ref (color_apply);
   OBJECT_SET_DATA_FULL(color_win, "color_apply", color_apply, gtk_widget_unref);
   gtk_widget_show (color_apply);
-  gtk_box_pack_start (GTK_BOX (button_ok_hbox), color_apply, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (okapply_vbox), color_apply, FALSE, FALSE, 0);
   gtk_tooltips_set_tip (tooltips, color_apply, ("Apply filters in list"), NULL);
 
+  saverevert_vbox = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (saverevert_vbox);
+  OBJECT_SET_DATA_FULL(color_win, "saverevert_vbox", saverevert_vbox, gtk_widget_unref);
+  gtk_widget_show (saverevert_vbox);
+  gtk_box_pack_start (GTK_BOX (button_ok_hbox), saverevert_vbox, TRUE, TRUE, 0);
+
 #if GTK_MAJOR_VERSION < 2
   color_save = gtk_button_new_with_label (("Save"));
 #else
@@ -384,7 +425,7 @@
   gtk_widget_ref(color_save);
   OBJECT_SET_DATA_FULL(color_win, "color_save", color_save, gtk_widget_unref);
   gtk_widget_show(color_save);
-  gtk_box_pack_start(GTK_BOX (button_ok_hbox), color_save, FALSE, FALSE, 5);
+  gtk_box_pack_start(GTK_BOX (saverevert_vbox), color_save, FALSE, FALSE, 0);
   gtk_tooltips_set_tip(tooltips, color_save, ("Save all filters to disk"), NULL);
 
 #if GTK_MAJOR_VERSION < 2
@@ -395,9 +436,35 @@
   gtk_widget_ref(color_revert);
   OBJECT_SET_DATA_FULL(color_win, "color_revert", color_revert, gtk_widget_unref);
   gtk_widget_show(color_revert);
-  gtk_box_pack_start(GTK_BOX (button_ok_hbox), color_revert, FALSE, FALSE, 5);
+  gtk_box_pack_start(GTK_BOX (saverevert_vbox), color_revert, FALSE, FALSE, 0);
   gtk_tooltips_set_tip(tooltips, color_revert, ("Delete filter file and revert to system-wide default filter set"), NULL);
 
+  importexport_vbox = gtk_vbox_new (FALSE, 0);
+  gtk_widget_ref (importexport_vbox);
+  OBJECT_SET_DATA_FULL(color_win, "importexport_vbox", importexport_vbox, gtk_widget_unref);
+  gtk_widget_show (importexport_vbox);
+  gtk_box_pack_start (GTK_BOX (button_ok_hbox), importexport_vbox, TRUE, TRUE, 0);
+
+#if GTK_MAJOR_VERSION < 2
+  color_export = gtk_button_new_with_label (("Export"));
+#else
+  color_export = gtk_button_new_from_stock(GTK_STOCK_SAVE_AS);
+#endif
+  gtk_widget_ref(color_export);
+  gtk_widget_show(color_export);
+  gtk_box_pack_start(GTK_BOX (importexport_vbox), color_export, FALSE, FALSE, 0);
+  gtk_tooltips_set_tip(tooltips, color_export, ("Save filters to specified file"), NULL);
+
+#if GTK_MAJOR_VERSION < 2
+  color_import = gtk_button_new_with_label (("Import"));
+#else
+  color_import = gtk_button_new_from_stock(GTK_STOCK_OPEN);
+#endif
+  gtk_widget_ref(color_import);
+  gtk_widget_show(color_import);
+  gtk_box_pack_start(GTK_BOX (importexport_vbox), color_import, FALSE, FALSE, 0);
+  gtk_tooltips_set_tip(tooltips, color_import, ("Load filters from specified file"), NULL);
+
 #if GTK_MAJOR_VERSION < 2
   color_cancel = gtk_button_new_with_label (("Cancel"));
 #else
@@ -433,8 +501,11 @@
   OBJECT_SET_DATA(color_delete, COLOR_FILTERS_CL, color_filters);
   SIGNAL_CONNECT(color_delete, "clicked", color_delete_cb, NULL);
   SIGNAL_CONNECT(color_save, "clicked", color_save_cb, NULL);
-  SIGNAL_CONNECT(color_revert, "clicked", color_revert_cb, NULL);
+  SIGNAL_CONNECT(color_export, "clicked", file_color_export_cmd_cb, NULL);
+  OBJECT_SET_DATA(color_import, COLOR_FILTERS_CL, color_filters);
+  SIGNAL_CONNECT(color_import, "clicked", color_import_cb, color_filters);
   OBJECT_SET_DATA(color_revert, COLOR_FILTERS_CL, color_filters);
+  SIGNAL_CONNECT(color_revert, "clicked", color_revert_cb, NULL);
   SIGNAL_CONNECT(color_ok, "clicked", color_ok_cb, NULL);
   SIGNAL_CONNECT(color_apply, "clicked", color_apply_cb, NULL);
   SIGNAL_CONNECT(color_cancel, "clicked", color_cancel_cb, NULL);
@@ -484,40 +554,55 @@
   num_of_filters++;
 }
 
-/* Move the selected filter up in the list */
-static void
-color_filter_up_cb(GtkButton *button, gpointer user_data _U_)
+void move_this_row (GtkWidget   *color_filters, 
+                     gint         filter_number,
+                     gint         amount)            /* only tested with +1(down) and -1(up) */
 {
-  gint            filter_number;
-  GtkWidget      *color_filters;
   color_filter_t *colorf;
-#if GTK_MAJOR_VERSION >= 2
+#if GTK_MAJOR_VERSION < 2
+  gint            lower, higher;
+#else
   GtkTreeModel   *model;
   GtkTreeIter     iter1, iter2;
   gchar          *name, *string, *fg_str, *bg_str;
 #endif
 
-  filter_number = row_selected;
-  g_assert(filter_number > 0);
+  g_assert(amount == +1 || amount == -1);
+  g_assert(amount == +1 || filter_number > 0);
+  g_assert(amount == -1 || filter_number < num_of_filters - 1);
 
-  color_filters = (GtkWidget *)OBJECT_GET_DATA(button, COLOR_FILTERS_CL);
 #if GTK_MAJOR_VERSION < 2
+  if (amount > 0)
+  {
+    lower = filter_number;
+    higher = filter_number + amount;
+  }
+  else
+  {
+    higher = filter_number;
+    lower = filter_number + amount;
+  }
+
   colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), filter_number);
-  gtk_clist_swap_rows(GTK_CLIST(color_filters), filter_number, filter_number-1);
+  gtk_clist_swap_rows(GTK_CLIST(color_filters), higher, lower);
 
   /*
-   * That row is still selected, but it's now row N-1.
+   * That row is still selected, but it's now moved.
    */
-  remember_selected_row(GTK_CLIST(color_filters), filter_number-1, 0, NULL,
-                        NULL);
+  remember_selected_row(GTK_CLIST(color_filters), filter_number + amount, 0, NULL, NULL);
 #else
+
   model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
-  gtk_tree_model_iter_nth_child(model, &iter1, NULL, row_selected);
-  gtk_tree_model_iter_nth_child(model, &iter2, NULL, row_selected-1);
+  gtk_tree_model_iter_nth_child(model, &iter1, NULL, filter_number);
+  gtk_tree_model_iter_nth_child(model, &iter2, NULL, filter_number + amount);
+  
   gtk_tree_model_get(model, &iter1, 0, &name, 1, &string,
                      2, &fg_str, 3, &bg_str, 4, &colorf, -1);
   gtk_list_store_remove(GTK_LIST_STORE(model), &iter1);
-  gtk_list_store_insert_before(GTK_LIST_STORE(model), &iter1, &iter2);
+  if (amount < 0)
+    gtk_list_store_insert_before(GTK_LIST_STORE(model), &iter1, &iter2);
+  else
+    gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter1, &iter2);
   gtk_list_store_set(GTK_LIST_STORE(model), &iter1, 0, name, 1, string,
                      2, fg_str, 3, bg_str, 4, colorf, -1);
   g_free(name);
@@ -530,64 +615,91 @@
    */
   gtk_widget_grab_focus(color_filters);
   gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters)), &iter1);
+  
 #endif
 
   filter_list = g_slist_remove(filter_list, colorf);
-  filter_list = g_slist_insert(filter_list, colorf, filter_number-1);
+  filter_list = g_slist_insert(filter_list, colorf, filter_number + amount);
 }
 
-/* Move the selected filter down in the list */
+/* Move the selected filters up in the list */
 static void
-color_filter_down_cb(GtkButton *button, gpointer user_data _U_)
+color_filter_up_cb(GtkButton *button, gpointer user_data _U_)
 {
-  gint            filter_number;
-  GtkWidget      *color_filters;
+  gint amount;
+  gint filter_number;
+  GtkWidget * color_filters;
   color_filter_t *colorf;
-#if GTK_MAJOR_VERSION >= 2
-  GtkTreeModel   *model;
-  GtkTreeIter     iter1, iter2;
-  gchar          *name, *string, *fg_str, *bg_str;
+#if GTK_MAJOR_VERSION < 2
+#else
+  GtkTreeIter       iter;
+  GtkTreeModel     *model;
+  GtkTreeSelection *sel;
 #endif
 
-  filter_number = row_selected;
-  g_assert(filter_number < num_of_filters - 1);
-
+  amount = -1;
   color_filters = (GtkWidget *)OBJECT_GET_DATA(button, COLOR_FILTERS_CL);
+
 #if GTK_MAJOR_VERSION < 2
-  colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), filter_number);
-  gtk_clist_swap_rows(GTK_CLIST(color_filters), filter_number+1, filter_number);
+    colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), 0);
+    if (colorf->marked)
+      return;
+#endif
 
-  /*
-   * That row is still selected, but it's now row N+1.
-   */
-  remember_selected_row(GTK_CLIST(color_filters), filter_number+1, 0, NULL,
-      NULL);
+  for (filter_number = 0; filter_number < num_of_filters; filter_number++)
+  {
+#if GTK_MAJOR_VERSION < 2
+    colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), filter_number);
+    if (colorf->marked)
+      move_this_row (color_filters, filter_number, amount);
 #else
-  model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
-  gtk_tree_model_iter_nth_child(model, &iter1, NULL, row_selected);
-  gtk_tree_model_iter_nth_child(model, &iter2, NULL, row_selected+1);
-  gtk_tree_model_get(model, &iter1, 0, &name, 1, &string,
-                     2, &fg_str, 3, &bg_str, 4, &colorf, -1);
-  gtk_list_store_remove(GTK_LIST_STORE(model), &iter1);
-  gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter1, &iter2);
-  gtk_list_store_set(GTK_LIST_STORE(model), &iter1, 0, name, 1, string,
-                     2, fg_str, 3, bg_str, 4, colorf, -1);
-  g_free(name);
-  g_free(string);
-  g_free(fg_str);
-  g_free(bg_str);
+    model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
+    gtk_tree_model_iter_nth_child(model, &iter, NULL, filter_number);
+    gtk_tree_model_get(model, &iter, 4, &colorf, -1);
+    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
+    if (gtk_tree_selection_iter_is_selected(sel, &iter))
+      move_this_row (color_filters, filter_number, amount);
+#endif
+  }
+}
 
-  /*
-   * re-select the initial row
-   */
-  gtk_widget_grab_focus(color_filters);
-  gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters)), &iter1);
+/* Move the selected filters down in the list */
+static void
+color_filter_down_cb(GtkButton *button, gpointer user_data _U_)
+{
+  gint amount;
+  gint filter_number;
+  GtkWidget * color_filters;
+  color_filter_t *colorf;
+#if GTK_MAJOR_VERSION < 2
+#else
+  GtkTreeIter     iter;
+  GtkTreeModel   *model;
 #endif
 
-  filter_list = g_slist_remove(filter_list, colorf);
-  filter_list = g_slist_insert(filter_list, colorf, filter_number+1);
-}
+  amount = +1;
+  color_filters = (GtkWidget *)OBJECT_GET_DATA(button, COLOR_FILTERS_CL);
+
+#if GTK_MAJOR_VERSION < 2
+    colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), num_of_filters - 1);
+    if (colorf->marked)
+      return;
+#endif
 
+  for (filter_number = num_of_filters - 1; filter_number >= 0; filter_number--)
+  {
+#if GTK_MAJOR_VERSION < 2
+    colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), filter_number);
+#else
+    model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
+    gtk_tree_model_iter_nth_child(model, &iter, NULL, filter_number);
+    gtk_tree_model_get(model, &iter, 4, &colorf, -1);
+#endif
+    if (colorf->marked)
+      move_this_row (color_filters, filter_number, amount);
+  }
+}
+ 
 /* A row was selected; remember its row number */
 #if GTK_MAJOR_VERSION < 2
 static void
@@ -595,9 +707,13 @@
                       GdkEvent *event _U_, gpointer user_data _U_)
 {
     GtkWidget    *button;
+    color_filter_t *colorf;
 
     row_selected = row;
 
+    colorf = gtk_clist_get_row_data(clist, row);
+    colorf->marked = TRUE;
+    
     /*
      * A row is selected, so we can move it up *if* it's not at the top
      * and move it down *if* it's not at the bottom.
@@ -614,58 +730,111 @@
     gtk_widget_set_sensitive (button, TRUE);
     button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_DELETE_LB);
     gtk_widget_set_sensitive(button, TRUE);
+    
 }
 #else
+
+struct remember_data
+{
+    gint count;               /* count of selected filters */
+    gboolean first_marked;    /* true if the first filter in the list is marked */
+    gboolean last_marked;     /* true if the last filter in the list is marked */
+    gpointer color_filters;
+};
+/* called for each selected row in the tree. The first call is detected and does
+the stuff that only needs to be done once. If we are never called the visited
+variable stays false and means that no rows are selected.
+*/
+void remember_this_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer arg)
+{
+    GtkWidget    *button;
+    gchar        *path_str;
+    color_filter_t *colorf;
+    struct remember_data *data = arg;
+    
+    gtk_tree_model_get(model, iter, 4, &colorf, -1);
+    colorf->marked = TRUE;
+        
+    path_str = gtk_tree_path_to_string(path);
+    row_selected = atoi(path_str);
+    g_free(path_str);
+
+    /*
+     * A row is selected, so we can move it up *if* it's not at the top
+     * and move it down *if* it's not at the bottom.
+     */
+    button = (GtkWidget *)OBJECT_GET_DATA(data->color_filters, COLOR_UP_LB);
+    gtk_widget_set_sensitive(button, row_selected > 0);
+    if (row_selected == 0)
+      data->first_marked = TRUE;
+    if (row_selected == num_of_filters - 1)
+      data->last_marked = TRUE;
+
+    data->count++;
+}
+
+/* clear the mark on this filter */
+static void
+clear_mark(gpointer filter_arg, gpointer arg _U_)
+{
+  	color_filter_t *colorf = filter_arg;
+
+    colorf->marked = FALSE;
+}
+
+/* The gtk+2.0 version gets called for, (maybe multiple,) changes in the selection. */
 static void
 remember_selected_row(GtkTreeSelection *sel, gpointer color_filters)
 {
     GtkWidget    *button;
-    GtkTreeModel *model;
-    GtkTreeIter   iter;
-    GtkTreePath  *path;
-    gchar        *path_str;
+    struct remember_data data;
+    
+    data.first_marked = data.last_marked = FALSE;
+    data.count = 0; 
+    data.color_filters = color_filters;
+    
 
-    if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-        path = gtk_tree_model_get_path(model, &iter);
-        path_str = gtk_tree_path_to_string(path);
-        row_selected = atoi(path_str);
-        g_free(path_str);
-        gtk_tree_path_free(path);
-
-        /*
-         * A row is selected, so we can move it up *if* it's not at the top
-         * and move it down *if* it's not at the bottom.
-         */
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_UP_LB);
-        gtk_widget_set_sensitive(button, row_selected > 0);
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DOWN_LB);
-        gtk_widget_set_sensitive(button, row_selected < num_of_filters - 1);
-
-        /*
-         * A row is selected, so we can operate on it.
-         */
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_EDIT_LB);
-        gtk_widget_set_sensitive (button, TRUE);
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DELETE_LB);
-        gtk_widget_set_sensitive (button, TRUE);
+    g_slist_foreach(filter_list, clear_mark, NULL);
+    gtk_tree_selection_selected_foreach(sel,remember_this_row, &data);
+                                      
+    if (data.count > 0)
+    {
+      /*
+       * One or more rows are selected, so we can operate on them.
+      */
+       
+      /* We can only edit if there is exactly one filter selected */
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_EDIT_LB);
+      gtk_widget_set_sensitive (button, data.count == 1);
+      
+      /* We can delete any number of filters */
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DELETE_LB);
+      gtk_widget_set_sensitive (button, TRUE);
+      /*
+       * We can move them up *if* one of them isn't the top row,
+       * and move them down *if* one of them isn't the bottom row.
+      */
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_UP_LB);
+      gtk_widget_set_sensitive(button, !data.first_marked);
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DOWN_LB);
+      gtk_widget_set_sensitive(button, !data.last_marked);
     }
-    /* A row was unselected; un-remember its row number */
     else
     {
-        row_selected = -1;
+      row_selected = -1;
 
-        /*
-         * No row is selected, so we can't do operations that affect the
-         * selected row.
-         */
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_UP_LB);
-        gtk_widget_set_sensitive (button, FALSE);
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DOWN_LB);
-        gtk_widget_set_sensitive (button, FALSE);
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_EDIT_LB);
-        gtk_widget_set_sensitive (button, FALSE);
-        button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DELETE_LB);
-        gtk_widget_set_sensitive (button, FALSE);
+      /*
+       * No row is selected, so we can't do operations that affect the
+       * selected row.
+      */
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_UP_LB);
+      gtk_widget_set_sensitive (button, FALSE);
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DOWN_LB);
+      gtk_widget_set_sensitive (button, FALSE);
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_EDIT_LB);
+      gtk_widget_set_sensitive (button, FALSE);
+      button = (GtkWidget *)OBJECT_GET_DATA(color_filters, COLOR_DELETE_LB);
+      gtk_widget_set_sensitive (button, FALSE);
     }
 }
 #endif
@@ -680,21 +849,28 @@
                                          gpointer         user_data _U_)
 {
   GtkWidget *button;
+  color_filter_t *colorf;
 
   row_selected = -1;
 
-  /*
-   * No row is selected, so we can't do operations that affect the
-   * selected row.
-   */
-  button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_UP_LB);
-  gtk_widget_set_sensitive (button, FALSE);
-  button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_DOWN_LB);
-  gtk_widget_set_sensitive (button, FALSE);
-  button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_EDIT_LB);
-  gtk_widget_set_sensitive (button, FALSE);
-  button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_DELETE_LB);
-  gtk_widget_set_sensitive(button, FALSE);
+  colorf = gtk_clist_get_row_data(clist, row);
+  colorf->marked = FALSE;
+
+  if (color_marked_count() == 0)
+  {
+    /*
+     * No row is selected, so we can't do operations that affect the
+     * selected row.
+     */
+    button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_UP_LB);
+    gtk_widget_set_sensitive (button, FALSE);
+    button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_DOWN_LB);
+    gtk_widget_set_sensitive (button, FALSE);
+    button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_EDIT_LB);
+    gtk_widget_set_sensitive (button, FALSE);
+    button = (GtkWidget *)OBJECT_GET_DATA(clist, COLOR_DELETE_LB);
+    gtk_widget_set_sensitive(button, FALSE);
+  }
 }
 #endif
 
@@ -726,16 +902,10 @@
 static GtkWidget *filt_name_entry;
 static GtkWidget *filt_text_entry;
 
-/* Create a new filter in the list, and pop up an "Edit color filter"
-   dialog box to edit it. */
 static void
-color_new_cb(GtkButton *button, gpointer user_data _U_)
+color_add_colorf(GtkWidget *color_filters, color_filter_t *colorf)
 {
-  color_filter_t   *colorf;
-  GtkWidget        *color_filters;
 #if GTK_MAJOR_VERSION < 2
-  gchar            *data[2];
-  gint              row;
 #else
   GtkTreeModel     *model;
   gint              num_filters;
@@ -743,31 +913,82 @@
   GtkTreeSelection *sel;
 #endif
 
-  colorf = new_color_filter("name", "filter"); /* Adds at end! */
+  add_filter_to_list(colorf, color_filters);
 
-  color_filters = (GtkWidget *)OBJECT_GET_DATA(button, COLOR_FILTERS_CL);
 #if GTK_MAJOR_VERSION < 2
-  data[0] = colorf->filter_name;
-  data[1] = colorf->filter_text;
-  row = gtk_clist_append(GTK_CLIST(color_filters), data);
-  gtk_clist_set_row_data(GTK_CLIST(color_filters), row, colorf);
-  num_of_filters++;
 
   /* select the new row */
-  gtk_clist_select_row(GTK_CLIST(color_filters), row, -1);
-  edit_color_filter_dialog_new(color_filters, &filt_name_entry,
-                               &filt_text_entry);
+  gtk_clist_select_row(GTK_CLIST(color_filters), num_of_filters - 1, -1);
 #else
-  add_filter_to_list(colorf, color_filters);
-
   /* select the new row */
   model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
   num_filters = gtk_tree_model_iter_n_children(model, NULL);
   gtk_tree_model_iter_nth_child(model, &iter, NULL, num_filters - 1);
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
   gtk_tree_selection_select_iter(sel, &iter);
+#endif
+}
+
+void
+color_add_filter_cb (color_filter_t *colorf, gpointer arg)
+{
+  GtkWidget        *color_filters = arg;
+
+  color_add_colorf(color_filters, colorf);
+#if GTK_MAJOR_VERSION >= 2
+  gtk_widget_grab_focus(color_filters);
+#endif
+}
+
+/* Pop up an "Export color filter" dialog box. */
+static void
+color_import_cb(GtkButton *button, gpointer user_data )
+{
+  GtkWidget        *color_filters;
+#if GTK_MAJOR_VERSION >= 2
+  GtkTreeSelection *sel;
+#endif
+
+  color_filters = (GtkWidget *)OBJECT_GET_DATA(button, COLOR_FILTERS_CL);
+
+#if GTK_MAJOR_VERSION >= 2
+  sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
+  gtk_tree_selection_unselect_all (sel);
+#else
+  gtk_clist_unselect_all (GTK_CLIST(color_filters));
+#endif
+
+  file_color_import_cmd_cb(GTK_WIDGET(button), user_data);
+}
+
+/* Create a new filter in the list, and pop up an "Edit color filter"
+   dialog box to edit it. */
+static void
+color_new_cb(GtkButton *button, gpointer user_data _U_)
+{
+  color_filter_t   *colorf;
+  GtkWidget        *color_filters;
+#if GTK_MAJOR_VERSION >= 2
+  GtkTreeSelection *sel;
+#endif
+
+  color_filters = (GtkWidget *)OBJECT_GET_DATA(button, COLOR_FILTERS_CL);
+
+#if GTK_MAJOR_VERSION >= 2
+  sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
+  gtk_tree_selection_unselect_all (sel);
+#else
+  gtk_clist_unselect_all (GTK_CLIST(color_filters));
+#endif
+
+  colorf = new_color_filter("name", "filter"); /* Adds at end! */
+
+  color_add_colorf(color_filters, colorf);
+
   edit_color_filter_dialog_new(color_filters, &filt_name_entry,
                                &filt_text_entry);
+  
+#if GTK_MAJOR_VERSION >= 2
   gtk_widget_grab_focus(color_filters);
 #endif
 }
@@ -793,8 +1014,6 @@
 #if GTK_MAJOR_VERSION >= 2
     GtkTreeModel     *model;
     GtkTreeIter       iter;
-    gint              rowsel;
-    GtkTreeSelection *sel;
 
     
     /* The "selection changed" callback is called when the row is
@@ -819,16 +1038,6 @@
     * row is always selected, so we do it before */
     gtk_widget_grab_focus(color_filters);
     /* Update the selection */
-    if (row_selected <= (num_of_filters-1)) {
-        sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
-        gtk_tree_model_iter_nth_child(model, &iter, NULL, row_selected);
-        gtk_tree_selection_select_iter(sel, &iter);
-    }
-    else if (num_of_filters > 0) {
-        sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
-        gtk_tree_model_iter_nth_child(model, &iter, NULL, num_of_filters-1);
-        gtk_tree_selection_select_iter(sel, &iter);
-    }
 #else
    colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), row);
 
@@ -844,24 +1053,44 @@
     /* Remove the color filter from the list of color filters. */
     delete_color_filter(colorf);
 
-    /* Select the previous row, if there is one. */
-    if (row <= row_selected && row_selected > 0) {
-        row_selected--;
-        gtk_clist_select_row(GTK_CLIST(color_filters), row_selected, 0);
-    }
 #endif
 }
 /* Delete the selected color from the list.*/
 static void
 color_delete_cb(GtkWidget *widget, gpointer user_data _U_)
 {
-    GtkWidget  *color_filters;
+  GtkWidget  *color_filters;
+  gint row, num_filters;
+#if GTK_MAJOR_VERSION < 2
+  color_filter_t *colorf;
+#else
+    GtkTreeModel     *model;
+    GtkTreeIter       iter;
+    GtkTreeSelection *sel;
+#endif
+
+  color_filters = (GtkWidget *)OBJECT_GET_DATA(widget, COLOR_FILTERS_CL);
     
-    if(row_selected != -1)
-    {
-        color_filters = (GtkWidget *)OBJECT_GET_DATA(widget, COLOR_FILTERS_CL);
-        color_delete (row_selected, color_filters);
-    }
+#if GTK_MAJOR_VERSION < 2
+  num_filters = num_of_filters;
+#else
+  model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
+  num_filters = gtk_tree_model_iter_n_children(model, NULL);
+  sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
+#endif
+
+  for (row = num_filters - 1; row >= 0; row--)
+  {
+#if GTK_MAJOR_VERSION < 2
+    colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), row);
+    if (colorf->marked)
+      color_delete (row, color_filters);
+#else
+    gtk_tree_model_iter_nth_child(model, &iter, NULL, row);
+    if (gtk_tree_selection_iter_is_selected(sel, &iter))
+      color_delete (row, color_filters);
+#endif
+  }
 }
 
 /* Save color filters to the color filter file. */
@@ -957,15 +1186,16 @@
     GtkWidget *edit_color_filter_cancel;
 
 #if GTK_MAJOR_VERSION >= 2
-    GtkTreeSelection *sel;
     GtkTreeModel     *model;
     GtkTreeIter       iter;
+#endif
 
-    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
-    /* should never happen */
-    if (!gtk_tree_selection_get_selected(sel, &model, &iter))
-        return;
+#if GTK_MAJOR_VERSION >= 2
+    model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
+
+    gtk_tree_model_iter_nth_child(model, &iter, NULL, row_selected);
     gtk_tree_model_get(model, &iter, 4, &colorf, -1);
+
 #else
     colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters), row_selected);
 #endif
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/gtk/color_dlg.h ethereal/gtk/color_dlg.h
--- ethereal-0.9.14/gtk/color_dlg.h	2002-08-29 01:40:08.000000000 +0100
+++ ethereal/gtk/color_dlg.h	2003-08-13 21:52:17.000000000 +0100
@@ -27,5 +27,6 @@
 #define __COLOR_DLG_H__
 
 void color_display_cb(GtkWidget *w, gpointer d);
-
+int color_marked_count(void);
+void color_add_filter_cb (color_filter_t *colorf, gpointer arg);
 #endif /* color_dlg.h */
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/gtk/color_filters.c ethereal/gtk/color_filters.c
--- ethereal-0.9.14/gtk/color_filters.c	2003-05-17 17:33:02.000000000 +0100
+++ ethereal/gtk/color_filters.c	2003-08-14 20:56:33.000000000 +0100
@@ -39,6 +39,7 @@
 #include "colors.h"
 #include "color_filters.h"
 #include "color_utils.h"
+#include "color_dlg.h"
 #include "file.h"
 #include <epan/dfilter/dfilter.h>
 #include "simple_dialog.h"
@@ -105,6 +106,7 @@
 	gdkcolor_to_color_t(&colorf->fg_color, &style->text[GTK_STATE_NORMAL]);
 	colorf->c_colorfilter = NULL;
 	colorf->edit_dialog = NULL;
+  colorf->marked = FALSE;
 	filter_list = g_slist_append(filter_list, colorf);
         return colorf;
 }
@@ -131,7 +133,7 @@
 
 /* read filters from the given file */
 static gboolean
-read_filters_file(gpointer file_arg)
+read_filters_file(FILE *f, gpointer arg)
 {
 	/* TODO: Lots more syntax checking on the file */
 	/* I hate these fixed length names! TODO: make more dynamic */
@@ -143,7 +145,6 @@
 	GdkColor fg_color, bg_color;
 	color_filter_t *colorf;
 	dfilter_t *temp_dfilter;
-	FILE *f = file_arg;
 
 	do {
 		if (fgets(buf,sizeof buf, f) == NULL)
@@ -194,10 +193,14 @@
 			bg_color.red = bg_r;
 			bg_color.green = bg_g;
 			bg_color.blue = bg_b;
-
+      
 			gdkcolor_to_color_t(&colorf->bg_color, &bg_color);
 			gdkcolor_to_color_t(&colorf->fg_color, &fg_color);
-		}    /* if sscanf */
+
+      if (arg != NULL)
+        color_add_filter_cb (colorf, arg);
+
+    }    /* if sscanf */
 	} while(!feof(f));
 	fclose(f);
 	return TRUE;
@@ -228,7 +231,7 @@
 	g_free((gchar *)path);
 	path = NULL;
 
-	return read_filters_file(f);
+	return read_filters_file(f, NULL);
 }
 
 /* read filters from the filter file */
@@ -252,32 +255,65 @@
 	g_free((gchar *)path);
 	path = NULL;
 
-	return read_filters_file(f);
+	return read_filters_file(f, NULL);
 }
 
+/* save filters in some other filter file */
+
+gboolean
+read_other_filters(gchar *path, gpointer arg)
+{
+	FILE *f;
+
+	if ((f = fopen(path, "r")) == NULL) {
+		simple_dialog(ESD_TYPE_CRIT, NULL,
+		    "Could not open\n%s\nfor reading: %s.",
+		    path, strerror(errno));
+		return FALSE;
+	}
+
+	read_filters_file(f, arg);
+	fclose(f);
+	return TRUE;
+}
+
+struct write_filter_data
+{
+  FILE * f;
+  gboolean only_marked;
+};
+
 static void
-write_filter(gpointer filter_arg, gpointer file_arg)
+write_filter(gpointer filter_arg, gpointer data_arg)
 {
+  struct write_filter_data *data = data_arg;
 	color_filter_t *colorf = filter_arg;
-	FILE *f = file_arg;
+	FILE *f = data->f;
 
-	fprintf(f,"@%s@%s@[%d,%d,%d][%d,%d,%d]\n",
-	    colorf->filter_name,
-	    colorf->filter_text,
-	    colorf->bg_color.red,
-	    colorf->bg_color.green,
-	    colorf->bg_color.blue,
-	    colorf->fg_color.red,
-	    colorf->fg_color.green,
-	    colorf->fg_color.blue);
+  if (colorf->marked || !data->only_marked)
+  {
+    fprintf(f,"@%s@%s@[%d,%d,%d][%d,%d,%d]\n",
+        colorf->filter_name,
+        colorf->filter_text,
+        colorf->bg_color.red,
+        colorf->bg_color.green,
+        colorf->bg_color.blue,
+        colorf->fg_color.red,
+        colorf->fg_color.green,
+        colorf->fg_color.blue);
+  }
 }
 
 /* save filters in a filter file */
 gboolean
-write_filters_file(FILE *f)
+write_filters_file(FILE *f, gboolean only_marked)
 {
+  struct write_filter_data data;
+  data.f = f;
+  data.only_marked = only_marked;
+  
 	fprintf(f,"# DO NOT EDIT THIS FILE!  It was created by Ethereal\n");
-        g_slist_foreach(filter_list, write_filter, f);
+        g_slist_foreach(filter_list, write_filter, &data);
 	return TRUE;
 }
 
@@ -307,7 +343,7 @@
 		    path, strerror(errno));
 		return FALSE;
 	}
-	write_filters_file(f);
+	write_filters_file(f, FALSE);
 	fclose(f);
 	return TRUE;
 }
@@ -343,7 +379,7 @@
 /* save filters in some other filter file */
 
 gboolean
-write_other_filters(gchar *path)
+write_other_filters(gchar *path, gboolean only_marked)
 {
 	FILE *f;
 
@@ -353,7 +389,7 @@
 		    path, strerror(errno));
 		return FALSE;
 	}
-	write_filters_file(f);
+	write_filters_file(f, only_marked);
 	fclose(f);
 	return TRUE;
 }
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/gtk/color_filters.h ethereal/gtk/color_filters.h
--- ethereal-0.9.14/gtk/color_filters.h	2003-05-17 17:33:02.000000000 +0100
+++ ethereal/gtk/color_filters.h	2003-08-13 21:29:35.000000000 +0100
@@ -38,5 +38,6 @@
 
 color_filter_t *new_color_filter(gchar *name, gchar *filter_string);
 void delete_color_filter(color_filter_t *colorf);
-gboolean write_other_filters(gchar *path);
+gboolean read_other_filters(gchar *path, gpointer arg);
+gboolean write_other_filters(gchar *path, gboolean only_marked);
 #endif
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/gtk/file_dlg.c ethereal/gtk/file_dlg.c
--- ethereal-0.9.14/gtk/file_dlg.c	2003-07-22 04:14:30.000000000 +0100
+++ ethereal/gtk/file_dlg.c	2003-08-14 21:58:49.000000000 +0100
@@ -43,17 +43,26 @@
 #include "main.h"
 #include "compat_macros.h"
 #include "prefs.h"
+#include "color.h"
+#include "gtk/color_filters.h"
+#include "gtk/color_dlg.h"
 
 static void file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs);
 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
 static void select_file_type_cb(GtkWidget *w, gpointer data);
 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
+static void file_color_import_ok_cb(GtkWidget *w, GtkFileSelection *fs);
+static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
+static void file_color_export_ok_cb(GtkWidget *w, GtkFileSelection *fs);
+static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
 
 #define E_FILE_M_RESOLVE_KEY	  "file_dlg_mac_resolve_key"
 #define E_FILE_N_RESOLVE_KEY	  "file_dlg_network_resolve_key"
 #define E_FILE_T_RESOLVE_KEY	  "file_dlg_transport_resolve_key"
 
+#define ARGUMENT_CL "argument_cl"
+
 /*
  * Keep a static pointer to the current "Open Capture File" window, if
  * any, so that if somebody tries to do "File:Open" while there's already
@@ -301,9 +310,11 @@
 /* XXX - can we make these not be static? */
 static gboolean filtered;
 static gboolean marked;
+static gboolean color_marked;
 static int filetype;
 static GtkWidget *filter_cb;
 static GtkWidget *mark_cb;
+static GtkWidget *cfmark_cb;
 static GtkWidget *ft_om;
 
 static gboolean
@@ -661,3 +672,295 @@
      we should free up our copy. */
   g_free(filename);
 }
+
+/******************** Color Filters *********************************/
+/*
+ * Keep a static pointer to the current "Color Export" window, if
+ * any, so that if somebody tries to do "Export"
+ * while there's already a "Color Export" window up, we just pop
+ * up the existing one, rather than creating a new one.
+ */
+static GtkWidget *file_color_import_w;
+
+/* sets the file path to the global color filter file.
+   WARNING: called by both the import and the export dialog.
+*/
+static void
+color_global_cb(GtkWidget *widget _U_, gpointer data)
+{
+  GtkWidget *fs_widget = data;
+  
+	gchar *path;
+
+	/* decide what file to open (from dfilter code) */
+	path = get_datafile_path("colorfilters");
+
+  gtk_file_selection_set_filename (GTK_FILE_SELECTION(fs_widget), path);
+
+  g_free((gchar *)path);
+}
+
+/* Import color filters */
+void
+file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
+{
+  GtkWidget	*main_vb, *cfglobal_but;
+#if GTK_MAJOR_VERSION < 2
+  GtkAccelGroup *accel_group;
+#endif
+  /* No Apply button, and "OK" just sets our text widget, it doesn't
+     activate it (i.e., it doesn't cause us to try to open the file). */
+
+  if (file_color_import_w != NULL) {
+    /* There's already an "Import Color Filters" dialog box; reactivate it. */
+    reactivate_window(file_color_import_w);
+    return;
+  }
+
+  file_color_import_w = gtk_file_selection_new ("Ethereal: Import Color Filters");
+  SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
+
+#if GTK_MAJOR_VERSION < 2
+  /* Accelerator group for the accelerators (or, as they're called in
+     Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
+     Ctrl+<key> is an accelerator). */
+  accel_group = gtk_accel_group_new();
+  gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
+#endif
+
+  /* If we've opened a file, start out by showing the files in the directory
+     in which that file resided. */
+  if (last_open_dir)
+    gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_import_w), last_open_dir);
+
+  /* Container for each row of widgets */
+  main_vb = gtk_vbox_new(FALSE, 3);
+  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+  gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_import_w)->action_area),
+    main_vb, FALSE, FALSE, 0);
+  gtk_widget_show(main_vb);
+
+
+  cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
+  gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
+  SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
+  gtk_widget_show(cfglobal_but);
+
+  /* Connect the ok_button to file_open_ok_cb function and pass along a
+     pointer to the file selection box widget */
+  SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
+                 file_color_import_ok_cb, file_color_import_w);
+
+  OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
+                  ARGUMENT_CL, data);
+
+  /* Connect the cancel_button to destroy the widget */
+  SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_import_w)->cancel_button,
+                        "clicked", (GtkSignalFunc)gtk_widget_destroy,
+                        file_color_import_w);
+
+  /* Catch the "key_press_event" signal in the window, so that we can catch
+     the ESC key being pressed and act as if the "Cancel" button had
+     been selected. */
+  dlg_set_cancel(file_color_import_w, GTK_FILE_SELECTION(file_color_import_w)->cancel_button);
+
+  gtk_widget_show(file_color_import_w);
+}
+
+static void
+file_color_import_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
+  gchar     *cf_name, *s;
+  gpointer  argument;
+
+  argument = OBJECT_GET_DATA(w, ARGUMENT_CL);     /* to be passed back into read_other_filters */
+  
+  cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
+  /* Perhaps the user specified a directory instead of a file.
+     Check whether they did. */
+  if (test_for_directory(cf_name) == EISDIR) {
+	/* It's a directory - set the file selection box to display that
+	   directory, don't try to open the directory as a capture file. */
+	set_last_open_dir(cf_name);
+        g_free(cf_name);
+	gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
+    	return;
+  }
+
+  /* Try to open the capture file. */
+
+  if (!read_other_filters(cf_name, argument)) {
+    /* We couldn't open it; don't dismiss the open dialog box,
+       just leave it around so that the user can, after they
+       dismiss the alert box popped up for the open error,
+       try again. */
+    g_free(cf_name);
+    return;
+  }
+
+  /* We've crossed the Rubicon; get rid of the file selection box. */
+  gtk_widget_hide(GTK_WIDGET (fs));
+  gtk_widget_destroy(GTK_WIDGET (fs));
+
+  /* Save the name of the containing directory specified in the path name,
+     if any; we can write over cf_name, which is a good thing, given that
+     "get_dirname()" does write over its argument. */
+  s = get_dirname(cf_name);
+  set_last_open_dir(s);
+  gtk_widget_grab_focus(packet_list);
+
+  g_free(cf_name);
+}
+
+static void
+file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+  /* Note that we no longer have a "Open Capture File" dialog box. */
+  file_color_import_w = NULL;
+}
+
+static GtkWidget *file_color_export_w;
+/*
+ * Set the "Export only marked filters" toggle button as appropriate for
+ * the current output file type and count of marked filters.
+ *
+ * Called when the "Export" dialog box is created and when the marked
+ * count changes.
+ */
+void
+color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
+{
+  if (file_color_export_w == NULL) {
+    /* We don't currently have an "Export" dialog box up. */
+    return;
+  }
+
+  /* We can request that only the marked filters be saved only if
+        there *are* marked filters. */
+  if (color_marked_count() != 0)
+    gtk_widget_set_sensitive(cfmark_cb, TRUE);
+  else {
+    /* Force the "Export only marked filters" toggle to "false", turn
+       off the flag it controls. */
+    color_marked = FALSE;
+    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
+    gtk_widget_set_sensitive(cfmark_cb, FALSE);
+  }
+}
+
+static void
+color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
+{
+  color_marked = GTK_TOGGLE_BUTTON (widget)->active;
+}
+
+void
+file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
+{
+  GtkWidget *ok_bt, *main_vb, *cfglobal_but;
+
+  if (file_color_export_w != NULL) {
+    /* There's already an "Color Filter Export" dialog box; reactivate it. */
+    reactivate_window(file_color_export_w);
+    return;
+  }
+
+  /* Default to saving all packets, in the file's current format. */
+  filtered = FALSE;
+  color_marked   = FALSE;
+  filetype = cfile.cd_t;
+
+  file_color_export_w = gtk_file_selection_new ("Ethereal: Export Color Filters");
+  SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
+
+  /* If we've opened a file, start out by showing the files in the directory
+     in which that file resided. */
+  if (last_open_dir)
+    gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), last_open_dir);
+
+  /* Connect the ok_button to file_export_ok_cb function and pass along a
+     pointer to the file selection box widget */
+  ok_bt = GTK_FILE_SELECTION (file_color_export_w)->ok_button;
+  SIGNAL_CONNECT(ok_bt, "clicked", file_color_export_ok_cb, file_color_export_w);
+
+  /* Container for each row of widgets */
+  main_vb = gtk_vbox_new(FALSE, 3);
+  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+  gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_export_w)->action_area),
+    main_vb, FALSE, FALSE, 0);
+  gtk_widget_show(main_vb);
+
+  cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
+  gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
+  SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
+  gtk_widget_show(cfmark_cb);
+  color_set_export_marked_sensitive(cfmark_cb);
+
+  cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
+  gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
+  SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
+  gtk_widget_show(cfglobal_but);
+
+  /* Connect the cancel_button to destroy the widget */
+  SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_export_w)->cancel_button,
+                        "clicked", (GtkSignalFunc)gtk_widget_destroy,
+                        file_color_export_w);
+
+  /* Catch the "key_press_event" signal in the window, so that we can catch
+     the ESC key being pressed and act as if the "Cancel" button had
+     been selected. */
+  dlg_set_cancel(file_color_export_w, GTK_FILE_SELECTION(file_color_export_w)->cancel_button);
+
+  gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
+
+  gtk_widget_show(file_color_export_w);
+}
+
+static void
+file_color_export_ok_cb(GtkWidget *w _U_, GtkFileSelection *fs) {
+  gchar	*cf_name;
+  gchar	*dirname;
+
+  cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
+
+  /* Perhaps the user specified a directory instead of a file.
+     Check whether they did. */
+  if (test_for_directory(cf_name) == EISDIR) {
+        /* It's a directory - set the file selection box to display that
+           directory, and leave the selection box displayed. */
+        set_last_open_dir(cf_name);
+        g_free(cf_name);
+        gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
+        return;
+  }
+
+  /* Write out the filters (all, or only the ones that are currently
+     displayed or marked) to the file with the specified name. */
+
+   if (!write_other_filters(cf_name, color_marked))
+   {
+    /* The write failed; don't dismiss the open dialog box,
+       just leave it around so that the user can, after they
+       dismiss the alert box popped up for the error, try again. */
+
+       g_free(cf_name);
+       return;
+   }
+
+  /* The write succeeded; get rid of the file selection box. */
+  gtk_widget_hide(GTK_WIDGET (fs));
+  gtk_widget_destroy(GTK_WIDGET (fs));
+
+  /* Save the directory name for future file dialogs. */
+  dirname = get_dirname(cf_name);  /* Overwrites cf_name */
+  set_last_open_dir(dirname);
+  g_free(cf_name);
+}
+
+static void
+file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+  file_color_export_w = NULL;
+}
+
+
diff -Bur --ignore-matching-lines=: --exclude='*.o' --exclude='*.dtd' --exclude='*.xml' --exclude=configure --exclude='ascend-grammar.[ch]' --exclude='ascend-scanner.[ch]' --exclude=Makefile --exclude='*.1' --exclude='*.log' --exclude='*.log' --exclude='*.Po' --exclude='*.status' ethereal-0.9.14/gtk/file_dlg.h ethereal/gtk/file_dlg.h
--- ethereal-0.9.14/gtk/file_dlg.h	2002-08-29 01:40:08.000000000 +0100
+++ ethereal/gtk/file_dlg.h	2003-08-13 22:14:02.000000000 +0100
@@ -31,6 +31,9 @@
 void file_close_cmd_cb(GtkWidget *, gpointer);
 void file_reload_cmd_cb(GtkWidget *, gpointer);
 
+void file_color_import_cmd_cb(GtkWidget *w, gpointer data);
+void file_color_export_cmd_cb(GtkWidget *, gpointer);
+
 /*
  * Set the "Save only marked packets" toggle button as appropriate for
  * the current output file type and count of marked packets.

Thu Aug 14 22:27:25 BST 2003 Comparison between ethereal-0.9.14 and ethereal
Changes to:
ethereal/AUTHORS
ethereal/color.h
ethereal/gtk/color_dlg.c
ethereal/gtk/color_dlg.h
ethereal/gtk/color_filters.c
ethereal/gtk/color_filters.h
ethereal/gtk/file_dlg.c
ethereal/gtk/file_dlg.h
New Files:
NONE
See 'colorfilters2.patch' for details
How Colorization Works
----------------------
Packets are colored according to a list of color filters. Each filter
consists of a name, a filter expression and a coloration. A packet is
colored according to the first filter that it matches, Color filter
expressions use exactly the same syntax as display filter expressions.
 
When Ethereal starts the color filters are loaded from:
1. The user's personal colorfilters file or, if that does not exist,
2. The global colorfilters file.
If neither of these exist then the packets will not be colored.

The Color Filters Dialog
------------------------
This dialog displays a list of color filters and allows it to be
modified.

THE FILTER LIST
Single rows may be selected by clicking. Multiple rows may be selected
by using the ctrl and shift keys in combination with the mouse button.

UP
Moves the selected filter(s) up the list, making it more likely that
they will be used to color packets.

DOWN
Moves the selected filter(s) down the list, making it less likely that
they will be used to color packets.

NEW
Adds a new filter at the bottom of the list and opens the Edit Color
Filter dialog box. You will have to alter the filter expression at
least before the filter will be accepted. The format of color filter
expressions is identical to that of display filters. The new filter is
selected, so it may immediately be moved up and down, deleted or edited.
To avoid confusion all filters are unselected before the new filter is
created.

EDIT
Opens the Edit Color Filter dialog box for the selected filter. (If this
button is disabled you may have more than one filter selected, making it
ambiguous which is to be edited.)

DELETE
Deletes the selected color filter(s).

OK
Closes the dialog and uses the color filters as they stand.

APPLY
Colors the packets according to the current list of color filters, but
does not close the dialog.

SAVE
Saves the current list of color filters in your personal colorfilters
file. Unless you do this they will not be used the next time you start
Ethereal.

REVERT
Deletes your personal colorfilters file, reloads the global
colorfilters file, if any, and closes the dialog.

EXPORT (Save As if using GTK2+)
Allows you to choose a file in which to save the current list of color
filters. You may also choose to save only the selected filters. A
button is provided to save the filters in the global colorfilter file,
(you must have sufficient permissions to write this file, of course.)

IMPORT (Open if using GTK2+)
Allows you to choose a file containing color filters which are then
added to the bottom of the current list. All the added filters are
selected, so they may be moved to the correct position in the list as a
group. To avoid confusion all filters are unselected before the new
filters are imported. A button is provided to load the filters from the
global colorfilter file.

CANCEL
Closes the dialog without changing the coloration of the packets. Note
that changes you have made to the current list of color filters is not
undone.