summaryrefslogtreecommitdiff
path: root/grc
diff options
context:
space:
mode:
Diffstat (limited to 'grc')
-rw-r--r--grc/base/Block.py1
-rw-r--r--grc/base/Platform.py4
-rw-r--r--grc/blocks/gr_sub_xx.xml2
-rw-r--r--grc/blocks/pad_sink.xml20
-rw-r--r--grc/blocks/pad_source.xml20
-rw-r--r--grc/gui/ActionHandler.py142
-rw-r--r--grc/gui/Actions.py16
-rw-r--r--grc/gui/Bars.py3
-rw-r--r--grc/gui/BlockTreeWindow.py5
-rw-r--r--grc/gui/FlowGraph.py4
-rw-r--r--grc/gui/MainWindow.py5
-rw-r--r--grc/python/FlowGraph.py1
-rw-r--r--grc/python/block.dtd3
-rw-r--r--grc/python/convert_hier.py3
14 files changed, 226 insertions, 3 deletions
diff --git a/grc/base/Block.py b/grc/base/Block.py
index fe7ad3c2f..a20be9db9 100644
--- a/grc/base/Block.py
+++ b/grc/base/Block.py
@@ -67,6 +67,7 @@ class Block(Element):
self._name = n.find('name')
self._key = n.find('key')
self._category = n.find('category') or ''
+ self._grc_source = n.find('grc_source') or ''
self._block_wrapper_path = n.find('block_wrapper_path')
#create the param objects
self._params = list()
diff --git a/grc/base/Platform.py b/grc/base/Platform.py
index 94d0077ea..d4b09088b 100644
--- a/grc/base/Platform.py
+++ b/grc/base/Platform.py
@@ -61,6 +61,10 @@ class Platform(_Element):
#create a dummy flow graph for the blocks
self._flow_graph = _Element(self)
#search for *.xml files in the given search path
+
+ self.loadblocks();
+
+ def loadblocks(self):
xml_files = list()
for block_path in self._block_paths:
if os.path.isfile(block_path): xml_files.append(block_path)
diff --git a/grc/blocks/gr_sub_xx.xml b/grc/blocks/gr_sub_xx.xml
index f1f4797e0..c677747da 100644
--- a/grc/blocks/gr_sub_xx.xml
+++ b/grc/blocks/gr_sub_xx.xml
@@ -48,7 +48,7 @@
<type>int</type>
</param>
<check>$vlen &gt; 0</check>
- <check>$num_inputs &gt;= 2</check>
+ <check>$num_inputs &gt;= 1</check>
<sink>
<name>in</name>
<type>$type</type>
diff --git a/grc/blocks/pad_sink.xml b/grc/blocks/pad_sink.xml
index 2e9495260..f89eaa53c 100644
--- a/grc/blocks/pad_sink.xml
+++ b/grc/blocks/pad_sink.xml
@@ -43,6 +43,11 @@
<key>byte</key>
<opt>size:gr.sizeof_char</opt>
</option>
+ <option>
+ <name>Wildcard</name>
+ <key></key>
+ <opt>size:0</opt>
+ </option>
</param>
<param>
<name>Vec Length</name>
@@ -50,6 +55,21 @@
<value>1</value>
<type>int</type>
</param>
+ <param>
+ <name>Optional</name>
+ <key>optional</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>part</hide>
+ <option>
+ <name>Optional</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Required</name>
+ <key>False</key>
+ </option>
+ </param>
<check>$vlen &gt; 0</check>
<sink>
<name>in</name>
diff --git a/grc/blocks/pad_source.xml b/grc/blocks/pad_source.xml
index 7b2210cbb..cbf38eb39 100644
--- a/grc/blocks/pad_source.xml
+++ b/grc/blocks/pad_source.xml
@@ -43,6 +43,11 @@
<key>byte</key>
<opt>size:gr.sizeof_char</opt>
</option>
+ <option>
+ <name>Wildcard</name>
+ <key></key>
+ <opt>size:0</opt>
+ </option>
</param>
<param>
<name>Vec Length</name>
@@ -50,6 +55,21 @@
<value>1</value>
<type>int</type>
</param>
+ <param>
+ <name>Optional</name>
+ <key>optional</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>part</hide>
+ <option>
+ <name>Optional</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>Required</name>
+ <key>False</key>
+ </option>
+ </param>
<check>$vlen &gt; 0</check>
<source>
<name>out</name>
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 476c82b4f..9fb5e4ebf 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -53,6 +53,7 @@ class ActionHandler:
self.clipboard = None
for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
#setup the main window
+ self.platform = platform;
self.main_window = MainWindow(platform)
self.main_window.connect('delete-event', self._quit)
self.main_window.connect('key-press-event', self._handle_key_press)
@@ -152,6 +153,134 @@ class ActionHandler:
self.get_flow_graph().update()
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
+ ##################################################
+ # Create heir block
+ ##################################################
+ elif action == Actions.BLOCK_CREATE_HIER:
+
+ # keeping track of coordinates for pasting later
+ coords = self.get_flow_graph().get_selected_blocks()[0].get_coordinate()
+ x,y = coords
+ x_min = x
+ y_min = y
+
+ pads = [];
+ params = [];
+
+ # Save the state of the leaf blocks
+ for block in self.get_flow_graph().get_selected_blocks():
+
+ # Check for string variables within the blocks
+ for param in block.get_params():
+ for variable in self.get_flow_graph().get_variables():
+ # If a block parameter exists that is a variable, create a parameter for it
+ if param.get_value() == variable.get_id():
+ params.append(param.get_value())
+ for flow_param in self.get_flow_graph().get_parameters():
+ # If a block parameter exists that is a parameter, create a parameter for it
+ if param.get_value() == flow_param.get_id():
+ params.append(param.get_value())
+
+
+ # keep track of x,y mins for pasting later
+ (x,y) = block.get_coordinate()
+ if x < x_min:
+ x_min = x
+ if y < y_min:
+ y_min = y
+
+ for connection in block.get_connections():
+
+ # Get id of connected blocks
+ source_id = connection.get_source().get_parent().get_id()
+ sink_id = connection.get_sink().get_parent().get_id()
+
+ # If connected block is not in the list of selected blocks create a pad for it
+ if self.get_flow_graph().get_block(source_id) not in self.get_flow_graph().get_selected_blocks():
+ pads.append({'key': connection.get_sink().get_key(), 'coord': connection.get_source().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'source'})
+
+ if self.get_flow_graph().get_block(sink_id) not in self.get_flow_graph().get_selected_blocks():
+ pads.append({'key': connection.get_source().get_key(), 'coord': connection.get_sink().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'sink'})
+
+
+ # Copy the selected blocks and paste them into a new page
+ # then move the flowgraph to a reasonable position
+ Actions.BLOCK_COPY()
+ self.main_window.new_page()
+ Actions.BLOCK_PASTE()
+ coords = (x_min,y_min)
+ self.get_flow_graph().move_selected(coords)
+
+
+ # Set flow graph to heir block type
+ top_block = self.get_flow_graph().get_block("top_block")
+ top_block.get_param('generate_options').set_value('hb')
+
+ # this needs to be a unique name
+ top_block.get_param('id').set_value('new_heir')
+
+ # Remove the default samp_rate variable block that is created
+ remove_me = self.get_flow_graph().get_block("samp_rate")
+ self.get_flow_graph().remove_element(remove_me)
+
+
+ # Add the param blocks along the top of the window
+ x_pos = 150
+ for param in params:
+ param_id = self.get_flow_graph().add_new_block('parameter',(x_pos,10))
+ param_block = self.get_flow_graph().get_block(param_id)
+ param_block.get_param('id').set_value(param)
+ x_pos = x_pos + 100
+
+ for pad in pads:
+ # Add the pad sources and sinks within the new heir block
+ if pad['direction'] == 'sink':
+
+ # Add new PAD_SINK block to the canvas
+ pad_id = self.get_flow_graph().add_new_block('pad_sink', pad['coord'])
+
+ # setup the references to the sink and source
+ pad_block = self.get_flow_graph().get_block(pad_id)
+ pad_sink = pad_block.get_sinks()[0]
+
+ source_block = self.get_flow_graph().get_block(pad['block_id'])
+ source = source_block.get_source(pad['key'])
+
+ # Ensure the port types match
+ while pad_sink.get_type() != source.get_type():
+
+ # Special case for some blocks that have non-standard type names, e.g. uhd
+ if pad_sink.get_type() == 'complex' and source.get_type() == 'fc32':
+ break;
+ pad_block.type_controller_modify(1)
+
+ # Connect the pad to the proper sinks
+ new_connection = self.get_flow_graph().connect(source,pad_sink)
+
+ elif pad['direction'] == 'source':
+ pad_id = self.get_flow_graph().add_new_block('pad_source', pad['coord'])
+
+ # setup the references to the sink and source
+ pad_block = self.get_flow_graph().get_block(pad_id)
+ pad_source = pad_block.get_sources()[0]
+
+ sink_block = self.get_flow_graph().get_block(pad['block_id'])
+ sink = sink_block.get_sink(pad['key'])
+
+ # Ensure the port types match
+ while sink.get_type() != pad_source.get_type():
+ # Special case for some blocks that have non-standard type names, e.g. uhd
+ if pad_source.get_type() == 'complex' and sink.get_type() == 'fc32':
+ break;
+ pad_block.type_controller_modify(1)
+
+ # Connect the pad to the proper sinks
+ new_connection = self.get_flow_graph().connect(pad_source,sink)
+
+ # update the new heir block flow graph
+ self.get_flow_graph().update()
+
+
##################################################
# Move/Rotate/Delete/Create
##################################################
@@ -263,6 +392,7 @@ class ActionHandler:
else:
try:
ParseXML.to_file(self.get_flow_graph().export_data(), self.get_page().get_file_path())
+ self.get_flow_graph().grc_file_path = self.get_page().get_file_path()
self.get_page().set_saved(True)
except IOError:
Messages.send_fail_save(self.get_page().get_file_path())
@@ -302,6 +432,15 @@ class ActionHandler:
except: print "could not kill process: %d"%self.get_page().get_proc().pid
elif action == Actions.PAGE_CHANGE: #pass and run the global actions
pass
+ elif action == Actions.RELOAD_BLOCKS:
+ self.platform.loadblocks()
+ self.main_window.btwin.clear();
+ self.platform.load_block_tree(self.main_window.btwin);
+ elif action == Actions.OPEN_HIER:
+ bn = [];
+ for b in self.get_flow_graph().get_selected_blocks():
+ if b._grc_source:
+ self.main_window.new_page(b._grc_source, show=True);
else: print '!!! Action "%s" not handled !!!'%action
##################################################
# Global Actions for all States
@@ -319,6 +458,9 @@ class ActionHandler:
#update enable/disable
Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.BLOCK_CREATE_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.OPEN_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.RELOAD_BLOCKS.set_sensitive(True)
#set the exec and stop buttons
self.update_exec_stop()
#saved status
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 4d196477e..8087f4955 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -198,6 +198,12 @@ BLOCK_DISABLE = Action(
stock_id=gtk.STOCK_DISCONNECT,
keypresses=(gtk.keysyms.d, NO_MODS_MASK),
)
+BLOCK_CREATE_HIER = Action(
+ label='C_reate Hier',
+ tooltip='Create hier block from selected blocks',
+ stock_id=gtk.STOCK_CONNECT,
+ keypresses=(gtk.keysyms.c, NO_MODS_MASK),
+)
BLOCK_CUT = Action(
label='Cu_t',
tooltip='Cut',
@@ -273,3 +279,13 @@ BLOCK_INC_TYPE = Action(
BLOCK_DEC_TYPE = Action(
keypresses=(gtk.keysyms.Up, NO_MODS_MASK),
)
+RELOAD_BLOCKS = Action(
+ label='Reload _Blocks',
+ tooltip='Reload Blocks',
+ stock_id=gtk.STOCK_REFRESH
+)
+OPEN_HIER = Action(
+ label='Open H_ier',
+ tooltip='Open the source of the selected hierarchical block',
+ stock_id=gtk.STOCK_JUMP_TO,
+)
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index 8fd167869..d95d23f1f 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -49,6 +49,9 @@ TOOLBAR_LIST = (
None,
Actions.BLOCK_ENABLE,
Actions.BLOCK_DISABLE,
+ None,
+ Actions.RELOAD_BLOCKS,
+ Actions.OPEN_HIER,
)
##The list of actions and categories for the menu bar.
diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py
index 0175c8bec..62afb6205 100644
--- a/grc/gui/BlockTreeWindow.py
+++ b/grc/gui/BlockTreeWindow.py
@@ -90,6 +90,11 @@ class BlockTreeWindow(gtk.VBox):
#initialize
self._update_add_button()
+ def clear(self):
+ self.treestore.clear();
+ self._categories = {tuple(): None}
+
+
############################################################
## Block Tree Methods
############################################################
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 9f3326ada..67e5af97b 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -63,6 +63,8 @@ class FlowGraph(Element):
Actions.BLOCK_ENABLE,
Actions.BLOCK_DISABLE,
Actions.BLOCK_PARAM_MODIFY,
+ Actions.BLOCK_CREATE_HIER,
+ Actions.OPEN_HIER,
]: self._context_menu.append(action.create_menu_item())
###########################################################################
@@ -97,6 +99,8 @@ class FlowGraph(Element):
block.get_param('id').set_value(id)
Actions.ELEMENT_CREATE()
+ return id
+
###########################################################################
# Copy Paste
###########################################################################
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index 2f761df1f..37a100c94 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -93,7 +93,8 @@ class MainWindow(gtk.Window):
#flow_graph_box.pack_start(self.scrolled_window)
self.flow_graph_vpaned.pack1(self.notebook)
self.hpaned.pack1(self.flow_graph_vpaned)
- self.hpaned.pack2(BlockTreeWindow(platform, self.get_flow_graph), False) #dont allow resize
+ self.btwin = BlockTreeWindow(platform, self.get_flow_graph);
+ self.hpaned.pack2(self.btwin, False) #dont allow resize
#create the reports window
self.text_display = TextDisplay()
#house the reports in a scrolled window
@@ -169,6 +170,8 @@ class MainWindow(gtk.Window):
try: #try to load from file
if file_path: Messages.send_start_load(file_path)
flow_graph = self._platform.get_new_flow_graph()
+ flow_graph.grc_file_path = file_path;
+ #print flow_graph
page = NotebookPage(
self,
flow_graph=flow_graph,
diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py
index 89a169355..efe362760 100644
--- a/grc/python/FlowGraph.py
+++ b/grc/python/FlowGraph.py
@@ -64,6 +64,7 @@ class FlowGraph(_FlowGraph, _GUIFlowGraph):
'type': str(pad.get_param('type').get_evaluated()),
'vlen': str(pad.get_param('vlen').get_evaluated()),
'size': pad.get_param('type').get_opt('size'),
+ 'optional': bool(pad.get_param('optional').get_evaluated()),
} for pad in sorted_pads]
def get_pad_sources(self):
diff --git a/grc/python/block.dtd b/grc/python/block.dtd
index 41a744d07..292ea06cb 100644
--- a/grc/python/block.dtd
+++ b/grc/python/block.dtd
@@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Top level element.
A block contains a name, ...parameters list, and list of IO ports.
-->
-<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param*, check*, sink*, source*, doc?)>
+<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param*, check*, sink*, source*, doc?, grc_source?)>
<!--
Sub level elements.
-->
@@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
<!ELEMENT category (#PCDATA)>
<!ELEMENT import (#PCDATA)>
<!ELEMENT doc (#PCDATA)>
+<!ELEMENT grc_source (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT key (#PCDATA)>
<!ELEMENT check (#PCDATA)>
diff --git a/grc/python/convert_hier.py b/grc/python/convert_hier.py
index c6ca5b769..b609af24a 100644
--- a/grc/python/convert_hier.py
+++ b/grc/python/convert_hier.py
@@ -62,6 +62,7 @@ def convert_hier(flow_graph, python_file):
sink_n['name'] = input_sig['label']
sink_n['type'] = input_sig['type']
sink_n['vlen'] = input_sig['vlen']
+ if input_sig['optional']: sink_n['optional'] = '1'
block_n['sink'].append(sink_n)
#source data
block_n['source'] = list()
@@ -70,9 +71,11 @@ def convert_hier(flow_graph, python_file):
source_n['name'] = output_sig['label']
source_n['type'] = output_sig['type']
source_n['vlen'] = output_sig['vlen']
+ if output_sig['optional']: source_n['optional'] = '1'
block_n['source'].append(source_n)
#doc data
block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file)
+ block_n['grc_source'] = "%s"%(flow_graph.grc_file_path)
#write the block_n to file
xml_file = python_file + '.xml'
ParseXML.to_file({'block': block_n}, xml_file)