Logo Search packages:      
Sourcecode: vboxgtk version File versions  Download package

vboxgtk_iface.py

# VBoxGtk: A VirtualBox GTK+ GUI
# Copyright (C) 2008 Francisco J. Vazquez-Araujo, Spain
# franjva at gmail dot com

# This file is part of VBoxGtk.

# VBoxGtk is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# VBoxGtk is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with VBoxGtk.  If not, see <http://www.gnu.org/licenses/>.



"""
The GTK interface. Interacts with the vboxdao.
"""


import gtk
import datetime
import os

import vboxgtk
from . import util
from . import vboxdao_xpcom


class VBoxGtk():

    ###### Initialization functions

    def __init__(self, vboxdao):
        self.vboxdao = vboxdao
        self.vboxdao.set_iface(self)
        self.selected_vm = -1
        self.vm_states = {self.vboxdao.vm_states.Null: _("Null"),
                          self.vboxdao.vm_states.PoweredOff: _("Powered Off"),
                          self.vboxdao.vm_states.Saved: _("Saved"),
                          self.vboxdao.vm_states.Aborted: _("Aborted"),
                          self.vboxdao.vm_states.Running: _("Running"),
                          self.vboxdao.vm_states.Paused: _("Paused"),
                          self.vboxdao.vm_states.Stuck: _("Stuck"),
                          self.vboxdao.vm_states.Starting: _("Starting"),
                          self.vboxdao.vm_states.Stopping: _("Stopping"),
                          self.vboxdao.vm_states.Saving: _("Saving"),
                          self.vboxdao.vm_states.Restoring: _("Restoring"),
                          self.vboxdao.vm_states.Discarding: _("Discading"),
                          self.vboxdao.vm_states.SettingUp: _("Setting Up") }
        self.builder = gtk.Builder()
        xml_files = ['xml/vboxgtk-actions.xml',
                     'xml/vboxgtk.xml']
        for f in xml_files:
            self.builder.add_from_file(os.path.join(vboxgtk.data_path, f))
        dic = {'on_window_main_destroy': self.on_window_main_destroy,
               'on_action_about_activate': self.on_action_about_activate,
               'on_action_newvm_activate': self.on_action_newvm_activate,
               'on_action_deletevm_activate': self.on_action_deletevm_activate,
               'on_action_run_activate': self.on_action_run_activate,
               'on_action_sleep_activate': self.on_action_sleep_activate,
               'on_action_stop_activate': self.on_action_stop_activate,
               'on_action_manage_media_activate': self.on_action_manage_media_activate,
               'on_vms_selection_changed': self.on_vms_selection_changed,
               'on_vms_row_activated': self.on_vms_row_activated,
               'on_entry_shared_name_changed': self.on_entry_shared_name_changed,
               'on_treeview_shared_selection_changed': self.on_treeview_shared_selection_changed,
               'on_treeview_snapshots_selection_changed': self.on_treeview_snapshots_selection_changed,
               'on_media_list_selection_changed': self.on_media_list_selection_changed,
               'on_snapshotname_edited': self.on_snapshotname_edited,
               'on_button_newvm_hd_browse_clicked': self.on_button_newvm_hd_browse_clicked,
               'on_button_generatemac_clicked': self.on_button_generatemac_clicked,
               'on_button_trace_file_browse_clicked': self.on_button_trace_file_browse_clicked,
               'on_button_shared_add_clicked': self.on_button_shared_add_clicked,
               'on_button_shared_remove_clicked': self.on_button_shared_remove_clicked,
               'on_button_snapshots_take_clicked': self.on_button_snapshots_take_clicked,
               'on_button_snapshots_discard_clicked': self.on_button_snapshots_discard_clicked,
               'on_button_snapshots_revert_clicked': self.on_button_snapshots_revert_clicked,
               'on_button_manage_hd_new_clicked': self.on_button_manage_hd_new_clicked,
               'on_button_manage_media_register_clicked': self.on_button_manage_media_register_clicked,
               'on_button_manage_media_unregister_clicked': self.on_button_manage_media_unregister_clicked,
               'on_combobox_newvm_os_types_changed': self.on_combobox_newvm_os_types_changed,
               'on_combobox_newvm_hd_changed': self.on_combobox_newvm_hd_changed,
               'on_entry_newvm_any_changed': self.on_entry_newvm_any_changed,
               'on_combobox_hd_changed': self.on_combobox_hd_changed,
               'on_combobox_dvd_changed': self.on_combobox_dvd_changed,
               'on_settings_changed': self.on_settings_changed,
               'on_devices_changed': self.on_devices_changed,
               'on_devices_trace_changed': self.on_devices_trace_changed,
               'on_devices_nic_atts_changed': self.on_devices_nic_atts_changed}
        self.builder.connect_signals(dic)
        self.resetting_settings = True
        self.resetting_media = True
        self.resetting_devices = True
        self.init_widgets()   
        self.reset_media_list('hd')
        self.reset_media_list('dvd')
        self.resetting_settings = False
        self.resetting_media = False        
        self.resetting_devices = False
        self.init_wstates()
        self.set_icons()
        self.vboxdao.start()
        
    def init_widgets(self):
        hscale_ram = self.builder.get_object('hscale_ram')
        hscale_ram.set_range(self.vboxdao.min_ram, self.vboxdao.max_ram)
        hscale_vram = self.builder.get_object('hscale_vram')
        hscale_vram.set_range(1, self.vboxdao.max_vram)
        model_vms = self.builder.get_object('liststore_vms')
        for vm_elem in self.vboxdao.vms:
            model_vms.append([vm_elem.name, self.vm_states[vm_elem.state]])
        model_os_types = self.builder.get_object('liststore_os_types')
        for os_type_elem in self.vboxdao.os_types:
            model_os_types.append([os_type_elem.description, os_type_elem.id])
        def extend(model, list):
            for e in list:
                model.append((e[0], e[1]))
        model_nic_atts = self.builder.get_object('liststore_nic_atts')
        nic_atts = self.vboxdao.nic_atts
        list_nic_atts = (('Null', nic_atts.Null),
                         ('NAT', nic_atts.NAT),
                         ('Bridged', nic_atts.Bridged),
                         ('Internal network', nic_atts.Internal))
        extend(model_nic_atts, list_nic_atts)
        model_nic_devs = self.builder.get_object('liststore_nic_devs')
        nic_devs = self.vboxdao.nic_devs
        list_nic_devs = (('Am79C970A', nic_devs.Am79C970A),
                         ('Am79C973', nic_devs.Am79C973),
                         ('82540EM', nic_devs.I82540EM),
                         ('I82543GC', nic_devs.I82543GC))
        extend(model_nic_devs, list_nic_devs)
        model_audio_drivers = self.builder.get_object('liststore_audio_devs')
        audio_drivers = self.vboxdao.audio_drivers
        list_audio_drivers = (('Null', audio_drivers.Null),
                              ('OSS', audio_drivers.OSS),
                              ('ALSA', audio_drivers.ALSA),
                             ('PulseAudio', audio_drivers.Pulse))
        extend(model_audio_drivers, list_audio_drivers)
        is_separator = lambda model, iter: not model.get_value(iter, 0)
        combo_names = ('combobox_newvm_hd', 'combobox_hd', 'combobox_dvd')
        for combo_name in combo_names:
            combo = self.builder.get_object(combo_name)
            combo.set_row_separator_func(is_separator)

    def init_wstates(self):
        self.wstates = []
        non_sleep_widgets = ['frame_settings_media', 'hbuttonbox_shared']
        non_running_widgets = ['action_run']
        running_widgets = ['action_sleep', 'action_stop']
        stopped_widgets = ['action_deletevm', 'frame_settings_general',
                           'frame_settings_ram', 'label_hd', 'combobox_hd', 
                           'label_floppy', 'combobox_floppy', 
                           'frame_devices_network', 'frame_devices_audio']
        for w in non_sleep_widgets:
            self.wstates.append((w, [self.vboxdao.vm_states.PoweredOff,
                                     self.vboxdao.vm_states.Aborted,
                                     self.vboxdao.vm_states.Running]))
        for w in non_running_widgets:
            self.wstates.append((w, [self.vboxdao.vm_states.PoweredOff,
                                     self.vboxdao.vm_states.Saved,
                                     self.vboxdao.vm_states.Aborted]))
        for w in stopped_widgets:
            self.wstates.append((w, [self.vboxdao.vm_states.PoweredOff,
                                     self.vboxdao.vm_states.Aborted]))
        for w in running_widgets:
            self.wstates.append((w, [self.vboxdao.vm_states.Running]))

    def set_icons(self):
        gtk.icon_theme_get_default().append_search_path(vboxgtk.icons_path)
        gtk.window_set_default_icon_name('vboxgtk')
        self.builder.get_object('window_main').set_icon_name('vboxgtk')
        self.builder.get_object('dialog_about').set_logo_icon_name('vboxgtk')
        
    ########## Callbacks

    ## Exit

    def on_window_main_destroy(self, obj):
        needs_stopping = self.vboxdao.exit()
        if needs_stopping:
            for i, vm in enumerate(self.vboxdao.vms):
                if vm.state == self.vboxdao.vm_states.Running:
                    self.vboxdao.stop_vm(i)
        gtk.main_quit()

    ## About

    def on_action_about_activate(self, obj):
        about = self.builder.get_object('dialog_about')
        about.run()
        about.hide()
    
    ## VM
    
    def reset_everything(self):
        self.reset_settings()
        self.reset_media_list('hd')
        self.reset_media_list('dvd')
        self.reset_devices()
        self.reset_shared()
        self.reset_snapshots()

    def on_vms_row_activated(self, treeview, path, view_column):
        self.on_action_run_activate(None)

    def on_vms_selection_changed(self, obj):
        selected_vm_cursor = obj.get_cursor()[0]
        if selected_vm_cursor is None:
            for w in self.wstates:
                self.builder.get_object(w[0]).set_sensitive(False)
            self.builder.get_object('notebook_vm').set_sensitive(False)
            self.selected_vm = -1
            return
        self.selected_vm = selected_vm_cursor[0]
        self.builder.get_object('notebook_vm').set_sensitive(True)
        for w in self.wstates:
            is_senstitive = self.vboxdao.vms[self.selected_vm].state in w[1]
            self.builder.get_object(w[0]).set_sensitive(is_senstitive)
        self.reset_everything()

    def on_action_newvm_activate(self, obj):
        self.builder.get_object('table_newvm_vm_name').show()
        self.builder.get_object('combobox_newvm_os_types').set_active(0)
        self.builder.get_object('entry_newvm_vm_name').set_text('')
        self.builder.get_object('entry_newvm_hd_name').set_text('')
        liststore_hd = self.builder.get_object('liststore_combo_hd')
        liststore_hd.append(["",''])
        liststore_hd.append([_("New VDI"),'new'])
        self.builder.get_object('combobox_newvm_hd').set_active(0)
        dialog = self.builder.get_object('dialog_newvm')
        dialog.set_title(_("New VM"))
        finished = False
        while not finished:
            if dialog.run() != 0:
                dialog.hide()
                del liststore_hd[-1]
                del liststore_hd[-1]
                return
            vm_name = self.builder.get_object('entry_newvm_vm_name').get_text()
            os_type = self.get_value_from_combobox('combobox_newvm_os_types', 1)
            if self.show_msg_if_error(self.vboxdao.create_vm(vm_name, os_type)):
                continue
            finished = True
        state = self.vm_states[self.vboxdao.vm_states.PoweredOff]
        self.builder.get_object('liststore_vms').append([vm_name, state])
        hd_id = liststore_hd[self.builder.get_object('combobox_newvm_hd').get_active()][1]
        del liststore_hd[-1]
        del liststore_hd[-1]
        dialog.hide()
        if hd_id == 'new':   # New image
            hd_path = self.builder.get_object('entry_newvm_hd_name').get_text()
            hd_size = self.builder.get_object('hscale_newvm_hd_size').get_value()
            hd_dynamic = self.builder.get_object('checkbutton_newvm_hd_dynamic').get_active()
            if not self.show_msg_if_error(self.vboxdao.create_hd_image(hd_path, hd_size * 1024, hd_dynamic)):
                hd_id = self.vboxdao.hard_disks[-1].id
        # If the disk was created successfully OR none/other was selected:
        if hd_id != 'new':
            self.show_msg_if_error(self.vboxdao.attach_hd(-1, hd_id)) 
        self.reset_media_list('hd')

    def on_combobox_newvm_os_types_changed(self, obj):
        os_idx = obj.get_active()
        if os_idx < 1:
            return
        os_type = self.vboxdao.os_types[os_idx]
        self.builder.get_object('entry_newvm_vm_name').set_text(os_type.description)
        self.builder.get_object('entry_newvm_hd_name').set_text(os_type.description + '.img')
        self.builder.get_object('hscale_newvm_hd_size').set_value(os_type.recommendedHDD / 1024)
        
    def on_combobox_newvm_hd_changed(self, obj):
        if self.resetting_media:
            return
        hd_id = self.get_value_from_combobox('combobox_newvm_hd',1)
        wlist = [ 'table_newvm_hd', 'checkbutton_newvm_hd_dynamic' ]
        for w in wlist:
            self.builder.get_object(w).set_sensitive(hd_id == 'new' or hd_id == '') # Ugly hack: if the separator is selected, consider it as "New"
        self.on_entry_newvm_any_changed(None)

    def on_entry_newvm_any_changed(self, obj):
        vm_name = self.builder.get_object('entry_newvm_vm_name').get_text()
        hd_id = self.get_value_from_combobox('combobox_newvm_hd',1)
        hd_name = self.builder.get_object('entry_newvm_hd_name').get_text() if hd_id == 'new' else 'doesntmatter'
        self.builder.get_object('button_newvm_add').set_sensitive(len(vm_name) != 0 and len(hd_name) != 0) # FIXME: validate filenames

    def on_button_newvm_hd_browse_clicked(self, obj):
        dialog = gtk.FileChooserDialog(_("Save..."), None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK))
        dialog.set_do_overwrite_confirmation(True)
        dialog.set_current_folder(self.vboxdao.default_media_folder)
        dialog.set_default_response(gtk.RESPONSE_OK)
        if dialog.run() == gtk.RESPONSE_OK:
            self.builder.get_object('entry_newvm_hd_name').set_text(dialog.get_filename())
        dialog.destroy()

    def on_action_deletevm_activate(self, obj):
        if self.confirm_msg(_("Are you sure you want to delete the virtual\nmachine '%s'?") % self.vboxdao.vms[self.selected_vm].name, 
            _("The machine settings will be lost, but the disks attached\nto the machine will not be deleted.")) == gtk.RESPONSE_CANCEL:
                return
        if self.show_msg_if_error(self.vboxdao.delete_vm(self.selected_vm)):
            return
        del self.builder.get_object('treeview_vms').get_model()[self.selected_vm]
        self.selected_vm = -1
        self.reset_media_list('hd')
        self.reset_media_list('dvd')
        self.on_vms_selection_changed(self.builder.get_object('treeview_vms'))

    def on_action_run_activate(self, obj):
        self.vboxdao.prepare_vm(self.selected_vm)
        (status, msg) = self.vboxdao.start_vm(self.selected_vm)
        if status:  # Assume module not loaded
            self.show_msg(True, _("The VM could not be started"), 
                          _("This usually means that the vboxdrv module is not\
                             loaded.\nTry again after loading the module."))

    def on_action_sleep_activate(self, obj):
        self.vboxdao.sleep_vm(self.selected_vm)

    def on_action_stop_activate(self, obj):
        self.vboxdao.stop_vm(self.selected_vm)
    
    ## Media
    
    def reset_media_list(self, media_type):
        self.resetting_media = True
        liststore_combo = self.builder.get_object('liststore_combo_' + media_type)
        liststore_tree = self.builder.get_object('liststore_tree_' + media_type)
        liststore_combo.clear()
        liststore_tree.clear()
        liststore_combo.append([_("(none)"), None])
        liststore_combo.append(["", ''])
        if media_type == 'hd':
            list = self.vboxdao.hard_disks
        else:
            list = self.vboxdao.dvd_images
        for i, image in enumerate(list):
            image_owner_names = ''
            vm_list = image.getMachineIds()
            if vm_list is not None:
                for vm in self.vboxdao.vms:
                    if vm.id in vm_list:
                        if image_owner_names != '':
                            image_owner_names += ', '
                        image_owner_names += vm.name
            image_name = os.path.basename(image.location)
            liststore_tree.append([image_name, util.shortname(os.path.dirname(image.location)), image_owner_names])
            liststore_combo.append([image_name, image.id])
        if media_type == 'dvd':
            liststore_combo.append(['', ''])
            for i, hostdrive in enumerate(self.vboxdao.dvd_host_drives):
                liststore_combo.append([hostdrive.name, hostdrive.name])
        self.select_value_in_combobox('combobox_hd', 1, self.vboxdao.get_hd_id(self.selected_vm) if self.selected_vm != -1 else None)
        self.select_value_in_combobox('combobox_dvd', 1, self.vboxdao.get_dvd_id(self.selected_vm) if self.selected_vm != -1 else None)
        self.resetting_media = False
                
    def on_action_manage_media_activate(self, obj):
        self.builder.get_object('dialog_manage_media').run()
        self.builder.get_object('dialog_manage_media').hide()

    def on_media_list_selection_changed(self, obj):
        media_type = 'hd' if obj == self.builder.get_object('treeview_manage_hd') else 'dvd'
        sensitive = False
        selected_media_cursor = obj.get_cursor()[0]
        if selected_media_cursor:
            selected_image = selected_media_cursor[0]
            image = self.vboxdao.dvd_images[selected_image] \
                    if media_type == 'dvd' else \
                    self.vboxdao.hard_disks[selected_image]
            sensitive = image.getMachineIds() is None
        but = 'button_manage_' + media_type + '_unregister'
        self.builder.get_object(but).set_sensitive(sensitive)
        if media_type == 'hd':
            but = 'button_manage_hd_delete'
            self.builder.get_object(but).set_sensitive(sensitive)
    
    def on_button_manage_hd_new_clicked(self, obj):
        dialog = self.builder.get_object('dialog_newvm')
        dialog.set_title(_("New hard disk image"))
        # Ugly hack: select separator to enable hd entries:
        self.select_value_in_combobox('combobox_newvm_hd', 1, '') 
        # Unlock add button:
        self.builder.get_object('entry_newvm_vm_name').set_text('doesntmatter')
        self.builder.get_object('table_newvm_vm_name').hide()
        self.builder.get_object('entry_newvm_hd_name').set_text('')
        finished = False
        while not finished:
            if dialog.run() != 0:
                dialog.hide()
                return
            hd_path = self.builder.get_object('entry_newvm_hd_name').get_text()
            hd_size = self.builder.get_object('hscale_newvm_hd_size').get_value()
            hd_dynamic = self.builder.get_object('checkbutton_newvm_hd_dynamic').get_active()
            st_msg = self.vboxdao.create_hd_image(hd_path, hd_size * 1024, hd_dynamic)
            if self.show_msg_if_error(st_msg):
                continue
            finished = True
        self.reset_media_list("hd")
        dialog.hide()
    
    def on_button_manage_media_register_clicked(self, obj):
        dialog = gtk.FileChooserDialog(_("Open..."), None, 
                                       gtk.FILE_CHOOSER_ACTION_OPEN, 
                                       (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)
        if obj == self.builder.get_object('button_manage_dvd_register'):
            media_type = 'dvd'
        else:
            media_type = 'hd'
            dialog.set_current_folder(self.vboxdao.default_media_folder)
        if dialog.run() != gtk.RESPONSE_OK:
            dialog.destroy()
            return
        filename = dialog.get_filename()
        dialog.destroy()
        status_and_msg = self.vboxdao.add_dvd_image(filename) \
                         if media_type == 'dvd' else \
                         self.vboxdao.add_hd(filename)
        if self.show_msg_if_error(status_and_msg):
            return
        self.reset_media_list(media_type)
        treeview = self.builder.get_object('treeview_manage_' + media_type)
        self.on_media_list_selection_changed(treeview)

    def on_button_manage_media_unregister_clicked(self, obj):
        delete_file = False
        if obj == self.builder.get_object('button_manage_dvd_unregister'):
            media_type = 'dvd'
        else: 
            media_type = 'hd'
            if obj == self.builder.get_object('button_manage_hd_delete'):
                delete_file = True
        treeview_media_list = self.builder.get_object('treeview_manage_' + media_type)
        selected_media_num = treeview_media_list.get_cursor()[0][0]
        model_media_list = treeview_media_list.get_model()
        if delete_file:
            if self.confirm_msg(_("Are you sure you want to delete the\nhd image?"),
                                _("The file will be permantently lost.")) == gtk.RESPONSE_CANCEL:
                return
        status_and_msg = self.vboxdao.remove_dvd_image(selected_media_num) \
                         if media_type == 'dvd' else \
                         self.vboxdao.remove_hd(selected_media_num, delete_file)
        if self.show_msg_if_error(status_and_msg):
            return
        self.reset_media_list(media_type)
        self.on_media_list_selection_changed(treeview_media_list)

    
    ## Settings tab
    
    def reset_settings(self):
        self.resetting_settings = True
        os_type = self.vboxdao.vms[self.selected_vm].OSTypeId
        hwvirtex = self.vboxdao.vms[self.selected_vm].HWVirtExEnabled
        ram = self.vboxdao.vms[self.selected_vm].memorySize
        vram = self.vboxdao.vms[self.selected_vm].VRAMSize
        dvdpass = self.vboxdao.vms[self.selected_vm].DVDDrive.passthrough
        self.select_value_in_combobox('combobox_os_types', 1, os_type)
        self.builder.get_object('checkbutton_hw_virt_ext').set_active(hwvirtex)
        self.builder.get_object('hscale_ram').set_value(ram)
        self.builder.get_object('hscale_vram').set_value(vram)
        self.builder.get_object('checkbutton_dvd_passthrough').set_active(dvdpass)
        self.update_dvd_passthrough_state()
        self.resetting_settings = False

    def on_settings_changed(self, obj):
        if self.resetting_settings:
            return
        os_type = self.get_value_from_combobox('combobox_os_types',1)
        hw_virt_ext = self.builder.get_object('checkbutton_hw_virt_ext').get_active()
        mem = self.builder.get_object('hscale_ram').get_value()
        vmem = self.builder.get_object('hscale_vram').get_value()
        dvd_passthrough = self.builder.get_object('checkbutton_dvd_passthrough').get_active()
        self.vboxdao.update_settings(self.selected_vm, os_type, hw_virt_ext, 
                                     mem, vmem, dvd_passthrough)

    def on_combobox_hd_changed(self, obj):
        if self.resetting_media:
            return
        hd_id = self.get_value_from_combobox('combobox_hd', 1)
        if not self.show_msg_if_error(self.vboxdao.attach_hd(self.selected_vm, hd_id)):
            self.reset_media_list('hd')
        
    def on_combobox_dvd_changed(self, obj):
        if self.resetting_media:
            return
        dvd_id = self.get_value_from_combobox('combobox_dvd', 1)
        if not self.show_msg_if_error(self.vboxdao.attach_dvd(self.selected_vm, dvd_id)):
            self.reset_media_list('dvd')
        self.update_dvd_passthrough_state()
                
    def update_dvd_passthrough_state(self):
        sensitive = False
        combo = self.builder.get_object('combobox_dvd')
        if combo.state != gtk.STATE_INSENSITIVE:
            dvd_id = self.get_value_from_combobox('combobox_dvd', 1)
            is_host_drive = (dvd_id is not None and dvd_id[0] == '/')  # FIXME, UGLY
            sensitive = self.vboxdao.vms[self.selected_vm].state in \
                        [self.vboxdao.vm_states.PoweredOff, self.vboxdao.vm_states.Aborted] and \
                        is_host_drive
        self.builder.get_object('checkbutton_dvd_passthrough').set_sensitive(sensitive)

    ## Devices tab

    def reset_devices(self):
        self.resetting_devices = True
        net = self.vboxdao.vms[self.selected_vm].getNetworkAdapter(0)
        self.select_value_in_combobox('combobox_nic_atts', 1, net.attachmentType)
        self.select_value_in_combobox('combobox_nic_devs', 1, net.adapterType)
        if net.internalNetwork is not None:
            self.builder.get_object('entry_intnet').set_text(net.internalNetwork)
        if net.hostInterface is not None:
            self.builder.get_object('entry_hostif').set_text(net.hostInterface)
        self.builder.get_object('entry_mac').set_text(net.MACAddress)
        self.builder.get_object('checkbutton_cable_connected').set_active(net.cableConnected)
        self.builder.get_object('checkbutton_trace').set_active(net.traceEnabled)
        if net.traceFile is not None:
            self.builder.get_object('entry_trace_file').set_text(net.traceFile)
        self.update_nic_config_state()
        audio = self.vboxdao.vms[self.selected_vm].audioAdapter.audioDriver
        self.select_value_in_combobox('combobox_audio_devs', 1, audio)
        self.resetting_devices = False
    
    def on_button_generatemac_clicked(self, obj):
        self.builder.get_object('entry_mac').set_text(util.random_mac())

    def on_button_trace_file_browse_clicked(self, obj):
        dialog = gtk.FileChooserDialog(_("Save..."), None, 
                                       gtk.FILE_CHOOSER_ACTION_SAVE, 
                                       (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
                                        gtk.STOCK_SAVE, gtk.RESPONSE_OK))
        dialog.set_do_overwrite_confirmation(True)
        dialog.set_default_response(gtk.RESPONSE_OK)
        if dialog.run() == gtk.RESPONSE_OK:
            self.builder.get_object('entry_trace_file').set_text(dialog.get_filename())
        dialog.destroy()
    
    def on_devices_changed(self, obj):
        if self.resetting_devices:
            return
        audio_dev = self.get_value_from_combobox('combobox_audio_devs', 1)
        mac = self.builder.get_object('entry_mac').get_text()
        net_att = self.get_value_from_combobox('combobox_nic_atts', 1)
        net_dev = self.get_value_from_combobox('combobox_nic_devs', 1)
        cable = self.builder.get_object('checkbutton_cable_connected').get_active()
        trace_file = self.builder.get_object('entry_trace_file').get_text()
        trace = self.builder.get_object('checkbutton_trace').get_active() and \
                trace_file != ''  # FIXME: check validity
        intnet = self.builder.get_object('entry_intnet').get_text()
        if intnet == '':
            intnet = 'intnet'
            self.builder.get_object('entry_intnet').set_text(intnet)
        hostif = self.builder.get_object('entry_hostif').get_text()
        self.vboxdao.update_devices(self.selected_vm, net_att, net_dev, 
                                    intnet, hostif, mac, cable, trace, 
                                    trace_file, audio_dev)
    
    def on_devices_nic_atts_changed(self, obj):
        if self.resetting_devices:
            return
        self.update_nic_config_state()
        self.on_devices_changed(obj)

    def on_devices_trace_changed(self, obj):
        if self.resetting_devices:
            return
        self.update_trace_file_state()
        self.on_devices_changed(obj)

    def update_nic_config_state(self):
        combo_atts = self.builder.get_object('combobox_nic_atts')
        nic_att_sensitive = combo_atts.state != gtk.STATE_INSENSITIVE
        nic_att = self.get_value_from_combobox('combobox_nic_atts', 1)
        net_widg = ('label_nic_dev', 'combobox_nic_devs', 'label_mac', 
                    'entry_mac', 'button_generatemac', 
                    'checkbutton_cable_connected', 'checkbutton_trace')
        for w in net_widg:
            sens = nic_att != self.vboxdao.nic_atts.Null and nic_att_sensitive
            self.builder.get_object(w).set_sensitive(sens)
        sens = nic_att == self.vboxdao.nic_atts.Bridged and nic_att_sensitive
        self.builder.get_object('label_hostif').set_sensitive(sens)
        self.builder.get_object('entry_hostif').set_sensitive(sens)
        sens = nic_att == self.vboxdao.nic_atts.Internal and nic_att_sensitive
        self.builder.get_object('label_intnet').set_sensitive(sens)
        self.builder.get_object('entry_intnet').set_sensitive(sens)
        self.update_trace_file_state() 
        
    def update_trace_file_state(self):
        trace = self.builder.get_object('checkbutton_trace')
        sensitive = trace.state != gtk.STATE_INSENSITIVE and trace.get_active()
        self.builder.get_object('label_trace_file').set_sensitive(sensitive)
        self.builder.get_object('entry_trace_file').set_sensitive(sensitive)
        self.builder.get_object('button_trace_file_browse').set_sensitive(sensitive)
        
    ## Shared folders tab & dialog

    def reset_shared(self):
        model_shared = self.builder.get_object('liststore_shared')
        model_shared.clear()
        shared_list = self.vboxdao.vms[self.selected_vm].getSharedFolders()
        for shared in shared_list:
            model_shared.append([shared.name, util.shortname(shared.hostPath),
                                 shared.writable])
        self.update_shared_remove_state()

    def on_entry_shared_name_changed(self, obj):
        shared_name = obj.get_text()
        button_add = self.builder.get_object('button_addshared_add')
        # FIXME: check name validity:
        button_add.set_sensitive(len(shared_name) != 0)

    def on_treeview_shared_selection_changed(self, obj):
        self.update_shared_remove_state()
            
    def update_shared_remove_state(self):
        treeview_sharedlist = self.builder.get_object('treeview_shared')
        model_sharedlist = treeview_sharedlist.get_model()
        selected_shared_cursor = treeview_sharedlist.get_cursor()[0]
        sensitive = selected_shared_cursor is not None
        self.builder.get_object('button_shared_remove').set_sensitive(sensitive)
    
    def on_button_shared_add_clicked(self, obj):
        dialog = self.builder.get_object('dialog_addshared')
        finished = False
        while not finished:
            if dialog.run() != 0:
                dialog.hide()
                return
            name = self.builder.get_object('entry_shared_name').get_text();
            path = self.builder.get_object('filechooserbutton_shared_path').get_filename();
            writable = self.builder.get_object('checkbutton_shared_writable').get_active();
            if self.show_msg_if_error(self.vboxdao.create_shared(self.selected_vm, name, path, writable)):
                continue
            finished = True
        model_sharedlist = self.builder.get_object('treeview_shared').get_model()
        model_sharedlist.append([name, util.shortname(path), writable])
        dialog.hide()

    def on_button_shared_remove_clicked(self, obj):
        treeview_sharedlist = self.builder.get_object('treeview_shared')
        model_sharedlist = treeview_sharedlist.get_model()
        selected_shared = treeview_sharedlist.get_cursor()[0][0]
        shared_name = model_sharedlist[selected_shared][0]
        if self.show_msg_if_error(self.vboxdao.remove_shared(self.selected_vm, shared_name)):
            return
        del model_sharedlist[selected_shared]
        self.update_shared_remove_state()

    ## Snapshots tab

    def reset_snapshots(self):
        treeview_snapshots = self.builder.get_object('treeview_snapshots')
        model_snapshots = treeview_snapshots.get_model()
        model_snapshots.clear()
        snapshot_list = self.vboxdao.get_snapshot_tree(self.selected_vm)
        def fill_snapshot_list(node, pos):
            snapshot = snapshot_list[pos][0]
            iter = model_snapshots.append(node, [snapshot.name, str(snapshot.id)])
            pos = pos + 1
            while pos != len(snapshot_list) and snapshot_list[pos][1] == snapshot.id:
                fill_snapshot_list(iter, pos)
                pos = pos + 1
        if snapshot_list != []:
            fill_snapshot_list(None, 0)
        treeview_snapshots.expand_all()
        self.on_treeview_snapshots_selection_changed(treeview_snapshots)
        self.update_snapshot_revert_state()

    def on_treeview_snapshots_selection_changed(self, obj):
        self.update_snapshot_discard_state()

    def update_snapshot_discard_state(self):
        selected_snapshot_cursor = self.builder.get_object('treeview_snapshots').get_cursor()[0]
        sensitive = selected_snapshot_cursor is not None \
                    and self.vboxdao.vms[self.selected_vm].state != self.vboxdao.vm_states.Running
        self.builder.get_object('button_snapshots_discard').set_sensitive(sensitive)
        
    def update_snapshot_revert_state(self):
        model = self.builder.get_object('treestore_snapshots')
        sensitive = len(model) > 0 \
                    and self.vboxdao.vms[self.selected_vm].state != self.vboxdao.vm_states.Running
        self.builder.get_object('button_snapshots_revert').set_sensitive(sensitive)

    def on_snapshotname_edited(self, cell, path, new_name):
        if len(new_name) == 0:
            return
        model = self.builder.get_object('treestore_snapshots')
        if self.show_msg_if_error(self.vboxdao.edit_snapshot(self.selected_vm, model[path][1], new_name)):
            return
        model[path][0] = new_name
        
    def on_button_snapshots_take_clicked(self, obj):
        model = self.builder.get_object('treestore_snapshots')
        new_name = 'Snapshot ' + datetime.datetime.now().ctime()
        if self.show_msg_if_error(self.vboxdao.take_snapshot(self.selected_vm, new_name)):
            return
        self.reset_snapshots()
        self.update_snapshot_revert_state()

    def on_button_snapshots_discard_clicked(self, obj):
        tree = self.builder.get_object('treeview_snapshots')
        model = tree.get_model()
        snapshot_id = model[tree.get_cursor()[0]][1]
        if self.show_msg_if_error(self.vboxdao.discard_snapshot(self.selected_vm, snapshot_id)):
            return
        self.reset_snapshots()
        self.update_snapshot_discard_state()
        self.update_snapshot_revert_state()
        
    def on_button_snapshots_revert_clicked(self, obj):
        self.vboxdao.discard_current_state(self.selected_vm)
        self.reset_everything()
        
    ########## Auxiliary functions

    def update_state(self, vm, from_thread = False):
        if from_thread:
            gtk.gdk.threads_enter()
        model_vmlist = self.builder.get_object('treeview_vms').get_model()
        model_vmlist.set_value(model_vmlist.get_iter(self.vboxdao.vms.index(vm)), 
                               1, self.vm_states[vm.state]);
        if self.vboxdao.vms[self.selected_vm] == vm:
            # Widgets that only depend on VM state
            for w in self.wstates:
                self.builder.get_object(w[0]).set_sensitive(vm.state in w[1])
            self.update_dvd_passthrough_state()
            self.update_nic_config_state()
            self.update_shared_remove_state()
            self.update_snapshot_discard_state()
            self.update_snapshot_revert_state()
        if from_thread:
            gtk.gdk.threads_leave()

    def show_msg_if_error(self, status_and_msg):
        if status_and_msg[0] == 0:
            return 0
        self.show_msg(True, status_and_msg[1])
        return 1

    def show_msg(self, is_error, msg1, msg2 = '', from_thread = False):
        if from_thread:
            gtk.gdk.threads_enter()
        if is_error:
            msg_type = gtk.MESSAGE_ERROR
        else:
            msg_type = gtk.MESSAGE_INFO
        dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, msg_type, 
                                   gtk.BUTTONS_CLOSE, msg1)
        dialog.format_secondary_text(msg2)
        dialog.run()
        dialog.destroy()
        if from_thread:
            gtk.gdk.threads_leave()

    def confirm_msg(self, msg1, msg2):
        dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING,
                                         gtk.BUTTONS_NONE, msg1)
        dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
                           gtk.STOCK_DELETE, gtk.RESPONSE_OK)
        dialog.format_secondary_text(msg2)
        decision = dialog.run()
        dialog.destroy()
        return decision
            
    def get_value_from_combobox(self, combobox_name, column):
        combobox = self.builder.get_object(combobox_name)
        model = combobox.get_model()
        if combobox.get_active() == -1:
            return None
        return model.get_value(model.get_iter(combobox.get_active()), column)

    def select_value_in_combobox(self, combobox_name, column, value):
        combobox = self.builder.get_object(combobox_name)
        model = combobox.get_model()
        for i, row in enumerate(model):
            if row[column] == value:
                combobox.set_active(i)
                break

####### End of VBoxGtk class


def main():
    VBoxGtk(vboxdao_xpcom.VBoxDaoXpcom())
    gtk.gdk.threads_init()
    gtk.main()

Generated by  Doxygen 1.6.0   Back to index