diff options
author | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-07 04:31:35 +0000 |
---|---|---|
committer | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-07 04:31:35 +0000 |
commit | b504899244b4264994d4daae2bee660706dba652 (patch) | |
tree | eda190cb35dfff7f700a4c636730ff2487cb35d8 /chrome/browser/views | |
parent | e562de106eeab2667eeb6922ddf2d771a0efa55d (diff) | |
download | chromium_src-b504899244b4264994d4daae2bee660706dba652.zip chromium_src-b504899244b4264994d4daae2bee660706dba652.tar.gz chromium_src-b504899244b4264994d4daae2bee660706dba652.tar.bz2 |
Adds import/export of bookmarks to bookmarks.html file.
BUG=1649
TEST=bring up bookmark manager and try out import/export from the
tools menu. Note that import ALWAYS creates a new folder under
the 'Other bookmarks folder' with the name of Imported (x). This
is by design.
Review URL: http://codereview.chromium.org/9471
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4968 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views')
-rw-r--r-- | chrome/browser/views/bookmark_manager_view.cc | 172 | ||||
-rw-r--r-- | chrome/browser/views/bookmark_manager_view.h | 27 | ||||
-rw-r--r-- | chrome/browser/views/importing_progress_view.cc | 35 | ||||
-rw-r--r-- | chrome/browser/views/importing_progress_view.h | 9 | ||||
-rw-r--r-- | chrome/browser/views/shell_dialogs.cc | 37 |
5 files changed, 254 insertions, 26 deletions
diff --git a/chrome/browser/views/bookmark_manager_view.cc b/chrome/browser/views/bookmark_manager_view.cc index 9650e92..76ac3d7 100644 --- a/chrome/browser/views/bookmark_manager_view.cc +++ b/chrome/browser/views/bookmark_manager_view.cc @@ -9,12 +9,15 @@ #include "base/gfx/skia_utils.h" #include "chrome/app/locales/locale_settings.h" #include "chrome/browser/bookmarks/bookmark_folder_tree_model.h" +#include "chrome/browser/bookmarks/bookmark_html_writer.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/profile.h" +#include "chrome/browser/user_metrics.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" @@ -40,6 +43,53 @@ 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; + +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) { + 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); +}; + +} // namespace + BookmarkManagerView::BookmarkManagerView(Profile* profile) : profile_(profile->GetOriginalProfile()), table_view_(NULL), @@ -59,6 +109,12 @@ BookmarkManagerView::BookmarkManagerView(Profile* profile) views::MenuButton* organize_menu_button = new views::MenuButton( l10n_util::GetString(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU), this, true); + organize_menu_button->SetID(kOrganizeMenuButtonID); + + views::MenuButton* tools_menu_button = new views::MenuButton( + l10n_util::GetString(IDS_BOOKMARK_MANAGER_TOOLS_MENU), + this, true); + tools_menu_button->SetID(kToolsMenuButtonID); split_view_ = new views::SingleSplitView(tree_view_, table_view_); @@ -66,10 +122,13 @@ BookmarkManagerView::BookmarkManagerView(Profile* profile) SetLayoutManager(layout); const int top_id = 1; const int split_cs_id = 2; - layout->SetInsets(kPanelVertMargin, 0, 0, 0); + layout->SetInsets(2, 0, 0, 0); views::ColumnSet* column_set = layout->AddColumnSet(top_id); column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, - 1, views::GridLayout::USE_PREF, 0, 0); + 0, views::GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, + 0, views::GridLayout::USE_PREF, 0, 0); column_set->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing); column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 1, views::GridLayout::USE_PREF, 0, 0); @@ -81,6 +140,7 @@ BookmarkManagerView::BookmarkManagerView(Profile* profile) layout->StartRow(0, top_id); layout->AddView(organize_menu_button); + layout->AddView(tools_menu_button); layout->AddView(search_tf_); layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); @@ -94,6 +154,9 @@ BookmarkManagerView::BookmarkManagerView(Profile* profile) } BookmarkManagerView::~BookmarkManagerView() { + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); + if (!GetBookmarkModel()->IsLoaded()) { GetBookmarkModel()->RemoveObserver(this); } else { @@ -164,6 +227,16 @@ void BookmarkManagerView::SelectInTree(BookmarkNode* node) { } } +void BookmarkManagerView::ExpandAll(BookmarkNode* node) { + 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); +} + BookmarkNode* BookmarkManagerView::GetSelectedFolder() { return tree_view_->GetSelectedBookmarkNode(); } @@ -339,8 +412,62 @@ void BookmarkManagerView::RunMenu(views::View* source, // 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. - ShowMenu(hwnd, pt.x - source->width() + 5, pt.y + 2, - BookmarkContextMenu::BOOKMARK_MANAGER_ORGANIZE_MENU); + if (!GetBookmarkModel()->IsLoaded()) + return; + + if (source->GetID() == kOrganizeMenuButtonID) { + ShowMenu(hwnd, pt.x - source->width() + 5, pt.y + 2, + BookmarkContextMenu::BOOKMARK_MANAGER_ORGANIZE_MENU); + } else if (source->GetID() == kToolsMenuButtonID) { + ShowToolsMenu(hwnd, pt.x - source->width() + 5, 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 std::wstring& path, + 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; + StartImportingWithUI(GetContainer()->GetHWND(), 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() { @@ -456,3 +583,40 @@ void BookmarkManagerView::ShowMenu( menu.RunMenuAt(x, y); } } + +void BookmarkManagerView::ShowToolsMenu(HWND host, 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)); + menu.RunMenuAt(GetContainer()->GetHWND(), gfx::Rect(x, y, 0, 0), + views::MenuItemView::TOPLEFT, true); +} + +void BookmarkManagerView::ShowImportBookmarksFileChooser() { + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); + + // TODO(sky): need a textual description here once we can add new + // strings. + std::wstring filter_string(L"*.html\0*.html\0\0"); + select_file_dialog_ = SelectFileDialog::Create(this); + select_file_dialog_->SelectFile( + SelectFileDialog::SELECT_OPEN_FILE, std::wstring(), std::wstring(), + filter_string, GetContainer()->GetHWND(), + reinterpret_cast<void*>(IDS_BOOKMARK_MANAGER_IMPORT_MENU)); +} + +void BookmarkManagerView::ShowExportBookmarksFileChooser() { + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); + + select_file_dialog_ = SelectFileDialog::Create(this); + select_file_dialog_->SelectFile( + SelectFileDialog::SELECT_SAVEAS_FILE, std::wstring(), std::wstring(), + std::wstring(), GetContainer()->GetHWND(), + reinterpret_cast<void*>(IDS_BOOKMARK_MANAGER_EXPORT_MENU)); +} diff --git a/chrome/browser/views/bookmark_manager_view.h b/chrome/browser/views/bookmark_manager_view.h index 8a28eac..0aa83dd 100644 --- a/chrome/browser/views/bookmark_manager_view.h +++ b/chrome/browser/views/bookmark_manager_view.h @@ -5,9 +5,11 @@ #ifndef CHROME_BROWSER_VIEWS_BOOKMARK_MANAGER_VIEW_H_ #define CHROME_BROWSER_VIEWS_BOOKMARK_MANAGER_VIEW_H_ +#include "base/ref_counted.h" #include "base/task.h" #include "chrome/browser/bookmarks/bookmark_context_menu.h" #include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/shell_dialogs.h" #include "chrome/views/table_view.h" #include "chrome/views/text_field.h" #include "chrome/views/tree_view.h" @@ -39,7 +41,9 @@ class BookmarkManagerView : public views::View, public views::TextField::Controller, public BookmarkModelObserver, public views::ContextMenuController, - public views::ViewMenuDelegate { + public views::ViewMenuDelegate, + public views::MenuDelegate, + public SelectFileDialog::Listener { public: explicit BookmarkManagerView(Profile* profile); virtual ~BookmarkManagerView(); @@ -56,6 +60,9 @@ class BookmarkManagerView : public views::View, // selected and node is selected in the table. void SelectInTree(BookmarkNode* node); + // Expands all the children of the selected folder. + void ExpandAll(BookmarkNode* node); + // Returns the selected folder, which may be null. BookmarkNode* GetSelectedFolder(); @@ -137,6 +144,13 @@ class BookmarkManagerView : public views::View, // ViewMenuDelegate. virtual void RunMenu(views::View* source, const CPoint& pt, HWND hwnd); + // MenuDelegate. + virtual void ExecuteCommand(int id); + + // SelectFileDialog::Listener. + virtual void FileSelected(const std::wstring& path, void* params); + virtual void FileSelectionCanceled(void* params); + // Creates the table model to use when searching. This returns NULL if there // is no search text. BookmarkTableModel* CreateSearchTableModel(); @@ -167,6 +181,14 @@ class BookmarkManagerView : public views::View, int y, BookmarkContextMenu::ConfigurationType config); + // Shows the tools menu. + void ShowToolsMenu(HWND host, int x, int y); + + // Shows the import/export file chooser. These invoke + // FileSelected/FileSelectionCanceled when done. + void ShowImportBookmarksFileChooser(); + void ShowExportBookmarksFileChooser(); + Profile* profile_; BookmarkTableView* table_view_; BookmarkFolderTreeView* tree_view_; @@ -175,6 +197,9 @@ class BookmarkManagerView : public views::View, views::TextField* search_tf_; views::SingleSplitView* split_view_; + // Import/export file dialog. + scoped_refptr<SelectFileDialog> select_file_dialog_; + // Factory used for delaying search. ScopedRunnableMethodFactory<BookmarkManagerView> search_factory_; diff --git a/chrome/browser/views/importing_progress_view.cc b/chrome/browser/views/importing_progress_view.cc index 3d759ef..783a83c 100644 --- a/chrome/browser/views/importing_progress_view.cc +++ b/chrome/browser/views/importing_progress_view.cc @@ -22,14 +22,13 @@ ImportingProgressView::ImportingProgressView(const std::wstring& source_name, int16 items, ImporterHost* coordinator, ImportObserver* observer, - HWND parent_window) + HWND parent_window, + bool bookmarks_import) : state_bookmarks_(new views::CheckmarkThrobber), state_searches_(new views::CheckmarkThrobber), state_passwords_(new views::CheckmarkThrobber), state_history_(new views::CheckmarkThrobber), state_cookies_(new views::CheckmarkThrobber), - label_info_(new views::Label(l10n_util::GetStringF( - IDS_IMPORT_PROGRESS_INFO, source_name))), label_bookmarks_(new views::Label( l10n_util::GetString(IDS_IMPORT_PROGRESS_STATUS_BOOKMARKS))), label_searches_(new views::Label( @@ -44,7 +43,12 @@ ImportingProgressView::ImportingProgressView(const std::wstring& source_name, coordinator_(coordinator), import_observer_(observer), items_(items), - importing_(true) { + importing_(true), + bookmarks_import_(bookmarks_import) { + std::wstring info_text = bookmarks_import ? + l10n_util::GetString(IDS_IMPORT_BOOKMARKS) : + l10n_util::GetStringF(IDS_IMPORT_PROGRESS_INFO, source_name); + label_info_ = new views::Label(info_text); coordinator_->SetObserver(this); label_info_->SetMultiLine(true); label_info_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); @@ -78,6 +82,17 @@ ImportingProgressView::~ImportingProgressView() { RemoveChildView(label_passwords_.get()); RemoveChildView(label_history_.get()); RemoveChildView(label_cookies_.get()); + + if (importing_) { + // We're being deleted while importing, clean up state so that the importer + // doesn't have a reference to us and cancel the import. We can get here + // if our parent window is closed, which closes our window and deletes us. + importing_ = false; + coordinator_->SetObserver(NULL); + coordinator_->Cancel(); + if (import_observer_) + import_observer_->ImportComplete(); + } } //////////////////////////////////////////////////////////////////////////////// @@ -217,6 +232,11 @@ void ImportingProgressView::InitControlLayout() { const int single_column_view_set_id = 0; ColumnSet* column_set = layout->AddColumnSet(single_column_view_set_id); + if (bookmarks_import_) { + column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, + GridLayout::FIXED, ps.width(), 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + } column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); const int double_column_view_set_id = 1; @@ -230,10 +250,12 @@ void ImportingProgressView::InitControlLayout() { column_set->AddPaddingColumn(0, kUnrelatedControlLargeHorizontalSpacing); layout->StartRow(0, single_column_view_set_id); + if (bookmarks_import_) + layout->AddView(state_bookmarks_.get()); layout->AddView(label_info_); layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); - if (items_ & FAVORITES) { + if (items_ & FAVORITES && !bookmarks_import_) { layout->StartRow(0, double_column_view_set_id); layout->AddView(state_bookmarks_.get()); layout->AddView(label_bookmarks_.get()); @@ -277,7 +299,8 @@ void StartImportingWithUI(HWND parent_window, bool first_run) { DCHECK(items != 0); ImportingProgressView* v = new ImportingProgressView( - source_profile.description, items, coordinator, observer, parent_window); + source_profile.description, items, coordinator, observer, parent_window, + source_profile.browser_type == BOOKMARKS_HTML); views::Window* window = views::Window::CreateChromeWindow(parent_window, gfx::Rect(), v); diff --git a/chrome/browser/views/importing_progress_view.h b/chrome/browser/views/importing_progress_view.h index c7f97c0..61ec12f 100644 --- a/chrome/browser/views/importing_progress_view.h +++ b/chrome/browser/views/importing_progress_view.h @@ -19,11 +19,15 @@ class ImportingProgressView : public views::View, public views::DialogDelegate, public ImporterHost::Observer { public: + // |items| is a bitmask of ImportItems being imported. + // |bookmark_import| is true if we're importing bookmarks from a + // bookmarks.html file. ImportingProgressView(const std::wstring& source_name, int16 items, ImporterHost* coordinator, ImportObserver* observer, - HWND parent_window); + HWND parent_window, + bool bookmarks_import); virtual ~ImportingProgressView(); protected: @@ -79,6 +83,9 @@ class ImportingProgressView : public views::View, // True if the import operation is in progress. bool importing_; + // Are we importing a bookmarks.html file? + bool bookmarks_import_; + DISALLOW_EVIL_CONSTRUCTORS(ImportingProgressView); }; diff --git a/chrome/browser/views/shell_dialogs.cc b/chrome/browser/views/shell_dialogs.cc index b2dbf1c..feadbed 100644 --- a/chrome/browser/views/shell_dialogs.cc +++ b/chrome/browser/views/shell_dialogs.cc @@ -192,7 +192,9 @@ class SelectFileDialogImpl : public SelectFileDialog, // SelectFileDialog implementation: virtual void SelectFile(Type type, const std::wstring& title, - const std::wstring& default_path, HWND owning_hwnd, + const std::wstring& default_path, + const std::wstring& filter, + HWND owning_hwnd, void* params); virtual bool IsRunning(HWND owning_hwnd) const; virtual void ListenerDestroyed(); @@ -203,6 +205,7 @@ class SelectFileDialogImpl : public SelectFileDialog, void ExecuteSelectFile(Type type, const std::wstring& title, const std::wstring& default_path, + const std::wstring& filter, RunState run_state, void* params); @@ -225,6 +228,7 @@ class SelectFileDialogImpl : public SelectFileDialog, // Runs an Open file dialog box, with similar semantics for input paramaters // as RunSelectFolderDialog. bool RunOpenFileDialog(const std::wstring& title, + const std::wstring& filters, HWND owner, std::wstring* path); @@ -245,12 +249,13 @@ SelectFileDialogImpl::~SelectFileDialogImpl() { void SelectFileDialogImpl::SelectFile(Type type, const std::wstring& title, const std::wstring& default_path, + const std::wstring& filter, HWND owner, void* params) { RunState run_state = BeginRun(owner); run_state.dialog_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &SelectFileDialogImpl::ExecuteSelectFile, type, - title, default_path, run_state, params)); + title, default_path, filter, run_state, params)); } bool SelectFileDialogImpl::IsRunning(HWND owning_hwnd) const { @@ -263,11 +268,13 @@ void SelectFileDialogImpl::ListenerDestroyed() { listener_ = NULL; } -void SelectFileDialogImpl::ExecuteSelectFile(Type type, - const std::wstring& title, - const std::wstring& default_path, - RunState run_state, - void* params) { +void SelectFileDialogImpl::ExecuteSelectFile( + Type type, + const std::wstring& title, + const std::wstring& default_path, + const std::wstring& filter, + RunState run_state, + void* params) { std::wstring path = default_path; bool success = false; if (type == SELECT_FOLDER) { @@ -276,7 +283,7 @@ void SelectFileDialogImpl::ExecuteSelectFile(Type type, success = win_util::SaveFileAs(run_state.owner, default_path, &path); DisableOwner(run_state.owner); } else if (type == SELECT_OPEN_FILE) { - success = RunOpenFileDialog(title, run_state.owner, &path); + success = RunOpenFileDialog(title, filter, run_state.owner, &path); } if (success) { @@ -331,9 +338,11 @@ bool SelectFileDialogImpl::RunSelectFolderDialog(const std::wstring& title, return false; } -bool SelectFileDialogImpl::RunOpenFileDialog(const std::wstring& title, - HWND owner, - std::wstring* path) { +bool SelectFileDialogImpl::RunOpenFileDialog( + const std::wstring& title, + const std::wstring& filter, + HWND owner, + std::wstring* path) { OPENFILENAME ofn; // We must do this otherwise the ofn's FlagsEx may be initialized to random // junk in release builds which can cause the Places Bar not to show up! @@ -350,8 +359,9 @@ bool SelectFileDialogImpl::RunOpenFileDialog(const std::wstring& title, // without having to close Chrome first. ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - // TODO(beng): (http://b/issue?id=1126563) edit the filter options in the - // dropdown list. + if (!filter.empty()) { + ofn.lpstrFilter = filter.c_str(); + } bool success = !!GetOpenFileName(&ofn); DisableOwner(owner); if (success) @@ -527,4 +537,3 @@ void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) { SelectFontDialog* SelectFontDialog::Create(Listener* listener) { return new SelectFontDialogImpl(listener); } - |