Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.234
diff -u -r1.234 MainWindow.cs
--- src/MainWindow.cs	16 Nov 2005 00:39:20 -0000	1.234
+++ src/MainWindow.cs	20 Nov 2005 17:57:27 -0000
@@ -86,6 +86,15 @@
 
 	[Glade.Widget] Gtk.HBox tagbar;
 	[Glade.Widget] Gtk.Entry tag_entry;
+	
+	[Glade.Widget] Gtk.HBox findbar;
+	[Glade.Widget] Gtk.Entry find_entry;
+	[Glade.Widget] Gtk.ComboBox find_option_combo;
+			
+	enum Option : byte {
+		Filename,
+		Description
+	};
 
 	Gtk.Toolbar toolbar;
 
@@ -201,6 +210,13 @@
 		left_vbox.PackStart (cal, false, true, 0);
 #endif
 
+		find_option_combo.Active = 0;
+		find_entry.Completion = new Gtk.EntryCompletion ();
+		find_entry.Completion.MatchFunc = FindEntryCompletionMatchFunc;
+		find_entry.KeyPressEvent += HandleFindEntryKeyPressEvent;
+		find_entry.Activated += HandleFindEntryActivated;
+		find_entry.Changed += HandleFindEntryChanged;
+
 		group_selector = new FSpot.GroupSelector ();
 		FSpot.GroupAdaptor adaptor = new FSpot.TimeAdaptor (query);
 
@@ -269,8 +285,8 @@
 		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 += HandleTyping;
+		photo_view.KeyPressEvent += HandleTyping;
 		tag_entry.KeyPressEvent += HandleTagEntryKeyPressEvent;
 		tag_entry.FocusOutEvent += HandleTagEntryFocusOutEvent;
 		tag_entry.Changed += HandleTagEntryChanged;
@@ -289,6 +305,7 @@
 		main_window.ShowAll ();
 
 		tagbar.Hide ();
+		findbar.Hide ();
 
 		LoadPreference (Preferences.SHOW_TOOLBAR);
 		LoadPreference (Preferences.SHOW_SIDEBAR);
@@ -375,6 +392,7 @@
 			
 			JumpTo (icon_view.FocusCell);
 			zoom_scale.Value = photo_view.Zoom;
+			HideFindbar ();
 			break;
 		}
 		UpdateToolbar ();
@@ -2184,6 +2202,18 @@
 		remove_tag_from_selection.Sensitive = tag_sensitive && active_selection;
 	}
 
+	public void HandleTyping (object sender, Gtk.KeyPressEventArgs args)
+	{
+		switch (args.Event.Key) {
+			case Gdk.Key.t: HandlePossibleTagTyping (sender, args);
+					break;
+			case Gdk.Key.f: HandlePossibleFindTyping (sender, args);
+					break;			
+			default: 
+				break;
+		}	
+	}
+
 	// Tag typing
 
 	private ArrayList selected_photos_tagnames;
@@ -2233,26 +2263,12 @@
 	{
 		if (tagbar.Visible && tag_entry.HasFocus)
 			return;
-
-#if !ALLOW_TAG_TYPING_WITHOUT_HOTKEY
-		if (args.Event.Key != Gdk.Key.t)
-			return;
-#endif
-
-#if ALLOW_TAG_TYPING_WITHOUT_HOTKEY
-		char c = System.Convert.ToChar (Gdk.Keyval.ToUnicode ((uint) args.Event.Key));
-		if (! System.Char.IsLetter (c))
-			return;
-#endif
 		
 		if (tag_entry.Text.Length > 0)
 			tag_entry.Text += ", ";
 
-#if ALLOW_TAG_TYPING_WITHOUT_HOTKEY
-		tag_entry.Text += c;
-#endif
-
 		tagbar.Show ();
+		HideFindbar ();
 		tag_entry.GrabFocus ();
 		tag_entry.SelectRegion (-1, -1);
 	}
@@ -2358,6 +2374,7 @@
 
 		if (args.Event.Key == Gdk.Key.Escape) { 
 			HideTagbar ();
+			findbar.Hide ();
 			args.RetVal = true;
 		} else if (args.Event.Key == Gdk.Key.Tab) {
 			DoTagCompletion ();
@@ -2452,4 +2469,113 @@
 				return true;
 		return false;
 	}
+	
+	// Findbar stuff
+
+	public void HandlePossibleFindTyping (object sender, Gtk.KeyPressEventArgs args)
+	{
+		if (view_mode != ModeType.IconView)
+			return;
+
+		if (findbar.Visible && find_entry.HasFocus)
+			return;
+
+		findbar.Show ();
+		find_entry.GrabFocus ();
+		HideTagbar ();		
+	}
+
+	public void HandleFindEntryKeyPressEvent(object sender, Gtk.KeyPressEventArgs args)
+	{
+		if (args.Event.Key != Gdk.Key.Escape)
+			return;
+
+		HideFindbar ();
+	}
+
+	private void HideFindbar ()
+	{
+		if (!findbar.Visible)
+			return;
+
+		findbar.Hide ();
+
+		if (view_mode == ModeType.IconView)
+			icon_view.GrabFocus ();
+		else
+			photo_view.View.GrabFocus ();
+	}
+
+	public void HandleFindBarCloseButtonPressed (object sender, EventArgs args)
+	{
+		HideFindbar ();
+	}
+
+	private void HandleFindEntryActivated(object sender, EventArgs e)
+	{
+		switch ((Option) find_option_combo.Active) {
+			case Option.Filename:
+				query.Filename = find_entry.Text;
+				break;
+			case Option.Description:
+				query.Description = find_entry.Text;
+				break;
+		}
+	}
+
+	private void HandleFindEntryChanged(object sender, EventArgs e)
+	{
+		find_entry.Completion.Clear ();
+		find_entry.Completion.Model = CreateFindEntryCompletionModel ();
+		find_entry.Completion.TextColumn = 0;
+	}
+
+	private TreeModel CreateFindEntryCompletionModel ()
+	{
+		ListStore store = new ListStore (typeof (string));
+
+		uint counter = 0;
+
+		Photo []photos;
+		ArrayList strings = new ArrayList ();
+
+		switch ((Option) find_option_combo.Active) {
+			case Option.Filename:
+				photos = query.Store.Query (query.Tags, query.Range, find_entry.Text, null);
+				foreach (Photo photo in photos) {
+					if (strings.IndexOf (photo.Name) >= 0)
+						continue;
+
+					strings.Add (photo.Name);
+					if (counter++ >= 10)
+						break;
+				}
+				break;
+			case Option.Description:
+				photos = query.Store.Query (query.Tags, query.Range, null, find_entry.Text);
+				foreach (Photo photo in photos) {
+					if (strings.IndexOf (photo.Description) >= 0)
+						continue;
+
+					strings.Add (photo.Description);
+					if (counter++ >= 10)
+						break;
+				}			
+				break;
+			default:
+				break;
+		}
+
+		foreach (string to_add in strings) {
+			store.AppendValues (to_add);
+		}
+
+		return store;
+	}
+
+	private bool FindEntryCompletionMatchFunc (EntryCompletion completion, string key, TreeIter iter)
+	{
+		return true;
+	}
+
 }
Index: src/PhotoQuery.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoQuery.cs,v
retrieving revision 1.16
diff -u -r1.16 PhotoQuery.cs
--- src/PhotoQuery.cs	19 Oct 2005 05:30:45 -0000	1.16
+++ src/PhotoQuery.cs	20 Nov 2005 17:57:28 -0000
@@ -8,6 +8,8 @@
 		private PhotoStore store;
 		private Tag [] tags;
 		private PhotoStore.DateRange range = null;
+		private string filename = null;
+		private string description = null;
 		
 		// Constructor
 		public PhotoQuery (PhotoStore store)
@@ -76,6 +78,35 @@
 				RequestReload ();
 			}
 		}
+		
+		public string Filename {
+			get {
+				return filename;
+			}
+			set {
+				if (filename == value)
+					return;
+			
+				filename = value;
+				photos = store.Query (tags, range, filename, null);
+				RequestReload();
+			}		
+		}
+		
+		public string Description {
+			get {
+				return description;
+			}
+			set {
+				if (description == value)
+					return;
+
+				description = value;
+				photos = store.Query (tags, range, null, description);
+				RequestReload();
+			}
+		}
+		
 
 		public void RequestReload ()
 		{
Index: src/PhotoStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoStore.cs,v
retrieving revision 1.72
diff -u -r1.72 PhotoStore.cs
--- src/PhotoStore.cs	2 Nov 2005 08:33:15 -0000	1.72
+++ src/PhotoStore.cs	20 Nov 2005 17:57:29 -0000
@@ -1113,9 +1113,25 @@
 
 	public Photo [] Query (Tag [] tags, DateRange range)
 	{
-		string query;
+		string query = CreateQuery (tags, range, null, null);
+		
+		return Query (query);
+	}
+	
+	public Photo[] Query (Tag []tags, DateRange range, string filename, string description)
+	{
+	       string query = CreateQuery (tags, range, filename, description);
+	       	       
+	       return Query (query);
+	}
+			
 
+        // private members
+	private string CreateQuery(Tag []tags, DateRange range, string filename, string description)
+	{
 		bool hide = true;
+		bool has_where = false;
+		
 		if (tags != null) {
 			foreach (Tag t in tags) {
 				if (tag_store.Hidden == null || t.Id == tag_store.Hidden.Id) 
@@ -1132,12 +1148,13 @@
 		//        photos.name,
 		//        photos.description,
 		//        photos.default_version_id
-		//                  FROM photos, photo_tags
-		//                  WHERE photos.id = photo_tags.photo_id
-		// 		          AND (photo_tags.tag_id = tag1
-		//			       OR photo_tags.tag_id = tag2
-		//                             OR photo_tags.tag_id = tag3 ...)
-		//                  GROUP BY photos.id
+		// FROM  photos
+		// WHERE photos.time >= <start_time> AND photos.time <end_time>
+		// AND   photos.id NOT IN (SELECT photo_id FROM photo_tags WHERE tag_id = <hidden_id>)
+		// AND   photos.id IN     (SELECT photo_id FROM photo_tags WHERE tag_id IN (<list of tag_id's>)
+		// AND   photos.name LIKE '%<filename>%'
+		// AND   photos.description LIKE '%<description>%'
+		// ORDER BY photos.time
 		
 		StringBuilder query_builder = new StringBuilder ();
 		query_builder.Append ("SELECT photos.id,                          " +
@@ -1146,17 +1163,20 @@
 				      "       photos.name,                        " +
 				      "       photos.description,                 " +
 				      "       photos.default_version_id           " +
-				      "     FROM photos                      ");
+				      "FROM photos ");
 		
 		if (range != null) {
-			query_builder.Append (String.Format ("WHERE photos.time >= {0} AND photos.time < {1} ",
+			query_builder.Append (String.Format ("{0} photos.time >= {1} AND photos.time < {2} ",
+							     has_where ? "AND" : "WHERE",
 							     DbUtils.UnixTimeFromDateTime (range.Start), 
 							     DbUtils.UnixTimeFromDateTime (range.End)));
+			has_where = true;
 		}
 		
 		if (hide) {
-			query_builder.Append (String.Format ("{0} photos.id NOT IN (SELECT photo_id FROM photo_tags WHERE tag_id = {1})", 
-							     range != null ? " AND " : " WHERE ", tag_store.Hidden.Id));
+			query_builder.Append (String.Format ("{0} photos.id NOT IN (SELECT photo_id FROM photo_tags WHERE tag_id = {1}) ", 
+							     has_where ? "AND" : "WHERE", tag_store.Hidden.Id));
+			has_where = true;						     
 		}
 		
 		if (tags != null && tags.Length > 0) {
@@ -1170,7 +1190,8 @@
 				
 				if (first) {
 					query_builder.Append (String.Format ("{0} photos.id IN (SELECT photo_id FROM photo_tags WHERE tag_id IN (",
-									     hide || range != null ? " AND " : " WHERE "));
+									     has_where ? " AND " : " WHERE "));
+					has_where = true;
 				}
 				
 				query_builder.Append (String.Format ("{0}{1} ", first ? "" : ", ", t.Id));
@@ -1180,13 +1201,28 @@
 			
 			if (!first)
 				query_builder.Append (")) ");
+		}	
+		
+		if (filename != null && filename != "")	{
+			query_builder.Append (String.Format ("{0} photos.name LIKE '%{1}%' ",
+							     has_where ? "AND" : "WHERE",
+							     filename));
+			has_where = true;
 		}
 		
-		query_builder.Append ("ORDER BY photos.time");
-		query = query_builder.ToString ();
+		if (description != null && description != "")	{
+			query_builder.Append (String.Format ("{0} photos.description LIKE '%{1}%' ",
+							     has_where ? "AND" : "WHERE",
+							     description));
+			has_where = true;
+		}
 		
-		return Query (query);
+		query_builder.Append ("ORDER BY photos.time");		
+		
+		return query_builder.ToString();
 	}
+
+
 
 #if TEST_PHOTO_STORE
 	static void Dump (Photo photo)
Index: src/TagSelectionWidget.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagSelectionWidget.cs,v
retrieving revision 1.22
diff -u -r1.22 TagSelectionWidget.cs
--- src/TagSelectionWidget.cs	11 Nov 2005 02:23:15 -0000	1.22
+++ src/TagSelectionWidget.cs	20 Nov 2005 17:57:30 -0000
@@ -35,6 +35,12 @@
 public class TagSelectionWidget : TreeView {
 	TagSelectionWidget widget;
 	private TagStore tag_store;
+		
+	public TagStore Store {
+		get {
+			return tag_store;
+		}
+	}
 
 	// FIXME this is a hack.
 	private static Pixbuf empty_pixbuf = new Pixbuf (Colorspace.Rgb, true, 8, 1, 1);
Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.118
diff -u -r1.118 f-spot.glade
--- src/f-spot.glade	11 Nov 2005 10:04:28 -0000	1.118
+++ src/f-spot.glade	20 Nov 2005 17:57:57 -0000
@@ -7586,6 +7586,107 @@
 		      <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="GtkComboBox" id="find_option_combo">
+			  <property name="visible">True</property>
+			  <property name="items" translatable="yes">Filename
+Description</property>
+			  <property name="add_tearoffs">False</property>
+			  <property name="focus_on_click">True</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</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>
