2 Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
3 This file is part of GNU Radio
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.
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.
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
20 from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH, DND_TARGETS
38 CAT_MARKUP_TMPL="""Category: $cat"""
40 class BlockTreeWindow(gtk.VBox):
41 """The block selection panel."""
43 def __init__(self, platform, get_flow_graph):
45 BlockTreeWindow constructor.
46 Create a tree view of the possible blocks in the platform.
47 The tree view nodes will be category names, the leaves will be block names.
48 A mouse double click or button press action will trigger the add block event.
49 @param platform the particular platform will all block prototypes
50 @param get_flow_graph get the selected flow graph
52 gtk.VBox.__init__(self)
53 self.platform = platform
54 self.get_flow_graph = get_flow_graph
55 #make the tree model for holding blocks
56 self.treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
57 self.treeview = gtk.TreeView(self.treestore)
58 self.treeview.set_enable_search(False) #disable pop up search box
59 self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
60 self.treeview.connect('button-press-event', self._handle_mouse_button_press)
61 selection = self.treeview.get_selection()
62 selection.set_mode('single')
63 selection.connect('changed', self._handle_selection_change)
64 renderer = gtk.CellRendererText()
65 column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX)
66 self.treeview.append_column(column)
67 #try to enable the tooltips (available in pygtk 2.12 and above)
68 try: self.treeview.set_tooltip_column(DOC_INDEX)
71 self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY)
72 self.treeview.connect('drag-data-get', self._handle_drag_get_data)
73 #make the scrolled window to hold the tree view
74 scrolled_window = gtk.ScrolledWindow()
75 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
76 scrolled_window.add_with_viewport(self.treeview)
77 scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
78 self.pack_start(scrolled_window)
80 self.add_button = gtk.Button(None, gtk.STOCK_ADD)
81 self.add_button.connect('clicked', self._handle_add_button)
82 self.pack_start(self.add_button, False)
83 #map categories to iters, automatic mapping for root
84 self._categories = {tuple(): None}
85 #add blocks and categories
86 self.platform.load_block_tree(self)
88 self._update_add_button()
90 ############################################################
92 ############################################################
93 def add_block(self, category, block=None):
95 Add a block with category to this selection window.
96 Add only the category when block is None.
97 @param category the category list or path string
98 @param block the block object or None
100 if isinstance(category, str): category = category.split('/')
101 category = tuple(filter(lambda x: x, category)) #tuple is hashable
102 #add category and all sub categories
103 for i, cat_name in enumerate(category):
104 sub_category = category[:i+1]
105 if sub_category not in self._categories:
106 iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None)
107 self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
108 self.treestore.set_value(iter, KEY_INDEX, '')
109 self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
110 self._categories[sub_category] = iter
112 if block is None: return
113 iter = self.treestore.insert_before(self._categories[category], None)
114 self.treestore.set_value(iter, NAME_INDEX, block.get_name())
115 self.treestore.set_value(iter, KEY_INDEX, block.get_key())
116 self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
118 ############################################################
120 ############################################################
121 def _get_selected_block_key(self):
123 Get the currently selected block key.
124 @return the key of the selected block or a empty string
126 selection = self.treeview.get_selection()
127 treestore, iter = selection.get_selected()
128 return iter and treestore.get_value(iter, KEY_INDEX) or ''
130 def _update_add_button(self):
132 Update the add button's sensitivity.
133 The button should be active only if a block is selected.
135 key = self._get_selected_block_key()
136 self.add_button.set_sensitive(bool(key))
138 def _add_selected_block(self):
140 Add the selected block with the given key to the flow graph.
142 key = self._get_selected_block_key()
143 if key: self.get_flow_graph().add_new_block(key)
145 ############################################################
147 ############################################################
148 def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time):
150 Handle a drag and drop by setting the key to the selection object.
151 This will call the destination handler for drag and drop.
152 Only call set when the key is valid to ignore DND from categories.
154 key = self._get_selected_block_key()
155 if key: selection_data.set(selection_data.target, 8, key)
157 def _handle_mouse_button_press(self, widget, event):
159 Handle the mouse button press.
160 If a left double click is detected, call add selected block.
162 if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
163 self._add_selected_block()
165 def _handle_selection_change(self, selection):
167 Handle a selection change in the tree view.
168 If a selection changes, set the add button sensitive.
170 self._update_add_button()
172 def _handle_add_button(self, widget):
174 Handle the add button clicked signal.
175 Call add selected block.
177 self._add_selected_block()