Removed the flagging api and usage from the base classes.
[debian/gnuradio] / grc / base / FlowGraph.py
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 from . import odict
21 from Element import Element
22 from Block import Block
23 from Connection import Connection
24 from .. gui import Messages
25
26 class FlowGraph(Element):
27
28         def __init__(self, platform):
29                 """
30                 Make a flow graph from the arguments.
31                 @param platform a platforms with blocks and contrcutors
32                 @return the flow graph object
33                 """
34                 #initialize
35                 Element.__init__(self, platform)
36                 #inital blank import
37                 self.import_data()
38
39         def _get_unique_id(self, base_id=''):
40                 """
41                 Get a unique id starting with the base id.
42                 @param base_id the id starts with this and appends a count
43                 @return a unique id
44                 """
45                 index = 0
46                 while True:
47                         id = '%s_%d'%(base_id, index)
48                         index = index + 1
49                         #make sure that the id is not used by another block
50                         if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id
51
52         def __str__(self): return 'FlowGraph - %s(%s)'%(self.get_option('title'), self.get_option('id'))
53
54         def get_option(self, key):
55                 """
56                 Get the option for a given key.
57                 The option comes from the special options block.
58                 @param key the param key for the options block
59                 @return the value held by that param
60                 """
61                 return self._options_block.get_param(key).get_evaluated()
62
63         def is_flow_graph(self): return True
64
65         ##############################################
66         ## Access Elements
67         ##############################################
68         def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
69         def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements())
70         def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
71         def get_elements(self):
72                 """
73                 Get a list of all the elements.
74                 Always ensure that the options block is in the list (only once).
75                 @return the element list
76                 """
77                 options_block_count = self._elements.count(self._options_block)
78                 if not options_block_count:
79                         self._elements.append(self._options_block)
80                 for i in range(options_block_count-1):
81                         self._elements.remove(self._options_block)
82                 return self._elements
83
84         def get_enabled_blocks(self):
85                 """
86                 Get a list of all blocks that are enabled.
87                 @return a list of blocks
88                 """
89                 return filter(lambda b: b.get_enabled(), self.get_blocks())
90
91         def get_enabled_connections(self):
92                 """
93                 Get a list of all connections that are enabled.
94                 @return a list of connections
95                 """
96                 return filter(lambda c: c.get_enabled(), self.get_connections())
97
98         def get_new_block(self, key):
99                 """
100                 Get a new block of the specified key.
101                 Add the block to the list of elements.
102                 @param key the block key
103                 @return the new block or None if not found
104                 """
105                 if key not in self.get_parent().get_block_keys(): return None
106                 block = self.get_parent().get_new_block(self, key)
107                 self.get_elements().append(block)
108                 return block
109
110         def connect(self, porta, portb):
111                 """
112                 Create a connection between porta and portb.
113                 @param porta a port
114                 @param portb another port
115                 @throw Exception bad connection
116                 @return the new connection
117                 """
118                 connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
119                 self.get_elements().append(connection)
120                 return connection
121
122         def remove_element(self, element):
123                 """
124                 Remove the element from the list of elements.
125                 If the element is a port, remove the whole block.
126                 If the element is a block, remove its connections.
127                 If the element is a connection, just remove the connection.
128                 """
129                 if element not in self.get_elements(): return
130                 #found a port, set to parent signal block
131                 if element.is_port():
132                         element = element.get_parent()
133                 #remove block, remove all involved connections
134                 if element.is_block():
135                         for port in element.get_ports():
136                                 map(self.remove_element, port.get_connections())
137                 self.get_elements().remove(element)
138
139         def evaluate(self, expr):
140                 """
141                 Evaluate the expression.
142                 @param expr the string expression
143                 @throw NotImplementedError
144                 """
145                 raise NotImplementedError
146
147         def rewrite(self):
148                 """
149                 Rewrite critical structures.
150                 Call rewrite on all sub elements.
151                 """
152                 Element.rewrite(self)
153                 for elem in self.get_elements(): elem.rewrite()
154
155         def validate(self):
156                 """
157                 Validate the flow graph.
158                 Validate only the blocks.
159                 Connections will be validated within the blocks.
160                 """
161                 Element.validate(self)
162                 for c in self.get_blocks():
163                         c.validate()
164                         if not c.is_valid():
165                                 self.add_error_message('Element "%s" is not valid.'%c)
166
167         ##############################################
168         ## Import/Export Methods
169         ##############################################
170         def export_data(self):
171                 """
172                 Export this flow graph to nested data.
173                 Export all block and connection data.
174                 @return a nested data odict
175                 """
176                 import time
177                 n = odict()
178                 n['timestamp'] = time.ctime()
179                 n['block'] = [block.export_data() for block in self.get_blocks()]
180                 n['connection'] = [connection.export_data() for connection in self.get_connections()]
181                 return odict({'flow_graph': n})
182
183         def import_data(self, n=None):
184                 """
185                 Import blocks and connections into this flow graph.
186                 Clear this flowgraph of all previous blocks and connections.
187                 Any blocks or connections in error will be ignored.
188                 @param n the nested data odict
189                 """
190                 #remove previous elements
191                 self._elements = list()
192                 #use blank data if none provided
193                 fg_n = n and n.find('flow_graph') or odict()
194                 blocks_n = fg_n.findall('block')
195                 connections_n = fg_n.findall('connection')
196                 #create option block
197                 self._options_block = self.get_parent().get_new_block(self, 'options')
198                 #build the blocks
199                 for block_n in blocks_n:
200                         key = block_n.find('key')
201                         if key == 'options': block = self._options_block
202                         else: block = self.get_new_block(key)
203                         #only load the block when the block key was valid
204                         if block: block.import_data(block_n)
205                         else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
206                 self.rewrite() #rewrite all blocks before connections are made (ex: nports)
207                 #build the connections
208                 for connection_n in connections_n:
209                         #try to make the connection
210                         try:
211                                 #get the block ids
212                                 source_block_id = connection_n.find('source_block_id')
213                                 sink_block_id = connection_n.find('sink_block_id')
214                                 #get the port keys
215                                 source_key = connection_n.find('source_key')
216                                 sink_key = connection_n.find('sink_key')
217                                 #verify the blocks
218                                 block_ids = map(lambda b: b.get_id(), self.get_blocks())
219                                 assert(source_block_id in block_ids)
220                                 assert(sink_block_id in block_ids)
221                                 #get the blocks
222                                 source_block = self.get_block(source_block_id)
223                                 sink_block = self.get_block(sink_block_id)
224                                 #verify the ports
225                                 assert(source_key in source_block.get_source_keys())
226                                 assert(sink_key in sink_block.get_sink_keys())
227                                 #get the ports
228                                 source = source_block.get_source(source_key)
229                                 sink = sink_block.get_sink(sink_key)
230                                 #build the connection
231                                 self.connect(source, sink)
232                         except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key))
233                 self.rewrite() #global rewrite