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