<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -40,7 +40,14 @@ void cb_connect_to()
 {
     Shell *shell = shell_get_main_shell();
 
-    remote_dialog_show(shell-&gt;window);
+    connect_dialog_show(shell-&gt;window);
+}
+
+void cb_manage_hosts()
+{
+    Shell *shell = shell_get_main_shell();
+    
+    host_manager_show(shell-&gt;window);
 }
 
 void cb_save_graphic()</diff>
      <filename>hardinfo2/callbacks.c</filename>
    </modified>
    <modified>
      <diff>@@ -36,5 +36,6 @@ void cb_sync_manager();
 void cb_report_bug();
 void cb_donate();
 void cb_connect_to();
+void cb_manage_hosts();
 
 #endif	/* __CALLBACKS_H__ */</diff>
      <filename>hardinfo2/callbacks.h</filename>
    </modified>
    <modified>
      <diff>@@ -32,6 +32,7 @@
 
 static GtkActionEntry entries[] = {
     {&quot;InformationMenuAction&quot;, NULL, &quot;_Information&quot;},	/* name, stock id, label */
+    {&quot;RemoteMenuAction&quot;, NULL, &quot;_Remote&quot;},
     {&quot;ViewMenuAction&quot;, NULL, &quot;_View&quot;},
     {&quot;HelpMenuAction&quot;, NULL, &quot;_Help&quot;},
     {&quot;HelpMenuModulesAction&quot;, HI_STOCK_ABOUT_MODULES, &quot;About _Modules&quot;},
@@ -53,13 +54,18 @@ static GtkActionEntry entries[] = {
      G_CALLBACK(cb_sync_manager)},
      
     {&quot;ConnectToAction&quot;, GTK_STOCK_CONNECT,
-     &quot;_Connect to&quot;, NULL,
+     &quot;_Connect to...&quot;, NULL,
      NULL,
      G_CALLBACK(cb_connect_to)},
 
+    {&quot;ManageAction&quot;, GTK_STOCK_OPEN,
+     &quot;_Manage hosts...&quot;, NULL,
+     NULL,
+     G_CALLBACK(cb_manage_hosts)},
+
     {&quot;CopyAction&quot;, GTK_STOCK_COPY,
      &quot;_Copy to Clipboard&quot;, &quot;&lt;control&gt;C&quot;,
-     NULL,
+     &quot;Copy to clipboard&quot;,
      G_CALLBACK(cb_copy_to_clipboard)},
 
     {&quot;SaveGraphAction&quot;, GTK_STOCK_SAVE_AS,</diff>
      <filename>hardinfo2/menu.c</filename>
    </modified>
    <modified>
      <diff>@@ -63,12 +63,15 @@
  *    X forwarding, but that'll be local X11 info anyway]).
  */
 
-typedef struct _RemoteDialog RemoteDialog;
-typedef struct _HostEditorDialog HostEditorDialog;
+typedef struct _HostManager HostManager;
+typedef struct _HostDialog HostDialog;
 
-struct _RemoteDialog {
-    GKeyFile *key_file;
+typedef enum {
+  HOST_DIALOG_MODE_EDIT,
+  HOST_DIALOG_MODE_CONNECT
+} HostDialogMode;
 
+struct _HostManager {
     GtkWidget *dialog;
     GtkWidget *btn_connect, *btn_cancel;
     GtkWidget *btn_add, *btn_edit, *btn_remove;
@@ -80,7 +83,7 @@ struct _RemoteDialog {
     GtkTreeIter *selected_iter;
 };
 
-struct _HostEditorDialog {
+struct _HostDialog {
     GtkWidget *dialog;
     GtkWidget *notebook;
     
@@ -90,10 +93,14 @@ struct _HostEditorDialog {
     GtkWidget *cmb_type;
 };
 
-static RemoteDialog *remote_dialog_new(GtkWidget * parent);
-static void remote_dialog_destroy(RemoteDialog * rd);
+static HostManager *host_manager_new(GtkWidget * parent);
+static void host_manager_destroy(HostManager * rd);
+static HostDialog *host_dialog_new(GtkWidget * parent,
+                                   gchar * title,
+                                   HostDialogMode mode);
+static void host_dialog_destroy(HostDialog *hd);
 
-static gboolean remote_version_is_supported(RemoteDialog * rd)
+static gboolean remote_version_is_supported(HostManager * rd)
 {
     gint remote_ver;
     GtkWidget *dialog;
@@ -219,7 +226,7 @@ static ModuleAbout *remote_module_get_about()
     return NULL;
 }
 
-static gboolean load_module_list(RemoteDialog * rd)
+static gboolean load_module_list(HostManager * rd)
 {
     Shell *shell;
     GValueArray *modules;
@@ -296,7 +303,7 @@ static gboolean load_module_list(RemoteDialog * rd)
     return TRUE;
 }
 
-static void remote_connect(RemoteDialog * rd)
+static void remote_connect(HostManager * rd)
 {
     xmlrpc_init();
 
@@ -319,10 +326,21 @@ static void remote_connect(RemoteDialog * rd)
     shell_status_update(&quot;Done.&quot;);
 }
 
-void remote_dialog_show(GtkWidget * parent)
+void connect_dialog_show(GtkWidget * parent)
+{
+    HostDialog *he = host_dialog_new(parent, &quot;Connect to&quot;, HOST_DIALOG_MODE_CONNECT);
+
+    if (gtk_dialog_run(GTK_DIALOG(he-&gt;dialog)) == GTK_RESPONSE_ACCEPT) {
+        DEBUG(&quot;connecting&quot;);
+    }
+    
+    host_dialog_destroy(he);
+}
+
+void host_manager_show(GtkWidget * parent)
 {
     gboolean success;
-    RemoteDialog *rd = remote_dialog_new(parent);
+    HostManager *rd = host_manager_new(parent);
 
     if (gtk_dialog_run(GTK_DIALOG(rd-&gt;dialog)) == GTK_RESPONSE_ACCEPT) {
 	gtk_widget_hide(rd-&gt;dialog);
@@ -335,33 +353,28 @@ void remote_dialog_show(GtkWidget * parent)
 	shell_view_set_enabled(TRUE);
     }
 
-    remote_dialog_destroy(rd);
+    host_manager_destroy(rd);
 }
 
-static void populate_store(RemoteDialog * rd, GtkListStore * store)
+static void populate_store(HostManager * rd, GtkListStore * store)
 {
+    Shell *shell;
     GtkTreeIter iter;
     gchar *path;
     gchar **hosts;
     gint i, no_groups;
 
     gtk_list_store_clear(store);
-
-    gtk_list_store_append(store, &amp;iter);
-    gtk_list_store_set(store, &amp;iter,
-		       0, icon_cache_get_pixbuf(&quot;home.png&quot;),
-		       1, g_strdup(&quot;Local Computer&quot;),
-		       2, GINT_TO_POINTER(-1), -1);
-
-
-    hosts = g_key_file_get_groups(rd-&gt;key_file, &amp;no_groups);
+    shell = shell_get_main_shell();
+    
+    hosts = g_key_file_get_groups(shell-&gt;hosts, &amp;no_groups);
     DEBUG(&quot;%d hosts found&quot;, no_groups);
     for (i = 0; i &lt; no_groups; i++) {
 	gchar *icon;
 
 	DEBUG(&quot;host #%d: %s&quot;, i, hosts[i]);
 
-	icon = g_key_file_get_string(rd-&gt;key_file, hosts[i], &quot;icon&quot;, NULL);
+	icon = g_key_file_get_string(shell-&gt;hosts, hosts[i], &quot;icon&quot;, NULL);
 
 	gtk_list_store_append(store, &amp;iter);
 	gtk_list_store_set(store, &amp;iter,
@@ -376,22 +389,52 @@ static void populate_store(RemoteDialog * rd, GtkListStore * store)
     g_strfreev(hosts);
 }
 
-static void host_editor_combo_changed_cb(GtkComboBox * widget,
+static GtkTreeModel *host_dialog_get_completion_model(void)
+{
+    Shell *shell;
+    GtkListStore *store;
+    GtkTreeIter iter;
+    gchar **groups;
+    gint i = 0;
+    
+    shell = shell_get_main_shell();
+    
+    store = gtk_list_store_new(1, G_TYPE_STRING);
+    for (groups = g_key_file_get_groups(shell-&gt;hosts, NULL); groups[i]; i++) {
+        gtk_list_store_append(store, &amp;iter);
+        gtk_list_store_set(store, &amp;iter, 0, g_strdup(groups[i]), -1);
+    }
+    g_strfreev(groups);
+    
+    return GTK_TREE_MODEL(store);
+}
+
+static void host_combo_changed_cb(GtkComboBox * widget,
 					 gpointer user_data)
 {
-    HostEditorDialog *host_dlg = (HostEditorDialog *) user_data;
+    HostDialog *host_dlg = (HostDialog *) user_data;
+    const gint default_ports[] = { 4242, 22 };
     gint index;
 
     index = gtk_combo_box_get_active(widget);
     
     gtk_notebook_set_current_page(GTK_NOTEBOOK(host_dlg-&gt;notebook), index);
+    gtk_spin_button_set_value(GTK_SPIN_BUTTON(host_dlg-&gt;txt_port), default_ports[index]);
 }
 
-static HostEditorDialog *host_editor_dialog_new(GtkWidget * parent,
-						gchar * title)
+static void host_dialog_destroy(HostDialog *rd)
 {
-    HostEditorDialog *host_dlg;
+    gtk_widget_destroy(rd-&gt;dialog);
+    g_free(rd);
+}
 
+static HostDialog *host_dialog_new(GtkWidget * parent,
+                                   gchar * title,
+                                   HostDialogMode mode)
+{
+    HostDialog *host_dlg;
+    GtkEntryCompletion *completion;
+    GtkTreeModel *completion_model;
     GtkWidget *dialog;
     GtkWidget *dialog_vbox1;
     GtkWidget *vbox1;
@@ -400,8 +443,8 @@ static HostEditorDialog *host_editor_dialog_new(GtkWidget * parent,
     GtkWidget *label5;
     GtkWidget *txt_hostname;
     GtkWidget *alignment2;
-    GtkObject *spn_port_adj;
-    GtkWidget *spn_port;
+    GtkObject *txt_port_adj;
+    GtkWidget *txt_port;
     GtkWidget *frame1;
     GtkWidget *alignment3;
     GtkWidget *notebook1;
@@ -482,10 +525,10 @@ static HostEditorDialog *host_editor_dialog_new(GtkWidget * parent,
 		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
 		     (GtkAttachOptions) (GTK_FILL), 0, 0);
 
-    spn_port_adj = gtk_adjustment_new(4242, 1025, 65535, 1, 10, 0);
-    spn_port = gtk_spin_button_new(GTK_ADJUSTMENT(spn_port_adj), 1, 0);
-    gtk_widget_show(spn_port);
-    gtk_container_add(GTK_CONTAINER(alignment2), spn_port);
+    txt_port_adj = gtk_adjustment_new(4242, 1, 65535, 1, 10, 0);
+    txt_port = gtk_spin_button_new(GTK_ADJUSTMENT(txt_port_adj), 1, 0);
+    gtk_widget_show(txt_port);
+    gtk_container_add(GTK_CONTAINER(alignment2), txt_port);
 
     frame1 = gtk_frame_new(NULL);
     gtk_widget_show(frame1);
@@ -569,35 +612,36 @@ static HostEditorDialog *host_editor_dialog_new(GtkWidget * parent,
 		     (GtkAttachOptions) (0), 0, 0);
     gtk_misc_set_alignment(GTK_MISC(label11), 0, 0.5);
 
-    hbox3 = gtk_hbox_new(FALSE, 4);
-    gtk_widget_show(hbox3);
-    gtk_box_pack_end(GTK_BOX(vbox3), hbox3, TRUE, TRUE, 0);
-
-    image2 =
-	gtk_image_new_from_stock(&quot;gtk-dialog-warning&quot;,
-				 GTK_ICON_SIZE_SMALL_TOOLBAR);
-    gtk_widget_show(image2);
-    gtk_box_pack_start(GTK_BOX(hbox3), image2, FALSE, FALSE, 0);
-    gtk_misc_set_alignment(GTK_MISC(image2), 0.5, 0);
-
-    label12 =
-	gtk_label_new
-	(&quot;&lt;small&gt;&lt;i&gt;The password will be saved in clear text on &lt;b&gt;~/.hardinfo/remote.conf&lt;/b&gt;. Passwordless RSA keys can be used instead.&lt;/i&gt;&lt;/small&gt;&quot;);
-    gtk_widget_show(label12);
-    gtk_box_pack_start(GTK_BOX(hbox3), label12, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label12), TRUE);
-    gtk_label_set_line_wrap(GTK_LABEL(label12), TRUE);
-    gtk_misc_set_alignment(GTK_MISC(label12), 0, 0.5);
-    gtk_label_set_width_chars(GTK_LABEL(label12), 36);
+    if (mode == HOST_DIALOG_MODE_EDIT) {
+        hbox3 = gtk_hbox_new(FALSE, 4);
+        gtk_widget_show(hbox3);
+        gtk_box_pack_end(GTK_BOX(vbox3), hbox3, TRUE, TRUE, 0);
+
+        image2 =
+            gtk_image_new_from_stock(&quot;gtk-dialog-warning&quot;,
+                                     GTK_ICON_SIZE_SMALL_TOOLBAR);
+        gtk_widget_show(image2);
+        gtk_box_pack_start(GTK_BOX(hbox3), image2, FALSE, FALSE, 0);
+        gtk_misc_set_alignment(GTK_MISC(image2), 0.5, 0);
+
+        label12 =
+            gtk_label_new
+            (&quot;&lt;small&gt;&lt;i&gt;The password will be saved in clear text on &lt;b&gt;~/.hardinfo/remote.conf&lt;/b&gt;. Passwordless RSA keys can be used instead.&lt;/i&gt;&lt;/small&gt;&quot;);
+        gtk_widget_show(label12);
+        gtk_box_pack_start(GTK_BOX(hbox3), label12, FALSE, FALSE, 0);
+        gtk_label_set_use_markup(GTK_LABEL(label12), TRUE);
+        gtk_label_set_line_wrap(GTK_LABEL(label12), TRUE);
+        gtk_misc_set_alignment(GTK_MISC(label12), 0, 0.5);
+        gtk_label_set_width_chars(GTK_LABEL(label12), 36);
+    }
 
     hbox1 = gtk_hbox_new(FALSE, 4);
     gtk_widget_show(hbox1);
     gtk_frame_set_label_widget(GTK_FRAME(frame1), hbox1);
 
-    label3 = gtk_label_new(&quot;&lt;b&gt;Type:&lt;/b&gt;&quot;);
+    label3 = gtk_label_new(&quot;Type:&quot;);
     gtk_widget_show(label3);
     gtk_box_pack_start(GTK_BOX(hbox1), label3, FALSE, FALSE, 0);
-    gtk_label_set_use_markup(GTK_LABEL(label3), TRUE);
 
     cmb_type = gtk_combo_box_new_text();
     gtk_widget_show(cmb_type);
@@ -611,57 +655,111 @@ static HostEditorDialog *host_editor_dialog_new(GtkWidget * parent,
     gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area1),
 			      GTK_BUTTONBOX_END);
 
-    btn_cancel = gtk_button_new_from_stock(&quot;gtk-cancel&quot;);
+    btn_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
     gtk_widget_show(btn_cancel);
     gtk_dialog_add_action_widget(GTK_DIALOG(dialog), btn_cancel,
 				 GTK_RESPONSE_CANCEL);
     GTK_WIDGET_SET_FLAGS(btn_cancel, GTK_CAN_DEFAULT);
 
-    btn_save = gtk_button_new_from_stock(&quot;gtk-save&quot;);
+    if (mode == HOST_DIALOG_MODE_EDIT) {
+        btn_save = gtk_button_new_from_stock(GTK_STOCK_SAVE);
+    } else if (mode == HOST_DIALOG_MODE_CONNECT) {
+        btn_save = gtk_button_new_from_stock(GTK_STOCK_CONNECT);
+    }
     gtk_widget_show(btn_save);
     gtk_dialog_add_action_widget(GTK_DIALOG(dialog), btn_save,
 				 GTK_RESPONSE_ACCEPT);
     GTK_WIDGET_SET_FLAGS(btn_save, GTK_CAN_DEFAULT);
 
-    host_dlg = g_new0(HostEditorDialog, 1);
+    host_dlg = g_new0(HostDialog, 1);
     host_dlg-&gt;dialog = dialog;
     host_dlg-&gt;notebook = notebook1;
     host_dlg-&gt;txt_hostname = txt_hostname;
-    host_dlg-&gt;txt_port = spn_port;
+    host_dlg-&gt;txt_port = txt_port;
     host_dlg-&gt;txt_ssh_user = txt_ssh_user;
     host_dlg-&gt;txt_ssh_password = txt_ssh_password;
     host_dlg-&gt;cmb_type = cmb_type;
 
+    completion = gtk_entry_completion_new();
+    gtk_entry_set_completion(GTK_ENTRY(host_dlg-&gt;txt_hostname), completion);
+    g_object_unref(completion);
+    
+    completion_model = host_dialog_get_completion_model();
+    gtk_entry_completion_set_model(completion, completion_model);
+    g_object_unref(completion_model);
+    
+    gtk_entry_completion_set_text_column(completion, 0);
+    
     gtk_combo_box_set_active(GTK_COMBO_BOX(host_dlg-&gt;cmb_type), 0);
     g_signal_connect(G_OBJECT(cmb_type), &quot;changed&quot;,
-		     G_CALLBACK(host_editor_combo_changed_cb), host_dlg);
+		     G_CALLBACK(host_combo_changed_cb), host_dlg);
 
     return host_dlg;
 }
 
-static void remote_dialog_add(GtkWidget * button, gpointer data)
+static void host_manager_add(GtkWidget * button, gpointer data)
 {
-    RemoteDialog *rd = (RemoteDialog *) data;
-    HostEditorDialog *he =
-	host_editor_dialog_new(rd-&gt;dialog, &quot;Add a host&quot;);
+    Shell *shell = shell_get_main_shell();
+    HostManager *rd = (HostManager *) data;
+    HostDialog *he =
+	host_dialog_new(rd-&gt;dialog, &quot;Add a host&quot;, HOST_DIALOG_MODE_EDIT);
 
+retry:
     if (gtk_dialog_run(GTK_DIALOG(he-&gt;dialog)) == GTK_RESPONSE_ACCEPT) {
-	DEBUG(&quot;saving&quot;);
+        const gchar *hostname = gtk_entry_get_text(GTK_ENTRY(he-&gt;txt_hostname));
+
+        if (g_key_file_has_group(shell-&gt;hosts, hostname)) {
+            GtkWidget *dialog;
+            
+            dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(rd-&gt;dialog),
+                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                        GTK_MESSAGE_ERROR,
+                                                        GTK_BUTTONS_CLOSE,
+                                                        &quot;Hostname &lt;b&gt;%s&lt;/b&gt; already exists.&quot;, hostname);
+
+            gtk_dialog_run(GTK_DIALOG(dialog));
+            gtk_widget_destroy(dialog);
+            
+            goto retry;
+        } else {
+            GtkTreeIter iter;
+            const gchar *type[] = { &quot;direct&quot;, &quot;ssh&quot; };
+            const gint selected_type = gtk_combo_box_get_active(GTK_COMBO_BOX(he-&gt;cmb_type));
+            const gint port = (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(he-&gt;txt_port));
+
+            g_key_file_set_string(shell-&gt;hosts, hostname, &quot;type&quot;, type[selected_type]);
+            g_key_file_set_integer(shell-&gt;hosts, hostname, &quot;port&quot;, port);
+            
+            if (selected_type == 1) {
+                const gchar *username = gtk_entry_get_text(GTK_ENTRY(he-&gt;txt_ssh_user));
+                const gchar *password = gtk_entry_get_text(GTK_ENTRY(he-&gt;txt_ssh_password));
+                
+                g_key_file_set_string(shell-&gt;hosts, hostname, &quot;username&quot;, username);
+                g_key_file_set_string(shell-&gt;hosts, hostname, &quot;password&quot;, password);
+            }
+
+            gtk_list_store_append(rd-&gt;tree_store, &amp;iter);
+            gtk_list_store_set(rd-&gt;tree_store, &amp;iter,
+                               0, icon_cache_get_pixbuf(&quot;server.png&quot;),
+                               1, g_strdup(hostname),
+                               2, 0,
+                               -1);
+        }
     }
 
-    gtk_widget_destroy(he-&gt;dialog);
-    g_free(he);
+    host_dialog_destroy(he);
 }
 
-static void remote_dialog_edit(GtkWidget * button, gpointer data)
+static void host_manager_edit(GtkWidget * button, gpointer data)
 {
+    Shell *shell = shell_get_main_shell();
     GtkWidget *dialog;
-    RemoteDialog *rd = (RemoteDialog *) data;
-    HostEditorDialog *he = host_editor_dialog_new(rd-&gt;dialog, &quot;Edit a host&quot;);
+    HostManager *rd = (HostManager *) data;
+    HostDialog *he = host_dialog_new(rd-&gt;dialog, &quot;Edit a host&quot;, HOST_DIALOG_MODE_EDIT);
     gchar *host_type;
     gint host_port;
     
-    host_type = g_key_file_get_string(rd-&gt;key_file, rd-&gt;selected_name, &quot;type&quot;, NULL);
+    host_type = g_key_file_get_string(shell-&gt;hosts, rd-&gt;selected_name, &quot;type&quot;, NULL);
     if (!host_type || g_str_equal(host_type, &quot;direct&quot;)) {
         gtk_combo_box_set_active(GTK_COMBO_BOX(he-&gt;cmb_type), 0);
     } else if (g_str_equal(host_type, &quot;ssh&quot;)) {
@@ -669,13 +767,13 @@ static void remote_dialog_edit(GtkWidget * button, gpointer data)
 
         gtk_combo_box_set_active(GTK_COMBO_BOX(he-&gt;cmb_type), 1);
 
-	username = g_key_file_get_string(rd-&gt;key_file, rd-&gt;selected_name, &quot;username&quot;, NULL);
+	username = g_key_file_get_string(shell-&gt;hosts, rd-&gt;selected_name, &quot;username&quot;, NULL);
 	if (username) {
 	    gtk_entry_set_text(GTK_ENTRY(he-&gt;txt_ssh_user), username);
 	    g_free(username);
 	}
 
-	password = g_key_file_get_string(rd-&gt;key_file, rd-&gt;selected_name, &quot;password&quot;, NULL);
+	password = g_key_file_get_string(shell-&gt;hosts, rd-&gt;selected_name, &quot;password&quot;, NULL);
 	if (password) {
 	    gtk_entry_set_text(GTK_ENTRY(he-&gt;txt_ssh_password), password);
 	    g_free(password);
@@ -696,7 +794,7 @@ static void remote_dialog_edit(GtkWidget * button, gpointer data)
 
     gtk_entry_set_text(GTK_ENTRY(he-&gt;txt_hostname), rd-&gt;selected_name);
     
-    host_port = g_key_file_get_integer(rd-&gt;key_file, rd-&gt;selected_name, &quot;port&quot;, NULL);
+    host_port = g_key_file_get_integer(shell-&gt;hosts, rd-&gt;selected_name, &quot;port&quot;, NULL);
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(he-&gt;txt_port), host_port ? host_port : 4242);
 
     if (gtk_dialog_run(GTK_DIALOG(he-&gt;dialog)) == GTK_RESPONSE_ACCEPT) {
@@ -704,14 +802,14 @@ static void remote_dialog_edit(GtkWidget * button, gpointer data)
     }
 
   bad:
-    gtk_widget_destroy(he-&gt;dialog);
-    g_free(he);
+    host_dialog_destroy(he);
     g_free(host_type);
 }
 
-static void remote_dialog_remove(GtkWidget * button, gpointer data)
+static void host_manager_remove(GtkWidget * button, gpointer data)
 {
-    RemoteDialog *rd = (RemoteDialog *) data;
+    Shell *shell = shell_get_main_shell();
+    HostManager *rd = (HostManager *) data;
     GtkWidget *dialog;
 
     dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(rd-&gt;dialog),
@@ -726,17 +824,20 @@ static void remote_dialog_remove(GtkWidget * button, gpointer data)
 			   GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT, NULL);
 
     if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
-	g_key_file_remove_group(rd-&gt;key_file, rd-&gt;selected_name, NULL);
+	g_key_file_remove_group(shell-&gt;hosts, rd-&gt;selected_name, NULL);
 	gtk_list_store_remove(rd-&gt;tree_store, rd-&gt;selected_iter);
+	
+	gtk_widget_set_sensitive(rd-&gt;btn_edit, FALSE);
+	gtk_widget_set_sensitive(rd-&gt;btn_remove, FALSE);
     }
 
     gtk_widget_destroy(dialog);
 }
 
-static void remote_dialog_tree_sel_changed(GtkTreeSelection * sel,
+static void host_manager_tree_sel_changed(GtkTreeSelection * sel,
 					   gpointer data)
 {
-    RemoteDialog *rd = (RemoteDialog *) data;
+    HostManager *rd = (HostManager *) data;
     GtkTreeModel *model;
     GtkTreeIter iter;
 
@@ -765,28 +866,17 @@ static void remote_dialog_tree_sel_changed(GtkTreeSelection * sel,
     }
 }
 
-static void remote_dialog_destroy(RemoteDialog * rd)
+static void host_manager_destroy(HostManager * rd)
 {
-    gchar *path, *remote_conf;
-    gsize length;
-
-    path =
-	g_build_filename(g_get_home_dir(), &quot;.hardinfo&quot;, &quot;remote.conf&quot;,
-			 NULL);
-
-    remote_conf = g_key_file_to_data(rd-&gt;key_file, &amp;length, NULL);
-    g_file_set_contents(path, remote_conf, length, NULL);
-
+    shell_save_hosts_file();
     gtk_widget_destroy(rd-&gt;dialog);
-
-    g_free(remote_conf);
-    g_free(path);
+    
     g_free(rd);
 }
 
-static RemoteDialog *remote_dialog_new(GtkWidget * parent)
+static HostManager *host_manager_new(GtkWidget * parent)
 {
-    RemoteDialog *rd;
+    HostManager *rd;
     gchar *path;
     GtkWidget *dialog;
     GtkWidget *dialog1_vbox;
@@ -807,10 +897,10 @@ static RemoteDialog *remote_dialog_new(GtkWidget * parent)
     GtkListStore *store;
     GtkTreeModel *model;
 
-    rd = g_new0(RemoteDialog, 1);
+    rd = g_new0(HostManager, 1);
 
     dialog = gtk_dialog_new();
-    gtk_window_set_title(GTK_WINDOW(dialog), &quot;Connect to Remote Computer&quot;);
+    gtk_window_set_title(GTK_WINDOW(dialog), &quot;Remote Host Manager&quot;);
     gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
     gtk_window_set_default_size(GTK_WINDOW(dialog), 420, 260);
     gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
@@ -824,6 +914,7 @@ static RemoteDialog *remote_dialog_new(GtkWidget * parent)
     gtk_container_set_border_width(GTK_CONTAINER(dialog1_vbox), 4);
     gtk_widget_show(dialog1_vbox);
 
+/*
     hbox = gtk_hbox_new(FALSE, 5);
     gtk_box_pack_start(GTK_BOX(dialog1_vbox), hbox, FALSE, FALSE, 0);
 
@@ -838,6 +929,7 @@ static RemoteDialog *remote_dialog_new(GtkWidget * parent)
 		       FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
     gtk_widget_show_all(hbox);
+*/
 
     hbox = gtk_hbox_new(FALSE, 5);
     gtk_box_pack_start(GTK_BOX(dialog1_vbox), hbox, TRUE, TRUE, 0);
@@ -888,20 +980,20 @@ static RemoteDialog *remote_dialog_new(GtkWidget * parent)
     gtk_container_add(GTK_CONTAINER(vbuttonbox3), button3);
     GTK_WIDGET_SET_FLAGS(button3, GTK_CAN_DEFAULT);
     g_signal_connect(button3, &quot;clicked&quot;,
-		     G_CALLBACK(remote_dialog_add), rd);
+		     G_CALLBACK(host_manager_add), rd);
 
     button6 = gtk_button_new_with_mnemonic(&quot;_Edit&quot;);
     gtk_widget_show(button6);
     gtk_container_add(GTK_CONTAINER(vbuttonbox3), button6);
     GTK_WIDGET_SET_FLAGS(button6, GTK_CAN_DEFAULT);
-    g_signal_connect(button6, &quot;clicked&quot;, G_CALLBACK(remote_dialog_edit),
+    g_signal_connect(button6, &quot;clicked&quot;, G_CALLBACK(host_manager_edit),
 		     rd);
 
     button2 = gtk_button_new_with_mnemonic(&quot;_Remove&quot;);
     gtk_widget_show(button2);
     gtk_container_add(GTK_CONTAINER(vbuttonbox3), button2);
     GTK_WIDGET_SET_FLAGS(button2, GTK_CAN_DEFAULT);
-    g_signal_connect(button2, &quot;clicked&quot;, G_CALLBACK(remote_dialog_remove),
+    g_signal_connect(button2, &quot;clicked&quot;, G_CALLBACK(host_manager_remove),
 		     rd);
 
     dialog1_action_area = GTK_DIALOG(dialog)-&gt;action_area;
@@ -915,18 +1007,19 @@ static RemoteDialog *remote_dialog_new(GtkWidget * parent)
 				 GTK_RESPONSE_CANCEL);
     GTK_WIDGET_SET_FLAGS(button8, GTK_CAN_DEFAULT);
 
+/*
     button7 = gtk_button_new_from_stock(GTK_STOCK_CONNECT);
     gtk_widget_show(button7);
     gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button7,
 				 GTK_RESPONSE_ACCEPT);
     GTK_WIDGET_SET_FLAGS(button7, GTK_CAN_DEFAULT);
-
+*/
     gtk_tree_view_collapse_all(GTK_TREE_VIEW(treeview2));
 
     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview2));
 
     g_signal_connect(G_OBJECT(sel), &quot;changed&quot;,
-		     (GCallback) remote_dialog_tree_sel_changed, rd);
+		     (GCallback) host_manager_tree_sel_changed, rd);
 
     rd-&gt;dialog = dialog;
     rd-&gt;btn_cancel = button8;
@@ -936,13 +1029,6 @@ static RemoteDialog *remote_dialog_new(GtkWidget * parent)
     rd-&gt;btn_remove = button2;
     rd-&gt;tree_store = store;
 
-    rd-&gt;key_file = g_key_file_new();
-    path =
-	g_build_filename(g_get_home_dir(), &quot;.hardinfo&quot;, &quot;remote.conf&quot;,
-			 NULL);
-    g_key_file_load_from_file(rd-&gt;key_file, path, 0, NULL);
-    g_free(path);
-
     populate_store(rd, store);
     gtk_widget_set_sensitive(GTK_WIDGET(rd-&gt;btn_edit), FALSE);
     gtk_widget_set_sensitive(GTK_WIDGET(rd-&gt;btn_remove), FALSE);</diff>
      <filename>hardinfo2/remote.c</filename>
    </modified>
    <modified>
      <diff>@@ -585,6 +585,20 @@ static void __tree_iter_destroy(gpointer data)
     gtk_tree_iter_free((GtkTreeIter *) data);
 }
 
+void shell_save_hosts_file(void)
+{
+    gchar *path, *remote_conf;
+    gsize length;
+
+    path = g_build_filename(g_get_home_dir(), &quot;.hardinfo&quot;, &quot;remote.conf&quot;, NULL);
+
+    remote_conf = g_key_file_to_data(shell-&gt;hosts, &amp;length, NULL);
+    g_file_set_contents(path, remote_conf, length, NULL);
+
+    g_free(remote_conf);
+    g_free(path);
+}
+
 void shell_init(GSList * modules)
 {
     if (shell) {
@@ -600,6 +614,7 @@ void shell_init(GSList * modules)
     shell_action_set_property(&quot;CopyAction&quot;, &quot;is-important&quot;, TRUE);
     shell_action_set_property(&quot;RefreshAction&quot;, &quot;is-important&quot;, TRUE);
     shell_action_set_property(&quot;ReportAction&quot;, &quot;is-important&quot;, TRUE);
+    shell_action_set_property(&quot;ReportBugAction&quot;, &quot;is-important&quot;, TRUE);
 
     shell-&gt;tree = tree_new();
     shell-&gt;info = info_tree_new(FALSE);
@@ -649,6 +664,18 @@ void shell_init(GSList * modules)
     shell_action_set_enabled(&quot;SyncManagerAction&quot;, FALSE);
 #else
     shell_action_set_enabled(&quot;SyncManagerAction&quot;, sync_manager_count_entries() &gt; 0);
+
+    {
+        gchar *path;
+
+        shell-&gt;hosts = g_key_file_new();
+        path = g_build_filename(g_get_home_dir(), &quot;.hardinfo&quot;, &quot;remote.conf&quot;, NULL);
+        g_key_file_load_from_file(shell-&gt;hosts, path, 0, NULL);
+        g_free(path);
+        
+        g_atexit(shell_save_hosts_file);
+    }
+
 #endif
 }
 </diff>
      <filename>hardinfo2/shell.c</filename>
    </modified>
    <modified>
      <diff>@@ -94,6 +94,8 @@ struct _Shell {
     ShellOrderType	_order_type;
     
     gchar		*selected_module_name;
+
+    GKeyFile		*hosts;
 };
 
 struct _ShellTree {
@@ -193,6 +195,7 @@ void		shell_set_title(Shell *shell, char *subtitle);
 
 void		shell_add_modules_to_gui(gpointer _shell_module, gpointer _shell_tree);
 
+void		shell_save_hosts_file();
 #endif				/* __SHELL_H__ */
 
 </diff>
      <filename>hardinfo2/shell.h</filename>
    </modified>
    <modified>
      <diff>@@ -1,15 +1,34 @@
 #ifndef __UIDEFS_H__
 #define __UIDEFS_H__ 
 
+#include &quot;config.h&quot;
+
+#if RELEASE
+#define DEBUG_TOOLBAR_ITEMS
+#else 		/* !RELEASE */
+#define DEBUG_TOOLBAR_ITEMS	&quot;&lt;separator/&gt;&quot; \
+                                &quot;&lt;toolitem name=\&quot;ReportBug\&quot; action=\&quot;ReportBugAction\&quot; /&gt;&quot;
+#endif		/* !RELEASE */
+
+#ifdef HAS_LIBSOUP
+#define REMOTE_MENU_ITEMS &quot;       &lt;menu name=\&quot;RemoteMenu\&quot; action=\&quot;RemoteMenuAction\&quot;&gt;&quot; \
+&quot;		&lt;menuitem name=\&quot;ConnectTo\&quot; action=\&quot;ConnectToAction\&quot; /&gt;&quot; \
+&quot;		&lt;menuitem name=\&quot;Manage\&quot; action=\&quot;ManageAction\&quot; /&gt;&quot; \
+&quot;		&lt;separator/&gt;&quot; \
+&quot;		&lt;separator name=\&quot;RemoteLastSep\&quot;/&gt;&quot; \
+&quot;       &lt;/menu&gt;&quot; 
+
+#else		/* !HAS_LIBSOUP */
+#define REMOTE_MENU_ITEMS
+#endif		/* !HAS_LIBSOUP */
+
 char *uidefs_str = &quot;&lt;ui&gt;&quot; \
 &quot;	&lt;menubar&gt;&quot; \
 &quot;	&lt;menu name=\&quot;InformationMenu\&quot; action=\&quot;InformationMenuAction\&quot;&gt;&quot; \
-&quot;		&lt;menuitem name=\&quot;ConnectTo\&quot; action=\&quot;ConnectToAction\&quot; /&gt;&quot; \
-&quot;		&lt;menuitem name=\&quot;SyncManager\&quot; action=\&quot;SyncManagerAction\&quot; /&gt;&quot; \
-&quot;		&lt;separator/&gt;&quot; \
 &quot;		&lt;menuitem name=\&quot;Report\&quot; action=\&quot;ReportAction\&quot; /&gt;&quot; \
-&quot;		&lt;separator/&gt;&quot; \
 &quot;		&lt;menuitem name=\&quot;Copy\&quot; action=\&quot;CopyAction\&quot; /&gt;&quot; \
+&quot;		&lt;separator/&gt;&quot; \
+&quot;		&lt;menuitem name=\&quot;SyncManager\&quot; action=\&quot;SyncManagerAction\&quot; /&gt;&quot; \
 /*
  * Save Image is not ready for prime time. Yet.
  * &quot;&lt;menuitem name=\&quot;SaveGraph\&quot; action=\&quot;SaveGraphAction\&quot; /&gt;&quot; \
@@ -25,6 +44,7 @@ char *uidefs_str = &quot;&lt;ui&gt;&quot; \
 &quot;		&lt;separator/&gt;&quot; \
 &quot;		&lt;separator name=\&quot;LastSep\&quot;/&gt;&quot; \
 &quot;	&lt;/menu&gt;&quot; \
+REMOTE_MENU_ITEMS
 &quot;	&lt;menu name=\&quot;HelpMenu\&quot; action=\&quot;HelpMenuAction\&quot;&gt;&quot; \
 &quot;		&lt;menuitem name=\&quot;OnlineDocs\&quot; action=\&quot;OnlineDocsAction\&quot;/&gt;&quot; \
 &quot;		&lt;separator/&gt;&quot; \
@@ -43,10 +63,11 @@ char *uidefs_str = &quot;&lt;ui&gt;&quot; \
 &quot;		&lt;placeholder name=\&quot;ToolItems\&quot;&gt;&quot; \
 &quot;			&lt;toolitem name=\&quot;Refresh\&quot; action=\&quot;RefreshAction\&quot;/&gt;&quot; \
 &quot;			&lt;separator/&gt;&quot; \
-&quot;   		        &lt;toolitem name=\&quot;ConnectTo\&quot; action=\&quot;ConnectToAction\&quot; /&gt;&quot; \
-&quot;			&lt;separator/&gt;&quot; \
-&quot;			&lt;toolitem name=\&quot;Copy\&quot; action=\&quot;CopyAction\&quot;/&gt;&quot; \
 &quot;			&lt;toolitem name=\&quot;Report\&quot; action=\&quot;ReportAction\&quot;/&gt;&quot; \
+&quot;			&lt;toolitem name=\&quot;Copy\&quot; action=\&quot;CopyAction\&quot;/&gt;&quot; \
+&quot;			&lt;separator/&gt;&quot; \
+&quot;   		        &lt;toolitem name=\&quot;ConnectTo\&quot; action=\&quot;ConnectToAction\&quot; /&gt;&quot; \
+DEBUG_TOOLBAR_ITEMS \
 &quot;		&lt;/placeholder&gt;&quot; \
 &quot;	&lt;/toolbar&gt;&quot; \
 &quot;&lt;/ui&gt;&quot;;</diff>
      <filename>hardinfo2/uidefs.h</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>79bfb31978e30c1d9c1e6de5a8c234383b07bd66</id>
    </parent>
  </parents>
  <author>
    <name>Leandro A. F. Pereira</name>
    <email>leandro@hardinfo.org</email>
  </author>
  <url>http://github.com/lpereira/hardinfo/commit/dbaeacf7888957ca8d0cad69822b2fe4851b19d4</url>
  <id>dbaeacf7888957ca8d0cad69822b2fe4851b19d4</id>
  <committed-date>2009-05-09T07:57:06-07:00</committed-date>
  <authored-date>2009-05-09T07:57:06-07:00</authored-date>
  <message>Change remote host dialog to be a Host Manager; add a Connect To window and a Remote menu.</message>
  <tree>dad4e950c1e997870069120fcc30cf3663420810</tree>
  <committer>
    <name>Leandro A. F. Pereira</name>
    <email>leandro@hardinfo.org</email>
  </committer>
</commit>
