9543fdda27e4c1614dfb7e523c14e901d1b3ae30
[debian/gnuradio] / grc / src / grc / gui / BlockTreeWindow.py
1 """
2 Copyright 2007 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 ##@package grc.gui.BlockTreeWindow
20 #The block selection panel gives the user a tree selection to choose a block.
21
22 from grc.Constants import *
23 import pygtk
24 pygtk.require('2.0')
25 import gtk
26 import gobject
27
28 NAME_INDEX = 0
29 KEY_INDEX = 1
30
31 class BlockTreeWindow(gtk.VBox):
32         """The block selection panel."""
33
34         def __init__(self, platform, get_flow_graph):
35                 """!
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
42                 """
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)
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                 #make the scrolled window to hold the tree view
59                 scrolled_window = gtk.ScrolledWindow()
60                 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
61                 scrolled_window.add_with_viewport(self.treeview)
62                 scrolled_window.set_size_request(BLOCK_SELECTION_WINDOW_WIDTH, -1)
63                 self.pack_start(scrolled_window)
64                 #add button
65                 self.add_button = gtk.Button(None, 'gtk-add')
66                 self.add_button.connect('clicked', self._handle_add_button)
67                 self.pack_start(self.add_button, False)
68                 #map categories to iters
69                 self.categories = dict()
70                 self.categories[tuple()] = None
71                 #add blocks and categories
72                 self.platform.load_block_tree(self)
73                 #initialize
74                 self._update_add_button()
75
76         ############################################################
77         ## Block Tree Methods
78         ############################################################
79         def add_block(self, category, block=None):
80                 """!
81                 Add a block with category to this selection window.
82                 Add only the category when block is None.
83                 @param category the category string
84                 @param block the block object or None
85                 """
86                 #rectify category
87                 category = filter(lambda x: x, category.split('/'))
88                 #add category and all sub categories
89                 for i in range(len(category)):
90                         sub_category = tuple(category[:i+1])
91                         if sub_category not in self.categories.keys():
92                                 iter = self.treestore.insert_before(self.categories[tuple(category[:i])], None)
93                                 self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%category[i])
94                                 self.treestore.set_value(iter, KEY_INDEX, '')
95                                 self.categories[sub_category] = iter
96                 #add block
97                 if block is None: return
98                 iter = self.treestore.insert_before(self.categories[tuple(category)], None)
99                 self.treestore.set_value(iter, NAME_INDEX, block.get_name())
100                 self.treestore.set_value(iter, KEY_INDEX, block.get_key())
101
102         ############################################################
103         ## Helper Methods
104         ############################################################
105         def _get_selected_block_key(self):
106                 """!
107                 Get the currently selected block key.
108                 @return the key of the selected block or a empty string
109                 """
110                 selection = self.treeview.get_selection()
111                 treestore, iter = selection.get_selected()
112                 return iter and treestore.get_value(iter, KEY_INDEX) or ''
113
114         def _update_add_button(self):
115                 """!
116                 Update the add button's sensitivity.
117                 The button should be active only if a block is selected.
118                 """
119                 key = self._get_selected_block_key()
120                 self.add_button.set_sensitive(bool(key))
121
122         def _add_selected_block(self):
123                 """!
124                 Add the selected block with the given key to the flow graph.
125                 """
126                 key = self._get_selected_block_key()
127                 if key: self.get_flow_graph().add_new_block(key)
128
129         ############################################################
130         ## Event Handlers
131         ############################################################
132         def _handle_mouse_button_press(self, widget, event):
133                 """!
134                 Handle the mouse button press.
135                 If a left double click is detected, call add selected block.
136                 """
137                 if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
138                         self._add_selected_block()
139
140         def _handle_selection_change(self, selection):
141                 """!
142                 Handle a selection change in the tree view.
143                 If a selection changes, set the add button sensitive.
144                 """
145                 self._update_add_button()
146
147         def _handle_add_button(self, widget):
148                 """!
149                 Handle the add button clicked signal.
150                 Call add selected block.
151                 """
152                 self._add_selected_block()
153