blob: 1cad27351309d1cb33c15f99b62c96c13ed6d024 [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/views/bookmark_manager_view.h"
#include <algorithm>
#include "app/gfx/canvas.h"
#include "app/gfx/color_utils.h"
#include "app/l10n_util.h"
#include "base/keyboard_codes.h"
#include "base/thread.h"
#include "chrome/browser/bookmarks/bookmark_folder_tree_model.h"
#include "chrome/browser/bookmarks/bookmark_html_writer.h"
#include "chrome/browser/bookmarks/bookmark_manager.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_table_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/bookmark_editor_view.h"
#include "chrome/browser/views/bookmark_folder_tree_view.h"
#include "chrome/browser/views/bookmark_table_view.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "skia/ext/skia_utils.h"
#include "third_party/skia/include/core/SkShader.h"
#include "views/grid_layout.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_item_view.h"
#include "views/controls/label.h"
#include "views/controls/single_split_view.h"
#include "views/standard_layout.h"
#include "views/widget/widget.h"
#include "views/window/window.h"
#if defined(CHROME_PERSONALIZATION)
#include "chrome/browser/options_window.h"
#include "chrome/browser/sync/sync_status_ui_helper.h"
#endif
// If non-null, there is an open editor and this is the window it is contained
// in it.
static views::Window* open_window = NULL;
// And this is the manager contained in it.
static BookmarkManagerView* manager = NULL;
// Delay, in ms, between when the user types and when we run the search.
static const int kSearchDelayMS = 200;
static const int kOrganizeMenuButtonID = 1;
static const int kToolsMenuButtonID = 2;
// Background color.
static const SkColor kBackgroundColorTop = SkColorSetRGB(242, 247, 253);
static const SkColor kBackgroundColorBottom = SkColorSetRGB(223, 234, 248);
static const int kBackgroundGradientHeight = 28;
namespace {
// Observer installed on the importer. When done importing the newly created
// folder is selected in the bookmark manager.
class ImportObserverImpl : public ImportObserver {
public:
explicit ImportObserverImpl(Profile* profile) : profile_(profile) {
BookmarkModel* model = profile->GetBookmarkModel();
initial_other_count_ = model->other_node()->GetChildCount();
}
virtual void ImportCanceled() {
delete this;
}
virtual void ImportComplete() {
// We aren't needed anymore.
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
BookmarkManagerView* manager = BookmarkManagerView::current();
if (!manager || manager->profile() != profile_)
return;
BookmarkModel* model = profile_->GetBookmarkModel();
int other_count = model->other_node()->GetChildCount();
if (other_count == initial_other_count_ + 1) {
const BookmarkNode* imported_node =
model->other_node()->GetChild(initial_other_count_);
manager->SelectInTree(imported_node);
manager->ExpandAll(imported_node);
}
}
private:
Profile* profile_;
// Number of children in the other bookmarks folder at the time we were
// created.
int initial_other_count_;
DISALLOW_COPY_AND_ASSIGN(ImportObserverImpl);
};
// Converts a virtual keycode into the CutCopyPasteType.
BookmarkManagerView::CutCopyPasteType KeyCodeToCutCopyPaste(
unsigned short virtual_keycode) {
switch (virtual_keycode) {
case VK_INSERT:
if (GetKeyState(VK_CONTROL) < 0)
return BookmarkManagerView::COPY;
if (GetKeyState(VK_SHIFT) < 0)
return BookmarkManagerView::PASTE;
return BookmarkManagerView::NONE;
case VK_DELETE:
if (GetKeyState(VK_SHIFT) < 0)
return BookmarkManagerView::CUT;
return BookmarkManagerView::NONE;
case 'C':
if (GetKeyState(VK_CONTROL) < 0)
return BookmarkManagerView::COPY;
return BookmarkManagerView::NONE;
case 'V':
if (GetKeyState(VK_CONTROL) < 0)
return BookmarkManagerView::PASTE;
return BookmarkManagerView::NONE;
case 'X':
if (GetKeyState(VK_CONTROL) < 0)
return BookmarkManagerView::CUT;
return BookmarkManagerView::NONE;
default:
return BookmarkManagerView::NONE;
}
}
} // namespace
namespace browser {
// Declared in browser_dialogs.h so others don't need to depend on our header.
void ShowBookmarkManagerView(Profile* profile) {
BookmarkManagerView::Show(profile);
}
} // namespace browser
// BookmarkManager -------------------------------------------------------------
void BookmarkManager::SelectInTree(Profile* profile, const BookmarkNode* node) {
if (manager && manager->profile() == profile)
manager->SelectInTree(node);
}
void BookmarkManager::Show(Profile* profile) {
BookmarkManagerView::Show(profile);
}
// -----------------------------------------------------------------------------
BookmarkManagerView::BookmarkManagerView(Profile* profile)
: profile_(profile->GetOriginalProfile()),
table_view_(NULL),
tree_view_(NULL),
#if defined(CHROME_PERSONALIZATION)
sync_status_button_(NULL),
sync_service_(NULL),
#endif
ALLOW_THIS_IN_INITIALIZER_LIST(search_factory_(this)) {
search_tf_ = new views::Textfield();
search_tf_->set_default_width_in_chars(30);
table_view_ = new BookmarkTableView(profile_, NULL);
table_view_->SetObserver(this);
table_view_->SetContextMenuController(this);
tree_view_ = new BookmarkFolderTreeView(profile_, NULL);
tree_view_->SetController(this);
tree_view_->SetContextMenuController(this);
views::MenuButton* organize_menu_button = new views::MenuButton(
NULL, l10n_util::GetString(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU),
this, true);
organize_menu_button->SetID(kOrganizeMenuButtonID);
views::MenuButton* tools_menu_button = new views::MenuButton(
NULL, l10n_util::GetString(IDS_BOOKMARK_MANAGER_TOOLS_MENU),
this, true);
tools_menu_button->SetID(kToolsMenuButtonID);
split_view_ = new views::SingleSplitView(tree_view_, table_view_,
views::SingleSplitView::HORIZONTAL_SPLIT);
split_view_->set_resize_leading_on_bounds_change(false);
split_view_->set_background(
views::Background::CreateSolidBackground(kBackgroundColorBottom));
views::GridLayout* layout = new views::GridLayout(this);
SetLayoutManager(layout);
const int top_id = 1;
const int split_cs_id = 2;
layout->SetInsets(2, 0, 0, 0); // 2px padding above content.
views::ColumnSet* column_set = layout->AddColumnSet(top_id);
column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
#if defined(CHROME_PERSONALIZATION)
column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
#endif
column_set->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing);
column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
0, views::GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, 3); // 3px padding at end of row.
column_set = layout->AddColumnSet(split_cs_id);
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, top_id);
layout->AddView(organize_menu_button);
layout->AddView(tools_menu_button);
#if defined(CHROME_PERSONALIZATION)
sync_status_button_ = new views::TextButton(this, std::wstring());
layout->AddView(sync_status_button_);
#endif
layout->AddView(new views::Label(
l10n_util::GetString(IDS_BOOKMARK_MANAGER_SEARCH_TITLE)));
layout->AddView(search_tf_);
layout->AddPaddingRow(0, 3); // 3px padding between rows.
layout->StartRow(1, split_cs_id);
layout->AddView(split_view_);
// Press Ctrl-W to close bookmark manager window.
AddAccelerator(views::Accelerator(base::VKEY_W, false, true, false));
BookmarkModel* bookmark_model = profile_->GetBookmarkModel();
if (!bookmark_model->IsLoaded())
bookmark_model->AddObserver(this);
#if defined(CHROME_PERSONALIZATION)
if (profile->GetProfileSyncService()) {
sync_service_ = profile_->GetProfileSyncService();
sync_service_->AddObserver(this);
UpdateSyncStatus();
}
#endif
}
BookmarkManagerView::~BookmarkManagerView() {
if (select_file_dialog_.get())
select_file_dialog_->ListenerDestroyed();
if (!GetBookmarkModel()->IsLoaded()) {
GetBookmarkModel()->RemoveObserver(this);
} else {
// The models are deleted before the views. Make sure we set the models of
// the views to NULL so that they aren't left holding a reference to a
// deleted model.
table_view_->SetModel(NULL);
tree_view_->SetModel(NULL);
}
manager = NULL;
open_window = NULL;
#if defined(CHROME_PERSONALIZATION)
if (sync_service_)
sync_service_->RemoveObserver(this);
#endif
}
// static
void BookmarkManagerView::Show(Profile* profile) {
if (!profile->GetBookmarkModel())
return;
if (open_window != NULL) {
open_window->Activate();
return;
}
// Both of these will be deleted when the dialog closes.
manager = new BookmarkManagerView(profile);
// Create the window.
open_window = views::Window::CreateChromeWindow(NULL, gfx::Rect(), manager);
// Let the manager know it's parented.
manager->PrepareForShow();
// And show it.
open_window->Show();
// Give initial focus to the search field.
manager->search_tf_->RequestFocus();
}
// static
BookmarkManagerView* BookmarkManagerView::current() {
return manager;
}
void BookmarkManagerView::SelectInTree(const BookmarkNode* node) {
if (!node)
return;
const BookmarkNode* parent = node->is_url() ? node->GetParent() : node;
FolderNode* folder_node = tree_model_->GetFolderNodeForBookmarkNode(parent);
if (!folder_node) {
NOTREACHED();
return;
}
tree_view_->SetSelectedNode(folder_node);
if (node->is_url()) {
int index = table_model_->IndexOfNode(node);
if (index != -1)
table_view_->Select(index);
// TODO(sky): this doesn't work when invoked from add page.
table_view_->RequestFocus();
}
}
void BookmarkManagerView::ExpandAll(const BookmarkNode* node) {
const BookmarkNode* parent = node->is_url() ? node->GetParent() : node;
FolderNode* folder_node = tree_model_->GetFolderNodeForBookmarkNode(parent);
if (!folder_node) {
NOTREACHED();
return;
}
tree_view_->ExpandAll(folder_node);
}
const BookmarkNode* BookmarkManagerView::GetSelectedFolder() {
return tree_view_->GetSelectedBookmarkNode();
}
std::vector<const BookmarkNode*> BookmarkManagerView::GetSelectedTableNodes() {
std::vector<const BookmarkNode*> nodes;
for (views::TableView::iterator i = table_view_->SelectionBegin();
i != table_view_->SelectionEnd(); ++i) {
nodes.push_back(table_model_->GetNodeForRow(*i));
}
// TableViews iterator iterates in reverse order. Reverse the nodes so they
// are opened in visual order.
std::reverse(nodes.begin(), nodes.end());
return nodes;
}
void BookmarkManagerView::PaintBackground(gfx::Canvas* canvas) {
canvas->drawColor(kBackgroundColorBottom, SkXfermode::kSrc_Mode);
SkPaint paint;
paint.setShader(skia::CreateGradientShader(0, kBackgroundGradientHeight,
kBackgroundColorTop,
kBackgroundColorBottom))->safeUnref();
canvas->FillRectInt(0, 0, width(), kBackgroundGradientHeight, paint);
}
gfx::Size BookmarkManagerView::GetPreferredSize() {
return gfx::Size(views::Window::GetLocalizedContentsSize(
IDS_BOOKMARK_MANAGER_DIALOG_WIDTH_CHARS,
IDS_BOOKMARK_MANAGER_DIALOG_HEIGHT_LINES));
}
std::wstring BookmarkManagerView::GetWindowTitle() const {
return l10n_util::GetString(IDS_BOOKMARK_MANAGER_TITLE);
}
std::wstring BookmarkManagerView::GetWindowName() const {
return prefs::kBookmarkManagerPlacement;
}
void BookmarkManagerView::WindowClosing() {
g_browser_process->local_state()->SetInteger(
prefs::kBookmarkManagerSplitLocation, split_view_->divider_offset());
}
#if defined(CHROME_PERSONALIZATION)
void BookmarkManagerView::OnStateChanged() {
UpdateSyncStatus();
}
#endif
bool BookmarkManagerView::AcceleratorPressed(
const views::Accelerator& accelerator) {
// Ctrl-W to close bookmark manager.
DCHECK(accelerator.GetKeyCode() == 'W' && accelerator.IsCtrlDown());
window()->Close();
return true;
}
void BookmarkManagerView::OnDoubleClick() {
std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes();
if (nodes.empty())
return;
if (nodes.size() == 1 && nodes[0]->is_folder()) {
// Double click on a folder descends into the folder.
SelectInTree(nodes[0]);
return;
}
// TODO(sky): OnDoubleClick needs a handle to the current mouse event so that
// we can use
// event_utils::DispositionFromEventFlags(sender->mouse_event_flags()) .
bookmark_utils::OpenAll(
GetWidget()->GetNativeView(), profile_, NULL, nodes, CURRENT_TAB);
}
void BookmarkManagerView::OnMiddleClick() {
std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes();
if (nodes.empty())
return;
if (nodes.size() == 1 && nodes[0]->is_folder()) {
// Middle clicking on a folder results in no action.
return;
}
bookmark_utils::OpenAll(
GetWidget()->GetNativeView(), profile_, NULL, nodes, NEW_FOREGROUND_TAB);
}
void BookmarkManagerView::OnTableViewDelete(views::TableView* table) {
std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes();
if (nodes.empty())
return;
for (size_t i = 0; i < nodes.size(); ++i) {
GetBookmarkModel()->Remove(nodes[i]->GetParent(),
nodes[i]->GetParent()->IndexOfChild(nodes[i]));
}
}
void BookmarkManagerView::OnKeyDown(unsigned short virtual_keycode) {
switch (virtual_keycode) {
case VK_RETURN: {
std::vector<const BookmarkNode*> selected_nodes = GetSelectedTableNodes();
if (selected_nodes.size() == 1 && selected_nodes[0]->is_folder()) {
SelectInTree(selected_nodes[0]);
} else {
bookmark_utils::OpenAll(
GetWidget()->GetNativeView(), profile_, NULL, selected_nodes,
CURRENT_TAB);
}
break;
}
case VK_BACK: {
const BookmarkNode* selected_folder = GetSelectedFolder();
if (selected_folder != NULL &&
selected_folder->GetParent() != GetBookmarkModel()->root_node()) {
SelectInTree(selected_folder->GetParent());
}
break;
}
default:
OnCutCopyPaste(KeyCodeToCutCopyPaste(virtual_keycode), true);
break;
}
}
void BookmarkManagerView::OnTreeViewSelectionChanged(
views::TreeView* tree_view) {
TreeModelNode* node = tree_view_->GetSelectedNode();
BookmarkTableModel* new_table_model = NULL;
const BookmarkNode* table_parent_node = NULL;
bool is_search = false;
if (node) {
switch (tree_model_->GetNodeType(node)) {
case BookmarkFolderTreeModel::BOOKMARK:
table_parent_node = tree_model_->TreeNodeAsBookmarkNode(node);
new_table_model =
BookmarkTableModel::CreateBookmarkTableModelForFolder(
profile_->GetBookmarkModel(),
table_parent_node);
break;
case BookmarkFolderTreeModel::RECENTLY_BOOKMARKED:
new_table_model = BookmarkTableModel::CreateRecentlyBookmarkedModel(
profile_->GetBookmarkModel());
break;
case BookmarkFolderTreeModel::SEARCH:
is_search = true;
search_factory_.RevokeAll();
new_table_model = CreateSearchTableModel();
break;
default:
NOTREACHED();
break;
}
}
SetTableModel(new_table_model, table_parent_node, is_search);
}
void BookmarkManagerView::OnTreeViewKeyDown(unsigned short virtual_keycode) {
switch (virtual_keycode) {
case VK_DELETE: {
const BookmarkNode* node = GetSelectedFolder();
if (!node || node->GetParent() == GetBookmarkModel()->root_node())
return;
const BookmarkNode* parent = node->GetParent();
GetBookmarkModel()->Remove(parent, parent->IndexOfChild(node));
break;
}
default:
OnCutCopyPaste(KeyCodeToCutCopyPaste(virtual_keycode), false);
break;
}
}
#if defined(CHROME_PERSONALIZATION)
void BookmarkManagerView::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == sync_status_button_) {
UserMetrics::RecordAction(L"BookmarkManager_Sync", profile_);
OpenSyncMyBookmarksDialog();
}
}
#endif
void BookmarkManagerView::Loaded(BookmarkModel* model) {
model->RemoveObserver(this);
LoadedImpl();
}
void BookmarkManagerView::ContentsChanged(views::Textfield* sender,
const std::wstring& new_contents) {
search_factory_.RevokeAll();
MessageLoop::current()->PostDelayedTask(FROM_HERE,
search_factory_.NewRunnableMethod(&BookmarkManagerView::PerformSearch),
kSearchDelayMS);
}
bool BookmarkManagerView::HandleKeystroke(
views::Textfield* sender,
const views::Textfield::Keystroke& key) {
if (key.GetKeyboardCode() == base::VKEY_RETURN) {
PerformSearch();
search_tf_->SelectAll();
}
return false;
}
void BookmarkManagerView::ShowContextMenu(views::View* source,
int x,
int y,
bool is_mouse_gesture) {
DCHECK(source == table_view_ || source == tree_view_);
bool is_table = (source == table_view_);
ShowMenu(x, y,
is_table ? BookmarkContextMenuController::BOOKMARK_MANAGER_TABLE :
BookmarkContextMenuController::BOOKMARK_MANAGER_TREE);
}
void BookmarkManagerView::RunMenu(views::View* source, const gfx::Point& pt) {
// TODO(glen): when you change the buttons around and what not, futz with
// this to make it look good. If you end up keeping padding numbers make them
// constants.
if (!GetBookmarkModel()->IsLoaded())
return;
int menu_x = pt.x();
menu_x += UILayoutIsRightToLeft() ? (source->width() - 5) :
(-source->width() + 5);
if (source->GetID() == kOrganizeMenuButtonID) {
ShowMenu(menu_x, pt.y() + 2,
BookmarkContextMenuController::BOOKMARK_MANAGER_ORGANIZE_MENU);
} else if (source->GetID() == kToolsMenuButtonID) {
ShowToolsMenu(menu_x, pt.y() + 2);
} else {
NOTREACHED();
}
}
void BookmarkManagerView::ExecuteCommand(int id) {
switch (id) {
case IDS_BOOKMARK_MANAGER_IMPORT_MENU:
UserMetrics::RecordAction(L"BookmarkManager_Import", profile_);
ShowImportBookmarksFileChooser();
break;
case IDS_BOOKMARK_MANAGER_EXPORT_MENU:
UserMetrics::RecordAction(L"BookmarkManager_Export", profile_);
ShowExportBookmarksFileChooser();
break;
default:
NOTREACHED();
break;
}
}
void BookmarkManagerView::FileSelected(const FilePath& path,
int index,
void* params) {
int id = reinterpret_cast<int>(params);
if (id == IDS_BOOKMARK_MANAGER_IMPORT_MENU) {
// ImporterHost is ref counted and will delete itself when done.
ImporterHost* host = new ImporterHost();
ProfileInfo profile_info;
profile_info.browser_type = BOOKMARKS_HTML;
profile_info.source_path = path.ToWStringHack();
StartImportingWithUI(GetWidget()->GetNativeView(), FAVORITES, host,
profile_info, profile_,
new ImportObserverImpl(profile()), false);
} else if (id == IDS_BOOKMARK_MANAGER_EXPORT_MENU) {
if (g_browser_process->io_thread()) {
bookmark_html_writer::WriteBookmarks(
g_browser_process->io_thread()->message_loop(), GetBookmarkModel(),
path);
}
} else {
NOTREACHED();
}
}
void BookmarkManagerView::FileSelectionCanceled(void* params) {
select_file_dialog_ = NULL;
}
BookmarkTableModel* BookmarkManagerView::CreateSearchTableModel() {
std::wstring search_text = search_tf_->text();
if (search_text.empty())
return NULL;
std::wstring languages =
profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
return BookmarkTableModel::CreateSearchTableModel(
GetBookmarkModel(), search_text, languages);
}
void BookmarkManagerView::SetTableModel(BookmarkTableModel* new_table_model,
const BookmarkNode* parent_node,
bool is_search) {
// Be sure and reset the model on the view before updating table_model_.
// Otherwise the view will attempt to use the deleted model when we set the
// new one.
table_view_->SetModel(NULL);
table_view_->SetShowPathColumn(!parent_node);
table_view_->SetModel(new_table_model);
table_view_->set_parent_node(parent_node);
table_model_.reset(new_table_model);
if (!is_search || (new_table_model && new_table_model->RowCount() > 0)) {
table_view_->SetAltText(std::wstring());
} else if (search_tf_->text().empty()) {
table_view_->SetAltText(
l10n_util::GetString(IDS_BOOKMARK_MANAGER_NO_SEARCH_TEXT));
} else {
table_view_->SetAltText(
l10n_util::GetStringF(IDS_BOOKMARK_MANAGER_NO_RESULTS,
search_tf_->text()));
}
}
void BookmarkManagerView::PerformSearch() {
search_factory_.RevokeAll();
// Reset the controller, otherwise when we change the selection we'll get
// notified and update the model twice.
tree_view_->SetController(NULL);
tree_view_->SetSelectedNode(tree_model_->search_node());
tree_view_->SetController(this);
SetTableModel(CreateSearchTableModel(), NULL, true);
}
void BookmarkManagerView::PrepareForShow() {
// Restore the split location, but don't let it get too small (or big),
// otherwise users might inadvertently not see the divider.
int split_x = g_browser_process->local_state()->GetInteger(
prefs::kBookmarkManagerSplitLocation);
if (split_x == -1) {
// First time running the bookmark manager, give a third of the width to
// the tree.
split_x = split_view_->width() / 3;
}
int min_split_size = split_view_->width() / 8;
// Make sure the user can see both the tree/table.
split_x = std::min(split_view_->width() - min_split_size,
std::max(min_split_size, split_x));
split_view_->set_divider_offset(split_x);
if (!GetBookmarkModel()->IsLoaded()) {
search_tf_->SetReadOnly(true);
return;
}
LoadedImpl();
}
void BookmarkManagerView::LoadedImpl() {
BookmarkModel* bookmark_model = GetBookmarkModel();
const BookmarkNode* bookmark_bar_node = bookmark_model->GetBookmarkBarNode();
table_model_.reset(
BookmarkTableModel::CreateBookmarkTableModelForFolder(bookmark_model,
bookmark_bar_node));
table_view_->SetModel(table_model_.get());
table_view_->set_parent_node(bookmark_bar_node);
tree_model_.reset(new BookmarkFolderTreeModel(bookmark_model));
tree_view_->SetModel(tree_model_.get());
tree_view_->ExpandAll();
tree_view_->SetSelectedNode(
tree_model_->GetFolderNodeForBookmarkNode(bookmark_bar_node));
search_tf_->SetReadOnly(false);
search_tf_->SetController(this);
Layout();
SchedulePaint();
}
BookmarkModel* BookmarkManagerView::GetBookmarkModel() const {
return profile_->GetBookmarkModel();
}
void BookmarkManagerView::ShowMenu(
int x, int y, BookmarkContextMenuController::ConfigurationType config) {
if (!GetBookmarkModel()->IsLoaded())
return;
if (config == BookmarkContextMenuController::BOOKMARK_MANAGER_TABLE ||
(config ==
BookmarkContextMenuController::BOOKMARK_MANAGER_ORGANIZE_MENU &&
table_view_->HasFocus())) {
std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes();
const BookmarkNode* parent = GetSelectedFolder();
if (!parent) {
if (config == BookmarkContextMenuController::BOOKMARK_MANAGER_TABLE) {
config = BookmarkContextMenuController::BOOKMARK_MANAGER_TABLE_OTHER;
} else {
config =
BookmarkContextMenuController::BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER;
}
}
BookmarkContextMenu menu(GetWindow()->GetNativeWindow(), profile_, NULL,
parent, nodes, config);
menu.RunMenuAt(gfx::Point(x, y));
} else {
const BookmarkNode* node = GetSelectedFolder();
std::vector<const BookmarkNode*> nodes;
if (node)
nodes.push_back(node);
BookmarkContextMenu menu(GetWidget()->GetNativeView(), profile_, NULL,
node, nodes, config);
menu.RunMenuAt(gfx::Point(x, y));
}
}
void BookmarkManagerView::OnCutCopyPaste(CutCopyPasteType type,
bool from_table) {
if (type == CUT || type == COPY) {
std::vector<const BookmarkNode*> nodes;
if (from_table) {
nodes = GetSelectedTableNodes();
} else {
const BookmarkNode* node = GetSelectedFolder();
if (!node || node->GetParent() == GetBookmarkModel()->root_node())
return;
nodes.push_back(node);
}
if (nodes.empty())
return;
bookmark_utils::CopyToClipboard(GetBookmarkModel(), nodes, type == CUT);
} else if (type == PASTE) {
int index = from_table ? table_view_->FirstSelectedRow() : -1;
if (index != -1)
index++;
bookmark_utils::PasteFromClipboard(GetBookmarkModel(), GetSelectedFolder(),
index);
}
}
void BookmarkManagerView::ShowToolsMenu(int x, int y) {
views::MenuItemView menu(this);
menu.AppendMenuItemWithLabel(
IDS_BOOKMARK_MANAGER_IMPORT_MENU,
l10n_util::GetString(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
menu.AppendMenuItemWithLabel(
IDS_BOOKMARK_MANAGER_EXPORT_MENU,
l10n_util::GetString(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
views::MenuItemView::AnchorPosition anchor =
UILayoutIsRightToLeft() ? views::MenuItemView::TOPRIGHT :
views::MenuItemView::TOPLEFT;
menu.RunMenuAt(GetWidget()->GetNativeView(), gfx::Rect(x, y, 0, 0), anchor,
true);
}
void BookmarkManagerView::ShowImportBookmarksFileChooser() {
if (select_file_dialog_.get())
select_file_dialog_->ListenerDestroyed();
SelectFileDialog::FileTypeInfo file_type_info;
file_type_info.extensions.resize(1);
file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html"));
file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("htm"));
file_type_info.include_all_files = true;
select_file_dialog_ = SelectFileDialog::Create(this);
select_file_dialog_->SelectFile(
SelectFileDialog::SELECT_OPEN_FILE, std::wstring(),
FilePath(FILE_PATH_LITERAL("bookmarks.html")), &file_type_info, 0,
std::wstring(), GetWidget()->GetNativeView(),
reinterpret_cast<void*>(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
}
void BookmarkManagerView::ShowExportBookmarksFileChooser() {
if (select_file_dialog_.get())
select_file_dialog_->ListenerDestroyed();
SelectFileDialog::FileTypeInfo file_type_info;
file_type_info.extensions.resize(1);
file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html"));
file_type_info.include_all_files = true;
select_file_dialog_ = SelectFileDialog::Create(this);
select_file_dialog_->SelectFile(
SelectFileDialog::SELECT_SAVEAS_FILE, std::wstring(),
FilePath(FILE_PATH_LITERAL("bookmarks.html")), &file_type_info, 0,
L"html", GetWidget()->GetNativeView(),
reinterpret_cast<void*>(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
}
#if defined(CHROME_PERSONALIZATION)
void BookmarkManagerView::UpdateSyncStatus() {
DCHECK(sync_service_);
std::wstring status_label;
std::wstring link_label;
bool synced = SyncStatusUIHelper::GetLabels(sync_service_,
&status_label, &link_label) == SyncStatusUIHelper::SYNCED;
if (sync_service_->HasSyncSetupCompleted()) {
std::wstring username = UTF16ToWide(
sync_service_->GetAuthenticatedUsername());
status_label = l10n_util::GetStringF(IDS_SYNC_NTP_SYNCED_TO, username);
} else if (!sync_service_->SetupInProgress() && !synced) {
status_label = l10n_util::GetString(IDS_SYNC_START_SYNC_BUTTON_LABEL);
}
sync_status_button_->SetText(status_label);
sync_status_button_->GetParent()->Layout();
}
void BookmarkManagerView::OpenSyncMyBookmarksDialog() {
if (!sync_service_)
return;
if (sync_service_->HasSyncSetupCompleted()) {
ShowOptionsWindow(OPTIONS_PAGE_CONTENT, OPTIONS_GROUP_NONE, profile_);
} else {
sync_service_->EnableForUser();
ProfileSyncService::SyncEvent(
ProfileSyncService::START_FROM_BOOKMARK_MANAGER);
}
}
#endif