merge_all_tap_menus() has been moved to menus.c.
[obnox/wireshark/wip.git] / gtk / profile_dlg.c
index 5cfe00d84d2e066c9d75cea580f09b73b6f271bc..16d719f5d4488fc08f94fc437930ffc8c809ed39 100644 (file)
@@ -31,6 +31,9 @@
 
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
+#if GTK_CHECK_VERSION(3,0,0)
+# include <gdk/gdkkeysyms-compat.h>
+#endif
 
 #include <epan/filesystem.h>
 #include <epan/prefs.h>
 #include "gtk/gtkglobals.h"
 #include "gtk/help_dlg.h"
 #include "gtk/recent.h"
-
+#include "gtk/old-gtk-compat.h"
+enum {
+  NAME_COLUMN,
+  GLOBAL_COLUMN,
+  DATA_COLUMN,
+  NUM_COLUMNS
+};
 
 #define E_PROF_PROFILE_L_KEY        "profile_profile_l"
 #define E_PROF_DEL_BT_KEY           "profile_del_bt"
@@ -63,17 +72,19 @@ static GList *edited_profiles = NULL;
 #define PROF_STAT_COPY     5
 
 #define PROF_OPERATION_NEW  1
-#define PROF_OPERATION_COPY 2
-#define PROF_OPERATION_EDIT 3
+#define PROF_OPERATION_EDIT 2
 
 typedef struct {
   char *name;           /* profile name */
   char *reference;      /* profile reference */
   int   status;
+  gboolean is_global;
+  gboolean from_global;
 } profile_def;
 
 static GList *
-add_profile_entry(GList *fl, const char *profilename, const char *reference, int status)
+add_profile_entry(GList *fl, const char *profilename, const char *reference, int status, 
+                 gboolean is_global, gboolean from_global)
 {
     profile_def *profile;
 
@@ -81,6 +92,8 @@ add_profile_entry(GList *fl, const char *profilename, const char *reference, int
     profile->name = g_strdup(profilename);
     profile->reference = g_strdup(reference);
     profile->status = status;
+    profile->is_global = is_global;
+    profile->from_global = from_global;
     return g_list_append(fl, profile);
 }
 
@@ -129,9 +142,11 @@ get_profile_parent (const gchar *profilename)
 }
 
 static GList *
-add_to_profile_list(const char *name, const char *expression, int status)
+add_to_profile_list(const char *name, const char *expression, int status, 
+                   gboolean is_global, gboolean from_global)
 {
-  edited_profiles = add_profile_entry(edited_profiles, name, expression, status);
+  edited_profiles = add_profile_entry(edited_profiles, name, expression, status,
+                                     is_global, from_global);
 
   return g_list_last(edited_profiles);
 }
@@ -182,7 +197,8 @@ copy_profile_list(void)
         profile = (flp_src)->data;
 
         current_profiles = add_profile_entry(current_profiles, profile->name,
-                                            profile->reference, profile->status);
+                                            profile->reference, profile->status, 
+                                            profile->is_global, profile->from_global);
         flp_src = g_list_next(flp_src);
     }
 }
@@ -205,9 +221,9 @@ fill_list(GtkWidget *main_w)
   profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
   store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
 
-  fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT);
+  fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT, FALSE, FALSE);
   gtk_list_store_append(store, &iter);
-  gtk_list_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, fl_entry, -1);
+  gtk_list_store_set(store, &iter, NAME_COLUMN, DEFAULT_PROFILE, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
   if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
     l_select = g_memdup(&iter, sizeof(iter));
   }
@@ -220,10 +236,10 @@ fill_list(GtkWidget *main_w)
       filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
 
       if (test_for_directory(filename) == EISDIR) {
-       fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS);
-       profile    = (profile_def *) fl_entry->data;
+       fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS, FALSE, FALSE);
+       profile = (profile_def *) fl_entry->data;
        gtk_list_store_append(store, &iter);
-       gtk_list_store_set(store, &iter, 0, profile->name, 1, fl_entry, -1);
+       gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
 
        if (profile->name) {
          if (strcmp(profile_name, profile->name) == 0) {
@@ -241,6 +257,23 @@ fill_list(GtkWidget *main_w)
     ws_dir_close (dir);
   }
 
+  profiles_dir = get_global_profiles_dir();
+  if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+    while ((file = ws_dir_read_name(dir)) != NULL) {
+      name = ws_dir_get_name(file);
+      filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
+
+      if (test_for_directory(filename) == EISDIR) {
+       fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS, TRUE, TRUE);
+       profile = (profile_def *) fl_entry->data;
+       gtk_list_store_append(store, &iter);
+       gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, TRUE, DATA_COLUMN, fl_entry, -1);
+      }
+      g_free (filename);
+    }
+    ws_dir_close (dir);
+  }
+
   /* Make the current list and the edited list equal */
   copy_profile_list ();
 
@@ -299,13 +332,13 @@ profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
 
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
     if (fl_entry) {
       profile = (profile_def *) fl_entry->data;
-      if (profile_exists (profile->name)) {
+      if (profile_exists (profile->name, FALSE) || profile_exists (profile->name, TRUE)) {
        /* The new profile exists, change */
        change_configuration_profile (profile->name);
-      } else if (!profile_exists (get_profile_name())) {
+      } else if (!profile_exists (get_profile_name(), FALSE)) {
        /* The new profile does not exist, and the previous profile has
           been deleted.  Change to the default profile */
        change_configuration_profile (NULL);
@@ -350,18 +383,18 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
       if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                       "Can't create directory\n\"%s\":\n%s.",
-                      pf_dir_path, strerror(errno));
+                      pf_dir_path, g_strerror(errno));
         
         g_free(pf_dir_path);
       }
       profile1->status = PROF_STAT_EXISTS;
 
       if (profile1->reference) {
-        if (copy_persconffile_profile(profile1->name, profile1->reference, &pf_filename,
-                                      &pf_dir_path, &pf_dir_path2) == -1) {
+        if (copy_persconffile_profile(profile1->name, profile1->reference, profile1->from_global,
+                                     &pf_filename, &pf_dir_path, &pf_dir_path2) == -1) {
           simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                         "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
-                        pf_filename, pf_dir_path2, pf_dir_path, strerror(errno));
+                        pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
 
           g_free(pf_filename);
           g_free(pf_dir_path);
@@ -387,7 +420,7 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
        if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                        "Can't create directory\n\"%s\":\n%s.",
-                       pf_dir_path, strerror(errno));
+                       pf_dir_path, g_strerror(errno));
 
          g_free(pf_dir_path);
        }
@@ -403,7 +436,7 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
                                        &pf_dir_path, &pf_dir_path2) == -1) {
          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                        "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
-                       pf_dir_path, pf_dir_path2, strerror(errno));
+                       pf_dir_path, pf_dir_path2, g_strerror(errno));
 
          g_free(pf_dir_path);
          g_free(pf_dir_path2);
@@ -424,12 +457,14 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
     fl2 = g_list_first(edited_profiles);
     while (fl2) {
       profile2 = (profile_def *) fl2->data;
-      if (strcmp(profile1->name, profile2->name)==0) {
-       /* Profile exists in both lists */
-       found = TRUE;
-      } else if (strcmp(profile1->name, profile2->reference)==0) {
-       /* Profile has been renamed */
-       found = TRUE;
+      if (!profile2->is_global) {
+       if (strcmp(profile1->name, profile2->name)==0) {
+         /* Profile exists in both lists */
+         found = TRUE;
+       } else if (strcmp(profile1->name, profile2->reference)==0) {
+         /* Profile has been renamed */
+         found = TRUE;
+       }
       }
       fl2 = fl2->next;
     }
@@ -438,7 +473,7 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
       if (delete_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                      "Can't delete profile directory\n\"%s\":\n%s.",
-                     pf_dir_path, strerror(errno));
+                     pf_dir_path, g_strerror(errno));
 
        g_free(pf_dir_path);
       }
@@ -539,11 +574,11 @@ profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
   gint          sensitivity = FALSE;
 
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
     if (fl_entry) {
-      profile= (profile_def *) fl_entry->data;
-      name   = g_strdup(profile->name);
-      if (profile->status!=PROF_STAT_DEFAULT) {
+      profile = (profile_def *) fl_entry->data;
+      name = g_strdup(profile->name);
+      if ((profile->status != PROF_STAT_DEFAULT) && !profile->is_global) {
        sensitivity = TRUE;
       }
     }
@@ -588,11 +623,11 @@ profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   const gchar  *name = "New profile";
 
   /* Add a new entry to the profile list. */
-  fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW);
+  fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW, FALSE, FALSE);
 
   store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
   gtk_list_store_append(store, &iter);
-  gtk_list_store_set(store, &iter, 0, name, 1, fl_entry, -1);
+  gtk_list_store_set(store, &iter, NAME_COLUMN, name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
   /* Select the item. */
   gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
 
@@ -610,16 +645,39 @@ profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   GtkTreeIter   iter;
   GList        *fl_entry;
   const gchar  *name = gtk_entry_get_text(GTK_ENTRY(name_te));
+  const gchar  *parent = NULL;
   gchar        *new_name;
 
-  new_name = g_strdup_printf ("%s (copy)", name);
+  GtkTreeSelection *sel;
+  GtkTreeModel     *model;
+  profile_def   *profile = NULL;
+
+  sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
+  if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
+    if (fl_entry) {
+      profile = (profile_def *) fl_entry->data;
+    }
+  }
+
+  if (profile && profile->is_global) {
+    parent = profile->name;
+  } else {
+    parent = get_profile_parent (name);
+  }
+
+  if (profile && profile->is_global && !profile_exists (parent, FALSE)) {
+    new_name = g_strdup (name);
+  } else {
+    new_name = g_strdup_printf ("%s (copy)", name);
+  }
 
   /* Add a new entry to the profile list. */
-  fl_entry = add_to_profile_list(new_name, get_profile_parent(name), PROF_STAT_COPY);
+  fl_entry = add_to_profile_list(new_name, parent, PROF_STAT_COPY, FALSE, profile ? profile->from_global : FALSE);
 
   store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
   gtk_list_store_append(store, &iter);
-  gtk_list_store_set(store, &iter, 0, new_name, 1, fl_entry, -1);
+  gtk_list_store_set(store, &iter, NAME_COLUMN, new_name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
   /* Select the item. */
   gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
 
@@ -648,11 +706,11 @@ profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
 
   /* if something was selected */
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
     if (fl_entry != NULL) {
       profile = (profile_def *) fl_entry->data;
 
-      if (strlen(name) > 0 && profile) {
+      if (strlen(name) > 0 && profile && !profile->is_global) {
        if (profile->status != PROF_STAT_DEFAULT) {
          g_free(profile->name);
          profile->name = g_strdup(name);
@@ -660,7 +718,7 @@ profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
              (profile->status != PROF_STAT_COPY)) {
            profile->status = PROF_STAT_CHANGED;
          }
-         gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, name, -1);
+         gtk_list_store_set(GTK_LIST_STORE(model), &iter, NAME_COLUMN, name, -1);
        }
       }
     }
@@ -681,7 +739,7 @@ profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
   /* If something was selected */
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
 
     if (fl_entry != NULL) {
       remove_from_profile_list (fl_entry);
@@ -719,19 +777,17 @@ profile_dialog_new(void)
     *profile_fr,
     *edit_fr,
     *props_fr;
-  GtkTooltips       *tooltips;
   GtkListStore      *store;
   GtkCellRenderer   *renderer;
   GtkTreeViewColumn *column;
   GtkTreeSelection  *sel;
   GtkTreeIter       *l_select;
-
+  gboolean           has_global = has_global_profiles();
+  
   /* Get a pointer to a static variable holding the type of profile on
      which we're working, so we can pass that pointer to callback
      routines. */
 
-  tooltips = gtk_tooltips_new ();
-
   main_w = dlg_conf_window_new("Wireshark: Configuration Profiles");
   gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
 
@@ -764,15 +820,13 @@ profile_dialog_new(void)
   g_signal_connect(new_bt, "clicked", G_CALLBACK(profile_new_bt_clicked_cb), NULL);
   gtk_widget_show(new_bt);
   gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, new_bt,
-                       "Create a new profile (with default properties)", NULL);
+  gtk_widget_set_tooltip_text (new_bt, "Create a new profile (with default properties)");
 
   copy_bt = gtk_button_new_from_stock(GTK_STOCK_COPY);
   g_signal_connect(copy_bt, "clicked", G_CALLBACK(profile_copy_bt_clicked_cb), NULL);
   gtk_widget_show(copy_bt);
   gtk_box_pack_start (GTK_BOX (list_bb), copy_bt, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, copy_bt,
-                       "Copy the selected profile", NULL);
+  gtk_widget_set_tooltip_text (copy_bt,        "Copy the selected profile");
 
   del_bt = gtk_button_new_from_stock(GTK_STOCK_DELETE);
   gtk_widget_set_sensitive(del_bt, FALSE);
@@ -780,7 +834,7 @@ profile_dialog_new(void)
   g_object_set_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY, del_bt);
   gtk_widget_show(del_bt);
   gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, del_bt, "Delete the selected profile", NULL);
+  gtk_widget_set_tooltip_text (del_bt, "Delete the selected profile");
 
   profile_fr = gtk_frame_new("Configuration Profiles");
   gtk_box_pack_start(GTK_BOX(top_hb), profile_fr, TRUE, TRUE, 0);
@@ -794,13 +848,23 @@ profile_dialog_new(void)
   gtk_container_add(GTK_CONTAINER(profile_fr), profile_sc);
   gtk_widget_show(profile_sc);
 
-  store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
+  store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER);
   profile_l = tree_view_new(GTK_TREE_MODEL(store));
-  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), FALSE);
+  /* Only show headers if having more than one column */
+  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), has_global);
+
   renderer = gtk_cell_renderer_text_new();
-  column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
-  gtk_tree_view_column_set_sort_column_id(column, 0);
+  column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", NAME_COLUMN, NULL);
+  gtk_tree_view_column_set_expand(column, TRUE);
+  gtk_tree_view_column_set_sort_column_id(column, NAME_COLUMN);
+  gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
+
+  renderer = gtk_cell_renderer_toggle_new();
+  column = gtk_tree_view_column_new_with_attributes("Global", renderer, "active", GLOBAL_COLUMN, NULL);
   gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
+  gtk_widget_set_tooltip_text(gtk_tree_view_column_get_button(column), "Global profiles will be copied to users profiles when used");
+  gtk_tree_view_column_set_visible(column, has_global);
+
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
   gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
   g_signal_connect(sel, "changed", G_CALLBACK(profile_sel_list_cb), profile_vb);
@@ -838,9 +902,9 @@ profile_dialog_new(void)
   g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
   g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
 #ifdef _WIN32
-  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);
+  gtk_widget_set_tooltip_text (name_te, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n   \\ / : * ? \" < > |");
 #else
-  gtk_tooltips_set_tip (tooltips, name_te, "A profile name cannot contain the '/' character", NULL);
+  gtk_widget_set_tooltip_text (name_te, "A profile name cannot contain the '/' character");
 #endif
   gtk_widget_show(name_te);
 
@@ -851,7 +915,7 @@ profile_dialog_new(void)
 
   ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
   g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_dlg_ok_cb), NULL);
-  gtk_tooltips_set_tip (tooltips, ok_bt, "Apply the profiles and close this dialog", NULL);
+  gtk_widget_set_tooltip_text (ok_bt, "Apply the profiles and close this dialog");
 
   /* Catch the "activate" signal on the profile name and profile
      list entries, so that if the user types Return
@@ -862,16 +926,16 @@ profile_dialog_new(void)
 
   apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
   g_signal_connect(apply_bt, "clicked", G_CALLBACK(profile_dlg_apply_cb), NULL);
-  gtk_tooltips_set_tip (tooltips, apply_bt, "Apply the profiles and keep this dialog open", NULL);
+  gtk_widget_set_tooltip_text (apply_bt, "Apply the profiles and keep this dialog open");
 
   cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
-  gtk_tooltips_set_tip (tooltips, cancel_bt, "Cancel the changes", NULL);
+  gtk_widget_set_tooltip_text (cancel_bt, "Cancel the changes");
   g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_dlg_cancel_cb), NULL);
   window_set_cancel_button(main_w, cancel_bt, NULL);
 
   help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
   g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_CONFIG_PROFILES_DIALOG);
-  gtk_tooltips_set_tip (tooltips, help_bt, "Show topic specific help", NULL);
+  gtk_widget_set_tooltip_text (help_bt, "Show topic specific help");
 
   if(ok_bt) {
     gtk_widget_grab_default(ok_bt);
@@ -925,13 +989,30 @@ profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_
   menu = gtk_menu_new ();
 
   if (bevent->button != 1) {
-    GtkWidget *top_menu = menus_get_profiles_menu ();
-    gtk_menu_item_set_submenu (GTK_MENU_ITEM(top_menu), menu);
+    GtkWidget *change_menu = menus_get_profiles_change_menu ();
+
+#if GTK_CHECK_VERSION(2,16,0)
+    GtkWidget *edit_menu = menus_get_profiles_edit_menu ();
+    GtkWidget *delete_menu = menus_get_profiles_delete_menu ();
+    if (strcmp (profile_name, DEFAULT_PROFILE) != 0) {
+      gchar *label;
+      label = g_strdup_printf ("Edit \"%s\"...", profile_name);
+      gtk_menu_item_set_label (GTK_MENU_ITEM(edit_menu), label);
+      g_free (label);
+      label = g_strdup_printf ("Delete \"%s\"", profile_name);
+      gtk_menu_item_set_label (GTK_MENU_ITEM(delete_menu), label);
+      g_free (label);
+    } else {
+      gtk_menu_item_set_label (GTK_MENU_ITEM(edit_menu), "Edit...");
+      gtk_menu_item_set_label (GTK_MENU_ITEM(delete_menu), "Delete");
+    }
+#endif
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM(change_menu), menu);
   }
 
   /* Add a menu item for the Default profile */
   menu_item = gtk_check_menu_item_new_with_label (DEFAULT_PROFILE);
-  if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
+  if (strcmp (profile_name, DEFAULT_PROFILE) == 0) {
     /* Check current profile */
     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
   }
@@ -945,7 +1026,7 @@ profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_
     while ((file = ws_dir_read_name(dir)) != NULL) {
       name = ws_dir_get_name(file);
 
-      if (profile_exists(name)) {
+      if (profile_exists(name, FALSE)) {
        menu_item = gtk_check_menu_item_new_with_label (name);
        if (strcmp (name, profile_name)==0) {
          /* Check current profile */
@@ -960,6 +1041,42 @@ profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_
     ws_dir_close (dir);
   }
 
+  profiles_dir = get_global_profiles_dir();
+  if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+    GtkWidget *sub_menu = NULL;
+    gboolean   added_submenu = FALSE;
+  
+    while ((file = ws_dir_read_name(dir)) != NULL) {
+      name = ws_dir_get_name(file);
+
+      if (profile_exists(name, TRUE)) {
+       if (!added_submenu) {
+         menu_item =  gtk_separator_menu_item_new ();
+         gtk_menu_shell_append  (GTK_MENU_SHELL (menu), menu_item);
+         gtk_widget_show (menu_item);
+         
+         menu_item = gtk_menu_item_new_with_label ("New from Global");
+         gtk_menu_shell_append  (GTK_MENU_SHELL (menu), menu_item);
+         gtk_widget_show (menu_item);
+
+         sub_menu = gtk_menu_new ();
+         gtk_menu_item_set_submenu (GTK_MENU_ITEM(menu_item), sub_menu);
+
+         added_submenu = TRUE;
+       }
+
+       menu_item = gtk_menu_item_new_with_label (name);
+       g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
+       if (profile_exists(name, FALSE)) {
+         gtk_widget_set_sensitive(menu_item, FALSE);
+       }
+       gtk_menu_shell_append  (GTK_MENU_SHELL (sub_menu), menu_item);
+       gtk_widget_show (menu_item);
+      }
+    }
+    ws_dir_close (dir);
+  }
+
   if (bevent->button != 1) {
     /* Second-click is handled in popup_menu_handler() */
     return FALSE;
@@ -975,22 +1092,39 @@ static void
 profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
 {
   gint operation = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(w), "operation"));
-  GtkWidget *entry = g_object_get_data (G_OBJECT(w), "entry");
+  GtkComboBox  *combo_box = g_object_get_data (G_OBJECT(w), "create_from");
+  GtkWidget    *entry = g_object_get_data (G_OBJECT(w), "entry");
+  GtkTreeStore *store;
+  GtkTreeIter iter;
   const gchar *new_name =  gtk_entry_get_text(GTK_ENTRY(entry));
-  const gchar *profile_name = get_profile_name();
+  const gchar *profile_name = "";
+  gboolean     from_global = FALSE;
   char        *pf_dir_path, *pf_dir_path2, *pf_filename;
 
   if (strlen(new_name) == 0 || profile_is_invalid_name(new_name)) {
     return;
   }
 
-  if (operation == PROF_OPERATION_EDIT && strcmp(new_name, profile_name) == 0) {
-    /* Rename without a change, do nothing */
-    window_destroy(GTK_WIDGET(parent_w));
-    return;
+  switch (operation) {
+  case PROF_OPERATION_NEW:
+    if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
+      store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
+      gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &profile_name, 1, &from_global, -1);
+    }
+    break;
+  case PROF_OPERATION_EDIT:
+    profile_name = get_profile_name();
+    if (strcmp(new_name, profile_name) == 0) {
+      /* Rename without a change, do nothing */
+      window_destroy(GTK_WIDGET(parent_w));
+      return;
+    }
+    break;
+  default:
+    g_assert_not_reached();
   }
 
-  if (profile_exists (new_name)) {
+  if (profile_exists (new_name, FALSE)) {
     simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
                  "The profile already exists:\n%s.", new_name);
     return;
@@ -1004,33 +1138,22 @@ profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
     if (create_persconffile_profile(new_name, &pf_dir_path) == -1) {
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                    "Can't create directory\n\"%s\":\n%s.",
-                   pf_dir_path, strerror(errno));
+                   pf_dir_path, g_strerror(errno));
       
       g_free(pf_dir_path);
-    } else {
-      change_configuration_profile (new_name);
-    }
-    break;
-  case PROF_OPERATION_COPY:
-    if (create_persconffile_profile(new_name, &pf_dir_path) == -1) {
+    } else if (strlen (profile_name) && 
+              copy_persconffile_profile(new_name, profile_name, from_global, &pf_filename,
+                                        &pf_dir_path, &pf_dir_path2) == -1)
+    {
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                   "Can't create directory\n\"%s\":\n%s.",
-                   pf_dir_path, strerror(errno));
-      
+                   "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
+                   pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
+       
+      g_free(pf_filename);
       g_free(pf_dir_path);
+      g_free(pf_dir_path2);
     } else {
-      if (copy_persconffile_profile(new_name, profile_name, &pf_filename,
-                                   &pf_dir_path, &pf_dir_path2) == -1) {
-       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                     "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
-                     pf_filename, pf_dir_path2, pf_dir_path, strerror(errno));
-       
-       g_free(pf_filename);
-       g_free(pf_dir_path);
-       g_free(pf_dir_path2);
-      } else {
-       change_configuration_profile (new_name);
-      }
+      change_configuration_profile (new_name);
     }
     break;
   case PROF_OPERATION_EDIT:
@@ -1038,7 +1161,7 @@ profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
                                    &pf_dir_path, &pf_dir_path2) == -1) {
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                    "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
-                   pf_dir_path, pf_dir_path2, strerror(errno));
+                   pf_dir_path, pf_dir_path2, g_strerror(errno));
       
       g_free(pf_dir_path);
       g_free(pf_dir_path2);
@@ -1047,7 +1170,7 @@ profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
     }
     break;
   default:
-      g_assert_not_reached();
+    g_assert_not_reached();
   }
 
   window_destroy(GTK_WIDGET(parent_w));
@@ -1062,24 +1185,25 @@ profile_name_edit_cancel (GtkWidget *w _U_, gpointer parent_w)
 static void
 profile_name_edit_dlg (gint operation)
 {
+  WS_DIR      *dir;             /* scanned directory */
+  WS_DIRENT   *file;            /* current file */
   GtkWidget   *win, *main_tb, *main_vb, *bbox, *cancel_bt, *ok_bt;
-  GtkWidget   *entry, *label;
-  gchar       *window_title=NULL, *new_name;
-  const gchar *profile_name;
-  GtkTooltips *tooltips;
+  GtkWidget   *entry, *label, *combo_box=NULL;
+  GtkCellRenderer *cell;
+  GtkTreeStore    *store;
+  GtkTreeIter   iter, parent;
+  gchar       *window_title=NULL;
+  const gchar *profile_name, *profiles_dir, *name;
+  gboolean     has_global = has_global_profiles();
 
-  tooltips = gtk_tooltips_new();
   profile_name = get_profile_name();
 
   switch (operation) {
   case PROF_OPERATION_NEW:
     window_title = g_strdup ("Create New Profile");
     break;
-  case PROF_OPERATION_COPY:
-    window_title = g_strdup_printf ("Copy: %s", profile_name);
-    break;
   case PROF_OPERATION_EDIT:
-    window_title = g_strdup_printf ("Rename: %s", profile_name);
+    window_title = g_strdup_printf ("Edit: %s", profile_name);
     break;
   default:
     g_assert_not_reached();
@@ -1098,8 +1222,66 @@ profile_name_edit_dlg (gint operation)
   main_tb = gtk_table_new(2, 2, FALSE);
   gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
   gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
+  gtk_table_set_row_spacings(GTK_TABLE(main_tb), 5);
+
+  if (operation == PROF_OPERATION_NEW) {
+    label = gtk_label_new("Create from:");
+    gtk_widget_set_tooltip_text (label, "All configuration files will be copied from this profile");
+    gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 0, 1);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
+
+    store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+    combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL (store));
+    gtk_widget_set_tooltip_text (combo_box, "All configuration files will be copied from this profile");
+
+    cell = gtk_cell_renderer_text_new();
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
+    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
+                                   "text", 0, "sensitive", 2,
+                                   NULL);
+
+    gtk_tree_store_append(store, &iter, NULL);
+    gtk_tree_store_set(store, &iter, 0, "", 1, FALSE, 2, TRUE, -1);
+
+    if (has_global) {
+      gtk_tree_store_append(store, &parent, NULL);
+      gtk_tree_store_set(store, &parent, 0, "Personal", 1, FALSE, 2, FALSE, -1);
+    }
+
+    gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
+    gtk_tree_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, FALSE, 2, TRUE, -1);
+    profiles_dir = get_profiles_dir();
+    if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+      while ((file = ws_dir_read_name(dir)) != NULL) {
+       name = ws_dir_get_name(file);
+       if (profile_exists(name, FALSE)) {
+         gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
+         gtk_tree_store_set(store, &iter, 0, name, 1, FALSE, 2, TRUE, -1);
+       }
+      }
+      ws_dir_close (dir);
+    }
 
-  label = gtk_label_new(ep_strdup_printf("Profile name:"));
+    if (has_global) {
+      gtk_tree_store_append(store, &parent, NULL);
+      gtk_tree_store_set(store, &parent, 0, "Global", 1, FALSE, 2, FALSE, -1);
+      profiles_dir = get_global_profiles_dir();
+      if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+       while ((file = ws_dir_read_name(dir)) != NULL) {
+         name = ws_dir_get_name(file);
+         if (profile_exists(name, TRUE)) {
+           gtk_tree_store_append(store, &iter, &parent);
+           gtk_tree_store_set(store, &iter, 0, name, 1, TRUE, 2, TRUE, -1);
+         }
+       }
+       ws_dir_close (dir);
+      }
+    }
+    gtk_table_attach_defaults(GTK_TABLE(main_tb), combo_box, 1, 2, 0, 1);
+    g_object_unref(store);
+  }
+
+  label = gtk_label_new("Profile name:");
   gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 1, 2);
   gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
 
@@ -1109,11 +1291,6 @@ profile_name_edit_dlg (gint operation)
   case PROF_OPERATION_NEW:
     gtk_entry_set_text(GTK_ENTRY(entry), "New profile");
     break;
-  case PROF_OPERATION_COPY:
-    new_name = g_strdup_printf ("%s (copy)", profile_name);
-    gtk_entry_set_text(GTK_ENTRY(entry), new_name);
-    g_free (new_name);
-    break;
   case PROF_OPERATION_EDIT:
     gtk_entry_set_text(GTK_ENTRY(entry), profile_name);
     break;
@@ -1122,9 +1299,9 @@ profile_name_edit_dlg (gint operation)
     break;
   }
 #ifdef _WIN32
-  gtk_tooltips_set_tip (tooltips, entry, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n   \\ / : * ? \" < > |", NULL);
+  gtk_widget_set_tooltip_text (entry, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n   \\ / : * ? \" < > |");
 #else
-  gtk_tooltips_set_tip (tooltips, entry, "A profile name cannot contain the '/' character", NULL);
+  gtk_widget_set_tooltip_text (entry, "A profile name cannot contain the '/' character");
 #endif
 
   bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_OK, NULL);
@@ -1132,10 +1309,12 @@ profile_name_edit_dlg (gint operation)
 
   ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
   g_object_set_data (G_OBJECT(ok_bt), "entry", entry);
+  g_object_set_data (G_OBJECT(ok_bt), "create_from", combo_box);
   g_object_set_data (G_OBJECT(ok_bt), "operation", GINT_TO_POINTER(operation));
   g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_name_edit_ok), win);
 
   dlg_set_activate(entry, ok_bt);
+  gtk_widget_grab_focus(entry);
 
   cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
   g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_name_edit_cancel), win);
@@ -1151,23 +1330,17 @@ profile_new_cb (GtkWidget *w _U_, gpointer data _U_)
   profile_name_edit_dlg (PROF_OPERATION_NEW);
 }
 
-void
-profile_copy_cb (GtkWidget *w _U_, gpointer data _U_)
-{
-  profile_name_edit_dlg (PROF_OPERATION_COPY);
-}
-
 void
 profile_delete_cb (GtkWidget *w _U_, gpointer data _U_)
 {
   const gchar *name = get_profile_name();
   char        *pf_dir_path;
 
-  if (profile_exists(name) && strcmp (name, DEFAULT_PROFILE) != 0) {
+  if (profile_exists(name, FALSE) && strcmp (name, DEFAULT_PROFILE) != 0) {
     if (delete_persconffile_profile(name, &pf_dir_path) == -1) {
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                    "Can't delete profile directory\n\"%s\":\n%s.",
-                   pf_dir_path, strerror(errno));
+                   pf_dir_path, g_strerror(errno));
       
       g_free(pf_dir_path);
     }
@@ -1178,7 +1351,7 @@ profile_delete_cb (GtkWidget *w _U_, gpointer data _U_)
 }
 
 void
-profile_rename_cb (GtkWidget *w _U_, gpointer data _U_)
+profile_edit_cb (GtkWidget *w _U_, gpointer data _U_)
 {
   profile_name_edit_dlg (PROF_OPERATION_EDIT);
 }