# HG changeset patch
# User "Cole Robinson <crobinso@redhat.com>"
# Date 1216848252 14400
# Node ID 8a86b6ed3a80104a0704fda2480b1a05d9ed4ca0
# Parent  f4c491621a100ed8101622601a87c5dc978ceb47
Allow viewing and removing sound devices

diff -r f4c491621a10 -r 8a86b6ed3a80 src/virtManager/details.py
--- a/src/virtManager/details.py	Wed Jul 23 16:23:56 2008 -0400
+++ b/src/virtManager/details.py	Wed Jul 23 17:24:12 2008 -0400
@@ -55,6 +55,7 @@
 HW_LIST_TYPE_NIC = 4
 HW_LIST_TYPE_INPUT = 5
 HW_LIST_TYPE_GRAPHICS = 6
+HW_LIST_TYPE_SOUND = 7
 
 # Console pages
 PAGE_UNAVAILABLE = 0
@@ -252,6 +253,7 @@
             "on_config_network_remove_clicked": self.remove_network,
             "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_add_hardware_button_clicked": self.add_hardware,
 
             "on_details_menu_view_fullscreen_activate": self.toggle_fullscreen,
@@ -536,6 +538,8 @@
                 self.refresh_input_page()
             elif pagetype == HW_LIST_TYPE_GRAPHICS:
                 self.refresh_graphics_page()
+            elif pagetype == HW_LIST_TYPE_SOUND:
+                self.refresh_sound_page()
             elif pagetype == HW_LIST_TYPE_BOOT:
                 self.refresh_boot_page()
                 self.window.get_widget("config-boot-options-apply").set_sensitive(False)
@@ -720,6 +724,8 @@
                     self.refresh_input_page()
                 elif pagetype == HW_LIST_TYPE_GRAPHICS:
                     self.refresh_graphics_page()
+                elif pagetype == HW_LIST_TYPE_SOUND:
+                    self.refresh_sound_page()
 
     def refresh_summary(self):
         self.window.get_widget("overview-cpu-usage-text").set_text("%d %%" % self.vm.cpu_time_percentage())
@@ -889,6 +895,21 @@
                 self.window.get_widget("config-input-remove").set_sensitive(False)
             else:
                 self.window.get_widget("config-input-remove").set_sensitive(True)
+
+    def refresh_sound_page(self):
+        vmlist = self.window.get_widget("hw-list")
+        selection = vmlist.get_selection()
+        active = selection.get_selected()
+        if active[1] is None:
+            return
+        sound = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
+        self.window.get_widget("sound-model").set_text(sound[3])
+
+        # Can't remove sound dev from live guest
+        if self.vm.is_active():
+            self.window.get_widget("config-sound-remove").set_sensitive(False)
+        else:
+            self.window.get_widget("config-sound-remove").set_sensitive(True)
 
     def refresh_boot_page(self):
         # Refresh autostart
@@ -1296,6 +1317,18 @@
             self.remove_device(xml)
             self.refresh_resources()
 
+    def remove_sound(self, src):
+        vmlist = self.window.get_widget("hw-list")
+        selection = vmlist.get_selection()
+        active = selection.get_selected()
+        if active[1] is None:
+            return
+        sound = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
+
+        xml = "<sound model='%s'/>" % sound[3]
+        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)
@@ -1426,6 +1459,25 @@
             if missing:
                 hw_list_model.insert(insertAt, [_("Display"), gtk.STOCK_SELECT_COLOR, gtk.ICON_SIZE_LARGE_TOOLBAR, None, HW_LIST_TYPE_GRAPHICS, graphic])
 
+        # Populate list of sound devices
+        currentSounds = {}
+        for sound in self.vm.get_sound_devices():
+            missing = True
+            insertAt = 0
+            currentSounds[sound[3]] = 1
+            for row in hw_list_model:
+                if row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_SOUND and \
+                   row[HW_LIST_COL_DEVICE][3] == sound[3]:
+                    # Update metadata
+                    row[HW_LIST_COL_DEVICE] = sound
+                    missing = False
+
+                if row[HW_LIST_COL_TYPE] <= HW_LIST_TYPE_SOUND:
+                    insertAt = insertAt + 1
+            # Add in row
+            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])
+
         # Now remove any no longer current devs
         devs = range(len(hw_list_model))
         devs.reverse()
@@ -1441,6 +1493,9 @@
             elif row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_INPUT and not currentInputs.has_key(row[HW_LIST_COL_DEVICE][3]):
                 removeIt = True
             elif row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_GRAPHICS and not currentGraphics.has_key(row[HW_LIST_COL_DEVICE][3]):
+                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
 
             if removeIt:
diff -r f4c491621a10 -r 8a86b6ed3a80 src/virtManager/domain.py
--- a/src/virtManager/domain.py	Wed Jul 23 16:23:56 2008 -0400
+++ b/src/virtManager/domain.py	Wed Jul 23 17:24:12 2008 -0400
@@ -692,6 +692,16 @@
 
         return self._parse_device_xml(_parse_graphics_devs)
 
+    def get_sound_devices(self):
+        def _parse_sound_devs(ctx):
+            sound = []
+            ret = ctx.xpathEval("/domain/devices/sound")
+            for node in ret:
+                sound.append([None, None, None, node.prop("model")])
+            return sound
+
+        return self._parse_device_xml(_parse_sound_devs)
+
     def _parse_device_xml(self, parse_function):
         doc = None
         ctx = None
@@ -808,6 +818,22 @@
                     logging.debug("Redefine with " + newxml)
                     self.get_connection().define_domain(newxml)
 
+            elif dev_type == "sound":
+                model = dev_ctx.xpathEval("/sound/@model")
+                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)
+                if len(ret) > 0:
+                    ret[0].unlinkNode()
+                    ret[0].freeNode()
+                    newxml=doc.serialize()
+                    logging.debug("Redefine with " + newxml)
+                    self.get_connection().define_domain(newxml)
+
+            else:
+                raise RuntimeError, _("Unknown device type '%s'" %
+                                      dev_type)
+
         finally:
             if ctx != None:
                 ctx.xpathFreeContext()
diff -r f4c491621a10 -r 8a86b6ed3a80 src/vmm-details.glade
--- a/src/vmm-details.glade	Wed Jul 23 16:23:56 2008 -0400
+++ b/src/vmm-details.glade	Wed Jul 23 17:24:12 2008 -0400
@@ -4476,6 +4476,188 @@
 		      <property name="type">tab</property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkVBox" id="vbox58">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">0</property>
+
+		      <child>
+			<widget class="GtkFrame" id="frame13">
+			  <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="alignment159">
+			      <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">5</property>
+			      <property name="bottom_padding">3</property>
+			      <property name="left_padding">12</property>
+			      <property name="right_padding">0</property>
+
+			      <child>
+				<widget class="GtkTable" id="table36">
+				  <property name="border_width">3</property>
+				  <property name="visible">True</property>
+				  <property name="n_rows">1</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="label452">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Device Model:</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">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="sound-model">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">insert sound model</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="y_padding">1</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+				</widget>
+			      </child>
+			    </widget>
+			  </child>
+
+			  <child>
+			    <widget class="GtkLabel" id="label451">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">&lt;b&gt;Sound Device&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="hbuttonbox14">
+			  <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-sound-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_sound_remove_clicked" last_modification_time="Wed, 23 Jul 2008 21:17:37 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="label440">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Sound</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>
