Statistics
| Branch: | Tag: | Revision:

root / grc / base / Platform.py @ 63c92857

History | View | Annotate | Download (6.6 kB)

1
"""
2
Copyright 2008, 2009 Free Software Foundation, Inc.
3
This file is part of GNU Radio
4
5
GNU Radio Companion is free software; you can redistribute it and/or
6
modify it under the terms of the GNU General Public License
7
as published by the Free Software Foundation; either version 2
8
of the License, or (at your option) any later version.
9
10
GNU Radio Companion 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, MA  02110-1301, USA
18
"""
19
20
import os
21
import sys
22
from .. base import ParseXML, odict
23
from Element import Element as _Element
24
from FlowGraph import FlowGraph as _FlowGraph
25
from Connection import Connection as _Connection
26
from Block import Block as _Block
27
from Port import Port as _Port
28
from Param import Param as _Param
29
from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD
30
31
class Platform(_Element):
32
33
        def __init__(self, name, version, key,
34
                block_paths, block_dtd, default_flow_graph, generator,
35
                license='', website=None, colors=[]):
36
                """
37
                Make a platform from the arguments.
38
                @param name the platform name
39
                @param version the version string
40
                @param key the unique platform key
41
                @param block_paths the file paths to blocks in this platform
42
                @param block_dtd the dtd validator for xml block wrappers
43
                @param default_flow_graph the default flow graph file path
44
                @param generator the generator class for this platform
45
                @param colors a list of title, color_spec tuples
46
                @param license a multi-line license (first line is copyright)
47
                @param website the website url for this platform
48
                @return a platform object
49
                """
50
                _Element.__init__(self)
51
                self._name = name
52
                self._version = version
53
                self._key = key
54
                self._license = license
55
                self._website = website
56
                self._block_paths = block_paths
57
                self._block_dtd = block_dtd
58
                self._default_flow_graph = default_flow_graph
59
                self._generator = generator
60
                self._colors = colors
61
                #create a dummy flow graph for the blocks
62
                self._flow_graph = _Element(self)
63
                #search for *.xml files in the given search path
64
                xml_files = list()
65
                for block_path in self._block_paths:
66
                        if os.path.isfile(block_path): xml_files.append(block_path)
67
                        elif os.path.isdir(block_path):
68
                                for dirpath, dirnames, filenames in os.walk(block_path):
69
                                        for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
70
                                                xml_files.append(os.path.join(dirpath, filename))
71
                #load the blocks
72
                self._blocks = odict()
73
                self._blocks_n = odict()
74
                self._block_tree_files = list()
75
                for xml_file in xml_files:
76
                        try: #try to add the xml file as a block wrapper
77
                                ParseXML.validate_dtd(xml_file, self._block_dtd)
78
                                n = ParseXML.from_file(xml_file).find('block')
79
                                #inject block wrapper path
80
                                n['block_wrapper_path'] = xml_file
81
                                block = self.Block(self._flow_graph, n)
82
                                key = block.get_key()
83
                                #test against repeated keys
84
                                try:
85
                                        assert key not in self.get_block_keys()
86
                                        #store the block
87
                                        self._blocks[key] = block
88
                                        self._blocks_n[key] = n
89
                                except AssertionError:
90
                                        print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file)
91
                        except ParseXML.XMLSyntaxError, e: 
92
                                try: #try to add the xml file as a block tree
93
                                        ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
94
                                        self._block_tree_files.append(xml_file)
95
                                except ParseXML.XMLSyntaxError, e:
96
                                        print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
97
                        except Exception, e:
98
                                print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
99
100
        def parse_flow_graph(self, flow_graph_file):
101
                """
102
                Parse a saved flow graph file.
103
                Ensure that the file exists, and passes the dtd check.
104
                @param flow_graph_file the flow graph file
105
                @return nested data
106
                @throws exception if the validation fails
107
                """
108
                flow_graph_file = flow_graph_file or self._default_flow_graph
109
                open(flow_graph_file, 'r') #test open
110
                ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
111
                return ParseXML.from_file(flow_graph_file)
112
113
        def load_block_tree(self, block_tree):
114
                """
115
                Load a block tree with categories and blocks.
116
                Step 1: Load all blocks from the xml specification.
117
                Step 2: Load blocks with builtin category specifications.
118
                @param block_tree the block tree object
119
                """
120
                #recursive function to load categories and blocks
121
                def load_category(cat_n, parent=[]):
122
                        #add this category
123
                        parent = parent + [cat_n.find('name')]
124
                        block_tree.add_block(parent)
125
                        #recursive call to load sub categories
126
                        map(lambda c: load_category(c, parent), cat_n.findall('cat'))
127
                        #add blocks in this category
128
                        for block_key in cat_n.findall('block'):
129
                                if block_key not in self.get_block_keys():
130
                                        print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.'%(block_key)
131
                                        continue
132
                                block = self.get_block(block_key)
133
                                #if it exists, the block's category overrides the block tree
134
                                if not block.get_category(): block_tree.add_block(parent, block)
135
                #load the block tree
136
                for block_tree_file in self._block_tree_files:
137
                        #recursivly add all blocks in the tree
138
                        load_category(ParseXML.from_file(block_tree_file).find('cat'))
139
                #add all other blocks, use the catgory tag
140
                for block in self.get_blocks():
141
                        #blocks with empty categories are in the xml block tree or hidden
142
                        if not block.get_category(): continue
143
                        block_tree.add_block(block.get_category(), block)
144
145
        def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
146
147
        def is_platform(self): return True
148
149
        def get_new_flow_graph(self): return self.FlowGraph(self)
150
151
        def get_generator(self): return self._generator
152
153
        ##############################################
154
        # Access Blocks
155
        ##############################################
156
        def get_block_keys(self): return self._blocks.keys()
157
        def get_block(self, key): return self._blocks[key]
158
        def get_blocks(self): return self._blocks.values()
159
        def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key])
160
161
        def get_name(self): return self._name
162
        def get_version(self): return self._version
163
        def get_key(self): return self._key
164
        def get_license(self): return self._license
165
        def get_website(self): return self._website
166
        def get_colors(self): return self._colors
167
168
        ##############################################
169
        # Constructors
170
        ##############################################
171
        FlowGraph = _FlowGraph
172
        Connection = _Connection
173
        Block = _Block
174
        Port = _Port
175
        Param = _Param