context: // created on 6/15/2005 at 1:29 PM
  /*
   *   Copyright (c) 2005, Alexandros Frantzis (alf82 [at] freemail [dot] gr)
   *
   *   This file is part of Bless.
   *
   *   Bless 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.
   *
   *   Bless 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 Bless; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  using System;
  using Gtk;
  using Bless.Tools.Find;
  using Bless.Util;
  using Bless.Gui;
  using Bless.Gui.Areas;
  using Bless.Buffers;
  using Bless.Gui.Dialogs;
  using System.Text;
  using Bless.Plugins;
  using Mono.Unix;
  
  namespace Bless.Gui.Plugins {
  
  public class FindReplacePlugin : GuiPlugin
  {
  	DataBook dataBook;
  	FindReplaceWidget widget;
  
  	Gtk.Action FindAction;
  	Gtk.Action FindNextAction;
  	Gtk.Action FindPreviousAction;
  	Gtk.Action ReplaceAction;
  
  	IFinder finder;
  	Window mainWindow;
  	UIManager uiManager;
  
  	const string uiXml =
  		"<menubar>" +
  		"	<menu action=\"Search\">" +
  		"		<menuitem name=\"Find\" action=\"FindAction\" />" +
  		"		<menuitem name=\"FindNext\" action=\"FindNextAction\" />" +
  		"		<menuitem name=\"FindPrevious\" action=\"FindPreviousAction\" />" +
  		"		<menuitem name=\"Replace\" action=\"ReplaceAction\" />" +
  		"		<separator/>" +
  		"	</menu>" +
  		"</menubar>" +
  		"<toolbar>" +
  		"	<placeholder name=\"SearchItems\">" +
  		"		<toolitem name=\"Find\" action=\"FindAction\" />" +
  		"		<toolitem name=\"Replace\" action=\"ReplaceAction\" />" +
  		"	</placeholder>" +
  		"</toolbar>";
  
  	public FindReplacePlugin(Window mw, UIManager uim)
  	{
  		mainWindow = mw;
  		uiManager = uim;
  
  		name = "FindReplace";
  		author = "Alexandros Frantzis";
  		description = "Adds a firefox like find/replace bar";
  	}
  
  	public override bool Load()
  	{
  		dataBook = (DataBook)GetDataBook(mainWindow);
  
  		// create the finder object
  		ProgressDialog findProgressDialog = new ProgressDialog("", mainWindow);
  		finder = new DataBookFinder(dataBook, findProgressDialog.Update);
  		finder.Strategy = new BMFindStrategy();
  		finder.FirstFind += OnFirstFind;
  
  		// create the FindReplaceWidget (hidden)
  		widget = new FindReplaceWidget(dataBook, finder);
  		widget.Visible = false;
  
  		WidgetGroup wgroup = (WidgetGroup)GetWidgetGroup(mainWindow, 0);
  		wgroup.Add(widget);
  
  		// add the menu items
  		AddActions(uiManager);
  
  		dataBook.PageAdded += new DataView.DataViewEventHandler(OnDataViewAdded);
  		dataBook.PageRemoved += new DataView.DataViewEventHandler(OnDataViewRemoved);
  		dataBook.SwitchPage += new SwitchPageHandler(OnSwitchPage);
  
  		loaded = true;
  		return true;
  	}
  
  	void OnDataViewAdded(DataView dv)
  	{
  		dv.Buffer.Changed += new ByteBuffer.ChangedHandler(OnBufferContentsChanged);
  		dv.BufferChanged += new DataView.DataViewEventHandler(OnBufferChanged);
  	}
  
  	void OnDataViewRemoved(DataView dv)
  	{
  		dv.Buffer.Changed -= new ByteBuffer.ChangedHandler(OnBufferContentsChanged);
  		dv.BufferChanged -= new DataView.DataViewEventHandler(OnBufferChanged);
  		// if there are no pages left update the menu
  		if (dataBook.NPages == 0)
  			UpdateActions(null);
  	}
  
  	void OnBufferChanged(DataView dv)
  	{
  		UpdateActions(dv);
  	}
  
  	void OnBufferContentsChanged(ByteBuffer bb)
  	{
  		Gtk.Application.Invoke(delegate {
  			DataView dv = null;
  
  			// find DataView that owns bb
  			foreach (DataViewDisplay dvtemp in dataBook.Children) {
  				if (dvtemp.View.Buffer == bb) {
  					dv = dvtemp.View;
  					break;
  				}
  			}
  
  			UpdateActions(dv);
  		});
  	}
  
  	void OnSwitchPage(object o, SwitchPageArgs args)
  	{
  		DataView dv = ((DataViewDisplay)dataBook.GetNthPage((int)args.PageNum)).View;
  
  		UpdateActions(dv);
  	}
  	private void AddActions(UIManager uim)
  	{
  		ActionEntry[] actionEntries = new ActionEntry[] {
  										  new ActionEntry ("FindAction", Stock.Find, null, "<control>F", "Find",
  														   new EventHandler(OnFindActivated)),
  										  new ActionEntry ("FindNextAction", null, Catalog.GetString("Find _Next"), "F3", null,
  														   new EventHandler(OnFindNextActivated)),
  										  new ActionEntry ("FindPreviousAction", null, Catalog.GetString("Find _Previous"), "<shift>F3", null,
  														   new EventHandler(OnFindPreviousActivated)),
  										  new ActionEntry ("ReplaceAction", Stock.FindAndReplace, null, "<control>R", "Replace",
  														   new EventHandler(OnReplaceActivated))
  									  };
  
  		ActionGroup group = new ActionGroup ("SearchActions");
  		group.Add (actionEntries);
  
  		uim.InsertActionGroup(group, 0);
  		uim.AddUiFromString(uiXml);
  
  		FindAction = (Gtk.Action)uim.GetAction("/menubar/Search/Find");
  		FindNextAction = (Gtk.Action)uim.GetAction("/menubar/Search/FindNext");
  		FindPreviousAction = (Gtk.Action)uim.GetAction("/menubar/Search/FindPrevious");
  		ReplaceAction = (Gtk.Action)uim.GetAction("/menubar/Search/Replace");
  
  		uim.EnsureUpdate();
  
  	}
  
  	private void OnFindActivated(object o, EventArgs args)
  	{
  		// get pattern from current selection...
  		if (dataBook.NPages > 0) {
  			DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View;
  			widget.LoadWithSelection(dv);
  		}
  
  		widget.SearchVisible = true;
  		widget.ReplaceVisible = false;
  
  		widget.Show();
  	}
  
  	private void OnReplaceActivated(object o, EventArgs args)
  	{
  		// get pattern from current selection...
  		if (dataBook.NPages > 0) {
  			DataView dv = ((DataViewDisplay)dataBook.CurrentPageWidget).View;
  			widget.LoadWithSelection(dv);
  		}
  
  		widget.SearchVisible = true;
  		widget.ReplaceVisible = true;
  
  		widget.Show();
  	}
  
  	///<summary>Handle the Search->Find Next command</summary>
  	public void OnFindNextActivated(object o, EventArgs args)
  	{
  		finder.FindNext(FindNextAsyncCallback);
  	}
  
  	void FindNextAsyncCallback(IAsyncResult ar)
  	{
  		ThreadedAsyncResult tar = (ThreadedAsyncResult) ar;
  
  		FindNextOperation state = (FindNextOperation)tar.AsyncState;
  		if (state.Result == FindNextOperation.OperationResult.Finished && state.Match == null) {
  			InformationAlert ia = new InformationAlert(Catalog.GetString("The pattern you requested was not found."), Catalog.GetString("End of file reached."), mainWindow);
  			ia.Run();
  			ia.Destroy();
  		}
  	}
  
  	///<summary>Handle the Search->Find Previous command</summary>
  	public void OnFindPreviousActivated(object o, EventArgs args)
  	{
  		finder.FindPrevious(FindPreviousAsyncCallback);
  	}
  
  	void FindPreviousAsyncCallback(IAsyncResult ar)
  	{
  		ThreadedAsyncResult tar = (ThreadedAsyncResult) ar;
  
  		FindPreviousOperation state = (FindPreviousOperation)tar.AsyncState;
  		if (state.Result == FindPreviousOperation.OperationResult.Finished && state.Match == null) {
  			InformationAlert ia = new InformationAlert(Catalog.GetString("The pattern you requested was not found."), Catalog.GetString("Beginning of file reached."), mainWindow);
  			ia.Run();
  			ia.Destroy();
  		}
  	}
  
  	//
  	// called the first time a pattern is sought
  	//
  	void OnFirstFind()
  	{
  		//SearchFindNextAction.Sensitive=true;
  		//SearchFindPreviousAction.Sensitive=true;
  	}
  
  	void UpdateActions(DataView dv)
  	{
  		if (dv == null) {
  			FindAction.Sensitive = false;
  			FindNextAction.Sensitive = false;
  			FindPreviousAction.Sensitive = false;
  			ReplaceAction.Sensitive = false;
  			return;
  		}
  
  		FindAction.Sensitive = true;
  		FindNextAction.Sensitive = true;
  		FindPreviousAction.Sensitive = true;
  		ReplaceAction.Sensitive = true;
  	}
  }
  
  ///<summary>
  /// A widget for find and replace operations
  ///</summary>
  public class FindReplaceWidget : Gtk.HBox
  {
  	DataBook dataBook;
  	IFinder finder;
  
  	bool searchPatternChanged;
  	bool replacePatternChanged;
  
  	byte[] replacePattern;
  
  
gt: 	[Glade.Widget] Gtk.Table FindReplaceTable;