# Find File Gedit Plugin
# Copyright (c) 2010 James Pharaoh <james@phsys.co.uk>

from gettext import gettext as _

import gedit
import gtk
import gobject
import os

ui_str = """
	<ui>
		<menubar name="MenuBar">
			<menu name="FileMenu" action="File">
				<placeholder name="FileOps_2">
					<menuitem name="FindFilePy" action="FindFilePy"/>
				</placeholder>
			</menu>
		</menubar>
	</ui>
"""

max_entries = 1000

search_dir = "/home/james/projects"

class FindFileDialog (gtk.Dialog):

	def __init__ (self, window):
		gtk.Dialog.__init__ (self)

		self._window = window

		self.connect ("destroy", self.quit)
		self.connect ("delete-event", self.quit)

		self.set_title (_ ("Find file"))
		self.resize (600, 500)

		self._model = gtk.ListStore (str)

		self._scroll = gtk.ScrolledWindow ()
		self._scroll.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		self.vbox.pack_start (self._scroll, True)
		self._scroll.show ()

		self._tree = gtk.TreeView (self._model)
		cell = gtk.CellRendererText ()
		column = gtk.TreeViewColumn ("Filename")
		column.pack_start (cell, True)
		column.set_attributes (cell, text = 0)
		self._tree.append_column (column)
		self._tree.set_headers_visible (False)
		self._scroll.add (self._tree)
		self._tree.show ()

		self._entry = gtk.Entry ()
		self.vbox.pack_start (self._entry, False)
		self._entry.set_activates_default (True)
		self._entry.show ()
		self._entry.grab_focus ()
		self._entry.connect ("changed", self.changed)
		self._entry.connect ("key-press-event", self.pressed)

		self._cancel = gtk.Button ("Cancel")
		self._cancel.connect ("clicked", self.quit)
		self.action_area.pack_start (self._cancel)
		self._cancel.show ()

		self._ok = gtk.Button ("Ok")
		self._ok.connect ("clicked", self.ok)
		self._ok.set_flags (gtk.CAN_DEFAULT)
		#self._ok.grab_default ()
		self.action_area.pack_start (self._ok)
		self._ok.show ()
		self.set_default (self._ok)

		self.scan ()
		self.update ()

		sel = self._tree.get_selection ()
		sel.select_path (0)

	def scan (self):
		self._files = []
		os.path.walk (search_dir, self.scan_one, None)

	def scan_one (self, arg, dirname, names):
		for name in names:
			path = dirname + "/" + name
			if not os.path.isfile (path): continue
			self._files.append (path)

	def changed (self, entry):
		self.update ()
		sel = self._tree.get_selection ()
		sel.select_path (0)

	def pressed (self, entry, event):
		if event.keyval in [
			gtk.keysyms.Up,
			gtk.keysyms.Down,
			gtk.keysyms.Page_Up,
			gtk.keysyms.Page_Down,
			gtk.keysyms.Home,
			gtk.keysyms.End,
		]:
			sel = self._tree.get_selection ()
			(model, paths) = sel.get_selected_rows ()
			sel_index = paths [0] [0]

			first, last = self._tree.get_visible_range ()
			page_size = max (1, last [0] - first [0] - 1)

			if event.keyval == gtk.keysyms.Up: sel_index -= 1
			if event.keyval == gtk.keysyms.Down: sel_index += 1

			if event.keyval == gtk.keysyms.Page_Up: sel_index -= page_size
			if event.keyval == gtk.keysyms.Page_Down: sel_index += page_size

			if event.keyval == gtk.keysyms.Home: sel_index = 0
			if event.keyval == gtk.keysyms.End: sel_index = len (model) - 1

			if sel_index < 0: sel_index = 0
			if sel_index >= len (model): sel_index = len (model) - 1

			sel_index %= len (model)
			sel.select_path (sel_index)
			self._tree.scroll_to_cell (sel_index)

			return True

	def update (self):
		model = self._model.clear ()
		text = self._entry.get_text ()
		num = 0
		for file in self._files:
			dir_name, sep, file_name = file.rpartition ("/")
			if file_name.find (text) == -1:
				continue
			self._model.append ([ file [(len (search_dir) + 1):] ])
			num += 1
			if num == max_entries:
				break

	def quit (self, *args):
		self.hide ()
		self.destroy ()

	def ok (self, button):
		sel = self._tree.get_selection ()
		model, sel_iter = sel.get_selected ()
		uri = "file://" + search_dir + "/" + model.get_value (sel_iter, 0)
		self._window.create_tab_from_uri (uri, None, 0, False, True)

		self.hide ()
		self.destroy ()

class FindFileWindowHelper:

	def __init__ (self, plugin, window):
		self._window = window
		self._plugin = plugin
		self._insert_menu ()

	def deactivate (self):
		self._remove_menu ()
		self._window = None
		self._plugin = None

	def _insert_menu (self):
		manager = self._window.get_ui_manager ()
		self._action_group = gtk.ActionGroup ("FindFilePyPluginActions")
		self._action_group.add_actions ( [
			( "FindFilePy", None, _("Find..."), "<Control><Shift>R", _("Find a file by name"), self.on_find_file_activate )
		] )
		manager.insert_action_group (self._action_group, -1)
		self._ui_id = manager.add_ui_from_string (ui_str)

	def _remove_menu (self):
		manager = self._window.get_ui_manager ()
		manager.remove_ui (self._ui_id)
		manager.remove_action_group (self._action_group)
		manager.ensure_update ()

	def update_ui (self):
		pass

	def on_find_file_activate (self, action):
		dialog = FindFileDialog (self._window)
		dialog.run ()

class FindFilePyPlugin (gedit.Plugin):

	def __init__ (self):
		gedit.Plugin.__init__ (self)
		self._instances = {}

	def activate (self, window):
		self._instances [window] = FindFileWindowHelper (self, window)

	def deactivate (self, window):
		self._instances [window].deactivate ()
		del self._instances [window]

	def update_ui (self, window):
		self._instances [window].update_ui ()
