2 * Dialog box for profiles editing
3 * Stig Bjørlykke <stig@bjorlykke.org>, 2008
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <gdk/gdkkeysyms.h>
35 #include <epan/filesystem.h>
36 #include <epan/prefs.h>
38 #include "../simple_dialog.h"
39 #include <wsutil/file_util.h>
42 #include "gtk/profile_dlg.h"
43 #include "gtk/dlg_utils.h"
44 #include "gtk/gui_utils.h"
45 #include "gtk/gtkglobals.h"
46 #include "gtk/help_dlg.h"
49 #define E_PROF_PROFILE_L_KEY "profile_profile_l"
50 #define E_PROF_COPY_BT_KEY "profile_copy_bt"
51 #define E_PROF_DEL_BT_KEY "profile_del_bt"
52 #define E_PROF_NAME_TE_KEY "profile_name_te"
54 static GtkWidget *global_profile_w = NULL;
55 static GList *current_profiles = NULL;
56 static GList *edited_profiles = NULL;
58 #define PROF_STAT_DEFAULT 1
59 #define PROF_STAT_EXISTS 2
60 #define PROF_STAT_NEW 3
61 #define PROF_STAT_CHANGED 4
62 #define PROF_STAT_COPY 5
65 char *name; /* profile name */
66 char *reference; /* profile reference */
71 add_profile_entry(GList *fl, const char *profilename, const char *reference, int status)
75 profile = (profile_def *) g_malloc(sizeof(profile_def));
76 profile->name = g_strdup(profilename);
77 profile->reference = g_strdup(reference);
78 profile->status = status;
79 return g_list_append(fl, profile);
83 remove_profile_entry(GList *fl, GList *fl_entry)
87 profile = (profile_def *) fl_entry->data;
88 g_free(profile->name);
89 g_free(profile->reference);
91 return g_list_remove_link(fl, fl_entry);
95 add_to_profile_list(const char *name, const char *expression, int status)
97 edited_profiles = add_profile_entry(edited_profiles, name, expression, status);
99 return g_list_last(edited_profiles);
103 remove_from_profile_list(GList *fl_entry)
105 edited_profiles = remove_profile_entry(edited_profiles, fl_entry);
109 empty_profile_list(gboolean edit_list)
114 flpp = &edited_profiles;
117 *flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
120 g_assert(g_list_length(*flpp) == 0);
123 flpp = ¤t_profiles;
126 *flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
129 g_assert(g_list_length(*flpp) == 0);
133 copy_profile_list(void)
136 profile_def *profile;
138 flp_src = edited_profiles;
140 /* throw away the "old" destination list - a NULL list is ok here */
141 empty_profile_list(FALSE);
143 /* copy the list entries */
145 profile = (flp_src)->data;
147 current_profiles = add_profile_entry(current_profiles, profile->name,
148 profile->reference, profile->status);
149 flp_src = g_list_next(flp_src);
155 fill_list(GtkWidget *main_w)
157 ETH_DIR *dir; /* scanned directory */
158 ETH_DIRENT *file; /* current file */
160 profile_def *profile;
161 GtkTreeView *profile_l;
163 GtkTreeIter iter, *l_select = NULL;
164 const gchar *profile_name = get_profile_name ();
165 const gchar *profiles_dir, *name;
168 profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
169 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
171 fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT);
172 gtk_list_store_append(store, &iter);
173 gtk_list_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, fl_entry, -1);
174 if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
175 l_select = g_memdup(&iter, sizeof(iter));
179 profiles_dir = get_profiles_dir();
180 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
181 while ((file = ws_dir_read_name(dir)) != NULL) {
182 name = ws_dir_get_name(file);
183 filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
185 if (test_for_directory(filename) == EISDIR) {
186 fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS);
187 profile = (profile_def *) fl_entry->data;
188 gtk_list_store_append(store, &iter);
189 gtk_list_store_set(store, &iter, 0, profile->name, 1, fl_entry, -1);
192 if (strcmp(profile_name, profile->name) == 0) {
194 * XXX - We're assuming that we can just copy a GtkTreeIter
195 * and use it later without any crashes. This may not be a
198 l_select = g_memdup(&iter, sizeof(iter));
207 /* Make the current list an the edited list equal */
208 copy_profile_list ();
214 profile_is_invalid_name(gchar *name)
216 gchar *message = NULL;
219 char *invalid_dir_char = "\\/:*?\"<>|";
220 gboolean invalid = FALSE;
223 for (i = 0; i < 9; i++) {
224 if (strchr(name, invalid_dir_char[i])) {
225 /* Invalid character in directory */
229 if (name[0] == '.' || name[strlen(name)-1] == '.') {
230 /* Profile name cannot start or end with period */
234 message = g_strdup_printf("start or end with period (.), or contain any of the following characters:\n"
235 " \\ / : * ? \" < > |");
238 if (strchr(name, '/')) {
239 /* Invalid character in directory */
240 message = g_strdup_printf("contain the '/' character.");
245 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "A profile name cannot %s\nProfiles unchanged.", message);
254 profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
257 profile_def *profile;
258 GtkTreeSelection *sel;
262 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
264 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
265 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
267 profile = (profile_def *) fl_entry->data;
268 if (profile_exists (profile->name)) {
269 /* The new profile exists, change */
270 change_configuration_profile (profile->name);
271 } else if (!profile_exists (get_profile_name())) {
272 /* The new profile does not exist, and the previous profile has
273 been deleted. Change to the default profile */
274 change_configuration_profile (NULL);
281 * Destroy the profile dialog box.
283 empty_profile_list (TRUE);
284 window_destroy(main_w);
289 profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
291 char *pf_dir_path, *pf_dir_path2;
293 profile_def *profile1, *profile2;
296 /* First validate all profile names */
297 fl1 = g_list_first(edited_profiles);
300 profile1 = (profile_def *) fl1->data;
301 g_strstrip(profile1->name);
302 if (profile_is_invalid_name(profile1->name)) {
305 fl1 = g_list_next(fl1);
308 /* Then create new and rename changed */
309 fl1 = g_list_first(edited_profiles);
312 profile1 = (profile_def *) fl1->data;
313 g_strstrip(profile1->name);
314 if (profile1->status == PROF_STAT_NEW) {
315 /* We do not create a directory for the default profile */
316 if (strcmp(profile1->name, DEFAULT_PROFILE)!=0) {
317 if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
318 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
319 "Can't create directory\n\"%s\":\n%s.",
320 pf_dir_path, strerror(errno));
324 profile1->status = PROF_STAT_EXISTS;
325 if (profile1->reference) {
326 g_free (profile1->reference);
328 profile1->reference = g_strdup(profile1->name);
330 } else if (profile1->status == PROF_STAT_CHANGED) {
331 if (strcmp(profile1->reference, profile1->name)!=0) {
332 /* Rename old profile directory to new */
333 if (rename_persconffile_profile(profile1->reference, profile1->name,
334 &pf_dir_path, &pf_dir_path2) == -1) {
335 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
336 "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
337 pf_dir_path, pf_dir_path2, strerror(errno));
341 profile1->status = PROF_STAT_EXISTS;
342 g_free (profile1->reference);
343 profile1->reference = g_strdup(profile1->name);
346 fl1 = g_list_next(fl1);
349 /* Last remove deleted */
350 fl1 = g_list_first(current_profiles);
353 profile1 = (profile_def *) fl1->data;
354 fl2 = g_list_first(edited_profiles);
356 profile2 = (profile_def *) fl2->data;
357 if (strcmp(profile1->name, profile2->name)==0) {
358 /* Profile exists in both lists */
360 } else if (strcmp(profile1->name, profile2->reference)==0) {
361 /* Profile has been renamed */
367 /* Exists in existing list and not in edited, this is a deleted profile */
368 if (delete_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
369 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
370 "Can't delete profile directory\n\"%s\":\n%s.",
371 pf_dir_path, strerror(errno));
376 fl1 = g_list_next(fl1);
380 profile_select(main_w, profile_l, destroy);
384 profile_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
386 GtkWidget *main_w = gtk_widget_get_toplevel(ok_bt);
387 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
390 * Apply the profile and destroy the dialog box.
392 profile_apply(main_w, profile_l, TRUE);
396 profile_dlg_apply_cb(GtkWidget *apply_bt, gpointer data _U_)
398 GtkWidget *main_w = gtk_widget_get_toplevel(apply_bt);
399 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
402 * Apply the profile, but don't destroy the dialog box.
404 profile_apply(main_w, profile_l, FALSE);
407 /* cancel button pressed, revert changes and exit dialog */
409 profile_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer data _U_)
411 GtkWidget *main_w = gtk_widget_get_toplevel(cancel_bt);
413 empty_profile_list (TRUE);
414 window_destroy(GTK_WIDGET(main_w));
417 /* Treat this as a cancel, by calling "profile_dlg_cancel_cb()" */
419 profile_dlg_delete_event_cb(GtkWidget *main_w, GdkEvent *event _U_,
422 profile_dlg_cancel_cb(main_w, data);
427 profile_dlg_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
429 global_profile_w = NULL;
434 profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
436 if (event->type == GDK_2BUTTON_PRESS) {
437 GtkWidget *main_w = gtk_widget_get_toplevel(list);
439 profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
446 profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
448 if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
449 GtkWidget *main_w = gtk_widget_get_toplevel(list);
451 profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
458 profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
460 GtkWidget *profile_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
461 GtkWidget *main_w = gtk_widget_get_toplevel(profile_l);
464 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
465 GtkWidget *copy_bt = g_object_get_data(G_OBJECT(main_w), E_PROF_COPY_BT_KEY);
466 GtkWidget *del_bt = g_object_get_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY);
467 profile_def *profile;
470 gint sensitivity = FALSE;
472 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
473 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
475 profile= (profile_def *) fl_entry->data;
476 name = g_strdup(profile->name);
477 if (profile->status!=PROF_STAT_DEFAULT) {
484 * Did you know that this function is called when the window is destroyed?
486 * This means that we have to:
488 * attach to the top-level window data items containing pointers to
489 * the widgets we affect here;
491 * give each of those widgets their own destroy callbacks;
493 * clear that pointer when the widget is destroyed;
495 * don't do anything to the widget if the pointer we get back is
498 * so that if we're called after any of the widgets we'd affect are
499 * destroyed, we know that we shouldn't do anything to those widgets.
501 if (name_te != NULL) {
502 gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
503 gtk_widget_set_sensitive(name_te, sensitivity);
506 gtk_widget_set_sensitive(copy_bt, sensitivity);
508 gtk_widget_set_sensitive(del_bt, sensitivity);
514 profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
516 GtkWidget *main_w = gtk_widget_get_toplevel(w);
517 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
518 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
522 const gchar *name = "New profile";
524 /* Add a new entry to the profile list. */
525 fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW);
527 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
528 gtk_list_store_append(store, &iter);
529 gtk_list_store_set(store, &iter, 0, name, 1, fl_entry, -1);
530 /* Select the item. */
531 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
533 gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
534 gtk_widget_grab_focus(name_te);
539 profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
541 GtkWidget *main_w = gtk_widget_get_toplevel(w);
542 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
543 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
547 const gchar *name = gtk_entry_get_text(GTK_ENTRY(name_te));
550 new_name = g_strdup_printf ("%s (copy)", name);
552 /* Add a new entry to the profile list. */
553 fl_entry = add_to_profile_list(new_name, name, PROF_STAT_COPY);
555 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
556 gtk_list_store_append(store, &iter);
557 gtk_list_store_set(store, &iter, 0, new_name, 1, fl_entry, -1);
558 /* Select the item. */
559 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
561 gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
562 gtk_widget_grab_focus(name_te);
569 profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
571 GtkWidget *main_w = gtk_widget_get_toplevel(w);
572 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
573 GtkWidget *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
574 profile_def *profile;
576 const gchar *name = "";
578 GtkTreeSelection *sel;
582 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
583 name = gtk_entry_get_text(GTK_ENTRY(name_te));
585 /* if something was selected */
586 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
587 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
588 if (fl_entry != NULL) {
589 profile = (profile_def *) fl_entry->data;
591 if (strlen(name) > 0 && profile) {
592 if (profile->status != PROF_STAT_DEFAULT) {
593 g_free(profile->name);
594 profile->name = g_strdup(name);
595 if (profile->status != PROF_STAT_NEW) {
596 profile->status = PROF_STAT_CHANGED;
598 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, name, -1);
606 profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
608 GtkWidget *main_w = gtk_widget_get_toplevel(w);
609 GtkWidget *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
612 GtkTreeSelection *sel;
616 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
617 /* If something was selected */
618 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
619 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
621 if (fl_entry != NULL) {
622 remove_from_profile_list (fl_entry);
623 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
627 if (gtk_tree_model_get_iter_first (model, &iter)) {
628 gtk_tree_selection_select_iter(sel, &iter);
633 profile_dialog_new(void)
635 GtkWidget *main_w, /* main window */
636 *main_vb, /* main container */
637 *bbox, /* button container */
638 *ok_bt, /* "OK" button */
639 *apply_bt, /* "Apply" button */
640 *cancel_bt, /* "Cancel" button */
641 *help_bt; /* "Help" button */
642 GtkWidget *profile_vb, /* profile settings box */
659 GtkTooltips *tooltips;
661 GtkCellRenderer *renderer;
662 GtkTreeViewColumn *column;
663 GtkTreeSelection *sel;
664 GtkTreeIter *l_select;
666 /* Get a pointer to a static variable holding the type of profile on
667 which we're working, so we can pass that pointer to callback
670 tooltips = gtk_tooltips_new ();
672 main_w = dlg_conf_window_new("Wireshark: Configuration Profiles");
673 gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
675 main_vb = gtk_vbox_new(FALSE, 0);
676 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
677 gtk_container_add(GTK_CONTAINER(main_w), main_vb);
678 gtk_widget_show(main_vb);
680 /* Container for each row of widgets */
681 profile_vb = gtk_vbox_new(FALSE, 0);
682 gtk_container_set_border_width(GTK_CONTAINER(profile_vb), 0);
683 gtk_container_add(GTK_CONTAINER(main_vb), profile_vb);
684 gtk_widget_show(profile_vb);
686 /* Top row: Buttons and profile list */
687 top_hb = gtk_hbox_new(FALSE, 0);
688 gtk_container_add(GTK_CONTAINER(profile_vb), top_hb);
689 gtk_widget_show(top_hb);
691 edit_fr = gtk_frame_new("Edit");
692 gtk_box_pack_start(GTK_BOX(top_hb), edit_fr, FALSE, FALSE, 0);
693 gtk_widget_show(edit_fr);
695 list_bb = gtk_vbox_new(TRUE, 0);
696 gtk_container_set_border_width(GTK_CONTAINER(list_bb), 5);
697 gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
698 gtk_widget_show(list_bb);
700 new_bt = gtk_button_new_from_stock(GTK_STOCK_NEW);
701 g_signal_connect(new_bt, "clicked", G_CALLBACK(profile_new_bt_clicked_cb), NULL);
702 gtk_widget_show(new_bt);
703 gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
704 gtk_tooltips_set_tip (tooltips, new_bt,
705 "Create a new profile (with default properties)", NULL);
708 copy_bt = gtk_button_new_from_stock(GTK_STOCK_COPY);
709 gtk_widget_set_sensitive(copy_bt, FALSE);
710 g_signal_connect(copy_bt, "clicked", G_CALLBACK(profile_copy_bt_clicked_cb), NULL);
711 g_object_set_data(G_OBJECT(main_w), E_PROF_COPY_BT_KEY, copy_bt);
712 gtk_widget_show(copy_bt);
713 gtk_box_pack_start (GTK_BOX (list_bb), copy_bt, FALSE, FALSE, 0);
714 gtk_tooltips_set_tip (tooltips, copy_bt,
715 "Copy the selected profile", NULL);
718 del_bt = gtk_button_new_from_stock(GTK_STOCK_DELETE);
719 gtk_widget_set_sensitive(del_bt, FALSE);
720 g_signal_connect(del_bt, "clicked", G_CALLBACK(profile_del_bt_clicked_cb), NULL);
721 g_object_set_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY, del_bt);
722 gtk_widget_show(del_bt);
723 gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
724 gtk_tooltips_set_tip (tooltips, del_bt, "Delete the selected profile", NULL);
726 profile_fr = gtk_frame_new("Configuration Profiles");
727 gtk_box_pack_start(GTK_BOX(top_hb), profile_fr, TRUE, TRUE, 0);
728 gtk_widget_show(profile_fr);
730 profile_sc = scrolled_window_new(NULL, NULL);
731 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(profile_sc),
734 gtk_container_set_border_width (GTK_CONTAINER (profile_sc), 5);
735 gtk_container_add(GTK_CONTAINER(profile_fr), profile_sc);
736 gtk_widget_show(profile_sc);
738 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
739 profile_l = tree_view_new(GTK_TREE_MODEL(store));
740 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), FALSE);
741 renderer = gtk_cell_renderer_text_new();
742 column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
743 gtk_tree_view_column_set_sort_column_id(column, 0);
744 gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
745 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
746 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
747 g_signal_connect(sel, "changed", G_CALLBACK(profile_sel_list_cb), profile_vb);
748 g_signal_connect(profile_l, "button_press_event", G_CALLBACK(profile_button_press_cb), NULL);
749 g_signal_connect(profile_l, "key_release_event", G_CALLBACK(profile_key_release_cb), NULL);
750 g_object_set_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY, profile_l);
751 gtk_container_add(GTK_CONTAINER(profile_sc), profile_l);
752 gtk_widget_show(profile_l);
755 l_select = fill_list(main_w);
757 g_object_unref(G_OBJECT(store));
759 props_fr = gtk_frame_new("Properties");
760 gtk_box_pack_start(GTK_BOX(profile_vb), props_fr, FALSE, FALSE, 0);
761 gtk_widget_show(props_fr);
763 props_vb = gtk_vbox_new(FALSE, 3);
764 gtk_container_set_border_width(GTK_CONTAINER(props_vb), 5);
765 gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
766 gtk_widget_show(props_vb);
768 /* row: Profile name entry */
769 middle_hb = gtk_hbox_new(FALSE, 3);
770 gtk_container_add(GTK_CONTAINER(props_vb), middle_hb);
771 gtk_widget_show(middle_hb);
773 name_lb = gtk_label_new("Profile name:");
774 gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 0);
775 gtk_widget_show(name_lb);
777 name_te = gtk_entry_new();
778 gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
779 g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
780 g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
782 gtk_tooltips_set_tip (tooltips, name_te, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n \\ / : * ? \" < > |", NULL);
784 gtk_tooltips_set_tip (tooltips, name_te, "A profile name cannot contain the '/' character", NULL);
786 gtk_widget_show(name_te);
788 /* button row (create all possible buttons and hide the unrequired later - it's a lot easier) */
789 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
790 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
791 gtk_widget_show(bbox);
793 ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
794 g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_dlg_ok_cb), NULL);
795 gtk_tooltips_set_tip (tooltips, ok_bt, "Apply the profiles and close this dialog", NULL);
797 /* Catch the "activate" signal on the profile name and profile
798 list entries, so that if the user types Return
799 there, we act as if the "OK" button had been selected, as
800 happens if Return is typed if some widget that *doesn't*
801 handle the Return key has the input focus. */
802 dlg_set_activate(name_te, ok_bt);
804 apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
805 g_signal_connect(apply_bt, "clicked", G_CALLBACK(profile_dlg_apply_cb), NULL);
806 gtk_tooltips_set_tip (tooltips, apply_bt, "Apply the profiles and keep this dialog open", NULL);
808 cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
809 gtk_tooltips_set_tip (tooltips, cancel_bt, "Cancel the changes", NULL);
810 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_dlg_cancel_cb), NULL);
811 window_set_cancel_button(main_w, cancel_bt, NULL);
813 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
814 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_CONFIG_PROFILES_DIALOG);
815 gtk_tooltips_set_tip (tooltips, help_bt, "Show topic specific help", NULL);
818 gtk_widget_grab_default(ok_bt);
822 /* DO SELECTION THINGS *AFTER* SHOWING THE DIALOG! */
823 /* otherwise the updatings can get confused */
825 gtk_tree_selection_select_iter(sel, l_select);
830 gtk_widget_grab_focus(profile_l);
833 g_signal_connect(main_w, "delete_event", G_CALLBACK(profile_dlg_delete_event_cb), NULL);
834 g_signal_connect(main_w, "destroy", G_CALLBACK(profile_dlg_destroy_cb), NULL);
836 gtk_widget_show(main_w);
838 window_present(main_w);
845 select_profile_cb (GtkWidget *w _U_, gpointer data)
847 const gchar *current_profile = get_profile_name ();
848 gchar *selected_profile = (gchar *) data;
850 if (strcmp (selected_profile, current_profile) != 0) {
851 change_configuration_profile (selected_profile);
856 profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event)
858 GdkEventButton *bevent = (GdkEventButton *)event;
859 const gchar *profile_name = get_profile_name ();
860 const gchar *profiles_dir, *name;
861 ETH_DIR *dir; /* scanned directory */
862 ETH_DIRENT *file; /* current file */
864 GtkWidget *menu_item;
866 menu = gtk_menu_new ();
868 /* Add a menu item for the Default profile */
869 menu_item = gtk_check_menu_item_new_with_label (DEFAULT_PROFILE);
870 if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
871 /* Check current profile */
872 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
874 g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
875 g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (DEFAULT_PROFILE));
876 gtk_menu_append (menu, menu_item);
877 gtk_widget_show (menu_item);
879 profiles_dir = get_profiles_dir();
880 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
881 while ((file = ws_dir_read_name(dir)) != NULL) {
882 name = ws_dir_get_name(file);
884 if (profile_exists(name)) {
885 menu_item = gtk_check_menu_item_new_with_label (name);
886 if (strcmp (name, profile_name)==0) {
887 /* Check current profile */
888 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
890 g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
891 g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
892 gtk_menu_append (menu, menu_item);
893 gtk_widget_show (menu_item);
898 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
899 bevent->button, bevent->time);
904 /* Create a profile dialog for editing display profiles; this is to be used
905 as a callback for menu items, toolbars, etc.. */
907 profile_dialog_cb(GtkWidget *w _U_)
909 /* Has a profiles dialog box already been opened */
910 if (global_profile_w != NULL) {
911 /* Yes. Just reactivate it. */
912 reactivate_window(global_profile_w);
914 global_profile_w = profile_dialog_new ();