diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-15 20:43:44 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-15 20:43:44 +0000 |
commit | 3ee88ee11b8fd2092ca1287e7c48f9f6c4ed886e (patch) | |
tree | 951a04950724ccc925f45e5a9d264b7ee49d09b3 /chrome/browser/views/options | |
parent | 7f858d1032720f471991db19c383e1af19c24088 (diff) | |
download | chromium_src-3ee88ee11b8fd2092ca1287e7c48f9f6c4ed886e.zip chromium_src-3ee88ee11b8fd2092ca1287e7c48f9f6c4ed886e.tar.gz chromium_src-3ee88ee11b8fd2092ca1287e7c48f9f6c4ed886e.tar.bz2 |
Use tab to group "Show saved passwords" and "Exceptions"
BUG=9026
"Show saved passwords" and "Exceptions" were splited into
2 dialogs, group together in one single dialog with
different pages by tabbing.
Review URL: http://codereview.chromium.org/67055
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13786 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views/options')
10 files changed, 924 insertions, 16 deletions
diff --git a/chrome/browser/views/options/content_page_view.cc b/chrome/browser/views/options/content_page_view.cc index 10feabc9..7263505 100644 --- a/chrome/browser/views/options/content_page_view.cc +++ b/chrome/browser/views/options/content_page_view.cc @@ -15,8 +15,7 @@ #include "chrome/browser/shell_dialogs.h" #include "chrome/browser/views/options/fonts_languages_window_view.h" #include "chrome/browser/views/options/options_group_view.h" -#include "chrome/browser/views/password_manager_view.h" -#include "chrome/browser/views/password_manager_exceptions_view.h" +#include "chrome/browser/views/options/passwords_exceptions_window_view.h" #include "chrome/browser/views/standard_layout.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/l10n_util.h" @@ -180,7 +179,6 @@ ContentPageView::ContentPageView(Profile* profile) passwords_group_(NULL), passwords_asktosave_radio_(NULL), passwords_neversave_radio_(NULL), - passwords_show_passwords_button_(NULL), fonts_lang_group_(NULL), fonts_and_languages_label_(NULL), change_content_fonts_button_(NULL), @@ -242,11 +240,8 @@ void ContentPageView::ButtonPressed(views::Button* sender) { } ask_to_save_passwords_.SetValue(enabled); } else if (sender == passwords_exceptions_button_) { - UserMetricsRecordAction(L"Options_ShowPasswordManagerExceptions", NULL); - PasswordManagerExceptionsView::Show(profile()); - }else if (sender == passwords_show_passwords_button_) { - UserMetricsRecordAction(L"Options_ShowPasswordManager", NULL); - PasswordManagerView::Show(profile()); + UserMetricsRecordAction(L"Options_ShowPasswordsExceptions", NULL); + PasswordsExceptionsWindowView::Show(profile()); } else if (sender == form_autofill_checkbox_) { bool enabled = form_autofill_checkbox_->checked(); if (enabled) { @@ -413,8 +408,6 @@ void ContentPageView::InitPasswordSavingGroup() { kPasswordSavingRadioGroup); passwords_neversave_radio_->set_listener(this); passwords_neversave_radio_->SetMultiLine(true); - passwords_show_passwords_button_ = new views::NativeButton( - this, l10n_util::GetString(IDS_OPTIONS_PASSWORDS_SHOWPASSWORDS)); passwords_exceptions_button_ = new views::NativeButton( this, l10n_util::GetString(IDS_OPTIONS_PASSWORDS_EXCEPTIONS)); @@ -444,8 +437,7 @@ void ContentPageView::InitPasswordSavingGroup() { layout->StartRow(0, single_column_view_set_id); layout->AddView(passwords_neversave_radio_); layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); - layout->StartRow(0, double_column_view_set_id); - layout->AddView(passwords_show_passwords_button_); + layout->StartRow(0, single_column_view_set_id); layout->AddView(passwords_exceptions_button_); passwords_group_ = new OptionsGroupView( diff --git a/chrome/browser/views/options/content_page_view.h b/chrome/browser/views/options/content_page_view.h index 98d2030..7102f63 100644 --- a/chrome/browser/views/options/content_page_view.h +++ b/chrome/browser/views/options/content_page_view.h @@ -70,7 +70,6 @@ class ContentPageView : public OptionsPageView, OptionsGroupView* passwords_group_; views::RadioButton* passwords_asktosave_radio_; views::RadioButton* passwords_neversave_radio_; - views::NativeButton* passwords_show_passwords_button_; // Controls for the Form Autofill group OptionsGroupView* form_autofill_group_; diff --git a/chrome/browser/views/options/exceptions_page_view.cc b/chrome/browser/views/options/exceptions_page_view.cc new file mode 100644 index 0000000..b4c580c --- /dev/null +++ b/chrome/browser/views/options/exceptions_page_view.cc @@ -0,0 +1,179 @@ +// 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/options/exceptions_page_view.h" + +#include "base/string_util.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/views/standard_layout.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/views/background.h" +#include "chrome/views/controls/button/native_button.h" +#include "chrome/views/grid_layout.h" +#include "grit/generated_resources.h" + +using views::ColumnSet; +using views::GridLayout; + +/////////////////////////////////////////////////////////////////////////////// +// ExceptionsTableModel +ExceptionsTableModel::ExceptionsTableModel(Profile* profile) + : PasswordsTableModel(profile) { +} + +ExceptionsTableModel::~ExceptionsTableModel() { +} + +std::wstring ExceptionsTableModel::GetText(int row, int col_id) { + DCHECK_EQ(col_id, IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN); + return PasswordsTableModel::GetText(row, col_id); +} + +int ExceptionsTableModel::CompareValues(int row1, int row2, + int col_id) { + DCHECK_EQ(col_id, IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN); + return PasswordsTableModel::CompareValues(row1, row2, col_id); +} + +void ExceptionsTableModel::GetAllExceptionsForProfile() { + DCHECK(!pending_login_query_); + pending_login_query_ = web_data_service()->GetAllLogins(this); +} + +void ExceptionsTableModel::OnWebDataServiceRequestDone( + WebDataService::Handle h, + const WDTypedResult* result) { + DCHECK_EQ(pending_login_query_, h); + pending_login_query_ = NULL; + + if (!result) + return; + + DCHECK(result->GetType() == PASSWORD_RESULT); + + // Get the result from the database into a useable form. + const WDResult<std::vector<PasswordForm*> >* r = + static_cast<const WDResult<std::vector<PasswordForm*> >*>(result); + std::vector<PasswordForm*> rows = r->GetValue(); + STLDeleteElements<PasswordRows>(&saved_signons_); + std::wstring languages = + profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); + for (size_t i = 0; i < rows.size(); ++i) { + if (rows[i]->blacklisted_by_user) { + saved_signons_.push_back(new PasswordRow( + gfx::SortedDisplayURL(rows[i]->origin, languages), rows[i])); + } + } + if (observer_) + observer_->OnModelChanged(); + if (row_count_observer_) + row_count_observer_->OnRowCountChanged(RowCount()); +} + +/////////////////////////////////////////////////////////////////////////////// +// ExceptionsPageView, public +ExceptionsPageView::ExceptionsPageView(Profile* profile) + : OptionsPageView(profile), + remove_button_(this, l10n_util::GetString( + IDS_EXCEPTIONS_PAGE_VIEW_REMOVE_BUTTON)), + remove_all_button_(this, l10n_util::GetString( + IDS_EXCEPTIONS_PAGE_VIEW_REMOVE_ALL_BUTTON)), + table_model_(profile), + table_view_(NULL) { +} + +void ExceptionsPageView::OnSelectionChanged() { + bool has_selection = table_view_->SelectedRowCount() > 0; + remove_button_.SetEnabled(has_selection); +} + +void ExceptionsPageView::ButtonPressed(views::Button* sender) { + // Close will result in our destruction. + if (sender == &remove_all_button_) { + table_model_.ForgetAndRemoveAllSignons(); + return; + } + + // The following require a selection (and only one, since table is single- + // select only). + views::TableSelectionIterator iter = table_view_->SelectionBegin(); + int row = *iter; + PasswordForm* selected = table_model_.GetPasswordFormAt(row); + DCHECK(++iter == table_view_->SelectionEnd()); + + if (sender == &remove_button_) { + table_model_.ForgetAndRemoveSignon(row); + } else { + NOTREACHED() << "Invalid button."; + } +} + +void ExceptionsPageView::OnRowCountChanged(size_t rows) { + remove_all_button_.SetEnabled(rows > 0); +} + +/////////////////////////////////////////////////////////////////////////////// +// ExceptionsPageView, protected +void ExceptionsPageView::InitControlLayout() { + SetupButtons(); + SetupTable(); + + // Do the layout thing. + const int column_set_id = 0; + GridLayout* layout = CreatePanelGridLayout(this); + SetLayoutManager(layout); + + // Design the grid. + ColumnSet* column_set = layout->AddColumnSet(column_set_id); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::FIXED, 300, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); + + // Fill the grid. + layout->StartRow(0.05f, column_set_id); + layout->AddView(table_view_, 1, 2); + layout->AddView(&remove_button_); + layout->StartRow(0.80f, column_set_id); + layout->SkipColumns(1); + layout->AddView(&remove_all_button_); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + + // Ask the database for exception data. + table_model_.GetAllExceptionsForProfile(); +} + +/////////////////////////////////////////////////////////////////////////////// +// ExceptionsPageView, private +void ExceptionsPageView::SetupButtons() { + remove_button_.SetParentOwned(false); + remove_button_.SetEnabled(false); + + remove_all_button_.SetParentOwned(false); + remove_all_button_.SetEnabled(false); +} + +void ExceptionsPageView::SetupTable() { + // Tell the table model we are concerned about how many rows it has. + table_model_.set_row_count_observer(this); + + // Creates the different columns for the table. + // The float resize values are the result of much tinkering. + std::vector<views::TableColumn> columns; + columns.push_back(views::TableColumn( + IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN, + views::TableColumn::LEFT, -1, 0.55f)); + columns.back().sortable = true; + table_view_ = new views::TableView(&table_model_, columns, views::TEXT_ONLY, + true, true, true); + // Make the table initially sorted by host. + views::TableView::SortDescriptors sort; + sort.push_back(views::TableView::SortDescriptor( + IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN, true)); + table_view_->SetSortDescriptors(sort); + table_view_->SetObserver(this); +} diff --git a/chrome/browser/views/options/exceptions_page_view.h b/chrome/browser/views/options/exceptions_page_view.h new file mode 100644 index 0000000..e0abe67 --- /dev/null +++ b/chrome/browser/views/options/exceptions_page_view.h @@ -0,0 +1,69 @@ +// 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. + +#ifndef CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_PAGE_VIEW_H_ +#define CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_PAGE_VIEW_H_ + +#include "chrome/browser/views/options/options_page_view.h" +#include "chrome/browser/views/options/passwords_page_view.h" + +class Profile; + +/////////////////////////////////////////////////////////////////////////////// +// ExceptionsTableModel +class ExceptionsTableModel : public PasswordsTableModel { + public: + explicit ExceptionsTableModel(Profile* profile); + virtual ~ExceptionsTableModel(); + + // TableModel methods. + virtual std::wstring GetText(int row, int column); + virtual int CompareValues(int row1, int row2, int col_id); + + // WebDataServiceConsumer implementation. + virtual void OnWebDataServiceRequestDone(WebDataService::Handle h, + const WDTypedResult* result); + // Request all logins data. + void GetAllExceptionsForProfile(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// ExceptionsPageView +class ExceptionsPageView : public OptionsPageView, + public views::TableViewObserver, + public views::ButtonListener, + public PasswordsTableModelObserver { + public: + explicit ExceptionsPageView(Profile* profile); + + // views::TableViewObserverImplementation. + virtual void OnSelectionChanged(); + + // views::ButtonListener implementation. + virtual void ButtonPressed(views::Button* sender); + + // PasswordsTableModelObserver implementation. + virtual void OnRowCountChanged(size_t rows); + + protected: + virtual void InitControlLayout(); + + private: + // Helper to configure our buttons and labels. + void SetupButtons(); + + // Helper to configure our table view. + void SetupTable(); + + ExceptionsTableModel table_model_; + views::TableView* table_view_; + + // The buttons and labels. + views::NativeButton remove_button_; + views::NativeButton remove_all_button_; + + DISALLOW_COPY_AND_ASSIGN(ExceptionsPageView); +}; + +#endif // CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_PAGE_VIEW_H_ diff --git a/chrome/browser/views/options/fonts_page_view.cc b/chrome/browser/views/options/fonts_page_view.cc index 7433a65..b05941f 100644 --- a/chrome/browser/views/options/fonts_page_view.cc +++ b/chrome/browser/views/options/fonts_page_view.cc @@ -16,7 +16,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/character_encoding.h" #include "chrome/browser/shell_dialogs.h" -#include "chrome/browser/views/password_manager_view.h" #include "chrome/browser/views/standard_layout.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/gfx/chrome_font.h" @@ -402,7 +401,7 @@ void FontsPageView::InitFontLayout() { this, l10n_util::GetString( IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_BUTTON_LABEL)); - + sans_serif_font_label_ = new views::Label( l10n_util::GetString( IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SANS_SERIF_LABEL)); diff --git a/chrome/browser/views/options/languages_page_view.cc b/chrome/browser/views/options/languages_page_view.cc index 2634639..40a427f 100644 --- a/chrome/browser/views/options/languages_page_view.cc +++ b/chrome/browser/views/options/languages_page_view.cc @@ -16,7 +16,6 @@ #include "chrome/browser/shell_dialogs.h" #include "chrome/browser/spellchecker.h" #include "chrome/browser/views/options/language_combobox_model.h" -#include "chrome/browser/views/password_manager_view.h" #include "chrome/browser/views/restart_message_box.h" #include "chrome/browser/views/standard_layout.h" #include "chrome/common/gfx/chrome_canvas.h" @@ -31,6 +30,7 @@ #include "chrome/views/controls/text_field.h" #include "chrome/views/grid_layout.h" #include "chrome/views/widget/widget.h" +#include "chrome/views/window/window.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" diff --git a/chrome/browser/views/options/passwords_exceptions_window_view.cc b/chrome/browser/views/options/passwords_exceptions_window_view.cc new file mode 100644 index 0000000..9bf44b4 --- /dev/null +++ b/chrome/browser/views/options/passwords_exceptions_window_view.cc @@ -0,0 +1,99 @@ +// 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/options/passwords_exceptions_window_view.h" + +#include "chrome/browser/views/options/passwords_page_view.h" +#include "chrome/browser/views/options/exceptions_page_view.h" +#include "chrome/common/l10n_util.h" +#include "grit/generated_resources.h" + +// static +PasswordsExceptionsWindowView* PasswordsExceptionsWindowView::instance_ = NULL; + +static const int kDefaultWindowWidth = 530; +static const int kDefaultWindowHeight = 240; +static const int kDialogPadding = 7; + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsExceptionsWindowView, public + +PasswordsExceptionsWindowView::PasswordsExceptionsWindowView(Profile* profile) + : tabs_(NULL), + passwords_page_view_(NULL), + exceptions_page_view_(NULL), + profile_(profile) { +} + +// static +void PasswordsExceptionsWindowView::Show(Profile* profile) { + DCHECK(profile); + if (!instance_) { + instance_ = new PasswordsExceptionsWindowView(profile); + + // instances_ will get deleted once Close() is called. + views::Window::CreateChromeWindow(NULL, gfx::Rect(), instance_); + } + if (!instance_->window()->IsVisible()) { + instance_->window()->Show(); + } else { + instance_->window()->Activate(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// PasswordsExceptionsWindowView, views::View implementations + +void PasswordsExceptionsWindowView::Layout() { + tabs_->SetBounds(kDialogPadding, kDialogPadding, + width() - (2 * kDialogPadding), + height() - (2 * kDialogPadding)); +} + +gfx::Size PasswordsExceptionsWindowView::GetPreferredSize() { + return gfx::Size(kDefaultWindowWidth, kDefaultWindowHeight); +} + +void PasswordsExceptionsWindowView::ViewHierarchyChanged( + bool is_add, views::View* parent, views::View* child) { + if (is_add && child == this) + Init(); +} + +///////////////////////////////////////////////////////////////////////////// +// PasswordsExceptionsWindowView, views::DisloagDelegate implementations + +int PasswordsExceptionsWindowView::GetDialogButtons() const { + return DIALOGBUTTON_CANCEL; +} + +std::wstring PasswordsExceptionsWindowView::GetWindowTitle() const { + return l10n_util::GetString(IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE); +} + +void PasswordsExceptionsWindowView::WindowClosing() { + // |instnace_| is deleted once the window is closed, so we just have to set + // it to NULL. + instance_ = NULL; +} + +views::View* PasswordsExceptionsWindowView::GetContentsView() { + return this; +} + +///////////////////////////////////////////////////////////////////////////// +// PasswordsExceptionsWindowView, private + +void PasswordsExceptionsWindowView::Init() { + tabs_ = new views::TabbedPane(); + AddChildView(tabs_); + + passwords_page_view_ = new PasswordsPageView(profile_); + tabs_->AddTab(l10n_util::GetString( + IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE), passwords_page_view_); + + exceptions_page_view_ = new ExceptionsPageView(profile_); + tabs_->AddTab(l10n_util::GetString( + IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE), exceptions_page_view_); +} diff --git a/chrome/browser/views/options/passwords_exceptions_window_view.h b/chrome/browser/views/options/passwords_exceptions_window_view.h new file mode 100644 index 0000000..e3e8705 --- /dev/null +++ b/chrome/browser/views/options/passwords_exceptions_window_view.h @@ -0,0 +1,64 @@ +// 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. + +#ifndef CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_VIEW_H_ +#define CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_VIEW_H_ + +#include "chrome/views/controls/tabbed_pane.h" +#include "chrome/views/view.h" +#include "chrome/views/window/dialog_delegate.h" +#include "chrome/views/window/window.h" + +class Profile; +class PasswordsPageView; +class ExceptionsPageView; + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsExceptionsWindowView +// +// The contents of the "Save passwords and exceptions" dialog window. +// +class PasswordsExceptionsWindowView : public views::View, + public views::DialogDelegate { + public: + explicit PasswordsExceptionsWindowView(Profile* profile); + virtual ~PasswordsExceptionsWindowView() {} + + // Show the PasswordManagerExceptionsView for the given profile. + static void Show(Profile* profile); + + // views::View methods. + virtual void Layout(); + virtual gfx::Size GetPreferredSize(); + virtual void ViewHierarchyChanged(bool is_add, views::View* parent, + views::View* child); + + // views::DialogDelegate methods: + virtual int GetDialogButtons() const; + virtual bool CanResize() const { return true; } + virtual bool CanMaximize() const { return false; } + virtual bool IsAlwaysOnTop() const { return false; } + virtual bool HasAlwaysOnTopMenu() const { return false; } + virtual std::wstring GetWindowTitle() const; + virtual void WindowClosing(); + virtual views::View* GetContentsView(); + + private: + void Init(); + + // The Tab view that contains all of the options pages. + views::TabbedPane* tabs_; + + PasswordsPageView* passwords_page_view_; + + ExceptionsPageView* exceptions_page_view_; + + Profile* profile_; + + static PasswordsExceptionsWindowView* instance_; + + DISALLOW_COPY_AND_ASSIGN(PasswordsExceptionsWindowView); +}; + +#endif // CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_VIEW_H_ diff --git a/chrome/browser/views/options/passwords_page_view.cc b/chrome/browser/views/options/passwords_page_view.cc new file mode 100644 index 0000000..7325dd4 --- /dev/null +++ b/chrome/browser/views/options/passwords_page_view.cc @@ -0,0 +1,328 @@ +// 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/options/passwords_page_view.h" + +#include "base/string_util.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/views/standard_layout.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/views/background.h" +#include "chrome/views/controls/button/native_button.h" +#include "chrome/views/grid_layout.h" +#include "grit/generated_resources.h" + +using views::ColumnSet; +using views::GridLayout; + +/////////////////////////////////////////////////////////////////////////////// +// MultiLabelButtons +MultiLabelButtons::MultiLabelButtons(views::ButtonListener* listener, + const std::wstring& label, + const std::wstring& alt_label) + : NativeButton(listener, label), + label_(label), + alt_label_(alt_label), + pref_size_(-1, -1) { +} + +gfx::Size MultiLabelButtons::GetPreferredSize() { + if (pref_size_.width() == -1 && pref_size_.height() == -1) { + // Let's compute our preferred size. + std::wstring current_label = label(); + SetLabel(label_); + pref_size_ = NativeButton::GetPreferredSize(); + SetLabel(alt_label_); + gfx::Size alt_pref_size = NativeButton::GetPreferredSize(); + // Revert to the original label. + SetLabel(current_label); + pref_size_.SetSize(std::max(pref_size_.width(), alt_pref_size.width()), + std::max(pref_size_.height(), alt_pref_size.height())); + } + return gfx::Size(pref_size_.width(), pref_size_.height()); +} + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsTableModel, public +PasswordsTableModel::PasswordsTableModel(Profile* profile) + : observer_(NULL), + row_count_observer_(NULL), + pending_login_query_(NULL), + saved_signons_cleanup_(&saved_signons_), + profile_(profile) { + DCHECK(profile && profile->GetWebDataService(Profile::EXPLICIT_ACCESS)); +} + +PasswordsTableModel::~PasswordsTableModel() { + CancelLoginsQuery(); +} + +int PasswordsTableModel::RowCount() { + return static_cast<int>(saved_signons_.size()); +} + +std::wstring PasswordsTableModel::GetText(int row, + int col_id) { + switch (col_id) { + case IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN: { // Site. + const std::wstring& url = saved_signons_[row]->display_url.display_url(); + // Force URL to have LTR directionality. + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { + std::wstring localized_url = url; + l10n_util::WrapStringWithLTRFormatting(&localized_url); + return localized_url; + } + return url; + } + case IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN: { // Username. + std::wstring username = GetPasswordFormAt(row)->username_value; + l10n_util::AdjustStringForLocaleDirection(username, &username); + return username; + } + default: + NOTREACHED() << "Invalid column."; + return std::wstring(); + } +} + +int PasswordsTableModel::CompareValues(int row1, int row2, + int column_id) { + if (column_id == IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN) { + return saved_signons_[row1]->display_url.Compare( + saved_signons_[row2]->display_url, GetCollator()); + } + return TableModel::CompareValues(row1, row2, column_id); +} + +void PasswordsTableModel::SetObserver( + views::TableModelObserver* observer) { + observer_ = observer; +} + +void PasswordsTableModel::GetAllSavedLoginsForProfile() { + DCHECK(!pending_login_query_); + pending_login_query_ = web_data_service()->GetAllAutofillableLogins(this); +} + +void PasswordsTableModel::OnWebDataServiceRequestDone( + WebDataService::Handle h, + const WDTypedResult* result) { + DCHECK_EQ(pending_login_query_, h); + pending_login_query_ = NULL; + + if (!result) + return; + + DCHECK(result->GetType() == PASSWORD_RESULT); + + // Get the result from the database into a useable form. + const WDResult<std::vector<PasswordForm*> >* r = + static_cast<const WDResult<std::vector<PasswordForm*> >*>(result); + std::vector<PasswordForm*> rows = r->GetValue(); + STLDeleteElements<PasswordRows>(&saved_signons_); + saved_signons_.resize(rows.size(), NULL); + std::wstring languages = + profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); + for (size_t i = 0; i < rows.size(); ++i) { + saved_signons_[i] = new PasswordRow( + gfx::SortedDisplayURL(rows[i]->origin, languages), rows[i]); + } + if (observer_) + observer_->OnModelChanged(); + if (row_count_observer_) + row_count_observer_->OnRowCountChanged(RowCount()); +} + +PasswordForm* PasswordsTableModel::GetPasswordFormAt(int row) { + DCHECK(row >= 0 && row < RowCount()); + return saved_signons_[row]->form.get(); +} + +void PasswordsTableModel::ForgetAndRemoveSignon(int row) { + DCHECK(row >= 0 && row < RowCount()); + PasswordRows::iterator target_iter = saved_signons_.begin() + row; + // Remove from DB, memory, and vector. + PasswordRow* password_row = *target_iter; + web_data_service()->RemoveLogin(*(password_row->form.get())); + delete password_row; + saved_signons_.erase(target_iter); + if (observer_) + observer_->OnItemsRemoved(row, 1); + if (row_count_observer_) + row_count_observer_->OnRowCountChanged(RowCount()); +} + +void PasswordsTableModel::ForgetAndRemoveAllSignons() { + PasswordRows::iterator iter = saved_signons_.begin(); + while (iter != saved_signons_.end()) { + // Remove from DB, memory, and vector. + PasswordRow* row = *iter; + web_data_service()->RemoveLogin(*(row->form.get())); + delete row; + iter = saved_signons_.erase(iter); + } + if (observer_) + observer_->OnModelChanged(); + if (row_count_observer_) + row_count_observer_->OnRowCountChanged(RowCount()); +} + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsTableModel, private +void PasswordsTableModel::CancelLoginsQuery() { + if (pending_login_query_) { + web_data_service()->CancelRequest(pending_login_query_); + pending_login_query_ = NULL; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsPageView, public +PasswordsPageView::PasswordsPageView(Profile* profile) + : OptionsPageView(profile), + show_button_( + this, + l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON), + l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON)), + remove_button_(this, l10n_util::GetString( + IDS_PASSWORDS_PAGE_VIEW_REMOVE_BUTTON)), + remove_all_button_(this, l10n_util::GetString( + IDS_PASSWORDS_PAGE_VIEW_REMOVE_ALL_BUTTON)), + table_model_(profile), + table_view_(NULL) { +} + +void PasswordsPageView::OnSelectionChanged() { + bool has_selection = table_view_->SelectedRowCount() > 0; + remove_button_.SetEnabled(has_selection); + // Reset the password related views. + show_button_.SetLabel( + l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON)); + show_button_.SetEnabled(has_selection); + password_label_.SetText(std::wstring()); +} + +void PasswordsPageView::ButtonPressed(views::Button* sender) { + // Close will result in our destruction. + if (sender == &remove_all_button_) { + table_model_.ForgetAndRemoveAllSignons(); + return; + } + + // The following require a selection (and only one, since table is single- + // select only). + views::TableSelectionIterator iter = table_view_->SelectionBegin(); + int row = *iter; + PasswordForm* selected = table_model_.GetPasswordFormAt(row); + DCHECK(++iter == table_view_->SelectionEnd()); + + if (sender == &remove_button_) { + table_model_.ForgetAndRemoveSignon(row); + } else if (sender == &show_button_) { + if (password_label_.GetText().length() == 0) { + password_label_.SetText(selected->password_value); + show_button_.SetLabel( + l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON)); + } else { + password_label_.SetText(L""); + show_button_.SetLabel( + l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON)); + } + } else { + NOTREACHED() << "Invalid button."; + } +} + +void PasswordsPageView::OnRowCountChanged(size_t rows) { + remove_all_button_.SetEnabled(rows > 0); +} + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsPageView, protected +void PasswordsPageView::InitControlLayout() { + SetupButtonsAndLabels(); + SetupTable(); + + // Do the layout thing. + const int top_column_set_id = 0; + const int lower_column_set_id = 1; + GridLayout* layout = CreatePanelGridLayout(this); + SetLayoutManager(layout); + + // Design the grid. + ColumnSet* column_set = layout->AddColumnSet(top_column_set_id); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::FIXED, 300, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); + + column_set = layout->AddColumnSet(lower_column_set_id); + column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(1, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); + column_set->LinkColumnSizes(0, 2, -1); + + // Fill the grid. + layout->StartRow(0.05f, top_column_set_id); + layout->AddView(table_view_, 1, 4); + layout->AddView(&remove_button_); + layout->StartRow(0.05f, top_column_set_id); + layout->SkipColumns(1); + layout->AddView(&remove_all_button_); + layout->StartRow(0.05f, top_column_set_id); + layout->SkipColumns(1); + layout->AddView(&show_button_); + layout->StartRow(0.80f, top_column_set_id); + layout->SkipColumns(1); + layout->AddView(&password_label_); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + + // Ask the database for saved password data. + table_model_.GetAllSavedLoginsForProfile(); +} + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsPageView, private +void PasswordsPageView::SetupButtonsAndLabels() { + // Disable all buttons in the first place. + show_button_.SetParentOwned(false); + show_button_.SetEnabled(false); + + remove_button_.SetParentOwned(false); + remove_button_.SetEnabled(false); + + remove_all_button_.SetParentOwned(false); + remove_all_button_.SetEnabled(false); + + password_label_.SetParentOwned(false); +} + +void PasswordsPageView::SetupTable() { + // Tell the table model we are concern about how many rows it has. + table_model_.set_row_count_observer(this); + + // Creates the different columns for the table. + // The float resize values are the result of much tinkering. + std::vector<views::TableColumn> columns; + columns.push_back(views::TableColumn(IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN, + views::TableColumn::LEFT, -1, 0.55f)); + columns.back().sortable = true; + columns.push_back(views::TableColumn( + IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN, views::TableColumn::RIGHT, + -1, 0.37f)); + columns.back().sortable = true; + table_view_ = new views::TableView(&table_model_, columns, views::TEXT_ONLY, + true, true, true); + // Make the table initially sorted by host. + views::TableView::SortDescriptors sort; + sort.push_back(views::TableView::SortDescriptor( + IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN, true)); + table_view_->SetSortDescriptors(sort); + table_view_->SetObserver(this); +} diff --git a/chrome/browser/views/options/passwords_page_view.h b/chrome/browser/views/options/passwords_page_view.h new file mode 100644 index 0000000..dca2b1e --- /dev/null +++ b/chrome/browser/views/options/passwords_page_view.h @@ -0,0 +1,179 @@ +// 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. + +#ifndef CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_PAGE_VIEW_H_ +#define CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_PAGE_VIEW_H_ + +#include <vector> + +#include "base/scoped_ptr.h" +#include "chrome/browser/views/options/options_page_view.h" +#include "chrome/browser/webdata/web_data_service.h" +#include "chrome/common/gfx/text_elider.h" +#include "chrome/common/stl_util-inl.h" +#include "chrome/views/controls/button/native_button.h" +#include "chrome/views/controls/label.h" +#include "chrome/views/controls/table/table_view.h" +#include "chrome/views/window/dialog_delegate.h" +#include "chrome/views/window/window.h" +#include "webkit/glue/password_form.h" + +class Profile; + +/////////////////////////////////////////////////////////////////////////////// +// PasswordTableModelObserver +// An observer interface to notify change of row count in a table model. This +// allow the container view of TableView(i.e. PasswordsPageView and +// ExceptionsPageView), to be notified of row count changes directly +// from the TableModel. We have two different observers in +// PasswordsTableModel, namely views::TableModelObserver and +// PasswordsTableModelObserver, rather than adding this event to +// views::TableModelObserver because only container view of +// PasswordsTableModel cares about this event. +class PasswordsTableModelObserver { + public: + virtual void OnRowCountChanged(size_t rows) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// MultiLabelButtons +// A button that can have 2 different labels set on it and for which the +// preferred size is the size of the widest string. +class MultiLabelButtons : public views::NativeButton { + public: + MultiLabelButtons(views::ButtonListener* listener, + const std::wstring& label, + const std::wstring& alt_label); + + virtual gfx::Size GetPreferredSize(); + + private: + std::wstring label_; + std::wstring alt_label_; + gfx::Size pref_size_; + + DISALLOW_COPY_AND_ASSIGN(MultiLabelButtons); +}; + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsTableModel +class PasswordsTableModel : public views::TableModel, + public WebDataServiceConsumer { + public: + explicit PasswordsTableModel(Profile* profile); + virtual ~PasswordsTableModel(); + + // TableModel methods. + virtual int RowCount(); + virtual std::wstring GetText(int row, int column); + virtual int CompareValues(int row1, int row2, int column_id); + virtual void SetObserver(views::TableModelObserver* observer); + + // Delete the PasswordForm at specified row from the database (and remove + // from view). + void ForgetAndRemoveSignon(int row); + + // Delete all saved signons for the active profile (via web data service), + // and clear the view. + void ForgetAndRemoveAllSignons(); + + // WebDataServiceConsumer implementation. + virtual void OnWebDataServiceRequestDone(WebDataService::Handle h, + const WDTypedResult* result); + // Request saved logins data. + void GetAllSavedLoginsForProfile(); + + // Return the PasswordForm at the specified index. + PasswordForm* GetPasswordFormAt(int row); + + // Set the observer who concerns about how many rows are in the table. + void set_row_count_observer(PasswordsTableModelObserver* observer) { + row_count_observer_ = observer; + } + + protected: + // Wraps the PasswordForm from the database and caches the display URL for + // quick sorting. + struct PasswordRow { + PasswordRow(const gfx::SortedDisplayURL& url, PasswordForm* password_form) + : display_url(url), form(password_form) { + } + + // Contains the URL that is displayed along with the + gfx::SortedDisplayURL display_url; + + // The underlying PasswordForm. We own this. + scoped_ptr<PasswordForm> form; + }; + + // The web data service associated with the currently active profile. + WebDataService* web_data_service() { + return profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); + } + + // The TableView observing this model. + views::TableModelObserver* observer_; + + // Dispatching row count events specific to this password manager table model + // to this observer. + PasswordsTableModelObserver* row_count_observer_; + + // Handle to any pending WebDataService::GetLogins query. + WebDataService::Handle pending_login_query_; + + // The set of passwords we're showing. + typedef std::vector<PasswordRow*> PasswordRows; + PasswordRows saved_signons_; + STLElementDeleter<PasswordRows> saved_signons_cleanup_; + + Profile* profile_; + + private: + // Cancel any pending login query involving a callback. + void CancelLoginsQuery(); + + DISALLOW_COPY_AND_ASSIGN(PasswordsTableModel); +}; + +/////////////////////////////////////////////////////////////////////////////// +// PasswordsPageView +class PasswordsPageView : public OptionsPageView, + public views::TableViewObserver, + public views::ButtonListener, + public PasswordsTableModelObserver { + public: + explicit PasswordsPageView(Profile* profile); + + // views::TableViewObserverImplementation. + virtual void OnSelectionChanged(); + + // views::ButtonListener implementation. + virtual void ButtonPressed(views::Button* sender); + + // PasswordsTableModelObserver implementation. + virtual void OnRowCountChanged(size_t rows); + + protected: + virtual void InitControlLayout(); + + private: + // Helper to configure our buttons and labels. + void SetupButtonsAndLabels(); + + // Helper to configure our table view. + void SetupTable(); + + PasswordsTableModel table_model_; + views::TableView* table_view_; + + // The buttons and labels. + MultiLabelButtons show_button_; + views::NativeButton remove_button_; + views::NativeButton remove_all_button_; + views::Label password_label_; + + DISALLOW_COPY_AND_ASSIGN(PasswordsPageView); +}; + +#endif // CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_PAGE_VIEW_H_ |