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