From deecf5b9ba80231978a0dd8f3660f77b33428ded Mon Sep 17 00:00:00 2001
From: "estade@chromium.org"
 <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Thu, 11 Jun 2009 01:17:09 +0000
Subject: Linux bookmark manager:

- Add more dragging.
- Make right pane updating less clobbery.

Review URL: http://codereview.chromium.org/122005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18136 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/gtk/bookmark_manager_gtk.cc | 251 ++++++++++++++++++++++++-----
 chrome/browser/gtk/bookmark_manager_gtk.h  |  43 +++--
 chrome/browser/gtk/bookmark_tree_model.cc  |  67 ++++----
 chrome/browser/gtk/bookmark_tree_model.h   |   8 +-
 4 files changed, 278 insertions(+), 91 deletions(-)

(limited to 'chrome/browser')

diff --git a/chrome/browser/gtk/bookmark_manager_gtk.cc b/chrome/browser/gtk/bookmark_manager_gtk.cc
index 3618e77..a591cf2 100644
--- a/chrome/browser/gtk/bookmark_manager_gtk.cc
+++ b/chrome/browser/gtk/bookmark_manager_gtk.cc
@@ -72,21 +72,106 @@ void BookmarkManagerGtk::Show(Profile* profile) {
 }
 
 void BookmarkManagerGtk::BookmarkManagerGtk::Loaded(BookmarkModel* model) {
-  SuppressUpdatesToRightStore();
   BuildLeftStore();
-  AllowUpdatesToRightStore();
+  BuildRightStore();
+  g_signal_connect(left_selection(), "changed",
+                   G_CALLBACK(OnLeftSelectionChanged), this);
 }
 
 void BookmarkManagerGtk::BookmarkModelBeingDeleted(BookmarkModel* model) {
   gtk_widget_destroy(window_);
 }
 
+void BookmarkManagerGtk::BookmarkNodeMoved(BookmarkModel* model,
+                                           BookmarkNode* old_parent,
+                                           int old_index,
+                                           BookmarkNode* new_parent,
+                                           int new_index) {
+  BookmarkNodeRemoved(model, old_parent, old_index,
+                      new_parent->GetChild(new_index));
+  BookmarkNodeAdded(model, new_parent, new_index);
+}
+
+void BookmarkManagerGtk::BookmarkNodeAdded(BookmarkModel* model,
+                                           BookmarkNode* parent,
+                                           int index) {
+  BookmarkNode* node = parent->GetChild(index);
+  // Update left store.
+  if (node->is_folder()) {
+    GtkTreeIter iter;
+    gtk_tree_model_get_iter_first(GTK_TREE_MODEL(left_store_), &iter);
+
+    if (RecursiveFind(GTK_TREE_MODEL(left_store_), &iter, parent->id()))
+      bookmark_utils::AddToTreeStoreAt(node, 0, left_store_, NULL, &iter);
+  }
+
+  // Update right store.
+  if (parent->id() == GetFolder()->id()) {
+    GtkTreeIter iter;
+    gtk_tree_model_get_iter_first(GTK_TREE_MODEL(right_store_), &iter);
+
+    if (RecursiveFind(GTK_TREE_MODEL(right_store_), &iter,
+        parent->GetChild(index - 1)->id())) {
+      AppendNodeToRightStore(node, &iter);
+    }
+  }
+}
+
+void BookmarkManagerGtk::BookmarkNodeRemoved(BookmarkModel* model,
+                                             BookmarkNode* parent,
+                                             int index) {
+  NOTREACHED();
+}
+
+void BookmarkManagerGtk::BookmarkNodeRemoved(BookmarkModel* model,
+                                             BookmarkNode* parent,
+                                             int old_index,
+                                             BookmarkNode* node) {
+  if (node->is_folder()) {
+    GtkTreeIter iter;
+    gtk_tree_model_get_iter_first(GTK_TREE_MODEL(left_store_), &iter);
+
+    if (RecursiveFind(GTK_TREE_MODEL(left_store_), &iter, node->id())) {
+      // If we are deleting the currently selected folder, set the selection to
+      // its parent.
+      if (gtk_tree_selection_iter_is_selected(left_selection(), &iter)) {
+        GtkTreeIter parent;
+        gtk_tree_model_iter_parent(GTK_TREE_MODEL(left_store_), &parent, &iter);
+        gtk_tree_selection_select_iter(left_selection(), &parent);
+      }
+
+      gtk_tree_store_remove(left_store_, &iter);
+    }
+  }
+
+  GtkTreeIter iter;
+  gtk_tree_model_get_iter_first(GTK_TREE_MODEL(right_store_), &iter);
+
+  if (RecursiveFind(GTK_TREE_MODEL(right_store_), &iter, node->id()))
+    gtk_list_store_remove(right_store_, &iter);
+}
+
+void BookmarkManagerGtk::BookmarkNodeChanged(BookmarkModel* model,
+                                             BookmarkNode* node) {
+  // TODO(estade): implement.
+}
+
+void BookmarkManagerGtk::BookmarkNodeChildrenReordered(BookmarkModel* model,
+                                                       BookmarkNode* node) {
+  if (node->id() == GetFolder()->id())
+    BuildRightStore();
+}
+
+void BookmarkManagerGtk::BookmarkNodeFavIconLoaded(BookmarkModel* model,
+                                                   BookmarkNode* node) {
+  // TODO(estade): implement.
+}
+
 // BookmarkManagerGtk, private -------------------------------------------------
 
 BookmarkManagerGtk::BookmarkManagerGtk(Profile* profile)
     : profile_(profile),
-      model_(profile->GetBookmarkModel()),
-      update_suppressions_(0) {
+      model_(profile->GetBookmarkModel()) {
   InitWidgets();
   g_signal_connect(window_, "destroy",
                    G_CALLBACK(OnWindowDestroy), this);
@@ -173,6 +258,17 @@ GtkWidget* BookmarkManagerGtk::MakeLeftPane() {
   gtk_tree_view_append_column(GTK_TREE_VIEW(left_tree_view_), icon_column);
   gtk_tree_view_append_column(GTK_TREE_VIEW(left_tree_view_), name_column);
 
+  // The left side is only a drag destination (not a source).
+  gtk_drag_dest_set(left_tree_view_, GTK_DEST_DEFAULT_DROP,
+                    bookmark_utils::kTargetTable,
+                    bookmark_utils::kTargetTableSize,
+                    GDK_ACTION_MOVE);
+
+  g_signal_connect(left_tree_view_, "drag-data-received",
+                   G_CALLBACK(&OnLeftTreeViewDragReceived), this);
+  g_signal_connect(left_tree_view_, "drag-motion",
+                   G_CALLBACK(&OnLeftTreeViewDragMotion), this);
+
   GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
@@ -189,6 +285,8 @@ GtkWidget* BookmarkManagerGtk::MakeRightPane() {
                                     G_TYPE_STRING, G_TYPE_INT);
 
   GtkTreeViewColumn* title_column = gtk_tree_view_column_new();
+  gtk_tree_view_column_set_title(title_column,
+      l10n_util::GetStringUTF8(IDS_BOOKMARK_TABLE_TITLE).c_str());
   GtkCellRenderer* image_renderer = gtk_cell_renderer_pixbuf_new();
   gtk_tree_view_column_pack_start(title_column, image_renderer, FALSE);
   gtk_tree_view_column_add_attribute(title_column, image_renderer,
@@ -206,8 +304,6 @@ GtkWidget* BookmarkManagerGtk::MakeRightPane() {
   g_object_unref(right_store_);
   gtk_tree_view_append_column(GTK_TREE_VIEW(right_tree_view_), title_column);
   gtk_tree_view_append_column(GTK_TREE_VIEW(right_tree_view_), url_column);
-  g_signal_connect(left_selection(), "changed",
-                   G_CALLBACK(OnLeftSelectionChanged), this);
   g_signal_connect(right_selection(), "changed",
                    G_CALLBACK(OnRightSelectionChanged), this);
 
@@ -221,16 +317,14 @@ GtkWidget* BookmarkManagerGtk::MakeRightPane() {
                                        bookmark_utils::kTargetTableSize,
                                        GDK_ACTION_MOVE);
   g_signal_connect(right_tree_view_, "drag-data-get",
-                   G_CALLBACK(&OnTreeViewDragGet), this);
+                   G_CALLBACK(&OnRightTreeViewDragGet), this);
   g_signal_connect(right_tree_view_, "drag-data-received",
-                   G_CALLBACK(&OnTreeViewDragReceived), this);
+                   G_CALLBACK(&OnRightTreeViewDragReceived), this);
   g_signal_connect(right_tree_view_, "drag-motion",
-                   G_CALLBACK(&OnTreeViewDragMotion), this);
+                   G_CALLBACK(&OnRightTreeViewDragMotion), this);
   // Connect after so we can overwrite the drag icon.
   g_signal_connect_after(right_tree_view_, "drag-begin",
-                         G_CALLBACK(&OnTreeViewDragBegin), this);
-  g_signal_connect(right_tree_view_, "drag-end",
-                   G_CALLBACK(&OnTreeViewDragEnd), this);
+                         G_CALLBACK(&OnRightTreeViewDragBegin), this);
 
   GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
@@ -252,9 +346,6 @@ void BookmarkManagerGtk::BuildLeftStore() {
 }
 
 void BookmarkManagerGtk::BuildRightStore() {
-  if (update_suppressions_ > 0)
-    return;
-
   BookmarkNode* node = GetFolder();
   // TODO(estade): eventually we may hit a fake node here (recently bookmarked
   // or search), but until then we require that node != NULL.
@@ -304,7 +395,7 @@ std::vector<BookmarkNode*> BookmarkManagerGtk::GetRightSelection() {
 }
 
 void BookmarkManagerGtk::AppendNodeToRightStore(BookmarkNode* node,
-                                                         GtkTreeIter* iter) {
+                                                GtkTreeIter* iter) {
   GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model_);
   gtk_list_store_append(right_store_, iter);
   gtk_list_store_set(right_store_, iter,
@@ -315,16 +406,37 @@ void BookmarkManagerGtk::AppendNodeToRightStore(BookmarkNode* node,
   g_object_unref(pixbuf);
 }
 
-void BookmarkManagerGtk::SuppressUpdatesToRightStore() {
-  update_suppressions_++;
-}
+bool BookmarkManagerGtk::RecursiveFind(GtkTreeModel* model, GtkTreeIter* iter,
+                                       int target) {
+  GValue value = { 0, };
+  bool left = model == GTK_TREE_MODEL(left_store_);
+  if (left)
+    gtk_tree_model_get_value(model, iter, bookmark_utils::ITEM_ID, &value);
+  else
+    gtk_tree_model_get_value(model, iter, RIGHT_PANE_ID, &value);
+  int id = g_value_get_int(&value);
+  g_value_unset(&value);
 
-void BookmarkManagerGtk::AllowUpdatesToRightStore() {
-  update_suppressions_--;
-  DCHECK_GE(update_suppressions_, 0);
+  if (id == target) {
+    return true;
+  }
 
-  if (update_suppressions_ <= 0)
-    BuildRightStore();
+  GtkTreeIter child;
+  // Check the first child.
+  if (gtk_tree_model_iter_children(model, &child, iter)) {
+    if (RecursiveFind(model, &child, target)) {
+      *iter = child;
+      return true;
+    }
+  }
+
+  // Check siblings.
+  while (gtk_tree_model_iter_next(model, iter)) {
+    if (RecursiveFind(model, iter, target))
+      return true;
+  }
+
+  return false;
 }
 
 // static
@@ -348,8 +460,76 @@ void BookmarkManagerGtk::OnRightSelectionChanged(GtkTreeSelection* selection,
       bookmark_manager->GetRightSelection());
 }
 
+// statuc
+void BookmarkManagerGtk::OnLeftTreeViewDragReceived(
+    GtkWidget* tree_view, GdkDragContext* context, gint x, gint y,
+    GtkSelectionData* selection_data, guint target_type, guint time,
+    BookmarkManagerGtk* bm) {
+  gboolean dnd_success = FALSE;
+  gboolean delete_selection_data = FALSE;
+
+  std::vector<BookmarkNode*> nodes =
+      bookmark_utils::GetNodesFromSelection(context, selection_data,
+                                            target_type,
+                                            bm->profile_,
+                                            &delete_selection_data,
+                                            &dnd_success);
+
+  if (nodes.empty()) {
+    gtk_drag_finish(context, FALSE, delete_selection_data, time);
+    return;
+  }
+
+  GtkTreePath* path;
+  GtkTreeViewDropPosition pos;
+  gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(tree_view), x, y,
+                                    &path, &pos);
+  if (!path) {
+    gtk_drag_finish(context, FALSE, delete_selection_data, time);
+    return;
+  }
+
+  GtkTreeIter iter;
+  gtk_tree_model_get_iter(GTK_TREE_MODEL(bm->left_store_), &iter, path);
+  BookmarkNode* folder = bm->GetNodeAt(GTK_TREE_MODEL(bm->left_store_), &iter);
+  for (std::vector<BookmarkNode*>::iterator it = nodes.begin();
+       it != nodes.end(); ++it) {
+    // Don't try to drop a node into one of its descendants.
+    if (!folder->HasAncestor(*it))
+      bm->model_->Move(*it, folder, 0);
+  }
+
+  gtk_tree_path_free(path);
+  gtk_drag_finish(context, dnd_success, delete_selection_data, time);
+}
+
 // static
-void BookmarkManagerGtk::OnTreeViewDragGet(
+gboolean BookmarkManagerGtk::OnLeftTreeViewDragMotion(GtkWidget* tree_view,
+    GdkDragContext* context, gint x, gint y, guint time,
+    BookmarkManagerGtk* bm) {
+  GtkTreePath* path;
+  GtkTreeViewDropPosition pos;
+  gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(tree_view), x, y,
+                                    &path, &pos);
+
+  if (path) {
+    // Only allow INTO.
+    if (pos == GTK_TREE_VIEW_DROP_BEFORE)
+      pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+    else if (pos == GTK_TREE_VIEW_DROP_AFTER)
+      pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
+    gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(tree_view), path, pos);
+  } else {
+    return FALSE;
+  }
+
+  gdk_drag_status(context, GDK_ACTION_MOVE, time);
+  gtk_tree_path_free(path);
+  return TRUE;
+}
+
+// static
+void BookmarkManagerGtk::OnRightTreeViewDragGet(
     GtkWidget* tree_view,
     GdkDragContext* context, GtkSelectionData* selection_data,
     guint target_type, guint time, BookmarkManagerGtk* bookmark_manager) {
@@ -360,7 +540,7 @@ void BookmarkManagerGtk::OnTreeViewDragGet(
 }
 
 // static
-void BookmarkManagerGtk::OnTreeViewDragReceived(
+void BookmarkManagerGtk::OnRightTreeViewDragReceived(
     GtkWidget* tree_view, GdkDragContext* context, gint x, gint y,
     GtkSelectionData* selection_data, guint target_type, guint time,
     BookmarkManagerGtk* bm) {
@@ -379,8 +559,6 @@ void BookmarkManagerGtk::OnTreeViewDragReceived(
     return;
   }
 
-  // TODO(estade): Support drops on the left side tree view.
-  DCHECK_EQ(tree_view, bm->right_tree_view_);
   GtkTreePath* path;
   GtkTreeViewDropPosition pos;
   gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(tree_view), x, y,
@@ -421,40 +599,27 @@ void BookmarkManagerGtk::OnTreeViewDragReceived(
         gtk_tree_path_get_indices(path)[gtk_tree_path_get_depth(path) - 1];
   }
 
-  bm->SuppressUpdatesToRightStore();
   for (std::vector<BookmarkNode*>::iterator it = nodes.begin();
        it != nodes.end(); ++it) {
     // Don't try to drop a node into one of its descendants.
     if (!parent->HasAncestor(*it))
       bm->model_->Move(*it, parent, idx++);
   }
-  bm->AllowUpdatesToRightStore();
 
   gtk_tree_path_free(path);
   gtk_drag_finish(context, dnd_success, delete_selection_data, time);
 }
 
 // static
-void BookmarkManagerGtk::OnTreeViewDragBegin(
+void BookmarkManagerGtk::OnRightTreeViewDragBegin(
     GtkWidget* tree_view,
     GdkDragContext* drag_context,
     BookmarkManagerGtk* bookmark_manager) {
   gtk_drag_set_icon_stock(drag_context, GTK_STOCK_DND, 0, 0);
-  // Balanced in OnTreeViewDragEnd().
-  bookmark_manager->SuppressUpdatesToRightStore();
-}
-
-// static
-void BookmarkManagerGtk::OnTreeViewDragEnd(
-    GtkWidget* tree_view,
-    GdkDragContext* drag_context,
-    BookmarkManagerGtk* bookmark_manager) {
-  // Balanced in OnTreeViewDragBegin().
-  bookmark_manager->AllowUpdatesToRightStore();
 }
 
 // static
-gboolean BookmarkManagerGtk::OnTreeViewDragMotion(
+gboolean BookmarkManagerGtk::OnRightTreeViewDragMotion(
     GtkWidget* tree_view, GdkDragContext* context, gint x, gint y, guint time,
     BookmarkManagerGtk* bm) {
   GtkTreePath* path;
diff --git a/chrome/browser/gtk/bookmark_manager_gtk.h b/chrome/browser/gtk/bookmark_manager_gtk.h
index dd47091..3352a25 100644
--- a/chrome/browser/gtk/bookmark_manager_gtk.h
+++ b/chrome/browser/gtk/bookmark_manager_gtk.h
@@ -29,28 +29,27 @@ class BookmarkManagerGtk : public BookmarkModelObserver {
   // BookmarkModelObserver implementation.
   virtual void Loaded(BookmarkModel* model);
   virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
-  // TODO(estade): Implement these.
   virtual void BookmarkNodeMoved(BookmarkModel* model,
                                  BookmarkNode* old_parent,
                                  int old_index,
                                  BookmarkNode* new_parent,
-                                 int new_index) {}
+                                 int new_index);
   virtual void BookmarkNodeAdded(BookmarkModel* model,
                                  BookmarkNode* parent,
-                                 int index) {}
+                                 int index);
   virtual void BookmarkNodeRemoved(BookmarkModel* model,
                                    BookmarkNode* parent,
-                                   int index) {}
+                                   int index);
   virtual void BookmarkNodeRemoved(BookmarkModel* model,
                                    BookmarkNode* parent,
                                    int old_index,
-                                   BookmarkNode* node) {}
+                                   BookmarkNode* node);
   virtual void BookmarkNodeChanged(BookmarkModel* model,
-                                   BookmarkNode* node) {}
+                                   BookmarkNode* node);
   virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
-                                             BookmarkNode* node) {}
+                                             BookmarkNode* node);
   virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
-                                         BookmarkNode* node) {}
+                                         BookmarkNode* node);
 
  private:
   explicit BookmarkManagerGtk(Profile* profile);
@@ -64,7 +63,7 @@ class BookmarkManagerGtk : public BookmarkModelObserver {
   // This one should only be called once (when the bookmark model is loaded).
   void BuildLeftStore();
   // This one clears the old right pane and refills it with the contents of
-  // whatever folder is selected on the left.
+  // whatever folder is selected on the left. It can be called multiple times.
   void BuildRightStore();
 
   // Get the node from |model| at |iter|.
@@ -93,31 +92,41 @@ class BookmarkManagerGtk : public BookmarkModelObserver {
   void SuppressUpdatesToRightStore();
   void AllowUpdatesToRightStore();
 
+  // Tries to find the node with id |target_id|. If found, returns true and set
+  // |iter| to point to the entry.
+  bool RecursiveFind(GtkTreeModel* model, GtkTreeIter* iter, int target_id);
+
   static void OnLeftSelectionChanged(GtkTreeSelection* selection,
                                      BookmarkManagerGtk* bookmark_manager);
 
   static void OnRightSelectionChanged(GtkTreeSelection* selection,
                                       BookmarkManagerGtk* bookmark_manager);
 
-  static void OnTreeViewDragGet(GtkWidget* tree_view, GdkDragContext* context,
+  static void OnLeftTreeViewDragReceived(
+      GtkWidget* tree_view, GdkDragContext* context, gint x, gint y,
+      GtkSelectionData* selection_data, guint target_type, guint time,
+      BookmarkManagerGtk* bookmark_manager);
+
+  static gboolean OnLeftTreeViewDragMotion(GtkWidget* tree_view,
+      GdkDragContext* context, gint x, gint y, guint time,
+      BookmarkManagerGtk* bookmark_manager);
+
+
+  static void OnRightTreeViewDragGet(GtkWidget* tree_view, GdkDragContext* context,
                                 GtkSelectionData* selection_data,
                                 guint target_type, guint time,
                                 BookmarkManagerGtk* bookmark_manager);
 
-  static void OnTreeViewDragReceived(
+  static void OnRightTreeViewDragReceived(
       GtkWidget* tree_view, GdkDragContext* context, gint x, gint y,
       GtkSelectionData* selection_data, guint target_type, guint time,
       BookmarkManagerGtk* bookmark_manager);
 
-  static void OnTreeViewDragBegin(GtkWidget* tree_view,
+  static void OnRightTreeViewDragBegin(GtkWidget* tree_view,
                                   GdkDragContext* drag_context,
                                   BookmarkManagerGtk* bookmark_manager);
 
-  static void OnTreeViewDragEnd(GtkWidget* tree_view,
-                                GdkDragContext* drag_context,
-                                BookmarkManagerGtk* bookmark_manager);
-
-  static gboolean OnTreeViewDragMotion(GtkWidget* tree_view,
+  static gboolean OnRightTreeViewDragMotion(GtkWidget* tree_view,
       GdkDragContext* context, gint x, gint y, guint time,
       BookmarkManagerGtk* bookmark_manager);
 
diff --git a/chrome/browser/gtk/bookmark_tree_model.cc b/chrome/browser/gtk/bookmark_tree_model.cc
index 1b5f4de..14f7471 100644
--- a/chrome/browser/gtk/bookmark_tree_model.cc
+++ b/chrome/browser/gtk/bookmark_tree_model.cc
@@ -13,35 +13,17 @@
 
 namespace {
 
-// Helper function for BuildTreeStoreFrom() which recursively inserts data from
-// a BookmarkNode tree into a GtkTreeStore.
-void RecursiveInsert(BookmarkNode* node, int selected_id,
-                     GtkTreeStore* store, GtkTreeIter* selected_iter,
-                     GtkTreeIter* parent) {
-  GtkTreeIter iter;
-
-  for (int i = 0; i < node->GetChildCount(); ++i) {
-    BookmarkNode* child = node->GetChild(i);
-    if (child->is_folder()) {
-      gtk_tree_store_append(store, &iter, parent);
-      // TODO(estade): we should show the folder open when it's expanded.
-      gtk_tree_store_set(store, &iter,
-                         bookmark_utils::FOLDER_ICON,
-                         bookmark_utils::GetFolderIcon(),
-                         bookmark_utils::FOLDER_NAME,
-                         WideToUTF8(child->GetTitle()).c_str(),
-                         bookmark_utils::ITEM_ID, child->id(),
-                         -1);
-      if (selected_id && child->id() == selected_id) {
-        // Save the iterator. Since we're using a GtkTreeStore, we're
-        // guaranteed that the iterator will remain valid as long as the above
-        // appended item exists.
-        *selected_iter = iter;
-      }
-
-      RecursiveInsert(child, selected_id, store, selected_iter, &iter);
-    }
-  }
+void AddSingleNodeToTreeStore(GtkTreeStore* store, BookmarkNode* node,
+                              GtkTreeIter *iter, GtkTreeIter* parent) {
+  gtk_tree_store_append(store, iter, parent);
+  // TODO(estade): we should show the folder open icon when it's expanded.
+  gtk_tree_store_set(store, iter,
+                     bookmark_utils::FOLDER_ICON,
+                     bookmark_utils::GetFolderIcon(),
+                     bookmark_utils::FOLDER_NAME,
+                     WideToUTF8(node->GetTitle()).c_str(),
+                     bookmark_utils::ITEM_ID, node->id(),
+                     -1);
 }
 
 // Helper function for CommitTreeStoreDifferencesBetween() which recursively
@@ -97,7 +79,32 @@ GtkTreeStore* MakeFolderTreeStore() {
 
 void AddToTreeStore(BookmarkModel* model, int selected_id,
                     GtkTreeStore* store, GtkTreeIter* selected_iter) {
-  RecursiveInsert(model->root_node(), selected_id, store, selected_iter, NULL);
+  BookmarkNode* root_node = model->root_node();
+  for (int i = 0; i < root_node->GetChildCount(); ++i) {
+    AddToTreeStoreAt(root_node->GetChild(i), selected_id, store,
+                     selected_iter, NULL);
+  }
+}
+
+void AddToTreeStoreAt(BookmarkNode* node, int selected_id,
+                      GtkTreeStore* store, GtkTreeIter* selected_iter,
+                      GtkTreeIter* parent) {
+  if (!node->is_folder())
+    return;
+
+  GtkTreeIter iter;
+  AddSingleNodeToTreeStore(store, node, &iter, parent);
+  if (selected_iter && node->id() == selected_id) {
+     // Save the iterator. Since we're using a GtkTreeStore, we're
+     // guaranteed that the iterator will remain valid as long as the above
+     // appended item exists.
+     *selected_iter = iter;
+  }
+
+  for (int i = 0; i < node->GetChildCount(); ++i) {
+    AddToTreeStoreAt(node->GetChild(i), selected_id, store,
+                     selected_iter, &iter);
+  }
 }
 
 BookmarkNode* CommitTreeStoreDifferencesBetween(
diff --git a/chrome/browser/gtk/bookmark_tree_model.h b/chrome/browser/gtk/bookmark_tree_model.h
index b7adafc..4ca0c5b 100644
--- a/chrome/browser/gtk/bookmark_tree_model.h
+++ b/chrome/browser/gtk/bookmark_tree_model.h
@@ -27,7 +27,7 @@ enum FolderTreeStoreColumns {
 // Make a tree store that has two columns: name and id.
 GtkTreeStore* MakeFolderTreeStore();
 
-// Copies the tree of folders rooted at |node| into a GtkTreeStore. We
+// Copies the folders in the model's root node into a GtkTreeStore. We
 // want the user to be able to modify the tree of folders, but to be able to
 // click Cancel and discard their modifications. |selected_id| is the
 // node->id() of the BookmarkNode that should selected on
@@ -39,6 +39,12 @@ GtkTreeStore* MakeFolderTreeStore();
 void AddToTreeStore(BookmarkModel* model, int selected_id,
                     GtkTreeStore* store, GtkTreeIter* selected_iter);
 
+// As above, but inserts just the tree rooted at |node| as a child of |parent|.
+// If |parent| is NULL, add it at the top level.
+void AddToTreeStoreAt(BookmarkNode* node, int selected_id,
+                      GtkTreeStore* store, GtkTreeIter* selected_iter,
+                      GtkTreeIter* parent);
+
 // Commits changes to a GtkTreeStore built from BuildTreeStoreFrom() back
 // into the BookmarkModel it was generated from.  Returns the BookmarkNode that
 // represented by |selected|.
-- 
cgit v1.1