Beispiel #1
0
class OpusProject(object):
    '''
    Methods and attributes for handling an OPUS project file.
    Inheritance is done by letting a XmlConfiguration object handle loading and saving.
    Each project has two root nodes, one for the full tree and one for the tree of all inherited
    values. Nodes that exists in the full tree AND in the inherited tree, but with different values
    are called "shadowing nodes", since they shadow the inherited value with a local variation.
    '''
    def __init__(self):
        self.name = ''  # Project name
        self.filename = ''  # Filename of loaded project
        self.xml_config = None  # XMLController object
        self._root_node = None  # Full project tree root
        self._inherited_root = None  # Root node of the tree with inherited nodes (original values)
        self._shadowing_nodes = {
        }  # Mapping of nodes in local tree to nodes in inherited tree
        self._dirty = False  # Dirty flag

    def __is_dirty(self):
        return self._dirty

    def __set_dirty(self, dirty):
        self._dirty = dirty
        update_mainwindow_savestate()

    dirty = property(__is_dirty, __set_dirty)

    def _read_xml_from_config(self, xml_config):
        ''' Extract XML information from the XML Configuration object '''
        self.xml_config = xml_config
        self._root_node = xml_config.full_tree.getroot()

        if xml_config.inherited_tree is None:
            self._inherited_root = XMLConfiguration().full_tree.getroot()
        else:
            self._inherited_root = xml_config.inherited_tree

        self._init_shadowing_nodes()
        self._set_project_name()

    def _init_shadowing_nodes(self):
        self._shadowing_nodes = {}
        self._add_shadowing_nodes(self._root_node, '')

    def _add_shadowing_nodes(self, root_node, root_node_id):
        # map id's to nodes for the inherited and the local nodes
        inherited_ids_to_nodes = dict(
            (node_identity_string(n), n)
            for n in self._inherited_root.getiterator())
        local_ids_to_nodes = dict((root_node_id + node_identity_string(n), n)
                                  for n in root_node.getiterator()
                                  if not n.get('inherited'))
        # join the local and inherited nodes on id-match
        for id_, node in local_ids_to_nodes.items():
            if id_ in inherited_ids_to_nodes:
                shadowing_node = inherited_ids_to_nodes[id_]
                assert node.tag == shadowing_node.tag
                self._shadowing_nodes[node] = shadowing_node

    def _set_project_name(self):
        if self.find('./general/project_name') is not None:
            self.name = self.find('./general/project_name').text
        else:
            self.name = 'unnamed_project'
        os.environ['OPUSPROJECTNAME'] = self.name
        self.dirty = False

    def load_minimal_project(self):
        ''' Setup the project as if it was loaded with an absolute minimal project config file '''
        minimal_config = XMLConfiguration()
        self._read_xml_from_config(minimal_config)

    def open(self, filename):
        '''
        Load a project file from XML.
        @return: flag and message (tuple(boolean, String))
        The flag is only True if the project loaded without problems.
        '''
        # Always close the project before loading another one to avoid mixing
        # data if the load is only partly successful
        self.close()
        filename = str(filename)
        if not os.path.exists(filename):
            return (
                False,
                "Tried to load project from file '%s', but that file does not exist"
                % filename)
        default_path = os.path.dirname(filename)
        filename = os.path.basename(filename)
        try:
            xml_config = XMLConfiguration(filename, default_path)
            self._read_xml_from_config(xml_config)
            self.filename = os.path.normpath(
                os.path.join(default_path, filename))
            return (True, 'Project %s loaded OK' % filename)
        # Catch only the errors that XMLConfiguration is known to throw
        except (IOError, SyntaxError, ValueError, SyntaxError,
                XMLVersionException), ex:
            self.close()
            return (False, str(ex))
class OpusProject(object):
    '''
    Methods and attributes for handling an OPUS project file.
    Inheritance is done by letting a XmlConfiguration object handle loading and saving.
    Each project has two root nodes, one for the full tree and one for the tree of all inherited
    values. Nodes that exists in the full tree AND in the inherited tree, but with different values
    are called "shadowing nodes", since they shadow the inherited value with a local variation.
    '''
    def __init__(self):
        self.name = ''              # Project name
        self.filename = ''          # Filename of loaded project
        self.xml_config = None      # XMLController object
        self._root_node = None      # Full project tree root
        self._inherited_root = None # Root node of the tree with inherited nodes (original values)
        self._shadowing_nodes = {}  # Mapping of nodes in local tree to nodes in inherited tree
        self._dirty = False         # Dirty flag

    def __is_dirty(self):
        return self._dirty

    def __set_dirty(self, dirty):
        self._dirty = dirty
        update_mainwindow_savestate()

    dirty = property(__is_dirty, __set_dirty)

    def _read_xml_from_config(self, xml_config):
        ''' Extract XML information from the XML Configuration object '''
        self.xml_config = xml_config
        self._root_node = xml_config.full_tree.getroot()

        if xml_config.inherited_tree is None:
            self._inherited_root = XMLConfiguration().full_tree.getroot()
        else:
            self._inherited_root = xml_config.inherited_tree
        
        self._init_shadowing_nodes()
        self._set_project_name()
        
    def _init_shadowing_nodes(self):
        self._shadowing_nodes = {}
        self._add_shadowing_nodes(self._root_node, '')
        
    def _add_shadowing_nodes(self, root_node, root_node_id):
        # map id's to nodes for the inherited and the local nodes
        inherited_ids_to_nodes = dict((node_identity_string(n), n) for n in self._inherited_root.getiterator())
        local_ids_to_nodes = dict((root_node_id + node_identity_string(n), n) for 
            n in root_node.getiterator() if not n.get('inherited'))
        # join the local and inherited nodes on id-match
        for id_, node in local_ids_to_nodes.items():
            if id_ in inherited_ids_to_nodes:
                shadowing_node = inherited_ids_to_nodes[id_]
                assert node.tag == shadowing_node.tag
                self._shadowing_nodes[node] = shadowing_node

    def _set_project_name(self):
        if self.find('./general/project_name') is not None:
            self.name = self.find('./general/project_name').text
        else:
            self.name = 'unnamed_project'
        os.environ['OPUSPROJECTNAME'] = self.name
        self.dirty = False
        
    def load_minimal_project(self):
        ''' Setup the project as if it was loaded with an absolute minimal project config file '''
        minimal_config = XMLConfiguration()
        self._read_xml_from_config(minimal_config)

    def open(self, filename):
        '''
        Load a project file from XML.
        @return: flag and message (tuple(boolean, String))
        The flag is only True if the project loaded without problems.
        '''
        # Always close the project before loading another one to avoid mixing
        # data if the load is only partly successful
        self.close()
        filename = str(filename)
        if not os.path.exists(filename):
            return (False, "Tried to load project from file '%s', but that file does not exist"
                    %filename)
        default_path = os.path.dirname(filename)
        filename = os.path.basename(filename)
        try:
            xml_config = XMLConfiguration(filename, default_path)
            self._read_xml_from_config(xml_config)
            self.filename = os.path.normpath(os.path.join(default_path, filename))
            return (True, 'Project %s loaded OK' % filename)
        # Catch only the errors that XMLConfiguration is known to throw
        except (IOError, SyntaxError, ValueError, SyntaxError, XMLVersionException), ex:
            self.close()
            return (False, str(ex))