~ubuntu-branches/ubuntu/precise/virt-manager/precise-proposed

« back to all changes in this revision

Viewing changes to .pc/fix-cpu-wrong-types.patch/src/virtManager/details.py

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-05-18 14:11:16 UTC
  • mfrom: (2.1.24 sid)
  • Revision ID: james.westby@ubuntu.com-20110518141116-3457j7twra3zlpve
Tags: 0.8.7-1ubuntu1
* Merge from debian unstable. Remaining changes: (LP: #747078)
  - debian/control: Depend on python-appindicator for appindicator
    support.
  - Add a /usr/share/pixmaps/virt-manager-icon.svg symlink to link icon to
    where the Application Indicator can find it.
  - debian/patches/more_helpful_error_message.patch: explain to the user
    why he can't connect to qemu:///system and what he can do fix it.
  - debian/control: lower libvirt-bin from Recommends to Suggests; seems
    some users (like netbooks) want to manage VMs, but not host them; see
    meta packages (ubuntu-virt, ubuntu-virt-server, ubuntu-virt-mgmt) for
    group installation of virt package sets.
  - debian/patches/use_ubuntu_package_names.patch: Suggest installing the
    packages that are actually available in Ubuntu.
  - debian/rules: Set qemu user to libvirt-qemu so appropriate
    permissions get set.
  - debian/rules: Set Ubuntu as the preferred distro so we appear first
    in the list.
  - debian/rules: disable TUI for now, since the required dependencies
    are not available (Newt Syrup).
  - debian/rules: Drop patchsys-quilt include since dpkg-source does the
    quilt dance for us.
  - debian/patches/fork_before_using_gconf.patch: fork earlier to resolve
    cpu usage issue and appindicator issue.
  - Removed python-ipy dependency as it is in universe:
    - debian/control: remove python-ipy from Depends
    - debian/series: disable 0002-Use-IPy-from-python-ipy.patch patch so
      we use the one that's included in the virt-manager source.
    - debian/rules: don't delete the IPy file.
* Removed patches:
  - debian/patches/dont-always-launch-consoles.patch: Upstream
  - debian/patches/fix_apparmor_details.patch: Upstream
  - debian/patches/fix-cpu-wrong-types.patch: Upstream
  - debian/patches/no_hal_traceback.patch: Upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# Copyright (C) 2006-2008 Red Hat, Inc.
3
 
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
4
 
#
5
 
# This program is free software; you can redistribute it and/or modify
6
 
# it under the terms of the GNU General Public License as published by
7
 
# the Free Software Foundation; either version 2 of the License, or
8
 
# (at your option) any later version.
9
 
#
10
 
# This program is distributed in the hope that it will be useful,
11
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
# GNU General Public License for more details.
14
 
#
15
 
# You should have received a copy of the GNU General Public License
16
 
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
 
# MA 02110-1301 USA.
19
 
#
20
 
 
21
 
import gobject
22
 
import gtk
23
 
import libvirt
24
 
import logging
25
 
import traceback
26
 
import os
27
 
 
28
 
import virtManager.uihelpers as uihelpers
29
 
from virtManager.storagebrowse import vmmStorageBrowser
30
 
from virtManager.baseclass import vmmGObjectUI
31
 
from virtManager.addhardware import vmmAddHardware
32
 
from virtManager.choosecd import vmmChooseCD
33
 
from virtManager.console import vmmConsolePages
34
 
from virtManager.serialcon import vmmSerialConsole
35
 
from virtManager.graphwidgets import Sparkline
36
 
from virtManager import util as util
37
 
 
38
 
import virtinst
39
 
 
40
 
# Columns in hw list model
41
 
HW_LIST_COL_LABEL = 0
42
 
HW_LIST_COL_ICON_NAME = 1
43
 
HW_LIST_COL_ICON_SIZE = 2
44
 
HW_LIST_COL_TYPE = 3
45
 
HW_LIST_COL_DEVICE = 4
46
 
 
47
 
# Types for the hw list model: numbers specify what order they will be listed
48
 
HW_LIST_TYPE_GENERAL = 0
49
 
HW_LIST_TYPE_STATS = 1
50
 
HW_LIST_TYPE_CPU = 2
51
 
HW_LIST_TYPE_MEMORY = 3
52
 
HW_LIST_TYPE_BOOT = 4
53
 
HW_LIST_TYPE_DISK = 5
54
 
HW_LIST_TYPE_NIC = 6
55
 
HW_LIST_TYPE_INPUT = 7
56
 
HW_LIST_TYPE_GRAPHICS = 8
57
 
HW_LIST_TYPE_SOUND = 9
58
 
HW_LIST_TYPE_CHAR = 10
59
 
HW_LIST_TYPE_HOSTDEV = 11
60
 
HW_LIST_TYPE_VIDEO = 12
61
 
HW_LIST_TYPE_WATCHDOG = 13
62
 
HW_LIST_TYPE_CONTROLLER = 14
63
 
 
64
 
remove_pages = [HW_LIST_TYPE_NIC, HW_LIST_TYPE_INPUT,
65
 
                HW_LIST_TYPE_GRAPHICS, HW_LIST_TYPE_SOUND, HW_LIST_TYPE_CHAR,
66
 
                HW_LIST_TYPE_HOSTDEV, HW_LIST_TYPE_DISK, HW_LIST_TYPE_VIDEO,
67
 
                HW_LIST_TYPE_WATCHDOG, HW_LIST_TYPE_CONTROLLER]
68
 
 
69
 
# Boot device columns
70
 
BOOT_DEV_TYPE = 0
71
 
BOOT_LABEL = 1
72
 
BOOT_ICON = 2
73
 
BOOT_ACTIVE = 3
74
 
 
75
 
# Main tab pages
76
 
PAGE_CONSOLE = 0
77
 
PAGE_DETAILS = 1
78
 
PAGE_DYNAMIC_OFFSET = 2
79
 
 
80
 
def prettyify_disk_bus(bus):
81
 
    if bus in ["ide", "scsi", "usb"]:
82
 
        return bus.upper()
83
 
 
84
 
    if bus in ["xen"]:
85
 
        return bus.capitalize()
86
 
 
87
 
    if bus == "virtio":
88
 
        return "VirtIO"
89
 
 
90
 
    return bus
91
 
 
92
 
def prettyify_disk(devtype, bus, idx):
93
 
    busstr = prettyify_disk_bus(bus) or ""
94
 
 
95
 
    if devtype == "floppy":
96
 
        devstr = "Floppy"
97
 
        busstr = ""
98
 
    elif devtype == "cdrom":
99
 
        devstr = "CDROM"
100
 
    else:
101
 
        devstr = devtype.capitalize()
102
 
 
103
 
    if busstr:
104
 
        ret = "%s %s" % (busstr, devstr)
105
 
    else:
106
 
        ret = devstr
107
 
 
108
 
    return "%s %s" % (ret, idx)
109
 
 
110
 
def safeint(val, fmt="%.3d"):
111
 
    try:
112
 
        int(val)
113
 
    except:
114
 
        return str(val)
115
 
    return fmt % int(val)
116
 
 
117
 
def prettyify_bytes(val):
118
 
    if val > (1024 * 1024 * 1024):
119
 
        return "%2.2f GB" % (val / (1024.0 * 1024.0 * 1024.0))
120
 
    else:
121
 
        return "%2.2f MB" % (val / (1024.0 * 1024.0))
122
 
 
123
 
def build_hostdev_label(hostdev):
124
 
    # String shown in the devices details section
125
 
    srclabel = ""
126
 
    # String shown in the VMs hardware list
127
 
    hwlabel = ""
128
 
 
129
 
    typ = hostdev.type
130
 
    vendor = hostdev.vendor
131
 
    product = hostdev.product
132
 
    addrbus = hostdev.bus
133
 
    addrdev = hostdev.device
134
 
    addrslt = hostdev.slot
135
 
    addrfun = hostdev.function
136
 
    addrdom = hostdev.domain
137
 
 
138
 
    def dehex(val):
139
 
        if val.startswith("0x"):
140
 
            val = val[2:]
141
 
        return val
142
 
 
143
 
    hwlabel = typ.upper()
144
 
    srclabel = typ.upper()
145
 
 
146
 
    if vendor and product:
147
 
        # USB by vendor + product
148
 
        devstr = " %s:%s" % (dehex(vendor), dehex(product))
149
 
        srclabel += devstr
150
 
        hwlabel += devstr
151
 
 
152
 
    elif addrbus and addrdev:
153
 
        # USB by bus + dev
154
 
        srclabel += (" Bus %s Device %s" %
155
 
                     (safeint(addrbus), safeint(addrdev)))
156
 
        hwlabel += " %s:%s" % (safeint(addrbus), safeint(addrdev))
157
 
 
158
 
    elif addrbus and addrslt and addrfun and addrdom:
159
 
        # PCI by bus:slot:function
160
 
        devstr = (" %s:%s:%s.%s" %
161
 
                  (dehex(addrdom), dehex(addrbus),
162
 
                   dehex(addrslt), dehex(addrfun)))
163
 
        srclabel += devstr
164
 
        hwlabel += devstr
165
 
 
166
 
    return srclabel, hwlabel
167
 
 
168
 
def lookup_nodedev(vmmconn, hostdev):
169
 
    def intify(val, do_hex=False):
170
 
        try:
171
 
            if do_hex:
172
 
                return int(val or '0x00', 16)
173
 
            else:
174
 
                return int(val)
175
 
        except:
176
 
            return -1
177
 
 
178
 
    def attrVal(node, attr):
179
 
        if not hasattr(node, attr):
180
 
            return None
181
 
        return getattr(node, attr)
182
 
 
183
 
    devtype     = hostdev.type
184
 
    vendor_id   = hostdev.vendor or -1
185
 
    product_id  = hostdev.product or -1
186
 
    device      = intify(hostdev.device, True)
187
 
    bus         = intify(hostdev.bus, True)
188
 
    domain      = intify(hostdev.domain, True)
189
 
    func        = intify(hostdev.function, True)
190
 
    slot        = intify(hostdev.slot, True)
191
 
    found_dev = None
192
 
 
193
 
    # For USB we want a device, not a bus
194
 
    if devtype == 'usb':
195
 
        devtype = 'usb_device'
196
 
 
197
 
    devs = vmmconn.get_devices(devtype, None)
198
 
    for dev in devs:
199
 
        # Try to get info from {product|vendor}_id
200
 
        if (attrVal(dev, "product_id") == product_id and
201
 
            attrVal(dev, "vendor_id") == vendor_id):
202
 
            found_dev = dev
203
 
            break
204
 
        else:
205
 
            # Try to get info from bus/addr
206
 
            dev_id = intify(attrVal(dev, "device"))
207
 
            bus_id = intify(attrVal(dev, "bus"))
208
 
            dom_id = intify(attrVal(dev, "domain"))
209
 
            func_id = intify(attrVal(dev, "function"))
210
 
            slot_id = intify(attrVal(dev, "slot"))
211
 
 
212
 
            if ((dev_id == device and bus_id == bus) or
213
 
                (dom_id == domain and func_id == func and
214
 
                 bus_id == bus and slot_id == slot)):
215
 
                found_dev = dev
216
 
                break
217
 
 
218
 
    return found_dev
219
 
 
220
 
class vmmDetails(vmmGObjectUI):
221
 
    __gsignals__ = {
222
 
        "action-show-console": (gobject.SIGNAL_RUN_FIRST,
223
 
                                gobject.TYPE_NONE, (str, str)),
224
 
        "action-save-domain": (gobject.SIGNAL_RUN_FIRST,
225
 
                                 gobject.TYPE_NONE, (str, str)),
226
 
        "action-destroy-domain": (gobject.SIGNAL_RUN_FIRST,
227
 
                                 gobject.TYPE_NONE, (str, str)),
228
 
        "action-suspend-domain": (gobject.SIGNAL_RUN_FIRST,
229
 
                                  gobject.TYPE_NONE, (str, str)),
230
 
        "action-resume-domain": (gobject.SIGNAL_RUN_FIRST,
231
 
                                 gobject.TYPE_NONE, (str, str)),
232
 
        "action-run-domain": (gobject.SIGNAL_RUN_FIRST,
233
 
                              gobject.TYPE_NONE, (str, str)),
234
 
        "action-shutdown-domain": (gobject.SIGNAL_RUN_FIRST,
235
 
                                   gobject.TYPE_NONE, (str, str)),
236
 
        "action-reboot-domain": (gobject.SIGNAL_RUN_FIRST,
237
 
                                 gobject.TYPE_NONE, (str, str)),
238
 
        "action-show-help": (gobject.SIGNAL_RUN_FIRST,
239
 
                               gobject.TYPE_NONE, [str]),
240
 
        "action-exit-app": (gobject.SIGNAL_RUN_FIRST,
241
 
                            gobject.TYPE_NONE, []),
242
 
        "action-view-manager": (gobject.SIGNAL_RUN_FIRST,
243
 
                                gobject.TYPE_NONE, []),
244
 
        "action-migrate-domain": (gobject.SIGNAL_RUN_FIRST,
245
 
                                  gobject.TYPE_NONE, (str, str)),
246
 
        "action-clone-domain": (gobject.SIGNAL_RUN_FIRST,
247
 
                                gobject.TYPE_NONE, (str, str)),
248
 
        "details-closed": (gobject.SIGNAL_RUN_FIRST,
249
 
                           gobject.TYPE_NONE, ()),
250
 
        }
251
 
 
252
 
 
253
 
    def __init__(self, vm, engine, parent=None):
254
 
        vmmGObjectUI.__init__(self, "vmm-details.glade", "vmm-details")
255
 
        self.vm = vm
256
 
        self.conn = self.vm.get_connection()
257
 
        self.engine = engine
258
 
 
259
 
        self.is_customize_dialog = False
260
 
        if parent:
261
 
            self.is_customize_dialog = True
262
 
            # Details window is being abused as a 'configure before install'
263
 
            # dialog, set things as appropriate
264
 
            self.topwin.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
265
 
            self.topwin.set_transient_for(parent)
266
 
 
267
 
            self.window.get_widget("customize-toolbar").show()
268
 
            self.window.get_widget("details-toolbar").hide()
269
 
            self.window.get_widget("details-menubar").hide()
270
 
            pages = self.window.get_widget("details-pages")
271
 
            pages.set_current_page(PAGE_DETAILS)
272
 
 
273
 
 
274
 
        self.serial_tabs = []
275
 
        self.last_console_page = PAGE_CONSOLE
276
 
        self.addhw = None
277
 
        self.media_choosers = {"cdrom": None, "floppy": None}
278
 
        self.storage_browser = None
279
 
 
280
 
        self.ignorePause = False
281
 
        self.ignoreDetails = False
282
 
        self._cpu_copy_host = False
283
 
 
284
 
        self.console = vmmConsolePages(self.vm, self.window)
285
 
 
286
 
        # Set default window size
287
 
        w, h = self.vm.get_details_window_size()
288
 
        self.topwin.set_default_size(w or 800, h or 600)
289
 
 
290
 
        self.addhwmenu = None
291
 
        self.init_menus()
292
 
        self.init_details()
293
 
 
294
 
        self.serial_popup = None
295
 
        self.serial_copy = None
296
 
        self.serial_paste = None
297
 
        self.serial_close = None
298
 
        self.init_serial()
299
 
 
300
 
        self.cpu_usage_graph = None
301
 
        self.memory_usage_graph = None
302
 
        self.disk_io_graph = None
303
 
        self.network_traffic_graph = None
304
 
        self.init_graphs()
305
 
 
306
 
        self.window.signal_autoconnect({
307
 
            "on_close_details_clicked": self.close,
308
 
            "on_details_menu_close_activate": self.close,
309
 
            "on_vmm_details_delete_event": self.close,
310
 
            "on_vmm_details_configure_event": self.window_resized,
311
 
            "on_details_menu_quit_activate": self.exit_app,
312
 
 
313
 
            "on_control_vm_details_toggled": self.details_console_changed,
314
 
            "on_control_vm_console_toggled": self.details_console_changed,
315
 
            "on_control_run_clicked": self.control_vm_run,
316
 
            "on_control_shutdown_clicked": self.control_vm_shutdown,
317
 
            "on_control_pause_toggled": self.control_vm_pause,
318
 
            "on_control_fullscreen_toggled": self.control_fullscreen,
319
 
 
320
 
            "on_details_customize_finish_clicked": self.close,
321
 
 
322
 
            "on_details_menu_run_activate": self.control_vm_run,
323
 
            "on_details_menu_poweroff_activate": self.control_vm_shutdown,
324
 
            "on_details_menu_reboot_activate": self.control_vm_reboot,
325
 
            "on_details_menu_save_activate": self.control_vm_save,
326
 
            "on_details_menu_destroy_activate": self.control_vm_destroy,
327
 
            "on_details_menu_pause_activate": self.control_vm_pause,
328
 
            "on_details_menu_clone_activate": self.control_vm_clone,
329
 
            "on_details_menu_migrate_activate": self.control_vm_migrate,
330
 
            "on_details_menu_screenshot_activate": self.control_vm_screenshot,
331
 
            "on_details_menu_graphics_activate": self.control_vm_console,
332
 
            "on_details_menu_view_toolbar_activate": self.toggle_toolbar,
333
 
            "on_details_menu_view_manager_activate": self.view_manager,
334
 
            "on_details_menu_view_details_toggled": self.details_console_changed,
335
 
            "on_details_menu_view_console_toggled": self.details_console_changed,
336
 
 
337
 
            "on_details_pages_switch_page": self.switch_page,
338
 
 
339
 
            "on_overview_acpi_changed": self.config_enable_apply,
340
 
            "on_overview_apic_changed": self.config_enable_apply,
341
 
            "on_overview_clock_changed": self.config_enable_apply,
342
 
            "on_security_label_changed": self.security_label_changed,
343
 
            "on_security_type_changed": self.security_type_changed,
344
 
 
345
 
            "on_config_vcpus_changed": self.config_vcpus_changed,
346
 
            "on_config_maxvcpus_changed": self.config_maxvcpus_changed,
347
 
            "on_config_vcpupin_changed": self.config_vcpus_changed,
348
 
            "on_config_vcpupin_generate_clicked": self.config_vcpupin_generate,
349
 
            "on_cpu_model_changed": self.config_enable_apply,
350
 
            "on_cpu_cores_changed": self.config_enable_apply,
351
 
            "on_cpu_sockets_changed": self.config_enable_apply,
352
 
            "on_cpu_threads_changed": self.config_enable_apply,
353
 
            "on_cpu_copy_host_clicked": self.config_cpu_copy_host,
354
 
            "on_cpu_topology_enable_toggled": self.config_cpu_topology_enable,
355
 
 
356
 
            "on_config_memory_changed": self.config_memory_changed,
357
 
            "on_config_maxmem_changed": self.config_maxmem_changed,
358
 
 
359
 
            "on_config_boot_moveup_clicked" : (self.config_boot_move, True),
360
 
            "on_config_boot_movedown_clicked" : (self.config_boot_move,
361
 
                                                 False),
362
 
            "on_config_autostart_changed": self.config_enable_apply,
363
 
            "on_boot_menu_changed": self.config_enable_apply,
364
 
            "on_boot_kernel_changed": self.config_enable_apply,
365
 
            "on_boot_kernel_initrd_changed": self.config_enable_apply,
366
 
            "on_boot_kernel_args_changed": self.config_enable_apply,
367
 
            "on_boot_kernel_browse_clicked": self.browse_kernel,
368
 
            "on_boot_kernel_initrd_browse_clicked": self.browse_initrd,
369
 
 
370
 
            "on_disk_readonly_changed": self.config_enable_apply,
371
 
            "on_disk_shareable_changed": self.config_enable_apply,
372
 
            "on_disk_cache_combo_changed": self.config_enable_apply,
373
 
            "on_disk_bus_combo_changed": self.config_enable_apply,
374
 
            "on_disk_format_changed": self.config_enable_apply,
375
 
 
376
 
            "on_network_model_combo_changed": self.config_enable_apply,
377
 
 
378
 
            "on_vnc_keymap_combo_changed": self.config_enable_apply,
379
 
            "on_vnc_password_changed": self.config_enable_apply,
380
 
 
381
 
            "on_sound_model_combo_changed": self.config_enable_apply,
382
 
 
383
 
            "on_video_model_combo_changed": self.config_enable_apply,
384
 
 
385
 
            "on_watchdog_model_combo_changed": self.config_enable_apply,
386
 
            "on_watchdog_action_combo_changed": self.config_enable_apply,
387
 
 
388
 
            "on_config_apply_clicked": self.config_apply,
389
 
 
390
 
            "on_details_help_activate": self.show_help,
391
 
 
392
 
            "on_config_cdrom_connect_clicked": self.toggle_storage_media,
393
 
            "on_config_remove_clicked": self.remove_xml_dev,
394
 
            "on_add_hardware_button_clicked": self.add_hardware,
395
 
 
396
 
            "on_hw_list_button_press_event": self.popup_addhw_menu,
397
 
 
398
 
            # Listeners stored in vmmConsolePages
399
 
            "on_details_menu_view_fullscreen_activate": self.console.toggle_fullscreen,
400
 
            "on_details_menu_view_size_to_vm_activate": self.console.size_to_vm,
401
 
            "on_details_menu_view_scale_always_toggled": self.console.set_scale_type,
402
 
            "on_details_menu_view_scale_fullscreen_toggled": self.console.set_scale_type,
403
 
            "on_details_menu_view_scale_never_toggled": self.console.set_scale_type,
404
 
 
405
 
            "on_details_menu_send_cad_activate": self.console.send_key,
406
 
            "on_details_menu_send_cab_activate": self.console.send_key,
407
 
            "on_details_menu_send_caf1_activate": self.console.send_key,
408
 
            "on_details_menu_send_caf2_activate": self.console.send_key,
409
 
            "on_details_menu_send_caf3_activate": self.console.send_key,
410
 
            "on_details_menu_send_caf4_activate": self.console.send_key,
411
 
            "on_details_menu_send_caf5_activate": self.console.send_key,
412
 
            "on_details_menu_send_caf6_activate": self.console.send_key,
413
 
            "on_details_menu_send_caf7_activate": self.console.send_key,
414
 
            "on_details_menu_send_caf8_activate": self.console.send_key,
415
 
            "on_details_menu_send_caf9_activate": self.console.send_key,
416
 
            "on_details_menu_send_caf10_activate": self.console.send_key,
417
 
            "on_details_menu_send_caf11_activate": self.console.send_key,
418
 
            "on_details_menu_send_caf12_activate": self.console.send_key,
419
 
            "on_details_menu_send_printscreen_activate": self.console.send_key,
420
 
 
421
 
            "on_console_auth_password_activate": self.console.auth_login,
422
 
            "on_console_auth_login_clicked": self.console.auth_login,
423
 
        })
424
 
 
425
 
        # Deliberately keep all this after signal connection
426
 
        self.vm.connect("status-changed", self.refresh_vm_state)
427
 
        self.vm.connect("config-changed", self.refresh_vm_state)
428
 
        self.vm.connect("resources-sampled", self.refresh_resources)
429
 
        self.window.get_widget("hw-list").get_selection().connect(
430
 
                                                        "changed",
431
 
                                                        self.hw_selected)
432
 
        self.window.get_widget("config-boot-list").get_selection().connect(
433
 
                                            "changed",
434
 
                                            self.config_bootdev_selected)
435
 
 
436
 
        finish_img = gtk.image_new_from_stock(gtk.STOCK_ADD,
437
 
                                              gtk.ICON_SIZE_BUTTON)
438
 
        self.window.get_widget("add-hardware-button").set_image(finish_img)
439
 
 
440
 
        self.populate_hw_list()
441
 
        self.repopulate_boot_list()
442
 
 
443
 
        self.hw_selected()
444
 
        self.refresh_vm_state()
445
 
 
446
 
 
447
 
    def show(self):
448
 
        vis = self.is_visible()
449
 
        self.topwin.present()
450
 
        if vis:
451
 
            return
452
 
 
453
 
        self.engine.increment_window_counter()
454
 
        self.refresh_vm_state()
455
 
 
456
 
    def close(self, ignore1=None, ignore2=None):
457
 
        fs = self.window.get_widget("details-menu-view-fullscreen")
458
 
        if fs.get_active():
459
 
            fs.set_active(False)
460
 
 
461
 
        if not self.is_visible():
462
 
            return
463
 
 
464
 
        self.topwin.hide()
465
 
        if self.console.viewer and self.console.viewer.get_widget() and \
466
 
                self.console.viewer.get_widget().flags() & gtk.VISIBLE:
467
 
            try:
468
 
                self.console.close_viewer()
469
 
            except:
470
 
                logging.error("Failure when disconnecting from desktop server")
471
 
        self.engine.decrement_window_counter()
472
 
 
473
 
        self.emit("details-closed")
474
 
        return 1
475
 
 
476
 
    def is_visible(self):
477
 
        return bool(self.topwin.flags() & gtk.VISIBLE)
478
 
 
479
 
 
480
 
    ##########################
481
 
    # Initialization helpers #
482
 
    ##########################
483
 
 
484
 
    def init_menus(self):
485
 
        # Shutdown button menu
486
 
        uihelpers.build_shutdown_button_menu(
487
 
                                   self.window.get_widget("control-shutdown"),
488
 
                                   self.control_vm_shutdown,
489
 
                                   self.control_vm_reboot,
490
 
                                   self.control_vm_destroy,
491
 
                                   self.control_vm_save)
492
 
 
493
 
        icon_name = self.config.get_shutdown_icon_name()
494
 
        for name in ["details-menu-shutdown",
495
 
                     "details-menu-reboot",
496
 
                     "details-menu-poweroff",
497
 
                     "details-menu-destroy"]:
498
 
            image = gtk.image_new_from_icon_name(icon_name, gtk.ICON_SIZE_MENU)
499
 
            self.window.get_widget(name).set_image(image)
500
 
 
501
 
        # Add HW popup menu
502
 
        self.addhwmenu = gtk.Menu()
503
 
        addHW = gtk.ImageMenuItem(_("Add Hardware"))
504
 
        addHWImg = gtk.Image()
505
 
        addHWImg.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU)
506
 
        addHW.set_image(addHWImg)
507
 
        addHW.show()
508
 
        addHW.connect("activate", self.add_hardware)
509
 
        self.addhwmenu.add(addHW)
510
 
 
511
 
        # Serial list menu
512
 
        smenu = gtk.Menu()
513
 
        smenu.connect("show", self.populate_serial_menu)
514
 
        self.window.get_widget("details-menu-view-serial-list").set_submenu(smenu)
515
 
 
516
 
        # Don't allowing changing network/disks for Dom0
517
 
        dom0 = self.vm.is_management_domain()
518
 
        self.window.get_widget("add-hardware-button").set_sensitive(not dom0)
519
 
 
520
 
        self.window.get_widget("hw-panel").set_show_tabs(False)
521
 
        self.window.get_widget("details-pages").set_show_tabs(False)
522
 
        self.window.get_widget("console-pages").set_show_tabs(False)
523
 
        self.window.get_widget("details-menu-view-toolbar").set_active(self.config.get_details_show_toolbar())
524
 
 
525
 
        # XXX: Help docs useless/out of date
526
 
        self.window.get_widget("help_menuitem").hide()
527
 
 
528
 
    def init_serial(self):
529
 
        self.serial_popup = gtk.Menu()
530
 
 
531
 
        self.serial_copy = gtk.ImageMenuItem(gtk.STOCK_COPY)
532
 
        self.serial_popup.add(self.serial_copy)
533
 
 
534
 
        self.serial_paste = gtk.ImageMenuItem(gtk.STOCK_PASTE)
535
 
        self.serial_popup.add(self.serial_paste)
536
 
 
537
 
        self.serial_popup.add(gtk.SeparatorMenuItem())
538
 
 
539
 
        self.serial_close = gtk.ImageMenuItem(_("Close tab"))
540
 
        close_image = gtk.Image()
541
 
        close_image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
542
 
        self.serial_close.set_image(close_image)
543
 
        self.serial_popup.add(self.serial_close)
544
 
 
545
 
    def init_graphs(self):
546
 
        graph_table = self.window.get_widget("graph-table")
547
 
 
548
 
        self.cpu_usage_graph = Sparkline()
549
 
        self.cpu_usage_graph.set_property("reversed", True)
550
 
        graph_table.attach(self.cpu_usage_graph, 1, 2, 0, 1)
551
 
 
552
 
        self.memory_usage_graph = Sparkline()
553
 
        self.memory_usage_graph.set_property("reversed", True)
554
 
        graph_table.attach(self.memory_usage_graph, 1, 2, 1, 2)
555
 
 
556
 
        self.disk_io_graph = Sparkline()
557
 
        self.disk_io_graph.set_property("reversed", True)
558
 
        self.disk_io_graph.set_property("filled", False)
559
 
        self.disk_io_graph.set_property("num_sets", 2)
560
 
        self.disk_io_graph.set_property("rgb", map(lambda x: x / 255.0,
561
 
                                        [0x82, 0x00, 0x3B, 0x29, 0x5C, 0x45]))
562
 
        graph_table.attach(self.disk_io_graph, 1, 2, 2, 3)
563
 
 
564
 
        self.network_traffic_graph = Sparkline()
565
 
        self.network_traffic_graph.set_property("reversed", True)
566
 
        self.network_traffic_graph.set_property("filled", False)
567
 
        self.network_traffic_graph.set_property("num_sets", 2)
568
 
        self.network_traffic_graph.set_property("rgb",
569
 
                                                map(lambda x: x / 255.0,
570
 
                                                    [0x82, 0x00, 0x3B,
571
 
                                                     0x29, 0x5C, 0x45]))
572
 
        graph_table.attach(self.network_traffic_graph, 1, 2, 3, 4)
573
 
 
574
 
        graph_table.show_all()
575
 
 
576
 
    def init_details(self):
577
 
        # Hardware list
578
 
        # [ label, icon name, icon size, hw type, hw data/class]
579
 
        hw_list_model = gtk.ListStore(str, str, int, int,
580
 
                                      gobject.TYPE_PYOBJECT)
581
 
        self.window.get_widget("hw-list").set_model(hw_list_model)
582
 
 
583
 
        hwCol = gtk.TreeViewColumn("Hardware")
584
 
        hwCol.set_spacing(6)
585
 
        hwCol.set_min_width(165)
586
 
        hw_txt = gtk.CellRendererText()
587
 
        hw_img = gtk.CellRendererPixbuf()
588
 
        hwCol.pack_start(hw_img, False)
589
 
        hwCol.pack_start(hw_txt, True)
590
 
        hwCol.add_attribute(hw_txt, 'text', HW_LIST_COL_LABEL)
591
 
        hwCol.add_attribute(hw_img, 'stock-size', HW_LIST_COL_ICON_SIZE)
592
 
        hwCol.add_attribute(hw_img, 'icon-name', HW_LIST_COL_ICON_NAME)
593
 
        self.window.get_widget("hw-list").append_column(hwCol)
594
 
 
595
 
        # Description text view
596
 
        desc = self.window.get_widget("overview-description")
597
 
        buf = gtk.TextBuffer()
598
 
        buf.connect("changed", self.config_enable_apply)
599
 
        desc.set_buffer(buf)
600
 
 
601
 
        # Clock combo
602
 
        clock_combo = self.window.get_widget("overview-clock-combo")
603
 
        clock_model = gtk.ListStore(str)
604
 
        clock_combo.set_model(clock_model)
605
 
        text = gtk.CellRendererText()
606
 
        clock_combo.pack_start(text, True)
607
 
        clock_combo.add_attribute(text, 'text', 0)
608
 
        clock_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
609
 
        for offset in ["localtime", "utc"]:
610
 
            clock_model.append([offset])
611
 
 
612
 
        # Security info tooltips
613
 
        util.tooltip_wrapper(self.window.get_widget("security-static-info"),
614
 
            _("Static SELinux security type tells libvirt to always start the guest process with the specified label. The administrator is responsible for making sure the images are labeled correctly on disk."))
615
 
        util.tooltip_wrapper(self.window.get_widget("security-dynamic-info"),
616
 
            _("The dynamic SELinux security type tells libvirt to automatically pick a unique label for the guest process and guest image, ensuring total isolation of the guest. (Default)"))
617
 
 
618
 
        # VCPU Pinning list
619
 
        generate_cpuset = self.window.get_widget("config-vcpupin-generate")
620
 
        generate_warn = self.window.get_widget("config-vcpupin-generate-err")
621
 
        if not self.conn.get_capabilities().host.topology:
622
 
            generate_cpuset.set_sensitive(False)
623
 
            generate_warn.show()
624
 
            util.tooltip_wrapper(generate_warn,
625
 
                                 _("Libvirt did not detect NUMA capabilities."))
626
 
 
627
 
 
628
 
        # [ VCPU #, Currently running on Phys CPU #, CPU Pinning list ]
629
 
        vcpu_list = self.window.get_widget("config-vcpu-list")
630
 
        vcpu_model = gtk.ListStore(str, str, str)
631
 
        vcpu_list.set_model(vcpu_model)
632
 
 
633
 
        vcpuCol = gtk.TreeViewColumn(_("VCPU"))
634
 
        physCol = gtk.TreeViewColumn(_("On CPU"))
635
 
        pinCol  = gtk.TreeViewColumn(_("Pinning"))
636
 
 
637
 
        vcpu_list.append_column(vcpuCol)
638
 
        vcpu_list.append_column(physCol)
639
 
        vcpu_list.append_column(pinCol)
640
 
 
641
 
        vcpu_text = gtk.CellRendererText()
642
 
        vcpuCol.pack_start(vcpu_text, True)
643
 
        vcpuCol.add_attribute(vcpu_text, 'text', 0)
644
 
        vcpuCol.set_sort_column_id(0)
645
 
 
646
 
        phys_text = gtk.CellRendererText()
647
 
        physCol.pack_start(phys_text, True)
648
 
        physCol.add_attribute(phys_text, 'text', 1)
649
 
        physCol.set_sort_column_id(1)
650
 
 
651
 
        pin_text = gtk.CellRendererText()
652
 
        pin_text.set_property("editable", True)
653
 
        pin_text.connect("edited", self.config_vcpu_pin)
654
 
        pinCol.pack_start(pin_text, True)
655
 
        pinCol.add_attribute(pin_text, 'text', 2)
656
 
 
657
 
        # Boot device list
658
 
        boot_list = self.window.get_widget("config-boot-list")
659
 
        # model = [ XML boot type, display name, icon name, enabled ]
660
 
        boot_list_model = gtk.ListStore(str, str, str, bool)
661
 
        boot_list.set_model(boot_list_model)
662
 
 
663
 
        chkCol = gtk.TreeViewColumn()
664
 
        txtCol = gtk.TreeViewColumn()
665
 
 
666
 
        boot_list.append_column(chkCol)
667
 
        boot_list.append_column(txtCol)
668
 
 
669
 
        chk = gtk.CellRendererToggle()
670
 
        chk.connect("toggled", self.config_boot_toggled)
671
 
        chkCol.pack_start(chk, False)
672
 
        chkCol.add_attribute(chk, 'active', BOOT_ACTIVE)
673
 
 
674
 
        icon = gtk.CellRendererPixbuf()
675
 
        txtCol.pack_start(icon, False)
676
 
        txtCol.add_attribute(icon, 'icon-name', BOOT_ICON)
677
 
 
678
 
        text = gtk.CellRendererText()
679
 
        txtCol.pack_start(text, True)
680
 
        txtCol.add_attribute(text, 'text', BOOT_LABEL)
681
 
        txtCol.add_attribute(text, 'sensitive', BOOT_ACTIVE)
682
 
 
683
 
        no_default = not self.is_customize_dialog
684
 
 
685
 
        # CPU model combo
686
 
        caps = self.vm.get_connection().get_capabilities()
687
 
        cpu_values = None
688
 
        cpu_names = []
689
 
 
690
 
        try:
691
 
            cpu_values = caps.get_cpu_values(self.vm.get_arch())
692
 
            cpu_names = sorted(map(lambda c: c.model, cpu_values.cpus),
693
 
                               key=str.lower)
694
 
        except:
695
 
            logging.exception("Error populating CPU model list")
696
 
 
697
 
        cpu_model = self.window.get_widget("cpu-model")
698
 
 
699
 
        model = gtk.ListStore(str, object)
700
 
        cpu_model.set_model(model)
701
 
        cpu_model.set_text_column(0)
702
 
        model.set_sort_column_id(0, gtk.SORT_ASCENDING)
703
 
        for name in cpu_names:
704
 
            model.append([name, cpu_values.get_cpu(name)])
705
 
 
706
 
        # Disk cache combo
707
 
        disk_cache = self.window.get_widget("disk-cache-combo")
708
 
        uihelpers.build_cache_combo(self.vm, disk_cache)
709
 
 
710
 
        # Disk format combo
711
 
        format_list = self.window.get_widget("disk-format")
712
 
        uihelpers.build_storage_format_combo(self.vm, format_list)
713
 
 
714
 
        # Disk bus combo
715
 
        disk_bus = self.window.get_widget("disk-bus-combo")
716
 
        uihelpers.build_disk_bus_combo(self.vm, disk_bus)
717
 
 
718
 
        # Network model
719
 
        net_model = self.window.get_widget("network-model-combo")
720
 
        uihelpers.build_netmodel_combo(self.vm, net_model)
721
 
 
722
 
        # Graphics keymap
723
 
        vnc_keymap = self.window.get_widget("gfx-keymap-combo")
724
 
        uihelpers.build_vnc_keymap_combo(self.vm, vnc_keymap,
725
 
                                         no_default=no_default)
726
 
 
727
 
        # Sound model
728
 
        sound_dev = self.window.get_widget("sound-model-combo")
729
 
        uihelpers.build_sound_combo(self.vm, sound_dev, no_default=no_default)
730
 
 
731
 
        # Video model combo
732
 
        video_dev = self.window.get_widget("video-model-combo")
733
 
        uihelpers.build_video_combo(self.vm, video_dev, no_default=no_default)
734
 
 
735
 
        # Watchdog model combo
736
 
        combo = self.window.get_widget("watchdog-model-combo")
737
 
        uihelpers.build_watchdogmodel_combo(self.vm, combo,
738
 
                                            no_default=no_default)
739
 
 
740
 
        # Watchdog action combo
741
 
        combo = self.window.get_widget("watchdog-action-combo")
742
 
        uihelpers.build_watchdogaction_combo(self.vm, combo,
743
 
                                             no_default=no_default)
744
 
 
745
 
    # Helper function to handle the combo/label pattern used for
746
 
    # video model, sound model, network model, etc.
747
 
    def set_combo_label(self, prefix, model_idx, value):
748
 
        model_label = self.window.get_widget(prefix + "-label")
749
 
        model_combo = self.window.get_widget(prefix + "-combo")
750
 
        model_list = map(lambda x: x[model_idx], model_combo.get_model())
751
 
        model_in_list = (value in model_list)
752
 
 
753
 
        model_label.set_property("visible", not model_in_list)
754
 
        model_combo.set_property("visible", model_in_list)
755
 
        model_label.set_text(value or "")
756
 
 
757
 
        if model_in_list:
758
 
            model_combo.set_active(model_list.index(value))
759
 
 
760
 
    ##########################
761
 
    # Window state listeners #
762
 
    ##########################
763
 
 
764
 
    def window_resized(self, ignore, event):
765
 
        # Sometimes dimensions change when window isn't visible
766
 
        if not self.is_visible():
767
 
            return
768
 
 
769
 
        self.vm.set_details_window_size(event.width, event.height)
770
 
 
771
 
    def popup_addhw_menu(self, widget, event):
772
 
        ignore = widget
773
 
        if event.button != 3:
774
 
            return
775
 
 
776
 
        self.addhwmenu.popup(None, None, None, 0, event.time)
777
 
 
778
 
    def populate_serial_menu(self, src):
779
 
        for ent in src:
780
 
            src.remove(ent)
781
 
 
782
 
        devs = self.vm.get_serial_devs()
783
 
        if len(devs) == 0:
784
 
            item = gtk.MenuItem(_("No text console available"))
785
 
            item.set_sensitive(False)
786
 
            src.add(item)
787
 
 
788
 
        on_serial = (self.last_console_page >= PAGE_DYNAMIC_OFFSET)
789
 
        serial_page_dev = None
790
 
        if on_serial:
791
 
            serial_idx = self.last_console_page - PAGE_DYNAMIC_OFFSET
792
 
            if len(self.serial_tabs) >= serial_idx:
793
 
                serial_page_dev = self.serial_tabs[serial_idx]
794
 
        on_graphics = (self.last_console_page == PAGE_CONSOLE)
795
 
 
796
 
        group = None
797
 
        usable_types = ["pty"]
798
 
        for dev in devs:
799
 
            sensitive = False
800
 
            msg = ""
801
 
            item = gtk.RadioMenuItem(group, dev[0])
802
 
            if group == None:
803
 
                group = item
804
 
 
805
 
            if self.vm.get_connection().is_remote():
806
 
                msg = _("Serial console not yet supported over remote "
807
 
                        "connection.")
808
 
            elif not self.vm.is_active():
809
 
                msg = _("Serial console not available for inactive guest.")
810
 
            elif not dev[1] in usable_types:
811
 
                msg = _("Console for device type '%s' not yet supported.") % \
812
 
                        dev[1]
813
 
            elif dev[2] and not os.access(dev[2], os.R_OK | os.W_OK):
814
 
                msg = _("Can not access console path '%s'.") % str(dev[2])
815
 
            else:
816
 
                sensitive = True
817
 
 
818
 
            if not sensitive:
819
 
                util.tooltip_wrapper(item, msg)
820
 
            item.set_sensitive(sensitive)
821
 
 
822
 
            if sensitive and on_serial and serial_page_dev == dev[0]:
823
 
                # Tab is already open, make sure marked as such
824
 
                item.set_active(True)
825
 
            item.connect("toggled", self.control_serial_tab, dev[0], dev[3])
826
 
            src.add(item)
827
 
 
828
 
        src.add(gtk.SeparatorMenuItem())
829
 
 
830
 
        devs = self.vm.get_graphics_devices()
831
 
        if len(devs) == 0:
832
 
            item = gtk.MenuItem(_("No graphical console available"))
833
 
            item.set_sensitive(False)
834
 
            src.add(item)
835
 
        else:
836
 
            dev = devs[0]
837
 
            item = gtk.RadioMenuItem(group, _("Graphical Console %s") %
838
 
                                     dev.type.upper())
839
 
            if group == None:
840
 
                group = item
841
 
 
842
 
            if on_graphics:
843
 
                item.set_active(True)
844
 
            item.connect("toggled", self.control_serial_tab,
845
 
                         dev.virtual_device_type, dev.type)
846
 
            src.add(item)
847
 
 
848
 
        src.show_all()
849
 
 
850
 
    def control_fullscreen(self, src):
851
 
        menu = self.window.get_widget("details-menu-view-fullscreen")
852
 
        if src.get_active() != menu.get_active():
853
 
            menu.set_active(src.get_active())
854
 
 
855
 
    def toggle_toolbar(self, src):
856
 
        active = src.get_active()
857
 
        self.config.set_details_show_toolbar(active)
858
 
        if active and not \
859
 
           self.window.get_widget("details-menu-view-fullscreen").get_active():
860
 
            self.window.get_widget("toolbar-box").show()
861
 
        else:
862
 
            self.window.get_widget("toolbar-box").hide()
863
 
 
864
 
    def get_boot_selection(self):
865
 
        widget = self.window.get_widget("config-boot-list")
866
 
        selection = widget.get_selection()
867
 
        model, treepath = selection.get_selected()
868
 
        if treepath == None:
869
 
            return None
870
 
        return model[treepath]
871
 
 
872
 
    def set_hw_selection(self, page):
873
 
        hwlist = self.window.get_widget("hw-list")
874
 
        selection = hwlist.get_selection()
875
 
        selection.select_path(str(page))
876
 
 
877
 
    def get_hw_selection(self, field):
878
 
        vmlist = self.window.get_widget("hw-list")
879
 
        selection = vmlist.get_selection()
880
 
        active = selection.get_selected()
881
 
        if active[1] == None:
882
 
            return None
883
 
        return active[0].get_value(active[1], field)
884
 
 
885
 
    def force_get_hw_pagetype(self, page=None):
886
 
        if page:
887
 
            return page
888
 
 
889
 
        page = self.get_hw_selection(HW_LIST_COL_TYPE)
890
 
        if page is None:
891
 
            page = HW_LIST_TYPE_GENERAL
892
 
            self.window.get_widget("hw-list").get_selection().select_path(0)
893
 
 
894
 
        return page
895
 
 
896
 
    def hw_selected(self, ignore1=None, page=None, selected=True):
897
 
        pagetype = self.force_get_hw_pagetype(page)
898
 
 
899
 
        self.window.get_widget("config-remove").set_sensitive(True)
900
 
        self.window.get_widget("hw-panel").set_sensitive(True)
901
 
        self.window.get_widget("hw-panel").show()
902
 
 
903
 
        try:
904
 
            if pagetype == HW_LIST_TYPE_GENERAL:
905
 
                self.refresh_overview_page()
906
 
            elif pagetype == HW_LIST_TYPE_STATS:
907
 
                self.refresh_stats_page()
908
 
            elif pagetype == HW_LIST_TYPE_CPU:
909
 
                self.refresh_config_cpu()
910
 
            elif pagetype == HW_LIST_TYPE_MEMORY:
911
 
                self.refresh_config_memory()
912
 
            elif pagetype == HW_LIST_TYPE_BOOT:
913
 
                self.refresh_boot_page()
914
 
            elif pagetype == HW_LIST_TYPE_DISK:
915
 
                self.refresh_disk_page()
916
 
            elif pagetype == HW_LIST_TYPE_NIC:
917
 
                self.refresh_network_page()
918
 
            elif pagetype == HW_LIST_TYPE_INPUT:
919
 
                self.refresh_input_page()
920
 
            elif pagetype == HW_LIST_TYPE_GRAPHICS:
921
 
                self.refresh_graphics_page()
922
 
            elif pagetype == HW_LIST_TYPE_SOUND:
923
 
                self.refresh_sound_page()
924
 
            elif pagetype == HW_LIST_TYPE_CHAR:
925
 
                self.refresh_char_page()
926
 
            elif pagetype == HW_LIST_TYPE_HOSTDEV:
927
 
                self.refresh_hostdev_page()
928
 
            elif pagetype == HW_LIST_TYPE_VIDEO:
929
 
                self.refresh_video_page()
930
 
            elif pagetype == HW_LIST_TYPE_WATCHDOG:
931
 
                self.refresh_watchdog_page()
932
 
            elif pagetype == HW_LIST_TYPE_CONTROLLER:
933
 
                self.refresh_controller_page()
934
 
            else:
935
 
                pagetype = -1
936
 
        except Exception, e:
937
 
            self.err.show_err(_("Error refreshing hardware page: %s") % str(e),
938
 
                              "".join(traceback.format_exc()))
939
 
            return
940
 
 
941
 
        rem = pagetype in remove_pages
942
 
        if selected:
943
 
            self.window.get_widget("config-apply").set_sensitive(False)
944
 
        self.window.get_widget("config-remove").set_property("visible", rem)
945
 
 
946
 
        self.window.get_widget("hw-panel").set_current_page(pagetype)
947
 
 
948
 
    def details_console_changed(self, src):
949
 
        if self.ignoreDetails:
950
 
            return
951
 
 
952
 
        if not src.get_active():
953
 
            return
954
 
 
955
 
        is_details = False
956
 
        if (src == self.window.get_widget("control-vm-details") or
957
 
            src == self.window.get_widget("details-menu-view-details")):
958
 
            is_details = True
959
 
 
960
 
        pages = self.window.get_widget("details-pages")
961
 
        if is_details:
962
 
            pages.set_current_page(PAGE_DETAILS)
963
 
        else:
964
 
            pages.set_current_page(self.last_console_page)
965
 
 
966
 
    def sync_details_console_view(self, is_details):
967
 
        details = self.window.get_widget("control-vm-details")
968
 
        details_menu = self.window.get_widget("details-menu-view-details")
969
 
        console = self.window.get_widget("control-vm-console")
970
 
        console_menu = self.window.get_widget("details-menu-view-console")
971
 
 
972
 
        try:
973
 
            self.ignoreDetails = True
974
 
 
975
 
            details.set_active(is_details)
976
 
            details_menu.set_active(is_details)
977
 
            console.set_active(not is_details)
978
 
            console_menu.set_active(not is_details)
979
 
        finally:
980
 
            self.ignoreDetails = False
981
 
 
982
 
    def switch_page(self, ignore1=None, ignore2=None, newpage=None):
983
 
        self.page_refresh(newpage)
984
 
 
985
 
        self.sync_details_console_view(newpage == PAGE_DETAILS)
986
 
 
987
 
        if newpage == PAGE_CONSOLE or newpage >= PAGE_DYNAMIC_OFFSET:
988
 
            self.last_console_page = newpage
989
 
 
990
 
    def change_run_text(self, can_restore):
991
 
        if can_restore:
992
 
            text = _("_Restore")
993
 
        else:
994
 
            text = _("_Run")
995
 
        strip_text = text.replace("_", "")
996
 
 
997
 
        self.window.get_widget("details-menu-run").get_child().set_label(text)
998
 
        self.window.get_widget("control-run").set_label(strip_text)
999
 
 
1000
 
    def refresh_vm_state(self, ignore1=None, ignore2=None, ignore3=None):
1001
 
        vm = self.vm
1002
 
        status = self.vm.status()
1003
 
 
1004
 
        self.toggle_toolbar(
1005
 
            self.window.get_widget("details-menu-view-toolbar"))
1006
 
 
1007
 
        destroy = vm.is_destroyable()
1008
 
        run     = vm.is_runable()
1009
 
        stop    = vm.is_stoppable()
1010
 
        paused  = vm.is_paused()
1011
 
        ro      = vm.is_read_only()
1012
 
 
1013
 
        if vm.managedsave_supported:
1014
 
            self.change_run_text(vm.hasSavedImage())
1015
 
 
1016
 
        self.window.get_widget("details-menu-destroy").set_sensitive(destroy)
1017
 
        self.window.get_widget("control-run").set_sensitive(run)
1018
 
        self.window.get_widget("details-menu-run").set_sensitive(run)
1019
 
 
1020
 
        self.window.get_widget("details-menu-migrate").set_sensitive(stop)
1021
 
        self.window.get_widget("control-shutdown").set_sensitive(stop)
1022
 
        self.window.get_widget("details-menu-shutdown").set_sensitive(stop)
1023
 
        self.window.get_widget("details-menu-save").set_sensitive(stop)
1024
 
        self.window.get_widget("control-pause").set_sensitive(stop)
1025
 
        self.window.get_widget("details-menu-pause").set_sensitive(stop)
1026
 
 
1027
 
        # Set pause widget states
1028
 
        try:
1029
 
            self.ignorePause = True
1030
 
            self.window.get_widget("control-pause").set_active(paused)
1031
 
            self.window.get_widget("details-menu-pause").set_active(paused)
1032
 
        finally:
1033
 
            self.ignorePause = False
1034
 
 
1035
 
        self.window.get_widget("config-vcpus").set_sensitive(not ro)
1036
 
        self.window.get_widget("config-vcpupin").set_sensitive(not ro)
1037
 
        self.window.get_widget("config-memory").set_sensitive(not ro)
1038
 
        self.window.get_widget("config-maxmem").set_sensitive(not ro)
1039
 
 
1040
 
        # Disable send key menu entries for offline VM
1041
 
        send_key = self.window.get_widget("details-menu-send-key")
1042
 
        for c in send_key.get_submenu().get_children():
1043
 
            c.set_sensitive(not (run or paused))
1044
 
 
1045
 
        self.console.update_widget_states(vm, status)
1046
 
 
1047
 
        self.window.get_widget("overview-status-text").set_text(
1048
 
                                                    self.vm.run_status())
1049
 
        self.window.get_widget("overview-status-icon").set_from_pixbuf(
1050
 
                                                    self.vm.run_status_icon())
1051
 
 
1052
 
        details = self.window.get_widget("details-pages")
1053
 
        self.page_refresh(details.get_current_page())
1054
 
 
1055
 
        # This is safe to refresh, and is dependent on domain state
1056
 
        self._refresh_runtime_pinning()
1057
 
 
1058
 
 
1059
 
    #############################
1060
 
    # External action listeners #
1061
 
    #############################
1062
 
 
1063
 
    def show_help(self, src_ignore):
1064
 
        self.emit("action-show-help", "virt-manager-details-window")
1065
 
 
1066
 
    def view_manager(self, src_ignore):
1067
 
        self.emit("action-view-manager")
1068
 
 
1069
 
    def exit_app(self, src_ignore):
1070
 
        self.emit("action-exit-app")
1071
 
 
1072
 
    def activate_console_page(self):
1073
 
        self.window.get_widget("details-pages").set_current_page(PAGE_CONSOLE)
1074
 
 
1075
 
    def activate_performance_page(self):
1076
 
        self.window.get_widget("details-pages").set_current_page(PAGE_DETAILS)
1077
 
        self.set_hw_selection(HW_LIST_TYPE_STATS)
1078
 
 
1079
 
    def activate_config_page(self):
1080
 
        self.window.get_widget("details-pages").set_current_page(PAGE_DETAILS)
1081
 
 
1082
 
    def add_hardware(self, src_ignore):
1083
 
        if self.addhw is None:
1084
 
            self.addhw = vmmAddHardware(self.vm)
1085
 
 
1086
 
        self.addhw.show()
1087
 
 
1088
 
    def remove_xml_dev(self, src_ignore):
1089
 
        info = self.get_hw_selection(HW_LIST_COL_DEVICE)
1090
 
        if not info:
1091
 
            return
1092
 
 
1093
 
        devtype = info.virtual_device_type
1094
 
        self.remove_device(devtype, info)
1095
 
 
1096
 
    def control_vm_pause(self, src):
1097
 
        if self.ignorePause:
1098
 
            return
1099
 
 
1100
 
        if src.get_active():
1101
 
            self.emit("action-suspend-domain",
1102
 
                      self.vm.get_connection().get_uri(),
1103
 
                      self.vm.get_uuid())
1104
 
        else:
1105
 
            self.emit("action-resume-domain",
1106
 
                      self.vm.get_connection().get_uri(),
1107
 
                      self.vm.get_uuid())
1108
 
 
1109
 
    def control_vm_run(self, src_ignore):
1110
 
        self.emit("action-run-domain",
1111
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1112
 
 
1113
 
    def control_vm_shutdown(self, src_ignore):
1114
 
        self.emit("action-shutdown-domain",
1115
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1116
 
 
1117
 
    def control_vm_reboot(self, src_ignore):
1118
 
        self.emit("action-reboot-domain",
1119
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1120
 
 
1121
 
    def control_vm_console(self, src_ignore):
1122
 
        self.emit("action-show-console",
1123
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1124
 
 
1125
 
    def control_vm_save(self, src_ignore):
1126
 
        self.emit("action-save-domain",
1127
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1128
 
 
1129
 
    def control_vm_destroy(self, src_ignore):
1130
 
        self.emit("action-destroy-domain",
1131
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1132
 
 
1133
 
    def control_vm_clone(self, src_ignore):
1134
 
        self.emit("action-clone-domain",
1135
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1136
 
 
1137
 
    def control_vm_migrate(self, src_ignore):
1138
 
        self.emit("action-migrate-domain",
1139
 
                  self.vm.get_connection().get_uri(), self.vm.get_uuid())
1140
 
 
1141
 
    def control_vm_screenshot(self, src_ignore):
1142
 
        # If someone feels kind they could extend this code to allow
1143
 
        # user to choose what image format they'd like to save in....
1144
 
        path = util.browse_local(
1145
 
                        self.topwin,
1146
 
                        _("Save Virtual Machine Screenshot"),
1147
 
                        self.vm.get_connection(),
1148
 
                        _type=("png", "PNG files"),
1149
 
                        dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE,
1150
 
                        browse_reason=self.config.CONFIG_DIR_SCREENSHOT)
1151
 
        if not path:
1152
 
            return
1153
 
 
1154
 
        filename = path
1155
 
        if not(filename.endswith(".png")):
1156
 
            filename += ".png"
1157
 
        image = self.console.viewer.get_pixbuf()
1158
 
 
1159
 
        # Save along with a little metadata about us & the domain
1160
 
        image.save(filename, 'png',
1161
 
                   {'tEXt::Hypervisor URI': self.vm.get_connection().get_uri(),
1162
 
                    'tEXt::Domain Name': self.vm.get_name(),
1163
 
                    'tEXt::Domain UUID': self.vm.get_uuid(),
1164
 
                    'tEXt::Generator App': self.config.get_appname(),
1165
 
                    'tEXt::Generator Version': self.config.get_appversion()})
1166
 
 
1167
 
        msg = gtk.MessageDialog(self.topwin,
1168
 
                                gtk.DIALOG_MODAL,
1169
 
                                gtk.MESSAGE_INFO,
1170
 
                                gtk.BUTTONS_OK,
1171
 
                                (_("The screenshot has been saved to:\n%s") %
1172
 
                                 filename))
1173
 
        msg.set_title(_("Screenshot saved"))
1174
 
        msg.run()
1175
 
        msg.destroy()
1176
 
 
1177
 
 
1178
 
    # ------------------------------
1179
 
    # Serial Console pieces
1180
 
    # ------------------------------
1181
 
 
1182
 
    def control_serial_tab(self, src_ignore, name, target_port):
1183
 
        is_graphics = (name == "graphics")
1184
 
        is_serial = not is_graphics
1185
 
 
1186
 
        if is_graphics:
1187
 
            self.window.get_widget("details-pages").set_current_page(PAGE_CONSOLE)
1188
 
        elif is_serial:
1189
 
            self._show_serial_tab(name, target_port)
1190
 
 
1191
 
    def show_serial_rcpopup(self, src, event):
1192
 
        if event.button != 3:
1193
 
            return
1194
 
 
1195
 
        self.serial_popup.show_all()
1196
 
        self.serial_copy.connect("activate", self.serial_copy_text, src)
1197
 
        self.serial_paste.connect("activate", self.serial_paste_text, src)
1198
 
        self.serial_close.connect("activate", self.serial_close_tab,
1199
 
                                  self.window.get_widget("details-pages").get_current_page())
1200
 
 
1201
 
        if src.get_has_selection():
1202
 
            self.serial_copy.set_sensitive(True)
1203
 
        else:
1204
 
            self.serial_copy.set_sensitive(False)
1205
 
        self.serial_popup.popup(None, None, None, 0, event.time)
1206
 
 
1207
 
    def serial_close_tab(self, src_ignore, pagenum):
1208
 
        tab_idx = (pagenum - PAGE_DYNAMIC_OFFSET)
1209
 
        if (tab_idx < 0) or (tab_idx > len(self.serial_tabs) - 1):
1210
 
            return
1211
 
        return self._close_serial_tab(self.serial_tabs[tab_idx])
1212
 
 
1213
 
    def serial_copy_text(self, src_ignore, terminal):
1214
 
        terminal.copy_clipboard()
1215
 
 
1216
 
    def serial_paste_text(self, src_ignore, terminal):
1217
 
        terminal.paste_clipboard()
1218
 
 
1219
 
    def _show_serial_tab(self, name, target_port):
1220
 
        if not self.serial_tabs.count(name):
1221
 
            child = vmmSerialConsole(self.vm, target_port)
1222
 
            child.terminal.connect("button-press-event",
1223
 
                                   self.show_serial_rcpopup)
1224
 
            title = gtk.Label(name)
1225
 
            child.show_all()
1226
 
            self.window.get_widget("details-pages").append_page(child, title)
1227
 
            self.serial_tabs.append(name)
1228
 
 
1229
 
        page_idx = self.serial_tabs.index(name) + PAGE_DYNAMIC_OFFSET
1230
 
        self.window.get_widget("details-pages").set_current_page(page_idx)
1231
 
 
1232
 
    def _close_serial_tab(self, name):
1233
 
        if not self.serial_tabs.count(name):
1234
 
            return
1235
 
 
1236
 
        page_idx = self.serial_tabs.index(name) + PAGE_DYNAMIC_OFFSET
1237
 
        self.window.get_widget("details-pages").remove_page(page_idx)
1238
 
        self.serial_tabs.remove(name)
1239
 
 
1240
 
    ############################
1241
 
    # Details/Hardware getters #
1242
 
    ############################
1243
 
 
1244
 
    def get_config_boot_devs(self):
1245
 
        boot_model = self.window.get_widget("config-boot-list").get_model()
1246
 
        devs = []
1247
 
 
1248
 
        for row in boot_model:
1249
 
            if row[BOOT_ACTIVE]:
1250
 
                devs.append(row[BOOT_DEV_TYPE])
1251
 
 
1252
 
        return devs
1253
 
 
1254
 
    def get_config_cpu_model(self):
1255
 
        cpu_list = self.window.get_widget("cpu-model")
1256
 
        model = cpu_list.child.get_text()
1257
 
 
1258
 
        for row in cpu_list.get_model():
1259
 
            if model == row[0]:
1260
 
                return model, row[1].vendor
1261
 
 
1262
 
        return model, None
1263
 
 
1264
 
    ##############################
1265
 
    # Details/Hardware listeners #
1266
 
    ##############################
1267
 
    def _spin_get_helper(self, wname):
1268
 
        widget = self.window.get_widget(wname)
1269
 
        adj = widget.get_adjustment()
1270
 
        txt = widget.get_text()
1271
 
 
1272
 
        try:
1273
 
            ret = int(txt)
1274
 
        except:
1275
 
            ret = adj.value
1276
 
        return ret
1277
 
 
1278
 
    def _browse_file(self, callback, is_media=False):
1279
 
        if is_media:
1280
 
            reason = self.config.CONFIG_DIR_MEDIA
1281
 
        else:
1282
 
            reason = self.config.CONFIG_DIR_IMAGE
1283
 
 
1284
 
        if self.storage_browser == None:
1285
 
            self.storage_browser = vmmStorageBrowser(self.conn)
1286
 
 
1287
 
        self.storage_browser.set_finish_cb(callback)
1288
 
        self.storage_browser.set_browse_reason(reason)
1289
 
        self.storage_browser.show(self.conn)
1290
 
 
1291
 
    def browse_kernel(self, src_ignore):
1292
 
        def cb(ignore, path):
1293
 
            self.window.get_widget("boot-kernel").set_text(path)
1294
 
        self._browse_file(cb)
1295
 
    def browse_initrd(self, src_ignore):
1296
 
        def cb(ignore, path):
1297
 
            self.window.get_widget("boot-kernel-initrd").set_text(path)
1298
 
        self._browse_file(cb)
1299
 
 
1300
 
    def config_enable_apply(self, ignore1=None, ignore2=None):
1301
 
        self.window.get_widget("config-apply").set_sensitive(True)
1302
 
 
1303
 
    # Overview -> Security
1304
 
    def security_label_changed(self, label_ignore):
1305
 
        self.config_enable_apply()
1306
 
 
1307
 
    def security_type_changed(self, button):
1308
 
        self.config_enable_apply()
1309
 
        self.window.get_widget("security-label").set_sensitive(
1310
 
                                                    not button.get_active())
1311
 
 
1312
 
    # Memory
1313
 
    def config_get_maxmem(self):
1314
 
        return self._spin_get_helper("config-maxmem")
1315
 
    def config_get_memory(self):
1316
 
        return self._spin_get_helper("config-memory")
1317
 
 
1318
 
    def config_maxmem_changed(self, src_ignore):
1319
 
        self.config_enable_apply()
1320
 
 
1321
 
    def config_memory_changed(self, src_ignore):
1322
 
        self.config_enable_apply()
1323
 
 
1324
 
        maxadj = self.window.get_widget("config-maxmem").get_adjustment()
1325
 
 
1326
 
        mem = self.config_get_memory()
1327
 
        if maxadj.value < mem:
1328
 
            maxadj.value = mem
1329
 
        maxadj.lower = mem
1330
 
 
1331
 
    def generate_cpuset(self):
1332
 
        mem = int(self.vm.get_memory()) / 1024 / 1024
1333
 
        return virtinst.Guest.generate_cpuset(self.conn.vmm, mem)
1334
 
 
1335
 
    # VCPUS
1336
 
    def config_get_vcpus(self):
1337
 
        return self._spin_get_helper("config-vcpus")
1338
 
    def config_get_maxvcpus(self):
1339
 
        return self._spin_get_helper("config-maxvcpus")
1340
 
 
1341
 
    def config_vcpupin_generate(self, ignore):
1342
 
        try:
1343
 
            pinstr = self.generate_cpuset()
1344
 
        except Exception, e:
1345
 
            return self.err.val_err(
1346
 
                _("Error generating CPU configuration: %s") % str(e))
1347
 
 
1348
 
        self.window.get_widget("config-vcpupin").set_text("")
1349
 
        self.window.get_widget("config-vcpupin").set_text(pinstr)
1350
 
 
1351
 
    def config_vcpus_changed(self, ignore):
1352
 
        self.config_enable_apply()
1353
 
 
1354
 
        conn = self.vm.get_connection()
1355
 
        host_active_count = conn.host_active_processor_count()
1356
 
        cur = self.config_get_vcpus()
1357
 
 
1358
 
        # Warn about overcommit
1359
 
        warn = bool(cur > host_active_count)
1360
 
        self.window.get_widget("config-vcpus-warn-box").set_property(
1361
 
                                                            "visible", warn)
1362
 
 
1363
 
        maxadj = self.window.get_widget("config-maxvcpus").get_adjustment()
1364
 
        maxval = self.config_get_maxvcpus()
1365
 
        if maxval < cur:
1366
 
            maxadj.value = cur
1367
 
        maxadj.lower = cur
1368
 
 
1369
 
    def config_maxvcpus_changed(self, ignore):
1370
 
        self.config_enable_apply()
1371
 
 
1372
 
    def config_cpu_copy_host(self, src_ignore):
1373
 
        # Update UI with output copied from host
1374
 
        try:
1375
 
            CPU = virtinst.CPU(self.vm.get_connection().vmm)
1376
 
            CPU.copy_host_cpu()
1377
 
 
1378
 
            self._refresh_cpu_config(CPU)
1379
 
            self._cpu_copy_host = True
1380
 
        except Exception, e:
1381
 
            self.err.show_err(_("Error copying host CPU: %s") % str(e),
1382
 
                              "".join(traceback.format_exc()))
1383
 
            return
1384
 
 
1385
 
    def config_cpu_topology_enable(self, src):
1386
 
        do_enable = src.get_active()
1387
 
        self.window.get_widget("cpu-topology-table").set_sensitive(do_enable)
1388
 
        self.config_enable_apply()
1389
 
 
1390
 
    # Boot device / Autostart
1391
 
    def config_bootdev_selected(self, ignore):
1392
 
        boot_row = self.get_boot_selection()
1393
 
        boot_selection = boot_row and boot_row[BOOT_DEV_TYPE]
1394
 
        boot_devs = self.get_config_boot_devs()
1395
 
        up_widget = self.window.get_widget("config-boot-moveup")
1396
 
        down_widget = self.window.get_widget("config-boot-movedown")
1397
 
 
1398
 
        down_widget.set_sensitive(bool(boot_devs and
1399
 
                                       boot_selection and
1400
 
                                       boot_selection in boot_devs and
1401
 
                                       boot_selection != boot_devs[-1]))
1402
 
        up_widget.set_sensitive(bool(boot_devs and boot_selection and
1403
 
                                     boot_selection in boot_devs and
1404
 
                                     boot_selection != boot_devs[0]))
1405
 
 
1406
 
    def config_boot_toggled(self, ignore, index):
1407
 
        boot_model = self.window.get_widget("config-boot-list").get_model()
1408
 
        boot_row = boot_model[index]
1409
 
        is_active = boot_row[BOOT_ACTIVE]
1410
 
 
1411
 
        boot_row[BOOT_ACTIVE] = not is_active
1412
 
 
1413
 
        self.repopulate_boot_list(self.get_config_boot_devs(),
1414
 
                                  boot_row[BOOT_DEV_TYPE])
1415
 
        self.config_enable_apply()
1416
 
 
1417
 
    def config_boot_move(self, src_ignore, move_up):
1418
 
        boot_row = self.get_boot_selection()
1419
 
        if not boot_row:
1420
 
            return
1421
 
 
1422
 
        boot_selection = boot_row[BOOT_DEV_TYPE]
1423
 
        boot_devs = self.get_config_boot_devs()
1424
 
        boot_idx = boot_devs.index(boot_selection)
1425
 
        if move_up:
1426
 
            new_idx = boot_idx - 1
1427
 
        else:
1428
 
            new_idx = boot_idx + 1
1429
 
 
1430
 
        if new_idx < 0 or new_idx >= len(boot_devs):
1431
 
            # Somehow we got out of bounds
1432
 
            return
1433
 
 
1434
 
        swap_dev = boot_devs[new_idx]
1435
 
        boot_devs[new_idx] = boot_selection
1436
 
        boot_devs[boot_idx] = swap_dev
1437
 
 
1438
 
        self.repopulate_boot_list(boot_devs, boot_selection)
1439
 
        self.config_enable_apply()
1440
 
 
1441
 
    # CDROM Eject/Connect
1442
 
    def toggle_storage_media(self, src_ignore):
1443
 
        disk = self.get_hw_selection(HW_LIST_COL_DEVICE)
1444
 
        if not disk:
1445
 
            return
1446
 
 
1447
 
        dev_id_info = disk
1448
 
        curpath = disk.path
1449
 
        devtype = disk.device
1450
 
 
1451
 
        if curpath:
1452
 
            # Disconnect cdrom
1453
 
            self.change_storage_media(dev_id_info, None)
1454
 
            return
1455
 
 
1456
 
        def change_cdrom_wrapper(src_ignore, dev_id_info, newpath):
1457
 
            return self.change_storage_media(dev_id_info, newpath)
1458
 
 
1459
 
        # Launch 'Choose CD' dialog
1460
 
        if self.media_choosers[devtype] is None:
1461
 
            ret = vmmChooseCD(dev_id_info,
1462
 
                              self.vm.get_connection(),
1463
 
                              devtype)
1464
 
 
1465
 
            ret.connect("cdrom-chosen", change_cdrom_wrapper)
1466
 
            self.media_choosers[devtype] = ret
1467
 
 
1468
 
        dialog = self.media_choosers[devtype]
1469
 
        dialog.dev_id_info = dev_id_info
1470
 
        dialog.show()
1471
 
 
1472
 
    ##################################################
1473
 
    # Details/Hardware config changes (apply button) #
1474
 
    ##################################################
1475
 
 
1476
 
    def config_apply(self, ignore):
1477
 
        pagetype = self.get_hw_selection(HW_LIST_COL_TYPE)
1478
 
        devobj = self.get_hw_selection(HW_LIST_COL_DEVICE)
1479
 
        key = devobj
1480
 
        ret = False
1481
 
 
1482
 
        if pagetype is HW_LIST_TYPE_GENERAL:
1483
 
            ret = self.config_overview_apply()
1484
 
        elif pagetype is HW_LIST_TYPE_CPU:
1485
 
            ret = self.config_vcpus_apply()
1486
 
        elif pagetype is HW_LIST_TYPE_MEMORY:
1487
 
            ret = self.config_memory_apply()
1488
 
        elif pagetype is HW_LIST_TYPE_BOOT:
1489
 
            ret = self.config_boot_options_apply()
1490
 
        elif pagetype is HW_LIST_TYPE_DISK:
1491
 
            ret = self.config_disk_apply(key)
1492
 
        elif pagetype is HW_LIST_TYPE_NIC:
1493
 
            ret = self.config_network_apply(key)
1494
 
        elif pagetype is HW_LIST_TYPE_GRAPHICS:
1495
 
            ret = self.config_graphics_apply(key)
1496
 
        elif pagetype is HW_LIST_TYPE_SOUND:
1497
 
            ret = self.config_sound_apply(key)
1498
 
        elif pagetype is HW_LIST_TYPE_VIDEO:
1499
 
            ret = self.config_video_apply(key)
1500
 
        elif pagetype is HW_LIST_TYPE_WATCHDOG:
1501
 
            ret = self.config_watchdog_apply(key)
1502
 
        else:
1503
 
            ret = False
1504
 
 
1505
 
        if ret is not False:
1506
 
            self.window.get_widget("config-apply").set_sensitive(False)
1507
 
 
1508
 
    # Helper for accessing value of combo/label pattern
1509
 
    def get_combo_label_value(self, prefix, model_idx=0):
1510
 
        comboname = prefix + "-combo"
1511
 
        label = self.window.get_widget(prefix + "-label")
1512
 
        value = None
1513
 
 
1514
 
        if label.get_property("visible"):
1515
 
            value = label.get_text()
1516
 
        else:
1517
 
            value = self.get_combo_value(comboname, model_idx)
1518
 
 
1519
 
        return value
1520
 
 
1521
 
    def get_combo_value(self, widgetname, model_idx=0):
1522
 
        combo = self.window.get_widget(widgetname)
1523
 
        if combo.get_active() < 0:
1524
 
            return None
1525
 
        return combo.get_model()[combo.get_active()][model_idx]
1526
 
 
1527
 
    # Overview section
1528
 
    def config_overview_apply(self):
1529
 
        # Machine details
1530
 
        enable_acpi = self.window.get_widget("overview-acpi").get_active()
1531
 
        enable_apic = self.window.get_widget("overview-apic").get_active()
1532
 
        clock_combo = self.window.get_widget("overview-clock-combo")
1533
 
        if clock_combo.get_property("visible"):
1534
 
            clock = clock_combo.get_model()[clock_combo.get_active()][0]
1535
 
        else:
1536
 
            clock = self.window.get_widget("overview-clock-label").get_text()
1537
 
 
1538
 
        # Security
1539
 
        if self.window.get_widget("security-dynamic").get_active():
1540
 
            setype = "dynamic"
1541
 
        else:
1542
 
            setype = "static"
1543
 
 
1544
 
        selabel = self.window.get_widget("security-label").get_text()
1545
 
        semodel = None
1546
 
        if self.window.get_widget("security-type-box").get_sensitive():
1547
 
            semodel = self.window.get_widget("security-model").get_text()
1548
 
 
1549
 
        # Description
1550
 
        desc_widget = self.window.get_widget("overview-description")
1551
 
        desc = desc_widget.get_buffer().get_property("text") or ""
1552
 
 
1553
 
        return self._change_config_helper([self.vm.define_acpi,
1554
 
                                           self.vm.define_apic,
1555
 
                                           self.vm.define_clock,
1556
 
                                           self.vm.define_seclabel,
1557
 
                                           self.vm.define_description],
1558
 
                                          [(enable_acpi,),
1559
 
                                           (enable_apic,),
1560
 
                                           (clock,),
1561
 
                                           (semodel, setype, selabel),
1562
 
                                           (desc,)])
1563
 
 
1564
 
    # CPUs
1565
 
    def config_vcpus_apply(self):
1566
 
        vcpus = self.config_get_vcpus()
1567
 
        maxv = self.config_get_maxvcpus()
1568
 
        cpuset = self.window.get_widget("config-vcpupin").get_text()
1569
 
 
1570
 
        do_top = self.window.get_widget("cpu-topology-enable").get_active()
1571
 
        sockets = self.window.get_widget("cpu-sockets").get_value()
1572
 
        cores = self.window.get_widget("cpu-cores").get_value()
1573
 
        threads = self.window.get_widget("cpu-threads").get_value()
1574
 
        model, vendor = self.get_config_cpu_model()
1575
 
 
1576
 
        logging.info("Setting vcpus for %s to %s, cpuset is %s" %
1577
 
                     (self.vm.get_name(), str(vcpus), cpuset))
1578
 
 
1579
 
        if not do_top:
1580
 
            sockets = None
1581
 
            cores = None
1582
 
            threads = None
1583
 
 
1584
 
        define_funcs = [self.vm.define_vcpus,
1585
 
                        self.vm.define_cpuset,
1586
 
                        self.vm.define_cpu,
1587
 
                        self.vm.define_cpu_topology]
1588
 
        define_args  = [(vcpus, maxv),
1589
 
                        (cpuset,),
1590
 
                        (model, vendor, self._cpu_copy_host),
1591
 
                        (sockets, cores, threads)]
1592
 
 
1593
 
        ret = self._change_config_helper(define_funcs, define_args,
1594
 
                                         [self.vm.hotplug_vcpus,
1595
 
                                          self.config_vcpu_pin_cpuset],
1596
 
                                         [(vcpus,), (cpuset,)])
1597
 
 
1598
 
        if ret:
1599
 
            self._cpu_copy_host = False
1600
 
 
1601
 
    def config_vcpu_pin(self, src_ignore, path, new_text):
1602
 
        vcpu_list = self.window.get_widget("config-vcpu-list")
1603
 
        vcpu_model = vcpu_list.get_model()
1604
 
        row = vcpu_model[path]
1605
 
        conn = self.vm.get_connection()
1606
 
 
1607
 
        try:
1608
 
            vcpu_num = int(row[0])
1609
 
            pinlist = virtinst.Guest.cpuset_str_to_tuple(conn.vmm, new_text)
1610
 
        except Exception, e:
1611
 
            self.err.val_err(_("Error building pin list: %s") % str(e))
1612
 
            return
1613
 
 
1614
 
        try:
1615
 
            self.vm.pin_vcpu(vcpu_num, pinlist)
1616
 
        except Exception, e:
1617
 
            self.err.show_err(_("Error pinning vcpus: %s") % str(e),
1618
 
                              "".join(traceback.format_exc()))
1619
 
            return
1620
 
 
1621
 
        self._refresh_runtime_pinning()
1622
 
 
1623
 
    def config_vcpu_pin_cpuset(self, cpuset):
1624
 
        conn = self.vm.get_connection()
1625
 
        vcpu_list = self.window.get_widget("config-vcpu-list")
1626
 
        vcpu_model = vcpu_list.get_model()
1627
 
 
1628
 
        if self.vm.vcpu_pinning() == cpuset:
1629
 
            return
1630
 
 
1631
 
        pinlist = virtinst.Guest.cpuset_str_to_tuple(conn.vmm, cpuset)
1632
 
        for row in vcpu_model:
1633
 
            vcpu_num = row[0]
1634
 
            self.vm.pin_vcpu(int(vcpu_num), pinlist)
1635
 
 
1636
 
    # Memory
1637
 
    def config_memory_apply(self):
1638
 
        curmem = None
1639
 
        maxmem = self.config_get_maxmem()
1640
 
        if self.window.get_widget("config-memory").get_property("sensitive"):
1641
 
            curmem = self.config_get_memory()
1642
 
 
1643
 
        if curmem:
1644
 
            curmem = int(curmem) * 1024
1645
 
        if maxmem:
1646
 
            maxmem = int(maxmem) * 1024
1647
 
 
1648
 
        return self._change_config_helper(self.vm.define_both_mem,
1649
 
                                          (curmem, maxmem),
1650
 
                                          self.vm.hotplug_both_mem,
1651
 
                                          (curmem, maxmem))
1652
 
 
1653
 
    # Boot device / Autostart
1654
 
    def config_boot_options_apply(self):
1655
 
        auto = self.window.get_widget("config-autostart")
1656
 
 
1657
 
        if auto.get_property("sensitive"):
1658
 
            try:
1659
 
                self.vm.set_autostart(auto.get_active())
1660
 
            except Exception, e:
1661
 
                self.err.show_err((_("Error changing autostart value: %s") %
1662
 
                                   str(e)), "".join(traceback.format_exc()))
1663
 
                return False
1664
 
 
1665
 
        bootdevs = self.get_config_boot_devs()
1666
 
        bootmenu = self.window.get_widget("boot-menu").get_active()
1667
 
 
1668
 
        kernel = self.window.get_widget("boot-kernel").get_text()
1669
 
        initrd = self.window.get_widget("boot-kernel-initrd").get_text()
1670
 
        args = self.window.get_widget("boot-kernel-args").get_text()
1671
 
 
1672
 
        return self._change_config_helper([self.vm.set_boot_device,
1673
 
                                           self.vm.set_boot_menu,
1674
 
                                           self.vm.set_boot_kernel],
1675
 
                                          [(bootdevs,),
1676
 
                                           (bootmenu,),
1677
 
                                           (kernel, initrd, args)])
1678
 
 
1679
 
    # CDROM
1680
 
    def change_storage_media(self, dev_id_info, newpath):
1681
 
        return self._change_config_helper(self.vm.define_storage_media,
1682
 
                                          (dev_id_info, newpath),
1683
 
                                          self.vm.hotplug_storage_media,
1684
 
                                          (dev_id_info, newpath))
1685
 
 
1686
 
    # Disk options
1687
 
    def config_disk_apply(self, dev_id_info):
1688
 
        do_readonly = self.window.get_widget("disk-readonly").get_active()
1689
 
        do_shareable = self.window.get_widget("disk-shareable").get_active()
1690
 
        cache = self.get_combo_label_value("disk-cache")
1691
 
        fmt = self.window.get_widget("disk-format").child.get_text()
1692
 
        bus = self.get_combo_label_value("disk-bus")
1693
 
 
1694
 
        return self._change_config_helper([self.vm.define_disk_readonly,
1695
 
                                           self.vm.define_disk_shareable,
1696
 
                                           self.vm.define_disk_cache,
1697
 
                                           self.vm.define_disk_driver_type,
1698
 
                                           self.vm.define_disk_bus],
1699
 
                                          [(dev_id_info, do_readonly),
1700
 
                                           (dev_id_info, do_shareable),
1701
 
                                           (dev_id_info, cache),
1702
 
                                           (dev_id_info, fmt),
1703
 
                                           (dev_id_info, bus)])
1704
 
 
1705
 
    # Audio options
1706
 
    def config_sound_apply(self, dev_id_info):
1707
 
        model = self.get_combo_label_value("sound-model")
1708
 
        if model:
1709
 
            return self._change_config_helper(self.vm.define_sound_model,
1710
 
                                              (dev_id_info, model))
1711
 
 
1712
 
    # Network options
1713
 
    def config_network_apply(self, dev_id_info):
1714
 
        model = self.get_combo_label_value("network-model")
1715
 
        return self._change_config_helper(self.vm.define_network_model,
1716
 
                                          (dev_id_info, model))
1717
 
 
1718
 
    # Graphics options
1719
 
    def config_graphics_apply(self, dev_id_info):
1720
 
        passwd = self.window.get_widget("gfx-password").get_text() or None
1721
 
        keymap = self.get_combo_label_value("gfx-keymap")
1722
 
 
1723
 
        return self._change_config_helper([self.vm.define_graphics_password,
1724
 
                                           self.vm.define_graphics_keymap],
1725
 
                                          [(dev_id_info, passwd),
1726
 
                                           (dev_id_info, keymap)],
1727
 
                                          [self.vm.hotplug_graphics_password],
1728
 
                                          [(dev_id_info, passwd)])
1729
 
 
1730
 
 
1731
 
    # Video options
1732
 
    def config_video_apply(self, dev_id_info):
1733
 
        model = self.get_combo_label_value("video-model")
1734
 
        if model:
1735
 
            return self._change_config_helper(self.vm.define_video_model,
1736
 
                                              (dev_id_info, model))
1737
 
 
1738
 
    # Watchdog options
1739
 
    def config_watchdog_apply(self, dev_id_info):
1740
 
        model = self.get_combo_label_value("watchdog-model")
1741
 
        action = self.get_combo_label_value("watchdog-action")
1742
 
        if model or action:
1743
 
            return self._change_config_helper([self.vm.define_watchdog_model,
1744
 
                                               self.vm.define_watchdog_action],
1745
 
                                               [(dev_id_info, model),
1746
 
                                                (dev_id_info, action)])
1747
 
 
1748
 
    # Device removal
1749
 
    def remove_device(self, dev_type, dev_id_info):
1750
 
        logging.debug("Removing device: %s %s" % (dev_type, dev_id_info))
1751
 
        do_prompt = self.config.get_confirm_removedev()
1752
 
 
1753
 
        if do_prompt:
1754
 
            res = self.err.warn_chkbox(
1755
 
                    text1=(_("Are you sure you want to remove this device?")),
1756
 
                    chktext=_("Don't ask me again."),
1757
 
                    buttons=gtk.BUTTONS_YES_NO)
1758
 
 
1759
 
            response, skip_prompt = res
1760
 
            if not response:
1761
 
                return
1762
 
            self.config.set_confirm_removedev(not skip_prompt)
1763
 
 
1764
 
        # Define the change
1765
 
        try:
1766
 
            self.vm.remove_device(dev_id_info)
1767
 
        except Exception, e:
1768
 
            self.err.show_err(_("Error Removing Device: %s" % str(e)),
1769
 
                              "".join(traceback.format_exc()))
1770
 
            return
1771
 
 
1772
 
        # Try to hot remove
1773
 
        detach_err = False
1774
 
        try:
1775
 
            if self.vm.is_active():
1776
 
                self.vm.detach_device(dev_id_info)
1777
 
        except Exception, e:
1778
 
            logging.debug("Device could not be hotUNplugged: %s" % str(e))
1779
 
            detach_err = (str(e), "".join(traceback.format_exc()))
1780
 
 
1781
 
        if not detach_err:
1782
 
            return
1783
 
 
1784
 
        self.err.show_err(
1785
 
            _("Device could not be removed from the running machine"),
1786
 
            detach_err[0] + "\n\n" + detach_err[1],
1787
 
            text2=_("This change will take effect after the next VM reboot."),
1788
 
            buttons=gtk.BUTTONS_OK,
1789
 
            dialog_type=gtk.MESSAGE_INFO)
1790
 
 
1791
 
    # Generic config change helpers
1792
 
    def _change_config_helper(self,
1793
 
                              define_funcs, define_funcs_args,
1794
 
                              hotplug_funcs=None, hotplug_funcs_args=None):
1795
 
        """
1796
 
        Requires at least a 'define' function and arglist to be specified
1797
 
        (a function where we change the inactive guest config).
1798
 
 
1799
 
        Arguments can be a single arg or a list or appropriate arg type (e.g.
1800
 
        a list of functions for define_funcs)
1801
 
        """
1802
 
        def listify(val):
1803
 
            if not val:
1804
 
                return []
1805
 
            if type(val) is not list:
1806
 
                return [val]
1807
 
            return val
1808
 
 
1809
 
        define_funcs = listify(define_funcs)
1810
 
        define_funcs_args = listify(define_funcs_args)
1811
 
        hotplug_funcs = listify(hotplug_funcs)
1812
 
        hotplug_funcs_args = listify(hotplug_funcs_args)
1813
 
 
1814
 
        hotplug_err = []
1815
 
        active = self.vm.is_active()
1816
 
 
1817
 
        # Hotplug change
1818
 
        func = None
1819
 
        if active and hotplug_funcs:
1820
 
            for idx in range(len(hotplug_funcs)):
1821
 
                func = hotplug_funcs[idx]
1822
 
                args = hotplug_funcs_args[idx]
1823
 
                try:
1824
 
                    func(*args)
1825
 
                except Exception, e:
1826
 
                    logging.debug("Hotplug failed: func=%s: %s" % (func,
1827
 
                                                                   str(e)))
1828
 
                    hotplug_err.append((str(e),
1829
 
                                        "".join(traceback.format_exc())))
1830
 
 
1831
 
        # Persistent config change
1832
 
        try:
1833
 
            for idx in range(len(define_funcs)):
1834
 
                func = define_funcs[idx]
1835
 
                args = define_funcs_args[idx]
1836
 
                func(*args)
1837
 
            if define_funcs:
1838
 
                self.vm.redefine_cached()
1839
 
        except Exception, e:
1840
 
            self.err.show_err((_("Error changing VM configuration: %s") %
1841
 
                              str(e)), "".join(traceback.format_exc()))
1842
 
            # If we fail, make sure we flush the cache
1843
 
            self.vm.refresh_xml()
1844
 
            return False
1845
 
 
1846
 
 
1847
 
        if (hotplug_err or
1848
 
            (active and not len(hotplug_funcs) == len(define_funcs))):
1849
 
            if len(define_funcs) > 1:
1850
 
                msg = _("Some changes may require a guest reboot "
1851
 
                        "to take effect.")
1852
 
            else:
1853
 
                msg = _("These changes will take effect after "
1854
 
                        "the next guest reboot.")
1855
 
 
1856
 
            dtype = hotplug_err and gtk.MESSAGE_WARNING or gtk.MESSAGE_INFO
1857
 
            hotplug_msg = ""
1858
 
            for err1, tb in hotplug_err:
1859
 
                hotplug_msg += (err1 + "\n\n" + tb + "\n")
1860
 
 
1861
 
            self.err.show_err(msg, details=hotplug_msg,
1862
 
                              buttons=gtk.BUTTONS_OK,
1863
 
                              dialog_type=dtype)
1864
 
 
1865
 
        return True
1866
 
 
1867
 
    ########################
1868
 
    # Details page refresh #
1869
 
    ########################
1870
 
 
1871
 
    def refresh_resources(self, ignore):
1872
 
        details = self.window.get_widget("details-pages")
1873
 
        page = details.get_current_page()
1874
 
 
1875
 
        # If the dialog is visible, we want to make sure the XML is always
1876
 
        # up to date
1877
 
        if self.is_visible():
1878
 
            self.vm.refresh_xml()
1879
 
 
1880
 
        # Stats page needs to be refreshed every tick
1881
 
        if (page == PAGE_DETAILS and
1882
 
            self.get_hw_selection(HW_LIST_COL_TYPE) == HW_LIST_TYPE_STATS):
1883
 
            self.refresh_stats_page()
1884
 
 
1885
 
    def page_refresh(self, page):
1886
 
        if page != PAGE_DETAILS:
1887
 
            return
1888
 
 
1889
 
        # This function should only be called when the VM xml actually
1890
 
        # changes (not everytime it is refreshed). This saves us from blindly
1891
 
        # parsing the xml every tick
1892
 
 
1893
 
        # Add / remove new devices
1894
 
        self.repopulate_hw_list()
1895
 
 
1896
 
        pagetype = self.get_hw_selection(HW_LIST_COL_TYPE)
1897
 
        if pagetype is None:
1898
 
            return
1899
 
 
1900
 
        if self.window.get_widget("config-apply").get_property("sensitive"):
1901
 
            # Apply button sensitive means user is making changes, don't
1902
 
            # erase them
1903
 
            return
1904
 
 
1905
 
        self.hw_selected(page=pagetype)
1906
 
 
1907
 
    def refresh_overview_page(self):
1908
 
        # Basic details
1909
 
        self.window.get_widget("overview-name").set_text(self.vm.get_name())
1910
 
        self.window.get_widget("overview-uuid").set_text(self.vm.get_uuid())
1911
 
        desc = self.vm.get_description() or ""
1912
 
        desc_widget = self.window.get_widget("overview-description")
1913
 
        desc_widget.get_buffer().set_text(desc)
1914
 
 
1915
 
        # Hypervisor Details
1916
 
        self.window.get_widget("overview-hv").set_text(self.vm.get_pretty_hv_type())
1917
 
        arch = self.vm.get_arch() or _("Unknown")
1918
 
        emu = self.vm.get_emulator() or _("None")
1919
 
        self.window.get_widget("overview-arch").set_text(arch)
1920
 
        self.window.get_widget("overview-emulator").set_text(emu)
1921
 
 
1922
 
        # Machine settings
1923
 
        acpi = self.vm.get_acpi()
1924
 
        apic = self.vm.get_apic()
1925
 
        clock = self.vm.get_clock()
1926
 
 
1927
 
        self.window.get_widget("overview-acpi").set_active(acpi)
1928
 
        self.window.get_widget("overview-apic").set_active(apic)
1929
 
 
1930
 
        if not clock:
1931
 
            clock = _("Same as host")
1932
 
        self.set_combo_label("overview-clock", 0, clock)
1933
 
 
1934
 
        # Security details
1935
 
        semodel, ignore, vmlabel = self.vm.get_seclabel()
1936
 
        caps = self.vm.get_connection().get_capabilities()
1937
 
 
1938
 
        if caps.host.secmodel and caps.host.secmodel.model:
1939
 
            semodel = caps.host.secmodel.model
1940
 
        self.window.get_widget("security-type-box").set_sensitive(bool(semodel))
1941
 
        self.window.get_widget("security-model").set_text(semodel or _("None"))
1942
 
 
1943
 
        if self.vm.get_seclabel()[1] == "static":
1944
 
            self.window.get_widget("security-static").set_active(True)
1945
 
        else:
1946
 
            self.window.get_widget("security-dynamic").set_active(True)
1947
 
 
1948
 
        self.window.get_widget("security-label").set_text(vmlabel)
1949
 
 
1950
 
    def refresh_stats_page(self):
1951
 
        def _dsk_rx_tx_text(rx, tx, unit):
1952
 
            return ('<span color="#82003B">%(rx)d %(unit)s read</span>\n'
1953
 
                    '<span color="#295C45">%(tx)d %(unit)s write</span>' %
1954
 
                    {"rx": rx, "tx": tx, "unit": unit})
1955
 
        def _net_rx_tx_text(rx, tx, unit):
1956
 
            return ('<span color="#82003B">%(rx)d %(unit)s in</span>\n'
1957
 
                    '<span color="#295C45">%(tx)d %(unit)s out</span>' %
1958
 
                    {"rx": rx, "tx": tx, "unit": unit})
1959
 
 
1960
 
        cpu_txt = _("Disabled")
1961
 
        mem_txt = _("Disabled")
1962
 
        dsk_txt = _("Disabled")
1963
 
        net_txt = _("Disabled")
1964
 
 
1965
 
        cpu_txt = "%d %%" % self.vm.cpu_time_percentage()
1966
 
 
1967
 
        vm_memory = self.vm.current_memory()
1968
 
        host_memory = self.vm.get_connection().host_memory_size()
1969
 
        mem_txt = "%d MB of %d MB" % (int(round(vm_memory / 1024.0)),
1970
 
                                      int(round(host_memory / 1024.0)))
1971
 
 
1972
 
        if self.config.get_stats_enable_disk_poll():
1973
 
            dsk_txt = _dsk_rx_tx_text(self.vm.disk_read_rate(),
1974
 
                                      self.vm.disk_write_rate(), "KB/s")
1975
 
 
1976
 
        if self.config.get_stats_enable_net_poll():
1977
 
            net_txt = _net_rx_tx_text(self.vm.network_rx_rate(),
1978
 
                                      self.vm.network_tx_rate(), "KB/s")
1979
 
 
1980
 
        self.window.get_widget("overview-cpu-usage-text").set_text(cpu_txt)
1981
 
        self.window.get_widget("overview-memory-usage-text").set_text(mem_txt)
1982
 
        self.window.get_widget("overview-network-traffic-text").set_markup(net_txt)
1983
 
        self.window.get_widget("overview-disk-usage-text").set_markup(dsk_txt)
1984
 
 
1985
 
        self.cpu_usage_graph.set_property("data_array",
1986
 
                                          self.vm.cpu_time_vector())
1987
 
        self.memory_usage_graph.set_property("data_array",
1988
 
                                             self.vm.current_memory_vector())
1989
 
        self.disk_io_graph.set_property("data_array",
1990
 
                                        self.vm.disk_io_vector())
1991
 
        self.network_traffic_graph.set_property("data_array",
1992
 
                                                self.vm.network_traffic_vector())
1993
 
 
1994
 
    def _refresh_cpu_count(self):
1995
 
        conn = self.vm.get_connection()
1996
 
        host_active_count = conn.host_active_processor_count()
1997
 
        maxvcpus = self.vm.vcpu_max_count()
1998
 
        curvcpus = self.vm.vcpu_count()
1999
 
 
2000
 
        curadj = self.window.get_widget("config-vcpus").get_adjustment()
2001
 
        maxadj = self.window.get_widget("config-maxvcpus").get_adjustment()
2002
 
        curadj.value = int(curvcpus)
2003
 
        maxadj.value = int(maxvcpus)
2004
 
 
2005
 
        self.window.get_widget("state-host-cpus").set_text(
2006
 
                                                        str(host_active_count))
2007
 
 
2008
 
        # Warn about overcommit
2009
 
        warn = bool(self.config_get_vcpus() > host_active_count)
2010
 
        self.window.get_widget("config-vcpus-warn-box").set_property(
2011
 
                                                            "visible", warn)
2012
 
    def _refresh_cpu_pinning(self):
2013
 
        # Populate VCPU pinning
2014
 
        vcpupin  = self.vm.vcpu_pinning()
2015
 
        self.window.get_widget("config-vcpupin").set_text(vcpupin)
2016
 
 
2017
 
    def _refresh_runtime_pinning(self):
2018
 
        conn = self.vm.get_connection()
2019
 
        host_active_count = conn.host_active_processor_count()
2020
 
 
2021
 
        vcpu_list = self.window.get_widget("config-vcpu-list")
2022
 
        vcpu_model = vcpu_list.get_model()
2023
 
        vcpu_model.clear()
2024
 
 
2025
 
        reason = ""
2026
 
        if not self.vm.is_active():
2027
 
            reason = _("VCPU info only available for running domain.")
2028
 
        elif not self.vm.getvcpus_supported:
2029
 
            reason = _("Virtual machine does not support runtime VPCU info.")
2030
 
        else:
2031
 
            try:
2032
 
                vcpu_info, vcpu_pinning = self.vm.vcpu_info()
2033
 
            except Exception, e:
2034
 
                reason = _("Error getting VCPU info: %s") % str(e)
2035
 
 
2036
 
        vcpu_list.set_sensitive(not bool(reason))
2037
 
        util.tooltip_wrapper(vcpu_list, reason or None)
2038
 
        if reason:
2039
 
            return
2040
 
 
2041
 
        def build_cpuset_str(pin_info):
2042
 
            pinstr = ""
2043
 
            for i in range(host_active_count):
2044
 
                if i < len(pin_info) and pin_info[i]:
2045
 
                    pinstr += (",%s" % str(i))
2046
 
 
2047
 
            return pinstr.strip(",")
2048
 
 
2049
 
        for idx in range(len(vcpu_info)):
2050
 
            vcpu = vcpu_info[idx][0]
2051
 
            vcpucur = vcpu_info[idx][3]
2052
 
            vcpupin = build_cpuset_str(vcpu_pinning[idx])
2053
 
 
2054
 
            vcpu_model.append([vcpu, vcpucur, vcpupin])
2055
 
 
2056
 
    def _refresh_cpu_config(self, cpu):
2057
 
        model = cpu.model or ""
2058
 
 
2059
 
        show_top = bool(cpu.sockets or cpu.cores or cpu.threads)
2060
 
        sockets = cpu.sockets or 1
2061
 
        cores = cpu.cores or 1
2062
 
        threads = cpu.threads or 1
2063
 
 
2064
 
        self.window.get_widget("cpu-topology-enable").set_active(show_top)
2065
 
        self.window.get_widget("cpu-model").child.set_text(model)
2066
 
        self.window.get_widget("cpu-sockets").set_value(sockets)
2067
 
        self.window.get_widget("cpu-cores").set_value(cores)
2068
 
        self.window.get_widget("cpu-threads").set_value(threads)
2069
 
 
2070
 
    def refresh_config_cpu(self):
2071
 
        self._cpu_copy_host = False
2072
 
        cpu = self.vm.get_cpu_config()
2073
 
 
2074
 
        self._refresh_cpu_count()
2075
 
        self._refresh_cpu_pinning()
2076
 
        self._refresh_runtime_pinning()
2077
 
        self._refresh_cpu_config(cpu)
2078
 
 
2079
 
    def refresh_config_memory(self):
2080
 
        host_mem_widget = self.window.get_widget("state-host-memory")
2081
 
        host_mem = self.vm.get_connection().host_memory_size() / 1024
2082
 
        vm_cur_mem = self.vm.get_memory() / 1024.0
2083
 
        vm_max_mem = self.vm.maximum_memory() / 1024.0
2084
 
 
2085
 
        host_mem_widget.set_text("%d MB" % (int(round(host_mem))))
2086
 
 
2087
 
        curmem = self.window.get_widget("config-memory").get_adjustment()
2088
 
        maxmem = self.window.get_widget("config-maxmem").get_adjustment()
2089
 
        curmem.value = int(round(vm_cur_mem))
2090
 
        maxmem.value = int(round(vm_max_mem))
2091
 
 
2092
 
        if (not
2093
 
            self.window.get_widget("config-memory").get_property("sensitive")):
2094
 
            maxmem.lower = curmem.value
2095
 
 
2096
 
 
2097
 
    def refresh_disk_page(self):
2098
 
        disk = self.get_hw_selection(HW_LIST_COL_DEVICE)
2099
 
        if not disk:
2100
 
            return
2101
 
 
2102
 
        path = disk.path
2103
 
        devtype = disk.device
2104
 
        ro = disk.read_only
2105
 
        share = disk.shareable
2106
 
        bus = disk.bus
2107
 
        idx = disk.disk_bus_index
2108
 
        cache = disk.driver_cache
2109
 
        driver_type = disk.driver_type or ""
2110
 
 
2111
 
        size = _("Unknown")
2112
 
        if not path:
2113
 
            size = "-"
2114
 
        else:
2115
 
            vol = self.conn.get_vol_by_path(path)
2116
 
            if vol:
2117
 
                size = vol.get_pretty_capacity()
2118
 
            elif not self.conn.is_remote():
2119
 
                ignore, val = virtinst.VirtualDisk.stat_local_path(path)
2120
 
                if val != 0:
2121
 
                    size = prettyify_bytes(val)
2122
 
 
2123
 
        is_cdrom = (devtype == virtinst.VirtualDisk.DEVICE_CDROM)
2124
 
        is_floppy = (devtype == virtinst.VirtualDisk.DEVICE_FLOPPY)
2125
 
 
2126
 
        pretty_name = prettyify_disk(devtype, bus, idx)
2127
 
 
2128
 
        self.window.get_widget("disk-source-path").set_text(path or "-")
2129
 
        self.window.get_widget("disk-target-type").set_text(pretty_name)
2130
 
 
2131
 
        self.window.get_widget("disk-readonly").set_active(ro)
2132
 
        self.window.get_widget("disk-readonly").set_sensitive(not is_cdrom)
2133
 
        self.window.get_widget("disk-shareable").set_active(share)
2134
 
        self.window.get_widget("disk-size").set_text(size)
2135
 
        self.set_combo_label("disk-cache", 0, cache)
2136
 
        self.window.get_widget("disk-format").child.set_text(driver_type)
2137
 
 
2138
 
        no_default = not self.is_customize_dialog
2139
 
 
2140
 
        self.populate_disk_bus_combo(devtype, no_default)
2141
 
        self.set_combo_label("disk-bus", 0, bus)
2142
 
 
2143
 
        button = self.window.get_widget("config-cdrom-connect")
2144
 
        if is_cdrom or is_floppy:
2145
 
            if not path:
2146
 
                # source device not connected
2147
 
                button.set_label(gtk.STOCK_CONNECT)
2148
 
            else:
2149
 
                button.set_label(gtk.STOCK_DISCONNECT)
2150
 
            button.show()
2151
 
        else:
2152
 
            button.hide()
2153
 
 
2154
 
    def refresh_network_page(self):
2155
 
        net = self.get_hw_selection(HW_LIST_COL_DEVICE)
2156
 
        if not net:
2157
 
            return
2158
 
 
2159
 
        nettype = net.type
2160
 
        source = net.get_source()
2161
 
        model = net.model
2162
 
 
2163
 
        netobj = None
2164
 
        if nettype == virtinst.VirtualNetworkInterface.TYPE_VIRTUAL:
2165
 
            name_dict = {}
2166
 
            for uuid in self.conn.list_net_uuids():
2167
 
                vnet = self.conn.get_net(uuid)
2168
 
                name = vnet.get_name()
2169
 
                name_dict[name] = vnet
2170
 
 
2171
 
            if source and source in name_dict:
2172
 
                netobj = name_dict[source]
2173
 
 
2174
 
        desc = uihelpers.pretty_network_desc(nettype, source, netobj)
2175
 
 
2176
 
        self.window.get_widget("network-mac-address").set_text(net.macaddr)
2177
 
        self.window.get_widget("network-source-device").set_text(desc)
2178
 
 
2179
 
        uihelpers.populate_netmodel_combo(self.vm,
2180
 
                            self.window.get_widget("network-model-combo"))
2181
 
        self.set_combo_label("network-model", 0, model)
2182
 
 
2183
 
    def refresh_input_page(self):
2184
 
        inp = self.get_hw_selection(HW_LIST_COL_DEVICE)
2185
 
        if not inp:
2186
 
            return
2187
 
 
2188
 
        ident = "%s:%s" % (inp.type, inp.bus)
2189
 
        if   ident == "tablet:usb":
2190
 
            dev = _("EvTouch USB Graphics Tablet")
2191
 
        elif ident == "mouse:usb":
2192
 
            dev = _("Generic USB Mouse")
2193
 
        elif ident == "mouse:xen":
2194
 
            dev = _("Xen Mouse")
2195
 
        elif ident == "mouse:ps2":
2196
 
            dev = _("PS/2 Mouse")
2197
 
        else:
2198
 
            dev = inp.bus + " " + inp.type
2199
 
 
2200
 
        if inp.type == "tablet":
2201
 
            mode = _("Absolute Movement")
2202
 
        else:
2203
 
            mode = _("Relative Movement")
2204
 
 
2205
 
        self.window.get_widget("input-dev-type").set_text(dev)
2206
 
        self.window.get_widget("input-dev-mode").set_text(mode)
2207
 
 
2208
 
        # Can't remove primary Xen or PS/2 mice
2209
 
        if inp.type == "mouse" and inp.bus in ("xen", "ps2"):
2210
 
            self.window.get_widget("config-remove").set_sensitive(False)
2211
 
        else:
2212
 
            self.window.get_widget("config-remove").set_sensitive(True)
2213
 
 
2214
 
    def refresh_graphics_page(self):
2215
 
        gfx = self.get_hw_selection(HW_LIST_COL_DEVICE)
2216
 
        if not gfx:
2217
 
            return
2218
 
 
2219
 
        title = self.window.get_widget("graphics-title")
2220
 
        table = self.window.get_widget("graphics-table")
2221
 
        table.foreach(lambda w, ignore: w.hide(), ())
2222
 
 
2223
 
        def set_title(text):
2224
 
            title.set_markup("<b>%s</b>" % text)
2225
 
 
2226
 
        def show_row(widget_name, suffix=""):
2227
 
            base = "gfx-%s" % widget_name
2228
 
            self.window.get_widget(base + "-title").show()
2229
 
            self.window.get_widget(base + suffix).show()
2230
 
 
2231
 
        def show_text(widget_name, text):
2232
 
            show_row(widget_name)
2233
 
            self.window.get_widget("gfx-" + widget_name).set_text(text)
2234
 
 
2235
 
        def port_to_string(port):
2236
 
            if port is None:
2237
 
                return "-"
2238
 
            return (port == -1 and _("Automatically allocated") or str(port))
2239
 
 
2240
 
        gtype = gfx.type
2241
 
        is_vnc = (gtype == "vnc")
2242
 
        is_sdl = (gtype == "sdl")
2243
 
        is_spice = (gtype == "spice")
2244
 
        is_other = not any([is_vnc, is_sdl, is_spice])
2245
 
 
2246
 
        set_title(_("%(graphicstype)s Server") %
2247
 
                  {"graphicstype" : str(gtype).upper()})
2248
 
 
2249
 
        if is_vnc or is_spice:
2250
 
            port  = port_to_string(gfx.port)
2251
 
            address = (gfx.listen or "127.0.0.1")
2252
 
            keymap  = (gfx.keymap or None)
2253
 
 
2254
 
            show_text("port", port)
2255
 
            show_text("address", address)
2256
 
 
2257
 
            show_row("keymap", "-box")
2258
 
            self.set_combo_label("gfx-keymap", 0, keymap)
2259
 
 
2260
 
        if is_vnc:
2261
 
            passwd  = gfx.passwd or ""
2262
 
            show_text("password", passwd)
2263
 
 
2264
 
        if is_spice:
2265
 
            tlsport = port_to_string(gfx.tlsPort)
2266
 
            show_text("tlsport", tlsport)
2267
 
 
2268
 
        if is_sdl:
2269
 
            set_title(_("Local SDL Window"))
2270
 
 
2271
 
            display = gfx.display or _("Unknown")
2272
 
            xauth   = gfx.xauth or _("Unknown")
2273
 
 
2274
 
            show_text("display", display)
2275
 
            show_text("xauth", xauth)
2276
 
 
2277
 
        if is_other:
2278
 
            show_text("type", str(gtype).upper())
2279
 
 
2280
 
    def refresh_sound_page(self):
2281
 
        sound = self.get_hw_selection(HW_LIST_COL_DEVICE)
2282
 
        if not sound:
2283
 
            return
2284
 
 
2285
 
        self.set_combo_label("sound-model", 0, sound.model)
2286
 
 
2287
 
    def refresh_char_page(self):
2288
 
        chardev = self.get_hw_selection(HW_LIST_COL_DEVICE)
2289
 
        if not chardev:
2290
 
            return
2291
 
 
2292
 
        char_type = chardev.virtual_device_type.capitalize()
2293
 
        target_port = chardev.target_port
2294
 
        dev_type = chardev.char_type or "pty"
2295
 
        src_path = chardev.source_path
2296
 
        primary = hasattr(chardev, "virtmanager_console_dup")
2297
 
 
2298
 
        typelabel = ""
2299
 
        if char_type == "serial":
2300
 
            typelabel = _("Serial Device")
2301
 
        elif char_type == "parallel":
2302
 
            typelabel = _("Parallel Device")
2303
 
        elif char_type == "console":
2304
 
            typelabel = _("Console Device")
2305
 
        elif char_type == "channel":
2306
 
            typelabel = _("Channel Device")
2307
 
        else:
2308
 
            typelabel = _("%s Device") % char_type.capitalize()
2309
 
 
2310
 
        if target_port is not None:
2311
 
            typelabel += " %s" % (int(target_port) + 1)
2312
 
        if primary:
2313
 
            typelabel += " (%s)" % _("Primary Console")
2314
 
        typelabel = "<b>%s</b>" % typelabel
2315
 
 
2316
 
        self.window.get_widget("char-type").set_markup(typelabel)
2317
 
        self.window.get_widget("char-dev-type").set_text(dev_type)
2318
 
        self.window.get_widget("char-source-path").set_text(src_path or "-")
2319
 
 
2320
 
    def refresh_hostdev_page(self):
2321
 
        hostdev = self.get_hw_selection(HW_LIST_COL_DEVICE)
2322
 
        if not hostdev:
2323
 
            return
2324
 
 
2325
 
        devtype = hostdev.type
2326
 
        pretty_name = None
2327
 
        nodedev = lookup_nodedev(self.vm.get_connection(), hostdev)
2328
 
        if nodedev:
2329
 
            pretty_name = nodedev.pretty_name()
2330
 
 
2331
 
        if not pretty_name:
2332
 
            pretty_name = build_hostdev_label(hostdev)[0] or "-"
2333
 
 
2334
 
        devlabel = "<b>Physical %s Device</b>" % devtype.upper()
2335
 
        self.window.get_widget("hostdev-title").set_markup(devlabel)
2336
 
        self.window.get_widget("hostdev-source").set_text(pretty_name)
2337
 
 
2338
 
    def refresh_video_page(self):
2339
 
        vid = self.get_hw_selection(HW_LIST_COL_DEVICE)
2340
 
        if not vid:
2341
 
            return
2342
 
 
2343
 
        model = vid.model_type
2344
 
        ram = vid.vram
2345
 
        heads = vid.heads
2346
 
        try:
2347
 
            ramlabel = ram and "%d MB" % (int(ram) / 1024) or "-"
2348
 
        except:
2349
 
            ramlabel = "-"
2350
 
 
2351
 
        self.window.get_widget("video-ram").set_text(ramlabel)
2352
 
        self.window.get_widget("video-heads").set_text(heads and heads or "-")
2353
 
 
2354
 
        self.set_combo_label("video-model", 0, model)
2355
 
 
2356
 
    def refresh_watchdog_page(self):
2357
 
        watch = self.get_hw_selection(HW_LIST_COL_DEVICE)
2358
 
        if not watch:
2359
 
            return
2360
 
 
2361
 
        model = watch.model
2362
 
        action = watch.action
2363
 
 
2364
 
        self.set_combo_label("watchdog-model", 0, model)
2365
 
        self.set_combo_label("watchdog-action", 0, action)
2366
 
 
2367
 
    def refresh_controller_page(self):
2368
 
        dev = self.get_hw_selection(HW_LIST_COL_DEVICE)
2369
 
        if not dev:
2370
 
            return
2371
 
 
2372
 
        type_label = virtinst.VirtualController.pretty_type(dev.type)
2373
 
        self.window.get_widget("controller-type").set_text(type_label)
2374
 
 
2375
 
    def refresh_boot_page(self):
2376
 
        # Refresh autostart
2377
 
        try:
2378
 
            # Older libvirt versions return None if not supported
2379
 
            autoval = self.vm.get_autostart()
2380
 
        except libvirt.libvirtError:
2381
 
            autoval = None
2382
 
 
2383
 
        autostart_chk = self.window.get_widget("config-autostart")
2384
 
        enable_autostart = (autoval is not None)
2385
 
        autostart_chk.set_sensitive(enable_autostart)
2386
 
        autostart_chk.set_active(enable_autostart and autoval or False)
2387
 
 
2388
 
        menu = self.vm.get_boot_menu() or False
2389
 
        self.window.get_widget("boot-menu").set_active(menu)
2390
 
 
2391
 
        kernel, initrd, args = self.vm.get_boot_kernel_info()
2392
 
        expand = bool(kernel or initrd or args)
2393
 
        self.window.get_widget("boot-kernel").set_text(kernel or "")
2394
 
        self.window.get_widget("boot-kernel-initrd").set_text(initrd or "")
2395
 
        self.window.get_widget("boot-kernel-args").set_text(args or "")
2396
 
        if expand:
2397
 
            self.window.get_widget("boot-kernel-expander").set_expanded(True)
2398
 
 
2399
 
        # Refresh Boot Device list
2400
 
        self.repopulate_boot_list()
2401
 
 
2402
 
 
2403
 
    ############################
2404
 
    # Hardware list population #
2405
 
    ############################
2406
 
 
2407
 
    def populate_disk_bus_combo(self, devtype, no_default):
2408
 
        buslist     = self.window.get_widget("disk-bus-combo")
2409
 
        busmodel    = buslist.get_model()
2410
 
        busmodel.clear()
2411
 
 
2412
 
        buses = []
2413
 
        if devtype == virtinst.VirtualDisk.DEVICE_FLOPPY:
2414
 
            buses.append(["fdc", "Floppy"])
2415
 
        elif devtype == virtinst.VirtualDisk.DEVICE_CDROM:
2416
 
            buses.append(["ide", "IDE"])
2417
 
            buses.append(["scsi", "SCSI"])
2418
 
        else:
2419
 
            if self.vm.is_hvm():
2420
 
                buses.append(["ide", "IDE"])
2421
 
                buses.append(["scsi", "SCSI"])
2422
 
                buses.append(["usb", "USB"])
2423
 
            if self.vm.get_hv_type() == "kvm":
2424
 
                buses.append(["virtio", "Virtio"])
2425
 
            if self.vm.get_connection().is_xen():
2426
 
                buses.append(["xen", "Xen"])
2427
 
 
2428
 
        for row in buses:
2429
 
            busmodel.append(row)
2430
 
        if not no_default:
2431
 
            busmodel.append([None, "default"])
2432
 
 
2433
 
    def populate_hw_list(self):
2434
 
        hw_list_model = self.window.get_widget("hw-list").get_model()
2435
 
        hw_list_model.clear()
2436
 
 
2437
 
        def add_hw_list_option(title, page_id, data, icon_name):
2438
 
            hw_list_model.append([title, icon_name,
2439
 
                                  gtk.ICON_SIZE_LARGE_TOOLBAR,
2440
 
                                  page_id, data])
2441
 
 
2442
 
        add_hw_list_option("Overview", HW_LIST_TYPE_GENERAL, [], "computer")
2443
 
        if not self.is_customize_dialog:
2444
 
            add_hw_list_option("Performance", HW_LIST_TYPE_STATS, [],
2445
 
                               "utilities-system-monitor")
2446
 
        add_hw_list_option("Processor", HW_LIST_TYPE_CPU, [], "device_cpu")
2447
 
        add_hw_list_option("Memory", HW_LIST_TYPE_MEMORY, [], "device_mem")
2448
 
        add_hw_list_option("Boot Options", HW_LIST_TYPE_BOOT, [], "system-run")
2449
 
 
2450
 
        self.repopulate_hw_list()
2451
 
 
2452
 
    def repopulate_hw_list(self):
2453
 
        hw_list = self.window.get_widget("hw-list")
2454
 
        hw_list_model = hw_list.get_model()
2455
 
 
2456
 
        currentDevices = []
2457
 
 
2458
 
        def dev_cmp(origdev, newdev):
2459
 
            if not origdev:
2460
 
                return False
2461
 
 
2462
 
            if origdev == newdev:
2463
 
                return True
2464
 
 
2465
 
            if not origdev.get_xml_node_path():
2466
 
                return False
2467
 
 
2468
 
            return origdev.get_xml_node_path() == newdev.get_xml_node_path()
2469
 
 
2470
 
        def add_hw_list_option(idx, name, page_id, info, icon_name):
2471
 
            hw_list_model.insert(idx, [name, icon_name,
2472
 
                                       gtk.ICON_SIZE_LARGE_TOOLBAR,
2473
 
                                       page_id, info])
2474
 
 
2475
 
        def update_hwlist(hwtype, info, name, icon_name):
2476
 
            """
2477
 
            See if passed hw is already in list, and if so, update info.
2478
 
            If not in list, add it!
2479
 
            """
2480
 
            currentDevices.append(info)
2481
 
 
2482
 
            insertAt = 0
2483
 
            for row in hw_list_model:
2484
 
                rowdev = row[HW_LIST_COL_DEVICE]
2485
 
                if dev_cmp(rowdev, info):
2486
 
                    # Update existing HW info
2487
 
                    row[HW_LIST_COL_DEVICE] = info
2488
 
                    row[HW_LIST_COL_LABEL] = name
2489
 
                    row[HW_LIST_COL_ICON_NAME] = icon_name
2490
 
                    return
2491
 
 
2492
 
                if row[HW_LIST_COL_TYPE] <= hwtype:
2493
 
                    insertAt += 1
2494
 
 
2495
 
            # Add the new HW row
2496
 
            add_hw_list_option(insertAt, name, hwtype, info, icon_name)
2497
 
 
2498
 
        # Populate list of disks
2499
 
        for disk in self.vm.get_disk_devices():
2500
 
            devtype = disk.device
2501
 
            bus = disk.bus
2502
 
            idx = disk.disk_bus_index
2503
 
 
2504
 
            icon = "drive-harddisk"
2505
 
            if devtype == "cdrom":
2506
 
                icon = "media-optical"
2507
 
            elif devtype == "floppy":
2508
 
                icon = "media-floppy"
2509
 
 
2510
 
            label = prettyify_disk(devtype, bus, idx)
2511
 
 
2512
 
            update_hwlist(HW_LIST_TYPE_DISK, disk, label, icon)
2513
 
 
2514
 
        # Populate list of NICs
2515
 
        for net in self.vm.get_network_devices():
2516
 
            mac = net.macaddr
2517
 
 
2518
 
            update_hwlist(HW_LIST_TYPE_NIC, net,
2519
 
                          "NIC %s" % mac[-9:], "network-idle")
2520
 
 
2521
 
        # Populate list of input devices
2522
 
        for inp in self.vm.get_input_devices():
2523
 
            inptype = inp.type
2524
 
 
2525
 
            icon = "input-mouse"
2526
 
            if inptype == "tablet":
2527
 
                label = _("Tablet")
2528
 
                icon = "input-tablet"
2529
 
            elif inptype == "mouse":
2530
 
                label = _("Mouse")
2531
 
            else:
2532
 
                label = _("Input")
2533
 
 
2534
 
            update_hwlist(HW_LIST_TYPE_INPUT, inp, label, icon)
2535
 
 
2536
 
        # Populate list of graphics devices
2537
 
        for gfx in self.vm.get_graphics_devices():
2538
 
            update_hwlist(HW_LIST_TYPE_GRAPHICS, gfx,
2539
 
                          _("Display %s") % (gfx.type.upper()),
2540
 
                          "video-display")
2541
 
 
2542
 
        # Populate list of sound devices
2543
 
        for sound in self.vm.get_sound_devices():
2544
 
            update_hwlist(HW_LIST_TYPE_SOUND, sound,
2545
 
                          _("Sound: %s" % sound.model), "audio-card")
2546
 
 
2547
 
        # Populate list of char devices
2548
 
        for chardev in self.vm.get_char_devices():
2549
 
            devtype = chardev.virtual_device_type
2550
 
            port = chardev.target_port
2551
 
 
2552
 
            label = devtype.capitalize()
2553
 
            if devtype != "console":
2554
 
                # Don't show port for console
2555
 
                label += " %s" % (int(port) + 1)
2556
 
 
2557
 
            update_hwlist(HW_LIST_TYPE_CHAR, chardev, label,
2558
 
                          "device_serial")
2559
 
 
2560
 
        # Populate host devices
2561
 
        for hostdev in self.vm.get_hostdev_devices():
2562
 
            devtype = hostdev.type
2563
 
            label = build_hostdev_label(hostdev)[1]
2564
 
 
2565
 
            if devtype == "usb":
2566
 
                icon = "device_usb"
2567
 
            else:
2568
 
                icon = "device_pci"
2569
 
            update_hwlist(HW_LIST_TYPE_HOSTDEV, hostdev, label, icon)
2570
 
 
2571
 
        # Populate video devices
2572
 
        for vid in self.vm.get_video_devices():
2573
 
            update_hwlist(HW_LIST_TYPE_VIDEO, vid, _("Video"), "video-display")
2574
 
 
2575
 
        for watch in self.vm.get_watchdog_devices():
2576
 
            update_hwlist(HW_LIST_TYPE_WATCHDOG, watch, _("Watchdog"),
2577
 
                          "device_pci")
2578
 
 
2579
 
        for cont in self.vm.get_controller_devices():
2580
 
            pretty_type = virtinst.VirtualController.pretty_type(cont.type)
2581
 
            update_hwlist(HW_LIST_TYPE_CONTROLLER, cont,
2582
 
                          _("Controller %s") % pretty_type,
2583
 
                          "device_pci")
2584
 
 
2585
 
        devs = range(len(hw_list_model))
2586
 
        devs.reverse()
2587
 
        for i in devs:
2588
 
            _iter = hw_list_model.iter_nth_child(None, i)
2589
 
            olddev = hw_list_model[i][HW_LIST_COL_DEVICE]
2590
 
 
2591
 
            # Existing device, don't remove it
2592
 
            if not olddev or olddev in currentDevices:
2593
 
                continue
2594
 
 
2595
 
            hw_list_model.remove(_iter)
2596
 
 
2597
 
    def repopulate_boot_list(self, bootdevs=None, dev_select=None):
2598
 
        boot_list = self.window.get_widget("config-boot-list")
2599
 
        boot_model = boot_list.get_model()
2600
 
        old_order = map(lambda x: x[BOOT_DEV_TYPE], boot_model)
2601
 
        boot_model.clear()
2602
 
 
2603
 
        if bootdevs == None:
2604
 
            bootdevs = self.vm.get_boot_device()
2605
 
 
2606
 
        boot_rows = {
2607
 
            "hd" : ["hd", "Hard Disk", "drive-harddisk", False],
2608
 
            "cdrom" : ["cdrom", "CDROM", "media-optical", False],
2609
 
            "network" : ["network", "Network (PXE)", "network-idle", False],
2610
 
            "fd" : ["fd", "Floppy", "media-floppy", False],
2611
 
        }
2612
 
 
2613
 
        for dev in bootdevs:
2614
 
            foundrow = None
2615
 
 
2616
 
            for key, row in boot_rows.items():
2617
 
                if key == dev:
2618
 
                    foundrow = row
2619
 
                    del(boot_rows[key])
2620
 
                    break
2621
 
 
2622
 
            if not foundrow:
2623
 
                # Some boot device listed that we don't know about.
2624
 
                foundrow = [dev, "Boot type '%s'" % dev,
2625
 
                            "drive-harddisk", True]
2626
 
 
2627
 
            foundrow[BOOT_ACTIVE] = True
2628
 
            boot_model.append(foundrow)
2629
 
 
2630
 
        # Append all remaining boot_rows that aren't enabled
2631
 
        for dev in old_order:
2632
 
            if dev in boot_rows:
2633
 
                boot_model.append(boot_rows[dev])
2634
 
                del(boot_rows[dev])
2635
 
 
2636
 
        for row in boot_rows.values():
2637
 
            boot_model.append(row)
2638
 
 
2639
 
        boot_list.set_model(boot_model)
2640
 
        selection = boot_list.get_selection()
2641
 
 
2642
 
        if dev_select:
2643
 
            idx = 0
2644
 
            for row in boot_model:
2645
 
                if row[BOOT_DEV_TYPE] == dev_select:
2646
 
                    break
2647
 
                idx += 1
2648
 
 
2649
 
            boot_list.get_selection().select_path(str(idx))
2650
 
 
2651
 
        elif not selection.get_selected()[1]:
2652
 
            # Set a default selection
2653
 
            selection.select_path("0")
2654
 
 
2655
 
 
2656
 
vmmGObjectUI.type_register(vmmDetails)