# HG changeset patch
# User "Cole Robinson <crobinso@redhat.com>"
# Date 1216924902 14400
# Node ID 2bbb1937e47b24db7257288117f0a9c5e50ee694
# Parent  8ff3fe2b729ea60b9393dfb778067007a03e2e4b
Populate serial and parallel devices in details section. Allow deleting them as well.

diff -r 8ff3fe2b729e -r 2bbb1937e47b src/virtManager/details.py
--- a/src/virtManager/details.py	Fri Jul 18 21:34:13 2008 -0400
+++ b/src/virtManager/details.py	Thu Jul 24 14:41:42 2008 -0400
@@ -56,6 +56,7 @@
 HW_LIST_TYPE_INPUT = 5
 HW_LIST_TYPE_GRAPHICS = 6
 HW_LIST_TYPE_SOUND = 7
+HW_LIST_TYPE_CHAR = 8
 
 # Console pages
 PAGE_UNAVAILABLE = 0
@@ -254,6 +255,7 @@
             "on_config_input_remove_clicked": self.remove_input,
             "on_config_graphics_remove_clicked": self.remove_graphics,
             "on_config_sound_remove_clicked": self.remove_sound,
+            "on_config_char_remove_clicked": self.remove_char,
             "on_add_hardware_button_clicked": self.add_hardware,
 
             "on_details_menu_view_fullscreen_activate": self.toggle_fullscreen,
@@ -541,6 +543,8 @@
                 self.refresh_graphics_page()
             elif pagetype == HW_LIST_TYPE_SOUND:
                 self.refresh_sound_page()
+            elif pagetype == HW_LIST_TYPE_CHAR:
+                self.refresh_char_page()
             elif pagetype == HW_LIST_TYPE_BOOT:
                 self.refresh_boot_page()
                 self.window.get_widget("config-boot-options-apply").set_sensitive(False)
@@ -727,6 +731,8 @@
                     self.refresh_graphics_page()
                 elif pagetype == HW_LIST_TYPE_SOUND:
                     self.refresh_sound_page()
+                elif pagetype == HW_LIST_TYPE_CHAR:
+                    self.refresh_char_page()
 
     def refresh_summary(self):
         self.window.get_widget("overview-cpu-usage-text").set_text("%d %%" % self.vm.cpu_time_percentage())
@@ -911,6 +917,26 @@
             self.window.get_widget("config-sound-remove").set_sensitive(False)
         else:
             self.window.get_widget("config-sound-remove").set_sensitive(True)
+
+    def refresh_char_page(self):
+        vmlist = self.window.get_widget("hw-list")
+        selection = vmlist.get_selection()
+        active = selection.get_selected()
+        if active[1] is None:
+            return
+        char = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
+        typelabel = "<b>%s Device %s</b>" % (char[0].capitalize(),
+                                             char[5] and _("(Primary Console)") or "")
+        self.window.get_widget("char-type").set_markup(typelabel)
+        self.window.get_widget("char-dev-type").set_text(char[1] or "-")
+        self.window.get_widget("char-target-port").set_text(char[2])
+        self.window.get_widget("char-source-path").set_text(char[4] or "-")
+
+        # Can't remove char dev from live guest
+        if self.vm.is_active():
+            self.window.get_widget("config-char-remove").set_sensitive(False)
+        else:
+            self.window.get_widget("config-char-remove").set_sensitive(True)
 
     def refresh_boot_page(self):
         # Refresh autostart
@@ -1330,6 +1356,20 @@
         self.remove_device(xml)
         self.refresh_resources()
 
+    def remove_char(self, src):
+        vmlist = self.window.get_widget("hw-list")
+        selection = vmlist.get_selection()
+        active = selection.get_selected()
+        if active[1] is None:
+            return
+        char = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
+
+        xml = "<%s>\n" % char[0] + \
+              "  <target port='%s'/>\n" % char[2] + \
+              "</%s>" % char[0]
+        self.remove_device(xml)
+        self.refresh_resources()
+
     def prepare_hw_list(self):
         hw_list_model = gtk.ListStore(str, str, int, gtk.gdk.Pixbuf, int, gobject.TYPE_PYOBJECT)
         self.window.get_widget("hw-list").set_model(hw_list_model)
@@ -1479,6 +1519,27 @@
             if missing:
                 hw_list_model.insert(insertAt, [_("Sound: %s" % sound[3]), gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_LARGE_TOOLBAR, None, HW_LIST_TYPE_SOUND, sound])
 
+
+        # Populate list of char devices
+        currentChars = {}
+        for char in self.vm.get_char_devices():
+            missing = True
+            insertAt = 0
+            currentChars[char[3]] = 1
+            for row in hw_list_model:
+                if row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_CHAR and \
+                   row[HW_LIST_COL_DEVICE][3] == char[3]:
+                    # Update metadata
+                    row[HW_LIST_COL_DEVICE] = char
+                    missing = False
+
+                if row[HW_LIST_COL_TYPE] <= HW_LIST_TYPE_CHAR:
+                    insertAt = insertAt + 1
+            # Add in row
+            if missing:
+                hw_list_model.insert(insertAt, ["%s %s" % (char[0].capitalize(), char[2]), gtk.STOCK_CONNECT, gtk.ICON_SIZE_LARGE_TOOLBAR, None, HW_LIST_TYPE_CHAR, char])
+
+
         # Now remove any no longer current devs
         devs = range(len(hw_list_model))
         devs.reverse()
@@ -1497,6 +1558,9 @@
                 removeIt = True
             elif row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_SOUND and not \
                  currentSounds.has_key(row[HW_LIST_COL_DEVICE][3]):
+                removeIt = True
+            elif row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_CHAR and not \
+                 currentChars.has_key(row[HW_LIST_COL_DEVICE][3]):
                 removeIt = True
 
             if removeIt:
diff -r 8ff3fe2b729e -r 2bbb1937e47b src/virtManager/domain.py
--- a/src/virtManager/domain.py	Fri Jul 18 21:34:13 2008 -0400
+++ b/src/virtManager/domain.py	Thu Jul 24 14:41:42 2008 -0400
@@ -702,6 +702,46 @@
 
         return self._parse_device_xml(_parse_sound_devs)
 
+    def get_char_devices(self):
+        def _parse_char_devs(ctx):
+            chars = []
+            devs  = []
+            cons = ctx.xpathEval("/domain/devices/console")
+            devs.extend(ctx.xpathEval("/domain/devices/parallel"))
+            devs.extend(ctx.xpathEval("/domain/devices/serial"))
+
+            # Since there is only one 'console' device ever in the xml
+            # find its port (if present)
+            cons_port = None
+            for node in cons:
+                for child in node.children:
+                    if child.name == "target":
+                        cons_port = child.prop("port")
+
+            for node in devs:
+                char_type = node.name
+                dev_type = node.prop("type")
+                target_port = None
+                source_path = None
+                console_dev = False
+
+                for child in node.children:
+                    if child.name == "target":
+                        target_port = child.prop("port")
+                    if child.name == "source":
+                        source_path = child.prop("path")
+
+                if node.name == "serial" and target_port == cons_port:
+                    # Console is just a dupe of this serial device
+                    console_dev = True
+
+                chars.append([char_type, dev_type, target_port,
+                              "%s:%s" % (char_type, target_port),
+                              source_path, console_dev])
+            return chars
+
+        return self._parse_device_xml(_parse_char_devs)
+
     def _parse_device_xml(self, parse_function):
         doc = None
         ctx = None
@@ -803,6 +843,30 @@
                 if len(model) > 0 and model[0].content != None:
                     logging.debug("Looking for type %s" % model[0].content)
                     ret = ctx.xpathEval("/domain/devices/sound[@model='%s']" % model[0].content)
+
+            elif dev_type == "parallel" or dev_type == "console" or \
+                 dev_type == "serial":
+                 port = dev_ctx.xpathEval("/%s/target/@port" % dev_type)
+                 if port and len(port) > 0 and port[0].content != None:
+                    logging.debug("Looking for %s w/ port %s" % (dev_type,
+                                                                 port))
+                    ret = ctx.xpathEval("/domain/devices/%s[target/@port='%s']" % (dev_type, port[0].content))
+
+                    # If serial and console are both present, console is
+                    # probably (always?) just a dup of the 'primary' serial
+                    # device. Try and find an associated console device with
+                    # the same port and remove that as well, otherwise the
+                    # removal doesn't go through
+                    if dev_type == "serial":
+                        cons_ret = ctx.xpathEval("/domain/devices/console[target/@port='%s']" % port[0].content)
+                        if cons_ret and len(cons_ret) > 0:
+                            logging.debug("Also removing console device "
+                                          "associated with serial dev.")
+                            cons_ret[0].unlinkNode()
+                            cons_ret[0].freeNode()
+                        else:
+                            logging.debug("No console device found associated "
+                                          "with passed serial devices")
 
             else:
                 raise RuntimeError, _("Unknown device type device type '%s'" %
diff -r 8ff3fe2b729e -r 2bbb1937e47b src/vmm-details.glade
--- a/src/vmm-details.glade	Fri Jul 18 21:34:13 2008 -0400
+++ b/src/vmm-details.glade	Thu Jul 24 14:41:42 2008 -0400
@@ -1550,7 +1550,7 @@
 	    <widget class="GtkHPaned" id="hpaned1">
 	      <property name="visible">True</property>
 	      <property name="can_focus">True</property>
-	      <property name="position">200</property>
+	      <property name="position">230</property>
 
 	      <child>
 		<widget class="GtkVBox" id="vbox53">
@@ -4658,6 +4658,299 @@
 		      <property name="type">tab</property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkVBox" id="vbox59">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">0</property>
+
+		      <child>
+			<widget class="GtkFrame" id="frame14">
+			  <property name="visible">True</property>
+			  <property name="label_xalign">0</property>
+			  <property name="label_yalign">0.5</property>
+			  <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+			  <child>
+			    <widget class="GtkAlignment" id="alignment160">
+			      <property name="visible">True</property>
+			      <property name="xalign">0.5</property>
+			      <property name="yalign">0.5</property>
+			      <property name="xscale">1</property>
+			      <property name="yscale">1</property>
+			      <property name="top_padding">0</property>
+			      <property name="bottom_padding">0</property>
+			      <property name="left_padding">12</property>
+			      <property name="right_padding">0</property>
+
+			      <child>
+				<widget class="GtkTable" id="table37">
+				  <property name="border_width">3</property>
+				  <property name="visible">True</property>
+				  <property name="n_rows">3</property>
+				  <property name="n_columns">2</property>
+				  <property name="homogeneous">False</property>
+				  <property name="row_spacing">3</property>
+				  <property name="column_spacing">3</property>
+
+				  <child>
+				    <widget class="GtkLabel" id="label503">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Device Type:</property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">1</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="left_attach">0</property>
+				      <property name="right_attach">1</property>
+				      <property name="top_attach">0</property>
+				      <property name="bottom_attach">1</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="label504">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Target Port:</property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">1</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="left_attach">0</property>
+				      <property name="right_attach">1</property>
+				      <property name="top_attach">1</property>
+				      <property name="bottom_attach">2</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="label505">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Source Path:</property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">1</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="left_attach">0</property>
+				      <property name="right_attach">1</property>
+				      <property name="top_attach">2</property>
+				      <property name="bottom_attach">3</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="char-dev-type">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">label506</property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="left_attach">1</property>
+				      <property name="right_attach">2</property>
+				      <property name="top_attach">0</property>
+				      <property name="bottom_attach">1</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="char-target-port">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">label507</property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="left_attach">1</property>
+				      <property name="right_attach">2</property>
+				      <property name="top_attach">1</property>
+				      <property name="bottom_attach">2</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="char-source-path">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">label508</property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="left_attach">1</property>
+				      <property name="right_attach">2</property>
+				      <property name="top_attach">2</property>
+				      <property name="bottom_attach">3</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+				</widget>
+			      </child>
+			    </widget>
+			  </child>
+
+			  <child>
+			    <widget class="GtkLabel" id="char-type">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">&lt;b&gt;insert type&lt;/b&gt;</property>
+			      <property name="use_underline">False</property>
+			      <property name="use_markup">True</property>
+			      <property name="justify">GTK_JUSTIFY_LEFT</property>
+			      <property name="wrap">False</property>
+			      <property name="selectable">False</property>
+			      <property name="xalign">0.5</property>
+			      <property name="yalign">0.5</property>
+			      <property name="xpad">0</property>
+			      <property name="ypad">0</property>
+			      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			      <property name="width_chars">-1</property>
+			      <property name="single_line_mode">False</property>
+			      <property name="angle">0</property>
+			    </widget>
+			    <packing>
+			      <property name="type">label_item</property>
+			    </packing>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">15</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkHButtonBox" id="hbuttonbox15">
+			  <property name="border_width">6</property>
+			  <property name="visible">True</property>
+			  <property name="layout_style">GTK_BUTTONBOX_END</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <widget class="GtkButton" id="config-char-remove">
+			      <property name="visible">True</property>
+			      <property name="can_default">True</property>
+			      <property name="can_focus">True</property>
+			      <property name="label">gtk-remove</property>
+			      <property name="use_stock">True</property>
+			      <property name="relief">GTK_RELIEF_NORMAL</property>
+			      <property name="focus_on_click">True</property>
+			      <signal name="clicked" handler="on_config_char_remove_clicked" last_modification_time="Sat, 19 Jul 2008 01:39:51 GMT"/>
+			    </widget>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="tab_expand">False</property>
+		      <property name="tab_fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label501">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Char</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="type">tab</property>
+		    </packing>
+		  </child>
 		</widget>
 		<packing>
 		  <property name="shrink">True</property>
