Re: Tag typing.



On Tue, 2005-11-08 at 20:40 -0600, Gabriel Burt wrote:
> 1. After using it a bit, I definitely prefer it to be hidden most of the
> time .. the medallions should definitely have a tooltip saying what they
> are on mouseover at least..

Yeah.  I'm not sure myself.  Personally I really like seeing the list of
tags down there.  It's a lot faster than tooltips.  To see a tooltip you
have to position the mouse inside a 20x20 pixel rectangle and wait one
second for the tooltip to appear.  That requires a little bit too much
skill for me.

Another way I've been thinking about this is: for a given photo, what
information is important to me?  I think the tags are probably important
to me.  They are at least as important as, say, the image's size.  The
little infobox in the lower-left shows the size, version, camera
exposure data all the time.   I think the tags are at least as important
as some of that information.

Maybe it should be a preference... I don't know.  I guess I'm going to
try it on my system for a while and see how I feel.

If you want to play with both modes, I've attached a version of the
patch that keeps the bar hidden most of the time.  Personally using it
in this "autohide" mode makes me want to have a hot key to show it... so
maybe that's something to try too.

> 2. When I go into full screen mode and then come out, it has displayed
> the tagging bar and it has focus (from pressing the 'f').

Yeah.  For maximal efficiency I made it so that if you type any
alphabetic character into either the photo view or the icon view, the
tagbar will appear and accept the character.  Unfortunately this means
we have a few shortcut collisions.  f, v and V. 

If we're going to stick with this maximal efficiency mode, which I
personally love, then we need to reshortcut those actions.  Alt-f maybe.

The other option I guess is to force the user to hit a hot key to start
tagging.

> 3. In PhotoView (Edit) mode when you press escape, it doesn't return the
> focus to the picture, meaning I can't press escape again to return to
> Browse mode.

Hmm, weird, I'll look at this.

> This is really awesome, especially combined with the drag and drop
> reparenting (in CVS) - you can create a bunch of new tags on the fly
> with this patch, and then put them where they go in a few short seconds.

Oooh sexy.  I hadn't tried this before.  Nice!

> This feature is definitely a good thing to have documented properly in
> the help (ahem) and on the website as it's not very easily discoverable.

We should think about enhancing the discoverability of this, I think
it's so awesome it's actually an advantage over other photo management
software I've used before.

> The stamp feature (ie select tag(s) and then single clicks on photos
> stamps them with those tags) is something we should keep in mind, and
> somebody should actually implement. ;)

I really want that, but I want a tag "paintbrush," so I can just select
a few tags, and then paint over the icon view iwndow.

Nat

? f-spot.glade.broken
? f-spot.gladep
? nat.diff
? p
? pp
? tag.diff
? tagger-hide.diff
? tagger.diff
Index: Db.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/Db.cs,v
retrieving revision 1.7
diff -u -r1.7 Db.cs
--- Db.cs	7 Oct 2005 21:35:39 -0000	1.7
+++ Db.cs	9 Nov 2005 03:35:58 -0000
@@ -24,7 +24,7 @@
 public abstract class DbStore {
 	// DbItem cache.
 
-	Hashtable item_cache;
+	protected Hashtable item_cache;
 	bool cache_is_immortal;
 
 	protected void AddToCache (DbItem item)
Index: MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.228
diff -u -r1.228 MainWindow.cs
--- MainWindow.cs	2 Nov 2005 08:33:16 -0000	1.228
+++ MainWindow.cs	9 Nov 2005 03:35:59 -0000
@@ -83,6 +83,9 @@
 	[Glade.Widget] Gtk.Image near_image;
 	[Glade.Widget] Gtk.Image far_image;
 
+	[Glade.Widget] Gtk.HBox tagbar;
+	[Glade.Widget] Gtk.Entry tag_entry;
+
 	Gtk.Toolbar toolbar;
 
 	PhotoVersionMenu versions_submenu;
@@ -260,6 +263,12 @@
 		photo_view.UpdateStarted += HandlePhotoViewUpdateStarted;
 		photo_view.UpdateFinished += HandlePhotoViewUpdateFinished;
 
+		// Tag typing: focus the tag entry if the user starts typing a tag
+		icon_view.KeyPressEvent += HandlePossibleTagTyping;
+		photo_view.KeyPressEvent += HandlePossibleTagTyping;
+		tag_entry.KeyPressEvent += HandleTagEntryKeyPressEvent;
+		tag_entry.FocusOutEvent += HandleTagEntryFocusOutEvent;
+		
 		Gtk.Drag.DestSet (photo_view, DestDefaults.All, tag_target_table, 
 				  DragAction.Copy | DragAction.Move); 
 
@@ -273,6 +282,8 @@
 		UpdateMenus ();
 		main_window.ShowAll ();
 
+		tagbar.Hide ();
+
 		LoadPreference (Preferences.SHOW_TOOLBAR);
 		LoadPreference (Preferences.SHOW_SIDEBAR);
 		LoadPreference (Preferences.SHOW_TIMELINE);
@@ -455,7 +466,6 @@
 	private void RotateSelectedPictures (RotateCommand.Direction direction)
 	{
 		RotateCommand command = new RotateCommand (main_window);
-
 		
 		int [] selected_ids = SelectedIds ();
 		if (command.Execute (direction, SelectedPhotos (selected_ids))) {
@@ -505,13 +515,9 @@
 	{
 		if (args.Event.Button == 3)
 		{
-			TreePath path;
-			tag_selection_widget.Selection.UnselectAll ();
-			if (tag_selection_widget.GetPathAtPos ((int)args.Event.X, (int)args.Event.Y, out path)) {
-				tag_selection_widget.Selection.SelectPath (path);
-			}
 			TagPopup popup = new TagPopup ();
-			popup.Activate (args.Event, tag_selection_widget.TagAtPosition ((int)args.Event.X, (int)args.Event.Y));
+			popup.Activate (args.Event, tag_selection_widget.TagAtPosition ((int)args.Event.X, (int)args.Event.Y),
+					tag_selection_widget.TagHighlight ());
 			args.RetVal = true;
 		}
 	}
@@ -626,6 +632,8 @@
 
 			break;
 		}
+
+		UpdateTagEntryFromSelection ();
 	}
 
 #if SHOW_CALENDAR
@@ -824,6 +832,8 @@
 					AttachTags (tag_selection_widget.TagHighlight (), SelectedIds());
 				else 
 					AttachTags (tag_selection_widget.TagHighlight (), new int [] {item});
+
+				UpdateTagEntryFromSelection ();
 			}
 			break;
 		case (uint)TargetType.UriList:
@@ -851,7 +861,9 @@
 		info_box.Photo = CurrentPhoto;
 		if (info_display != null)
 			info_display.Photo = CurrentPhoto;
+
 		UpdateMenus ();
+		UpdateTagEntryFromSelection ();
 	}
 
 	void HandleDoubleClicked (IconView icon_view, int clicked_item)
@@ -960,6 +972,8 @@
 		foreach (int num in SelectedIds ()) {
 			AddTagExtended (num, new Tag [] {t});
 		}
+
+		UpdateTagEntryFromSelection ();
 	}
 	
 	void HandleFindTagMenuSelected (Tag t)
@@ -973,6 +987,8 @@
 			query.Photos [num].RemoveTag (t);
 			query.Commit (num);
 		}
+
+		UpdateTagEntryFromSelection ();
 	}
 
 	//
@@ -1338,16 +1354,71 @@
 			query.Photos [num].RemoveTag (tags);
 			query.Commit (num);
 		}
+
+		UpdateTagEntryFromSelection ();
 	}
 
-	public void HandleEditSelectedTag (object obj, EventArgs args)
+	public void HandleEditSelectedTag (object sender, EventArgs ea)
 	{
-		Tag [] tags = tag_selection_widget.TagHighlight ();
+		Tag [] tags = this.tag_selection_widget.TagHighlight ();
 		if (tags.Length != 1)
 			return;
+
+		HandleEditSelectedTagWithTag (tags [0]);
+	}
+
+	public void HandleEditSelectedTagWithTag (Tag tag)
+	{
+		if (tag == null)
+			return;
 		
 		TagCommands.Edit command = new TagCommands.Edit (db, main_window);
-		command.Execute (tags [0]);
+		command.Execute (tag);
+		if (view_mode == ModeType.IconView)
+			icon_view.QueueDraw ();
+	}
+
+	public void HandleMergeTagsCommand (object obj, EventArgs args)
+	{
+		Tag [] tags = this.tag_selection_widget.TagHighlight ();
+		if (tags.Length < 2)
+			return;
+
+		System.Array.Sort (tags, new TagRemoveComparer ());
+		string header = Mono.Posix.Catalog.GetString ("Merge the {0} selected tags?");
+		
+		header = String.Format (header, tags.Length);
+		string msg = Mono.Posix.Catalog.GetString("This operation will delete all but one of the selected tags.");
+		string ok_caption = Mono.Posix.Catalog.GetString ("_Merge tags");
+		
+		if (ResponseType.Ok != HigMessageDialog.RunHigConfirmation(main_window, 
+									   DialogFlags.DestroyWithParent, 
+									   MessageType.Warning, 
+									   header, 
+									   msg, 
+									   ok_caption))
+			return;
+		
+		// The surviving tag is tags [0].  removetags will contain
+		// the tags to be merged.
+		Tag [] removetags = new Tag [tags.Length - 1];
+		Array.Copy (tags, 1, removetags, 0, tags.Length - 1);
+
+
+		// Remove the defunct tags from all the photos and
+		// replace them with the new tag.
+		Photo [] photos = db.Photos.Query (tags, null);
+		foreach (Photo p in photos) {
+			p.RemoveTag (removetags);
+			p.AddTag (tags [0]);
+			db.Photos.Commit (p);
+		}
+
+		// Remove the defunct tags from the tag list.
+		db.Photos.Remove (removetags);
+
+		UpdateTagEntryFromSelection ();
+		icon_view.QueueDraw ();
 	}
 
 	void HandleAdjustColor (object sender, EventArgs args)
@@ -1988,5 +2059,250 @@
 		remove_tag_from_selection.Sensitive = tag_sensitive && active_selection;
 	}
 
+	// Tag typing
+
+	private ArrayList selected_photos_tagnames;
+
+	private void UpdateTagEntryFromSelection ()
+	{
+		Hashtable taghash = new Hashtable ();
+
+		Photo [] sel = SelectedPhotos (SelectedIds ());
+		foreach (Photo p in sel) {
+			foreach (Tag t in p.Tags) {
+				int count = 1;
+				string tagname = t.Name;
+
+				if (taghash.Contains (tagname))
+					count = ((int) taghash [tagname]) + 1;
+
+				taghash [tagname] = count;
+			}
+		}
+
+		selected_photos_tagnames = new ArrayList ();
+		foreach (string tagname in taghash.Keys)
+			if ((int) (taghash [tagname]) == sel.Length)
+				selected_photos_tagnames.Add (tagname);
+		selected_photos_tagnames.Sort ();
+
+		string taglist = "";
+		foreach (string tagname in selected_photos_tagnames) {
+			if (taglist == "")
+				taglist = tagname;
+			else
+				taglist = taglist + ", " + tagname;
+		}
+
+		tag_entry.Text = taglist;
+	}
+
+	public void HandlePossibleTagTyping (object sender, Gtk.KeyPressEventArgs args)
+	{
+		if (tagbar.Visible && tag_entry.HasFocus)
+			return;
+
+		char c = System.Convert.ToChar (Gdk.Keyval.ToUnicode ((uint) args.Event.Key));
+		if (! System.Char.IsLetter (c))
+			return;
+
+		if (! tagbar.Visible)
+			tagbar.Show ();
+		
+		if (tag_entry.Text.Length > 0)
+			tag_entry.Text += ", ";
+		tag_entry.Text += c;
+
+		tagbar.Show ();
+		tag_entry.GrabFocus ();
+		tag_entry.SelectRegion (-1, -1);
+	}
+
+	public void HandleTagEntryActivate (object sender, EventArgs args)
+	{
+		string [] tagnames = GetTypedTagNames ();
+
+		// Add any new tags to the selected photos
+		Category default_category = null;
+		Tag [] selection = tag_selection_widget.TagHighlight ();
+		if (selection.Length > 0) {
+			if (selection [0] is Category)
+				default_category = (Category) selection [0];
+			else
+				default_category = selection [0].Category;
+		}
+
+		foreach (string tagname in tagnames) {
+			if (tagname.Length == 0)
+				continue;
+			
+			Tag t = db.Tags.GetTagByName (tagname);
+			if (t == null) {
+				t = db.Tags.CreateTag (default_category, tagname);
+				db.Tags.Commit (t);
+			}
+
+			Tag [] tags = new Tag [1];
+			tags [0] = t;
+
+			foreach (int num in SelectedIds ())
+				AddTagExtended (num, tags);
+		}
+
+		// Remove any removed tags from the selected photos
+		foreach (string tagname in selected_photos_tagnames) {
+			if (! IsTagInList (tagnames, tagname)) {
+				
+				Tag tag = db.Tags.GetTagByName (tagname);
+
+				foreach (int num in SelectedIds ()) {
+					query.Photos [num].RemoveTag (tag);
+					query.Commit (num);
+				}
+			}
+		}
+
+		UpdateTagEntryFromSelection ();
+		if (view_mode == ModeType.IconView) {
+			icon_view.QueueDraw ();
+			icon_view.GrabFocus ();
+		} else {
+			photo_view.QueueDraw ();
+			photo_view.GrabFocus ();
+		}
+	}
+
+	private void HideTagbar ()
+	{
+		if (! tagbar.Visible)
+			return;
+		
+		// Cancel any pending edits...
+		UpdateTagEntryFromSelection ();
+
+		tagbar.Hide ();
+
+		if (view_mode == ModeType.IconView)
+			icon_view.GrabFocus ();
+		else
+			photo_view.GrabFocus ();
+	}
+
+	public void HandleTagBarCloseButtonPressed (object sender, EventArgs args)
+	{
+		HideTagbar ();
+	}
+
+	public void HandleTagEntryKeyPressEvent (object sender, Gtk.KeyPressEventArgs args)
+	{
+		args.RetVal = false;
+		
+		if (args.Event.Key == Gdk.Key.Escape) {
+			HideTagbar (); 
+			args.RetVal = true;
+		} else if (args.Event.Key == Gdk.Key.Tab) {
+			DoTagCompletion ();
+			args.RetVal = true;
+		}
+	}
+
+	public void HandleTagEntryChanged (object sender, EventArgs args)
+	{
+		using (new Timer ("Completion")) {
+			UpdateTagCompletionSuggestion ();
+		}
+	}
+
+	private void UpdateTagCompletionSuggestion ()
+	{
+#if YOU_ARE_CAUGHT_IN_A_MAZE_OF_TWISTY_SIGNAL_EMISSIONS_ALL_ALIKE
+		if (tag_typing_ignore_signal) {
+			Console.WriteLine ("Ignoring signal...");
+			return;
+		}
+		
+		int pos = tag_entry.Position;
+		Console.WriteLine ("Update completion: " + pos + " - [" + tag_entry.Text.Substring (0, pos) + "]"
+				   + "{" + tag_entry.Text.Substring (pos) + "}");
+
+		string right_of_cursor = tag_entry.Text.Substring (pos);
+
+		int last_comma = tag_entry.Text.LastIndexOf (',');
+		if (last_comma > pos)
+			return;
+
+		string typed_so_far = tag_entry.Text.Substring (last_comma + 1).TrimStart (new char [] {' '});
+		Console.WriteLine ("Typed so far: [" + typed_so_far + "]");
+		if (typed_so_far == null || typed_so_far.Length == 0)
+			return;
+
+		Tag [] tags = db.Tags.GetTagsByNameStart (typed_so_far);
+		if (tags == null)
+			return;
+		foreach (Tag t in tags)
+			Console.WriteLine ("Completable: [" + t.Name + "]");
+
+		string you_complete_me = tags [0].Name.Substring (typed_so_far.Length);
+		tag_typing_ignore_signal = true;
+		tag_entry.Text = tag_entry.Text.Substring (0, pos + 1) + you_complete_me;
+		tag_typing_ignore_signal = false;
+		//		GLib.Idle.Add (new GLib.IdleHandler (delegate {
+		//			tag_entry.SelectRegion (tag_entry.Text.Length - you_complete_me.Length, tag_entry.Text.Length);
+		//			return false;
+		//		}));
+		//		Application.Run ();
+#endif
+	}
+
+	private void DoTagCompletion ()
+	{
+		string right_of_cursor = tag_entry.Text.Substring (tag_entry.Position);
+		if (right_of_cursor.Length > 1)
+			return;
+
+		int last_comma = tag_entry.Text.LastIndexOf (',');
+		if (last_comma > tag_entry.Position)
+			return;
+
+		string typed_so_far = tag_entry.Text.Substring (last_comma + 1).TrimStart (new char [] {' '});
+		if (typed_so_far == null || typed_so_far.Length == 0)
+			return;
+
+		Tag [] tags = db.Tags.GetTagsByNameStart (typed_so_far);
+		if (tags == null)
+			return;
+		string you_complete_me = tags [0].Name.Substring (typed_so_far.Length);
+		tag_entry.Text += you_complete_me + ", ";
+		tag_entry.Position = tag_entry.Text.Length;
+	}
+
+	public void HandleTagEntryFocusOutEvent (object sender, EventArgs args)
+	{
+		UpdateTagEntryFromSelection ();
+		HideTagbar ();
+	}
+
+	private string [] GetTypedTagNames ()
+	{
+		string [] tagnames = tag_entry.Text.Split (new char [] {','});
+
+		ArrayList list = new ArrayList ();
+		for (int i = 0; i < tagnames.Length; i ++) {
+			string s = tagnames [i].Trim ();
+
+			if (s.Length > 0)
+				list.Add (s);
+		}
+
+		return (string []) (list.ToArray (typeof (string)));
+	}
+
+	private bool IsTagInList (string [] tags, string tag)
+	{
+		foreach (string t in tags)
+			if (t == tag)
+				return true;
+		return false;
+	}
 }
 
Index: PhotoStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoStore.cs,v
retrieving revision 1.72
diff -u -r1.72 PhotoStore.cs
--- PhotoStore.cs	2 Nov 2005 08:33:15 -0000	1.72
+++ PhotoStore.cs	9 Nov 2005 03:35:59 -0000
@@ -1273,7 +1273,7 @@
 		db.Photos.Commit (me_in_sf);
 
 		me_in_sf.RemoveTag (favorites_tag);
-		me_in_sf.Description = "Myself and the SF skyline";
+     		me_in_sf.Description = "Myself and the SF skyline";
 		me_in_sf.CreateVersion ("cropped", Photo.OriginalVersionId);
 		me_in_sf.CreateVersion ("UM-ed", Photo.OriginalVersionId);
 		db.Photos.Commit (me_in_sf);
Index: PhotoView.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoView.cs,v
retrieving revision 1.68
diff -u -r1.68 PhotoView.cs
--- PhotoView.cs	2 Nov 2005 08:33:15 -0000	1.68
+++ PhotoView.cs	9 Nov 2005 03:35:59 -0000
@@ -253,7 +253,6 @@
 		}
 
 		Photo photo = (Photo)Item.Current;
-		Exif.ExifData exif_data = new Exif.ExifData (photo.DefaultVersionPath);
 
 		Pixbuf edited;
 		if (redeye) {
@@ -273,7 +272,6 @@
 		// be fixed there.
 		photo_view.Pixbuf = edited;
 		photo_view.UnsetSelection ();
-		bool version = false;
 
 		try {
 			bool create_version = photo.DefaultVersionId == Photo.OriginalVersionId;
Index: TagCommands.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagCommands.cs,v
retrieving revision 1.28
diff -u -r1.28 TagCommands.cs
--- TagCommands.cs	28 Oct 2005 19:52:30 -0000	1.28
+++ TagCommands.cs	9 Nov 2005 03:35:59 -0000
@@ -323,6 +323,7 @@
 			}
 			
 			this.Dialog.Destroy ();
+
 			return success;
 		}
 
Index: TagPopup.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagPopup.cs,v
retrieving revision 1.3
diff -u -r1.3 TagPopup.cs
--- TagPopup.cs	22 Oct 2005 06:10:27 -0000	1.3
+++ TagPopup.cs	9 Nov 2005 03:35:59 -0000
@@ -12,7 +12,7 @@
 using System;
 
 public class TagPopup {
-	public void Activate (Gdk.EventButton eb, Tag tag)
+	public void Activate (Gdk.EventButton eb, Tag tag, Tag [] tags)
 	{
 		int count = MainWindow.Toplevel.SelectedIds ().Length;
 		Gtk.Menu popup_menu = new Gtk.Menu ();
@@ -24,19 +24,30 @@
 		
 		GtkUtil.MakeMenuSeparator (popup_menu);
 
-		GtkUtil.MakeMenuItem (popup_menu, Mono.Posix.Catalog.GetString ("Edit Tag"),
-				      new EventHandler (MainWindow.Toplevel.HandleEditSelectedTag), tag != null);
+		string editstr = String.Format (Mono.Posix.Catalog.GetString ("Edit Tag `{0}'"), tag.Name);
+		GtkUtil.MakeMenuItem (popup_menu, editstr, delegate { MainWindow.Toplevel.HandleEditSelectedTagWithTag (tag); }, true);
 
-		GtkUtil.MakeMenuItem (popup_menu, Mono.Posix.Catalog.GetString ("Delete Tag"),
-				      new EventHandler (MainWindow.Toplevel.HandleDeleteSelectedTagCommand), tag != null);
-				      
+		GtkUtil.MakeMenuItem (popup_menu,
+				      Mono.Posix.Catalog.GetPluralString ("Delete Tag", "Delete Tags", tags.Length),
+				      new EventHandler (MainWindow.Toplevel.HandleDeleteSelectedTagCommand), tags != null && tags.Length > 0);
+		
 		GtkUtil.MakeMenuSeparator (popup_menu);
 
-		GtkUtil.MakeMenuItem (popup_menu, Mono.Posix.Catalog.GetString ("Attach Tag To Selection"),
+		GtkUtil.MakeMenuItem (popup_menu,
+				      Mono.Posix.Catalog.GetPluralString ("Attach Tag To Selection", "Attach Tags To Selection", tags.Length),
 				      new EventHandler (MainWindow.Toplevel.HandleAttachTagCommand), count > 0);
 
-		GtkUtil.MakeMenuItem (popup_menu, Mono.Posix.Catalog.GetString ("Remove Tag From Selection"),
+		GtkUtil.MakeMenuItem (popup_menu,
+				      Mono.Posix.Catalog.GetPluralString ("Remove Tag From Selection", "Remove Tags From Selection", tags.Length),
 				      new EventHandler (MainWindow.Toplevel.HandleRemoveTagCommand), count > 0);
+
+		if (tags.Length > 1) {
+			GtkUtil.MakeMenuSeparator (popup_menu);
+
+			GtkUtil.MakeMenuItem (popup_menu, Mono.Posix.Catalog.GetString ("Merge Tags"),
+					      new EventHandler (MainWindow.Toplevel.HandleMergeTagsCommand), tags.Length > 1);
+
+		}
 
 		popup_menu.Popup (null, null, null, eb.Button, eb.Time);
 	}
Index: TagSelectionWidget.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagSelectionWidget.cs,v
retrieving revision 1.21
diff -u -r1.21 TagSelectionWidget.cs
--- TagSelectionWidget.cs	2 Nov 2005 05:35:57 -0000	1.21
+++ TagSelectionWidget.cs	9 Nov 2005 03:35:59 -0000
@@ -290,7 +290,7 @@
 	{
 		TreeIter root = TreeIter.Zero;
 		iter = TreeIter.Zero;
-	
+
 		bool valid = Model.GetIterFirst (out root);
 		
 		while (valid) {
@@ -399,12 +399,14 @@
 	
 	private void HandleTagCreated (Tag tag) 
 	{
-		TreeIter iter;
+		TreeIter iter = TreeIter.Zero;
 
-		if (TreeIterForTag (tag.Category, out iter)) {
-			// create dialog doesn't let you create a top level tag...
-			InsertInOrder (iter, false, tag);
-		}
+		if (tag.Category != tag_store.RootCategory)
+			TreeIterForTag (tag.Category, out iter);
+
+		InsertInOrder (iter,
+			       tag.Category.Name == tag_store.RootCategory.Name,
+			       tag);
 	}
 	
 	private void HandleTagChanged (Tag tag) 
Index: TagStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagStore.cs,v
retrieving revision 1.20
diff -u -r1.20 TagStore.cs
--- TagStore.cs	28 Oct 2005 19:52:30 -0000	1.20
+++ TagStore.cs	9 Nov 2005 03:35:59 -0000
@@ -268,6 +268,30 @@
 		}
 	}
 
+	public Tag GetTagByName (string name)
+	{
+		foreach (Tag t in this.item_cache.Values) {
+			if (t.Name.ToLower () == name.ToLower ())
+				return t;
+		}
+
+		return null;
+	}
+
+	public Tag [] GetTagsByNameStart (string s)
+	{
+		ArrayList l = new ArrayList ();
+		foreach (Tag t in this.item_cache.Values) {
+			if (t.Name.ToLower ().StartsWith (s.ToLower ()))
+				l.Add (t);
+		}
+
+		if (l.Count == 0)
+			return null;
+
+		return (Tag []) (l.ToArray (typeof (Tag)));
+	}
+
 	// In this store we keep all the items (i.e. the tags) in memory at all times.  This is
 	// mostly to simplify handling of the parent relationship between tags, but it also makes it
 	// a little bit faster.  We achieve this by passing "true" as the cache_is_immortal to our
Index: f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.115
diff -u -r1.115 f-spot.glade
--- f-spot.glade	7 Nov 2005 20:06:48 -0000	1.115
+++ f-spot.glade	9 Nov 2005 03:36:00 -0000
@@ -6735,7 +6735,7 @@
 		      <signal name="activate" handler="HandleSendMailCommand" last_modification_time="Mon, 07 Jun 2004 22:31:01 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image22">
+			<widget class="GtkImage" id="image24">
 			  <property name="visible">True</property>
 			  <property name="stock">gnome-stock-mail-fwd</property>
 			  <property name="icon_size">1</property>
@@ -7065,7 +7065,7 @@
 			      <property name="visible">True</property>
 			      <property name="label" translatable="yes">_Month</property>
 			      <property name="use_underline">True</property>
-			      <property name="active">True</property>
+			      <property name="active">False</property>
 			      <signal name="activate" handler="HandleArrangeByTime" last_modification_time="Fri, 20 Aug 2004 22:26:32 GMT"/>
 			    </widget>
 			  </child>
@@ -7405,7 +7405,90 @@
 		  <property name="spacing">0</property>
 
 		  <child>
-		    <placeholder/>
+		    <widget class="GtkHBox" id="tagbar">
+		      <property name="border_width">2</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">1</property>
+
+		      <child>
+			<widget class="GtkLabel" id="label160">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Tags: </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="tag_entry">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="has_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>
+			  <signal name="activate" handler="HandleTagEntryActivate" last_modification_time="Mon, 07 Nov 2005 20:18:18 GMT"/>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkButton" id="tag_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="HandleTagBarCloseButtonPressed" last_modification_time="Tue, 08 Nov 2005 01:22:39 GMT"/>
+
+			  <child>
+			    <widget class="GtkImage" id="image23">
+			      <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>
 
 		  <child>
@@ -7671,6 +7754,7 @@
 	  <property name="padding">0</property>
 	  <property name="expand">False</property>
 	  <property name="fill">False</property>
+	  <property name="pack_type">GTK_PACK_END</property>
 	</packing>
       </child>
     </widget>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]