bookmark_editor_view.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/browser/bookmark_model.h" 21#include "components/bookmarks/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() const { 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( 380 BookmarkModel* model, 381 const BookmarkNode* parent, 382 int index, 383 const BookmarkNode* node, 384 const std::set<GURL>& removed_urls) { 385 if ((details_.type == EditDetails::EXISTING_NODE && 386 details_.existing_node->HasAncestor(node)) || 387 (parent_ && parent_->HasAncestor(node))) { 388 // The node, or its parent was removed. Close the dialog. 389 GetWidget()->Close(); 390 } else { 391 Reset(); 392 } 393} 394 395void BookmarkEditorView::BookmarkAllNodesRemoved( 396 BookmarkModel* model, 397 const std::set<GURL>& removed_urls) { 398 Reset(); 399} 400 401void BookmarkEditorView::BookmarkNodeChildrenReordered( 402 BookmarkModel* model, 403 const BookmarkNode* node) { 404 Reset(); 405} 406 407void BookmarkEditorView::Reset() { 408 if (!show_tree_) { 409 if (parent()) 410 UserInputChanged(); 411 return; 412 } 413 414 new_folder_button_->SetEnabled(true); 415 416 // Do this first, otherwise when we invoke SetModel with the real one 417 // tree_view will try to invoke something on the model we just deleted. 418 tree_view_->SetModel(NULL); 419 420 EditorNode* root_node = CreateRootNode(); 421 tree_model_.reset(new EditorTreeModel(root_node)); 422 423 tree_view_->SetModel(tree_model_.get()); 424 tree_view_->SetController(this); 425 426 context_menu_runner_.reset(); 427 428 if (parent()) 429 ExpandAndSelect(); 430} 431 432GURL BookmarkEditorView::GetInputURL() const { 433 if (details_.GetNodeType() == BookmarkNode::FOLDER) 434 return GURL(); 435 return URLFixerUpper::FixupURL( 436 base::UTF16ToUTF8(url_tf_->text()), std::string()); 437} 438 439void BookmarkEditorView::UserInputChanged() { 440 if (details_.GetNodeType() != BookmarkNode::FOLDER) { 441 const GURL url(GetInputURL()); 442 if (!url.is_valid()) 443 url_tf_->SetBackgroundColor(kErrorColor); 444 else 445 url_tf_->UseDefaultBackgroundColor(); 446 } 447 GetDialogClientView()->UpdateDialogButtons(); 448} 449 450void BookmarkEditorView::NewFolder() { 451 // Create a new entry parented to the selected item, or the bookmark 452 // bar if nothing is selected. 453 EditorNode* parent = tree_model_->AsNode(tree_view_->GetSelectedNode()); 454 if (!parent) { 455 NOTREACHED(); 456 return; 457 } 458 459 tree_view_->StartEditing(AddNewFolder(parent)); 460} 461 462BookmarkEditorView::EditorNode* BookmarkEditorView::AddNewFolder( 463 EditorNode* parent) { 464 EditorNode* new_node = new EditorNode( 465 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME), 0); 466 // |new_node| is now owned by |parent|. 467 tree_model_->Add(parent, new_node, parent->child_count()); 468 return new_node; 469} 470 471void BookmarkEditorView::ExpandAndSelect() { 472 BookmarkExpandedStateTracker::Nodes expanded_nodes = 473 bb_model_->expanded_state_tracker()->GetExpandedNodes(); 474 for (BookmarkExpandedStateTracker::Nodes::const_iterator i( 475 expanded_nodes.begin()); i != expanded_nodes.end(); ++i) { 476 EditorNode* editor_node = 477 FindNodeWithID(tree_model_->GetRoot(), (*i)->id()); 478 if (editor_node) 479 tree_view_->Expand(editor_node); 480 } 481 482 const BookmarkNode* to_select = parent_; 483 if (details_.type == EditDetails::EXISTING_NODE) 484 to_select = details_.existing_node->parent(); 485 int64 folder_id_to_select = to_select->id(); 486 EditorNode* b_node = 487 FindNodeWithID(tree_model_->GetRoot(), folder_id_to_select); 488 if (!b_node) 489 b_node = tree_model_->GetRoot()->GetChild(0); // Bookmark bar node. 490 491 tree_view_->SetSelectedNode(b_node); 492} 493 494BookmarkEditorView::EditorNode* BookmarkEditorView::CreateRootNode() { 495 EditorNode* root_node = new EditorNode(base::string16(), 0); 496 const BookmarkNode* bb_root_node = bb_model_->root_node(); 497 CreateNodes(bb_root_node, root_node); 498 DCHECK(root_node->child_count() >= 2 && root_node->child_count() <= 3); 499 DCHECK_EQ(BookmarkNode::BOOKMARK_BAR, bb_root_node->GetChild(0)->type()); 500 DCHECK_EQ(BookmarkNode::OTHER_NODE, bb_root_node->GetChild(1)->type()); 501 if (root_node->child_count() == 3) 502 DCHECK_EQ(BookmarkNode::MOBILE, bb_root_node->GetChild(2)->type()); 503 return root_node; 504} 505 506void BookmarkEditorView::CreateNodes(const BookmarkNode* bb_node, 507 BookmarkEditorView::EditorNode* b_node) { 508 for (int i = 0; i < bb_node->child_count(); ++i) { 509 const BookmarkNode* child_bb_node = bb_node->GetChild(i); 510 if (child_bb_node->IsVisible() && child_bb_node->is_folder()) { 511 EditorNode* new_b_node = new EditorNode(child_bb_node->GetTitle(), 512 child_bb_node->id()); 513 b_node->Add(new_b_node, b_node->child_count()); 514 CreateNodes(child_bb_node, new_b_node); 515 } 516 } 517} 518 519BookmarkEditorView::EditorNode* BookmarkEditorView::FindNodeWithID( 520 BookmarkEditorView::EditorNode* node, 521 int64 id) { 522 if (node->value == id) 523 return node; 524 for (int i = 0; i < node->child_count(); ++i) { 525 EditorNode* result = FindNodeWithID(node->GetChild(i), id); 526 if (result) 527 return result; 528 } 529 return NULL; 530} 531 532void BookmarkEditorView::ApplyEdits() { 533 DCHECK(bb_model_->loaded()); 534 535 if (tree_view_) 536 tree_view_->CommitEdit(); 537 538 EditorNode* parent = show_tree_ ? 539 tree_model_->AsNode(tree_view_->GetSelectedNode()) : NULL; 540 if (show_tree_ && !parent) { 541 NOTREACHED(); 542 return; 543 } 544 ApplyEdits(parent); 545} 546 547void BookmarkEditorView::ApplyEdits(EditorNode* parent) { 548 DCHECK(!show_tree_ || parent); 549 550 // We're going to apply edits to the bookmark bar model, which will call us 551 // back. Normally when a structural edit occurs we reset the tree model. 552 // We don't want to do that here, so we remove ourselves as an observer. 553 bb_model_->RemoveObserver(this); 554 555 GURL new_url(GetInputURL()); 556 base::string16 new_title(title_tf_->text()); 557 558 if (!show_tree_) { 559 BookmarkEditor::ApplyEditsWithNoFolderChange( 560 bb_model_, parent_, details_, new_title, new_url); 561 return; 562 } 563 564 // Create the new folders and update the titles. 565 const BookmarkNode* new_parent = NULL; 566 ApplyNameChangesAndCreateNewFolders( 567 bb_model_->root_node(), tree_model_->GetRoot(), parent, &new_parent); 568 569 BookmarkEditor::ApplyEditsWithPossibleFolderChange( 570 bb_model_, new_parent, details_, new_title, new_url); 571 572 BookmarkExpandedStateTracker::Nodes expanded_nodes; 573 UpdateExpandedNodes(tree_model_->GetRoot(), &expanded_nodes); 574 bb_model_->expanded_state_tracker()->SetExpandedNodes(expanded_nodes); 575 576 // Remove the folders that were removed. This has to be done after all the 577 // other changes have been committed. 578 bookmark_utils::DeleteBookmarkFolders(bb_model_, deletes_); 579} 580 581void BookmarkEditorView::ApplyNameChangesAndCreateNewFolders( 582 const BookmarkNode* bb_node, 583 BookmarkEditorView::EditorNode* b_node, 584 BookmarkEditorView::EditorNode* parent_b_node, 585 const BookmarkNode** parent_bb_node) { 586 if (parent_b_node == b_node) 587 *parent_bb_node = bb_node; 588 for (int i = 0; i < b_node->child_count(); ++i) { 589 EditorNode* child_b_node = b_node->GetChild(i); 590 const BookmarkNode* child_bb_node = NULL; 591 if (child_b_node->value == 0) { 592 // New folder. 593 child_bb_node = bb_model_->AddFolder(bb_node, 594 bb_node->child_count(), child_b_node->GetTitle()); 595 child_b_node->value = child_bb_node->id(); 596 } else { 597 // Existing node, reset the title (BookmarkModel ignores changes if the 598 // title is the same). 599 for (int j = 0; j < bb_node->child_count(); ++j) { 600 const BookmarkNode* node = bb_node->GetChild(j); 601 if (node->is_folder() && node->id() == child_b_node->value) { 602 child_bb_node = node; 603 break; 604 } 605 } 606 DCHECK(child_bb_node); 607 bb_model_->SetTitle(child_bb_node, child_b_node->GetTitle()); 608 } 609 ApplyNameChangesAndCreateNewFolders(child_bb_node, child_b_node, 610 parent_b_node, parent_bb_node); 611 } 612} 613 614void BookmarkEditorView::UpdateExpandedNodes( 615 EditorNode* editor_node, 616 BookmarkExpandedStateTracker::Nodes* expanded_nodes) { 617 if (!tree_view_->IsExpanded(editor_node)) 618 return; 619 620 if (editor_node->value != 0) // The root is 0. 621 expanded_nodes->insert(GetBookmarkNodeByID(bb_model_, editor_node->value)); 622 623 for (int i = 0; i < editor_node->child_count(); ++i) 624 UpdateExpandedNodes(editor_node->GetChild(i), expanded_nodes); 625} 626 627ui::SimpleMenuModel* BookmarkEditorView::GetMenuModel() { 628 if (!context_menu_model_.get()) { 629 context_menu_model_.reset(new ui::SimpleMenuModel(this)); 630 context_menu_model_->AddItemWithStringId(IDS_EDIT, IDS_EDIT); 631 context_menu_model_->AddItemWithStringId(IDS_DELETE, IDS_DELETE); 632 context_menu_model_->AddItemWithStringId( 633 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM, 634 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM); 635 } 636 return context_menu_model_.get(); 637} 638 639void BookmarkEditorView::EditorTreeModel::SetTitle( 640 ui::TreeModelNode* node, 641 const base::string16& title) { 642 if (!title.empty()) 643 ui::TreeNodeModel<EditorNode>::SetTitle(node, title); 644} 645