Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / bookmarks / bookmark_editor_view.cc
blob092c1ef76692f25ee4698cefa1516cab9d1387ae
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/bookmarks/bookmark_editor_view.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
17 #include "chrome/browser/ui/browser_dialogs.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "chrome/grit/locale_settings.h"
20 #include "components/bookmarks/browser/bookmark_model.h"
21 #include "components/bookmarks/browser/bookmark_utils.h"
22 #include "components/constrained_window/constrained_window_views.h"
23 #include "components/history/core/browser/history_service.h"
24 #include "components/url_formatter/url_fixer.h"
25 #include "components/user_prefs/user_prefs.h"
26 #include "ui/accessibility/ax_view_state.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/events/event.h"
29 #include "ui/views/background.h"
30 #include "ui/views/controls/button/label_button.h"
31 #include "ui/views/controls/label.h"
32 #include "ui/views/controls/menu/menu_runner.h"
33 #include "ui/views/controls/textfield/textfield.h"
34 #include "ui/views/controls/tree/tree_view.h"
35 #include "ui/views/focus/focus_manager.h"
36 #include "ui/views/layout/grid_layout.h"
37 #include "ui/views/layout/layout_constants.h"
38 #include "ui/views/widget/widget.h"
39 #include "ui/views/window/dialog_client_view.h"
40 #include "url/gurl.h"
42 using bookmarks::BookmarkExpandedStateTracker;
43 using bookmarks::BookmarkModel;
44 using bookmarks::BookmarkNode;
45 using views::GridLayout;
47 namespace {
49 // Background color of text field when URL is invalid.
50 const SkColor kErrorColor = SkColorSetRGB(0xFF, 0xBC, 0xBC);
52 } // namespace
54 BookmarkEditorView::BookmarkEditorView(
55 Profile* profile,
56 const BookmarkNode* parent,
57 const EditDetails& details,
58 BookmarkEditor::Configuration configuration)
59 : profile_(profile),
60 tree_view_(NULL),
61 url_label_(NULL),
62 url_tf_(NULL),
63 title_label_(NULL),
64 title_tf_(NULL),
65 parent_(parent),
66 details_(details),
67 bb_model_(BookmarkModelFactory::GetForProfile(profile)),
68 running_menu_for_root_(false),
69 show_tree_(configuration == SHOW_TREE) {
70 DCHECK(profile);
71 DCHECK(bb_model_);
72 DCHECK(bb_model_->client()->CanBeEditedByUser(parent));
73 Init();
76 BookmarkEditorView::~BookmarkEditorView() {
77 // The tree model is deleted before the view. Reset the model otherwise the
78 // tree will reference a deleted model.
79 if (tree_view_)
80 tree_view_->SetModel(NULL);
81 bb_model_->RemoveObserver(this);
84 base::string16 BookmarkEditorView::GetDialogButtonLabel(
85 ui::DialogButton button) const {
86 if (button == ui::DIALOG_BUTTON_OK)
87 return l10n_util::GetStringUTF16(IDS_SAVE);
88 return views::DialogDelegateView::GetDialogButtonLabel(button);
91 bool BookmarkEditorView::IsDialogButtonEnabled(ui::DialogButton button) const {
92 if (button == ui::DIALOG_BUTTON_OK) {
93 if (!bb_model_->loaded())
94 return false;
96 if (details_.GetNodeType() != BookmarkNode::FOLDER)
97 return GetInputURL().is_valid();
99 return true;
102 views::View* BookmarkEditorView::CreateExtraView() {
103 return new_folder_button_.get();
106 ui::ModalType BookmarkEditorView::GetModalType() const {
107 return ui::MODAL_TYPE_WINDOW;
110 bool BookmarkEditorView::CanResize() const {
111 return true;
114 base::string16 BookmarkEditorView::GetWindowTitle() const {
115 return l10n_util::GetStringUTF16(details_.GetWindowTitleId());
118 bool BookmarkEditorView::Accept() {
119 if (!IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)) {
120 if (details_.GetNodeType() != BookmarkNode::FOLDER) {
121 // The url is invalid, focus the url field.
122 url_tf_->SelectAll(true);
123 url_tf_->RequestFocus();
125 return false;
127 // Otherwise save changes and close the dialog box.
128 ApplyEdits();
129 return true;
132 gfx::Size BookmarkEditorView::GetPreferredSize() const {
133 if (!show_tree_)
134 return views::View::GetPreferredSize();
136 return gfx::Size(views::Widget::GetLocalizedContentsSize(
137 IDS_EDITBOOKMARK_DIALOG_WIDTH_CHARS,
138 IDS_EDITBOOKMARK_DIALOG_HEIGHT_LINES));
141 void BookmarkEditorView::OnTreeViewSelectionChanged(
142 views::TreeView* tree_view) {
145 bool BookmarkEditorView::CanEdit(views::TreeView* tree_view,
146 ui::TreeModelNode* node) {
147 // Only allow editting of children of the bookmark bar node and other node.
148 EditorNode* bb_node = tree_model_->AsNode(node);
149 return (bb_node->parent() && bb_node->parent()->parent());
152 void BookmarkEditorView::ContentsChanged(views::Textfield* sender,
153 const base::string16& new_contents) {
154 UserInputChanged();
157 bool BookmarkEditorView::HandleKeyEvent(views::Textfield* sender,
158 const ui::KeyEvent& key_event) {
159 return false;
162 void BookmarkEditorView::GetAccessibleState(ui::AXViewState* state) {
163 views::DialogDelegateView::GetAccessibleState(state);
164 state->name =
165 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_TITLE);
168 void BookmarkEditorView::ButtonPressed(views::Button* sender,
169 const ui::Event& event) {
170 DCHECK_EQ(new_folder_button_.get(), sender);
171 NewFolder();
174 bool BookmarkEditorView::IsCommandIdChecked(int command_id) const {
175 return false;
178 bool BookmarkEditorView::IsCommandIdEnabled(int command_id) const {
179 switch (command_id) {
180 case IDS_EDIT:
181 case IDS_DELETE:
182 return !running_menu_for_root_;
183 case IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM:
184 return true;
185 default:
186 NOTREACHED();
187 return false;
191 bool BookmarkEditorView::GetAcceleratorForCommandId(
192 int command_id,
193 ui::Accelerator* accelerator) {
194 return GetWidget()->GetAccelerator(command_id, accelerator);
197 void BookmarkEditorView::ExecuteCommand(int command_id, int event_flags) {
198 DCHECK(tree_view_->GetSelectedNode());
199 if (command_id == IDS_EDIT) {
200 tree_view_->StartEditing(tree_view_->GetSelectedNode());
201 } else if (command_id == IDS_DELETE) {
202 EditorNode* node = tree_model_->AsNode(tree_view_->GetSelectedNode());
203 if (!node)
204 return;
205 if (node->value != 0) {
206 const BookmarkNode* b_node =
207 bookmarks::GetBookmarkNodeByID(bb_model_, node->value);
208 if (!b_node->empty() &&
209 !chrome::ConfirmDeleteBookmarkNode(b_node,
210 GetWidget()->GetNativeWindow())) {
211 // The folder is not empty and the user didn't confirm.
212 return;
214 deletes_.push_back(node->value);
216 tree_model_->Remove(node->parent(), node);
217 } else {
218 DCHECK_EQ(IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM, command_id);
219 NewFolder();
223 void BookmarkEditorView::Show(gfx::NativeWindow parent) {
224 constrained_window::CreateBrowserModalDialogViews(this, parent);
225 UserInputChanged();
226 if (show_tree_ && bb_model_->loaded())
227 ExpandAndSelect();
228 GetWidget()->Show();
229 // Select all the text in the name Textfield.
230 title_tf_->SelectAll(true);
231 // Give focus to the name Textfield.
232 title_tf_->RequestFocus();
235 void BookmarkEditorView::ShowContextMenuForView(
236 views::View* source,
237 const gfx::Point& point,
238 ui::MenuSourceType source_type) {
239 DCHECK_EQ(tree_view_, source);
240 if (!tree_view_->GetSelectedNode())
241 return;
242 running_menu_for_root_ =
243 (tree_model_->GetParent(tree_view_->GetSelectedNode()) ==
244 tree_model_->GetRoot());
246 context_menu_runner_.reset(new views::MenuRunner(
247 GetMenuModel(),
248 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
250 if (context_menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
251 NULL,
252 gfx::Rect(point, gfx::Size()),
253 views::MENU_ANCHOR_TOPRIGHT,
254 source_type) ==
255 views::MenuRunner::MENU_DELETED) {
256 return;
260 const char* BookmarkEditorView::GetClassName() const {
261 return "BookmarkEditorView";
264 void BookmarkEditorView::BookmarkNodeMoved(BookmarkModel* model,
265 const BookmarkNode* old_parent,
266 int old_index,
267 const BookmarkNode* new_parent,
268 int new_index) {
269 Reset();
272 void BookmarkEditorView::BookmarkNodeAdded(BookmarkModel* model,
273 const BookmarkNode* parent,
274 int index) {
275 Reset();
278 void BookmarkEditorView::BookmarkNodeRemoved(
279 BookmarkModel* model,
280 const BookmarkNode* parent,
281 int index,
282 const BookmarkNode* node,
283 const std::set<GURL>& removed_urls) {
284 if ((details_.type == EditDetails::EXISTING_NODE &&
285 details_.existing_node->HasAncestor(node)) ||
286 (parent_ && parent_->HasAncestor(node))) {
287 // The node, or its parent was removed. Close the dialog.
288 GetWidget()->Close();
289 } else {
290 Reset();
294 void BookmarkEditorView::BookmarkAllUserNodesRemoved(
295 BookmarkModel* model,
296 const std::set<GURL>& removed_urls) {
297 Reset();
300 void BookmarkEditorView::BookmarkNodeChildrenReordered(
301 BookmarkModel* model,
302 const BookmarkNode* node) {
303 Reset();
306 void BookmarkEditorView::Init() {
307 bb_model_->AddObserver(this);
309 title_label_ = new views::Label(
310 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NAME_LABEL));
312 base::string16 title;
313 GURL url;
314 if (details_.type == EditDetails::EXISTING_NODE) {
315 title = details_.existing_node->GetTitle();
316 url = details_.existing_node->url();
317 } else if (details_.type == EditDetails::NEW_FOLDER) {
318 title = l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME);
319 } else if (details_.type == EditDetails::NEW_URL) {
320 url = details_.url;
321 title = details_.title;
323 title_tf_ = new views::Textfield;
324 title_tf_->SetAccessibleName(
325 l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_EDITOR_NAME_LABEL));
326 title_tf_->SetText(title);
327 title_tf_->set_controller(this);
329 if (show_tree_) {
330 tree_view_ = new views::TreeView;
331 tree_view_->SetRootShown(false);
332 tree_view_->set_context_menu_controller(this);
334 new_folder_button_.reset(new views::LabelButton(this,
335 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_BUTTON)));
336 new_folder_button_->SetStyle(views::Button::STYLE_BUTTON);
337 new_folder_button_->set_owned_by_client();
338 new_folder_button_->SetEnabled(false);
341 GridLayout* layout = GridLayout::CreatePanel(this);
342 SetLayoutManager(layout);
344 const int labels_column_set_id = 0;
345 const int single_column_view_set_id = 1;
346 const int buttons_column_set_id = 2;
348 views::ColumnSet* column_set = layout->AddColumnSet(labels_column_set_id);
349 column_set->AddColumn(views::kControlLabelGridAlignment, GridLayout::CENTER,
350 0, GridLayout::USE_PREF, 0, 0);
351 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
352 column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
353 GridLayout::USE_PREF, 0, 0);
355 column_set = layout->AddColumnSet(single_column_view_set_id);
356 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
357 GridLayout::USE_PREF, 0, 0);
359 column_set = layout->AddColumnSet(buttons_column_set_id);
360 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0,
361 GridLayout::USE_PREF, 0, 0);
362 column_set->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
363 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0,
364 GridLayout::USE_PREF, 0, 0);
365 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
366 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0,
367 GridLayout::USE_PREF, 0, 0);
368 column_set->LinkColumnSizes(0, 2, 4, -1);
370 layout->StartRow(0, labels_column_set_id);
371 layout->AddView(title_label_);
372 layout->AddView(title_tf_);
374 if (details_.GetNodeType() != BookmarkNode::FOLDER) {
375 url_label_ = new views::Label(
376 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_URL_LABEL));
378 url_tf_ = new views::Textfield;
379 PrefService* prefs =
380 profile_ ? user_prefs::UserPrefs::Get(profile_) : NULL;
381 url_tf_->SetText(chrome::FormatBookmarkURLForDisplay(url, prefs));
382 url_tf_->set_controller(this);
383 url_tf_->SetAccessibleName(
384 l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_EDITOR_URL_LABEL));
386 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
388 layout->StartRow(0, labels_column_set_id);
389 layout->AddView(url_label_);
390 layout->AddView(url_tf_);
393 if (show_tree_) {
394 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
395 layout->StartRow(1, single_column_view_set_id);
396 layout->AddView(tree_view_->CreateParentIfNecessary());
399 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
401 if (!show_tree_ || bb_model_->loaded())
402 Reset();
405 void BookmarkEditorView::Reset() {
406 if (!show_tree_) {
407 if (parent())
408 UserInputChanged();
409 return;
412 new_folder_button_->SetEnabled(true);
414 // Do this first, otherwise when we invoke SetModel with the real one
415 // tree_view will try to invoke something on the model we just deleted.
416 tree_view_->SetModel(NULL);
418 EditorNode* root_node = CreateRootNode();
419 tree_model_.reset(new EditorTreeModel(root_node));
421 tree_view_->SetModel(tree_model_.get());
422 tree_view_->SetController(this);
424 context_menu_runner_.reset();
426 if (parent())
427 ExpandAndSelect();
430 GURL BookmarkEditorView::GetInputURL() const {
431 if (details_.GetNodeType() == BookmarkNode::FOLDER)
432 return GURL();
433 return url_formatter::FixupURL(base::UTF16ToUTF8(url_tf_->text()),
434 std::string());
437 void BookmarkEditorView::UserInputChanged() {
438 if (details_.GetNodeType() != BookmarkNode::FOLDER) {
439 const GURL url(GetInputURL());
440 if (!url.is_valid())
441 url_tf_->SetBackgroundColor(kErrorColor);
442 else
443 url_tf_->UseDefaultBackgroundColor();
445 GetDialogClientView()->UpdateDialogButtons();
448 void BookmarkEditorView::NewFolder() {
449 // Create a new entry parented to the selected item, or the bookmark
450 // bar if nothing is selected.
451 EditorNode* parent = tree_model_->AsNode(tree_view_->GetSelectedNode());
452 if (!parent) {
453 NOTREACHED();
454 return;
457 tree_view_->StartEditing(AddNewFolder(parent));
460 BookmarkEditorView::EditorNode* BookmarkEditorView::AddNewFolder(
461 EditorNode* parent) {
462 EditorNode* new_node = new EditorNode(
463 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME), 0);
464 // |new_node| is now owned by |parent|.
465 tree_model_->Add(parent, new_node, parent->child_count());
466 return new_node;
469 void BookmarkEditorView::ExpandAndSelect() {
470 BookmarkExpandedStateTracker::Nodes expanded_nodes =
471 bb_model_->expanded_state_tracker()->GetExpandedNodes();
472 for (BookmarkExpandedStateTracker::Nodes::const_iterator i(
473 expanded_nodes.begin()); i != expanded_nodes.end(); ++i) {
474 EditorNode* editor_node =
475 FindNodeWithID(tree_model_->GetRoot(), (*i)->id());
476 if (editor_node)
477 tree_view_->Expand(editor_node);
480 const BookmarkNode* to_select = parent_;
481 if (details_.type == EditDetails::EXISTING_NODE)
482 to_select = details_.existing_node->parent();
483 int64 folder_id_to_select = to_select->id();
484 EditorNode* b_node =
485 FindNodeWithID(tree_model_->GetRoot(), folder_id_to_select);
486 if (!b_node)
487 b_node = tree_model_->GetRoot()->GetChild(0); // Bookmark bar node.
489 tree_view_->SetSelectedNode(b_node);
492 BookmarkEditorView::EditorNode* BookmarkEditorView::CreateRootNode() {
493 EditorNode* root_node = new EditorNode(base::string16(), 0);
494 const BookmarkNode* bb_root_node = bb_model_->root_node();
495 CreateNodes(bb_root_node, root_node);
496 DCHECK(root_node->child_count() >= 2 && root_node->child_count() <= 4);
497 DCHECK_EQ(BookmarkNode::BOOKMARK_BAR, bb_root_node->GetChild(0)->type());
498 DCHECK_EQ(BookmarkNode::OTHER_NODE, bb_root_node->GetChild(1)->type());
499 if (root_node->child_count() >= 3)
500 DCHECK_EQ(BookmarkNode::MOBILE, bb_root_node->GetChild(2)->type());
501 return root_node;
504 void BookmarkEditorView::CreateNodes(const BookmarkNode* bb_node,
505 BookmarkEditorView::EditorNode* b_node) {
506 for (int i = 0; i < bb_node->child_count(); ++i) {
507 const BookmarkNode* child_bb_node = bb_node->GetChild(i);
508 if (child_bb_node->IsVisible() && child_bb_node->is_folder() &&
509 bb_model_->client()->CanBeEditedByUser(child_bb_node)) {
510 EditorNode* new_b_node = new EditorNode(child_bb_node->GetTitle(),
511 child_bb_node->id());
512 b_node->Add(new_b_node, b_node->child_count());
513 CreateNodes(child_bb_node, new_b_node);
518 BookmarkEditorView::EditorNode* BookmarkEditorView::FindNodeWithID(
519 BookmarkEditorView::EditorNode* node,
520 int64 id) {
521 if (node->value == id)
522 return node;
523 for (int i = 0; i < node->child_count(); ++i) {
524 EditorNode* result = FindNodeWithID(node->GetChild(i), id);
525 if (result)
526 return result;
528 return NULL;
531 void BookmarkEditorView::ApplyEdits() {
532 DCHECK(bb_model_->loaded());
534 if (tree_view_)
535 tree_view_->CommitEdit();
537 EditorNode* parent = show_tree_ ?
538 tree_model_->AsNode(tree_view_->GetSelectedNode()) : NULL;
539 if (show_tree_ && !parent) {
540 NOTREACHED();
541 return;
543 ApplyEdits(parent);
546 void BookmarkEditorView::ApplyEdits(EditorNode* parent) {
547 DCHECK(!show_tree_ || parent);
549 // We're going to apply edits to the bookmark bar model, which will call us
550 // back. Normally when a structural edit occurs we reset the tree model.
551 // We don't want to do that here, so we remove ourselves as an observer.
552 bb_model_->RemoveObserver(this);
554 GURL new_url(GetInputURL());
555 base::string16 new_title(title_tf_->text());
557 if (!show_tree_) {
558 BookmarkEditor::ApplyEditsWithNoFolderChange(
559 bb_model_, parent_, details_, new_title, new_url);
560 return;
563 // Create the new folders and update the titles.
564 const BookmarkNode* new_parent = NULL;
565 ApplyNameChangesAndCreateNewFolders(
566 bb_model_->root_node(), tree_model_->GetRoot(), parent, &new_parent);
568 BookmarkEditor::ApplyEditsWithPossibleFolderChange(
569 bb_model_, new_parent, details_, new_title, new_url);
571 BookmarkExpandedStateTracker::Nodes expanded_nodes;
572 UpdateExpandedNodes(tree_model_->GetRoot(), &expanded_nodes);
573 bb_model_->expanded_state_tracker()->SetExpandedNodes(expanded_nodes);
575 // Remove the folders that were removed. This has to be done after all the
576 // other changes have been committed.
577 bookmarks::DeleteBookmarkFolders(bb_model_, deletes_);
580 void BookmarkEditorView::ApplyNameChangesAndCreateNewFolders(
581 const BookmarkNode* bb_node,
582 BookmarkEditorView::EditorNode* b_node,
583 BookmarkEditorView::EditorNode* parent_b_node,
584 const BookmarkNode** parent_bb_node) {
585 if (parent_b_node == b_node)
586 *parent_bb_node = bb_node;
587 for (int i = 0; i < b_node->child_count(); ++i) {
588 EditorNode* child_b_node = b_node->GetChild(i);
589 const BookmarkNode* child_bb_node = NULL;
590 if (child_b_node->value == 0) {
591 // New folder.
592 child_bb_node = bb_model_->AddFolder(bb_node,
593 bb_node->child_count(), child_b_node->GetTitle());
594 child_b_node->value = child_bb_node->id();
595 } else {
596 // Existing node, reset the title (BookmarkModel ignores changes if the
597 // title is the same).
598 for (int j = 0; j < bb_node->child_count(); ++j) {
599 const BookmarkNode* node = bb_node->GetChild(j);
600 if (node->is_folder() && node->id() == child_b_node->value) {
601 child_bb_node = node;
602 break;
605 DCHECK(child_bb_node);
606 bb_model_->SetTitle(child_bb_node, child_b_node->GetTitle());
608 ApplyNameChangesAndCreateNewFolders(child_bb_node, child_b_node,
609 parent_b_node, parent_bb_node);
613 void BookmarkEditorView::UpdateExpandedNodes(
614 EditorNode* editor_node,
615 BookmarkExpandedStateTracker::Nodes* expanded_nodes) {
616 if (!tree_view_->IsExpanded(editor_node))
617 return;
619 // The root is 0.
620 if (editor_node->value != 0) {
621 expanded_nodes->insert(
622 bookmarks::GetBookmarkNodeByID(bb_model_, editor_node->value));
625 for (int i = 0; i < editor_node->child_count(); ++i)
626 UpdateExpandedNodes(editor_node->GetChild(i), expanded_nodes);
629 ui::SimpleMenuModel* BookmarkEditorView::GetMenuModel() {
630 if (!context_menu_model_.get()) {
631 context_menu_model_.reset(new ui::SimpleMenuModel(this));
632 context_menu_model_->AddItemWithStringId(IDS_EDIT, IDS_EDIT);
633 context_menu_model_->AddItemWithStringId(IDS_DELETE, IDS_DELETE);
634 context_menu_model_->AddItemWithStringId(
635 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM,
636 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM);
638 return context_menu_model_.get();
641 void BookmarkEditorView::EditorTreeModel::SetTitle(
642 ui::TreeModelNode* node,
643 const base::string16& title) {
644 if (!title.empty())
645 ui::TreeNodeModel<EditorNode>::SetTitle(node, title);
648 namespace chrome {
650 void ShowBookmarkEditorViews(gfx::NativeWindow parent_window,
651 Profile* profile,
652 const BookmarkEditor::EditDetails& details,
653 BookmarkEditor::Configuration configuration) {
654 DCHECK(profile);
655 BookmarkEditorView* editor = new BookmarkEditorView(
656 profile, details.parent_node, details, configuration);
657 editor->Show(parent_window);
660 } // namespace chrome