Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.265.2.7
diff -u -b -r1.265.2.7 MainWindow.cs
--- src/MainWindow.cs	31 Jan 2006 22:26:25 -0000	1.265.2.7
+++ src/MainWindow.cs	27 Apr 2006 05:25:23 -0000
@@ -14,6 +14,7 @@
 
 using FSpot;
 using FSpot.Mail;
+using FSpot.Query;
 using LibGPhoto2;
 
 public class MainWindow {
@@ -106,6 +107,9 @@
 	[Glade.Widget] Gtk.HBox tagbar;
 	[Glade.Widget] Gtk.Entry tag_entry;
 
+	[Glade.Widget] Gtk.HBox findbar;
+	[Glade.Widget] Gtk.Entry find_entry;
+
 	Gtk.Toolbar toolbar;
 
 	PhotoVersionMenu versions_submenu;
@@ -336,11 +340,16 @@
 		photo_view.View.ZoomChanged += HandleZoomChanged;
 
 		// Tag typing: focus the tag entry if the user starts typing a tag
-		icon_view.KeyPressEvent += HandlePossibleTagTyping;
-		photo_view.KeyPressEvent += HandlePossibleTagTyping;
+		icon_view.KeyPressEvent += HandlePossibleTyping;
+		photo_view.KeyPressEvent += HandlePossibleTyping;
 		tag_entry.KeyPressEvent += HandleTagEntryKeyPressEvent;
 		tag_entry.FocusOutEvent += HandleTagEntryFocusOutEvent;
-		tag_entry.Changed += HandleTagEntryChanged;
+		tag_entry.Changed += HandleCompletionEntryChanged;
+
+		// Find typing
+		find_entry.KeyPressEvent += HandleFindEntryKeyPressEvent;
+		find_entry.Changed += HandleCompletionEntryChanged;
+		find_entry.Changed += HandleFindEntryChanged;
 
 		Gtk.Drag.DestSet (photo_view, DestDefaults.All, tag_target_table, 
 				  DragAction.Copy | DragAction.Move); 
@@ -360,6 +369,7 @@
 		main_window.ShowAll ();
 
 		tagbar.Hide ();
+		findbar.Hide ();
 
 		LoadPreference (Preferences.SHOW_TOOLBAR);
 		LoadPreference (Preferences.SHOW_SIDEBAR);
@@ -2520,35 +2530,40 @@
 		ClearTagCompletions ();
 	}
 
-	public void HandlePossibleTagTyping (object sender, Gtk.KeyPressEventArgs args)
+	public void HandlePossibleTyping (object sender, Gtk.KeyPressEventArgs args)
 	{
-		if (tagbar.Visible && tag_entry.HasFocus)
-			return;
+		if (args.Event.Key == Gdk.Key.t)
+			HandlePossibleTagTyping (sender, args);
 
-#if !ALLOW_TAG_TYPING_WITHOUT_HOTKEY
-		if (args.Event.Key != Gdk.Key.t)
-			return;
-#endif
+		if (args.Event.Key == Gdk.Key.f)
+		 	HandlePossibleFindTyping (sender, args);
+	}
 
-#if ALLOW_TAG_TYPING_WITHOUT_HOTKEY
-		char c = System.Convert.ToChar (Gdk.Keyval.ToUnicode ((uint) args.Event.Key));
-		if (! System.Char.IsLetter (c))
+	private void HandlePossibleTagTyping (object sender, Gtk.KeyPressEventArgs args)
+	{
+		if (tagbar.Visible && tag_entry.HasFocus)
 			return;
-#endif
 		
 		if (tag_entry.Text.Length > 0)
 			tag_entry.Text += ", ";
 
-#if ALLOW_TAG_TYPING_WITHOUT_HOTKEY
-		tag_entry.Text += c;
-#endif
+		ShowTagbar ();
+		HideFindbar ();
 
-		tagbar.Show ();
 		UpdateTagEntryFromSelection ();
 		tag_entry.GrabFocus ();
 		tag_entry.SelectRegion (-1, -1);
 	}
 
+	private void HandlePossibleFindTyping (object sender, Gtk.KeyPressEventArgs args)
+	{
+		if (findbar.Visible && find_entry.HasFocus)
+			return;
+
+		HideTagbar ();
+		ShowFindbar ();
+	}
+
 	// "Activate" means the user pressed the enter key
 	public void HandleTagEntryActivate (object sender, EventArgs args)
 	{
@@ -2622,6 +2637,15 @@
 	       }
 	}
 
+	private void ShowTagbar ()
+	{
+		if (tagbar.Visible && tag_entry.HasFocus)
+		 	return;
+
+		tagbar.Show ();
+		tag_entry.GrabFocus ();
+	}
+
 	private void HideTagbar ()
 	{
 		if (! tagbar.Visible)
@@ -2653,14 +2677,14 @@
 			HideTagbar ();
 			args.RetVal = true;
 		} else if (args.Event.Key == Gdk.Key.Tab) {
-			DoTagCompletion ();
+			DoTagCompletion (tag_entry, ',');
 			args.RetVal = true;
 		} else
 			ClearTagCompletions ();
 	}
 
 	bool tag_ignore_changes = false;
-	public void HandleTagEntryChanged (object sender, EventArgs args)
+	public void HandleCompletionEntryChanged (object sender, EventArgs args)
 	{
 		if (tag_ignore_changes)
 			return;
@@ -2672,25 +2696,26 @@
 	Tag [] tag_completions;
 	string tag_completion_typed_so_far;
 	int tag_completion_typed_position;
-	private void DoTagCompletion ()
+	private void DoTagCompletion (Gtk.Entry entry, char separator)
 	{
 		string completion;
 		
 		if (tag_completion_index != -1) {
 			tag_completion_index = (tag_completion_index + 1) % tag_completions.Length;
-		} else {
-
-			tag_completion_typed_position = tag_entry.Position;
+		}
+		else {
+			tag_completion_typed_position = entry.Position;
 		    
-			string right_of_cursor = tag_entry.Text.Substring (tag_completion_typed_position);
+			string right_of_cursor = entry.Text.Substring (tag_completion_typed_position);
 			if (right_of_cursor.Length > 1)
 				return;
 
-			int last_comma = tag_entry.Text.LastIndexOf (',');
-			if (last_comma > tag_completion_typed_position)
+			int last_sep = entry.Text.LastIndexOf (separator);
+			if (last_sep > tag_completion_typed_position)
 				return;
 
-			tag_completion_typed_so_far = tag_entry.Text.Substring (last_comma + 1).TrimStart (new char [] {' '});
+			tag_completion_typed_so_far = entry.Text.Substring (last_sep + 1).TrimStart (new char [] {' '});
+
 			if (tag_completion_typed_so_far == null || tag_completion_typed_so_far.Length == 0)
 				return;
 
@@ -2703,11 +2728,11 @@
 
 		tag_ignore_changes = true;
 		completion = tag_completions [tag_completion_index].Name.Substring (tag_completion_typed_so_far.Length);
-		tag_entry.Text = tag_entry.Text.Substring (0, tag_completion_typed_position) + completion;
+		entry.Text = entry.Text.Substring (0, tag_completion_typed_position) + completion;
 		tag_ignore_changes = false;
 
-		tag_entry.Position = tag_entry.Text.Length;
-		tag_entry.SelectRegion (tag_completion_typed_position, tag_entry.Text.Length);
+		entry.Position = entry.Text.Length;
+		entry.SelectRegion (tag_completion_typed_position, entry.Text.Length);
 	}
 
 	private void ClearTagCompletions ()
@@ -2749,5 +2774,124 @@
 	public static void SetTip (Widget widget, string tip)
 	{
 		toolTips.SetTip (widget, tip, null);
+	}
+
+	// find bar stuff
+	public void HandleFindBarCloseButtonPressed (object sender, EventArgs args)
+	{
+		HideFindbar ();
+	}
+
+	private void ShowFindbar ()
+	{
+		if (findbar.Visible && find_entry.HasFocus)
+		 	return;
+
+		findbar.Show ();
+		find_entry.GrabFocus ();
+	}
+
+	private void HideFindbar () 
+	{
+		if (! findbar.Visible)
+			return;
+		
+		// Cancel any pending edits...
+		findbar.Hide ();
+
+		if (view_mode == ModeType.IconView)
+			icon_view.GrabFocus ();
+		else
+			photo_view.View.GrabFocus ();
+	}
+
+	public void HandleFindEntryKeyPressEvent (object sender, Gtk.KeyPressEventArgs args)
+	{
+		args.RetVal = false;
+
+		if (args.Event.Key == Gdk.Key.Escape) { 
+			HideFindbar ();
+			args.RetVal = true;
+		} else if (args.Event.Key == Gdk.Key.Tab) {
+			DoTagCompletion (find_entry, ' ');
+			args.RetVal = true;
+		} else
+			ClearTagCompletions ();
+	}
+
+	string last_find;
+	private void HandleFindEntryChanged (object sender, EventArgs args)
+	{
+		GLib.Timeout.Add (250, new GLib.TimeoutHandler (QueryTags));
+	}
+
+	private bool QueryTags ()
+	{
+		string find_entry_text = find_entry.Text.Trim ();
+	 
+		if (find_entry_text == last_find)
+		 	return false;
+
+		if (find_entry_text == "") {
+			query_widget.ClearTags ();
+			return false;
+		}
+	 
+		last_find = find_entry_text;
+		query_widget.Logic.Clear = true;
+
+		GetTypedTagsToFind ();
+		return false;
+	}
+
+	private void GetTypedTagsToFind ()
+	{
+		string [] tagnames = find_entry.Text.Split (new char [] {' '});
+		LogicTerm root = LogicWidget.Root;
+
+		ArrayList list = new ArrayList ();
+		ArrayList tag_stack = new ArrayList ();
+		for (int i = 0; i < tagnames.Length; i++) {
+			if (tagnames[i] == " ")
+			 	continue;		 
+			else if (tagnames[i] == "OR") {
+			 	query_widget.Logic.InsertTerm ((Tag []) (list.ToArray (typeof (Tag))), root, null, false);
+				list.Clear ();
+				tag_stack.Clear ();
+			}
+			else {
+			 	tag_stack.Add (tagnames [i].Trim ());
+			 	Tag t = GetTagFromStack ((string[])(tag_stack.ToArray (typeof (string))));
+				//Tag t = db.Tags.GetTagByName (tagnames [i].Trim ());
+
+				if (t != null) {
+					list.Add (t);
+					tag_stack.Clear ();
+				}
+			}
+		}
+		query_widget.Logic.InsertTerm ((Tag []) (list.ToArray (typeof (Tag))), root, null, true);
+	}
+
+	private Tag GetTagFromStack (string[] tag_stack)
+	{
+	 	Tag found = null;	
+
+	 	for (int i = 0; i < tag_stack.Length; i++) {
+			string current = tag_stack[i];
+			found = db.Tags.GetTagByName (current);
+			if (found != null)
+			 	return found;
+
+			for (int j = i + 1; j < tag_stack.Length; j++)	{
+				current = current + " " + tag_stack[j];
+				found = db.Tags.GetTagByName (current);
+
+				if (found != null)
+				 	return found;
+			}
+		}
+	 	
+		return null;
 	}
 }
Index: src/TagQueryWidget.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/Attic/TagQueryWidget.cs,v
retrieving revision 1.1.2.7
diff -u -b -r1.1.2.7 TagQueryWidget.cs
--- src/TagQueryWidget.cs	31 Jan 2006 04:31:24 -0000	1.1.2.7
+++ src/TagQueryWidget.cs	27 Apr 2006 05:25:25 -0000
@@ -1189,6 +1189,11 @@
 		
 		public ArrayList InsertTerm (Tag [] tags, LogicTerm parent, Literal after)
 		{
+			return InsertTerm (tags, parent, after, true);
+		}
+		
+		public ArrayList InsertTerm (Tag [] tags, LogicTerm parent, Literal after, bool update)
+		{
 			int position;
 			if (after != null)
 				position = WidgetPosition (after.Widget) + 1;
@@ -1238,6 +1243,7 @@
 				InsertWidget (position, term.Widget);
 			}
 
+			if (update)
 			UpdateQuery ();
 
 			return added;
Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.142.2.6
diff -u -b -r1.142.2.6 f-spot.glade
--- src/f-spot.glade	31 Jan 2006 22:26:25 -0000	1.142.2.6
+++ src/f-spot.glade	27 Apr 2006 05:25:47 -0000
@@ -8149,6 +8149,92 @@
 		      <property name="fill">True</property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkHBox" id="findbar">
+		      <property name="border_width">2</property>
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">1</property>
+
+		      <child>
+			<widget class="GtkLabel" id="label161">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Find: </property>
+			  <property name="use_underline">False</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkEntry" id="find_entry">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="editable">True</property>
+			  <property name="visibility">True</property>
+			  <property name="max_length">0</property>
+			  <property name="text" translatable="yes"></property>
+			  <property name="has_frame">True</property>
+			  <property name="invisible_char">*</property>
+			  <property name="activates_default">False</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkButton" id="find_close_button">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="relief">GTK_RELIEF_NONE</property>
+			  <property name="focus_on_click">True</property>
+			  <signal name="pressed" handler="HandleFindBarCloseButtonPressed" last_modification_time="Mon, 14 Nov 2005 20:06:09 GMT"/>
+
+			  <child>
+			    <widget class="GtkImage" id="image25">
+			      <property name="visible">True</property>
+			      <property name="stock">gtk-close</property>
+			      <property name="icon_size">4</property>
+			      <property name="xalign">0.5</property>
+			      <property name="yalign">0.5</property>
+			      <property name="xpad">0</property>
+			      <property name="ypad">0</property>
+			    </widget>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">True</property>
+		      <property name="pack_type">GTK_PACK_END</property>
+		    </packing>
+		  </child>
 		</widget>
 		<packing>
 		  <property name="shrink">True</property>
