Fix the wireless settings button for AirPCap devices in the
[obnox/wireshark/wip.git] / gtk / color_dlg.c
1 /* color_dlg.c
2  * Definitions for dialog boxes for color filters
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <string.h>
30
31 #include <gtk/gtk.h>
32
33 #include <epan/packet.h>
34 #include <epan/dfilter/dfilter.h>
35 #include <epan/prefs.h>
36
37 #include "../color.h"
38 #include "../color_filters.h"
39 #include "../file.h"
40 #include "../simple_dialog.h"
41
42 #include "gtk/main.h"
43 #include "gtk/color_utils.h"
44 #include "gtk/color_dlg.h"
45 #include "gtk/dlg_utils.h"
46 #include "gtk/gui_utils.h"
47 #include "gtk/dfilter_expr_dlg.h"
48 #include "gtk/stock_icons.h"
49 #include "gtk/filter_dlg.h"
50 #include "gtk/capture_file_dlg.h"
51 #include "gtk/gtkglobals.h"
52 #include "gtk/help_dlg.h"
53 #include "gtk/color_edit_dlg.h"
54 #include "gtk/new_packet_list.h"
55
56
57 #define BUTTON_SIZE_X -1
58 #define BUTTON_SIZE_Y -1
59
60
61 static GtkWidget* colorize_dialog_new(char *filter);
62 static void add_filter_to_list(gpointer filter_arg, gpointer list_arg, gboolean prepend);
63 static void color_filter_up_cb(GtkButton *button, gpointer user_data);
64 static void color_filter_down_cb(GtkButton *button, gpointer user_data);
65 static void remember_selected_row(GtkTreeSelection *sel, gpointer list);
66 static void color_destroy_cb(GtkButton *button, gpointer user_data);
67 static void destroy_edit_dialog_cb(gpointer filter_arg, gpointer dummy);
68 static void create_new_color_filter(GtkButton *button, const char *filter);
69 static void color_new_cb(GtkButton *button, gpointer user_data);
70 static void color_edit_cb(GtkButton *button, gpointer user_data);
71 static gboolean color_filters_button_cb(GtkWidget *, GdkEventButton *, gpointer);
72 static void color_disable_cb(GtkWidget *widget, gboolean user_data);
73 static void color_delete_cb(GtkWidget *widget, gpointer user_data);
74 static void color_save_cb(GtkButton *button, gpointer user_data);
75 static void color_ok_cb(GtkButton *button, gpointer user_data);
76 static void color_cancel_cb(GtkWidget *widget, gpointer user_data);
77 static void color_apply_cb(GtkButton *button, gpointer user_data);
78 static void color_clear_cb(GtkWidget *button, gpointer user_data);
79 static void color_import_cb(GtkButton *button, gpointer user_data );
80 static void color_export_cb(GtkButton *button, gpointer user_data );
81
82
83 static GtkWidget *colorize_win;
84 gint      color_dlg_num_of_filters;  /* number of filters being displayed */
85 gint      color_dlg_row_selected;    /* row in color_filters that is selected */
86
87 static gboolean  row_is_moving = FALSE;
88
89 /* This is a list of all current color filters in the dialog
90  * (copied from color_filters.c and edited with the dialog).
91  * The color filter items are not identical to the ones used for the
92  * packet list display, so they can be safely edited.
93  *
94  * Keep the temporary filters in a separate list so that they are
95  * not shown in the edit-dialog
96  *
97  * XXX - use the existing GTK list for this purpose and build temporary copies
98  * e.g. for the save/export functions.
99  * Problem: Don't know when able to safely throw away, e.g. while exporting.
100  */
101 static GSList *color_filter_edit_list = NULL;
102 static GSList *color_filter_tmp_list = NULL;
103
104
105 #define COLOR_UP_LB             "color_up_lb"
106 #define COLOR_DOWN_LB           "color_down_lb"
107 #define COLOR_EDIT_LB           "color_edit_lb"
108 #define COLOR_ENABLE_LB         "color_enable_lb"
109 #define COLOR_DISABLE_LB        "color_disable_lb"
110 #define COLOR_DELETE_LB         "color_delete_lb"
111 #define COLOR_FILTERS_CL        "color_filters_cl"
112 #define COLOR_FILTER_LIST       "color_filter_list"
113
114
115 /* Callback for the "Display:Coloring Rules" menu item. */
116 void
117 color_display_cb(GtkWidget *w _U_, gpointer d _U_)
118 {
119   if (colorize_win != NULL) {
120     /* There's already a color dialog box active; reactivate it. */
121     reactivate_window(colorize_win);
122   } else {
123     /* Create a new "Colorize Display" dialog. */
124     colorize_win = colorize_dialog_new(NULL);
125   }
126 }
127
128 /* this opens the color dialog and presets the filter string */
129 void
130 color_display_with_filter(char *filter)
131 {
132   if (colorize_win != NULL) {
133     /* There's already a color dialog box active; reactivate it. */
134     reactivate_window(colorize_win);
135   } else {
136     /* Create a new "Colorize Display" dialog. */
137     colorize_win = colorize_dialog_new(filter);
138   }
139 }
140
141 /* if this filter is selected - count it in the given int* */
142 static void
143 count_this_select(gpointer filter_arg, gpointer counter_arg)
144 {
145   color_filter_t *colorf = filter_arg;
146   int * cnt = counter_arg;
147
148   if (colorf->selected)
149     (*cnt)++;
150 }
151
152 /* TODO: implement count of selected filters. Plug in to file_dlg update of "export selected" checkbox. */
153 int color_selected_count(void)
154 {
155   int count = 0;
156
157   g_slist_foreach(color_filter_edit_list, count_this_select, &count);
158
159   return count;
160 }
161
162 /* Create the "Coloring Rules" dialog. */
163 static GtkWidget*
164 colorize_dialog_new (char *filter)
165 {
166   GtkWidget *color_win;
167   GtkWidget *dlg_vbox;
168   GtkWidget *main_hbox;
169   GtkWidget *ctrl_vbox;
170   GtkWidget *order_fr;
171   GtkWidget *order_vbox;
172   GtkWidget *color_filter_up;
173   GtkWidget *order_move_label;
174   GtkWidget *color_filter_down;
175
176   GtkWidget *list_fr;
177   GtkWidget *list_vbox;
178   GtkWidget *scrolledwindow1;
179   GtkWidget *color_filters;
180   GtkWidget *list_label;
181
182   GtkWidget *edit_fr;
183   GtkWidget *edit_vbox;
184   GtkWidget *color_new;
185   GtkWidget *color_edit;
186   GtkWidget *color_enable;
187   GtkWidget *color_disable;
188   GtkWidget *color_delete;
189
190   GtkWidget *manage_fr;
191   GtkWidget *manage_vbox;
192   GtkWidget *color_import;
193   GtkWidget *color_export;
194   GtkWidget *color_clear;
195
196   GtkWidget *button_ok_hbox;
197   GtkWidget *color_ok;
198   GtkWidget *color_apply;
199   GtkWidget *color_save;
200   GtkWidget *color_cancel;
201   GtkWidget *color_help;
202
203   GtkListStore      *store;
204   GtkCellRenderer   *renderer;
205   GtkTreeViewColumn *column;
206   GtkTreeSelection  *selection;
207   const gchar *titles[] = { "Name", "String" };
208
209
210
211   color_dlg_num_of_filters = 0;
212   color_dlg_row_selected = -1; /* no row selected */
213   /* Resizing of the dialog window is now reasonably done.
214    * Default size is set so that it should fit into every usual screen resolution.
215    * All other widgets are always packed depending on the current window size. */
216   color_win = dlg_conf_window_new ("Wireshark: Coloring Rules");
217   g_object_set_data(G_OBJECT(color_win), "color_win", color_win);
218   gtk_window_set_default_size(GTK_WINDOW(color_win), DEF_WIDTH, DEF_HEIGHT * 2/3);
219   dlg_vbox = gtk_vbox_new (FALSE, 0);
220   gtk_container_set_border_width  (GTK_CONTAINER (dlg_vbox), 5);
221   gtk_container_add (GTK_CONTAINER (color_win), dlg_vbox);
222
223   main_hbox = gtk_hbox_new (FALSE, 0);
224   gtk_box_pack_start (GTK_BOX (dlg_vbox), main_hbox, TRUE, TRUE, 0);
225
226   ctrl_vbox = gtk_vbox_new (FALSE, 0);
227   gtk_box_pack_start (GTK_BOX (main_hbox), ctrl_vbox, FALSE, FALSE, 0);
228
229   /* edit buttons frame */
230   edit_fr = gtk_frame_new("Edit");
231   gtk_box_pack_start (GTK_BOX (ctrl_vbox), edit_fr, TRUE, TRUE, 0);
232
233   /* edit_vbox is first button column (containing: new, edit and such) */
234   edit_vbox = gtk_vbox_new(TRUE, 0);
235   gtk_container_set_border_width  (GTK_CONTAINER (edit_vbox), 5);
236   gtk_container_add(GTK_CONTAINER(edit_fr), edit_vbox);
237
238   color_new = gtk_button_new_from_stock(GTK_STOCK_NEW);
239   gtk_box_pack_start (GTK_BOX (edit_vbox), color_new, FALSE, FALSE, 5);
240   gtk_widget_set_tooltip_text(color_new, "Create a new filter at the top of the list");
241
242   color_edit = gtk_button_new_from_stock(WIRESHARK_STOCK_EDIT);
243   gtk_box_pack_start (GTK_BOX (edit_vbox), color_edit, FALSE, FALSE, 5);
244   gtk_widget_set_tooltip_text(color_edit, " If more than one filter is selected, edit the first selected one");
245   gtk_widget_set_sensitive (color_edit, FALSE);
246
247   color_enable = gtk_button_new_from_stock(WIRESHARK_STOCK_ENABLE);
248   gtk_box_pack_start (GTK_BOX (edit_vbox), color_enable, FALSE, FALSE, 5);
249   gtk_widget_set_tooltip_text(color_enable, "Enable the selected filter(s)");
250   gtk_widget_set_sensitive (color_enable, FALSE);
251
252   color_disable = gtk_button_new_from_stock(WIRESHARK_STOCK_DISABLE);
253   gtk_box_pack_start (GTK_BOX (edit_vbox), color_disable, FALSE, FALSE, 5);
254   gtk_widget_set_tooltip_text(color_disable, "Disable the selected filter(s)");
255   gtk_widget_set_sensitive (color_disable, FALSE);
256
257   color_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE);
258   gtk_box_pack_start (GTK_BOX (edit_vbox), color_delete, FALSE, FALSE, 5);
259   gtk_widget_set_tooltip_text(color_delete, "Delete the selected filter(s)");
260   gtk_widget_set_sensitive (color_delete, FALSE);
261   /* End edit buttons frame */
262
263
264   /* manage buttons frame */
265   manage_fr = gtk_frame_new("Manage");
266   gtk_box_pack_start (GTK_BOX (ctrl_vbox), manage_fr, TRUE, TRUE, 0);
267
268   manage_vbox = gtk_vbox_new (TRUE, 0);
269   gtk_container_set_border_width  (GTK_CONTAINER (manage_vbox), 5);
270   gtk_container_add(GTK_CONTAINER(manage_fr), manage_vbox);
271
272   color_import = gtk_button_new_from_stock(WIRESHARK_STOCK_IMPORT);
273   gtk_box_pack_start (GTK_BOX (manage_vbox), color_import, FALSE, FALSE, 5);
274   gtk_widget_set_tooltip_text(color_import, "Load filters from a file and append them to the list");
275   color_export = gtk_button_new_from_stock(WIRESHARK_STOCK_EXPORT);
276   gtk_box_pack_start (GTK_BOX (manage_vbox), color_export, FALSE, FALSE, 5);
277   gtk_widget_set_tooltip_text(color_export, "Save all/selected filters to a file");
278   color_clear = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
279   gtk_box_pack_start(GTK_BOX (manage_vbox), color_clear, FALSE, FALSE, 5);
280   gtk_widget_set_tooltip_text(color_clear, "Clear the filter list and revert to system-wide default filter set");
281
282   /* filter list frame */
283   list_fr = gtk_frame_new("Filter");
284   gtk_box_pack_start (GTK_BOX (main_hbox), list_fr, TRUE, TRUE, 0);
285
286   list_vbox = gtk_vbox_new (FALSE, 0);
287   gtk_container_set_border_width  (GTK_CONTAINER (list_vbox), 5);
288   gtk_container_add(GTK_CONTAINER(list_fr), list_vbox);
289
290   list_label = gtk_label_new (("List is processed in order until match is found"));
291   gtk_box_pack_start (GTK_BOX (list_vbox), list_label, FALSE, FALSE, 0);
292
293   /* create the list of filters */
294   scrolledwindow1 = scrolled_window_new(NULL, NULL);
295   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow1),
296                                    GTK_SHADOW_IN);
297   gtk_box_pack_start (GTK_BOX (list_vbox), scrolledwindow1, TRUE, TRUE, 0);
298
299   /* the list store contains : filter name, filter string, foreground
300    * color, background color, pointer to color filter */
301   store = gtk_list_store_new(6,
302                                  G_TYPE_STRING,
303                                  G_TYPE_STRING,
304                                  G_TYPE_STRING,
305                                  G_TYPE_STRING,
306                                  G_TYPE_BOOLEAN,
307                                  G_TYPE_POINTER);
308   color_filters = tree_view_new(GTK_TREE_MODEL(store));
309   g_object_unref(store);
310   renderer = gtk_cell_renderer_text_new();
311   column = gtk_tree_view_column_new_with_attributes(titles[0], renderer,
312                                                     "text", 0,
313                                                     "foreground", 2,
314                                                     "background", 3,
315                                                     "strikethrough", 4,
316                                                     NULL);
317   gtk_tree_view_column_set_fixed_width(column, 80);
318   gtk_tree_view_append_column(GTK_TREE_VIEW(color_filters), column);
319   renderer = gtk_cell_renderer_text_new();
320   column = gtk_tree_view_column_new_with_attributes(titles[1], renderer,
321                                                     "text", 1,
322                                                     "foreground", 2,
323                                                     "background", 3,
324                                                     "strikethrough", 4,
325                                                     NULL);
326   gtk_tree_view_column_set_fixed_width(column, 300);
327   gtk_tree_view_append_column(GTK_TREE_VIEW(color_filters), column);
328   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(color_filters), TRUE);
329   gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(color_filters), FALSE);
330
331   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
332   gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
333
334   gtk_container_add (GTK_CONTAINER (scrolledwindow1), color_filters);
335
336
337   /* order frame */
338   order_fr = gtk_frame_new("Order");
339   gtk_box_pack_start (GTK_BOX (main_hbox), order_fr, FALSE, FALSE, 0);
340
341   order_vbox = gtk_vbox_new (TRUE, 0);
342   gtk_container_set_border_width  (GTK_CONTAINER (order_vbox), 5);
343   gtk_container_add(GTK_CONTAINER(order_fr), order_vbox);
344
345   color_filter_up = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
346   gtk_box_pack_start (GTK_BOX (order_vbox), color_filter_up, FALSE, FALSE, 0);
347   gtk_widget_set_tooltip_text(color_filter_up, "Move filter higher in list");
348   gtk_widget_set_sensitive (color_filter_up, FALSE);
349
350   order_move_label = gtk_label_new (("Move\nselected filter\nup or down"));
351   gtk_box_pack_start (GTK_BOX (order_vbox), order_move_label, FALSE, FALSE, 0);
352
353   color_filter_down = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
354   gtk_box_pack_start (GTK_BOX (order_vbox), color_filter_down, FALSE, FALSE, 0);
355   gtk_widget_set_tooltip_text(color_filter_down, "Move filter lower in list");
356   gtk_widget_set_sensitive (color_filter_down, FALSE);
357
358
359   /* Button row: OK, cancel and help buttons */
360   button_ok_hbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
361   gtk_box_pack_start (GTK_BOX (dlg_vbox), button_ok_hbox, FALSE, FALSE, 5);
362
363   color_ok = g_object_get_data(G_OBJECT(button_ok_hbox), GTK_STOCK_OK);
364   gtk_widget_set_tooltip_text(color_ok, "Apply the color filters to the display and close this dialog");
365   color_apply = g_object_get_data(G_OBJECT(button_ok_hbox), GTK_STOCK_APPLY);
366   gtk_widget_set_tooltip_text(color_apply, "Apply the color filters to the display and keep this dialog open");
367
368   color_save = g_object_get_data(G_OBJECT(button_ok_hbox), GTK_STOCK_SAVE);
369   gtk_widget_set_tooltip_text(color_save, "Save the color filters permanently and keep this dialog open");
370   color_cancel = g_object_get_data(G_OBJECT(button_ok_hbox), GTK_STOCK_CANCEL);
371   window_set_cancel_button(color_win, color_cancel, color_cancel_cb);
372   gtk_widget_set_tooltip_text(color_cancel, "Cancel changes done (since last \"Apply\") and close this dialog");
373
374   color_help = g_object_get_data(G_OBJECT(button_ok_hbox), GTK_STOCK_HELP);
375   gtk_widget_set_tooltip_text(color_help, "Get help about this dialog");
376   g_signal_connect(color_help, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_COLORING_RULES_DIALOG);
377
378   gtk_widget_grab_default(color_ok);
379
380   /* signals and such */
381   g_signal_connect(color_win, "destroy", G_CALLBACK(color_destroy_cb), NULL);
382   g_object_set_data(G_OBJECT(color_filter_up), COLOR_FILTERS_CL, color_filters);
383   g_signal_connect(color_filter_up, "clicked", G_CALLBACK(color_filter_up_cb), NULL);
384   g_object_set_data(G_OBJECT(color_filter_down), COLOR_FILTERS_CL, color_filters);
385   g_signal_connect(color_filter_down, "clicked", G_CALLBACK(color_filter_down_cb), NULL);
386   g_signal_connect(selection, "changed", G_CALLBACK(remember_selected_row), color_filters);
387   g_signal_connect(color_filters, "button_press_event", G_CALLBACK(color_filters_button_cb), NULL);
388   g_object_set_data(G_OBJECT(color_filters), COLOR_UP_LB, color_filter_up);
389   g_object_set_data(G_OBJECT(color_filters), COLOR_DOWN_LB, color_filter_down);
390   g_object_set_data(G_OBJECT(color_filters), COLOR_EDIT_LB, color_edit);
391   g_object_set_data(G_OBJECT(color_filters), COLOR_ENABLE_LB, color_enable);
392   g_object_set_data(G_OBJECT(color_filters), COLOR_DISABLE_LB, color_disable);
393   g_object_set_data(G_OBJECT(color_filters), COLOR_DELETE_LB, color_delete);
394   g_object_set_data(G_OBJECT(color_new), COLOR_FILTERS_CL, color_filters);
395   g_signal_connect(color_new, "clicked", G_CALLBACK(color_new_cb), NULL);
396   g_object_set_data(G_OBJECT(color_edit), COLOR_FILTERS_CL, color_filters);
397   g_signal_connect(color_edit, "clicked", G_CALLBACK(color_edit_cb), NULL);
398   g_object_set_data(G_OBJECT(color_enable), COLOR_FILTERS_CL, color_filters);
399   g_signal_connect(color_enable, "clicked", G_CALLBACK(color_disable_cb), FALSE);
400   g_object_set_data(G_OBJECT(color_disable), COLOR_FILTERS_CL, color_filters);
401   g_signal_connect(color_disable, "clicked", G_CALLBACK(color_disable_cb), (gpointer)TRUE);
402   g_object_set_data(G_OBJECT(color_delete), COLOR_EDIT_LB, color_edit);
403   g_object_set_data(G_OBJECT(color_delete), COLOR_FILTERS_CL, color_filters);
404   g_signal_connect(color_delete, "clicked", G_CALLBACK(color_delete_cb), NULL);
405   g_object_set_data(G_OBJECT(color_import), COLOR_FILTERS_CL, color_filters);
406   g_signal_connect(color_import, "clicked", G_CALLBACK(color_import_cb), NULL);
407   g_signal_connect(color_export, "clicked", G_CALLBACK(color_export_cb), NULL);
408   g_object_set_data(G_OBJECT(color_clear), COLOR_FILTERS_CL, color_filters);
409   g_signal_connect(color_clear, "clicked", G_CALLBACK(color_clear_cb), NULL);
410   g_signal_connect(color_ok, "clicked", G_CALLBACK(color_ok_cb), NULL);
411   g_signal_connect(color_apply, "clicked", G_CALLBACK(color_apply_cb), NULL);
412   g_signal_connect(color_save, "clicked", G_CALLBACK(color_save_cb), NULL);
413
414   g_signal_connect(color_win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
415
416   gtk_widget_grab_focus(color_filters);
417
418   /* prepare filter list content */
419   color_filters_clone(color_filters);
420   g_object_set_data(G_OBJECT(color_win), COLOR_FILTER_LIST, &color_filter_edit_list);
421
422   gtk_widget_show_all(color_win);
423
424   /* hide the Save button if the user uses implicit save */
425   if(!prefs.gui_use_pref_save) {
426     gtk_widget_hide(color_save);
427   }
428
429   window_present(color_win);
430
431   if(filter){
432     /* if we specified a preset filter string, open the new dialog and
433        set the filter */
434     create_new_color_filter(GTK_BUTTON(color_new), filter);
435   }
436
437   return color_win;
438 }
439
440 /* move a row in the list +/- one position up/down */
441 static void move_this_row (GtkWidget   *color_filters,
442                      gint         filter_number,
443                      gint         amount)            /* only tested with +1(down) and -1(up) */
444 {
445   color_filter_t *colorf;
446   GtkTreeModel   *model;
447   GtkTreeIter     iter1, iter2;
448   gchar          *name, *string, *fg_str, *bg_str;
449   gboolean        disabled;
450
451   g_assert(amount == +1 || amount == -1);
452   g_assert(amount == +1 || filter_number > 0);
453   g_assert(amount == -1 || filter_number < color_dlg_num_of_filters - 1);
454
455   row_is_moving = TRUE;
456   model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
457   gtk_tree_model_iter_nth_child(model, &iter1, NULL, filter_number);
458   gtk_tree_model_iter_nth_child(model, &iter2, NULL, filter_number + amount);
459
460   gtk_tree_model_get(model, &iter1, 0, &name, 1, &string,
461                      2, &fg_str, 3, &bg_str, 4, &disabled, 5, &colorf, -1);
462   gtk_list_store_remove(GTK_LIST_STORE(model), &iter1);
463   if (amount < 0)
464     gtk_list_store_insert_before(GTK_LIST_STORE(model), &iter1, &iter2);
465   else
466     gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter1, &iter2);
467
468   gtk_list_store_set(GTK_LIST_STORE(model), &iter1,
469           0, name,
470           1, string,
471           2, fg_str,
472           3, bg_str,
473           4, disabled,
474           5, colorf, -1);
475
476   g_free(name);
477   g_free(string);
478   g_free(fg_str);
479   g_free(bg_str);
480   row_is_moving = FALSE;
481
482   /*
483    * re-select the initial row
484    */
485   gtk_widget_grab_focus(color_filters);
486   gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters)), &iter1);
487
488   color_filter_edit_list = g_slist_remove(color_filter_edit_list, colorf);
489   color_filter_edit_list = g_slist_insert(color_filter_edit_list, colorf, filter_number + amount);
490 }
491
492 /* User pressed the "Up" button: Move the selected filters up in the list */
493 static void
494 color_filter_up_cb(GtkButton *button, gpointer user_data _U_)
495 {
496   gint amount;
497   gint filter_number;
498   GtkWidget * color_filters;
499   color_filter_t *colorf;
500   GtkTreeIter       iter;
501   GtkTreeModel     *model;
502   GtkTreeSelection *sel;
503
504   amount = -1;
505   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(button), COLOR_FILTERS_CL);
506
507   for (filter_number = 0; filter_number < color_dlg_num_of_filters; filter_number++)
508   {
509     model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
510     gtk_tree_model_iter_nth_child(model, &iter, NULL, filter_number);
511     gtk_tree_model_get(model, &iter, 5, &colorf, -1);
512     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
513     if (gtk_tree_selection_iter_is_selected(sel, &iter))
514       move_this_row (color_filters, filter_number, amount);
515   }
516 }
517
518 /* User pressed the "Down" button: Move the selected filters down in the list */
519 static void
520 color_filter_down_cb(GtkButton *button, gpointer user_data _U_)
521 {
522   gint amount;
523   gint filter_number;
524   GtkWidget * color_filters;
525   color_filter_t *colorf;
526   GtkTreeIter     iter;
527   GtkTreeModel   *model;
528
529   amount = +1;
530   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(button), COLOR_FILTERS_CL);
531
532   for (filter_number = color_dlg_num_of_filters - 1; filter_number >= 0; filter_number--)
533   {
534     model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
535     gtk_tree_model_iter_nth_child(model, &iter, NULL, filter_number);
536     gtk_tree_model_get(model, &iter, 5, &colorf, -1);
537     if (colorf->selected)
538       move_this_row (color_filters, filter_number, amount);
539   }
540 }
541
542
543 struct remember_data
544 {
545   gint count;               /* count of selected filters */
546   gboolean first_selected;  /* true if the first filter in the list is selected */
547   gboolean last_selected;   /* true if the last filter in the list is selected */
548   gboolean all_enabled;     /* true if all selected coloring rules are enabled */
549   gboolean all_disabled;    /* true if all selected coloring rules are disabled */
550   gpointer color_filters;
551 };
552 /* called for each selected row in the tree.
553  */
554 static void remember_this_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer arg)
555 {
556   gint         *path_index;
557   color_filter_t *colorf;
558   struct remember_data *data = arg;
559
560   gtk_tree_model_get(model, iter, 5, &colorf, -1);
561   colorf->selected = TRUE;
562
563   data->all_enabled  &= (!colorf->disabled);
564   data->all_disabled &= colorf->disabled;
565
566   path_index = gtk_tree_path_get_indices(path);   /* not to be freed */
567   if (path_index == NULL)       /* can return NULL according to API doc.*/
568   {
569     return;
570   }
571   color_dlg_row_selected = path_index[0];
572
573   if (color_dlg_row_selected == 0)
574     data->first_selected = TRUE;
575   if (color_dlg_row_selected == color_dlg_num_of_filters - 1)
576     data->last_selected = TRUE;
577
578   data->count++;
579
580   gtk_tree_view_scroll_to_cell(data->color_filters, path, NULL, FALSE, 0.0f, 0.0f);
581 }
582
583 /* clear the selection flag of this filter */
584 static void
585 clear_select_flag(gpointer filter_arg, gpointer arg _U_)
586 {
587   color_filter_t *colorf = filter_arg;
588
589   colorf->selected = FALSE;
590 }
591
592 /* The gtk+2.0 version gets called for, (maybe multiple,) changes in the selection. */
593 static void
594 remember_selected_row(GtkTreeSelection *sel, gpointer color_filters)
595 {
596   GtkWidget    *button;
597   struct remember_data data;
598
599   data.first_selected = data.last_selected = FALSE;
600   data.all_enabled = data.all_disabled = TRUE;
601   data.count = 0;
602   data.color_filters = color_filters;
603
604   g_slist_foreach(color_filter_edit_list, clear_select_flag, NULL);
605   gtk_tree_selection_selected_foreach(sel,remember_this_row, &data);
606
607   if (data.count > 0)
608   {
609     /*
610      * One or more rows are selected, so we can operate on them.
611      */
612
613     /* We can only edit if there is exactly one filter selected */
614     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_EDIT_LB);
615     gtk_widget_set_sensitive (button, data.count == 1);
616
617     /* We can enable any number of filters */
618     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_ENABLE_LB);
619     gtk_widget_set_sensitive (button, !data.all_enabled);
620
621     /* We can disable any number of filters */
622     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DISABLE_LB);
623     gtk_widget_set_sensitive (button, !data.all_disabled);
624
625     /* We can delete any number of filters */
626     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DELETE_LB);
627     gtk_widget_set_sensitive (button, TRUE);
628
629     /*
630      * We can move them up *if* one of them isn't the top row,
631      * and move them down *if* one of them isn't the bottom row.
632      */
633     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_UP_LB);
634     gtk_widget_set_sensitive(button, !data.first_selected);
635     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DOWN_LB);
636     gtk_widget_set_sensitive(button, !data.last_selected);
637   }
638   else
639   {
640     color_dlg_row_selected = -1;
641
642     /*
643      * No row is selected, so we can't do operations that affect the
644      * selected row.
645      */
646     if (!row_is_moving) {
647       button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_UP_LB);
648       gtk_widget_set_sensitive (button, FALSE);
649       button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DOWN_LB);
650       gtk_widget_set_sensitive (button, FALSE);
651     }
652     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_EDIT_LB);
653     gtk_widget_set_sensitive (button, FALSE);
654     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_ENABLE_LB);
655     gtk_widget_set_sensitive (button, FALSE);
656     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DISABLE_LB);
657     gtk_widget_set_sensitive (button, FALSE);
658     button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DELETE_LB);
659     gtk_widget_set_sensitive (button, FALSE);
660   }
661 }
662
663
664
665 /* destroy a single color edit dialog */
666 static void
667 destroy_edit_dialog_cb(gpointer filter_arg, gpointer dummy _U_)
668 {
669   color_filter_t *colorf = (color_filter_t *)filter_arg;
670
671   if (colorf->edit_dialog != NULL)
672     window_destroy(colorf->edit_dialog);
673 }
674
675 /* Called when the dialog box is being destroyed; destroy any edit
676  * dialogs opened from this dialog.
677  */
678 static void
679 color_destroy_cb                       (GtkButton       *button _U_,
680                                         gpointer         user_data _U_)
681 {
682   /* Destroy any edit dialogs we have open. */
683   g_slist_foreach(color_filter_edit_list, destroy_edit_dialog_cb, NULL);
684
685   /* destroy the filter list itself */
686   color_filter_list_delete(&color_filter_edit_list);
687   color_filter_list_delete(&color_filter_tmp_list);
688
689   colorize_win = NULL;
690 }
691
692
693 static void
694 select_row(GtkWidget *color_filters, int row)
695 {
696   GtkTreeModel     *model;
697   GtkTreeIter       iter;
698   GtkTreeSelection *sel;
699
700   /* select the new row */
701   model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
702   gtk_tree_model_iter_nth_child(model, &iter, NULL, row);
703   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
704   gtk_tree_selection_select_iter(sel, &iter);
705 }
706
707
708 /* add a single color filter to the list */
709 static void
710 add_filter_to_list(gpointer filter_arg, gpointer list_arg, gboolean prepend)
711 {
712   color_filter_t *colorf = filter_arg;
713     gchar           fg_str[14], bg_str[14];
714     GtkListStore   *store;
715     GtkTreeIter     iter;
716
717   if( strstr(colorf->filter_name,CONVERSATION_COLOR_PREFIX)==NULL) {
718     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list_arg)));
719     if (prepend) {
720       gtk_list_store_prepend(store, &iter);
721     } else {
722       gtk_list_store_append(store, &iter);
723     }
724     g_snprintf(fg_str, sizeof(fg_str), "#%04X%04X%04X",
725             colorf->fg_color.red, colorf->fg_color.green, colorf->fg_color.blue);
726     g_snprintf(bg_str, sizeof(bg_str), "#%04X%04X%04X",
727             colorf->bg_color.red, colorf->bg_color.green, colorf->bg_color.blue);
728     gtk_list_store_set(store, &iter,
729                 0, colorf->filter_name,
730                 1, colorf->filter_text,
731                 2, fg_str,
732                 3, bg_str,
733                 4, colorf->disabled,
734                 5, colorf, -1);
735     if (prepend) {
736       color_filter_edit_list = g_slist_prepend(color_filter_edit_list, colorf);
737     } else {
738       color_filter_edit_list = g_slist_append(color_filter_edit_list, colorf);
739     }
740     color_dlg_num_of_filters++;
741   } else {
742     /* But keep the temporary ones too, so they can be added again
743      * when the user is done editing */
744     color_filter_tmp_list = g_slist_append(color_filter_tmp_list, colorf);
745   }
746 }
747
748
749 /* a new color filter was read in from a filter file */
750 void
751 color_filter_add_cb(color_filter_t *colorf, gpointer user_data)
752 {
753   GtkWidget        *color_filters = user_data;
754
755   add_filter_to_list(colorf, color_filters, FALSE);
756
757   gtk_widget_grab_focus(color_filters);
758 }
759
760 /* Create a new filter, add it to the list, and pop up an
761    "Edit color filter" dialog box to edit it. */
762 static void
763 create_new_color_filter(GtkButton *button, const char *filter)
764 {
765 #if GTK_CHECK_VERSION(3,0,0)
766   GtkStyleContext *context;
767   GdkRGBA          *rgba_bg_color;
768   GdkRGBA          *rgba_fg_color;
769 #else
770   GtkStyle         *style;
771 #endif
772   color_filter_t   *colorf;
773   color_t          bg_color, fg_color;
774   GtkWidget        *color_filters;
775   GtkTreeSelection *sel;
776
777   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(button), COLOR_FILTERS_CL);
778
779   /* unselect all filters */
780   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
781   gtk_tree_selection_unselect_all (sel);
782
783   /* Use the default background and foreground colors as the colors. */
784 #if GTK_CHECK_VERSION(3,0,0)
785   context = gtk_widget_get_style_context (new_packet_list_get_widget());
786   gtk_style_context_get (context, GTK_STATE_NORMAL,
787                        "background-color", &rgba_bg_color,
788                        NULL);
789   gtk_style_context_get (context, GTK_STATE_NORMAL,
790                        "color", &rgba_fg_color,
791                        NULL);
792   gdkRGBAcolor_to_color_t(&bg_color, rgba_bg_color);
793   gdkRGBAcolor_to_color_t(&fg_color, rgba_fg_color);
794   gdk_rgba_free (rgba_bg_color);
795   gdk_rgba_free (rgba_fg_color);
796
797 #else
798   style = gtk_widget_get_style(new_packet_list_get_widget());
799   gdkcolor_to_color_t(&bg_color, &style->base[GTK_STATE_NORMAL]);
800   gdkcolor_to_color_t(&fg_color, &style->text[GTK_STATE_NORMAL]);
801 #endif
802   colorf = color_filter_new("name", filter, &bg_color, &fg_color, FALSE);
803   add_filter_to_list(colorf, color_filters, TRUE);
804   select_row(color_filters, 0);
805
806   /* open the edit dialog */
807   edit_color_filter_dialog(color_filters, TRUE /* is a new filter */);
808
809   gtk_widget_grab_focus(color_filters);
810 }
811
812 /* User pressed the "New" button: Create a new filter in the list,
813    and pop up an "Edit color filter" dialog box to edit it. */
814 static void
815 color_new_cb(GtkButton *button, gpointer user_data _U_)
816 {
817   create_new_color_filter(button, "filter");
818 }
819
820 /* User pressed the "Edit" button: Pop up an "Edit color filter" dialog box
821  * to edit an existing filter. */
822 static void
823 color_edit_cb(GtkButton *button, gpointer user_data _U_)
824 {
825   GtkWidget *color_filters;
826
827   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(button), COLOR_FILTERS_CL);
828   g_assert(color_dlg_row_selected != -1);
829   edit_color_filter_dialog(color_filters, FALSE /* is not a new filter */);
830 }
831
832 /* User double-clicked on the coloring rule */
833 static gboolean
834 color_filters_button_cb(GtkWidget *list, GdkEventButton *event,
835                           gpointer data _U_)
836 {
837   if (event->type == GDK_2BUTTON_PRESS) {
838     edit_color_filter_dialog(list, FALSE);
839   }
840
841   return FALSE;
842 }
843
844 /* action_disable==TRUE  ==> User pressed the "Disable" button:
845  *                           Disable the selected filters in the list.
846  * action_disable==FALSE ==> User pressed the "Enable" button:
847  *                           Enable the selected filters in the list.
848  */
849 static void
850 color_disable_cb(GtkWidget *widget, gboolean action_disable)
851 {
852   gint filter_number;
853   GtkWidget *button;
854   GtkWidget * color_filters;
855   color_filter_t *colorf;
856   GtkTreeIter       iter;
857   GtkTreeModel     *model;
858   GtkTreeSelection *sel;
859
860   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(widget), COLOR_FILTERS_CL);
861
862   for (filter_number = 0; filter_number < color_dlg_num_of_filters; filter_number++)
863   {
864     model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
865     gtk_tree_model_iter_nth_child(model, &iter, NULL, filter_number);
866     gtk_tree_model_get(model, &iter, 5, &colorf, -1);
867     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
868     if (gtk_tree_selection_iter_is_selected(sel, &iter)) {
869       colorf->disabled = action_disable;
870       gtk_list_store_set(GTK_LIST_STORE(model), &iter,
871                   4, action_disable, -1);
872     }
873   }
874   button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_ENABLE_LB);
875   gtk_widget_set_sensitive(button, action_disable);
876   button = (GtkWidget *)g_object_get_data(G_OBJECT(color_filters), COLOR_DISABLE_LB);
877   gtk_widget_set_sensitive(button, !action_disable);
878 }
879
880 /* Delete a single color filter from the list and elsewhere. */
881 void
882 color_delete_single(gint row, GtkWidget *color_filters)
883 {
884   color_filter_t *colorf;
885
886   GtkTreeModel     *model;
887   GtkTreeIter       iter;
888
889
890   model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
891   gtk_tree_model_iter_nth_child(model, &iter, NULL, row);
892   gtk_tree_model_get(model, &iter, 5, &colorf, -1);
893
894   /* Remove this color filter from the CList displaying the
895      color filters. */
896   gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
897   color_dlg_num_of_filters--;
898
899   /* Destroy any "Edit color filter" dialog boxes editing it. */
900   if (colorf->edit_dialog != NULL)
901     window_destroy(colorf->edit_dialog);
902
903   /* Delete the color filter from the list of color filters. */
904   color_filter_edit_list = g_slist_remove(color_filter_edit_list, colorf);
905   color_filter_delete(colorf);
906
907   /* If we grab the focus after updating the selection, the first
908    * row is always selected, so we do it before */
909   gtk_widget_grab_focus(color_filters);
910 }
911
912 /* User pressed the "Delete" button: Delete the selected filters from the list.*/
913 static void
914 color_delete_cb(GtkWidget *widget, gpointer user_data _U_)
915 {
916   GtkWidget  *color_filters;
917   gint row, num_filters;
918   GtkTreeModel     *model;
919   GtkTreeIter       iter;
920   GtkTreeSelection *sel;
921
922   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(widget), COLOR_FILTERS_CL);
923
924   /* get the number of filters in the list */
925   model = gtk_tree_view_get_model(GTK_TREE_VIEW(color_filters));
926   num_filters = gtk_tree_model_iter_n_children(model, NULL);
927   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
928
929   /* iterate through the list and delete the selected ones */
930   for (row = num_filters - 1; row >= 0; row--)
931   {
932     gtk_tree_model_iter_nth_child(model, &iter, NULL, row);
933     if (gtk_tree_selection_iter_is_selected(sel, &iter))
934       color_delete_single (row, color_filters);
935   }
936 }
937
938 /* User pressed "Import": Pop up an "Import color filter" dialog box. */
939 static void
940 color_import_cb(GtkButton *button, gpointer data _U_)
941 {
942   GtkWidget        *color_filters;
943   GtkTreeSelection *sel;
944
945   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(button), COLOR_FILTERS_CL);
946
947   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(color_filters));
948   gtk_tree_selection_unselect_all (sel);
949
950   file_color_import_cmd_cb(color_filters, &color_filter_edit_list);
951 }
952
953 /* User pressed "Export": Pop up an "Export color filter" dialog box. */
954 static void
955 color_export_cb(GtkButton *button, gpointer data _U_)
956 {
957   GtkWidget        *color_filters;
958
959   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(button), COLOR_FILTERS_CL);
960
961   file_color_export_cmd_cb(color_filters, color_filter_edit_list);
962 }
963
964 /* User confirmed the clear operation: Remove all user defined color filters and
965    revert to the global file. */
966 static void
967 color_clear_cmd(GtkWidget *widget)
968 {
969   GtkWidget * color_filters;
970
971   color_filters = (GtkWidget *)g_object_get_data(G_OBJECT(widget), COLOR_FILTERS_CL);
972
973   while (color_dlg_num_of_filters > 0)
974   {
975     color_delete_single (color_dlg_num_of_filters-1, color_filters);
976   }
977
978   /* try to read the global filters */
979   color_filters_read_globals(color_filters);
980 }
981
982 /* Clear button: user responded to question */
983 static void color_clear_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
984 {
985   switch(btn) {
986   case(ESD_BTN_CLEAR):
987     color_clear_cmd(data);
988     break;
989   case(ESD_BTN_CANCEL):
990     break;
991   default:
992     g_assert_not_reached();
993   }
994 }
995
996 /* User pressed "clear" button: ask user before really doing it */
997 void
998 color_clear_cb(GtkWidget *widget, gpointer data _U_) {
999   gpointer  dialog;
1000
1001   /* ask user, if he/she is really sure */
1002   dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTN_CLEAR | ESD_BTN_CANCEL,
1003                          "%sRemove all your personal color settings?%s\n\n"
1004                          "This will revert the color settings to global defaults.\n\n"
1005                          "Are you really sure?",
1006                          simple_dialog_primary_start(), simple_dialog_primary_end());
1007
1008   simple_dialog_set_cb(dialog, color_clear_answered_cb, widget);
1009 }
1010
1011
1012
1013 /* User pressed "Ok" button: Exit dialog and apply new list of
1014    color filters to the capture. */
1015 static void
1016 color_ok_cb(GtkButton *button _U_, gpointer user_data _U_)
1017 {
1018   /* Apply the new coloring rules... */
1019   color_apply_cb(button,user_data);
1020
1021   /* ... and destroy the dialog box. */
1022   window_destroy(colorize_win);
1023 }
1024
1025 /* User pressed "Apply" button: apply the new list of color filters
1026    to the capture. */
1027 static void
1028 color_apply_cb(GtkButton *button _U_, gpointer user_data _U_)
1029 {
1030   /* if we don't have a Save button, just save the settings now */
1031   if (!prefs.gui_use_pref_save) {
1032       if (!color_filters_write(color_filter_edit_list))
1033             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1034                 "Could not open filter file: %s", g_strerror(errno));
1035   }
1036
1037   /* Apply the coloring rules, both the temporary ones in
1038    * color_filter_tmp_list as the permanent ones in color_filter_edit_list
1039    * */
1040   color_filters_apply(color_filter_tmp_list, color_filter_edit_list);
1041
1042   /* colorize list */
1043   new_packet_list_colorize_packets();
1044 }
1045
1046 /* User pressed the "Save" button: save the color filters to the
1047    color filter file. */
1048 static void
1049 color_save_cb(GtkButton *button _U_, gpointer user_data _U_)
1050 {
1051
1052   if (!color_filters_write(color_filter_edit_list))
1053         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1054             "Could not open filter file: %s", g_strerror(errno));
1055 }
1056
1057 /* User pressed "Cancel" button (or "ESC" or the 'X'):
1058    Exit dialog without colorizing packets with the new list. */
1059 static void
1060 color_cancel_cb(GtkWidget *widget _U_, gpointer user_data _U_)
1061 {
1062   /* Destroy the dialog box. */
1063   window_destroy(colorize_win);
1064 }