Re: Tag typing.
- From: Nat Friedman <nat novell com>
- To: f-spot-list gnome org
- Subject: Re: Tag typing.
- Date: Thu, 10 Nov 2005 16:19:40 -0500
Here's v4 of the tag typing patch. I believe this will be the final
version before committing to CVS. A number of bugs are fixed in here,
and I added a ChangeLog entry.
The 't' behavior is enabled in here; I don't like it yet but I'm willing
to see if it grows on me. Aaron's enter-expansion patch is in here too.
If people could please test this and make sure there aren't any
lingering bugs before I commit, that would be appreciated. And of
course I need Larry's green light, too.
best,
Nat
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/f-spot/ChangeLog,v
retrieving revision 1.1112
diff -u -r1.1112 ChangeLog
--- ChangeLog 8 Nov 2005 18:25:10 -0000 1.1112
+++ ChangeLog 10 Nov 2005 21:18:24 -0000
@@ -1,3 +1,27 @@
+2005-11-10 Nat Friedman <nat novell com>
+
+ * src/MainWindow.cs: Added support for creating and applying tags
+ by typing them into a tagbar entry. Added support for merging
+ tags. Support for multiselection operations in the tag sidebar.
+ Handle photo deleting in the icon and photo views by catching the
+ keypress in the icon and photo view widgets, not as a menu
+ accelerator. Pressing delete in the tag treeview will now delete
+ the selected tags. Fixed several bugs.
+
+ * src/TagPopup.cs: Added support for merging tags. Added support
+ for multiselection tag actions.
+
+ * src/TagSelectionWidget.cs: Handle top-level tag creation.
+
+ * src/Db.cs: Made the item_cache protected so the TagStore
+ subclass can access it.
+
+ * src/TagStore.cs: Added GetTagByName and GetTagByNameStart, both
+ of which are case-insensitive.
+
+ * src/f-spot.glade: Remove the Delete accelerator for deleting
+ photos. Add the tag typing bar.
+
2005-11-08 Larry Ewing <lewing novell com>
* src/Loupe.cs: queue a resize iff the dimentions have changed so that the
Index: src/Db.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/Db.cs,v
retrieving revision 1.7
diff -u -r1.7 Db.cs
--- src/Db.cs 7 Oct 2005 21:35:39 -0000 1.7
+++ src/Db.cs 10 Nov 2005 21:18:24 -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: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.228
diff -u -r1.228 MainWindow.cs
--- src/MainWindow.cs 2 Nov 2005 08:33:16 -0000 1.228
+++ src/MainWindow.cs 10 Nov 2005 21:18:25 -0000
@@ -15,6 +15,7 @@
using LibGPhoto2;
public class MainWindow {
+
public static MainWindow Toplevel;
Db db;
@@ -83,6 +84,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;
@@ -173,6 +177,7 @@
tag_selection_widget.DragDataGet += HandleTagSelectionDragDataGet;
tag_selection_widget.DragDrop += HandleTagSelectionDragDrop;
tag_selection_widget.DragBegin += HandleTagSelectionDragBegin;
+ tag_selection_widget.KeyPressEvent += HandleTagSelectionKeyPress;
Gtk.Drag.SourceSet (tag_selection_widget, Gdk.ModifierType.Button1Mask | Gdk.ModifierType.Button3Mask,
tag_target_table, DragAction.Copy | DragAction.Move);
@@ -251,6 +256,7 @@
icon_view.DragMotion += HandleIconViewDragMotion;
icon_view.DragDrop += HandleIconViewDragDrop;
icon_view.DragDataReceived += HandleIconViewDragDataReceived;
+ icon_view.KeyPressEvent += HandleIconViewKeyPressEvent;
photo_view = new PhotoView (query, db.Photos);
photo_box.Add (photo_view);
@@ -260,6 +266,13 @@
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;
+ tag_entry.Changed += HandleTagEntryChanged;
+
Gtk.Drag.DestSet (photo_view, DestDefaults.All, tag_target_table,
DragAction.Copy | DragAction.Move);
@@ -273,6 +286,8 @@
UpdateMenus ();
main_window.ShowAll ();
+ tagbar.Hide ();
+
LoadPreference (Preferences.SHOW_TOOLBAR);
LoadPreference (Preferences.SHOW_SIDEBAR);
LoadPreference (Preferences.SHOW_TIMELINE);
@@ -455,7 +470,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 +519,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 +636,8 @@
break;
}
+
+ UpdateTagEntryFromSelection ();
}
#if SHOW_CALENDAR
@@ -789,6 +801,13 @@
args.RetVal = true;
}
+ void HandleIconViewKeyPressEvent (object sender, Gtk.KeyPressEventArgs args)
+ {
+ if (args.Event.Key == Gdk.Key.Delete) {
+ HandleRemoveCommand (sender, (EventArgs) args);
+ }
+ }
+
public void ImportUriList (UriList list)
{
ImportCommand command = new ImportCommand (main_window);
@@ -824,6 +843,8 @@
AttachTags (tag_selection_widget.TagHighlight (), SelectedIds());
else
AttachTags (tag_selection_widget.TagHighlight (), new int [] {item});
+
+ UpdateTagEntryFromSelection ();
}
break;
case (uint)TargetType.UriList:
@@ -851,7 +872,9 @@
info_box.Photo = CurrentPhoto;
if (info_display != null)
info_display.Photo = CurrentPhoto;
+
UpdateMenus ();
+ UpdateTagEntryFromSelection ();
}
void HandleDoubleClicked (IconView icon_view, int clicked_item)
@@ -870,6 +893,7 @@
if (info_display != null)
info_display.Photo = CurrentPhoto;
UpdateMenus ();
+ UpdateTagEntryFromSelection ();
}
void HandlePhotoViewKeyPressEvent (object sender, Gtk.KeyPressEventArgs args)
@@ -884,6 +908,10 @@
SetViewMode (ModeType.IconView);
args.RetVal = true;
break;
+ case Gdk.Key.Delete:
+ HandleRemoveCommand (sender, (EventArgs) args);
+ args.RetVal = true;
+ break;
default:
break;
}
@@ -960,6 +988,8 @@
foreach (int num in SelectedIds ()) {
AddTagExtended (num, new Tag [] {t});
}
+
+ UpdateTagEntryFromSelection ();
}
void HandleFindTagMenuSelected (Tag t)
@@ -973,6 +1003,8 @@
query.Photos [num].RemoveTag (t);
query.Commit (num);
}
+
+ UpdateTagEntryFromSelection ();
}
//
@@ -1338,16 +1370,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)
@@ -1685,15 +1772,24 @@
{
icon_view.Selection.Clear ();
}
-
+
+ public void HandleTagSelectionKeyPress (object sender, Gtk.KeyPressEventArgs args)
+ {
+ if (args.Event.Key == Gdk.Key.Delete)
+ HandleDeleteSelectedTagCommand (sender, (EventArgs) args);
+ }
+
public void HandleDeleteSelectedTagCommand (object sender, EventArgs args)
{
Tag [] tags = this.tag_selection_widget.TagHighlight ();
System.Array.Sort (tags, new TagRemoveComparer ());
- string header = Mono.Posix.Catalog.GetPluralString ("Delete the selected tag?",
- "Delete the {0} selected tags?",
- tags.Length);
+
+ string header;
+ if (tags.Length == 1)
+ header = String.Format (Mono.Posix.Catalog.GetString ("Delete tag \"{0}\"?"), tags [0].Name);
+ else
+ header = String.Format (Mono.Posix.Catalog.GetString ("Delete the {0} selected tags?"), tags.Length);
header = String.Format (header, tags.Length);
string msg = Mono.Posix.Catalog.GetString("If you delete a tag, all associations with photos are lost.");
@@ -1988,5 +2084,264 @@
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;
+
+ ClearTagCompletions ();
+ }
+
+ public void HandlePossibleTagTyping (object sender, Gtk.KeyPressEventArgs args)
+ {
+ 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 ();
+ tag_entry.GrabFocus ();
+ tag_entry.SelectRegion (-1, -1);
+ }
+
+ // "Activate" means the user pressed the enter key
+ public void HandleTagEntryActivate (object sender, EventArgs args)
+ {
+ string [] tagnames = GetTypedTagNames ();
+ int [] selected_photos = SelectedIds ();
+
+ if (selected_photos == null || tagnames == null)
+ return;
+
+ int sel_start, sel_end;
+ if (tag_entry.GetSelectionBounds (out sel_start, out sel_end) && tag_completion_index != -1) {
+ tag_entry.InsertText (", ", ref sel_end);
+ tag_entry.SelectRegion (-1, -1);
+ tag_entry.Position = sel_end + 2;
+ ClearTagCompletions ();
+ return;
+ }
+
+
+ // 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 selected_photos)
+ 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 selected_photos) {
+ 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.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.View.GrabFocus ();
+
+ ClearTagCompletions ();
+ }
+
+ 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;
+ } else
+ ClearTagCompletions ();
+ }
+
+ bool tag_ignore_changes = false;
+ public void HandleTagEntryChanged (object sender, EventArgs args)
+ {
+ if (tag_ignore_changes)
+ return;
+
+ ClearTagCompletions ();
+ }
+
+ int tag_completion_index = -1;
+ Tag [] tag_completions;
+ string tag_completion_typed_so_far;
+ int tag_completion_typed_position;
+ private void DoTagCompletion ()
+ {
+ 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;
+
+ string right_of_cursor = tag_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)
+ return;
+
+ tag_completion_typed_so_far = tag_entry.Text.Substring (last_comma + 1).TrimStart (new char [] {' '});
+ if (tag_completion_typed_so_far == null || tag_completion_typed_so_far.Length == 0)
+ return;
+
+ tag_completions = db.Tags.GetTagsByNameStart (tag_completion_typed_so_far);
+ if (tag_completions == null)
+ return;
+
+ tag_completion_index = 0;
+ }
+
+ 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;
+ tag_ignore_changes = false;
+
+ tag_entry.Position = tag_entry.Text.Length;
+ tag_entry.SelectRegion (tag_completion_typed_position, tag_entry.Text.Length);
+ }
+
+ private void ClearTagCompletions ()
+ {
+ tag_completion_index = -1;
+ tag_completions = null;
+ }
+
+
+ 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: src/TagPopup.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagPopup.cs,v
retrieving revision 1.3
diff -u -r1.3 TagPopup.cs
--- src/TagPopup.cs 22 Oct 2005 06:10:27 -0000 1.3
+++ src/TagPopup.cs 10 Nov 2005 21:18:25 -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: src/TagSelectionWidget.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagSelectionWidget.cs,v
retrieving revision 1.21
diff -u -r1.21 TagSelectionWidget.cs
--- src/TagSelectionWidget.cs 2 Nov 2005 05:35:57 -0000 1.21
+++ src/TagSelectionWidget.cs 10 Nov 2005 21:18:26 -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: src/TagStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagStore.cs,v
retrieving revision 1.20
diff -u -r1.20 TagStore.cs
--- src/TagStore.cs 28 Oct 2005 19:52:30 -0000 1.20
+++ src/TagStore.cs 10 Nov 2005 21:18:26 -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: src/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
--- src/f-spot.glade 7 Nov 2005 20:06:48 -0000 1.115
+++ src/f-spot.glade 10 Nov 2005 21:18:27 -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>
@@ -6885,7 +6885,6 @@
<property name="label" translatable="yes">_Remove From Catalog</property>
<property name="use_underline">True</property>
<signal name="activate" handler="HandleRemoveCommand" last_modification_time="Thu, 10 Jun 2004 03:21:10 GMT"/>
- <accelerator key="Delete" modifiers="0" signal="activate"/>
</widget>
</child>
@@ -7405,7 +7404,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 +7753,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]