| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/views/options/passwords_page_view.h" |
| 6 |
| 7 #include "base/string_util.h" |
| 8 #include "chrome/browser/profile.h" |
| 9 #include "chrome/browser/views/standard_layout.h" |
| 10 #include "chrome/common/l10n_util.h" |
| 11 #include "chrome/common/pref_names.h" |
| 12 #include "chrome/common/pref_service.h" |
| 13 #include "chrome/views/background.h" |
| 14 #include "chrome/views/controls/button/native_button.h" |
| 15 #include "chrome/views/grid_layout.h" |
| 16 #include "grit/generated_resources.h" |
| 17 |
| 18 using views::ColumnSet; |
| 19 using views::GridLayout; |
| 20 |
| 21 /////////////////////////////////////////////////////////////////////////////// |
| 22 // MultiLabelButtons |
| 23 MultiLabelButtons::MultiLabelButtons(views::ButtonListener* listener, |
| 24 const std::wstring& label, |
| 25 const std::wstring& alt_label) |
| 26 : NativeButton(listener, label), |
| 27 label_(label), |
| 28 alt_label_(alt_label), |
| 29 pref_size_(-1, -1) { |
| 30 } |
| 31 |
| 32 gfx::Size MultiLabelButtons::GetPreferredSize() { |
| 33 if (pref_size_.width() == -1 && pref_size_.height() == -1) { |
| 34 // Let's compute our preferred size. |
| 35 std::wstring current_label = label(); |
| 36 SetLabel(label_); |
| 37 pref_size_ = NativeButton::GetPreferredSize(); |
| 38 SetLabel(alt_label_); |
| 39 gfx::Size alt_pref_size = NativeButton::GetPreferredSize(); |
| 40 // Revert to the original label. |
| 41 SetLabel(current_label); |
| 42 pref_size_.SetSize(std::max(pref_size_.width(), alt_pref_size.width()), |
| 43 std::max(pref_size_.height(), alt_pref_size.height())); |
| 44 } |
| 45 return gfx::Size(pref_size_.width(), pref_size_.height()); |
| 46 } |
| 47 |
| 48 /////////////////////////////////////////////////////////////////////////////// |
| 49 // PasswordsTableModel, public |
| 50 PasswordsTableModel::PasswordsTableModel(Profile* profile) |
| 51 : observer_(NULL), |
| 52 row_count_observer_(NULL), |
| 53 pending_login_query_(NULL), |
| 54 saved_signons_cleanup_(&saved_signons_), |
| 55 profile_(profile) { |
| 56 DCHECK(profile && profile->GetWebDataService(Profile::EXPLICIT_ACCESS)); |
| 57 } |
| 58 |
| 59 PasswordsTableModel::~PasswordsTableModel() { |
| 60 CancelLoginsQuery(); |
| 61 } |
| 62 |
| 63 int PasswordsTableModel::RowCount() { |
| 64 return static_cast<int>(saved_signons_.size()); |
| 65 } |
| 66 |
| 67 std::wstring PasswordsTableModel::GetText(int row, |
| 68 int col_id) { |
| 69 switch (col_id) { |
| 70 case IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN: { // Site. |
| 71 const std::wstring& url = saved_signons_[row]->display_url.display_url(); |
| 72 // Force URL to have LTR directionality. |
| 73 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { |
| 74 std::wstring localized_url = url; |
| 75 l10n_util::WrapStringWithLTRFormatting(&localized_url); |
| 76 return localized_url; |
| 77 } |
| 78 return url; |
| 79 } |
| 80 case IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN: { // Username. |
| 81 std::wstring username = GetPasswordFormAt(row)->username_value; |
| 82 l10n_util::AdjustStringForLocaleDirection(username, &username); |
| 83 return username; |
| 84 } |
| 85 default: |
| 86 NOTREACHED() << "Invalid column."; |
| 87 return std::wstring(); |
| 88 } |
| 89 } |
| 90 |
| 91 int PasswordsTableModel::CompareValues(int row1, int row2, |
| 92 int column_id) { |
| 93 if (column_id == IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN) { |
| 94 return saved_signons_[row1]->display_url.Compare( |
| 95 saved_signons_[row2]->display_url, GetCollator()); |
| 96 } |
| 97 return TableModel::CompareValues(row1, row2, column_id); |
| 98 } |
| 99 |
| 100 void PasswordsTableModel::SetObserver( |
| 101 views::TableModelObserver* observer) { |
| 102 observer_ = observer; |
| 103 } |
| 104 |
| 105 void PasswordsTableModel::GetAllSavedLoginsForProfile() { |
| 106 DCHECK(!pending_login_query_); |
| 107 pending_login_query_ = web_data_service()->GetAllAutofillableLogins(this); |
| 108 } |
| 109 |
| 110 void PasswordsTableModel::OnWebDataServiceRequestDone( |
| 111 WebDataService::Handle h, |
| 112 const WDTypedResult* result) { |
| 113 DCHECK_EQ(pending_login_query_, h); |
| 114 pending_login_query_ = NULL; |
| 115 |
| 116 if (!result) |
| 117 return; |
| 118 |
| 119 DCHECK(result->GetType() == PASSWORD_RESULT); |
| 120 |
| 121 // Get the result from the database into a useable form. |
| 122 const WDResult<std::vector<PasswordForm*> >* r = |
| 123 static_cast<const WDResult<std::vector<PasswordForm*> >*>(result); |
| 124 std::vector<PasswordForm*> rows = r->GetValue(); |
| 125 STLDeleteElements<PasswordRows>(&saved_signons_); |
| 126 saved_signons_.resize(rows.size(), NULL); |
| 127 std::wstring languages = |
| 128 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); |
| 129 for (size_t i = 0; i < rows.size(); ++i) { |
| 130 saved_signons_[i] = new PasswordRow( |
| 131 gfx::SortedDisplayURL(rows[i]->origin, languages), rows[i]); |
| 132 } |
| 133 if (observer_) |
| 134 observer_->OnModelChanged(); |
| 135 if (row_count_observer_) |
| 136 row_count_observer_->OnRowCountChanged(RowCount()); |
| 137 } |
| 138 |
| 139 PasswordForm* PasswordsTableModel::GetPasswordFormAt(int row) { |
| 140 DCHECK(row >= 0 && row < RowCount()); |
| 141 return saved_signons_[row]->form.get(); |
| 142 } |
| 143 |
| 144 void PasswordsTableModel::ForgetAndRemoveSignon(int row) { |
| 145 DCHECK(row >= 0 && row < RowCount()); |
| 146 PasswordRows::iterator target_iter = saved_signons_.begin() + row; |
| 147 // Remove from DB, memory, and vector. |
| 148 PasswordRow* password_row = *target_iter; |
| 149 web_data_service()->RemoveLogin(*(password_row->form.get())); |
| 150 delete password_row; |
| 151 saved_signons_.erase(target_iter); |
| 152 if (observer_) |
| 153 observer_->OnItemsRemoved(row, 1); |
| 154 if (row_count_observer_) |
| 155 row_count_observer_->OnRowCountChanged(RowCount()); |
| 156 } |
| 157 |
| 158 void PasswordsTableModel::ForgetAndRemoveAllSignons() { |
| 159 PasswordRows::iterator iter = saved_signons_.begin(); |
| 160 while (iter != saved_signons_.end()) { |
| 161 // Remove from DB, memory, and vector. |
| 162 PasswordRow* row = *iter; |
| 163 web_data_service()->RemoveLogin(*(row->form.get())); |
| 164 delete row; |
| 165 iter = saved_signons_.erase(iter); |
| 166 } |
| 167 if (observer_) |
| 168 observer_->OnModelChanged(); |
| 169 if (row_count_observer_) |
| 170 row_count_observer_->OnRowCountChanged(RowCount()); |
| 171 } |
| 172 |
| 173 /////////////////////////////////////////////////////////////////////////////// |
| 174 // PasswordsTableModel, private |
| 175 void PasswordsTableModel::CancelLoginsQuery() { |
| 176 if (pending_login_query_) { |
| 177 web_data_service()->CancelRequest(pending_login_query_); |
| 178 pending_login_query_ = NULL; |
| 179 } |
| 180 } |
| 181 |
| 182 /////////////////////////////////////////////////////////////////////////////// |
| 183 // PasswordsPageView, public |
| 184 PasswordsPageView::PasswordsPageView(Profile* profile) |
| 185 : OptionsPageView(profile), |
| 186 show_button_( |
| 187 this, |
| 188 l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON), |
| 189 l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON)), |
| 190 remove_button_(this, l10n_util::GetString( |
| 191 IDS_PASSWORDS_PAGE_VIEW_REMOVE_BUTTON)), |
| 192 remove_all_button_(this, l10n_util::GetString( |
| 193 IDS_PASSWORDS_PAGE_VIEW_REMOVE_ALL_BUTTON)), |
| 194 table_model_(profile), |
| 195 table_view_(NULL) { |
| 196 } |
| 197 |
| 198 void PasswordsPageView::OnSelectionChanged() { |
| 199 bool has_selection = table_view_->SelectedRowCount() > 0; |
| 200 remove_button_.SetEnabled(has_selection); |
| 201 // Reset the password related views. |
| 202 show_button_.SetLabel( |
| 203 l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON)); |
| 204 show_button_.SetEnabled(has_selection); |
| 205 password_label_.SetText(std::wstring()); |
| 206 } |
| 207 |
| 208 void PasswordsPageView::ButtonPressed(views::Button* sender) { |
| 209 // Close will result in our destruction. |
| 210 if (sender == &remove_all_button_) { |
| 211 table_model_.ForgetAndRemoveAllSignons(); |
| 212 return; |
| 213 } |
| 214 |
| 215 // The following require a selection (and only one, since table is single- |
| 216 // select only). |
| 217 views::TableSelectionIterator iter = table_view_->SelectionBegin(); |
| 218 int row = *iter; |
| 219 PasswordForm* selected = table_model_.GetPasswordFormAt(row); |
| 220 DCHECK(++iter == table_view_->SelectionEnd()); |
| 221 |
| 222 if (sender == &remove_button_) { |
| 223 table_model_.ForgetAndRemoveSignon(row); |
| 224 } else if (sender == &show_button_) { |
| 225 if (password_label_.GetText().length() == 0) { |
| 226 password_label_.SetText(selected->password_value); |
| 227 show_button_.SetLabel( |
| 228 l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON)); |
| 229 } else { |
| 230 password_label_.SetText(L""); |
| 231 show_button_.SetLabel( |
| 232 l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON)); |
| 233 } |
| 234 } else { |
| 235 NOTREACHED() << "Invalid button."; |
| 236 } |
| 237 } |
| 238 |
| 239 void PasswordsPageView::OnRowCountChanged(size_t rows) { |
| 240 remove_all_button_.SetEnabled(rows > 0); |
| 241 } |
| 242 |
| 243 /////////////////////////////////////////////////////////////////////////////// |
| 244 // PasswordsPageView, protected |
| 245 void PasswordsPageView::InitControlLayout() { |
| 246 SetupButtonsAndLabels(); |
| 247 SetupTable(); |
| 248 |
| 249 // Do the layout thing. |
| 250 const int top_column_set_id = 0; |
| 251 const int lower_column_set_id = 1; |
| 252 GridLayout* layout = CreatePanelGridLayout(this); |
| 253 SetLayoutManager(layout); |
| 254 |
| 255 // Design the grid. |
| 256 ColumnSet* column_set = layout->AddColumnSet(top_column_set_id); |
| 257 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, |
| 258 GridLayout::FIXED, 300, 0); |
| 259 column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); |
| 260 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, |
| 261 GridLayout::USE_PREF, 0, 0); |
| 262 |
| 263 column_set = layout->AddColumnSet(lower_column_set_id); |
| 264 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, |
| 265 GridLayout::USE_PREF, 0, 0); |
| 266 column_set->AddPaddingColumn(1, kRelatedControlHorizontalSpacing); |
| 267 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, |
| 268 GridLayout::USE_PREF, 0, 0); |
| 269 column_set->LinkColumnSizes(0, 2, -1); |
| 270 |
| 271 // Fill the grid. |
| 272 layout->StartRow(0.05f, top_column_set_id); |
| 273 layout->AddView(table_view_, 1, 4); |
| 274 layout->AddView(&remove_button_); |
| 275 layout->StartRow(0.05f, top_column_set_id); |
| 276 layout->SkipColumns(1); |
| 277 layout->AddView(&remove_all_button_); |
| 278 layout->StartRow(0.05f, top_column_set_id); |
| 279 layout->SkipColumns(1); |
| 280 layout->AddView(&show_button_); |
| 281 layout->StartRow(0.80f, top_column_set_id); |
| 282 layout->SkipColumns(1); |
| 283 layout->AddView(&password_label_); |
| 284 layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); |
| 285 |
| 286 // Ask the database for saved password data. |
| 287 table_model_.GetAllSavedLoginsForProfile(); |
| 288 } |
| 289 |
| 290 /////////////////////////////////////////////////////////////////////////////// |
| 291 // PasswordsPageView, private |
| 292 void PasswordsPageView::SetupButtonsAndLabels() { |
| 293 // Disable all buttons in the first place. |
| 294 show_button_.SetParentOwned(false); |
| 295 show_button_.SetEnabled(false); |
| 296 |
| 297 remove_button_.SetParentOwned(false); |
| 298 remove_button_.SetEnabled(false); |
| 299 |
| 300 remove_all_button_.SetParentOwned(false); |
| 301 remove_all_button_.SetEnabled(false); |
| 302 |
| 303 password_label_.SetParentOwned(false); |
| 304 } |
| 305 |
| 306 void PasswordsPageView::SetupTable() { |
| 307 // Tell the table model we are concern about how many rows it has. |
| 308 table_model_.set_row_count_observer(this); |
| 309 |
| 310 // Creates the different columns for the table. |
| 311 // The float resize values are the result of much tinkering. |
| 312 std::vector<views::TableColumn> columns; |
| 313 columns.push_back(views::TableColumn(IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN, |
| 314 views::TableColumn::LEFT, -1, 0.55f)); |
| 315 columns.back().sortable = true; |
| 316 columns.push_back(views::TableColumn( |
| 317 IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN, views::TableColumn::RIGHT, |
| 318 -1, 0.37f)); |
| 319 columns.back().sortable = true; |
| 320 table_view_ = new views::TableView(&table_model_, columns, views::TEXT_ONLY, |
| 321 true, true, true); |
| 322 // Make the table initially sorted by host. |
| 323 views::TableView::SortDescriptors sort; |
| 324 sort.push_back(views::TableView::SortDescriptor( |
| 325 IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN, true)); |
| 326 table_view_->SetSortDescriptors(sort); |
| 327 table_view_->SetObserver(this); |
| 328 } |
| OLD | NEW |