[virt-tools-list] [PATCH v2 remote-viewer] Connecting to ovirt without specifying VM name will not fail

Pavel Grunt pgrunt at redhat.com
Fri Sep 19 09:30:59 UTC 2014


When a user tries to connect to ovirt without specifying
VM name (remote-viewer ovirt://ovirt.example.com/) or with
wrong VM name a list of available virtual machines is shown,
and the user may pick a machine he wants to connect to.
---
changes:
 - dialog pops up on empty VM name
 - UI of the dialog is in separate file

 src/remote-viewer.c               |  88 +++++++++++++++++++++-
 src/virt-viewer-vm-connection.xml | 153 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 239 insertions(+), 2 deletions(-)
 create mode 100644 src/virt-viewer-vm-connection.xml

diff --git a/src/remote-viewer.c b/src/remote-viewer.c
index 5f5fa3d..5f5ea2d 100644
--- a/src/remote-viewer.c
+++ b/src/remote-viewer.c
@@ -74,6 +74,10 @@ enum {
     PROP_OPEN_RECENT_DIALOG
 };
 
+#ifdef HAVE_OVIRT
+static OvirtVm * choose_vm_dialog(char **vm_name, OvirtCollection *vms);
+#endif
+
 static gboolean remote_viewer_start(VirtViewerApp *self);
 #ifdef HAVE_SPICE_GTK
 static gboolean remote_viewer_activate(VirtViewerApp *self, GError **error);
@@ -692,10 +696,13 @@ parse_ovirt_uri(const gchar *uri_str, char **rest_uri, char **name, char **usern
     }
 
     if (uri->path == NULL) {
+        uri->path = g_strdup("/");
+    }
+
+    if(*uri->path != '/') {
         xmlFreeURI(uri);
         return FALSE;
     }
-    g_return_val_if_fail(*uri->path == '/', FALSE);
 
     /* extract VM name from path */
     path_elements = g_strsplit(uri->path, "/", -1);
@@ -840,7 +847,10 @@ create_ovirt_session(VirtViewerApp *app, const char *uri)
         goto error;
     }
     vm = OVIRT_VM(ovirt_collection_lookup_resource(vms, vm_name));
-    g_return_val_if_fail(vm != NULL, FALSE);
+    if (vm == NULL && (vm = choose_vm_dialog(&vm_name, vms)) == NULL) {
+        g_debug("no oVirt VM was chosen");
+        goto error;
+    }
     g_object_get(G_OBJECT(vm), "state", &state, NULL);
     if (state != OVIRT_VM_STATE_UP) {
         g_debug("oVirt VM %s is not running", vm_name);
@@ -980,6 +990,20 @@ recent_item_activated_dialog_cb(GtkRecentChooser *chooser G_GNUC_UNUSED, gpointe
    gtk_dialog_response(GTK_DIALOG (data), GTK_RESPONSE_ACCEPT);
 }
 
+static void
+vm_list_selection_changed_dialog_cb(GtkTreeSelection *selection, gpointer data)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model;
+    const gchar *vm_name;
+    GtkWidget *entry = data;
+
+    if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+        gtk_tree_model_get(model, &iter, 0, &vm_name, -1);
+        gtk_entry_set_text(GTK_ENTRY(entry), vm_name);
+    }
+}
+
 static void make_label_light(GtkLabel* label)
 {
     PangoAttrList* attributes = pango_attr_list_new();
@@ -1092,6 +1116,66 @@ connect_dialog(gchar **uri)
     return retval;
 }
 
+
+#ifdef HAVE_OVIRT
+static OvirtVm *choose_vm_dialog(char **vm_name, OvirtCollection *vms_collection)
+{
+    GtkBuilder *vm_connection;
+    GtkWidget *dialog, *entry;
+    GtkTreeModel *store;
+    GtkTreeSelection *select;
+    GtkTreeIter iter;
+    GHashTable *vms;
+    GHashTableIter vms_iter;
+    OvirtVm *vm;
+    char *tmp_vm_name;
+    OvirtVmState state;
+    gint vms_running;
+
+    vms = ovirt_collection_get_resources(vms_collection);
+    g_return_val_if_fail(g_hash_table_size(vms) > 0, NULL);
+
+    vm_connection = virt_viewer_util_load_ui("virt-viewer-vm-connection.xml");
+    dialog = GTK_WIDGET(gtk_builder_get_object(vm_connection, "vm-connection-dialog"));
+    entry = GTK_WIDGET(gtk_builder_get_object(vm_connection, "entry"));
+    select = GTK_TREE_SELECTION(gtk_builder_get_object(vm_connection, "treeview-selection"));
+    store = GTK_TREE_MODEL(gtk_builder_get_object(vm_connection, "store"));
+
+    vms_running = 0;
+    g_hash_table_iter_init(&vms_iter, vms);
+    while (g_hash_table_iter_next(&vms_iter, (gpointer *) &tmp_vm_name, (gpointer *) &vm)) {
+        g_object_get(G_OBJECT(vm), "state", &state, NULL);
+        if (state == OVIRT_VM_STATE_UP) {
+            gtk_list_store_append(GTK_LIST_STORE(store), &iter);
+            gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, tmp_vm_name, -1);
+            ++vms_running;
+        }
+    }
+
+    g_signal_connect(select, "changed",
+                     G_CALLBACK(vm_list_selection_changed_dialog_cb), entry);
+    if (gtk_tree_model_get_iter_first(store, &iter)) {
+        gtk_tree_selection_select_iter(select, &iter);
+    }
+    /* show and wait for response */
+    if (vms_running > 0) {
+        gtk_widget_show_all(dialog);
+        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+            *vm_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+            vm = OVIRT_VM(ovirt_collection_lookup_resource(vms_collection, *vm_name));
+        } else {
+            *vm_name = NULL;
+            vm = NULL;
+        }
+    } else {
+        vm = NULL;
+    }
+    gtk_widget_destroy(dialog);
+
+    return vm;
+}
+#endif
+
 static gboolean
 remote_viewer_start(VirtViewerApp *app)
 {
diff --git a/src/virt-viewer-vm-connection.xml b/src/virt-viewer-vm-connection.xml
new file mode 100644
index 0000000..4c6ced6
--- /dev/null
+++ b/src/virt-viewer-vm-connection.xml
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+  <object class="GtkListStore" id="store">
+    <columns>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+      <!-- column-name state -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkDialog" id="vm-connection-dialog">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Virtual machine connection details</property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">normal</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button-cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button-connect">
+                <property name="label">gtk-connect</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="n_rows">4</property>
+            <property name="column_spacing">6</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Virtual machine name</property>
+                <property name="ellipsize">end</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="editable">False</property>
+                <property name="progress_pulse_step">0.16</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Available virtual machines</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkTreeView" id="treeview">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">store</property>
+                <property name="headers_visible">False</property>
+                <property name="enable_grid_lines">horizontal</property>
+                <child internal-child="selection">
+                  <object class="GtkTreeSelection" id="treeview-selection"/>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+                    <property name="title" translatable="yes">Name</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+                    <property name="title" translatable="yes">State</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button-cancel</action-widget>
+      <action-widget response="-3">button-connect</action-widget>
+    </action-widgets>
+  </object>
+</interface>
-- 
1.9.3




More information about the virt-tools-list mailing list