summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/bookmark_tree_model.cc
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-05 00:35:09 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-05 00:35:09 +0000
commit140aea057fa118579380f685f362f2533862b03f (patch)
tree627c15d8adda34f2c602589e0bac815bbdc7d4d9 /chrome/browser/gtk/bookmark_tree_model.cc
parent57e3074163dc21bc3bc8cd37dc05f191532d836a (diff)
downloadchromium_src-140aea057fa118579380f685f362f2533862b03f.zip
chromium_src-140aea057fa118579380f685f362f2533862b03f.tar.gz
chromium_src-140aea057fa118579380f685f362f2533862b03f.tar.bz2
Port the folder selector portion of the BookmarkEditor to GTK.
Mirrors the BookmarkEditorView method, where the contents of BookmarkModel are copied to a temporary model so changes can be discarded if the user hits Cancel. In the GTK version, we copy not into another BookmarkModel, but into a GtkTreeStore, which serves as a model to the GtkTreeView on screen. Also ports the unit tests. http://crbug.com/11250 Review URL: http://codereview.chromium.org/99361 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15257 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk/bookmark_tree_model.cc')
-rw-r--r--chrome/browser/gtk/bookmark_tree_model.cc161
1 files changed, 161 insertions, 0 deletions
diff --git a/chrome/browser/gtk/bookmark_tree_model.cc b/chrome/browser/gtk/bookmark_tree_model.cc
new file mode 100644
index 0000000..309a9a1
--- /dev/null
+++ b/chrome/browser/gtk/bookmark_tree_model.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gtk/bookmark_tree_model.h"
+
+#include <gtk/gtk.h>
+
+#include "base/string_util.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+
+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);
+ gtk_tree_store_set(store, &iter,
+ 0, WideToUTF8(child->GetTitle()).c_str(),
+ 1, 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);
+ }
+ }
+}
+
+// Helper function for CommitTreeStoreDifferencesBetween() which recursively
+// merges changes back from a GtkTreeStore into a tree of BookmarkNodes. This
+// function only works on non-root nodes; our caller handles that special case.
+void RecursiveResolve(BookmarkModel* bb_model, BookmarkNode* bb_node,
+ GtkTreeModel* tree_model, GtkTreeIter* parent_iter,
+ GtkTreePath* selected_path,
+ BookmarkNode** selected_node) {
+ GtkTreePath* current_path = gtk_tree_model_get_path(tree_model, parent_iter);
+ if (gtk_tree_path_compare(current_path, selected_path) == 0)
+ *selected_node = bb_node;
+ gtk_tree_path_free(current_path);
+
+ GtkTreeIter child_iter;
+ if (gtk_tree_model_iter_children(tree_model, &child_iter, parent_iter)) {
+ do {
+ int id = bookmark_utils::GetIdFromTreeIter(tree_model, &child_iter);
+ std::wstring title =
+ bookmark_utils::GetTitleFromTreeIter(tree_model, &child_iter);
+ BookmarkNode* child_bb_node = NULL;
+ if (id == 0) {
+ child_bb_node = bb_model->AddGroup(bb_node, bb_node->GetChildCount(),
+ title);
+ } else {
+ // Existing node, reset the title (BBModel ignores changes if the title
+ // is the same).
+ for (int j = 0; j < bb_node->GetChildCount(); ++j) {
+ BookmarkNode* node = bb_node->GetChild(j);
+ if (node->is_folder() && node->id() == id) {
+ child_bb_node = node;
+ break;
+ }
+ }
+ DCHECK(child_bb_node);
+ bb_model->SetTitle(child_bb_node, title);
+ }
+ RecursiveResolve(bb_model, child_bb_node,
+ tree_model, &child_iter,
+ selected_path, selected_node);
+ } while (gtk_tree_model_iter_next(tree_model, &child_iter));
+ }
+}
+
+} // namespace
+
+namespace bookmark_utils {
+
+void BuildTreeStoreFrom(BookmarkModel* model, int selected_id,
+ GtkTreeStore** store, GtkTreeIter* selected_iter) {
+ *store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
+ RecursiveInsert(model->root_node(), selected_id, *store, selected_iter, NULL);
+}
+
+BookmarkNode* CommitTreeStoreDifferencesBetween(
+ BookmarkModel* bb_model, GtkTreeStore* tree_store, GtkTreeIter* selected) {
+ BookmarkNode* node_to_return = NULL;
+ GtkTreeModel* tree_model = GTK_TREE_MODEL(tree_store);
+
+ GtkTreePath* selected_path = gtk_tree_model_get_path(tree_model, selected);
+
+ GtkTreeIter tree_root;
+ if (!gtk_tree_model_get_iter_first(tree_model, &tree_root))
+ NOTREACHED() << "Impossible missing bookmarks case";
+
+ // The top level of this tree is weird and needs to be special cased. The
+ // BookmarksNode tree is rooted on a root node while the GtkTreeStore has a
+ // set of top level nodes that are the root BookmarksNode's children. These
+ // items in the top level are not editable and therefore don't need the extra
+ // complexity of trying to modify their title.
+ BookmarkNode* root_node = bb_model->root_node();
+ do {
+ DCHECK(GetIdFromTreeIter(tree_model, &tree_root) != 0)
+ << "It should be impossible to add another toplevel node";
+
+ int id = GetIdFromTreeIter(tree_model, &tree_root);
+ BookmarkNode* child_node = NULL;
+ for (int j = 0; j < root_node->GetChildCount(); ++j) {
+ BookmarkNode* node = root_node->GetChild(j);
+ if (node->is_folder() && node->id() == id) {
+ child_node = node;
+ break;
+ }
+ }
+ DCHECK(child_node);
+
+ GtkTreeIter child_iter = tree_root;
+ RecursiveResolve(bb_model, child_node, tree_model, &child_iter,
+ selected_path, &node_to_return);
+ } while (gtk_tree_model_iter_next(tree_model, &tree_root));
+
+ gtk_tree_path_free(selected_path);
+ return node_to_return;
+}
+
+int GetIdFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter) {
+ GValue value = { 0, };
+ int ret_val = -1;
+ gtk_tree_model_get_value(model, iter, 1, &value);
+ if (G_VALUE_HOLDS_INT(&value))
+ ret_val = g_value_get_int(&value);
+ else
+ NOTREACHED() << "Impossible type mismatch";
+
+ return ret_val;
+}
+
+std::wstring GetTitleFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter) {
+ GValue value = { 0, };
+ std::wstring ret_val;
+ gtk_tree_model_get_value(model, iter, 0, &value);
+ if (G_VALUE_HOLDS_STRING(&value)) {
+ const gchar* utf8str = g_value_get_string(&value);
+ ret_val = UTF8ToWide(utf8str);
+ g_value_unset(&value);
+ } else {
+ NOTREACHED() << "Impossible type mismatch";
+ }
+
+ return ret_val;
+}
+
+} // namespace bookmark_utils