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
31 class BlockTreeWindow(gtk.VBox):
32 """The block selection panel."""
34 def __init__(self, platform, get_flow_graph):
36 BlockTreeWindow constructor.
37 Create a tree view of the possible blocks in the platform.
38 The tree view nodes will be category names, the leaves will be block names.
39 A mouse double click or button press action will trigger the add block event.
40 @param platform the particular platform will all block prototypes
41 @param get_flow_graph get the selected flow graph
43 gtk.VBox.__init__(self)
44 self.platform = platform
45 self.get_flow_graph = get_flow_graph
46 #make the tree model for holding blocks
47 self.treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
48 self.treeview = gtk.TreeView(self.treestore)
49 self.treeview.set_enable_search(False) #disable pop up search box
50 self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
51 self.treeview.connect('button_press_event', self._handle_mouse_button_press)
52 selection = self.treeview.get_selection()
53 selection.set_mode('single')
54 selection.connect('changed', self._handle_selection_change)
55 renderer = gtk.CellRendererText()
56 column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX)
57 self.treeview.append_column(column)
58 #try to enable the tooltips (available in pygtk 2.12 and above)
59 try: self.treeview.set_tooltip_column(DOC_INDEX)
62 self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY)
63 self.treeview.connect('drag-data-get', self._handle_drag_get_data)
64 #make the scrolled window to hold the tree view
65 scrolled_window = gtk.ScrolledWindow()
66 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
67 scrolled_window.add_with_viewport(self.treeview)
68 scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
69 self.pack_start(scrolled_window)
71 self.add_button = gtk.Button(None, gtk.STOCK_ADD)
72 self.add_button.connect('clicked', self._handle_add_button)
73 self.pack_start(self.add_button, False)
74 #map categories to iters, automatic mapping for root
75 self._categories = {tuple(): None}
76 #add blocks and categories
77 self.platform.load_block_tree(self)
79 self._update_add_button()
81 ############################################################
83 ############################################################
84 def add_block(self, category, block=None):
86 Add a block with category to this selection window.
87 Add only the category when block is None.
88 @param category the category list or path string
89 @param block the block object or None
91 if isinstance(category, str): category = category.split('/')
92 category = tuple(filter(lambda x: x, category)) #tuple is hashable
93 #add category and all sub categories
94 for i, cat_name in enumerate(category):
95 sub_category = category[:i+1]
96 if sub_category not in self._categories:
97 iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None)
98 self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
99 self.treestore.set_value(iter, KEY_INDEX, '')
100 self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode('Category: %s'%cat_name))
101 self._categories[sub_category] = iter
103 if block is None: return
104 iter = self.treestore.insert_before(self._categories[category], None)
105 self.treestore.set_value(iter, NAME_INDEX, block.get_name())
106 self.treestore.set_value(iter, KEY_INDEX, block.get_key())
107 self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode(block.get_doc() or 'undocumented'))
109 ############################################################
111 ############################################################
112 def _get_selected_block_key(self):
114 Get the currently selected block key.
115 @return the key of the selected block or a empty string
117 selection = self.treeview.get_selection()
118 treestore, iter = selection.get_selected()
119 return iter and treestore.get_value(iter, KEY_INDEX) or ''
121 def _update_add_button(self):
123 Update the add button's sensitivity.
124 The button should be active only if a block is selected.
126 key = self._get_selected_block_key()
127 self.add_button.set_sensitive(bool(key))
129 def _add_selected_block(self):
131 Add the selected block with the given key to the flow graph.
133 key = self._get_selected_block_key()
134 if key: self.get_flow_graph().add_new_block(key)
136 ############################################################
138 ############################################################
139 def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time):
141 Handle a drag and drop by setting the key to the selection object.
142 This will call the destination handler for drag and drop.
143 Only call set when the key is valid to ignore DND from categories.
145 key = self._get_selected_block_key()
146 if key: selection_data.set(selection_data.target, 8, key)
148 def _handle_mouse_button_press(self, widget, event):
150 Handle the mouse button press.
151 If a left double click is detected, call add selected block.
153 if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
154 self._add_selected_block()
156 def _handle_selection_change(self, selection):
158 Handle a selection change in the tree view.
159 If a selection changes, set the add button sensitive.
161 self._update_add_button()
163 def _handle_add_button(self, widget):
165 Handle the add button clicked signal.
166 Call add selected block.
168 self._add_selected_block()