diff options
author | rouslan@chromium.org <rouslan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-17 00:31:33 +0000 |
---|---|---|
committer | rouslan@chromium.org <rouslan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-17 00:31:33 +0000 |
commit | eb4bf166cb254650e7e371f792efc024df457e30 (patch) | |
tree | 3817a6e2096a14299aad856fc4a2ca7d2555d0a7 /chrome | |
parent | 1c0088fc6cfec7c21c20a147218f49b8e34e21c0 (diff) | |
download | chromium_src-eb4bf166cb254650e7e371f792efc024df457e30.zip chromium_src-eb4bf166cb254650e7e371f792efc024df457e30.tar.gz chromium_src-eb4bf166cb254650e7e371f792efc024df457e30.tar.bz2 |
Make Web Intents picker in Views conform to latest mocks
BUG=148615
TBR=jhawkins
Review URL: https://chromiumcodereview.appspot.com/11044020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162287 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
20 files changed, 782 insertions, 611 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 895f365..c55801c 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -14078,7 +14078,7 @@ Some features may be unavailable. Please check that the profile exists and you Complete action using: </message> <message name="IDS_FIND_MORE_INTENT_HANDLER_MESSAGE" desc="Text to show to inform the user that more intent services can be found in the web store."> - Find more apps by visiting the Chrome Web Store. + Find more apps in the Chrome Web Store </message> <message name="IDS_FIND_MORE_INTENT_HANDLER_TOOLTIP" desc="Tooltip text for the web store plus button on the intent picker dialog."> Find apps in the Chrome Web Store @@ -14087,7 +14087,7 @@ Some features may be unavailable. Please check that the profile exists and you No apps are registered for this action. </message> <message name="IDS_INTENT_PICKER_CHOOSE_SERVICE" desc="Prompt to the user to select one of the given services to complete a Web Intents action."> - Which app do you want to use? + Choose an app… </message> <message name="IDS_INTENT_PICKER_CHOOSE_SERVICES_NONE_INSTALLED_TITLE" desc="Heading in the Web Intents picker box for a section containing suggested applications from the Chrome Web Store. Displayed only if there are no installed services."> You have no apps installed. @@ -14122,19 +14122,19 @@ Some features may be unavailable. Please check that the profile exists and you <!-- Web Intents common actions --> <message name="IDS_WEB_INTENTS_ACTION_SHARE" desc="Question asking the user to pick a service for the 'share' action."> - Which app should be used for sharing? + Share with… </message> <message name="IDS_WEB_INTENTS_ACTION_EDIT" desc="Question asking the user to pick a service for the 'edit' action."> - Which app should be used for editing? + Edit with… </message> <message name="IDS_WEB_INTENTS_ACTION_VIEW" desc="Question asking the user to pick a service for the 'viewing' action."> - Which app should be used for viewing? + View with… </message> <message name="IDS_WEB_INTENTS_ACTION_SUBSCRIBE" desc="Question asking the user to pick a service for the 'subscribe' action."> - Which app should be used for subscribing? + Subscribe with… </message> <message name="IDS_WEB_INTENTS_ACTION_SAVE" desc="Question asking the user to pick a service for the 'save' action."> - Which app should be used for saving? + Save with… </message> <!-- Web Intents native services (titles) --> diff --git a/chrome/browser/ui/constrained_window_constants.cc b/chrome/browser/ui/constrained_window_constants.cc new file mode 100644 index 0000000..58817f7 --- /dev/null +++ b/chrome/browser/ui/constrained_window_constants.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2012 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/ui/constrained_window_constants.h" + +const int ConstrainedWindowConstants::kTitleTopPadding = 15; +const int ConstrainedWindowConstants::kHorizontalPadding = 20; +const int ConstrainedWindowConstants::kClientTopPadding = 15; +const int ConstrainedWindowConstants::kClientBottomPadding = 20; +const int ConstrainedWindowConstants::kCloseButtonPadding = 7; +const int ConstrainedWindowConstants::kBorderRadius = 2; +const int ConstrainedWindowConstants::kRowPadding = 20; + +const ui::ResourceBundle::FontStyle ConstrainedWindowConstants::kTextFontStyle = + ui::ResourceBundle::BaseFont; +const ui::ResourceBundle::FontStyle + ConstrainedWindowConstants::kBoldTextFontStyle = + ui::ResourceBundle::BoldFont; +const ui::ResourceBundle::FontStyle + ConstrainedWindowConstants::kTitleFontStyle = + ui::ResourceBundle::MediumFont; diff --git a/chrome/browser/ui/constrained_window_constants.h b/chrome/browser/ui/constrained_window_constants.h index 0d9d9ef..5a4e62a8 100644 --- a/chrome/browser/ui/constrained_window_constants.h +++ b/chrome/browser/ui/constrained_window_constants.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_CONSTRAINED_WINDOW_CONSTANTS_H_ #define CHROME_BROWSER_UI_CONSTRAINED_WINDOW_CONSTANTS_H_ +#include "ui/base/resource/resource_bundle.h" + /////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowConstants // @@ -12,23 +14,22 @@ // class ConstrainedWindowConstants { public: - static const int kTitleTopPadding = 15; // Padding above the title. - static const int kHorizontalPadding = 20; // Left and right padding. - static const int kClientTopPadding = 18; // Padding above the client view. - static const int kClientBottomPadding = 20; // Padding below the client view. - static const int kCloseButtonPadding = 7; // Padding around the close button. - static const int kBorderRadius = 2; // Border radius for dialog corners. - static const int kRowPadding = 20; // Padding between rows of text. + static const int kTitleTopPadding; // Padding above the title. + static const int kHorizontalPadding; // Left and right padding. + static const int kClientTopPadding; // Padding above the client view. + static const int kClientBottomPadding; // Padding below the client view. + static const int kCloseButtonPadding; // Padding around the close button. + static const int kBorderRadius; // Border radius for dialog corners. + static const int kRowPadding; // Padding between rows of text. // Font style for dialog text. - static const ui::ResourceBundle::FontStyle kTextFontStyle = - ui::ResourceBundle::BaseFont; + static const ui::ResourceBundle::FontStyle kTextFontStyle; + // Font style for bold dialog text. - static const ui::ResourceBundle::FontStyle kBoldTextFontStyle = - ui::ResourceBundle::BoldFont; + static const ui::ResourceBundle::FontStyle kBoldTextFontStyle; + // Font style for dialog title. - static const ui::ResourceBundle::FontStyle kTitleFontStyle = - ui::ResourceBundle::MediumFont; + static const ui::ResourceBundle::FontStyle kTitleFontStyle; }; #endif // CHROME_BROWSER_UI_CONSTRAINED_WINDOW_CONSTANTS_H_ diff --git a/chrome/browser/ui/intents/web_intent_picker.h b/chrome/browser/ui/intents/web_intent_picker.h index 3320b9b..38348ca 100644 --- a/chrome/browser/ui/intents/web_intent_picker.h +++ b/chrome/browser/ui/intents/web_intent_picker.h @@ -37,7 +37,7 @@ class WebIntentPicker { static const int kTitleLinkMaxWidth = 130; // The space in pixels between the top-level groups and the dialog border. - static const int kContentAreaBorder = 10; + static const int kContentAreaBorder = 20; // Vertical space above the separator. static const int kHeaderSeparatorPaddingTop = 16; @@ -52,7 +52,7 @@ class WebIntentPicker { static const int kServiceIconHeight = 16; // Space between icon and text. - static const int kIconTextPadding = 6; + static const int kIconTextPadding = 10; // Space between star rating and select button. static const int kStarButtonPadding = 20; diff --git a/chrome/browser/ui/intents/web_intent_picker_controller.cc b/chrome/browser/ui/intents/web_intent_picker_controller.cc index 8223228..40b35fd 100644 --- a/chrome/browser/ui/intents/web_intent_picker_controller.cc +++ b/chrome/browser/ui/intents/web_intent_picker_controller.cc @@ -553,9 +553,8 @@ void WebIntentPickerController::DispatchToInstalledExtension( // services. For now, just choose the first. const webkit_glue::WebIntentServiceData& service_data = services[0]; - picker_model_->AddInstalledService( - service_data.title, service_data.service_url, - service_data.disposition); + picker_model_->RemoveSuggestedExtension(extension_id); + AddServiceToModel(service_data); OnServiceChosen(service_data.service_url, service_data.disposition, kEnableDefaults); AsyncOperationFinished(); diff --git a/chrome/browser/ui/intents/web_intent_picker_model.cc b/chrome/browser/ui/intents/web_intent_picker_model.cc index 16b0fb2..1a9bda8 100644 --- a/chrome/browser/ui/intents/web_intent_picker_model.cc +++ b/chrome/browser/ui/intents/web_intent_picker_model.cc @@ -114,6 +114,19 @@ void WebIntentPickerModel::AddSuggestedExtensions( observer_->OnModelChanged(this); } +void WebIntentPickerModel::RemoveSuggestedExtension(const std::string& id) { + std::vector<SuggestedExtension>::iterator it; + for (it = suggested_extensions_.begin(); + it < suggested_extensions_.end(); + ++it) { + SuggestedExtension extension = *it; + if (extension.id == id) { + suggested_extensions_.erase(it); + break; + } + } +} + const WebIntentPickerModel::SuggestedExtension& WebIntentPickerModel::GetSuggestedExtensionAt(size_t index) const { DCHECK_LT(index, suggested_extensions_.size()); diff --git a/chrome/browser/ui/intents/web_intent_picker_model.h b/chrome/browser/ui/intents/web_intent_picker_model.h index f748a69..171e497 100644 --- a/chrome/browser/ui/intents/web_intent_picker_model.h +++ b/chrome/browser/ui/intents/web_intent_picker_model.h @@ -113,6 +113,9 @@ class WebIntentPickerModel { void AddSuggestedExtensions( const std::vector<SuggestedExtension>& suggestions); + // Remove the suggested extension with this id. + void RemoveSuggestedExtension(const std::string& id); + // Return the suggested extension at |index|. const SuggestedExtension& GetSuggestedExtensionAt(size_t index) const; diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc index b0a025d..9b1c38f 100644 --- a/chrome/browser/ui/views/collected_cookies_views.cc +++ b/chrome/browser/ui/views/collected_cookies_views.cc @@ -199,7 +199,8 @@ CollectedCookiesViews::CollectedCookiesViews(content::WebContents* web_contents) TabSpecificContentSettings::FromWebContents(web_contents); registrar_.Add(this, chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, content::Source<TabSpecificContentSettings>(content_settings)); - window_ = new ConstrainedWindowViews(web_contents, this, false); + window_ = new ConstrainedWindowViews( + web_contents, this, false, ConstrainedWindowViews::DEFAULT_INSETS); } /////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc index 95edf10..1af7f4c 100644 --- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc +++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc @@ -184,7 +184,8 @@ ConstrainedWebDialogDelegate* ui::CreateConstrainedWebDialog( ConstrainedWindow* constrained_window = new ConstrainedWindowViews(container->web_contents(), constrained_delegate, - false); + false, + ConstrainedWindowViews::DEFAULT_INSETS); constrained_delegate->set_window(constrained_window); return constrained_delegate; } diff --git a/chrome/browser/ui/views/constrained_window_frame_simple.cc b/chrome/browser/ui/views/constrained_window_frame_simple.cc index 4107fe7..6768ac2 100644 --- a/chrome/browser/ui/views/constrained_window_frame_simple.cc +++ b/chrome/browser/ui/views/constrained_window_frame_simple.cc @@ -4,172 +4,118 @@ #include "chrome/browser/ui/views/constrained_window_frame_simple.h" -#include "chrome/browser/ui/constrained_window.h" #include "chrome/browser/ui/constrained_window_constants.h" +#include "chrome/browser/ui/constrained_window.h" #include "chrome/browser/ui/views/constrained_window_views.h" -#include "grit/ui_resources.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/google_chrome_strings.h" #include "grit/shared_resources.h" #include "grit/theme_resources.h" +#include "grit/ui_resources.h" #include "ui/base/hit_test.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/rect.h" #include "ui/gfx/path.h" +#include "ui/gfx/rect.h" #include "ui/views/background.h" -#include "ui/views/controls/label.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/label.h" #include "ui/views/layout/grid_layout.h" -#include "ui/views/layout/layout_manager.h" #include "ui/views/layout/layout_constants.h" -#include "ui/views/widget/widget.h" +#include "ui/views/layout/layout_manager.h" #include "ui/views/widget/widget_delegate.h" - -namespace { - -typedef ConstrainedWindowFrameSimple::HeaderViews HeaderViews; - -// A layout manager that lays out the header view with proper padding, -// and sized to the widget's client view. -class HeaderLayout : public views::LayoutManager { - public: - explicit HeaderLayout() {} - virtual ~HeaderLayout() {} - - // Overridden from LayoutManager - virtual void Layout(views::View* host); - virtual gfx::Size GetPreferredSize(views::View* host); - - DISALLOW_COPY_AND_ASSIGN(HeaderLayout); -}; - -void HeaderLayout::Layout(views::View* host) { - if (!host->has_children()) - return; - - int top_padding = ConstrainedWindowConstants::kCloseButtonPadding; - int left_padding = ConstrainedWindowConstants::kHorizontalPadding; - int right_padding = ConstrainedWindowConstants::kCloseButtonPadding; - - views::View* header = host->child_at(0); - gfx::Size preferred_size = GetPreferredSize(host); - int width = preferred_size.width() - left_padding - right_padding; - int height = preferred_size.height() - top_padding; - - header->SetBounds(left_padding, top_padding, width, height); -} - -gfx::Size HeaderLayout::GetPreferredSize(views::View* host) { - int top_padding = ConstrainedWindowConstants::kCloseButtonPadding; - int left_padding = ConstrainedWindowConstants::kHorizontalPadding; - int right_padding = ConstrainedWindowConstants::kCloseButtonPadding; - - views::View* header = host->child_at(0); - gfx::Size header_size = header ? header->GetPreferredSize() : gfx::Size(); - int width = std::max(host->GetPreferredSize().width(), - left_padding + header_size.width() + right_padding); - int height = header_size.height() + top_padding; - - return gfx::Size(width, height); -} - -} // namespace - -ConstrainedWindowFrameSimple::HeaderViews::HeaderViews( - views::View* header, - views::Label* title_label, - views::Button* close_button) - : header(header), - title_label(title_label), - close_button(close_button) { - DCHECK(header); -} +#include "ui/views/widget/widget.h" ConstrainedWindowFrameSimple::ConstrainedWindowFrameSimple( - ConstrainedWindowViews* container) - : container_(container) { + ConstrainedWindowViews* container, + ConstrainedWindowViews::ChromeStyleClientInsets client_insets) + : container_(container), + title_label_( + new views::Label(container->widget_delegate()->GetWindowTitle())), + ALLOW_THIS_IN_INITIALIZER_LIST(close_button_( + new views::ImageButton(this))) { container_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM); - layout_ = new HeaderLayout(); - SetLayoutManager(layout_); + views::GridLayout* layout = new views::GridLayout(this); + const int kHeaderTopPadding = std::min( + ConstrainedWindowConstants::kCloseButtonPadding, + ConstrainedWindowConstants::kTitleTopPadding); + layout->SetInsets(kHeaderTopPadding, + ConstrainedWindowConstants::kHorizontalPadding, + 0, + ConstrainedWindowConstants::kCloseButtonPadding); + SetLayoutManager(layout); + views::ColumnSet* cs = layout->AddColumnSet(0); + cs->AddColumn(views::GridLayout::FILL, views::GridLayout::LEADING, 1, + views::GridLayout::USE_PREF, 0, 0); // Title. + cs->AddPaddingColumn(0, ConstrainedWindowConstants::kCloseButtonPadding); + cs->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0, + views::GridLayout::USE_PREF, 0, 0); // Close Button. + + layout->StartRow(0, 0); - SetHeaderView(CreateDefaultHeaderView()); + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + title_label_->SetFont(rb.GetFont( + ConstrainedWindowConstants::kTitleFontStyle)); + title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + title_label_->SetEnabledColor(ConstrainedWindow::GetTextColor()); + title_label_->set_border(views::Border::CreateEmptyBorder( + ConstrainedWindowConstants::kTitleTopPadding - kHeaderTopPadding, + 0, 0, 0)); + layout->AddView(title_label_); + + close_button_->SetImage(views::CustomButton::BS_NORMAL, + rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X)); + close_button_->SetImage(views::CustomButton::BS_HOT, + rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER)); + close_button_->SetImage(views::CustomButton::BS_PUSHED, + rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_PRESSED)); + close_button_->set_border(views::Border::CreateEmptyBorder( + ConstrainedWindowConstants::kCloseButtonPadding - kHeaderTopPadding, + 0, 0, 0)); + layout->AddView(close_button_); set_background(views::Background::CreateSolidBackground( ConstrainedWindow::GetBackgroundColor())); - set_border(views::Border::CreateEmptyBorder( - ConstrainedWindowConstants::kClientTopPadding, - ConstrainedWindowConstants::kHorizontalPadding, - ConstrainedWindowConstants::kClientBottomPadding, - ConstrainedWindowConstants::kHorizontalPadding)); + // Client insets have no relation to header insets: + // - The client insets are the distance from the window border to the client + // view. + // - The header insets are the distance from the window border to the header + // elements. + // + // The NO_ISNETS consumers draw atop the views above. + if (client_insets == ConstrainedWindowViews::DEFAULT_INSETS) { + const int kTitleBuiltinBottomPadding = 4; + set_border(views::Border::CreateEmptyBorder( + ConstrainedWindowConstants::kClientTopPadding + kHeaderTopPadding + + std::max(close_button_->GetPreferredSize().height(), + title_label_->GetPreferredSize().height()) - + kTitleBuiltinBottomPadding, + ConstrainedWindowConstants::kHorizontalPadding, + ConstrainedWindowConstants::kClientBottomPadding, + ConstrainedWindowConstants::kHorizontalPadding)); + } } ConstrainedWindowFrameSimple::~ConstrainedWindowFrameSimple() { } -void ConstrainedWindowFrameSimple::SetHeaderView(HeaderViews* header_views) -{ - RemoveAllChildViews(true); - - header_views_.reset(header_views); - - AddChildView(header_views_->header); -} - -HeaderViews* ConstrainedWindowFrameSimple::CreateDefaultHeaderView() { - const int kTitleTopPadding = ConstrainedWindowConstants::kTitleTopPadding - - ConstrainedWindowConstants::kCloseButtonPadding; - const int kTitleLeftPadding = 0; - const int kTitleBottomPadding = 0; - const int kTitleRightPadding = 0; - - views::View* header_view = new views::View; - - views::GridLayout* grid_layout = new views::GridLayout(header_view); - header_view->SetLayoutManager(grid_layout); - - views::ColumnSet* header_cs = grid_layout->AddColumnSet(0); - header_cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, - views::GridLayout::USE_PREF, 0, 0); // Title. - header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); - header_cs->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, - 0, views::GridLayout::USE_PREF, 0, 0); // Close Button. - - // Header row. - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - grid_layout->StartRow(0, 0); - - views::Label* title_label = new views::Label(); - title_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - title_label->SetFont(rb.GetFont(ConstrainedWindowConstants::kTitleFontStyle)); - title_label->SetEnabledColor(ConstrainedWindow::GetTextColor()); - title_label->SetText(container_->widget_delegate()->GetWindowTitle()); - title_label->set_border(views::Border::CreateEmptyBorder(kTitleTopPadding, - kTitleLeftPadding, kTitleBottomPadding, kTitleRightPadding)); - grid_layout->AddView(title_label); - - views::Button* close_button = CreateCloseButton(); - grid_layout->AddView(close_button); - - return new HeaderViews(header_view, title_label, close_button); -} - gfx::Rect ConstrainedWindowFrameSimple::GetBoundsForClientView() const { - gfx::Rect bounds(GetContentsBounds()); - if (header_views_->header) - bounds.Inset(0, header_views_->header->GetPreferredSize().height(), 0, 0); - return bounds; + return GetContentsBounds(); } gfx::Rect ConstrainedWindowFrameSimple::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { gfx::Rect bounds(client_bounds); bounds.Inset(-GetInsets()); - if (header_views_->header) - bounds.Inset(0, -header_views_->header->GetPreferredSize().height(), 0, 0); + bounds.set_width(std::max( + bounds.width(), + ConstrainedWindowConstants::kHorizontalPadding + + 2 * ConstrainedWindowConstants::kCloseButtonPadding + + title_label_->GetPreferredSize().width() + + close_button_->GetPreferredSize().width())); return bounds; } @@ -205,32 +151,16 @@ void ConstrainedWindowFrameSimple::UpdateWindowIcon() { } void ConstrainedWindowFrameSimple::UpdateWindowTitle() { - if (!header_views_->title_label) - return; - - string16 text = container_->widget_delegate()->GetWindowTitle(); - header_views_->title_label->SetText(text); + title_label_->SetText(container_->widget_delegate()->GetWindowTitle()); } gfx::Size ConstrainedWindowFrameSimple::GetPreferredSize() { - return container_->non_client_view()->GetWindowBoundsForClientBounds( + return GetWindowBoundsForClientBounds( gfx::Rect(container_->client_view()->GetPreferredSize())).size(); } void ConstrainedWindowFrameSimple::ButtonPressed(views::Button* sender, const ui::Event& event) { - if (header_views_->close_button && sender == header_views_->close_button) + if (sender == close_button_) sender->GetWidget()->Close(); } - -views::ImageButton* ConstrainedWindowFrameSimple::CreateCloseButton() { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - views::ImageButton* close_button = new views::ImageButton(this); - close_button->SetImage(views::CustomButton::BS_NORMAL, - rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X)); - close_button->SetImage(views::CustomButton::BS_HOT, - rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER)); - close_button->SetImage(views::CustomButton::BS_PUSHED, - rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_PRESSED)); - return close_button; -} diff --git a/chrome/browser/ui/views/constrained_window_frame_simple.h b/chrome/browser/ui/views/constrained_window_frame_simple.h index 3a141a5..552408c 100644 --- a/chrome/browser/ui/views/constrained_window_frame_simple.h +++ b/chrome/browser/ui/views/constrained_window_frame_simple.h @@ -6,15 +6,13 @@ #define CHROME_BROWSER_UI_VIEWS_CONSTRAINED_WINDOW_FRAME_SIMPLE_H_ #include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/views/constrained_window_views.h" #include "ui/views/controls/button/button.h" #include "ui/views/window/non_client_view.h" -class ConstrainedWindowViews; - namespace views { class ImageButton; class Label; -class LayoutManager; } //////////////////////////////////////////////////////////////////////////////// @@ -24,24 +22,11 @@ class LayoutManager; class ConstrainedWindowFrameSimple : public views::NonClientFrameView, public views::ButtonListener { public: - // Contains references to relevant views in the header. The header - // must be non-NULL. - struct HeaderViews { - HeaderViews(views::View* header, - views::Label* title_label, - views::Button* close_button); - - views::View* header; - views::Label* title_label; - views::Button* close_button; - }; - - explicit ConstrainedWindowFrameSimple(ConstrainedWindowViews* container); + explicit ConstrainedWindowFrameSimple( + ConstrainedWindowViews* container, + ConstrainedWindowViews::ChromeStyleClientInsets client_insets); virtual ~ConstrainedWindowFrameSimple(); - // SetHeaderView assumes ownership of the passed parameter. - void SetHeaderView(HeaderViews* header_views); - private: // Overridden from views::NonClientFrameView: virtual gfx::Rect GetBoundsForClientView() const OVERRIDE; @@ -61,15 +46,9 @@ class ConstrainedWindowFrameSimple : public views::NonClientFrameView, virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; - HeaderViews* CreateDefaultHeaderView(); - - views::ImageButton* CreateCloseButton(); - ConstrainedWindowViews* container_; - - views::LayoutManager* layout_; - - scoped_ptr<HeaderViews> header_views_; + views::Label* title_label_; + views::ImageButton* close_button_; DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowFrameSimple); }; diff --git a/chrome/browser/ui/views/constrained_window_views.cc b/chrome/browser/ui/views/constrained_window_views.cc index 6e0058a..63d2656 100644 --- a/chrome/browser/ui/views/constrained_window_views.cc +++ b/chrome/browser/ui/views/constrained_window_views.cc @@ -20,6 +20,10 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" #include "grit/chromium_strings.h" @@ -163,9 +167,6 @@ class VistaWindowResources : public views::WindowResources { gfx::ImageSkia* XPWindowResources::images_[]; gfx::ImageSkia* VistaWindowResources::images_[]; -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowFrameView - class ConstrainedWindowFrameView : public views::NonClientFrameView, public views::ButtonListener { public: @@ -285,9 +286,6 @@ const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0); } // namespace -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowFrameView, public: - ConstrainedWindowFrameView::ConstrainedWindowFrameView( ConstrainedWindowViews* container) : NonClientFrameView(), @@ -320,9 +318,6 @@ void ConstrainedWindowFrameView::UpdateWindowTitle() { SchedulePaintInRect(title_bounds_); } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowFrameView, views::NonClientFrameView implementation: - gfx::Rect ConstrainedWindowFrameView::GetBoundsForClientView() const { return client_view_bounds_; } @@ -371,9 +366,6 @@ void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size, views::GetDefaultWindowMask(size, window_mask); } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowFrameView, views::View implementation: - void ConstrainedWindowFrameView::OnPaint(gfx::Canvas* canvas) { PaintFrameBorder(canvas); PaintTitleBar(canvas); @@ -390,18 +382,12 @@ void ConstrainedWindowFrameView::OnThemeChanged() { InitWindowResources(); } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowFrameView, views::ButtonListener implementation: - void ConstrainedWindowFrameView::ButtonPressed( views::Button* sender, const ui::Event& event) { if (sender == close_button_) container_->CloseConstrainedWindow(); } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowFrameView, private: - int ConstrainedWindowFrameView::NonClientBorderThickness() const { return kFrameBorderThickness + kClientEdgeThickness; } @@ -574,18 +560,17 @@ class ConstrainedWindowFrameViewAsh : public ash::CustomFrameViewAsh { }; #endif // defined(USE_ASH) -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowViews, public: - ConstrainedWindowViews::ConstrainedWindowViews( content::WebContents* web_contents, views::WidgetDelegate* widget_delegate, - bool enable_chrome_style) + bool enable_chrome_style, + ChromeStyleClientInsets chrome_style_client_insets) : WebContentsObserver(web_contents), web_contents_(web_contents), + enable_chrome_style_(enable_chrome_style), + chrome_style_client_insets_(chrome_style_client_insets), ALLOW_THIS_IN_INITIALIZER_LIST(native_constrained_window_( - NativeConstrainedWindow::CreateNativeConstrainedWindow(this))), - enable_chrome_style_(enable_chrome_style) { + NativeConstrainedWindow::CreateNativeConstrainedWindow(this))) { views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.delegate = widget_delegate; params.native_widget = native_constrained_window_->AsNativeWidget(); @@ -594,9 +579,9 @@ ConstrainedWindowViews::ConstrainedWindowViews( if (enable_chrome_style_) { params.parent_widget = Widget::GetTopLevelWidgetForNativeView( - web_contents->GetView()->GetNativeView()); + web_contents_->GetView()->GetNativeView()); } else { - params.parent = web_contents->GetNativeView(); + params.parent = web_contents_->GetNativeView(); } #if defined(USE_ASH) @@ -622,7 +607,10 @@ ConstrainedWindowViews::ConstrainedWindowViews( if (dialog_client_view) dialog_client_view->set_background(background); } - PositionChromeStyleWindow(); + PositionChromeStyleWindow(GetRootView()->bounds().size()); + registrar_.Add(this, + content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, + content::Source<content::WebContents>(web_contents)); } ConstrainedWindowTabHelper* constrained_window_tab_helper = @@ -636,9 +624,6 @@ ConstrainedWindowViews::ConstrainedWindowViews( ConstrainedWindowViews::~ConstrainedWindowViews() { } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowViews, ConstrainedWindow implementation: - void ConstrainedWindowViews::ShowConstrainedWindow() { Show(); FocusConstrainedWindow(); @@ -684,34 +669,27 @@ void ConstrainedWindowViews::NotifyTabHelperWillClose() { constrained_window_tab_helper->WillClose(this); } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowViews, views::Widget overrides: - void ConstrainedWindowViews::CenterWindow(const gfx::Size& size) { - Widget::CenterWindow(size); if (enable_chrome_style_) - PositionChromeStyleWindow(); + PositionChromeStyleWindow(size); + else + Widget::CenterWindow(size); } views::NonClientFrameView* ConstrainedWindowViews::CreateNonClientFrameView() { - if (enable_chrome_style_) { - return new ConstrainedWindowFrameSimple(this); - } else { + if (enable_chrome_style_) + return new ConstrainedWindowFrameSimple(this, chrome_style_client_insets_); #if defined(USE_ASH) - CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(ash::switches::kAuraGoogleDialogFrames)) - return ash::Shell::GetInstance()->CreateDefaultNonClientFrameView(this); - ConstrainedWindowFrameViewAsh* frame = new ConstrainedWindowFrameViewAsh; - frame->Init(this); - return frame; + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(ash::switches::kAuraGoogleDialogFrames)) + return ash::Shell::GetInstance()->CreateDefaultNonClientFrameView(this); + ConstrainedWindowFrameViewAsh* frame = new ConstrainedWindowFrameViewAsh; + frame->Init(this); + return frame; #endif - return new ConstrainedWindowFrameView(this); - } + return new ConstrainedWindowFrameView(this); } -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowViews, NativeConstrainedWindowDelegate implementation: - void ConstrainedWindowViews::OnNativeConstrainedWindowDestroyed() { NotifyTabHelperWillClose(); } @@ -730,27 +708,35 @@ int ConstrainedWindowViews::GetNonClientComponent(const gfx::Point& point) { return HTNOWHERE; } -void ConstrainedWindowViews::PositionChromeStyleWindow() { +void ConstrainedWindowViews::WebContentsDestroyed( + content::WebContents* web_contents) { + web_contents_ = NULL; +} + +void ConstrainedWindowViews::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK(enable_chrome_style_); + DCHECK_EQ(type, content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED); + if (*content::Details<bool>(details).ptr()) + Show(); + else + Hide(); +} + +void ConstrainedWindowViews::PositionChromeStyleWindow(const gfx::Size& size) { DCHECK(enable_chrome_style_); - gfx::Rect bounds = GetRootView()->bounds(); + gfx::Rect bounds(GetRootView()->bounds().origin(), size); ConstrainedWindowTabHelperDelegate* tab_helper_delegate = ConstrainedWindowTabHelper::FromWebContents(web_contents_)->delegate(); - BrowserWindow* browser_window = tab_helper_delegate ? tab_helper_delegate->GetBrowserWindow() : NULL; - int top_y; - if (browser_window && browser_window->GetConstrainedWindowTopY(&top_y)) { - bounds.set_y(top_y); - bounds.set_x( - browser_window->GetBounds().width() / 2 - bounds.width() / 2); - SetBounds(bounds); + if (browser_window) { + bounds.set_x(browser_window->GetBounds().width() / 2 - bounds.width() / 2); + int top_y; + if (browser_window->GetConstrainedWindowTopY(&top_y)) + bounds.set_y(top_y); } -} - -//////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowViews, content::WebContentsObserver implementation: - -void ConstrainedWindowViews::WebContentsDestroyed( - content::WebContents* web_contents) { - web_contents_ = NULL; + SetBounds(bounds); } diff --git a/chrome/browser/ui/views/constrained_window_views.h b/chrome/browser/ui/views/constrained_window_views.h index 97d5b604..2e20a54 100644 --- a/chrome/browser/ui/views/constrained_window_views.h +++ b/chrome/browser/ui/views/constrained_window_views.h @@ -7,6 +7,8 @@ #include "base/compiler_specific.h" #include "chrome/browser/ui/constrained_window.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_observer.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" @@ -59,11 +61,19 @@ class NativeConstrainedWindow { class ConstrainedWindowViews : public views::Widget, public ConstrainedWindow, public NativeConstrainedWindowDelegate, - public content::WebContentsObserver { + public content::WebContentsObserver, + public content::NotificationObserver { public: + // Types of insets to use with chrome style frame. + enum ChromeStyleClientInsets { + DEFAULT_INSETS, + NO_INSETS, + }; + ConstrainedWindowViews(content::WebContents* web_contents, views::WidgetDelegate* widget_delegate, - bool enable_chrome_style); + bool enable_chrome_style, + ChromeStyleClientInsets chrome_style_client_insets); virtual ~ConstrainedWindowViews(); // Returns the WebContents that constrains this Constrained Window. @@ -78,6 +88,9 @@ class ConstrainedWindowViews : public views::Widget, // Overridden from views::Widget: void CenterWindow(const gfx::Size& size); + // Default insets for the dialog: + static gfx::Insets GetDefaultInsets(); + private: void NotifyTabHelperWillClose(); @@ -91,21 +104,30 @@ class ConstrainedWindowViews : public views::Widget, AsNativeWidgetDelegate() OVERRIDE; virtual int GetNonClientComponent(const gfx::Point& point) OVERRIDE; - // Set the top of the window to overlap the browser chrome. - void PositionChromeStyleWindow(); - // Overridden from content::WebContentsObserver: virtual void WebContentsDestroyed(content::WebContents* web_contents) OVERRIDE; - content::WebContents* web_contents_; + // Overridden from content::NotificationObserver: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; - NativeConstrainedWindow* native_constrained_window_; + // Set the top of the window to overlap the browser chrome. + void PositionChromeStyleWindow(const gfx::Size& size); + + content::NotificationRegistrar registrar_; + content::WebContents* web_contents_; // TODO(wittman): remove once all constrained window dialogs are moved // over to Chrome style. const bool enable_chrome_style_; + // Client insets to use when |enable_chrome_style_| is true. + ChromeStyleClientInsets chrome_style_client_insets_; + + NativeConstrainedWindow* native_constrained_window_; + DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowViews); }; diff --git a/chrome/browser/ui/views/constrained_window_views_browsertest.cc b/chrome/browser/ui/views/constrained_window_views_browsertest.cc index 82c0002..c98a4a3 100644 --- a/chrome/browser/ui/views/constrained_window_views_browsertest.cc +++ b/chrome/browser/ui/views/constrained_window_views_browsertest.cc @@ -114,8 +114,9 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, FocusTest) { // Create a constrained dialog. It will attach itself to tab_contents. scoped_ptr<TestConstrainedDialog> test_dialog1(new TestConstrainedDialog); - ConstrainedWindowViews* window1 = - new ConstrainedWindowViews(web_contents, test_dialog1.get(), false); + ConstrainedWindowViews* window1 = new ConstrainedWindowViews( + web_contents, test_dialog1.get(), false, + ConstrainedWindowViews::DEFAULT_INSETS); views::FocusManager* focus_manager = window1->GetFocusManager(); ASSERT_TRUE(focus_manager); @@ -128,8 +129,9 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, FocusTest) { // tab_contents, but will remain hidden since the test_dialog1 is still // showing. scoped_ptr<TestConstrainedDialog> test_dialog2(new TestConstrainedDialog); - ConstrainedWindowViews* window2 = - new ConstrainedWindowViews(web_contents, test_dialog2.get(), false); + ConstrainedWindowViews* window2 = new ConstrainedWindowViews( + web_contents, test_dialog2.get(), false, + ConstrainedWindowViews::DEFAULT_INSETS); // Should be the same focus_manager. ASSERT_EQ(focus_manager, window2->GetFocusManager()); @@ -186,8 +188,9 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabCloseTest) { // Create a constrained dialog. It will attach itself to tab_contents. scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog); - ConstrainedWindowViews* window = - new ConstrainedWindowViews(web_contents, test_dialog.get(), true); + ConstrainedWindowViews* window = new ConstrainedWindowViews( + web_contents, test_dialog.get(), true, + ConstrainedWindowViews::DEFAULT_INSETS); bool closed = browser()->tab_strip_model()->CloseTabContentsAt( diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc index 7c8850c..30149c3 100644 --- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc +++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc @@ -56,7 +56,8 @@ MediaGalleriesDialogViews::MediaGalleriesDialogViews( // Ownership of |contents_| is handed off by this call. |window_| will take // care of deleting itself after calling DeleteDelegate(). window_ = new ConstrainedWindowViews( - controller->tab_contents()->web_contents(), this, false); + controller->tab_contents()->web_contents(), this, false, + ConstrainedWindowViews::DEFAULT_INSETS); } MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {} diff --git a/chrome/browser/ui/views/login_prompt_views.cc b/chrome/browser/ui/views/login_prompt_views.cc index babc4ec..345b993 100644 --- a/chrome/browser/ui/views/login_prompt_views.cc +++ b/chrome/browser/ui/views/login_prompt_views.cc @@ -127,7 +127,9 @@ class LoginHandlerViews : public LoginHandler, // will occur via an InvokeLater on the UI thread, which is guaranteed // to happen after this is called (since this was InvokeLater'd first). WebContents* requesting_contents = GetWebContentsForLogin(); - SetDialog(new ConstrainedWindowViews(requesting_contents, this, false)); + SetDialog(new ConstrainedWindowViews( + requesting_contents, this, false, + ConstrainedWindowViews::DEFAULT_INSETS)); NotifyAuthNeeded(); } diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector.cc b/chrome/browser/ui/views/ssl_client_certificate_selector.cc index 74be4fe..1e5ed1d 100644 --- a/chrome/browser/ui/views/ssl_client_certificate_selector.cc +++ b/chrome/browser/ui/views/ssl_client_certificate_selector.cc @@ -140,9 +140,9 @@ void SSLClientCertificateSelector::Init() { StartObserving(); - window_ = new ConstrainedWindowViews(tab_contents_->web_contents(), - this, - false); + window_ = new ConstrainedWindowViews( + tab_contents_->web_contents(), this, false, + ConstrainedWindowViews::DEFAULT_INSETS); // Select the first row automatically. This must be done after the dialog has // been created. diff --git a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc index 95e094a..eda8164 100644 --- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc +++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc @@ -68,9 +68,9 @@ TabModalConfirmDialogViews::TabModalConfirmDialogViews( message_box_view_(new views::MessageBoxView( CreateMessageBoxViewInitParams(delegate->GetMessage(), enable_chrome_style))) { - delegate_->set_window(new ConstrainedWindowViews(tab_contents->web_contents(), - this, - enable_chrome_style)); + delegate_->set_window(new ConstrainedWindowViews( + tab_contents->web_contents(), this, enable_chrome_style, + ConstrainedWindowViews::DEFAULT_INSETS)); } TabModalConfirmDialogViews::~TabModalConfirmDialogViews() { diff --git a/chrome/browser/ui/views/web_intent_picker_views.cc b/chrome/browser/ui/views/web_intent_picker_views.cc index e208843..9341aad 100644 --- a/chrome/browser/ui/views/web_intent_picker_views.cc +++ b/chrome/browser/ui/views/web_intent_picker_views.cc @@ -7,10 +7,13 @@ #include "base/memory/scoped_vector.h" #include "base/time.h" +#include "base/timer.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/download/download_util.h" #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/constrained_window_constants.h" #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" #include "chrome/browser/ui/intents/web_intent_picker.h" #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" @@ -46,6 +49,7 @@ #include "ui/views/controls/label.h" #include "ui/views/controls/link.h" #include "ui/views/controls/link_listener.h" +#include "ui/views/controls/separator.h" #include "ui/views/controls/throbber.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/layout/box_layout.h" @@ -65,6 +69,12 @@ namespace { // The color used to dim disabled elements. const SkColor kHalfOpacityWhite = SkColorSetARGB(128, 255, 255, 255); +// The color used to display an enabled label. +const SkColor kEnabledLabelColor = SkColorSetRGB(51, 51, 51); + +// The color used to display an enabled link. +const SkColor kEnabledLinkColor = SkColorSetRGB(17, 85, 204); + // The color used to display a disabled link. const SkColor kDisabledLinkColor = SkColorSetRGB(128, 128, 128); @@ -80,6 +90,9 @@ const int kMinRowCount = 4; // Maximum number of action buttons - do not add suggestions to reach. const int kMaxRowCount = 8; +// The vertical padding around the UI elements in the waiting view. +const int kWaitingViewVerticalPadding = 40; + // Enables or disables all child views of |view|. void EnableChildViews(views::View* view, bool enabled) { for (int i = 0; i < view->child_count(); ++i) { @@ -100,7 +113,80 @@ views::ImageButton* CreateCloseButton(views::ButtonListener* listener) { rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER)); return close_button; } -// SarsView ------------------------------------------------------------------- + +// Creates a label. +views::Label* CreateLabel() { + views::Label* label = new views::Label(); + label->SetEnabledColor(kEnabledLabelColor); + label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + return label; +} + +// Creates a title-style label. +views::Label* CreateTitleLabel() { + views::Label* label = CreateLabel(); + label->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont( + ui::ResourceBundle::MediumFont)); + const int kLabelBuiltinTopPadding = 5; + label->set_border(views::Border::CreateEmptyBorder( + WebIntentPicker::kContentAreaBorder - + ConstrainedWindowConstants::kCloseButtonPadding - + kLabelBuiltinTopPadding, + 0, 0, 0)); + return label; +} + +// Creates a link. +views::Link* CreateLink() { + views::Link* link = new views::Link(); + link->SetEnabledColor(kEnabledLinkColor); + link->SetDisabledColor(kDisabledLinkColor); + link->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + return link; +} + +// Creates a header for the inline disposition dialog. +views::View* CreateInlineDispositionHeader( + views::ImageView* app_icon, + views::Label* app_title, + views::Link* use_another_service_link) { + views::View* header = new views::View(); + views::GridLayout* grid_layout = new views::GridLayout(header); + const int kIconBuiltinTopPadding = 6; + grid_layout->SetInsets( + WebIntentPicker::kContentAreaBorder - + ConstrainedWindowConstants::kCloseButtonPadding - + kIconBuiltinTopPadding, + 0, 0, 0); + header->SetLayoutManager(grid_layout); + views::ColumnSet* header_cs = grid_layout->AddColumnSet(0); + header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); // App icon. + header_cs->AddPaddingColumn(0, WebIntentPicker::kIconTextPadding); + header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // App title. + header_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing); + header_cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); // Use another app link. + grid_layout->StartRow(0, 0); + grid_layout->AddView(app_icon); + grid_layout->AddView(app_title); + grid_layout->AddView(use_another_service_link); + header->Layout(); + return header; +} + +// Checks whether the inline disposition dialog should show the link for using +// another service. +bool IsUseAnotherServiceVisible(WebIntentPickerModel* model) { + DCHECK(model); + return model->show_use_another_service() && + (model->GetInstalledServiceCount() > 1 || + model->GetSuggestedExtensionCount()); +} + + +// StarsView ------------------------------------------------------------------- // A view that displays 5 stars: empty, full or half full, given a rating in // the range [0,5]. @@ -141,6 +227,7 @@ StarsView::StarsView(double rating) StarsView::~StarsView() { } + // ThrobberNativeTextButton ---------------------------------------------------- // A native text button that can display a throbber in place of its icon. Much @@ -268,142 +355,169 @@ void ThrobberNativeTextButton::Run() { SchedulePaint(); } -// WaitingView ---------------------------------------------------------- -class WaitingView : public views::View { + +// SpinnerProgressIndicator ---------------------------------------------------- +class SpinnerProgressIndicator : public views::View { public: - WaitingView(views::ButtonListener* listener, bool use_close_button); + SpinnerProgressIndicator(); + virtual ~SpinnerProgressIndicator(); + + void SetPercentDone(int percent); + void SetIndeterminate(bool indetereminate); + + // Overridden from views::View. + virtual void Paint(gfx::Canvas* canvas) OVERRIDE; + virtual gfx::Size GetPreferredSize() OVERRIDE; private: - DISALLOW_COPY_AND_ASSIGN(WaitingView); + void UpdateTimer(); + int GetProgressAngle(); + + static const int kTimerIntervalMs = 1000 / 30; + static const int kSpinRateDegreesPerSecond = 270; + + int percent_done_; + int indeterminate_; + + base::TimeTicks start_time_; + base::RepeatingTimer<SpinnerProgressIndicator> timer_; + + DISALLOW_COPY_AND_ASSIGN(SpinnerProgressIndicator); }; -WaitingView::WaitingView(views::ButtonListener* listener, - bool use_close_button) { - views::GridLayout* layout = new views::GridLayout(this); - layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0)); - layout->SetInsets(WebIntentPicker::kContentAreaBorder, - WebIntentPicker::kContentAreaBorder, - WebIntentPicker::kContentAreaBorder, - WebIntentPicker::kContentAreaBorder); - SetLayoutManager(layout); +SpinnerProgressIndicator::SpinnerProgressIndicator() + : percent_done_(0), + indeterminate_(true) {} - views::ColumnSet* cs = layout->AddColumnSet(0); - views::ColumnSet* header_cs = NULL; - if (use_close_button) { - header_cs = layout->AddColumnSet(1); - header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); - header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); // Close Button. - } - cs->AddPaddingColumn(0, views::kPanelHorizIndentation); - cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, - 1, GridLayout::USE_PREF, 0, 0); - cs->AddPaddingColumn(0, views::kPanelHorizIndentation); +SpinnerProgressIndicator::~SpinnerProgressIndicator() { +} - // Create throbber. - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const gfx::ImageSkia* frames = - rb.GetImageNamed(IDR_SPEECH_INPUT_SPINNER).ToImageSkia(); - views::Throbber* throbber = new views::Throbber(kThrobberFrameTimeMs, true); - throbber->SetFrames(frames); - throbber->Start(); +void SpinnerProgressIndicator::SetPercentDone(int percent) { + percent_done_ = percent; + SchedulePaint(); + UpdateTimer(); +} - // Create text. - views::Label* label = new views::Label(); - label->SetHorizontalAlignment(views::Label::ALIGN_CENTER); - label->SetFont(rb.GetFont(ui::ResourceBundle::MediumBoldFont)); - label->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_WAIT_FOR_CWS)); +void SpinnerProgressIndicator::SetIndeterminate(bool indetereminate) { + indeterminate_ = indetereminate; + SchedulePaint(); + UpdateTimer(); +} - // Layout the view. - if (use_close_button) { - layout->StartRow(0, 1); - layout->AddView(CreateCloseButton(listener)); +void SpinnerProgressIndicator::Paint(gfx::Canvas* canvas) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia* fg = rb.GetImageSkiaNamed(IDR_WEB_INTENT_PROGRESS_FOREGROUND); + gfx::ImageSkia* bg = rb.GetImageSkiaNamed(IDR_WEB_INTENT_PROGRESS_BACKGROUND); + download_util::PaintCustomDownloadProgress( + canvas, + *bg, + *fg, + fg->width(), + bounds(), + GetProgressAngle(), + indeterminate_ ? -1 : percent_done_); +} + +gfx::Size SpinnerProgressIndicator::GetPreferredSize() { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia* fg = rb.GetImageSkiaNamed(IDR_WEB_INTENT_PROGRESS_FOREGROUND); + return fg->size(); +} + +void SpinnerProgressIndicator::UpdateTimer() { + if (!parent() || !indeterminate_) { + timer_.Stop(); + return; } - layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing); - layout->StartRow(0, 0); - layout->AddView(throbber); - layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing); - layout->StartRow(0, 0); - layout->AddView(label); - layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing); + if (!timer_.IsRunning()) { + start_time_ = base::TimeTicks::Now(); + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimerIntervalMs), + this, &SpinnerProgressIndicator::SchedulePaint); + } } -// SuggestedExtensionsLayout --------------------------------------------------- +int SpinnerProgressIndicator::GetProgressAngle() { + if (!indeterminate_) + return download_util::kStartAngleDegrees; + base::TimeDelta delta = base::TimeTicks::Now() - start_time_; + int angle = delta.InSecondsF() * kSpinRateDegreesPerSecond; + return angle % 360; +} -// TODO(groby): Extremely fragile code, relies on order and number of fields. -// Would probably be better off as GridLayout or similar. Also see review -// comments on http://codereview.chromium.org/10909183 -// A LayoutManager used by a row of the IntentsView. It is similar -// to a BoxLayout, but it right aligns the rightmost view (which is the install -// button). It also uses the maximum height of all views in the row as a -// preferred height so it doesn't change when the install button is hidden. -class SuggestedExtensionsLayout : public views::LayoutManager { +// WaitingView ---------------------------------------------------------- +class WaitingView : public views::View { public: - SuggestedExtensionsLayout(); - virtual ~SuggestedExtensionsLayout(); - - // Implementation of views::LayoutManager. - virtual void Layout(views::View* host) OVERRIDE; - virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE; + WaitingView(views::ButtonListener* listener, bool use_close_button); + virtual ~WaitingView(); private: - DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsLayout); + DISALLOW_COPY_AND_ASSIGN(WaitingView); }; -SuggestedExtensionsLayout::SuggestedExtensionsLayout() { -} - -SuggestedExtensionsLayout::~SuggestedExtensionsLayout() { -} - -void SuggestedExtensionsLayout::Layout(views::View* host) { - gfx::Rect child_area(host->GetLocalBounds()); - child_area.Inset(host->GetInsets()); - int x = child_area.x(); - int y = child_area.y(); - - for (int i = 0; i < host->child_count(); ++i) { - views::View* child = host->child_at(i); - if (!child->visible()) - continue; - gfx::Size size(child->GetPreferredSize()); - gfx::Rect child_bounds(x, y, size.width(), child_area.height()); - if (i == host->child_count() - 1) { - // Last child (the install button) should be right aligned. - child_bounds.set_x(std::max(child_area.width() - size.width(), x)); - } else if (i == 1) { - // Label is considered fixed width, to align ratings widget. - DCHECK_LE(size.width(), WebIntentPicker::kTitleLinkMaxWidth); - x += WebIntentPicker::kTitleLinkMaxWidth + - views::kRelatedControlHorizontalSpacing; - } else { - x += size.width() + views::kRelatedControlHorizontalSpacing; - } - // Clamp child view bounds to |child_area|. - child->SetBoundsRect(child_bounds.Intersect(child_area)); - } +WaitingView::WaitingView(views::ButtonListener* listener, + bool use_close_button) { + views::GridLayout* layout = new views::GridLayout(this); + layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0)); + const int kMessageBuiltinBottomPadding = 3; + layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding, + 0, + kWaitingViewVerticalPadding - kMessageBuiltinBottomPadding, + 0); + SetLayoutManager(layout); + + enum GridLayoutColumnSets { + HEADER_ROW, + CONTENT_ROW, + }; + views::ColumnSet* header_cs = layout->AddColumnSet(HEADER_ROW); + header_cs->AddPaddingColumn(1, 1); + header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kCloseButtonPadding); + + views::ColumnSet* content_cs = layout->AddColumnSet(CONTENT_ROW); + content_cs->AddPaddingColumn(0, views::kPanelHorizIndentation); + content_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); + content_cs->AddPaddingColumn(0, views::kPanelHorizIndentation); + + // Close button + layout->StartRow(0, HEADER_ROW); + views::ImageButton* close_button = CreateCloseButton(listener); + layout->AddView(close_button); + close_button->SetVisible(use_close_button); + + // Throbber + layout->AddPaddingRow(0, + kWaitingViewVerticalPadding - + ConstrainedWindowConstants::kCloseButtonPadding - + close_button->GetPreferredSize().height()); + layout->StartRow(0, CONTENT_ROW); + SpinnerProgressIndicator* throbber = new SpinnerProgressIndicator(); + layout->AddView(throbber); + + // Message + const int kMessageBuiltinTopPadding = 5; + layout->AddPaddingRow(0, + ConstrainedWindowConstants::kRowPadding - + kMessageBuiltinTopPadding); + layout->StartRow(0, CONTENT_ROW); + views::Label* label = CreateLabel(); + label->SetHorizontalAlignment(views::Label::ALIGN_CENTER); + label->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_WAIT_FOR_CWS)); + layout->AddView(label); + + // Start the throbber. + throbber->SetIndeterminate(true); } -gfx::Size SuggestedExtensionsLayout::GetPreferredSize(views::View* host) { - int width = 0; - int height = 0; - for (int i = 0; i < host->child_count(); ++i) { - views::View* child = host->child_at(i); - gfx::Size size(child->GetPreferredSize()); - // The preferred height includes visible and invisible children. This - // prevents jank when a child is hidden. - height = std::max(height, size.height()); - if (!child->visible()) - continue; - if (i != 0) - width += views::kRelatedControlHorizontalSpacing; - } - gfx::Insets insets(host->GetInsets()); - return gfx::Size(width + insets.width(), height + insets.height()); +WaitingView::~WaitingView() { } + // IntentRowView -------------------------------------------------- // A view for each row in the IntentsView. It displays information @@ -545,12 +659,14 @@ IntentRowView* IntentRowView::CreateHandlerRow( if (service != NULL) { view = new IntentRowView(ACTION_INVOKE, tag); icon = service->favicon.ToImageSkia(); - label = new views::Label(elided_title); + label = CreateLabel(); + label->SetText(elided_title); } else { view = new IntentRowView(ACTION_INSTALL, tag); view->extension_id_ = extension->id; icon = extension->icon.ToImageSkia(); - views::Link* link = new views::Link(elided_title); + views::Link* link = CreateLink(); + link->SetText(elided_title); link->set_listener(view); label = link; stars = new StarsView(extension->average_rating); @@ -558,25 +674,43 @@ IntentRowView* IntentRowView::CreateHandlerRow( view->delegate_ = delegate; - view->SetLayoutManager(new SuggestedExtensionsLayout); + views::GridLayout* grid_layout = new views::GridLayout(view); + view->SetLayoutManager(grid_layout); + + views::ColumnSet* columns = grid_layout->AddColumnSet(0); + columns->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); // Icon. + columns->AddPaddingColumn(0, WebIntentPicker::kIconTextPadding); + columns->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1, + GridLayout::FIXED, WebIntentPicker::kTitleLinkMaxWidth, 0); + const int kStarRatingHorizontalSpacing = 20; + columns->AddPaddingColumn(0, kStarRatingHorizontalSpacing); + if (stars != NULL) { + columns->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); // Star rating. + columns->AddPaddingColumn(0, kStarRatingHorizontalSpacing); + } + columns->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, + GridLayout::FIXED, preferred_width, 0); // Button. - view->icon_ = new views::ImageView(); + grid_layout->StartRow(0, 0); + view->icon_ = new views::ImageView(); view->icon_->SetImage(icon); - view->AddChildView(view->icon_); + grid_layout->AddView(view->icon_); view->title_link_ = label; - view->AddChildView(view->title_link_); + grid_layout->AddView(view->title_link_); if (stars != NULL) { view->stars_ = stars; - view->AddChildView(view->stars_); + grid_layout->AddView(view->stars_); } view->install_button_ = new ThrobberNativeTextButton( view, view->GetActionButtonMessage()); view->install_button_->set_preferred_width(preferred_width); - view->AddChildView(view->install_button_); + grid_layout->AddView(view->install_button_); return view; } @@ -641,6 +775,7 @@ string16 IntentRowView::GetActionButtonMessage() { return l10n_util::GetStringUTF16(message_id); } + // IntentsView ----------------------------------------------------- // A view that contains both installed services and suggested extensions @@ -702,8 +837,9 @@ void IntentsView::Update() { button_width_ = std::max( kButtonWidth, size_helper.GetPreferredSize().width()); - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kVertical, 0, 0, views::kRelatedControlVerticalSpacing); + const int kAppRowVerticalSpacing = 10; + views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kVertical, + 0, 0, kAppRowVerticalSpacing); SetLayoutManager(layout); int available_rows = kMaxRowCount; @@ -755,11 +891,12 @@ void IntentsView::OnEnabledChanged() { } // namespace + // WebIntentPickerViews -------------------------------------------------------- // Views implementation of WebIntentPicker. class WebIntentPickerViews : public views::ButtonListener, - public views::DialogDelegate, + public views::WidgetDelegate, public views::LinkListener, public WebIntentPicker, public WebIntentPickerModelObserver, @@ -775,14 +912,12 @@ class WebIntentPickerViews : public views::ButtonListener, virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; - // views::DialogDelegate implementation. + // views::WidgetDelegate implementation. virtual void WindowClosing() OVERRIDE; virtual void DeleteDelegate() OVERRIDE; virtual views::Widget* GetWidget() OVERRIDE; virtual const views::Widget* GetWidget() const OVERRIDE; virtual views::View* GetContentsView() OVERRIDE; - virtual int GetDialogButtons() const OVERRIDE; - virtual bool Cancel() OVERRIDE; // LinkListener implementation. virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; @@ -817,9 +952,21 @@ class WebIntentPickerViews : public views::ButtonListener, size_t tag) OVERRIDE; private: + enum WebIntentPickerViewsState { + INITIAL, + WAITING, + NO_SERVICES, + LIST_SERVICES, + INLINE_SERVICE, + } state_; + // Update picker contents to reflect the current state of the model. void UpdateContents(); + // Shows a spinner and notifies the user that we are waiting for information + // from the Chrome Web Store. + void ShowWaitingForSuggestions(); + // Updates the dialog with the list of available services, suggestions, // and a nice link to CWS to find more suggestions. This is the "Main" // view of the picker. @@ -842,6 +989,13 @@ class WebIntentPickerViews : public views::ButtonListener, // of the picker. const string16 GetActionTitle(); + // Refresh the icon for the inline disposition service that is being + // displayed. + void RefreshInlineServiceIcon(); + + // Refresh the extensions control in the picker. + void RefreshExtensions(); + // A weak pointer to the WebIntentPickerDelegate to notify when the user // chooses a service or cancels. WebIntentPickerDelegate* delegate_; @@ -853,10 +1007,6 @@ class WebIntentPickerViews : public views::ButtonListener, // Created locally, owned by Views. views::Label* action_label_; - // A weak pointer to the header label for the extension suggestions. - // Created locally, owned by Views. - views::Label* suggestions_label_; - // A weak pointer to the intents view. // Created locally, owned by Views view hierarchy. IntentsView* extensions_; @@ -883,6 +1033,9 @@ class WebIntentPickerViews : public views::ButtonListener, // Created locally, owned by Views. views::Link* more_suggestions_link_; + // The icon for the inline disposition service. + views::ImageView* inline_service_icon_; + // A weak pointer to the choose another service link. // Created locally, owned by Views. views::Link* choose_another_service_link_; @@ -890,10 +1043,6 @@ class WebIntentPickerViews : public views::ButtonListener, // Weak pointer to "Waiting for CWS" display. Owned by parent view. WaitingView* waiting_view_; - // Set to true when displaying the inline disposition web contents. Used to - // prevent laying out the inline disposition widgets twice. - bool displaying_web_contents_; - // The text for the current action. string16 action_text_; @@ -922,29 +1071,31 @@ WebIntentPicker* WebIntentPicker::Create(content::WebContents* web_contents, WebIntentPickerViews::WebIntentPickerViews(TabContents* tab_contents, WebIntentPickerDelegate* delegate, WebIntentPickerModel* model) - : delegate_(delegate), + : state_(INITIAL), + delegate_(delegate), model_(model), action_label_(NULL), - suggestions_label_(NULL), extensions_(NULL), tab_contents_(tab_contents), webview_(new views::WebView(tab_contents->profile())), window_(NULL), more_suggestions_link_(NULL), + inline_service_icon_(NULL), choose_another_service_link_(NULL), waiting_view_(NULL), - displaying_web_contents_(false), can_close_(true) { bool enable_chrome_style = chrome::IsFramelessConstrainedDialogEnabled(); use_close_button_ = enable_chrome_style; model_->set_observer(this); contents_ = new views::View(); - // Show the dialog. - window_ = new ConstrainedWindowViews(tab_contents->web_contents(), - this, - enable_chrome_style); + contents_->set_background(views::Background::CreateSolidBackground( + ConstrainedWindow::GetBackgroundColor())); + // Show the dialog. + window_ = new ConstrainedWindowViews(tab_contents->web_contents(), this, + enable_chrome_style, + ConstrainedWindowViews::NO_INSETS); if (model_->IsInlineDisposition()) OnInlineDisposition(string16(), model_->inline_disposition_url()); else @@ -980,14 +1131,6 @@ views::View* WebIntentPickerViews::GetContentsView() { return contents_; } -int WebIntentPickerViews::GetDialogButtons() const { - return ui::DIALOG_BUTTON_NONE; -} - -bool WebIntentPickerViews::Cancel() { - return can_close_; -} - void WebIntentPickerViews::LinkClicked(views::Link* source, int event_flags) { if (source == more_suggestions_link_) { delegate_->OnSuggestionsLinkClicked( @@ -1007,11 +1150,11 @@ void WebIntentPickerViews::Close() { void WebIntentPickerViews::SetActionString(const string16& action) { action_text_ = action; - - if (action_label_) + if (action_label_) { action_label_->SetText(GetActionTitle()); contents_->Layout(); SizeToContents(); + } } void WebIntentPickerViews::OnExtensionInstallSuccess(const std::string& id) { @@ -1020,6 +1163,7 @@ void WebIntentPickerViews::OnExtensionInstallSuccess(const std::string& id) { void WebIntentPickerViews::OnExtensionInstallFailure(const std::string& id) { extensions_->StopThrobber(); + extensions_->SetEnabled(true); more_suggestions_link_->SetEnabled(true); can_close_ = true; contents_->Layout(); @@ -1040,139 +1184,185 @@ void WebIntentPickerViews::OnPendingAsyncCompleted() { } void WebIntentPickerViews::ShowNoServicesMessage() { - ClearContents(); - - views::GridLayout* grid_layout = new views::GridLayout(contents_); - contents_->SetLayoutManager(grid_layout); - - grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, - kContentAreaBorder, kContentAreaBorder); - views::ColumnSet* main_cs = grid_layout->AddColumnSet(0); - main_cs->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1, - GridLayout::USE_PREF, 0, 0); - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + if (state_ == NO_SERVICES) + return; + state_ = NO_SERVICES; - grid_layout->StartRow(0, 0); - views::Label* header = new views::Label(); - header->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - header->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont)); - header->SetText(l10n_util::GetStringUTF16( + ClearContents(); + views::GridLayout* layout = new views::GridLayout(contents_); + layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0)); + const int kContentBuiltinBottomPadding = 3; + layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding, + 0, + ConstrainedWindowConstants::kClientBottomPadding - + kContentBuiltinBottomPadding, + 0); + contents_->SetLayoutManager(layout); + + enum GridLayoutColumnSets { + HEADER_ROW, + CONTENT_ROW, + }; + views::ColumnSet* header_cs = layout->AddColumnSet(HEADER_ROW); + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); + header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // Title + header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); // Close button + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kCloseButtonPadding); + + views::ColumnSet* content_cs = layout->AddColumnSet(CONTENT_ROW); + content_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); + content_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // Body + content_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); + + // Header + layout->StartRow(0, HEADER_ROW); + views::Label* title = CreateTitleLabel(); + title->SetText(l10n_util::GetStringUTF16( IDS_INTENT_PICKER_NO_SERVICES_TITLE)); - grid_layout->AddView(header); - - grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); - - grid_layout->StartRow(0, 0); - views::Label* body = new views::Label(); + layout->AddView(title); + + views::ImageButton* close_button = CreateCloseButton(this); + layout->AddView(close_button); + close_button->SetVisible(use_close_button_); + + // Content + const int kHeaderBuiltinBottomPadding = 4; + const int kContentBuiltinTopPadding = 5; + layout->AddPaddingRow(0, + ConstrainedWindowConstants::kRowPadding - + kHeaderBuiltinBottomPadding - + kContentBuiltinTopPadding); + layout->StartRow(0, CONTENT_ROW); + views::Label* body = CreateLabel(); body->SetMultiLine(true); - body->SetHorizontalAlignment(views::Label::ALIGN_LEFT); body->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_NO_SERVICES)); - grid_layout->AddView(body); + layout->AddView(body); - int height = contents_->GetHeightForWidth(kWindowMinWidth); - contents_->SetSize(gfx::Size(kWindowMinWidth, height)); + int height = contents_->GetHeightForWidth(WebIntentPicker::kWindowMinWidth); + contents_->SetSize(gfx::Size(WebIntentPicker::kWindowMinWidth, height)); + contents_->Layout(); } void WebIntentPickerViews::OnInlineDispositionWebContentsLoaded( content::WebContents* web_contents) { - if (displaying_web_contents_) + if (state_ == INLINE_SERVICE) return; + state_ = INLINE_SERVICE; // Replace the picker with the inline disposition. ClearContents(); - views::GridLayout* grid_layout = new views::GridLayout(contents_); + grid_layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0)); + grid_layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding, 0, + ConstrainedWindowConstants::kClientBottomPadding, 0); contents_->SetLayoutManager(grid_layout); - grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, - kContentAreaBorder, kContentAreaBorder); - views::ColumnSet* header_cs = grid_layout->AddColumnSet(0); - header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); // Icon. - header_cs->AddPaddingColumn(0, 4); - header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); // Title. - header_cs->AddPaddingColumn(0, 4); - header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); // Link. - header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); - if (use_close_button_) { - header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); // Close Button. - } - - views::ColumnSet* full_cs = grid_layout->AddColumnSet(1); - full_cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0, - GridLayout::USE_PREF, 0, 0); + enum GridLayoutColumnSets { + HEADER_ROW, + SEPARATOR_ROW, + WEB_CONTENTS_ROW, + }; + views::ColumnSet* header_cs = grid_layout->AddColumnSet(HEADER_ROW); + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); + header_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // Icon, title, link. + header_cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); + header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); // Close button. + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kCloseButtonPadding); + + views::ColumnSet* sep_cs = grid_layout->AddColumnSet(SEPARATOR_ROW); + sep_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // Separator. + + views::ColumnSet* contents_cs = grid_layout->AddColumnSet(WEB_CONTENTS_ROW); + contents_cs->AddPaddingColumn(0, 1); + contents_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // Web contents. + contents_cs->AddPaddingColumn(0, 1); + + // Header. + grid_layout->StartRow(0, HEADER_ROW); const WebIntentPickerModel::InstalledService* service = model_->GetInstalledServiceWithURL(model_->inline_disposition_url()); - // Header row. - grid_layout->StartRow(0, 0); - views::ImageView* icon = new views::ImageView(); - icon->SetImage(service->favicon.ToImageSkia()); - grid_layout->AddView(icon); - - string16 elided_title = ui::ElideText( - service->title, gfx::Font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END); - views::Label* title = new views::Label(elided_title); - grid_layout->AddView(title); - // Add link for "choose another service" if other suggestions are available - // or if more than one (the current) service is installed. - if (model_->show_use_another_service() && - (model_->GetInstalledServiceCount() > 1 || - model_->GetSuggestedExtensionCount())) { - choose_another_service_link_ = new views::Link( - l10n_util::GetStringUTF16(IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE)); - grid_layout->AddView(choose_another_service_link_); - choose_another_service_link_->set_listener(this); - } - - if (use_close_button_) - grid_layout->AddView(CreateCloseButton(this)); + if (!inline_service_icon_) + inline_service_icon_ = new views::ImageView(); + inline_service_icon_->SetImage(service->favicon.ToImageSkia()); + + views::Label* title = CreateLabel(); + title->SetText(ui::ElideText( + service->title, title->font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END)); + + if (!choose_another_service_link_) + choose_another_service_link_ = CreateLink(); + choose_another_service_link_->SetText(l10n_util::GetStringUTF16( + IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE)); + choose_another_service_link_->set_listener(this); + + grid_layout->AddView(CreateInlineDispositionHeader( + inline_service_icon_, title, choose_another_service_link_)); + choose_another_service_link_->SetVisible(IsUseAnotherServiceVisible(model_)); + + views::ImageButton* close_button = CreateCloseButton(this); + grid_layout->AddView(close_button); + close_button->SetVisible(use_close_button_); + + // Separator. + const int kHeaderBuiltinBottomPadding = 4; + grid_layout->AddPaddingRow(0, + ConstrainedWindowConstants::kRowPadding - + kHeaderBuiltinBottomPadding); + grid_layout->StartRow(0, SEPARATOR_ROW); + grid_layout->AddView(new views::Separator()); + + // Inline web contents. + const int kSeparatorBottomPadding = 3; + grid_layout->AddPaddingRow(0, kSeparatorBottomPadding); + grid_layout->StartRow(0, WEB_CONTENTS_ROW); + grid_layout->AddView(webview_); - // Inline web contents row. - grid_layout->StartRow(0, 1); - grid_layout->AddView(webview_, 1, 1, GridLayout::CENTER, - GridLayout::CENTER, 0, 0); contents_->Layout(); SizeToContents(); - displaying_web_contents_ = true; } void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) { - if (waiting_view_ && !model->IsWaitingForSuggestions()) + if (state_ == WAITING && !model->IsWaitingForSuggestions()) UpdateContents(); - if (suggestions_label_) { - string16 label_text = model->GetSuggestionsLinkText(); - suggestions_label_->SetText(label_text); - suggestions_label_->SetVisible(!label_text.empty()); + if (choose_another_service_link_) { + choose_another_service_link_->SetVisible(IsUseAnotherServiceVisible(model)); + contents_->Layout(); + SizeToContents(); } if (extensions_) - extensions_->Update(); - contents_->Layout(); - SizeToContents(); + RefreshExtensions(); } void WebIntentPickerViews::OnFaviconChanged(WebIntentPickerModel* model, size_t index) { // TODO(groby): Update favicons on extensions_; - contents_->Layout(); - SizeToContents(); + if (inline_service_icon_) + RefreshInlineServiceIcon(); + if (extensions_) + RefreshExtensions(); } void WebIntentPickerViews::OnExtensionIconChanged( WebIntentPickerModel* model, const std::string& extension_id) { - if (extensions_) - extensions_->Update(); - - contents_->Layout(); - SizeToContents(); + OnFaviconChanged(model, -1); } void WebIntentPickerViews::OnInlineDisposition( @@ -1235,13 +1425,7 @@ void WebIntentPickerViews::UpdateContents() { return; if (model_ && model_->IsWaitingForSuggestions()) { - ClearContents(); - contents_->SetLayoutManager(new views::FillLayout()); - waiting_view_ = new WaitingView(this, use_close_button_); - contents_->AddChildView(waiting_view_); - int height = contents_->GetHeightForWidth(kWindowMinWidth); - contents_->SetSize(gfx::Size(kWindowMinWidth, height)); - contents_->Layout(); + ShowWaitingForSuggestions(); } else if (model_ && (model_->GetInstalledServiceCount() || model_->GetSuggestedExtensionCount())) { ShowAvailableServices(); @@ -1251,99 +1435,105 @@ void WebIntentPickerViews::UpdateContents() { SizeToContents(); } +void WebIntentPickerViews::ShowWaitingForSuggestions() { + if (state_ == WAITING) + return; + state_ = WAITING; + ClearContents(); + contents_->SetLayoutManager(new views::FillLayout()); + waiting_view_ = new WaitingView(this, use_close_button_); + contents_->AddChildView(waiting_view_); + int height = contents_->GetHeightForWidth(kWindowMinWidth); + contents_->SetSize(gfx::Size(kWindowMinWidth, height)); + contents_->Layout(); +} + const string16 WebIntentPickerViews::GetActionTitle() { - return (!action_text_.empty()) ? - action_text_ : - l10n_util::GetStringUTF16(IDS_INTENT_PICKER_CHOOSE_SERVICE); + return action_text_.empty() ? + l10n_util::GetStringUTF16(IDS_INTENT_PICKER_CHOOSE_SERVICE) : + action_text_; } void WebIntentPickerViews::ShowAvailableServices() { - enum { - kHeaderRowColumnSet, // Column set for header layout. - kFullWidthColumnSet, // Column set with a single full-width column. - kIndentedFullWidthColumnSet, // Single full-width column, indented. - }; - ClearContents(); - displaying_web_contents_ = false; - + state_ = LIST_SERVICES; extensions_ = new IntentsView(model_, this); + gfx::Size min_size = gfx::Size(extensions_->AdjustWidth(kWindowMinWidth), 0); views::GridLayout* grid_layout = new views::GridLayout(contents_); + grid_layout->set_minimum_size(min_size); + const int kIconBuiltinBottomPadding = 4; + grid_layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding, + 0, + ConstrainedWindowConstants::kClientBottomPadding - + kIconBuiltinBottomPadding, + 0); contents_->SetLayoutManager(grid_layout); - grid_layout->set_minimum_size( - gfx::Size(extensions_->AdjustWidth(kWindowMinWidth), 0)); - grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, - kContentAreaBorder, kContentAreaBorder); - views::ColumnSet* header_cs = grid_layout->AddColumnSet(kHeaderRowColumnSet); + enum GridLayoutColumnSets { + HEADER_ROW, + CONTENT_ROW, + }; + views::ColumnSet* header_cs = grid_layout->AddColumnSet(HEADER_ROW); + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); // Title. - if (use_close_button_) { - header_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing); - header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); // Close Button. - } - - views::ColumnSet* full_cs = grid_layout->AddColumnSet(kFullWidthColumnSet); - full_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); - - views::ColumnSet* indent_cs = - grid_layout->AddColumnSet(kIndentedFullWidthColumnSet); - indent_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing); - indent_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - - // Header row. - grid_layout->StartRow(0, kHeaderRowColumnSet); - action_label_ = new views::Label(GetActionTitle()); - action_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - action_label_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont)); + GridLayout::USE_PREF, 0, 0); // Action title + header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0, + GridLayout::USE_PREF, 0, 0); // Close button + header_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kCloseButtonPadding); + + views::ColumnSet* content_cs = grid_layout->AddColumnSet(CONTENT_ROW); + content_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); + content_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); // Content. + content_cs->AddPaddingColumn( + 0, ConstrainedWindowConstants::kHorizontalPadding); + + // Header. + grid_layout->StartRow(0, HEADER_ROW); + if (!action_label_) + action_label_ = CreateTitleLabel(); + action_label_->SetText(GetActionTitle()); grid_layout->AddView(action_label_); - if (use_close_button_) - grid_layout->AddView(CreateCloseButton(this)); - - // Padding row. - grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + views::ImageButton* close_button = CreateCloseButton(this); + grid_layout->AddView(close_button); + close_button->SetVisible(use_close_button_); - // Row with app suggestions label. - grid_layout->StartRow(0, kIndentedFullWidthColumnSet); - suggestions_label_ = new views::Label(); - suggestions_label_->SetVisible(false); - suggestions_label_->SetMultiLine(true); - suggestions_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - grid_layout->AddView(suggestions_label_); - - // Padding row. - grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); - - // Row with extension suggestions. - grid_layout->StartRow(0, kIndentedFullWidthColumnSet); + // Extensions. + const int kHeaderBuiltinBottomPadding = 4; + grid_layout->AddPaddingRow(0, + ConstrainedWindowConstants::kRowPadding - + kHeaderBuiltinBottomPadding); + grid_layout->StartRow(0, CONTENT_ROW); grid_layout->AddView(extensions_); - // Padding row. - grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); // Row with "more suggestions" link. - grid_layout->StartRow(0, kFullWidthColumnSet); + const int kIconBuiltinTopPadding = 6; + grid_layout->AddPaddingRow(0, + ConstrainedWindowConstants::kRowPadding - + kIconBuiltinTopPadding); + grid_layout->StartRow(0, CONTENT_ROW); views::View* more_view = new views::View(); - more_view->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, - views::kRelatedControlHorizontalSpacing)); + more_view->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kHorizontal, 0, 0, kIconTextPadding)); views::ImageView* icon = new views::ImageView(); - icon->SetImage(rb.GetImageNamed(IDR_WEBSTORE_ICON_16).ToImageSkia()); + icon->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_WEBSTORE_ICON_16)); more_view->AddChildView(icon); - more_suggestions_link_ = new views::Link( - l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE)); - more_suggestions_link_->SetDisabledColor(kDisabledLinkColor); + if (!more_suggestions_link_) + more_suggestions_link_ = CreateLink(); + more_suggestions_link_->SetText( + l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE)); more_suggestions_link_->set_listener(this); more_view->AddChildView(more_suggestions_link_); grid_layout->AddView(more_view, 1, 1, GridLayout::LEADING, GridLayout::CENTER); + contents_->Layout(); } @@ -1357,8 +1547,10 @@ void WebIntentPickerViews::ResetContents() { UpdateContents(); // Restore previous state. - extensions_->Update(); - action_label_->SetText(action_text_); + if (extensions_) + extensions_->Update(); + if (action_label_) + action_label_->SetText(action_text_); contents_->Layout(); SizeToContents(); } @@ -1379,8 +1571,23 @@ void WebIntentPickerViews::ClearContents() { // would cause hard-to-explain crashes. contents_->RemoveAllChildViews(true); action_label_ = NULL; - suggestions_label_ = NULL; extensions_ = NULL; more_suggestions_link_ = NULL; + inline_service_icon_ = NULL; choose_another_service_link_ = NULL; } + +void WebIntentPickerViews::RefreshInlineServiceIcon() { + DCHECK(inline_service_icon_); + const WebIntentPickerModel::InstalledService* inline_service = + model_->GetInstalledServiceWithURL(model_->inline_disposition_url()); + if (inline_service) + inline_service_icon_->SetImage(inline_service->favicon.ToImageSkia()); +} + +void WebIntentPickerViews::RefreshExtensions() { + DCHECK(extensions_); + extensions_->Update(); + contents_->Layout(); + SizeToContents(); +} diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 8888f98..b58629e 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -787,6 +787,7 @@ 'browser/ui/content_settings/content_setting_image_model.h', 'browser/ui/constrained_window.cc', 'browser/ui/constrained_window.h', + 'browser/ui/constrained_window_constants.cc', 'browser/ui/constrained_window_constants.h', 'browser/ui/constrained_window_tab_helper.cc', 'browser/ui/constrained_window_tab_helper.h', |