[shotwell] use text-only section headers in sidebar (#718349)



commit d2fe363e32cf77d1c74b8046669d92beb6eb91d2
Author: Wolfgang Steitz <wsteitz gmail com>
Date:   Tue Mar 17 22:14:58 2015 +0100

    use text-only section headers in sidebar (#718349)

 po/POTFILES.in                                     |   10 +-
 src/camera/Branch.vala                             |    8 +-
 src/events/Branch.vala                             |   25 +++-
 src/events/EventsDirectoryPage.vala                |    2 +-
 src/folders/Branch.vala                            |    4 +-
 src/library/Branch.vala                            |  108 ++++++++++-
 ...FlaggedBranch.vala => FlaggedSidebarEntry.vala} |   43 ++---
 ...eueBranch.vala => ImportQueueSidebarEntry.vala} |   56 ++----
 ...portBranch.vala => LastImportSidebarEntry.vala} |   27 +--
 src/library/LibraryWindow.vala                     |   35 +---
 ...OfflineBranch.vala => OfflineSidebarEntry.vala} |   18 +--
 .../{TrashBranch.vala => TrashSidebarEntry.vala}   |    6 -
 src/library/mk/library.mk                          |   10 +-
 src/searches/Branch.vala                           |   12 +-
 src/sidebar/Entry.vala                             |    9 +
 src/sidebar/Tree.vala                              |  193 ++++++++++++++++----
 src/sidebar/common.vala                            |   39 ++++-
 src/tags/Branch.vala                               |   16 ++-
 18 files changed, 423 insertions(+), 198 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0f3a05e..84c6d92 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -157,17 +157,17 @@ src/folders/Branch.vala
 src/folders/Folders.vala
 src/folders/Page.vala
 src/library/Branch.vala
-src/library/FlaggedBranch.vala
+src/library/FlaggedSidebarEntry.vala
 src/library/FlaggedPage.vala
-src/library/ImportQueueBranch.vala
+src/library/ImportQueueSidebarEntry.vala
 src/library/ImportQueuePage.vala
-src/library/LastImportBranch.vala
+src/library/LastImportSidebarEntry.vala
 src/library/LastImportPage.vala
 src/library/Library.vala
 src/library/LibraryWindow.vala
-src/library/OfflineBranch.vala
+src/library/OfflineSidebarEntry.vala
 src/library/OfflinePage.vala
-src/library/TrashBranch.vala
+src/library/TrashSidebarEntry.vala
 src/library/TrashPage.vala
 src/main.vala
 src/photos/BmpSupport.vala
diff --git a/src/camera/Branch.vala b/src/camera/Branch.vala
index 43e787a..83f3f56 100644
--- a/src/camera/Branch.vala
+++ b/src/camera/Branch.vala
@@ -11,7 +11,7 @@ public class Camera.Branch : Sidebar.Branch {
         DiscoveredCamera, Camera.SidebarEntry>();
     
     public Branch() {
-        base (new Camera.Grouping(),
+        base (new Camera.Header(),
             Sidebar.Branch.Options.HIDE_IF_EMPTY | Sidebar.Branch.Options.AUTO_OPEN_ON_NEW_CHILD,
             camera_comparator);
         
@@ -80,9 +80,9 @@ public class Camera.Branch : Sidebar.Branch {
     }
 }
 
-public class Camera.Grouping : Sidebar.Grouping {
-    public Grouping() {
-        base (_("Cameras"), Camera.Branch.cameras_icon);
+public class Camera.Header : Sidebar.Header {
+    public Header() {
+        base (_("Cameras"));
     }
 }
 
diff --git a/src/events/Branch.vala b/src/events/Branch.vala
index 114f85b..1093411 100644
--- a/src/events/Branch.vala
+++ b/src/events/Branch.vala
@@ -19,11 +19,14 @@ public class Events.Branch : Sidebar.Branch {
         Event, Events.EventEntry>();
     private Events.UndatedDirectoryEntry undated_entry = new Events.UndatedDirectoryEntry();
     private Events.NoEventEntry no_event_entry = new Events.NoEventEntry();
+    private Events.MasterDirectoryEntry all_events_entry = new Events.MasterDirectoryEntry();
     
     public Branch() {
-        base (new Events.MasterDirectoryEntry(), Sidebar.Branch.Options.STARTUP_EXPAND_TO_FIRST_CHILD,
+        base (new Sidebar.Header(_("Events")), Sidebar.Branch.Options.STARTUP_EXPAND_TO_FIRST_CHILD,
             event_year_comparator);
         
+        graft(get_root(), all_events_entry);
+        
         // seed the branch
         foreach (DataObject object in Event.global.get_all())
             add_event((Event) object);
@@ -54,8 +57,12 @@ public class Events.Branch : Sidebar.Branch {
     internal static void terminate() {
     }
     
+    public bool is_user_renameable() {
+        return true;
+    }
+    
     public Events.MasterDirectoryEntry get_master_entry() {
-        return (Events.MasterDirectoryEntry) get_root();
+        return all_events_entry;
     }
     
     private static int event_year_comparator(Sidebar.Entry a, Sidebar.Entry b) {
@@ -79,6 +86,12 @@ public class Events.Branch : Sidebar.Branch {
         else if (b is Events.NoEventEntry)
             return -1;
         
+        // The All events entry should always appear on top
+        if (a is Events.MasterDirectoryEntry)
+            return -1;
+        else if (b is Events.MasterDirectoryEntry)
+            return 1;
+        
         if (!sort_ascending) {
             Sidebar.Entry swap = a;
             a = b;
@@ -300,7 +313,8 @@ public class Events.Branch : Sidebar.Branch {
         int event_year = event_tm.year + 1900;
         
         return find_first_child(get_root(), (entry) => {
-            if ((entry is Events.UndatedDirectoryEntry) || (entry is Events.NoEventEntry))
+            if ((entry is Events.UndatedDirectoryEntry) || (entry is Events.NoEventEntry) || 
+                 entry is Events.MasterDirectoryEntry)
                 return false;
             else
                 return ((Events.YearDirectoryEntry) entry).get_year() == event_year;
@@ -472,6 +486,10 @@ public class Events.EventEntry : Sidebar.SimplePageEntry, Sidebar.RenameableEntr
         return new EventPage(event);
     }
     
+    public bool is_user_renameable() {
+        return true;
+    }
+    
     public void rename(string new_name) {
         string? prepped = Event.prep_event_name(new_name);
         if (prepped != null)
@@ -495,6 +513,7 @@ public class Events.EventEntry : Sidebar.SimplePageEntry, Sidebar.RenameableEntr
     }
 }
 
+
 public class Events.NoEventEntry : Sidebar.SimplePageEntry {
     public NoEventEntry() {
     }
diff --git a/src/events/EventsDirectoryPage.vala b/src/events/EventsDirectoryPage.vala
index b624ab5..99601a0 100644
--- a/src/events/EventsDirectoryPage.vala
+++ b/src/events/EventsDirectoryPage.vala
@@ -227,7 +227,7 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
 }
 
 public class MasterEventsDirectoryPage : EventsDirectoryPage {
-    public const string NAME = _("Events");
+    public const string NAME = _("All Events");
     
     public MasterEventsDirectoryPage() {
         base (NAME, new EventDirectoryManager(), (Gee.Collection<Event>) Event.global.get_all());
diff --git a/src/folders/Branch.vala b/src/folders/Branch.vala
index 3271d26..0904e5c 100644
--- a/src/folders/Branch.vala
+++ b/src/folders/Branch.vala
@@ -136,9 +136,9 @@ public class Folders.Branch : Sidebar.Branch {
     }
 }
 
-private class Folders.Root : Sidebar.Grouping {
+private class Folders.Root : Sidebar.Header {
     public Root() {
-        base (_("Folders"), Folders.icon);
+        base (_("Folders"));
     }
 }
 
diff --git a/src/library/Branch.vala b/src/library/Branch.vala
index 425deff..0e875d2 100644
--- a/src/library/Branch.vala
+++ b/src/library/Branch.vala
@@ -4,23 +4,97 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class Library.Branch : Sidebar.RootOnlyBranch {
+public class Library.Branch : Sidebar.Branch {
+    private const string POSITION_DATA = "x-photos-entry-position";
+
+    public Library.PhotosEntry photos_entry { get; private set; }
+    public Library.FlaggedSidebarEntry flagged_entry { get; private set; }
+    public Library.LastImportSidebarEntry last_imported_entry { get; private set; }
+    public Library.ImportQueueSidebarEntry import_queue_entry { get; private set; }
+    public Library.OfflineSidebarEntry offline_entry { get; private set; }
+    public Library.TrashSidebarEntry trash_entry { get; private set; }
+    
+    // This lists the order of the library items in the sidebar. To re-order, simply move
+    // the item in this list to a new position. These numbers should *not* persist anywhere
+    // outside the app.
+    private enum EntryPosition {
+        PHOTOS,
+        FLAGGED,
+        LAST_IMPORTED,
+        IMPORT_QUEUE,
+        OFFLINE,
+        TRASH
+    }
+    
     public Branch() {
-        base (new Library.SidebarEntry());
+        base(new Sidebar.Header(_("Library")),
+            Sidebar.Branch.Options.STARTUP_OPEN_GROUPING, comparator);
+
+        photos_entry = new Library.PhotosEntry();
+        trash_entry = new Library.TrashSidebarEntry();
+        last_imported_entry = new Library.LastImportSidebarEntry();
+        flagged_entry = new Library.FlaggedSidebarEntry();
+        offline_entry = new Library.OfflineSidebarEntry();
+        import_queue_entry = new Library.ImportQueueSidebarEntry();
+
+        insert(photos_entry, EntryPosition.PHOTOS);
+        insert(trash_entry, EntryPosition.TRASH);
+
+        flagged_entry.visibility_changed.connect(on_flagged_visibility_changed);
+        on_flagged_visibility_changed();
+
+        last_imported_entry.visibility_changed.connect(on_last_imported_visibility_changed);
+        on_last_imported_visibility_changed();
+
+        import_queue_entry.visibility_changed.connect(on_import_queue_visibility_changed);
+        on_import_queue_visibility_changed();
+
+        offline_entry.visibility_changed.connect(on_offline_visibility_changed);
+        on_offline_visibility_changed();
     }
     
-    public Library.MainPage get_main_page() {
-        return (Library.MainPage) ((Library.SidebarEntry) get_root()).get_page();
+    private void insert(Sidebar.Entry entry, int position) {
+        entry.set_data<int>(POSITION_DATA, position);
+        graft(get_root(), entry);
+    }
+
+    private void on_flagged_visibility_changed() {
+        update_entry_visibility(flagged_entry, EntryPosition.FLAGGED);
+    }
+
+    private void on_last_imported_visibility_changed() {
+        update_entry_visibility(last_imported_entry, EntryPosition.LAST_IMPORTED);
+    }
+
+    private void on_import_queue_visibility_changed() {
+        update_entry_visibility(import_queue_entry, EntryPosition.IMPORT_QUEUE);
+    }
+
+    private void on_offline_visibility_changed() {
+        update_entry_visibility(offline_entry, EntryPosition.OFFLINE);
+    }
+
+    private void update_entry_visibility(Library.HideablePageEntry entry, int position) {
+        if (entry.visible) {
+            if (!has_entry(entry))
+                insert(entry, position);
+        } else if (has_entry(entry)) {
+            prune(entry);
+        }
+    }
+
+    private static int comparator(Sidebar.Entry a, Sidebar.Entry b) {
+        return a.get_data<int>(POSITION_DATA) - b.get_data<int>(POSITION_DATA);
     }
 }
 
-public class Library.SidebarEntry : Sidebar.SimplePageEntry {
+public class Library.PhotosEntry : Sidebar.SimplePageEntry {
     
-    public SidebarEntry() {
+    public PhotosEntry() {
     }
     
     public override string get_sidebar_name() {
-        return Library.MainPage.NAME;
+        return _("Photos");
     }
     
     public override string? get_sidebar_icon() {
@@ -32,6 +106,26 @@ public class Library.SidebarEntry : Sidebar.SimplePageEntry {
     }
 }
 
+public abstract class Library.HideablePageEntry : Sidebar.SimplePageEntry {
+    // container branch should listen to this signal
+    public signal void visibility_changed(bool visible);
+
+    private bool show_entry = false;
+    public bool visible {
+        get { return show_entry; }
+        set {
+            if (value == show_entry)
+                return;
+
+            show_entry = value;
+            visibility_changed(value);
+        }
+    }
+
+    public HideablePageEntry() {
+    }
+}
+
 public class Library.MainPage : CollectionPage {
     public const string NAME = _("Library");
     
diff --git a/src/library/FlaggedBranch.vala b/src/library/FlaggedSidebarEntry.vala
similarity index 79%
rename from src/library/FlaggedBranch.vala
rename to src/library/FlaggedSidebarEntry.vala
index 70f24d5..240aaf3 100644
--- a/src/library/FlaggedBranch.vala
+++ b/src/library/FlaggedSidebarEntry.vala
@@ -4,38 +4,19 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class Library.FlaggedBranch : Sidebar.RootOnlyBranch {
-    public FlaggedBranch() {
-        base (new Library.FlaggedSidebarEntry());
-        
+public class Library.FlaggedSidebarEntry : Library.HideablePageEntry, Sidebar.InternalDropTargetEntry {
+    public FlaggedSidebarEntry() {
         foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
             media_sources.flagged_contents_altered.connect(on_flagged_contents_altered);
         
-        set_show_branch(get_total_flagged() != 0);
+        visible = (get_total_flagged() != 0);
     }
     
-    ~FlaggedBranch() {
+    ~FlaggedSidebarEntry() {
         foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
             media_sources.flagged_contents_altered.disconnect(on_flagged_contents_altered);
-    }
-    
-    private void on_flagged_contents_altered() {
-        set_show_branch(get_total_flagged() != 0);
-    }
-    
-    private int get_total_flagged() {
-        int total = 0;
-        foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
-            total += media_sources.get_flagged().size;
-        
-        return total;
-    }
-}
-
-public class Library.FlaggedSidebarEntry : Sidebar.SimplePageEntry, Sidebar.InternalDropTargetEntry {
-    public FlaggedSidebarEntry() {
-    }
-    
+    } 
+       
     public override string get_sidebar_name() {
         return FlaggedPage.NAME;
     }
@@ -57,5 +38,17 @@ public class Library.FlaggedSidebarEntry : Sidebar.SimplePageEntry, Sidebar.Inte
     public bool internal_drop_received_arbitrary(Gtk.SelectionData data) {
         return false;
     }
+
+    private void on_flagged_contents_altered() {
+        visible = (get_total_flagged() != 0);
+    }
+    
+    private int get_total_flagged() {
+        int total = 0;
+        foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
+            total += media_sources.get_flagged().size;
+        
+        return total;
+    }
 }
 
diff --git a/src/library/ImportQueueBranch.vala b/src/library/ImportQueueSidebarEntry.vala
similarity index 61%
rename from src/library/ImportQueueBranch.vala
rename to src/library/ImportQueueSidebarEntry.vala
index b26f1fd..5d34ce2 100644
--- a/src/library/ImportQueueBranch.vala
+++ b/src/library/ImportQueueSidebarEntry.vala
@@ -4,35 +4,34 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class Library.ImportQueueBranch : Sidebar.RootOnlyBranch {
-    private Library.ImportQueueSidebarEntry entry;
-    
-    public ImportQueueBranch() {
-        // can't pass to base() an object that was allocated in declaration; see
-        // https://bugzilla.gnome.org/show_bug.cgi?id=646286
-        base (new Library.ImportQueueSidebarEntry());
-        
-        entry = (Library.ImportQueueSidebarEntry) get_root();
-        
+public class Library.ImportQueueSidebarEntry : Library.HideablePageEntry {
+    public ImportQueueSidebarEntry() {
         // only attach signals to the page when it's created
-        entry.page_created.connect(on_page_created);
-        entry.destroying_page.connect(on_destroying_page);
+        page_created.connect(on_page_created);
+        destroying_page.connect(on_destroying_page);
         
         // don't use entry.get_page() or get_queue_page() because (a) we don't want to
         // create the page during initialization, and (b) we know there's no import activity
         // at this moment
-        set_show_branch(false);
+        visible = false;
     }
     
-    ~ImportQueueBranch() {
-        entry.page_created.disconnect(on_page_created);
-        entry.destroying_page.disconnect(on_destroying_page);
+    public override string get_sidebar_name() {
+        return ImportQueuePage.NAME;
     }
     
-    public ImportQueuePage get_queue_page() {
-        return (ImportQueuePage) entry.get_page();
+    public override string? get_sidebar_icon() {
+        return Resources.ICON_IMPORTING;
     }
     
+    protected override Page create_page() {
+        return new ImportQueuePage();
+    }
+
+    private ImportQueuePage get_queue_page() {
+        return get_page() as ImportQueuePage;
+    }
+
     private void on_page_created() {
         get_queue_page().batch_added.connect(on_batch_added_or_removed);
         get_queue_page().batch_removed.connect(on_batch_added_or_removed);
@@ -44,31 +43,14 @@ public class Library.ImportQueueBranch : Sidebar.RootOnlyBranch {
     }
     
     private void on_batch_added_or_removed() {
-        set_show_branch(get_queue_page().get_batch_count() > 0);
+        visible = (get_queue_page().get_batch_count() > 0);
     }
     
     public void enqueue_and_schedule(BatchImport batch_import, bool allow_user_cancel) {
         // want to display the branch before passing to the page because this might result in the
         // page being created, and want it all hooked up in the tree prior to creating the page
-        set_show_branch(true);
+        visible = true;
         get_queue_page().enqueue_and_schedule(batch_import, allow_user_cancel);
     }
 }
 
-public class Library.ImportQueueSidebarEntry : Sidebar.SimplePageEntry {
-    public ImportQueueSidebarEntry() {
-    }
-    
-    public override string get_sidebar_name() {
-        return ImportQueuePage.NAME;
-    }
-    
-    public override string? get_sidebar_icon() {
-        return Resources.ICON_IMPORTING;
-    }
-    
-    protected override Page create_page() {
-        return new ImportQueuePage();
-    }
-}
-
diff --git a/src/library/LastImportBranch.vala b/src/library/LastImportSidebarEntry.vala
similarity index 62%
rename from src/library/LastImportBranch.vala
rename to src/library/LastImportSidebarEntry.vala
index 52e682e..3414130 100644
--- a/src/library/LastImportBranch.vala
+++ b/src/library/LastImportSidebarEntry.vala
@@ -4,34 +4,19 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class Library.LastImportBranch : Sidebar.RootOnlyBranch {
-    public LastImportBranch() {
-        base (new Library.LastImportSidebarEntry());
-        
+public class Library.LastImportSidebarEntry : Library.HideablePageEntry {
+    public LastImportSidebarEntry() {
         foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
             media_sources.import_roll_altered.connect(on_import_rolls_altered);
         
-        set_show_branch(MediaCollectionRegistry.get_instance().get_last_import_id() != null);
+        visible = (MediaCollectionRegistry.get_instance().get_last_import_id() != null);
     }
     
-    ~LastImportBranch() {
+    ~LastImportSidebarEntry() {
         foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
             media_sources.import_roll_altered.disconnect(on_import_rolls_altered);
     }
     
-    public Library.LastImportSidebarEntry get_main_entry() {
-        return (Library.LastImportSidebarEntry) get_root();
-    }
-    
-    private void on_import_rolls_altered() {
-        set_show_branch(MediaCollectionRegistry.get_instance().get_last_import_id() != null);
-    }
-}
-
-public class Library.LastImportSidebarEntry : Sidebar.SimplePageEntry {
-    public LastImportSidebarEntry() {
-    }
-    
     public override string get_sidebar_name() {
         return LastImportPage.NAME;
     }
@@ -43,5 +28,9 @@ public class Library.LastImportSidebarEntry : Sidebar.SimplePageEntry {
     protected override Page create_page() {
         return new LastImportPage();
     }
+
+    private void on_import_rolls_altered() {
+        visible = (MediaCollectionRegistry.get_instance().get_last_import_id() != null);
+    }
 }
 
diff --git a/src/library/LibraryWindow.vala b/src/library/LibraryWindow.vala
index 5ff41c9..a756436 100644
--- a/src/library/LibraryWindow.vala
+++ b/src/library/LibraryWindow.vala
@@ -42,16 +42,11 @@ public class LibraryWindow : AppWindow {
     // outside the app.
     private enum SidebarRootPosition {
         LIBRARY,
-        FLAGGED,
-        LAST_IMPORTED,
         CAMERAS,
-        IMPORT_QUEUE,
         SAVED_SEARCH,
         EVENTS,
         FOLDERS,
-        TAGS,
-        TRASH,
-        OFFLINE
+        TAGS
     }
     
     public enum TargetType {
@@ -114,12 +109,7 @@ public class LibraryWindow : AppWindow {
     private Library.Branch library_branch = new Library.Branch();
     private Tags.Branch tags_branch = new Tags.Branch();
     private Folders.Branch folders_branch = new Folders.Branch();
-    private Library.TrashBranch trash_branch = new Library.TrashBranch();
     private Events.Branch events_branch = new Events.Branch();
-    private Library.OfflineBranch offline_branch = new Library.OfflineBranch();
-    private Library.FlaggedBranch flagged_branch = new Library.FlaggedBranch();
-    private Library.LastImportBranch last_import_branch = new Library.LastImportBranch();
-    private Library.ImportQueueBranch import_queue_branch = new Library.ImportQueueBranch();
     private Camera.Branch camera_branch = new Camera.Branch();
     private Searches.Branch saved_search_branch = new Searches.Branch();
     private bool page_switching_enabled = true;
@@ -172,12 +162,7 @@ public class LibraryWindow : AppWindow {
         sidebar_tree.graft(library_branch, SidebarRootPosition.LIBRARY);
         sidebar_tree.graft(tags_branch, SidebarRootPosition.TAGS);
         sidebar_tree.graft(folders_branch, SidebarRootPosition.FOLDERS);
-        sidebar_tree.graft(trash_branch, SidebarRootPosition.TRASH);
         sidebar_tree.graft(events_branch, SidebarRootPosition.EVENTS);
-        sidebar_tree.graft(offline_branch, SidebarRootPosition.OFFLINE);
-        sidebar_tree.graft(flagged_branch, SidebarRootPosition.FLAGGED);
-        sidebar_tree.graft(last_import_branch, SidebarRootPosition.LAST_IMPORTED);
-        sidebar_tree.graft(import_queue_branch, SidebarRootPosition.IMPORT_QUEUE);
         sidebar_tree.graft(camera_branch, SidebarRootPosition.CAMERAS);
         sidebar_tree.graft(saved_search_branch, SidebarRootPosition.SAVED_SEARCH);
         
@@ -207,7 +192,7 @@ public class LibraryWindow : AppWindow {
         menubar.no_show_all = true;
         
         // create the main layout & start at the Library page
-        create_layout(library_branch.get_main_page());
+        create_layout(library_branch.photos_entry.get_page());
         
         // settings that should persist between sessions
         load_configuration();
@@ -882,7 +867,7 @@ public class LibraryWindow : AppWindow {
     }
 
     public void enqueue_batch_import(BatchImport batch_import, bool allow_user_cancel) {
-        import_queue_branch.enqueue_and_schedule(batch_import, allow_user_cancel);
+        library_branch.import_queue_entry.enqueue_and_schedule(batch_import, allow_user_cancel);
     }
     
     private void import_reporter(ImportManifest manifest) {
@@ -1028,7 +1013,7 @@ public class LibraryWindow : AppWindow {
     }
     
     public void switch_to_library_page() {
-        switch_to_page(library_branch.get_main_page());
+        switch_to_page(library_branch.photos_entry.get_page());
     }
     
     public void switch_to_event(Event event) {
@@ -1065,7 +1050,7 @@ public class LibraryWindow : AppWindow {
     }
     
     public void switch_to_import_queue_page() {
-        switch_to_page(import_queue_branch.get_queue_page());
+        switch_to_page(library_branch.import_queue_entry.get_page());
     }
     
     private void on_camera_added(DiscoveredCamera camera) {
@@ -1440,7 +1425,7 @@ public class LibraryWindow : AppWindow {
     private void on_destroying_page(Sidebar.PageRepresentative entry, Page page) {
         // if page is the current page, switch to fallback before destroying
         if (page == get_current_page())
-            switch_to_page(library_branch.get_main_page());
+            switch_to_page(library_branch.photos_entry.get_page());
         
         remove_from_notebook(page);
         
@@ -1458,9 +1443,11 @@ public class LibraryWindow : AppWindow {
         // if the currently selected item is removed, want to jump to fallback page (which
         // depends on the item that was selected)
         
+        Library.LastImportSidebarEntry last_import_entry = library_branch.last_imported_entry;
+        
         // Importing... -> Last Import (if available)
-        if (selectable is Library.ImportQueueSidebarEntry && last_import_branch.get_show_branch()) {
-            switch_to_page(last_import_branch.get_main_entry().get_page());
+        if (selectable is Library.ImportQueueSidebarEntry && last_import_entry.visible) {
+            switch_to_page(last_import_entry.get_page());
             
             return;
         }
@@ -1480,7 +1467,7 @@ public class LibraryWindow : AppWindow {
         }
         
         // basic all-around default: jump to the Library page
-        switch_to_page(library_branch.get_main_page());
+        switch_to_page(library_branch.photos_entry.get_page());
     }
     
     private void subscribe_for_basic_information(Page page) {
diff --git a/src/library/OfflineBranch.vala b/src/library/OfflineSidebarEntry.vala
similarity index 78%
rename from src/library/OfflineBranch.vala
rename to src/library/OfflineSidebarEntry.vala
index ab2ea90..34c09a0 100644
--- a/src/library/OfflineBranch.vala
+++ b/src/library/OfflineSidebarEntry.vala
@@ -4,23 +4,22 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class Library.OfflineBranch : Sidebar.RootOnlyBranch {
-    public OfflineBranch() {
-        base (new Library.OfflineSidebarEntry());
+public class Library.OfflineSidebarEntry : Library.HideablePageEntry {
+    public OfflineSidebarEntry() {
         
         foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
             media_sources.offline_contents_altered.connect(on_offline_contents_altered);
         
-        set_show_branch(get_total_offline() != 0);
+        visible = (get_total_offline() != 0);
     }
-    
-    ~OfflineBranch() {
+
+    ~OfflineSidebarEntry() {
         foreach (MediaSourceCollection media_sources in MediaCollectionRegistry.get_instance().get_all())
             media_sources.trashcan_contents_altered.disconnect(on_offline_contents_altered);
     }
     
     private void on_offline_contents_altered() {
-        set_show_branch(get_total_offline() != 0);
+        visible = (get_total_offline() != 0);
     }
     
     private int get_total_offline() {
@@ -30,11 +29,6 @@ public class Library.OfflineBranch : Sidebar.RootOnlyBranch {
         
         return total;
     }
-}
-
-public class Library.OfflineSidebarEntry : Sidebar.SimplePageEntry {
-    public OfflineSidebarEntry() {
-    }
     
     public override string get_sidebar_name() {
         return OfflinePage.NAME;
diff --git a/src/library/TrashBranch.vala b/src/library/TrashSidebarEntry.vala
similarity index 92%
rename from src/library/TrashBranch.vala
rename to src/library/TrashSidebarEntry.vala
index 5710211..69412b7 100644
--- a/src/library/TrashBranch.vala
+++ b/src/library/TrashSidebarEntry.vala
@@ -4,12 +4,6 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class Library.TrashBranch : Sidebar.RootOnlyBranch {
-    public TrashBranch() {
-        base (new Library.TrashSidebarEntry());
-    }
-}
-
 public class Library.TrashSidebarEntry : Sidebar.SimplePageEntry, Sidebar.InternalDropTargetEntry {
     
     public TrashSidebarEntry() {
diff --git a/src/library/mk/library.mk b/src/library/mk/library.mk
index b4ab790..dc6201f 100644
--- a/src/library/mk/library.mk
+++ b/src/library/mk/library.mk
@@ -13,11 +13,11 @@ UNIT_DIR := library
 UNIT_FILES := \
        LibraryWindow.vala \
        Branch.vala \
-       TrashBranch.vala \
-       OfflineBranch.vala \
-       FlaggedBranch.vala \
-       LastImportBranch.vala \
-       ImportQueueBranch.vala \
+        TrashSidebarEntry.vala \
+        OfflineSidebarEntry.vala \
+        FlaggedSidebarEntry.vala \
+        LastImportSidebarEntry.vala \
+        ImportQueueSidebarEntry.vala \
        FlaggedPage.vala \
        ImportQueuePage.vala \
        LastImportPage.vala \
diff --git a/src/searches/Branch.vala b/src/searches/Branch.vala
index e4b1968..00a9ea7 100644
--- a/src/searches/Branch.vala
+++ b/src/searches/Branch.vala
@@ -9,7 +9,7 @@ public class Searches.Branch : Sidebar.Branch {
         new Gee.HashMap<SavedSearch, Searches.SidebarEntry>();
     
     public Branch() {
-        base (new Searches.Grouping(),
+        base (new Searches.Header(),
             Sidebar.Branch.Options.HIDE_IF_EMPTY
                 | Sidebar.Branch.Options.AUTO_OPEN_ON_NEW_CHILD
                 | Sidebar.Branch.Options.STARTUP_EXPAND_TO_FIRST_CHILD,
@@ -60,12 +60,12 @@ public class Searches.Branch : Sidebar.Branch {
     }
 }
 
-public class Searches.Grouping : Sidebar.Grouping, Sidebar.Contextable {
+public class Searches.Header : Sidebar.Header, Sidebar.Contextable {
     private Gtk.UIManager ui = new Gtk.UIManager();
     private Gtk.Menu? context_menu = null;
     
-    public Grouping() {
-        base (_("Saved Searches"), "find");
+    public Header() {
+        base (_("Saved Searches"));
         setup_context_menu();
     }
     
@@ -134,6 +134,10 @@ public class Searches.SidebarEntry : Sidebar.SimplePageEntry, Sidebar.Renameable
         return new SavedSearchPage(search);
     }
     
+    public bool is_user_renameable() {
+        return true;
+    }
+    
     public void rename(string new_name) {
         if (!SavedSearchTable.get_instance().exists(new_name))
             AppWindow.get_command_manager().execute(new RenameSavedSearchCommand(search, new_name));
diff --git a/src/sidebar/Entry.vala b/src/sidebar/Entry.vala
index 090c524..5a84f74 100644
--- a/src/sidebar/Entry.vala
+++ b/src/sidebar/Entry.vala
@@ -47,6 +47,15 @@ public interface Sidebar.RenameableEntry : Sidebar.Entry {
     public signal void sidebar_name_changed(string name);
     
     public abstract void rename(string new_name);
+    
+    // Return true to allow the user to rename the sidebar entry in the UI.
+    public abstract bool is_user_renameable();
+}
+
+public interface Sidebar.EmphasizableEntry : Sidebar.Entry {
+    public signal void is_emphasized_changed(bool emphasized);
+    
+    public abstract bool is_emphasized();
 }
 
 public interface Sidebar.DestroyableEntry : Sidebar.Entry {
diff --git a/src/sidebar/Tree.vala b/src/sidebar/Tree.vala
index e2d1879..a020b18 100644
--- a/src/sidebar/Tree.vala
+++ b/src/sidebar/Tree.vala
@@ -37,8 +37,7 @@ public class Sidebar.Tree : Gtk.TreeView {
     private class RootWrapper : EntryWrapper {
         public int root_position;
         
-        public RootWrapper(Gtk.TreeModel model, Sidebar.Entry entry, Gtk.TreePath path, int root_position) 
-            requires (root_position >= 0) {
+        public RootWrapper(Gtk.TreeModel model, Sidebar.Entry entry, Gtk.TreePath path, int root_position) {
             base (model, entry, path);
             
             this.root_position = root_position;
@@ -71,8 +70,11 @@ public class Sidebar.Tree : Gtk.TreeView {
     private bool mask_entry_selected_signal = false;
     private weak EntryWrapper? selected_wrapper = null;
     private Gtk.Menu? default_context_menu = null;
+    private bool expander_called_manually = false;
+    private int expander_special_count = 0;
     private bool is_internal_drag_in_progress = false;
     private Sidebar.Entry? internal_drag_source_entry = null;
+    private Gtk.TreeRowReference? old_path_ref = null;
     
     public signal void entry_selected(Sidebar.SelectableEntry selectable);
     
@@ -99,6 +101,7 @@ public class Sidebar.Tree : Gtk.TreeView {
         icon_renderer.follow_state = true;
         text_column.pack_start(icon_renderer, false);
         text_column.add_attribute(icon_renderer, "icon_name", Columns.ICON);
+        text_column.set_cell_data_func(icon_renderer, icon_renderer_function);
         text_renderer = new Gtk.CellRendererText();
         text_renderer.ellipsize = Pango.EllipsizeMode.END;
         text_renderer.editing_canceled.connect(on_editing_canceled);
@@ -126,6 +129,9 @@ public class Sidebar.Tree : Gtk.TreeView {
         selection.set_mode(Gtk.SelectionMode.BROWSE);
         selection.set_select_function(on_selection);
         
+        test_expand_row.connect(on_toggle_row);
+        test_collapse_row.connect(on_toggle_row);
+        
         // It Would Be Nice if the target entries and actions were gleaned by querying each 
         // Sidebar.Entry as it was added, but that's a tad too complicated for our needs
         // currently
@@ -152,6 +158,14 @@ public class Sidebar.Tree : Gtk.TreeView {
         text_renderer.editing_started.disconnect(on_editing_started);
     }
     
+    public void icon_renderer_function(Gtk.CellLayout layout, Gtk.CellRenderer renderer, Gtk.TreeModel 
model, Gtk.TreeIter iter) {
+        EntryWrapper? wrapper = get_wrapper_at_iter(iter);
+        if (wrapper == null) {
+            return;
+        }
+        renderer.visible = !(wrapper.entry is Sidebar.Header);
+    }
+    
     private void on_drag_begin(Gdk.DragContext ctx) {
         is_internal_drag_in_progress = true;
     }
@@ -261,41 +275,72 @@ public class Sidebar.Tree : Gtk.TreeView {
     public bool is_selected(Sidebar.Entry entry) {
         EntryWrapper? wrapper = get_wrapper(entry);
         
-        return (wrapper != null) ? get_selection().path_is_selected(wrapper.get_path()) : false;
+        // Even though get_selection() does not report its return type as nullable, it can be null
+        // if the window has been destroyed.
+        Gtk.TreeSelection selection = get_selection();
+        if (selection == null)
+            return false;
+        
+        return (wrapper != null) ? selection.path_is_selected(wrapper.get_path()) : false;
     }
     
     public bool is_any_selected() {
         return get_selection().count_selected_rows() != 0;
     }
-    
+
     private Gtk.TreePath? get_selected_path() {
         Gtk.TreeModel model;
-        GLib.List<Gtk.TreePath> rows = get_selection().get_selected_rows(out model);
+        Gtk.TreeSelection? selection = get_selection();
+        if (selection == null){
+            return null;
+        }
+        GLib.List<Gtk.TreePath> rows = selection.get_selected_rows(out model);
         assert(rows.length() == 0 || rows.length() == 1);
-        
+
         return rows.length() != 0 ? rows.nth_data(0) : null;
     }
+
+    private string get_name_for_entry(Sidebar.Entry entry) {
+        string name = guarded_markup_escape_text(entry.get_sidebar_name());
+        
+        Sidebar.EmphasizableEntry? emphasizable_entry = entry as Sidebar.EmphasizableEntry;
+        if (emphasizable_entry != null && emphasizable_entry.is_emphasized())
+            name = "<b>%s</b>".printf(name);
+        
+        return name;
+    }
+    
+    public virtual bool accept_cursor_changed() {
+        return true;
+    }
     
     public override void cursor_changed() {
         Gtk.TreePath? path = get_selected_path();
         if (path == null) {
             if (base.cursor_changed != null)
                 base.cursor_changed();
-            
             return;
         }
         
         EntryWrapper? wrapper = get_wrapper_at_path(path);
-      
-        selected_wrapper = wrapper;
         
-        if (editing_disabled == 0 && wrapper != null)
-            text_renderer.editable = wrapper.entry is Sidebar.RenameableEntry;
-        
-        if (wrapper != null && !mask_entry_selected_signal) {
-            Sidebar.SelectableEntry? selectable = wrapper.entry as Sidebar.SelectableEntry;
-            if (selectable != null)
-                entry_selected(selectable);
+        if (selected_wrapper != wrapper) {
+            EntryWrapper old_wrapper = selected_wrapper;
+            selected_wrapper = wrapper;
+            
+            if (editing_disabled == 0 && wrapper != null && wrapper.entry is Sidebar.RenameableEntry)
+                text_renderer.editable = ((Sidebar.RenameableEntry) wrapper.entry).is_user_renameable();
+            
+            if (wrapper != null && !mask_entry_selected_signal) {
+                Sidebar.SelectableEntry? selectable = wrapper.entry as Sidebar.SelectableEntry;
+                if (selectable != null) {
+                    if (accept_cursor_changed()) {
+                        entry_selected(selectable);
+                    } else {
+                        place_cursor(old_wrapper.entry, true);
+                    }
+                }
+            }
         }
         
         if (base.cursor_changed != null)
@@ -311,11 +356,14 @@ public class Sidebar.Tree : Gtk.TreeView {
         Gtk.TreePath? path = get_selected_path();
         if (path != null && editing_disabled > 0 && --editing_disabled == 0) {
             EntryWrapper? wrapper = get_wrapper_at_path(path);
-            text_renderer.editable = (wrapper != null && (wrapper.entry is Sidebar.RenameableEntry));
+            if (wrapper != null && (wrapper.entry is Sidebar.RenameableEntry))
+                text_renderer.editable = ((Sidebar.RenameableEntry) wrapper.entry).
+                    is_user_renameable();
         }
     }
     
     public void toggle_branch_expansion(Gtk.TreePath path, bool expand_all) {
+        expander_called_manually = true;
         if (is_row_expanded(path))
             collapse_row(path);
         else
@@ -323,6 +371,7 @@ public class Sidebar.Tree : Gtk.TreeView {
     }
     
     public bool expand_to_entry(Sidebar.Entry entry) {
+        expander_called_manually = true;
         EntryWrapper? wrapper = get_wrapper(entry);
         if (wrapper == null)
             return false;
@@ -333,6 +382,7 @@ public class Sidebar.Tree : Gtk.TreeView {
     }
     
     public void expand_to_first_child(Sidebar.Entry entry) {
+        expander_called_manually = true;
         EntryWrapper? wrapper = get_wrapper(entry);
         if (wrapper == null)
             return;
@@ -436,7 +486,7 @@ public class Sidebar.Tree : Gtk.TreeView {
         assert(!entry_map.has_key(entry));
         entry_map.set(entry, wrapper);
         
-        store.set(assoc_iter, Columns.NAME, guarded_markup_escape_text(entry.get_sidebar_name()));
+        store.set(assoc_iter, Columns.NAME, get_name_for_entry(entry));
         store.set(assoc_iter, Columns.TOOLTIP, guarded_markup_escape_text(entry.get_sidebar_tooltip()));
         store.set(assoc_iter, Columns.WRAPPER, wrapper);
         load_entry_icons(assoc_iter);
@@ -449,6 +499,10 @@ public class Sidebar.Tree : Gtk.TreeView {
             pageable.page_created.connect(on_sidebar_page_created);
             pageable.destroying_page.connect(on_sidebar_destroying_page);
         }
+
+        Sidebar.EmphasizableEntry? emphasizable = entry as Sidebar.EmphasizableEntry;
+        if (emphasizable != null)
+            emphasizable.is_emphasized_changed.connect(on_is_emphasized_changed);
         
         Sidebar.RenameableEntry? renameable = entry as Sidebar.RenameableEntry;
         if (renameable != null)
@@ -466,7 +520,7 @@ public class Sidebar.Tree : Gtk.TreeView {
         EntryWrapper new_wrapper = new EntryWrapper(store, entry, store.get_path(new_iter));
         entry_map.set(entry, new_wrapper);
         
-        store.set(new_iter, Columns.NAME, guarded_markup_escape_text(entry.get_sidebar_name()));
+        store.set(new_iter, Columns.NAME, get_name_for_entry(entry));
         store.set(new_iter, Columns.TOOLTIP, guarded_markup_escape_text(entry.get_sidebar_tooltip()));
         store.set(new_iter, Columns.WRAPPER, new_wrapper);
         load_entry_icons(new_iter);
@@ -558,6 +612,10 @@ public class Sidebar.Tree : Gtk.TreeView {
         if (renameable != null)
             renameable.sidebar_name_changed.disconnect(on_sidebar_name_changed);
         
+        Sidebar.EmphasizableEntry? emphasizable = entry as Sidebar.EmphasizableEntry;
+        if (emphasizable != null)
+            emphasizable.is_emphasized_changed.disconnect(on_is_emphasized_changed);
+        
         bool removed = entry_map.unset(entry);
         assert(removed);
     }
@@ -692,20 +750,28 @@ public class Sidebar.Tree : Gtk.TreeView {
         
         store.set(wrapper.get_iter(), Columns.ICON, icon);
     }
+
+    private void rename_entry(Sidebar.Entry entry) {
+        EntryWrapper? wrapper = get_wrapper(entry);
+        assert(wrapper != null);
+        
+        store.set(wrapper.get_iter(), Columns.NAME, get_name_for_entry(entry));
+    }
+    
+    private void on_sidebar_name_changed(Sidebar.Entry entry, string name) {
+        rename_entry(entry);
+    }
     
     private void on_sidebar_page_created(Sidebar.PageRepresentative entry, Page page) {
         page_created(entry, page);
     }
     
-    private void on_sidebar_destroying_page(Sidebar.PageRepresentative entry, Page page) {
-        destroying_page(entry, page);
+    private void on_is_emphasized_changed(Sidebar.EmphasizableEntry entry, bool is_emphasized) {
+        rename_entry(entry);
     }
     
-    private void on_sidebar_name_changed(Sidebar.RenameableEntry entry, string name) {
-        EntryWrapper? wrapper = get_wrapper(entry);
-        assert(wrapper != null);
-        
-        store.set(wrapper.get_iter(), Columns.NAME, guarded_markup_escape_text(name));
+    private void on_sidebar_destroying_page(Sidebar.PageRepresentative entry, Page page) {
+        destroying_page(entry, page);
     }
     
     private void load_entry_icons(Gtk.TreeIter iter) {
@@ -799,6 +865,42 @@ public class Sidebar.Tree : Gtk.TreeView {
         return true;
     }
     
+    public bool on_toggle_row(Gtk.TreeIter iter, Gtk.TreePath path) {
+        // Determine whether to allow the row to toggle
+        EntryWrapper? wrapper = get_wrapper_at_iter(iter);
+        if (wrapper == null) {
+            return false; // don't affect things
+        }
+        
+        // Most of the time, only allow manual toggles
+        bool should_allow_toggle = expander_called_manually;
+        
+        // Cancel out the manual flag
+        expander_called_manually = false;
+        
+        // If we are an expanded parent entry with content
+        if (is_row_expanded(path) && store.iter_has_child(iter) && wrapper.entry is Sidebar.SelectableEntry) 
{
+            // We are taking a special action
+            expander_special_count++;
+            if (expander_special_count == 1) {
+                // Workaround that prevents arrows from double-toggling
+                return true;
+            } else {
+                // Toggle only if non-manual, as opposed to the usual behavior
+                should_allow_toggle = !should_allow_toggle;
+            }
+        } else {
+            // Reset the special behavior count
+            expander_special_count = 0;
+        }
+        
+        if (should_allow_toggle) {
+            return false;
+        }
+        // Prevent branch expansion toggle
+        return true;
+    }
+    
     public override bool button_press_event(Gdk.EventButton event) {
         Gtk.TreePath? path = get_path_from_event(event);
 
@@ -813,19 +915,29 @@ public class Sidebar.Tree : Gtk.TreeView {
                 popup_context_menu(path, event);
             else
                 popup_default_context_menu(event);
-        } else if (event.button == 1 && event.type == Gdk.EventType.2BUTTON_PRESS) {
-            // double left click
-            if (path != null) {
+        } else if (event.button == 1 && event.type == Gdk.EventType.BUTTON_PRESS) {
+            if (path == null) {
+                old_path_ref = null;
+                return base.button_press_event(event);
+            }
+            
+            EntryWrapper? wrapper = get_wrapper_at_path(path);
+            
+            if (wrapper == null) {
+                old_path_ref = null;
+                return base.button_press_event(event);
+            }
+            
+            // Enable single click to toggle tree entries (bug 4985)
+            if (wrapper.entry is Sidebar.ExpandableEntry
+                || wrapper.entry is Sidebar.InternalDropTargetEntry) {
+                // all labels are InternalDropTargetEntries
                 toggle_branch_expansion(path, false);
-                
-                if (can_rename_path(path))
-                    return false;
             }
-        } else if (event.button == 1 && event.type == Gdk.EventType.BUTTON_PRESS) {
+            
             // Is this a click on an already-highlighted tree item?
-            Gtk.TreePath? cursor_path = null;
-            get_cursor(out cursor_path, null);
-            if ((cursor_path != null) && (cursor_path.compare(path) == 0)) {
+            if ((old_path_ref != null) && (old_path_ref.get_path() != null)
+                && (old_path_ref.get_path().compare(path) == 0)) {
                 // yes, don't allow single-click editing, but 
                 // pass the event on for dragging.
                 text_renderer.editable = false;
@@ -834,9 +946,13 @@ public class Sidebar.Tree : Gtk.TreeView {
             
             // Got click on different tree item, make sure it is editable
             // if it needs to be.
-            if (path != null && get_wrapper_at_path(path).entry is Sidebar.RenameableEntry) {
+            if (wrapper.entry is Sidebar.RenameableEntry &&
+                ((Sidebar.RenameableEntry) wrapper.entry).is_user_renameable()) {
                 text_renderer.editable = true;
             }
+            
+            // Remember what tree item is highlighted for next time.
+            old_path_ref = new Gtk.TreeRowReference(store, path);
         }
 
         return base.button_press_event(event);
@@ -1026,6 +1142,9 @@ public class Sidebar.Tree : Gtk.TreeView {
         if (renameable == null)
             return false;
         
+        if (wrapper.entry is Sidebar.Header)
+            return false;
+        
         get_selection().select_path(path);
         
         return true;
diff --git a/src/sidebar/common.vala b/src/sidebar/common.vala
index d698069..0f1bc05 100644
--- a/src/sidebar/common.vala
+++ b/src/sidebar/common.vala
@@ -5,13 +5,26 @@
  */
 
 // A simple grouping Entry that is only expandable
-public class Sidebar.Grouping : Object, Sidebar.Entry, Sidebar.ExpandableEntry {
+public class Sidebar.Grouping : Object, Sidebar.Entry, Sidebar.ExpandableEntry,
+    Sidebar.RenameableEntry {
+    
     private string name;
+    private string? tooltip;
     private string? icon;
     
-    public Grouping(string name, string? icon) {
+    public Grouping(string name, string? icon, string? tooltip = null) {
         this.name = name;
         this.icon = icon;
+        this.tooltip = tooltip;
+    }
+    
+    public void rename(string name) {
+        this.name = name;
+        sidebar_name_changed(name);
+    }
+    
+    public bool is_user_renameable() {
+        return false;
     }
     
     public string get_sidebar_name() {
@@ -19,7 +32,7 @@ public class Sidebar.Grouping : Object, Sidebar.Entry, Sidebar.ExpandableEntry {
     }
     
     public string? get_sidebar_tooltip() {
-        return name;
+        return tooltip;
     }
     
     public string? get_sidebar_icon() {
@@ -97,6 +110,26 @@ public class Sidebar.RootOnlyBranch : Sidebar.Branch {
     }
 }
 
+/**
+ * A header is an entry that is visually distinguished from its children. Bug 6397 recommends
+ * headers to appear bolded and without any icons. To prevent the icons from rendering, we set the
+ * icons to null in the base class @see Sidebar.Grouping. But we also go a step further by
+ * using a custom cell_data_function (@see Sidebar.Tree::icon_renderer_function) which ensures that
+ * header icons won't be rendered. This approach avoids the blank icon spacing issues.
+ */
+public class Sidebar.Header : Sidebar.Grouping, Sidebar.EmphasizableEntry {
+    private bool emphasized;
+    
+    public Header(string name, bool emphasized = true) {
+        base(name, null);
+        this.emphasized = emphasized;
+    }
+    
+    public bool is_emphasized() {
+        return emphasized;
+    }
+}
+
 public interface Sidebar.Contextable : Object {
     // Return null if the context menu should not be invoked for this event
     public abstract Gtk.Menu? get_sidebar_context_menu(Gdk.EventButton? event);
diff --git a/src/tags/Branch.vala b/src/tags/Branch.vala
index 8ea1293..e68b2b1 100644
--- a/src/tags/Branch.vala
+++ b/src/tags/Branch.vala
@@ -8,7 +8,7 @@ public class Tags.Branch : Sidebar.Branch {
     private Gee.HashMap<Tag, Tags.SidebarEntry> entry_map = new Gee.HashMap<Tag, Tags.SidebarEntry>();
     
     public Branch() {
-        base (new Tags.Grouping(),
+        base (new Tags.Header(),
             Sidebar.Branch.Options.HIDE_IF_EMPTY
                 | Sidebar.Branch.Options.AUTO_OPEN_ON_NEW_CHILD
                 | Sidebar.Branch.Options.STARTUP_OPEN_GROUPING,
@@ -31,6 +31,10 @@ public class Tags.Branch : Sidebar.Branch {
         return entry_map.get(tag);
     }
     
+    public bool is_user_renameable() {
+        return true;
+    }
+    
     private static int comparator(Sidebar.Entry a, Sidebar.Entry b) {
         if (a == b)
             return 0;
@@ -118,13 +122,13 @@ public class Tags.Branch : Sidebar.Branch {
     }
 }
 
-public class Tags.Grouping : Sidebar.Grouping, Sidebar.InternalDropTargetEntry, 
+public class Tags.Header : Sidebar.Header, Sidebar.InternalDropTargetEntry, 
     Sidebar.InternalDragSourceEntry, Sidebar.Contextable {
     private Gtk.UIManager ui = new Gtk.UIManager();
     private Gtk.Menu? context_menu = null;
     
-    public Grouping() {
-        base (_("Tags"), Resources.ICON_TAGS);
+    public Header() {
+        base (_("Tags"));
         setup_context_menu();
     }
     
@@ -229,6 +233,10 @@ public class Tags.SidebarEntry : Sidebar.SimplePageEntry, Sidebar.RenameableEntr
         return new TagPage(tag);
     }
     
+    public bool is_user_renameable() {
+        return true;
+    }
+    
     public void rename(string new_name) {
         string? prepped = Tag.prep_tag_name(new_name);
         if (prepped == null)


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