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