| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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/password_manager_view.h" | |
| 6 | |
| 7 #include "base/string_util.h" | |
| 8 #include "chrome/common/l10n_util.h" | |
| 9 #include "chrome/browser/profile.h" | |
| 10 #include "chrome/browser/views/standard_layout.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 PasswordManagerView* PasswordManagerView::instance_ = NULL; | |
| 22 | |
| 23 static const int kDefaultWindowWidth = 530; | |
| 24 static const int kDefaultWindowHeight = 240; | |
| 25 | |
| 26 //////////////////////////////////////////////////////////////////////////////// | |
| 27 // MultiLabelButtons | |
| 28 // | |
| 29 MultiLabelButtons::MultiLabelButtons(views::ButtonListener* listener, | |
| 30 const std::wstring& label, | |
| 31 const std::wstring& alt_label) | |
| 32 : NativeButton(listener, label), | |
| 33 label_(label), | |
| 34 alt_label_(alt_label), | |
| 35 pref_size_(-1, -1) { | |
| 36 } | |
| 37 | |
| 38 gfx::Size MultiLabelButtons::GetPreferredSize() { | |
| 39 if (pref_size_.width() == -1 && pref_size_.height() == -1) { | |
| 40 // Let's compute our preferred size. | |
| 41 std::wstring current_label = label(); | |
| 42 SetLabel(label_); | |
| 43 pref_size_ = NativeButton::GetPreferredSize(); | |
| 44 SetLabel(alt_label_); | |
| 45 gfx::Size alt_pref_size = NativeButton::GetPreferredSize(); | |
| 46 // Revert to the original label. | |
| 47 SetLabel(current_label); | |
| 48 pref_size_.SetSize(std::max(pref_size_.width(), alt_pref_size.width()), | |
| 49 std::max(pref_size_.height(), alt_pref_size.height())); | |
| 50 } | |
| 51 return gfx::Size(pref_size_.width(), pref_size_.height()); | |
| 52 } | |
| 53 | |
| 54 | |
| 55 //////////////////////////////////////////////////////////////////// | |
| 56 // PasswordManagerTableModel | |
| 57 PasswordManagerTableModel::PasswordManagerTableModel(Profile* profile) | |
| 58 : observer_(NULL), | |
| 59 row_count_observer_(NULL), | |
| 60 pending_login_query_(NULL), | |
| 61 saved_signons_cleanup_(&saved_signons_), | |
| 62 profile_(profile) { | |
| 63 DCHECK(profile && profile->GetWebDataService(Profile::EXPLICIT_ACCESS)); | |
| 64 } | |
| 65 | |
| 66 PasswordManagerTableModel::~PasswordManagerTableModel() { | |
| 67 CancelLoginsQuery(); | |
| 68 } | |
| 69 | |
| 70 int PasswordManagerTableModel::RowCount() { | |
| 71 return static_cast<int>(saved_signons_.size()); | |
| 72 } | |
| 73 | |
| 74 std::wstring PasswordManagerTableModel::GetText(int row, | |
| 75 int col_id) { | |
| 76 switch (col_id) { | |
| 77 case IDS_PASSWORD_MANAGER_VIEW_SITE_COLUMN: { // Site. | |
| 78 const std::wstring& url = saved_signons_[row]->display_url.display_url(); | |
| 79 // Force URL to have LTR directionality. | |
| 80 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { | |
| 81 std::wstring localized_url = url; | |
| 82 l10n_util::WrapStringWithLTRFormatting(&localized_url); | |
| 83 return localized_url; | |
| 84 } | |
| 85 return url; | |
| 86 } | |
| 87 case IDS_PASSWORD_MANAGER_VIEW_USERNAME_COLUMN: { // Username. | |
| 88 std::wstring username = GetPasswordFormAt(row)->username_value; | |
| 89 l10n_util::AdjustStringForLocaleDirection(username, &username); | |
| 90 return username; | |
| 91 } | |
| 92 default: | |
| 93 NOTREACHED() << "Invalid column."; | |
| 94 return std::wstring(); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 int PasswordManagerTableModel::CompareValues(int row1, int row2, | |
| 99 int column_id) { | |
| 100 if (column_id == IDS_PASSWORD_MANAGER_VIEW_SITE_COLUMN) { | |
| 101 return saved_signons_[row1]->display_url.Compare( | |
| 102 saved_signons_[row2]->display_url, GetCollator()); | |
| 103 } | |
| 104 return TableModel::CompareValues(row1, row2, column_id); | |
| 105 } | |
| 106 | |
| 107 void PasswordManagerTableModel::SetObserver( | |
| 108 views::TableModelObserver* observer) { | |
| 109 observer_ = observer; | |
| 110 } | |
| 111 | |
| 112 void PasswordManagerTableModel::GetAllSavedLoginsForProfile() { | |
| 113 DCHECK(!pending_login_query_); | |
| 114 pending_login_query_ = web_data_service()->GetAllAutofillableLogins(this); | |
| 115 } | |
| 116 | |
| 117 void PasswordManagerTableModel::OnWebDataServiceRequestDone( | |
| 118 WebDataService::Handle h, | |
| 119 const WDTypedResult* result) { | |
| 120 DCHECK_EQ(pending_login_query_, h); | |
| 121 pending_login_query_ = NULL; | |
| 122 | |
| 123 if (!result) | |
| 124 return; | |
| 125 | |
| 126 DCHECK(result->GetType() == PASSWORD_RESULT); | |
| 127 | |
| 128 // Get the result from the database into a useable form. | |
| 129 const WDResult<std::vector<PasswordForm*> >* r = | |
| 130 static_cast<const WDResult<std::vector<PasswordForm*> >*>(result); | |
| 131 std::vector<PasswordForm*> rows = r->GetValue(); | |
| 132 STLDeleteElements<PasswordRows>(&saved_signons_); | |
| 133 saved_signons_.resize(rows.size(), NULL); | |
| 134 std::wstring languages = | |
| 135 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); | |
| 136 for (size_t i = 0; i < rows.size(); ++i) { | |
| 137 saved_signons_[i] = new PasswordRow( | |
| 138 gfx::SortedDisplayURL(rows[i]->origin, languages), rows[i]); | |
| 139 } | |
| 140 if (observer_) | |
| 141 observer_->OnModelChanged(); | |
| 142 if (row_count_observer_) | |
| 143 row_count_observer_->OnRowCountChanged(RowCount()); | |
| 144 } | |
| 145 | |
| 146 void PasswordManagerTableModel::CancelLoginsQuery() { | |
| 147 if (pending_login_query_) { | |
| 148 web_data_service()->CancelRequest(pending_login_query_); | |
| 149 pending_login_query_ = NULL; | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 PasswordForm* PasswordManagerTableModel::GetPasswordFormAt(int row) { | |
| 154 DCHECK(row >= 0 && row < RowCount()); | |
| 155 return saved_signons_[row]->form.get(); | |
| 156 } | |
| 157 | |
| 158 void PasswordManagerTableModel::ForgetAndRemoveSignon(int row) { | |
| 159 DCHECK(row >= 0 && row < RowCount()); | |
| 160 PasswordRows::iterator target_iter = saved_signons_.begin() + row; | |
| 161 // Remove from DB, memory, and vector. | |
| 162 PasswordRow* password_row = *target_iter; | |
| 163 web_data_service()->RemoveLogin(*(password_row->form.get())); | |
| 164 delete password_row; | |
| 165 saved_signons_.erase(target_iter); | |
| 166 if (observer_) | |
| 167 observer_->OnItemsRemoved(row, 1); | |
| 168 if (row_count_observer_) | |
| 169 row_count_observer_->OnRowCountChanged(RowCount()); | |
| 170 } | |
| 171 | |
| 172 void PasswordManagerTableModel::ForgetAndRemoveAllSignons() { | |
| 173 PasswordRows::iterator iter = saved_signons_.begin(); | |
| 174 while (iter != saved_signons_.end()) { | |
| 175 // Remove from DB, memory, and vector. | |
| 176 PasswordRow* row = *iter; | |
| 177 web_data_service()->RemoveLogin(*(row->form.get())); | |
| 178 delete row; | |
| 179 iter = saved_signons_.erase(iter); | |
| 180 } | |
| 181 if (observer_) | |
| 182 observer_->OnModelChanged(); | |
| 183 if (row_count_observer_) | |
| 184 row_count_observer_->OnRowCountChanged(RowCount()); | |
| 185 } | |
| 186 | |
| 187 ////////////////////////////////////////////////////////////////////// | |
| 188 // PasswordManagerView | |
| 189 | |
| 190 // static | |
| 191 void PasswordManagerView::Show(Profile* profile) { | |
| 192 DCHECK(profile); | |
| 193 if (!instance_) { | |
| 194 instance_ = new PasswordManagerView(profile); | |
| 195 | |
| 196 // manager is owned by the dialog window, so Close() will delete it. | |
| 197 views::Window::CreateChromeWindow(NULL, gfx::Rect(), instance_); | |
| 198 } | |
| 199 if (!instance_->window()->IsVisible()) { | |
| 200 instance_->window()->Show(); | |
| 201 } else { | |
| 202 instance_->window()->Activate(); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 PasswordManagerView::PasswordManagerView(Profile* profile) | |
| 207 : show_button_( | |
| 208 this, | |
| 209 l10n_util::GetString(IDS_PASSWORD_MANAGER_VIEW_SHOW_BUTTON), | |
| 210 l10n_util::GetString(IDS_PASSWORD_MANAGER_VIEW_HIDE_BUTTON)), | |
| 211 remove_button_(this, l10n_util::GetString( | |
| 212 IDS_PASSWORD_MANAGER_VIEW_REMOVE_BUTTON)), | |
| 213 remove_all_button_(this, l10n_util::GetString( | |
| 214 IDS_PASSWORD_MANAGER_VIEW_REMOVE_ALL_BUTTON)), | |
| 215 table_model_(profile) { | |
| 216 Init(); | |
| 217 } | |
| 218 | |
| 219 void PasswordManagerView::SetupTable() { | |
| 220 // Tell the table model we are concern about how many rows it has. | |
| 221 table_model_.set_row_count_observer(this); | |
| 222 | |
| 223 // Creates the different columns for the table. | |
| 224 // The float resize values are the result of much tinkering. | |
| 225 std::vector<views::TableColumn> columns; | |
| 226 columns.push_back(views::TableColumn(IDS_PASSWORD_MANAGER_VIEW_SITE_COLUMN, | |
| 227 views::TableColumn::LEFT, -1, 0.55f)); | |
| 228 columns.back().sortable = true; | |
| 229 columns.push_back(views::TableColumn( | |
| 230 IDS_PASSWORD_MANAGER_VIEW_USERNAME_COLUMN, views::TableColumn::RIGHT, | |
| 231 -1, 0.37f)); | |
| 232 columns.back().sortable = true; | |
| 233 table_view_ = new views::TableView(&table_model_, columns, views::TEXT_ONLY, | |
| 234 true, true, true); | |
| 235 // Make the table initially sorted by host. | |
| 236 views::TableView::SortDescriptors sort; | |
| 237 sort.push_back(views::TableView::SortDescriptor( | |
| 238 IDS_PASSWORD_MANAGER_VIEW_SITE_COLUMN, true)); | |
| 239 table_view_->SetSortDescriptors(sort); | |
| 240 table_view_->SetObserver(this); | |
| 241 } | |
| 242 | |
| 243 void PasswordManagerView::SetupButtonsAndLabels() { | |
| 244 // Tell View not to delete class stack allocated views. | |
| 245 | |
| 246 show_button_.SetParentOwned(false); | |
| 247 show_button_.SetEnabled(false); | |
| 248 | |
| 249 remove_button_.SetParentOwned(false); | |
| 250 remove_button_.SetEnabled(false); | |
| 251 | |
| 252 remove_all_button_.SetParentOwned(false); | |
| 253 | |
| 254 password_label_.SetParentOwned(false); | |
| 255 } | |
| 256 | |
| 257 void PasswordManagerView::Init() { | |
| 258 // Configure the background and view elements (buttons, labels, table). | |
| 259 SetupButtonsAndLabels(); | |
| 260 SetupTable(); | |
| 261 | |
| 262 // Do the layout thing. | |
| 263 const int top_column_set_id = 0; | |
| 264 const int lower_column_set_id = 1; | |
| 265 GridLayout* layout = CreatePanelGridLayout(this); | |
| 266 SetLayoutManager(layout); | |
| 267 | |
| 268 // Design the grid. | |
| 269 ColumnSet* column_set = layout->AddColumnSet(top_column_set_id); | |
| 270 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, | |
| 271 GridLayout::FIXED, 300, 0); | |
| 272 column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); | |
| 273 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, | |
| 274 GridLayout::USE_PREF, 0, 0); | |
| 275 | |
| 276 column_set = layout->AddColumnSet(lower_column_set_id); | |
| 277 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, | |
| 278 GridLayout::USE_PREF, 0, 0); | |
| 279 column_set->AddPaddingColumn(1, kRelatedControlHorizontalSpacing); | |
| 280 column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, | |
| 281 GridLayout::USE_PREF, 0, 0); | |
| 282 column_set->LinkColumnSizes(0, 2, -1); | |
| 283 | |
| 284 // Fill the grid. | |
| 285 layout->StartRow(0.05f, top_column_set_id); | |
| 286 layout->AddView(table_view_, 1, 3); | |
| 287 layout->AddView(&remove_button_); | |
| 288 layout->StartRow(0.05f, top_column_set_id); | |
| 289 layout->SkipColumns(1); | |
| 290 layout->AddView(&show_button_); | |
| 291 layout->StartRow(0.80f, top_column_set_id); | |
| 292 layout->SkipColumns(1); | |
| 293 layout->AddView(&password_label_); | |
| 294 layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); | |
| 295 | |
| 296 // Ask the database for saved password data. | |
| 297 table_model_.GetAllSavedLoginsForProfile(); | |
| 298 } | |
| 299 | |
| 300 PasswordManagerView::~PasswordManagerView() { | |
| 301 } | |
| 302 | |
| 303 void PasswordManagerView::Layout() { | |
| 304 GetLayoutManager()->Layout(this); | |
| 305 | |
| 306 // Manually lay out the Remove All button in the same row as | |
| 307 // the close button. | |
| 308 gfx::Rect parent_bounds = GetParent()->GetLocalBounds(false); | |
| 309 gfx::Size prefsize = remove_all_button_.GetPreferredSize(); | |
| 310 int button_y = | |
| 311 parent_bounds.bottom() - prefsize.height() - kButtonVEdgeMargin; | |
| 312 remove_all_button_.SetBounds(kPanelHorizMargin, button_y, prefsize.width(), | |
| 313 prefsize.height()); | |
| 314 } | |
| 315 | |
| 316 gfx::Size PasswordManagerView::GetPreferredSize() { | |
| 317 return gfx::Size(kDefaultWindowWidth, kDefaultWindowHeight); | |
| 318 } | |
| 319 | |
| 320 void PasswordManagerView::ViewHierarchyChanged(bool is_add, | |
| 321 views::View* parent, | |
| 322 views::View* child) { | |
| 323 if (child == this) { | |
| 324 // Add and remove the Remove All button from the ClientView's hierarchy. | |
| 325 if (is_add) { | |
| 326 parent->AddChildView(&remove_all_button_); | |
| 327 } else { | |
| 328 parent->RemoveChildView(&remove_all_button_); | |
| 329 } | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 void PasswordManagerView::OnSelectionChanged() { | |
| 334 bool has_selection = table_view_->SelectedRowCount() > 0; | |
| 335 remove_button_.SetEnabled(has_selection); | |
| 336 // Reset the password related views. | |
| 337 show_button_.SetLabel( | |
| 338 l10n_util::GetString(IDS_PASSWORD_MANAGER_VIEW_SHOW_BUTTON)); | |
| 339 show_button_.SetEnabled(has_selection); | |
| 340 password_label_.SetText(std::wstring()); | |
| 341 } | |
| 342 | |
| 343 int PasswordManagerView::GetDialogButtons() const { | |
| 344 return DIALOGBUTTON_CANCEL; | |
| 345 } | |
| 346 | |
| 347 bool PasswordManagerView::CanResize() const { | |
| 348 return true; | |
| 349 } | |
| 350 | |
| 351 bool PasswordManagerView::CanMaximize() const { | |
| 352 return false; | |
| 353 } | |
| 354 | |
| 355 bool PasswordManagerView::IsAlwaysOnTop() const { | |
| 356 return false; | |
| 357 } | |
| 358 | |
| 359 bool PasswordManagerView::HasAlwaysOnTopMenu() const { | |
| 360 return false; | |
| 361 } | |
| 362 | |
| 363 std::wstring PasswordManagerView::GetWindowTitle() const { | |
| 364 return l10n_util::GetString(IDS_PASSWORD_MANAGER_VIEW_TITLE); | |
| 365 } | |
| 366 | |
| 367 void PasswordManagerView::ButtonPressed(views::Button* sender) { | |
| 368 DCHECK(window()); | |
| 369 // Close will result in our destruction. | |
| 370 if (sender == &remove_all_button_) { | |
| 371 table_model_.ForgetAndRemoveAllSignons(); | |
| 372 return; | |
| 373 } | |
| 374 | |
| 375 // The following require a selection (and only one, since table is single- | |
| 376 // select only). | |
| 377 views::TableSelectionIterator iter = table_view_->SelectionBegin(); | |
| 378 int row = *iter; | |
| 379 PasswordForm* selected = table_model_.GetPasswordFormAt(row); | |
| 380 DCHECK(++iter == table_view_->SelectionEnd()); | |
| 381 | |
| 382 if (sender == &remove_button_) { | |
| 383 table_model_.ForgetAndRemoveSignon(row); | |
| 384 } else if (sender == &show_button_) { | |
| 385 if (password_label_.GetText().length() == 0) { | |
| 386 password_label_.SetText(selected->password_value); | |
| 387 show_button_.SetLabel( | |
| 388 l10n_util::GetString(IDS_PASSWORD_MANAGER_VIEW_HIDE_BUTTON)); | |
| 389 } else { | |
| 390 password_label_.SetText(L""); | |
| 391 show_button_.SetLabel( | |
| 392 l10n_util::GetString(IDS_PASSWORD_MANAGER_VIEW_SHOW_BUTTON)); | |
| 393 } | |
| 394 } else { | |
| 395 NOTREACHED() << "Invalid button."; | |
| 396 } | |
| 397 } | |
| 398 | |
| 399 void PasswordManagerView::WindowClosing() { | |
| 400 // The table model will be deleted before the table view, so detach it. | |
| 401 table_view_->SetModel(NULL); | |
| 402 | |
| 403 // Clear the static instance so the next time Show() is called, a new | |
| 404 // instance is created. | |
| 405 instance_ = NULL; | |
| 406 } | |
| 407 | |
| 408 views::View* PasswordManagerView::GetContentsView() { | |
| 409 return this; | |
| 410 } | |
| 411 | |
| 412 void PasswordManagerView::OnRowCountChanged(size_t rows) { | |
| 413 remove_all_button_.SetEnabled(rows > 0); | |
| 414 } | |
| OLD | NEW |