bookmark_editor_view.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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. 4 5#include "chrome/browser/ui/views/bookmarks/bookmark_editor_view.h" 6 7#include <string> 8 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/history/history_service.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 18#include "chrome/browser/ui/views/constrained_window_views.h" 19#include "chrome/common/net/url_fixer_upper.h" 20#include "components/bookmarks/core/browser/bookmark_model.h" 21#include "components/bookmarks/core/browser/bookmark_utils.h" 22#include "components/user_prefs/user_prefs.h" 23#include "grit/chromium_strings.h" 24#include "grit/generated_resources.h" 25#include "grit/locale_settings.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" 41 42using views::GridLayout; 43 44namespace { 45 46// Background color of text field when URL is invalid. 47const SkColor kErrorColor = SkColorSetRGB(0xFF, 0xBC, 0xBC); 48 49} // namespace 50 51// static 52void BookmarkEditor::Show(gfx::NativeWindow parent_window, 53 Profile* profile, 54 const EditDetails& details, 55 Configuration configuration) { 56 DCHECK(profile); 57 BookmarkEditorView* editor = new BookmarkEditorView(profile, 58 details.parent_node, details, configuration); 59 editor->Show(parent_window); 60} 61 62BookmarkEditorView::BookmarkEditorView( 63 Profile* profile, 64 const BookmarkNode* parent, 65 const EditDetails& details, 66 BookmarkEditor::Configuration configuration) 67 : profile_(profile), 68 tree_view_(NULL), 69 url_label_(NULL), 70 url_tf_(NULL), 71 title_label_(NULL), 72 title_tf_(NULL), 73 parent_(parent), 74 details_(details), 75 running_menu_for_root_(false), 76 show_tree_(configuration == SHOW_TREE) { 77 DCHECK(profile); 78 Init(); 79} 80 81BookmarkEditorView::~BookmarkEditorView() { 82 // The tree model is deleted before the view. Reset the model otherwise the 83 // tree will reference a deleted model. 84 if (tree_view_) 85 tree_view_->SetModel(NULL); 86 bb_model_->RemoveObserver(this); 87} 88 89base::string16 BookmarkEditorView::GetDialogButtonLabel( 90 ui::DialogButton button) const { 91 if (button == ui::DIALOG_BUTTON_OK) 92 return l10n_util::GetStringUTF16(IDS_SAVE); 93 return views::DialogDelegateView::GetDialogButtonLabel(button); 94} 95 96bool BookmarkEditorView::IsDialogButtonEnabled(ui::DialogButton button) const { 97 if (button == ui::DIALOG_BUTTON_OK) { 98 if (!bb_model_->loaded()) 99 return false; 100 101 if (details_.GetNodeType() != BookmarkNode::FOLDER) 102 return GetInputURL().is_valid(); 103 } 104 return true; 105} 106 107views::View* BookmarkEditorView::CreateExtraView() { 108 return new_folder_button_.get(); 109} 110 111ui::ModalType BookmarkEditorView::GetModalType() const { 112 return ui::MODAL_TYPE_WINDOW; 113} 114 115bool BookmarkEditorView::CanResize() const { 116 return true; 117} 118 119base::string16 BookmarkEditorView::GetWindowTitle() const { 120 return l10n_util::GetStringUTF16(details_.GetWindowTitleId()); 121} 122 123bool BookmarkEditorView::Accept() { 124 if (!IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)) { 125 if (details_.GetNodeType() != BookmarkNode::FOLDER) { 126 // The url is invalid, focus the url field. 127 url_tf_->SelectAll(true); 128 url_tf_->RequestFocus(); 129 } 130 return false; 131 } 132 // Otherwise save changes and close the dialog box. 133 ApplyEdits(); 134 return true; 135} 136 137gfx::Size BookmarkEditorView::GetPreferredSize() { 138 if (!show_tree_) 139 return views::View::GetPreferredSize(); 140 141 return gfx::Size(views::Widget::GetLocalizedContentsSize( 142 IDS_EDITBOOKMARK_DIALOG_WIDTH_CHARS, 143 IDS_EDITBOOKMARK_DIALOG_HEIGHT_LINES)); 144} 145 146void BookmarkEditorView::OnTreeViewSelectionChanged( 147 views::TreeView* tree_view) { 148} 149 150bool BookmarkEditorView::CanEdit(views::TreeView* tree_view, 151 ui::TreeModelNode* node) { 152 // Only allow editting of children of the bookmark bar node and other node. 153 EditorNode* bb_node = tree_model_->AsNode(node); 154 return (bb_node->parent() && bb_node->parent()->parent()); 155} 156 157void BookmarkEditorView::ContentsChanged(views::Textfield* sender, 158 const base::string16& new_contents) { 159 UserInputChanged(); 160} 161 162bool BookmarkEditorView::HandleKeyEvent(views::Textfield* sender, 163 const ui::KeyEvent& key_event) { 164 return false; 165} 166 167void BookmarkEditorView::GetAccessibleState(ui::AXViewState* state) { 168 state->name = 169 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_TITLE); 170 state->role = ui::AX_ROLE_DIALOG; 171} 172 173void BookmarkEditorView::ButtonPressed(views::Button* sender, 174 const ui::Event& event) { 175 DCHECK_EQ(new_folder_button_.get(), sender); 176 NewFolder(); 177} 178 179bool BookmarkEditorView::IsCommandIdChecked(int command_id) const { 180 return false; 181} 182 183bool BookmarkEditorView::IsCommandIdEnabled(int command_id) const { 184 switch (command_id) { 185 case IDS_EDIT: 186 case IDS_DELETE: 187 return !running_menu_for_root_; 188 case IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM: 189 return true; 190 default: 191 NOTREACHED(); 192 return false; 193 } 194} 195 196bool BookmarkEditorView::GetAcceleratorForCommandId( 197 int command_id, 198 ui::Accelerator* accelerator) { 199 return GetWidget()->GetAccelerator(command_id, accelerator); 200} 201 202void BookmarkEditorView::ExecuteCommand(int command_id, int event_flags) { 203 DCHECK(tree_view_->GetSelectedNode()); 204 if (command_id == IDS_EDIT) { 205 tree_view_->StartEditing(tree_view_->GetSelectedNode()); 206 } else if (command_id == IDS_DELETE) { 207 EditorNode* node = tree_model_->AsNode(tree_view_->GetSelectedNode()); 208 if (!node) 209 return; 210 if (node->value != 0) { 211 const BookmarkNode* b_node = GetBookmarkNodeByID(bb_model_, node->value); 212 if (!b_node->empty() && 213 !chrome::ConfirmDeleteBookmarkNode(b_node, 214 GetWidget()->GetNativeWindow())) { 215 // The folder is not empty and the user didn't confirm. 216 return; 217 } 218 deletes_.push_back(node->value); 219 } 220 tree_model_->Remove(node->parent(), node); 221 } else { 222 DCHECK_EQ(IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM, command_id); 223 NewFolder(); 224 } 225} 226 227void BookmarkEditorView::Show(gfx::NativeWindow parent) { 228 CreateBrowserModalDialogViews(this, parent); 229 UserInputChanged(); 230 if (show_tree_ && bb_model_->loaded()) 231 ExpandAndSelect(); 232 GetWidget()->Show(); 233 // Select all the text in the name Textfield. 234 title_tf_->SelectAll(true); 235 // Give focus to the name Textfield. 236 title_tf_->RequestFocus(); 237} 238 239void BookmarkEditorView::ShowContextMenuForView( 240 views::View* source, 241 const gfx::Point& point, 242 ui::MenuSourceType source_type) { 243 DCHECK_EQ(tree_view_, source); 244 if (!tree_view_->GetSelectedNode()) 245 return; 246 running_menu_for_root_ = 247 (tree_model_->GetParent(tree_view_->GetSelectedNode()) == 248 tree_model_->GetRoot()); 249 250 context_menu_runner_.reset(new views::MenuRunner(GetMenuModel())); 251 252 if (context_menu_runner_->RunMenuAt( 253 source->GetWidget()->GetTopLevelWidget(), 254 NULL, 255 gfx::Rect(point, gfx::Size()), 256 views::MENU_ANCHOR_TOPRIGHT, 257 source_type, 258 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) == 259 views::MenuRunner::MENU_DELETED) { 260 return; 261 } 262} 263 264void BookmarkEditorView::Init() { 265 bb_model_ = BookmarkModelFactory::GetForProfile(profile_); 266 DCHECK(bb_model_); 267 bb_model_->AddObserver(this); 268 269 title_label_ = new views::Label( 270 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NAME_LABEL)); 271 272 base::string16 title; 273 GURL url; 274 if (details_.type == EditDetails::EXISTING_NODE) { 275 title = details_.existing_node->GetTitle(); 276 url = details_.existing_node->url(); 277 } else if (details_.type == EditDetails::NEW_FOLDER) { 278 title = l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME); 279 } else if (details_.type == EditDetails::NEW_URL) { 280 url = details_.url; 281 title = details_.title; 282 } 283 title_tf_ = new views::Textfield; 284 title_tf_->SetAccessibleName( 285 l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_EDITOR_NAME_LABEL)); 286 title_tf_->SetText(title); 287 title_tf_->set_controller(this); 288 289 if (show_tree_) { 290 tree_view_ = new views::TreeView; 291 tree_view_->SetRootShown(false); 292 tree_view_->set_context_menu_controller(this); 293 294 new_folder_button_.reset(new views::LabelButton(this, 295 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_BUTTON))); 296 new_folder_button_->SetStyle(views::Button::STYLE_BUTTON); 297 new_folder_button_->set_owned_by_client(); 298 new_folder_button_->SetEnabled(false); 299 } 300 301 GridLayout* layout = GridLayout::CreatePanel(this); 302 SetLayoutManager(layout); 303 304 const int labels_column_set_id = 0; 305 const int single_column_view_set_id = 1; 306 const int buttons_column_set_id = 2; 307 308 views::ColumnSet* column_set = layout->AddColumnSet(labels_column_set_id); 309 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, 310 GridLayout::USE_PREF, 0, 0); 311 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 312 column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, 313 GridLayout::USE_PREF, 0, 0); 314 315 column_set = layout->AddColumnSet(single_column_view_set_id); 316 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, 317 GridLayout::USE_PREF, 0, 0); 318 319 column_set = layout->AddColumnSet(buttons_column_set_id); 320 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, 321 GridLayout::USE_PREF, 0, 0); 322 column_set->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing); 323 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, 324 GridLayout::USE_PREF, 0, 0); 325 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 326 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, 327 GridLayout::USE_PREF, 0, 0); 328 column_set->LinkColumnSizes(0, 2, 4, -1); 329 330 layout->StartRow(0, labels_column_set_id); 331 layout->AddView(title_label_); 332 layout->AddView(title_tf_); 333 334 if (details_.GetNodeType() != BookmarkNode::FOLDER) { 335 url_label_ = new views::Label( 336 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_URL_LABEL)); 337 338 url_tf_ = new views::Textfield; 339 PrefService* prefs = 340 profile_ ? user_prefs::UserPrefs::Get(profile_) : NULL; 341 url_tf_->SetText(chrome::FormatBookmarkURLForDisplay(url, prefs)); 342 url_tf_->set_controller(this); 343 url_tf_->SetAccessibleName( 344 l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_EDITOR_URL_LABEL)); 345 346 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 347 348 layout->StartRow(0, labels_column_set_id); 349 layout->AddView(url_label_); 350 layout->AddView(url_tf_); 351 } 352 353 if (show_tree_) { 354 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 355 layout->StartRow(1, single_column_view_set_id); 356 layout->AddView(tree_view_->CreateParentIfNecessary()); 357 } 358 359 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 360 361 if (!show_tree_ || bb_model_->loaded()) 362 Reset(); 363} 364 365void BookmarkEditorView::BookmarkNodeMoved(BookmarkModel* model, 366 const BookmarkNode* old_parent, 367 int old_index, 368 const BookmarkNode* new_parent, 369 int new_index) { 370 Reset(); 371} 372 373void BookmarkEditorView::BookmarkNodeAdded(BookmarkModel* model, 374 const BookmarkNode* parent, 375 int index) { 376 Reset(); 377} 378 379void BookmarkEditorView::BookmarkNodeRemoved(BookmarkModel* model, 380 const BookmarkNode* parent, 381 int index, 382 const BookmarkNode* node) { 383 if ((details_.type == EditDetails::EXISTING_NODE && 384 details_.existing_node->HasAncestor(node)) || 385 (parent_ && parent_->HasAncestor(node))) { 386 // The node, or its parent was removed. Close the dialog. 387 GetWidget()->Close(); 388 } else { 389 Reset(); 390 } 391} 392 393void BookmarkEditorView::BookmarkAllNodesRemoved(BookmarkModel* model) { 394 Reset(); 395} 396 397void BookmarkEditorView::BookmarkNodeChildrenReordered( 398 BookmarkModel* model, const BookmarkNode* node) { 399 Reset(); 400} 401 402void BookmarkEditorView::Reset() { 403 if (!show_tree_) { 404 if (parent()) 405 UserInputChanged(); 406 return; 407 } 408 409 new_folder_button_->SetEnabled(true); 410 411 // Do this first, otherwise when we invoke SetModel with the real one 412 // tree_view will try to invoke something on the model we just deleted. 413 tree_view_->SetModel(NULL); 414 415 EditorNode* root_node = CreateRootNode(); 416 tree_model_.reset(new EditorTreeModel(root_node)); 417 418 tree_view_->SetModel(tree_model_.get()); 419 tree_view_->SetController(this); 420 421 context_menu_runner_.reset(); 422 423 if (parent()) 424 ExpandAndSelect(); 425} 426 427GURL BookmarkEditorView::GetInputURL() const { 428 if (details_.GetNodeType() == BookmarkNode::FOLDER) 429 return GURL(); 430 return URLFixerUpper::FixupURL( 431 base::UTF16ToUTF8(url_tf_->text()), std::string()); 432} 433 434void BookmarkEditorView::UserInputChanged() { 435 if (details_.GetNodeType() != BookmarkNode::FOLDER) { 436 const GURL url(GetInputURL()); 437 if (!url.is_valid()) 438 url_tf_->SetBackgroundColor(kErrorColor); 439 else 440 url_tf_->UseDefaultBackgroundColor(); 441 } 442 GetDialogClientView()->UpdateDialogButtons(); 443} 444 445void BookmarkEditorView::NewFolder() { 446 // Create a new entry parented to the selected item, or the bookmark 447 // bar if nothing is selected. 448 EditorNode* parent = tree_model_->AsNode(tree_view_->GetSelectedNode()); 449 if (!parent) { 450 NOTREACHED(); 451 return; 452 } 453 454 tree_view_->StartEditing(AddNewFolder(parent)); 455} 456 457BookmarkEditorView::EditorNode* BookmarkEditorView::AddNewFolder( 458 EditorNode* parent) { 459 EditorNode* new_node = new EditorNode( 460 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME), 0); 461 // |new_node| is now owned by |parent|. 462 tree_model_->Add(parent, new_node, parent->child_count()); 463 return new_node; 464} 465 466void BookmarkEditorView::ExpandAndSelect() { 467 BookmarkExpandedStateTracker::Nodes expanded_nodes = 468 bb_model_->expanded_state_tracker()->GetExpandedNodes(); 469 for (BookmarkExpandedStateTracker::Nodes::const_iterator i( 470 expanded_nodes.begin()); i != expanded_nodes.end(); ++i) { 471 EditorNode* editor_node = 472 FindNodeWithID(tree_model_->GetRoot(), (*i)->id()); 473 if (editor_node) 474 tree_view_->Expand(editor_node); 475 } 476 477 const BookmarkNode* to_select = parent_; 478 if (details_.type == EditDetails::EXISTING_NODE) 479 to_select = details_.existing_node->parent(); 480 int64 folder_id_to_select = to_select->id(); 481 EditorNode* b_node = 482 FindNodeWithID(tree_model_->GetRoot(), folder_id_to_select); 483 if (!b_node) 484 b_node = tree_model_->GetRoot()->GetChild(0); // Bookmark bar node. 485 486 tree_view_->SetSelectedNode(b_node); 487} 488 489BookmarkEditorView::EditorNode* BookmarkEditorView::CreateRootNode() { 490 EditorNode* root_node = new EditorNode(base::string16(), 0); 491 const BookmarkNode* bb_root_node = bb_model_->root_node(); 492 CreateNodes(bb_root_node, root_node); 493 DCHECK(root_node->child_count() >= 2 && root_node->child_count() <= 3); 494 DCHECK_EQ(BookmarkNode::BOOKMARK_BAR, bb_root_node->GetChild(0)->type()); 495 DCHECK_EQ(BookmarkNode::OTHER_NODE, bb_root_node->GetChild(1)->type()); 496 if (root_node->child_count() == 3) 497 DCHECK_EQ(BookmarkNode::MOBILE, bb_root_node->GetChild(2)->type()); 498 return root_node; 499} 500 501void BookmarkEditorView::CreateNodes(const BookmarkNode* bb_node, 502 BookmarkEditorView::EditorNode* b_node) { 503 for (int i = 0; i < bb_node->child_count(); ++i) { 504 const BookmarkNode* child_bb_node = bb_node->GetChild(i); 505 if (child_bb_node->IsVisible() && child_bb_node->is_folder()) { 506 EditorNode* new_b_node = new EditorNode(child_bb_node->GetTitle(), 507 child_bb_node->id()); 508 b_node->Add(new_b_node, b_node->child_count()); 509 CreateNodes(child_bb_node, new_b_node); 510 } 511 } 512} 513 514BookmarkEditorView::EditorNode* BookmarkEditorView::FindNodeWithID( 515 BookmarkEditorView::EditorNode* node, 516 int64 id) { 517 if (node->value == id) 518 return node; 519 for (int i = 0; i < node->child_count(); ++i) { 520 EditorNode* result = FindNodeWithID(node->GetChild(i), id); 521 if (result) 522 return result; 523 } 524 return NULL; 525} 526 527void BookmarkEditorView::ApplyEdits() { 528 DCHECK(bb_model_->loaded()); 529 530 if (tree_view_) 531 tree_view_->CommitEdit(); 532 533 EditorNode* parent = show_tree_ ? 534 tree_model_->AsNode(tree_view_->GetSelectedNode()) : NULL; 535 if (show_tree_ && !parent) { 536 NOTREACHED(); 537 return; 538 } 539 ApplyEdits(parent); 540} 541 542void BookmarkEditorView::ApplyEdits(EditorNode* parent) { 543 DCHECK(!show_tree_ || parent); 544 545 // We're going to apply edits to the bookmark bar model, which will call us 546 // back. Normally when a structural edit occurs we reset the tree model. 547 // We don't want to do that here, so we remove ourselves as an observer. 548 bb_model_->RemoveObserver(this); 549 550 GURL new_url(GetInputURL()); 551 base::string16 new_title(title_tf_->text()); 552 553 if (!show_tree_) { 554 BookmarkEditor::ApplyEditsWithNoFolderChange( 555 bb_model_, parent_, details_, new_title, new_url); 556 return; 557 } 558 559 // Create the new folders and update the titles. 560 const BookmarkNode* new_parent = NULL; 561 ApplyNameChangesAndCreateNewFolders( 562 bb_model_->root_node(), tree_model_->GetRoot(), parent, &new_parent); 563 564 BookmarkEditor::ApplyEditsWithPossibleFolderChange( 565 bb_model_, new_parent, details_, new_title, new_url); 566 567 BookmarkExpandedStateTracker::Nodes expanded_nodes; 568 UpdateExpandedNodes(tree_model_->GetRoot(), &expanded_nodes); 569 bb_model_->expanded_state_tracker()->SetExpandedNodes(expanded_nodes); 570 571 // Remove the folders that were removed. This has to be done after all the 572 // other changes have been committed. 573 bookmark_utils::DeleteBookmarkFolders(bb_model_, deletes_); 574} 575 576void BookmarkEditorView::ApplyNameChangesAndCreateNewFolders( 577 const BookmarkNode* bb_node, 578 BookmarkEditorView::EditorNode* b_node, 579 BookmarkEditorView::EditorNode* parent_b_node, 580 const BookmarkNode** parent_bb_node) { 581 if (parent_b_node == b_node) 582 *parent_bb_node = bb_node; 583 for (int i = 0; i < b_node->child_count(); ++i) { 584 EditorNode* child_b_node = b_node->GetChild(i); 585 const BookmarkNode* child_bb_node = NULL; 586 if (child_b_node->value == 0) { 587 // New folder. 588 child_bb_node = bb_model_->AddFolder(bb_node, 589 bb_node->child_count(), child_b_node->GetTitle()); 590 child_b_node->value = child_bb_node->id(); 591 } else { 592 // Existing node, reset the title (BookmarkModel ignores changes if the 593 // title is the same). 594 for (int j = 0; j < bb_node->child_count(); ++j) { 595 const BookmarkNode* node = bb_node->GetChild(j); 596 if (node->is_folder() && node->id() == child_b_node->value) { 597 child_bb_node = node; 598 break; 599 } 600 } 601 DCHECK(child_bb_node); 602 bb_model_->SetTitle(child_bb_node, child_b_node->GetTitle()); 603 } 604 ApplyNameChangesAndCreateNewFolders(child_bb_node, child_b_node, 605 parent_b_node, parent_bb_node); 606 } 607} 608 609void BookmarkEditorView::UpdateExpandedNodes( 610 EditorNode* editor_node, 611 BookmarkExpandedStateTracker::Nodes* expanded_nodes) { 612 if (!tree_view_->IsExpanded(editor_node)) 613 return; 614 615 if (editor_node->value != 0) // The root is 0. 616 expanded_nodes->insert(GetBookmarkNodeByID(bb_model_, editor_node->value)); 617 618 for (int i = 0; i < editor_node->child_count(); ++i) 619 UpdateExpandedNodes(editor_node->GetChild(i), expanded_nodes); 620} 621 622ui::SimpleMenuModel* BookmarkEditorView::GetMenuModel() { 623 if (!context_menu_model_.get()) { 624 context_menu_model_.reset(new ui::SimpleMenuModel(this)); 625 context_menu_model_->AddItemWithStringId(IDS_EDIT, IDS_EDIT); 626 context_menu_model_->AddItemWithStringId(IDS_DELETE, IDS_DELETE); 627 context_menu_model_->AddItemWithStringId( 628 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM, 629 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM); 630 } 631 return context_menu_model_.get(); 632} 633 634void BookmarkEditorView::EditorTreeModel::SetTitle( 635 ui::TreeModelNode* node, 636 const base::string16& title) { 637 if (!title.empty()) 638 ui::TreeNodeModel<EditorNode>::SetTitle(node, title); 639} 640