"""
Copyright 2007 Free Software Foundation, Inc.
This file is part of GNU Radio

GNU Radio Companion is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

GNU Radio Companion is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
"""

from Constants import DEFAULT_BLOCKS_WINDOW_WIDTH
import pygtk
pygtk.require('2.0')
import gtk
import gobject

NAME_INDEX = 0
KEY_INDEX = 1

class BlockTreeWindow(gtk.VBox):
	"""The block selection panel."""

	def __init__(self, platform, get_flow_graph):
		"""
		BlockTreeWindow constructor.
		Create a tree view of the possible blocks in the platform.
		The tree view nodes will be category names, the leaves will be block names.
		A mouse double click or button press action will trigger the add block event.
		@param platform the particular platform will all block prototypes
		@param get_flow_graph get the selected flow graph
		"""
		gtk.VBox.__init__(self)
		self.platform = platform
		self.get_flow_graph = get_flow_graph
		#make the tree model for holding blocks
		self.treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
		self.treeview = gtk.TreeView(self.treestore)
		self.treeview.set_enable_search(False) #disable pop up search box
		self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
		self.treeview.connect('button_press_event', self._handle_mouse_button_press)
		selection = self.treeview.get_selection()
		selection.set_mode('single')
		selection.connect('changed', self._handle_selection_change)
		renderer = gtk.CellRendererText()
		column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX)
		self.treeview.append_column(column)
		#make the scrolled window to hold the tree view
		scrolled_window = gtk.ScrolledWindow()
		scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		scrolled_window.add_with_viewport(self.treeview)
		scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
		self.pack_start(scrolled_window)
		#add button
		self.add_button = gtk.Button(None, 'gtk-add')
		self.add_button.connect('clicked', self._handle_add_button)
		self.pack_start(self.add_button, False)
		#map categories to iters
		self.categories = dict()
		self.categories[tuple()] = None
		#add blocks and categories
		self.platform.load_block_tree(self)
		#initialize
		self._update_add_button()

	############################################################
	## Block Tree Methods
	############################################################
	def add_block(self, category, block=None):
		"""
		Add a block with category to this selection window.
		Add only the category when block is None.
		@param category the category string
		@param block the block object or None
		"""
		#rectify category
		category = filter(lambda x: x, category.split('/'))
		#add category and all sub categories
		for i in range(len(category)):
			sub_category = tuple(category[:i+1])
			if sub_category not in self.categories.keys():
				iter = self.treestore.insert_before(self.categories[tuple(category[:i])], None)
				self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%category[i])
				self.treestore.set_value(iter, KEY_INDEX, '')
				self.categories[sub_category] = iter
		#add block
		if block is None: return
		iter = self.treestore.insert_before(self.categories[tuple(category)], None)
		self.treestore.set_value(iter, NAME_INDEX, block.get_name())
		self.treestore.set_value(iter, KEY_INDEX, block.get_key())

	############################################################
	## Helper Methods
	############################################################
	def _get_selected_block_key(self):
		"""
		Get the currently selected block key.
		@return the key of the selected block or a empty string
		"""
		selection = self.treeview.get_selection()
		treestore, iter = selection.get_selected()
		return iter and treestore.get_value(iter, KEY_INDEX) or ''

	def _update_add_button(self):
		"""
		Update the add button's sensitivity.
		The button should be active only if a block is selected.
		"""
		key = self._get_selected_block_key()
		self.add_button.set_sensitive(bool(key))

	def _add_selected_block(self):
		"""
		Add the selected block with the given key to the flow graph.
		"""
		key = self._get_selected_block_key()
		if key: self.get_flow_graph().add_new_block(key)

	############################################################
	## Event Handlers
	############################################################
	def _handle_mouse_button_press(self, widget, event):
		"""
		Handle the mouse button press.
		If a left double click is detected, call add selected block.
		"""
		if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
			self._add_selected_block()

	def _handle_selection_change(self, selection):
		"""
		Handle a selection change in the tree view.
		If a selection changes, set the add button sensitive.
		"""
		self._update_add_button()

	def _handle_add_button(self, widget):
		"""
		Handle the add button clicked signal.
		Call add selected block.
		"""
		self._add_selected_block()