grc: expanded nports ability to have multiple port duplicators per side
[debian/gnuradio] / grc / python / Block.py
index a9e999491e7a1a34fb9ab2a2e1bcaa124f2c19b9..bd03eb5cdbfc7d078578a59fd8690be23e0fd4b4 100644 (file)
@@ -18,9 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 from .. base.Block import Block as _Block
+from .. gui.Block import Block as _GUIBlock
 import extract_docs
+import extract_category
 
-class Block(_Block):
+class Block(_Block, _GUIBlock):
+
+       def is_virtual_sink(self): return self.get_key() == 'virtual_sink'
+       def is_virtual_source(self): return self.get_key() == 'virtual_source'
 
        ##for make source to keep track of indexes
        _source_count = 0
@@ -47,13 +52,13 @@ class Block(_Block):
                        flow_graph=flow_graph,
                        n=n,
                )
+               _GUIBlock.__init__(self)
 
        def validate(self):
                """
                Validate this block.
                Call the base class validate.
                Evaluate the checks: each check must evaluate to True.
-               Adjust the nports.
                """
                _Block.validate(self)
                #evaluate the checks
@@ -64,40 +69,54 @@ class Block(_Block):
                                try: assert check_eval
                                except AssertionError: self.add_error_message('Check "%s" failed.'%check)
                        except: self.add_error_message('Check "%s" did not evaluate.'%check)
+
+       def rewrite(self):
+               """
+               Add and remove ports to adjust for the nports.
+               """
+               _Block.rewrite(self)
+
+               def insert_port(get_ports, get_port, key):
+                       prev_port = get_port(str(int(key)-1))
+                       get_ports().insert(
+                               get_ports().index(prev_port)+1,
+                               prev_port.copy(new_key=key),
+                       )
+                       #restore integer contiguity after insertion
+                       for i, port in enumerate(get_ports()): port._key = str(i)
+
+               def remove_port(get_ports, get_port, key):
+                       port = get_port(key)
+                       for connection in port.get_connections():
+                               self.get_parent().remove_element(connection)
+                       get_ports().remove(port)
+                       #restore integer contiguity after insertion
+                       for i, port in enumerate(get_ports()): port._key = str(i)
+
                #adjust nports
-               for ports, Port in (
-                       (self._sources, self.get_parent().get_parent().Source),
-                       (self._sinks, self.get_parent().get_parent().Sink),
+               for get_ports, get_port in (
+                       (self.get_sources, self.get_source),
+                       (self.get_sinks, self.get_sink),
                ):
-                       #how many ports?
-                       num_ports = len(ports)
-                       #do nothing for 0 ports
-                       if not num_ports: continue
-                       #get the nports setting
-                       port0 = ports[str(0)]
-                       nports = port0.get_nports()
-                       #do nothing for no nports
-                       if not nports: continue
-                       #do nothing if nports is already num ports
-                       if nports == num_ports: continue
-                       #remove excess ports and connections
-                       if nports < num_ports:
-                               #remove the connections
-                               for key in map(str, range(nports, num_ports)):
-                                       port = ports[key]
-                                       for connection in port.get_connections():
-                                               self.get_parent().remove_element(connection)
-                               #remove the ports
-                               for key in map(str, range(nports, num_ports)): ports.pop(key)
-                               continue
-                       #add more ports
-                       if nports > num_ports:
-                               for key in map(str, range(num_ports, nports)):
-                                       n = port0._n
-                                       n['key'] = key
-                                       port = Port(self, n)
-                                       ports[key] = port
-                               continue
+                       master_ports = filter(lambda p: p.get_nports(), get_ports())
+                       for i, master_port in enumerate(master_ports):
+                               nports = master_port.get_nports()
+                               index_first = get_ports().index(master_port)
+                               try: index_last = get_ports().index(master_ports[i+1])
+                               except IndexError: index_last = len(get_ports())
+                               num_ports = index_last - index_first
+                               #do nothing if nports is already num ports
+                               if nports == num_ports: continue
+                               #remove excess ports and connections
+                               if nports < num_ports:
+                                       for key in map(str, range(index_first+nports, index_first+num_ports)):
+                                               remove_port(get_ports, get_port, key)
+                                       continue
+                               #add more ports
+                               if nports > num_ports:
+                                       for key in map(str, range(index_first+num_ports, index_first+nports)):
+                                               insert_port(get_ports, get_port, key)
+                                       continue
 
        def port_controller_modify(self, direction):
                """
@@ -106,10 +125,8 @@ class Block(_Block):
                @return true for change
                """
                changed = False
-               #concat the nports string from the private nports settings of both port0
-               nports_str = \
-                       (self.get_sinks() and self.get_sinks()[0]._nports or '') + \
-                       (self.get_sources() and self.get_sources()[0]._nports or '')
+               #concat the nports string from the private nports settings of all ports
+               nports_str = ' '.join([port._nports for port in self.get_ports()])
                #modify all params whose keys appear in the nports string
                for param in self.get_params():
                        if param.is_enum() or param.get_key() not in nports_str: continue
@@ -128,6 +145,11 @@ class Block(_Block):
                #merge custom doc with doxygen docs
                return '\n'.join([doc, extract_docs.extract(self.get_key())]).strip('\n')
 
+       def get_category(self):
+               category = extract_category.extract(self.get_key())
+               #if category: return category
+               return _Block.get_category(self)
+
        def get_imports(self):
                """
                Resolve all import statements.
@@ -148,6 +170,6 @@ class Block(_Block):
                """
                def make_callback(callback):
                        callback = self.resolve_dependencies(callback)
-                       if callback.startswith('self.'): return callback
+                       if 'self.' in callback: return callback
                        return 'self.%s.%s'%(self.get_id(), callback)
                return map(make_callback, self._callbacks)