| // 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 |