| // Copyright (c) 2010 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/url_picker.h" |
| |
| #include "app/l10n_util.h" |
| #include "app/resource_bundle.h" |
| #include "app/table_model.h" |
| #include "app/table_model_observer.h" |
| #include "base/keyboard_codes.h" |
| #include "base/stl_util-inl.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/net/url_fixer_upper.h" |
| #include "chrome/browser/possible_url_model.h" |
| #include "chrome/browser/pref_service.h" |
| #include "chrome/browser/profile.h" |
| #include "chrome/browser/tab_contents/tab_contents.h" |
| #include "chrome/common/pref_names.h" |
| #include "grit/app_resources.h" |
| #include "grit/generated_resources.h" |
| #include "grit/locale_settings.h" |
| #include "net/base/net_util.h" |
| #include "views/background.h" |
| #include "views/controls/label.h" |
| #include "views/controls/table/table_view.h" |
| #include "views/controls/textfield/textfield.h" |
| #include "views/focus/focus_manager.h" |
| #include "views/grid_layout.h" |
| #include "views/standard_layout.h" |
| #include "views/widget/widget.h" |
| |
| using views::ColumnSet; |
| using views::GridLayout; |
| |
| // Preferred width of the table. |
| static const int kTableWidth = 300; |
| |
| UrlPickerDelegate::~UrlPickerDelegate() {} |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // UrlPicker implementation |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| UrlPicker::UrlPicker(UrlPickerDelegate* delegate, |
| Profile* profile) |
| : profile_(profile), |
| delegate_(delegate) { |
| DCHECK(profile_); |
| |
| ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| |
| url_table_model_.reset(new PossibleURLModel()); |
| |
| TableColumn col1(IDS_ASI_PAGE_COLUMN, TableColumn::LEFT, -1, |
| 50); |
| col1.sortable = true; |
| TableColumn col2(IDS_ASI_URL_COLUMN, TableColumn::LEFT, -1, |
| 50); |
| col2.sortable = true; |
| std::vector<TableColumn> cols; |
| cols.push_back(col1); |
| cols.push_back(col2); |
| |
| url_table_ = new views::TableView(url_table_model_.get(), cols, |
| views::ICON_AND_TEXT, true, true, |
| true); |
| url_table_->SetObserver(this); |
| |
| // Yummy layout code. |
| GridLayout* layout = CreatePanelGridLayout(this); |
| SetLayoutManager(layout); |
| |
| const int labels_column_set_id = 0; |
| const int single_column_view_set_id = 1; |
| |
| ColumnSet* column_set = layout->AddColumnSet(labels_column_set_id); |
| column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, |
| GridLayout::USE_PREF, 0, 0); |
| column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); |
| column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, |
| GridLayout::USE_PREF, 0, 0); |
| |
| column_set = layout->AddColumnSet(single_column_view_set_id); |
| column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, |
| GridLayout::FIXED, kTableWidth, 0); |
| |
| layout->StartRow(0, labels_column_set_id); |
| views::Label* url_label = new views::Label(); |
| url_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| url_label->SetText(l10n_util::GetString(IDS_ASI_URL)); |
| layout->AddView(url_label); |
| |
| url_field_ = new views::Textfield(); |
| url_field_->SetController(this); |
| layout->AddView(url_field_); |
| |
| layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); |
| |
| layout->StartRow(0, single_column_view_set_id); |
| views::Label* description_label = new views::Label(); |
| description_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| description_label->SetText(l10n_util::GetString(IDS_ASI_DESCRIPTION)); |
| description_label->SetFont( |
| description_label->font().DeriveFont(0, gfx::Font::BOLD)); |
| layout->AddView(description_label); |
| |
| layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); |
| |
| layout->StartRow(1, single_column_view_set_id); |
| layout->AddView(url_table_); |
| |
| layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); |
| |
| AddAccelerator(views::Accelerator(base::VKEY_RETURN, false, false, false)); |
| } |
| |
| UrlPicker::~UrlPicker() { |
| url_table_->SetModel(NULL); |
| } |
| |
| void UrlPicker::Show(HWND parent) { |
| DCHECK(!window()); |
| views::Window::CreateChromeWindow(parent, gfx::Rect(), this)->Show(); |
| url_field_->SelectAll(); |
| url_field_->RequestFocus(); |
| url_table_model_->Reload(profile_); |
| } |
| |
| void UrlPicker::Close() { |
| DCHECK(window()); |
| window()->Close(); |
| } |
| |
| std::wstring UrlPicker::GetWindowTitle() const { |
| return l10n_util::GetString(IDS_ASI_ADD_TITLE); |
| } |
| |
| bool UrlPicker::IsModal() const { |
| return true; |
| } |
| |
| std::wstring UrlPicker::GetDialogButtonLabel( |
| MessageBoxFlags::DialogButton button) const { |
| if (button == MessageBoxFlags::DIALOGBUTTON_OK) |
| return l10n_util::GetString(IDS_ASI_ADD); |
| return std::wstring(); |
| } |
| |
| void UrlPicker::ContentsChanged(views::Textfield* sender, |
| const std::wstring& new_contents) { |
| GetDialogClientView()->UpdateDialogButtons(); |
| } |
| |
| bool UrlPicker::Accept() { |
| if (!IsDialogButtonEnabled(MessageBoxFlags::DIALOGBUTTON_OK)) { |
| if (!GetInputURL().is_valid()) |
| url_field_->RequestFocus(); |
| return false; |
| } |
| PerformModelChange(); |
| return true; |
| } |
| |
| int UrlPicker::GetDefaultDialogButton() const { |
| // Don't set a default button, this view already has an accelerator for the |
| // enter key. |
| return MessageBoxFlags::DIALOGBUTTON_NONE; |
| } |
| |
| bool UrlPicker::IsDialogButtonEnabled( |
| MessageBoxFlags::DialogButton button) const { |
| if (button == MessageBoxFlags::DIALOGBUTTON_OK) |
| return GetInputURL().is_valid(); |
| return true; |
| } |
| |
| views::View* UrlPicker::GetContentsView() { |
| return this; |
| } |
| |
| void UrlPicker::PerformModelChange() { |
| DCHECK(delegate_); |
| GURL url(GetInputURL()); |
| delegate_->AddBookmark(this, std::wstring(), url); |
| } |
| |
| gfx::Size UrlPicker::GetPreferredSize() { |
| return gfx::Size(views::Window::GetLocalizedContentsSize( |
| IDS_URLPICKER_DIALOG_WIDTH_CHARS, |
| IDS_URLPICKER_DIALOG_HEIGHT_LINES)); |
| } |
| |
| bool UrlPicker::AcceleratorPressed( |
| const views::Accelerator& accelerator) { |
| if (accelerator.GetKeyCode() == VK_ESCAPE) { |
| window()->Close(); |
| } else if (accelerator.GetKeyCode() == VK_RETURN) { |
| views::FocusManager* fm = GetFocusManager(); |
| if (fm->GetFocusedView() == url_table_) { |
| // Return on table behaves like a double click. |
| OnDoubleClick(); |
| } else if (fm->GetFocusedView()== url_field_) { |
| // Return on the url field accepts the input if url is valid. If the URL |
| // is invalid, focus is left on the url field. |
| if (GetInputURL().is_valid()) { |
| PerformModelChange(); |
| if (window()) |
| window()->Close(); |
| } else { |
| url_field_->SelectAll(); |
| } |
| } |
| } |
| return true; |
| } |
| |
| void UrlPicker::OnSelectionChanged() { |
| int selection = url_table_->FirstSelectedRow(); |
| if (selection >= 0 && selection < url_table_model_->RowCount()) { |
| std::wstring languages = UTF8ToWide( |
| profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
| // Because this gets parsed by FixupURL(), it's safe to omit the scheme or |
| // trailing slash, and unescape most characters, but we need to not drop any |
| // username/password, or unescape anything that changes the meaning. |
| std::wstring formatted = net::FormatUrl(url_table_model_->GetURL(selection), |
| languages, |
| net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword, |
| UnescapeRule::SPACES, NULL, NULL, NULL); |
| url_field_->SetText(formatted); |
| GetDialogClientView()->UpdateDialogButtons(); |
| } |
| } |
| |
| void UrlPicker::OnDoubleClick() { |
| int selection = url_table_->FirstSelectedRow(); |
| if (selection >= 0 && selection < url_table_model_->RowCount()) { |
| OnSelectionChanged(); |
| PerformModelChange(); |
| if (window()) |
| window()->Close(); |
| } |
| } |
| |
| GURL UrlPicker::GetInputURL() const { |
| return URLFixerUpper::FixupURL(UTF16ToUTF8(url_field_->text()), |
| std::string()); |
| } |