2 * Dialog box for profiles editing
3 * Stig Bjorlykke <stig@bjorlykke.org>, 2008
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <gdk/gdkkeysyms.h>
28 #if GTK_CHECK_VERSION(3,0,0)
29 # include <gdk/gdkkeysyms-compat.h>
32 #include <wsutil/filesystem.h>
33 #include <epan/prefs.h>
35 #include "ui/profile.h"
36 #include "ui/recent.h"
37 #include "ui/simple_dialog.h"
39 #include "ui/gtk/main.h"
40 #include "ui/gtk/menus.h"
41 #include "ui/gtk/profile_dlg.h"
42 #include "ui/gtk/dlg_utils.h"
43 #include "ui/gtk/gui_utils.h"
44 #include "ui/gtk/gtkglobals.h"
45 #include "ui/gtk/help_dlg.h"
46 #include "ui/gtk/old-gtk-compat.h"
47 #include "ui/gtk/stock_icons.h"
56 #define E_PROF_PROFILE_L_KEY "profile_profile_l"
57 #define E_PROF_DEL_BT_KEY "profile_del_bt"
58 #define E_PROF_NAME_TE_KEY "profile_name_te"
60 static GtkWidget *global_profile_w = NULL;
62 #define PROF_OPERATION_NEW 1
63 #define PROF_OPERATION_RENAME 2
67 fill_list(GtkWidget *main_w)
71 GtkTreeView *profile_l;
73 GtkTreeIter iter, *l_select = NULL;
74 const gchar *profile_name = get_profile_name();
76 profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
77 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
80 fl_entry = edited_profile_list();
81 while (fl_entry && fl_entry->data) {
82 profile = (profile_def *)fl_entry->data;
83 gtk_list_store_append(store, &iter);
84 gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, profile->is_global, DATA_COLUMN, fl_entry, -1);
86 if (profile->name && (strcmp(profile_name, profile->name) == 0)) {
88 * XXX - We're assuming that we can just copy a GtkTreeIter
89 * and use it later without any crashes. This may not be a
92 l_select = (GtkTreeIter *)g_memdup(&iter, sizeof(iter));
94 fl_entry = g_list_next(fl_entry);
101 profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
104 profile_def *profile;
105 GtkTreeSelection *sel;
109 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
111 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
112 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
114 profile = (profile_def *)fl_entry->data;
115 if (profile_exists(profile->name, FALSE) || profile_exists(profile->name, TRUE)) {
116 /* The new profile exists, change */
117 change_configuration_profile(profile->name);
118 } else if (!profile_exists(get_profile_name(), FALSE)) {
119 /* The new profile does not exist, and the previous profile has
120 been deleted. Change to the default profile */
121 change_configuration_profile(NULL);
128 * Destroy the profile dialog box.
130 empty_profile_list(TRUE);
131 window_destroy(main_w);
136 profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
138 const gchar *err_msg;
140 if ((err_msg = apply_profile_changes()) != NULL) {
141 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_msg);
142 g_free((gchar*)err_msg);
146 profile_select(main_w, profile_l, destroy);
150 profile_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
152 GtkWidget *main_w = gtk_widget_get_toplevel(ok_bt);
153 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
156 * Apply the profile and destroy the dialog box.
158 profile_apply(main_w, profile_l, TRUE);
162 profile_dlg_apply_cb(GtkWidget *apply_bt, gpointer data _U_)
164 GtkWidget *main_w = gtk_widget_get_toplevel(apply_bt);
165 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
168 * Apply the profile, but don't destroy the dialog box.
170 profile_apply(main_w, profile_l, FALSE);
173 /* cancel button pressed, revert changes and exit dialog */
175 profile_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer data _U_)
177 GtkWidget *main_w = gtk_widget_get_toplevel(cancel_bt);
179 empty_profile_list(TRUE);
180 window_destroy(GTK_WIDGET(main_w));
183 /* Treat this as a cancel, by calling "profile_dlg_cancel_cb()" */
185 profile_dlg_delete_event_cb(GtkWidget *main_w, GdkEvent *event _U_,
188 profile_dlg_cancel_cb(main_w, data);
193 profile_dlg_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
195 global_profile_w = NULL;
200 profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
202 if (event->type == GDK_2BUTTON_PRESS) {
203 GtkWidget *main_w = gtk_widget_get_toplevel(list);
205 profile_apply(main_w, GTK_TREE_VIEW(list), TRUE);
212 profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
214 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
215 GtkWidget *main_w = gtk_widget_get_toplevel(list);
217 profile_apply(main_w, GTK_TREE_VIEW(list), TRUE);
224 profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
226 GtkWidget *profile_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
227 GtkWidget *main_w = gtk_widget_get_toplevel(profile_l);
230 GtkWidget *name_te = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
231 GtkWidget *del_bt = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY);
232 profile_def *profile;
235 gint sensitivity = FALSE;
237 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
238 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
240 profile = (profile_def *)fl_entry->data;
241 name = g_strdup(profile->name);
242 if ((profile->status != PROF_STAT_DEFAULT) && !profile->is_global) {
249 * Did you know that this function is called when the window is destroyed?
251 * This means that we have to:
253 * attach to the top-level window data items containing pointers to
254 * the widgets we affect here;
256 * give each of those widgets their own destroy callbacks;
258 * clear that pointer when the widget is destroyed;
260 * don't do anything to the widget if the pointer we get back is
263 * so that if we're called after any of the widgets we'd affect are
264 * destroyed, we know that we shouldn't do anything to those widgets.
266 if (name_te != NULL) {
267 gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
268 gtk_widget_set_sensitive(name_te, sensitivity);
271 gtk_widget_set_sensitive(del_bt, sensitivity);
276 profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
278 GtkWidget *main_w = gtk_widget_get_toplevel(w);
279 GtkWidget *name_te = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
280 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
284 const gchar *name = "New profile";
286 /* Add a new entry to the profile list. */
287 fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW, FALSE, FALSE);
289 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
290 gtk_list_store_append(store, &iter);
291 gtk_list_store_set(store, &iter, NAME_COLUMN, name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
292 /* Select the item. */
293 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
295 gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
296 gtk_widget_grab_focus(name_te);
300 profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
302 GtkWidget *main_w = gtk_widget_get_toplevel(w);
303 GtkWidget *name_te = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
304 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
308 const gchar *name = gtk_entry_get_text(GTK_ENTRY(name_te));
309 const gchar *parent = NULL;
312 GtkTreeSelection *sel;
314 profile_def *profile = NULL;
316 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
317 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
318 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
320 profile = (profile_def *)fl_entry->data;
324 if (profile && profile->is_global) {
325 parent = profile->name;
327 parent = get_profile_parent(name);
330 if (profile && profile->is_global && !profile_exists(parent, FALSE)) {
331 new_name = g_strdup(name);
333 new_name = g_strdup_printf("%s (copy)", name);
336 /* Add a new entry to the profile list. */
337 fl_entry = add_to_profile_list(new_name, parent, PROF_STAT_COPY, FALSE, profile ? profile->from_global : FALSE);
339 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
340 gtk_list_store_append(store, &iter);
341 gtk_list_store_set(store, &iter, NAME_COLUMN, new_name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
342 /* Select the item. */
343 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
345 gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
346 gtk_widget_grab_focus(name_te);
352 profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
354 GtkWidget *main_w = gtk_widget_get_toplevel(w);
355 GtkWidget *name_te = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
356 GtkWidget *profile_l = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
357 profile_def *profile;
361 GtkTreeSelection *sel;
365 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
366 name = gtk_entry_get_text(GTK_ENTRY(name_te));
368 /* if something was selected */
369 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
370 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
371 if (fl_entry != NULL) {
372 profile = (profile_def *)fl_entry->data;
374 if ((strlen(name) > 0) && profile && !profile->is_global) {
375 if (profile->status != PROF_STAT_DEFAULT) {
376 g_free(profile->name);
377 profile->name = g_strdup(name);
378 if ((profile->status != PROF_STAT_NEW) &&
379 (profile->status != PROF_STAT_COPY)) {
380 profile->status = PROF_STAT_CHANGED;
382 gtk_list_store_set(GTK_LIST_STORE(model), &iter, NAME_COLUMN, name, -1);
390 profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
392 GtkWidget *main_w = gtk_widget_get_toplevel(w);
393 GtkWidget *profile_l = (GtkWidget *)g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
396 GtkTreeSelection *sel;
400 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
401 /* If something was selected */
402 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
403 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
405 if (fl_entry != NULL) {
406 remove_from_profile_list(fl_entry);
407 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
411 if (gtk_tree_model_get_iter_first(model, &iter)) {
412 gtk_tree_selection_select_iter(sel, &iter);
417 profile_dialog_new(void)
419 GtkWidget *main_w, /* main window */
420 *main_vb, /* main container */
421 *bbox, /* button container */
422 *ok_bt, /* "OK" button */
423 *apply_bt, /* "Apply" button */
424 *cancel_bt, /* "Cancel" button */
425 *help_bt; /* "Help" button */
426 GtkWidget *profile_vb, /* profile settings box */
442 GtkCellRenderer *renderer;
443 GtkTreeViewColumn *column;
444 GtkTreeSelection *sel;
445 GtkTreeIter *l_select;
446 gboolean has_global = has_global_profiles();
448 /* Get a pointer to a static variable holding the type of profile on
449 which we're working, so we can pass that pointer to callback
452 main_w = dlg_conf_window_new("Wireshark: Configuration Profiles");
453 gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
455 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
456 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
457 gtk_container_add(GTK_CONTAINER(main_w), main_vb);
458 gtk_widget_show(main_vb);
460 /* Container for each row of widgets */
461 profile_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
462 gtk_container_set_border_width(GTK_CONTAINER(profile_vb), 0);
463 gtk_box_pack_start(GTK_BOX(main_vb), profile_vb, TRUE, TRUE, 0);
464 gtk_widget_show(profile_vb);
466 /* Top row: Buttons and profile list */
467 top_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
468 gtk_box_pack_start(GTK_BOX(profile_vb), top_hb, TRUE, TRUE, 0);
469 gtk_widget_show(top_hb);
471 edit_fr = gtk_frame_new("Edit");
472 gtk_box_pack_start(GTK_BOX(top_hb), edit_fr, FALSE, FALSE, 0);
473 gtk_widget_show(edit_fr);
475 list_bb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, TRUE);
476 gtk_container_set_border_width(GTK_CONTAINER(list_bb), 5);
477 gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
478 gtk_widget_show(list_bb);
480 new_bt = ws_gtk_button_new_from_stock(GTK_STOCK_NEW);
481 g_signal_connect(new_bt, "clicked", G_CALLBACK(profile_new_bt_clicked_cb), NULL);
482 gtk_widget_show(new_bt);
483 gtk_box_pack_start(GTK_BOX(list_bb), new_bt, FALSE, FALSE, 0);
484 gtk_widget_set_tooltip_text(new_bt, "Create a new profile (with default properties)");
486 copy_bt = ws_gtk_button_new_from_stock(GTK_STOCK_COPY);
487 g_signal_connect(copy_bt, "clicked", G_CALLBACK(profile_copy_bt_clicked_cb), NULL);
488 gtk_widget_show(copy_bt);
489 gtk_box_pack_start(GTK_BOX(list_bb), copy_bt, FALSE, FALSE, 0);
490 gtk_widget_set_tooltip_text(copy_bt, "Copy the selected profile");
492 del_bt = ws_gtk_button_new_from_stock(GTK_STOCK_DELETE);
493 gtk_widget_set_sensitive(del_bt, FALSE);
494 g_signal_connect(del_bt, "clicked", G_CALLBACK(profile_del_bt_clicked_cb), NULL);
495 g_object_set_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY, del_bt);
496 gtk_widget_show(del_bt);
497 gtk_box_pack_start(GTK_BOX(list_bb), del_bt, FALSE, FALSE, 0);
498 gtk_widget_set_tooltip_text(del_bt, "Delete the selected profile");
500 profile_fr = gtk_frame_new("Configuration Profiles");
501 gtk_box_pack_start(GTK_BOX(top_hb), profile_fr, TRUE, TRUE, 0);
502 gtk_widget_show(profile_fr);
504 profile_sc = scrolled_window_new(NULL, NULL);
505 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(profile_sc),
508 gtk_container_set_border_width(GTK_CONTAINER(profile_sc), 5);
509 gtk_container_add(GTK_CONTAINER(profile_fr), profile_sc);
510 gtk_widget_show(profile_sc);
512 store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER);
513 profile_l = tree_view_new(GTK_TREE_MODEL(store));
514 /* Only show headers if having more than one column */
515 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), has_global);
517 renderer = gtk_cell_renderer_text_new();
518 column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", NAME_COLUMN, NULL);
519 gtk_tree_view_column_set_expand(column, TRUE);
520 gtk_tree_view_column_set_sort_column_id(column, NAME_COLUMN);
521 gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
523 renderer = gtk_cell_renderer_toggle_new();
524 column = gtk_tree_view_column_new_with_attributes("Global", renderer, "active", GLOBAL_COLUMN, NULL);
525 gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
526 gtk_widget_set_tooltip_text(gtk_tree_view_column_get_button(column),
527 "Global profiles will be copied to users profiles when used");
528 gtk_tree_view_column_set_visible(column, has_global);
530 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
531 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
532 g_signal_connect(sel, "changed", G_CALLBACK(profile_sel_list_cb), profile_vb);
533 g_signal_connect(profile_l, "button_press_event", G_CALLBACK(profile_button_press_cb), NULL);
534 g_signal_connect(profile_l, "key_release_event", G_CALLBACK(profile_key_release_cb), NULL);
535 g_object_set_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY, profile_l);
536 gtk_container_add(GTK_CONTAINER(profile_sc), profile_l);
537 gtk_widget_show(profile_l);
540 l_select = fill_list(main_w);
542 g_object_unref(G_OBJECT(store));
544 props_fr = gtk_frame_new("Properties");
545 gtk_box_pack_start(GTK_BOX(profile_vb), props_fr, FALSE, FALSE, 0);
546 gtk_widget_show(props_fr);
548 props_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
549 gtk_container_set_border_width(GTK_CONTAINER(props_vb), 5);
550 gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
551 gtk_widget_show(props_vb);
553 /* row: Profile name entry */
554 middle_hb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
555 gtk_box_pack_start(GTK_BOX(props_vb), middle_hb, TRUE, TRUE, 0);
556 gtk_widget_show(middle_hb);
558 name_lb = gtk_label_new("Profile name:");
559 gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 0);
560 gtk_widget_show(name_lb);
562 name_te = gtk_entry_new();
563 gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
564 g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
565 g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
567 gtk_widget_set_tooltip_text(name_te,
568 "A profile name cannot start or end with a period (.), and cannot"
569 " contain any of the following characters:\n \\ / : * ? \" < > |");
571 gtk_widget_set_tooltip_text(name_te, "A profile name cannot contain the '/' character");
573 gtk_widget_show(name_te);
575 /* button row(create all possible buttons and hide the unrequired later - it's a lot easier) */
576 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
577 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
578 gtk_widget_show(bbox);
580 ok_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
581 g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_dlg_ok_cb), NULL);
582 gtk_widget_set_tooltip_text(ok_bt, "Apply the profiles and close this dialog");
584 /* Catch the "activate" signal on the profile name and profile
585 list entries, so that if the user types Return
586 there, we act as if the "OK" button had been selected, as
587 happens if Return is typed if some widget that *doesn't*
588 handle the Return key has the input focus. */
589 dlg_set_activate(name_te, ok_bt);
591 apply_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
592 g_signal_connect(apply_bt, "clicked", G_CALLBACK(profile_dlg_apply_cb), NULL);
593 gtk_widget_set_tooltip_text(apply_bt, "Apply the profiles and keep this dialog open");
595 cancel_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
596 gtk_widget_set_tooltip_text(cancel_bt, "Cancel the changes");
597 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_dlg_cancel_cb), NULL);
598 window_set_cancel_button(main_w, cancel_bt, NULL);
600 help_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
601 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_CONFIG_PROFILES_DIALOG);
602 gtk_widget_set_tooltip_text(help_bt, "Show topic specific help");
605 gtk_widget_grab_default(ok_bt);
609 /* DO SELECTION THINGS *AFTER* SHOWING THE DIALOG! */
610 /* otherwise the updatings can get confused */
612 gtk_tree_selection_select_iter(sel, l_select);
617 gtk_widget_grab_focus(profile_l);
620 g_signal_connect(main_w, "delete_event", G_CALLBACK(profile_dlg_delete_event_cb), NULL);
621 g_signal_connect(main_w, "destroy", G_CALLBACK(profile_dlg_destroy_cb), NULL);
623 gtk_widget_show(main_w);
625 window_present(main_w);
632 select_profile_cb(GtkWidget *w _U_, gpointer data)
634 const gchar *current_profile = get_profile_name();
635 gchar *selected_profile = (gchar *)data;
637 if (strcmp(selected_profile, current_profile) != 0) {
638 change_configuration_profile(selected_profile);
643 profile_show_popup_cb(GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_)
645 GdkEventButton *bevent = (GdkEventButton *)event;
646 const gchar *profile_name = get_profile_name();
647 gboolean separator_added = FALSE;
649 profile_def *profile;
651 GtkWidget *menu_item;
653 menu = gtk_menu_new();
655 if (bevent->button != 1) {
656 GtkWidget *change_menu = menus_get_profiles_change_menu();
658 #if GTK_CHECK_VERSION(2,16,0)
659 GtkWidget *rename_menu = menus_get_profiles_rename_menu();
660 GtkWidget *delete_menu = menus_get_profiles_delete_menu();
661 if (strcmp(profile_name, DEFAULT_PROFILE) != 0) {
663 label = g_strdup_printf("Rename \"%s\"...", profile_name);
664 gtk_menu_item_set_label(GTK_MENU_ITEM(rename_menu), label);
666 label = g_strdup_printf("Delete \"%s\"", profile_name);
667 gtk_menu_item_set_label(GTK_MENU_ITEM(delete_menu), label);
670 gtk_menu_item_set_label(GTK_MENU_ITEM(rename_menu), "Rename...");
671 gtk_menu_item_set_label(GTK_MENU_ITEM(delete_menu), "Delete");
674 gtk_menu_item_set_submenu(GTK_MENU_ITEM(change_menu), menu);
678 fl_entry = current_profile_list();
679 while (fl_entry && fl_entry->data) {
680 profile = (profile_def *)fl_entry->data;
682 if (!profile->is_global || !profile_exists(profile->name, FALSE)) {
683 if (profile->is_global && !separator_added) {
684 menu_item = gtk_separator_menu_item_new();
685 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
686 gtk_widget_show(menu_item);
687 separator_added = TRUE;
689 menu_item = gtk_check_menu_item_new_with_label(profile->name);
690 if (strcmp(profile->name, profile_name)==0) {
691 /* Check current profile */
692 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), TRUE);
694 g_object_set(G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
695 g_signal_connect(menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup(profile->name));
696 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
697 gtk_widget_show(menu_item);
699 fl_entry = g_list_next(fl_entry);
702 if (bevent->button != 1) {
703 /* Second-click is handled in popup_menu_handler() */
707 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
708 bevent->button, bevent->time);
714 profile_name_edit_ok(GtkWidget *w _U_, gpointer parent_w)
716 gint operation = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "operation"));
717 GtkComboBox *combo_box = (GtkComboBox *)g_object_get_data(G_OBJECT(w), "create_from");
718 GtkWidget *entry = (GtkWidget *)g_object_get_data(G_OBJECT(w), "entry");
721 const gchar *new_name = gtk_entry_get_text(GTK_ENTRY(entry));
722 const gchar *profile_name = "";
723 gboolean from_global = FALSE;
724 char *pf_dir_path, *pf_dir_path2, *pf_filename, *valid_name;
726 if (strlen(new_name) == 0) {
729 valid_name = profile_name_is_valid(new_name);
730 if (valid_name != NULL) {
736 case PROF_OPERATION_NEW:
737 if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
738 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
739 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &profile_name, 1, &from_global, -1);
742 case PROF_OPERATION_RENAME:
743 profile_name = get_profile_name();
744 if (strcmp(new_name, profile_name) == 0) {
745 /* Rename without a change, do nothing */
746 window_destroy(GTK_WIDGET(parent_w));
751 g_assert_not_reached();
754 if (profile_exists(new_name, FALSE)) {
755 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
756 "The profile already exists:\n%s.", new_name);
760 /* Write recent file for profile we are leaving */
761 write_profile_recent();
764 case PROF_OPERATION_NEW:
765 if (create_persconffile_profile(new_name, &pf_dir_path) == -1) {
766 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
767 "Can't create directory\n\"%s\":\n%s.",
768 pf_dir_path, g_strerror(errno));
771 } else if (strlen(profile_name) &&
772 (copy_persconffile_profile(new_name, profile_name, from_global, &pf_filename,
773 &pf_dir_path, &pf_dir_path2) != 0))
775 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
776 "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
777 pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
781 g_free(pf_dir_path2);
783 change_configuration_profile(new_name);
786 case PROF_OPERATION_RENAME:
787 if (rename_persconffile_profile(profile_name, new_name,
788 &pf_dir_path, &pf_dir_path2) == -1) {
789 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
790 "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
791 pf_dir_path, pf_dir_path2, g_strerror(errno));
794 g_free(pf_dir_path2);
796 change_configuration_profile(new_name);
800 g_assert_not_reached();
803 window_destroy(GTK_WIDGET(parent_w));
807 profile_rename_cancel(GtkWidget *w _U_, gpointer parent_w)
809 window_destroy(GTK_WIDGET(parent_w));
813 profile_manage_profiles_dlg(gint operation)
815 GtkWidget *win, *main_grid, *main_vb, *bbox, *cancel_bt, *ok_bt;
816 GtkWidget *entry, *label;
817 GtkWidget *combo_box = NULL;
818 GtkCellRenderer *cell;
820 GtkTreeIter iter, parent;
821 gchar *window_title = NULL;
823 profile_def *profile;
824 const gchar *profile_name;
825 gboolean has_global = has_global_profiles();
827 profile_name = get_profile_name();
830 case PROF_OPERATION_NEW:
831 window_title = g_strdup("Create New Profile");
833 case PROF_OPERATION_RENAME:
834 window_title = g_strdup_printf("Rename: %s", profile_name);
837 g_assert_not_reached();
840 win = dlg_window_new(window_title);
841 g_free(window_title);
843 gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
844 gtk_window_resize(GTK_WINDOW(win), 400, 100);
846 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
847 gtk_container_add(GTK_CONTAINER(win), main_vb);
848 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
850 main_grid = ws_gtk_grid_new();
851 gtk_box_pack_start(GTK_BOX(main_vb), main_grid, FALSE, FALSE, 0);
852 ws_gtk_grid_set_column_spacing(GTK_GRID(main_grid), 10);
853 ws_gtk_grid_set_row_spacing(GTK_GRID(main_grid), 5);
855 if (operation == PROF_OPERATION_NEW) {
856 label = gtk_label_new("Create from:");
857 gtk_widget_set_tooltip_text(label, "All configuration files will be copied from this profile");
858 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), label, 0, 0, 1, 1);
859 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
861 store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
862 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
863 gtk_widget_set_tooltip_text(combo_box, "All configuration files will be copied from this profile");
865 cell = gtk_cell_renderer_text_new();
866 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
867 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
868 "text", 0, "sensitive", 2,
871 gtk_tree_store_append(store, &iter, NULL);
872 gtk_tree_store_set(store, &iter, 0, "", 1, FALSE, 2, TRUE, -1);
875 gtk_tree_store_append(store, &parent, NULL);
876 gtk_tree_store_set(store, &parent, 0, "Personal", 1, FALSE, 2, FALSE, -1);
880 fl_entry = current_profile_list();
882 while (fl_entry && fl_entry->data) {
883 profile = (profile_def *)fl_entry->data;
884 if (!profile->is_global) {
885 gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
886 gtk_tree_store_set(store, &iter, 0, profile->name, 1, FALSE, 2, TRUE, -1);
888 fl_entry = g_list_next(fl_entry);
892 gtk_tree_store_append(store, &parent, NULL);
893 gtk_tree_store_set(store, &parent, 0, "Global", 1, FALSE, 2, FALSE, -1);
894 fl_entry = current_profile_list();
896 while (fl_entry && fl_entry->data) {
897 profile = (profile_def *)fl_entry->data;
898 if (profile->is_global) {
899 gtk_tree_store_append(store, &iter, &parent);
900 gtk_tree_store_set(store, &iter, 0, profile->name, 1, TRUE, 2, TRUE, -1);
902 fl_entry = g_list_next(fl_entry);
905 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), combo_box, 1, 0, 1, 1);
906 g_object_unref(store);
909 label = gtk_label_new("Profile name:");
910 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), label, 0, 1, 1, 1);
911 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
913 entry = gtk_entry_new();
914 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), entry, 1, 1, 1, 1);
916 case PROF_OPERATION_NEW:
917 gtk_entry_set_text(GTK_ENTRY(entry), "New profile");
919 case PROF_OPERATION_RENAME:
920 gtk_entry_set_text(GTK_ENTRY(entry), profile_name);
923 g_assert_not_reached();
927 gtk_widget_set_tooltip_text(entry,
928 "A profile name cannot start or end with a period (.), and cannot"
929 " contain any of the following characters:\n \\ / : * ? \" < > |");
931 gtk_widget_set_tooltip_text(entry, "A profile name cannot contain the '/' character");
934 bbox = dlg_button_row_new(GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL);
935 gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
937 ok_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
938 g_object_set_data(G_OBJECT(ok_bt), "entry", entry);
939 g_object_set_data(G_OBJECT(ok_bt), "create_from", combo_box);
940 g_object_set_data(G_OBJECT(ok_bt), "operation", GINT_TO_POINTER(operation));
941 g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_name_edit_ok), win);
943 dlg_set_activate(entry, ok_bt);
944 gtk_widget_grab_focus(entry);
946 cancel_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
947 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_rename_cancel), win);
948 window_set_cancel_button(win, cancel_bt, NULL);
950 gtk_widget_grab_default(ok_bt);
951 gtk_widget_show_all(win);
955 profile_new_cb(GtkWidget *w _U_, gpointer data _U_)
957 profile_manage_profiles_dlg(PROF_OPERATION_NEW);
961 profile_delete_cb(GtkWidget *w _U_, gpointer data _U_)
963 if (delete_current_profile()) {
964 /* Change to the default profile (we have to do this ourselves). */
965 change_configuration_profile(NULL);
970 profile_rename_cb(GtkWidget *w _U_, gpointer data _U_)
972 profile_manage_profiles_dlg(PROF_OPERATION_RENAME);
975 /* Create a profile dialog for editing display profiles; this is to be used
976 as a callback for menu items, toolbars, etc.. */
978 profile_dialog_cb(GtkWidget *w _U_)
980 /* Has a profiles dialog box already been opened */
981 if (global_profile_w != NULL) {
982 /* Yes. Just reactivate it. */
983 reactivate_window(global_profile_w);
985 global_profile_w = profile_dialog_new();
990 * Editor modelines - http://www.wireshark.org/tools/modelines.html
995 * indent-tabs-mode: nil
998 * vi: set shiftwidth=2 tabstop=8 expandtab:
999 * :indentSize=2:tabSize=8:noTabs=true: