Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7998)

Unified Diff: chrome/browser/ui/views/web_intent_picker_views.cc

Issue 9959130: [Web Intents] Display throbber when loading inline disposition. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/intents/web_intent_picker.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/views/web_intent_picker_views.cc
diff --git a/chrome/browser/ui/views/web_intent_picker_views.cc b/chrome/browser/ui/views/web_intent_picker_views.cc
index f71d2f68ef491d43d89d396e37b0d363d6cf0b9c..75caf14f069b3ad1d1f0aa05676be7533e5c58e0 100644
--- a/chrome/browser/ui/views/web_intent_picker_views.cc
+++ b/chrome/browser/ui/views/web_intent_picker_views.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include <vector>
+#include "base/time.h"
#include "base/memory/scoped_vector.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
@@ -27,6 +28,7 @@
#include "grit/generated_resources.h"
#include "grit/google_chrome_strings.h"
#include "grit/theme_resources.h"
+#include "grit/ui_resources.h"
#include "grit/ui_resources_standard.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
@@ -76,6 +78,9 @@ const SkColor kHalfOpacityWhite = SkColorSetARGB(128, 255, 255, 255);
// The color used to display a disabled link.
const SkColor kDisabledLinkColor = SkColorSetRGB(128, 128, 128);
+// The time between successive throbber frames in milliseconds.
+const int kThrobberFrameTimeMs = 50;
+
// Enables or disables all child views of |view|.
void EnableChildViews(views::View* view, bool enabled) {
for (int i = 0; i < view->child_count(); ++i) {
@@ -125,6 +130,117 @@ StarsView::StarsView(double rating)
StarsView::~StarsView() {
}
+// ThrobberNativeTextButton ----------------------------------------------------
+
+// A native text button that can display a throbber in place of its icon. Much
+// of the logic of this class is copied from ui/views/controls/throbber.h.
+class ThrobberNativeTextButton : public views::NativeTextButton {
+ public:
+ ThrobberNativeTextButton(views::ButtonListener* listener,
+ const string16& text);
+ virtual ~ThrobberNativeTextButton();
+
+ // Start or stop the throbber.
+ void StartThrobber();
+ void StopThrobber();
+
+ // Set the throbber bitmap to use. IDR_THROBBER is used by default.
+ void SetFrames(const SkBitmap* frames);
+
+ protected:
+ virtual const SkBitmap& GetImageToPaint() const OVERRIDE;
+
+ private:
+ // The timer callback to schedule painting this view.
+ void Run();
+
+ // Bitmap that contains the throbber frames.
+ const SkBitmap* frames_;
+
+ // The currently displayed frame, given to GetImageToPaint.
+ mutable SkBitmap this_frame_;
+
+ // How long one frame is displayed.
+ base::TimeDelta frame_time_;
+
+ // Used to schedule Run calls.
+ base::RepeatingTimer<ThrobberNativeTextButton> timer_;
+
+ // How many frames we have.
+ int frame_count_;
+
+ // Time when StartThrobber was called.
+ base::TimeTicks start_time_;
+
+ // Whether the throbber is shown an animating.
+ bool running_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrobberNativeTextButton);
+};
+
+ThrobberNativeTextButton::ThrobberNativeTextButton(
+ views::ButtonListener* listener, const string16& text)
+ : NativeTextButton(listener, text),
+ frame_time_(base::TimeDelta::FromMilliseconds(kThrobberFrameTimeMs)),
+ frame_count_(0),
+ running_(false) {
+ SetFrames(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+ IDR_THROBBER).ToSkBitmap());
+}
+
+ThrobberNativeTextButton::~ThrobberNativeTextButton() {
+ StopThrobber();
+}
+
+void ThrobberNativeTextButton::StartThrobber() {
+ if (running_)
+ return;
+
+ start_time_ = base::TimeTicks::Now();
+ timer_.Start(FROM_HERE, frame_time_, this, &ThrobberNativeTextButton::Run);
+ running_ = true;
+
+ SchedulePaint();
+}
+
+void ThrobberNativeTextButton::StopThrobber() {
+ if (!running_)
+ return;
+
+ timer_.Stop();
+ running_ = false;
+}
+
+void ThrobberNativeTextButton::SetFrames(const SkBitmap* frames) {
+ frames_ = frames;
+ DCHECK(frames_->width() > 0 && frames_->height() > 0);
+ DCHECK(frames_->width() % frames_->height() == 0);
+ frame_count_ = frames_->width() / frames_->height();
+ PreferredSizeChanged();
+}
+
+const SkBitmap& ThrobberNativeTextButton::GetImageToPaint() const {
+ if (!running_)
+ return NativeTextButton::GetImageToPaint();
+
+ const base::TimeDelta elapsed_time = base::TimeTicks::Now() - start_time_;
+ const int current_frame =
+ static_cast<int>(elapsed_time / frame_time_) % frame_count_;
+ const int image_size = frames_->height();
+ const int image_offset = current_frame * image_size;
+
+ SkIRect subset_rect = SkIRect::MakeXYWH(image_offset, 0,
+ image_size, image_size);
+ frames_->extractSubset(&this_frame_, subset_rect);
+ return this_frame_;
+}
+
+void ThrobberNativeTextButton::Run() {
+ DCHECK(running_);
+
+ SchedulePaint();
+}
+
// ServiceButtonsView ----------------------------------------------------------
// A view that contains all service buttons (i.e. the installed services).
@@ -148,6 +264,10 @@ class ServiceButtonsView : public views::View,
// Updates the service button view with new model data.
void Update();
+ // Start a throbber on the service button that will launch the service at
+ // |url|.
+ void StartThrobber(const GURL& url);
+
// views::ButtonListener implementation.
virtual void ButtonPressed(views::Button* sender,
const views::Event& event) OVERRIDE;
@@ -194,8 +314,8 @@ void ServiceButtonsView::Update() {
grid_layout->StartRow(0, 0);
- views::NativeTextButton* button =
- new views::NativeTextButton(this, service.title);
+ ThrobberNativeTextButton* button =
+ new ThrobberNativeTextButton(this, service.title);
button->set_alignment(views::TextButton::ALIGN_LEFT);
button->SetTooltipText(UTF8ToUTF16(service.url.spec().c_str()));
button->SetIcon(*service.favicon.ToSkBitmap());
@@ -208,6 +328,20 @@ void ServiceButtonsView::Update() {
grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
}
+void ServiceButtonsView::StartThrobber(const GURL& url) {
+ for (size_t i = 0; i < model_->GetInstalledServiceCount(); ++i) {
+ const WebIntentPickerModel::InstalledService& service =
+ model_->GetInstalledServiceAt(i);
+ if (service.url != url)
+ continue;
+
+ ThrobberNativeTextButton* button =
+ static_cast<ThrobberNativeTextButton*>(child_at(i));
+ button->StartThrobber();
+ return;
+ }
+}
+
void ServiceButtonsView::ButtonPressed(views::Button* sender,
const views::Event& event) {
size_t index = static_cast<size_t>(sender->tag());
@@ -351,14 +485,11 @@ class SuggestedExtensionsRowView : public views::View,
// this extension.
views::Link* title_link_;
- // A throbber to display when the extension is being installed.
- views::Throbber* throbber_;
-
// The star rating of this extension.
StarsView* stars_;
// A button to install the extension.
- views::NativeTextButton* install_button_;
+ ThrobberNativeTextButton* install_button_;
DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsRowView);
};
@@ -380,14 +511,10 @@ SuggestedExtensionsRowView::SuggestedExtensionsRowView(
title_link_->set_listener(this);
AddChildView(title_link_);
- throbber_ = new views::Throbber(60, true);
- throbber_->SetVisible(false);
- AddChildView(throbber_);
-
stars_ = new StarsView(extension_->average_rating);
AddChildView(stars_);
- install_button_= new views::NativeTextButton(
+ install_button_= new ThrobberNativeTextButton(
this, l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION));
AddChildView(install_button_);
}
@@ -406,25 +533,20 @@ void SuggestedExtensionsRowView::LinkClicked(views::Link* source,
}
void SuggestedExtensionsRowView::StartThrobber() {
- stars_->SetVisible(false);
- install_button_->SetVisible(false);
- throbber_->SetVisible(true);
- throbber_->Start();
- Layout();
+ install_button_->StartThrobber();
+ install_button_->SetText(string16());
}
void SuggestedExtensionsRowView::StopThrobber() {
- stars_->SetVisible(true);
- install_button_->SetVisible(true);
- throbber_->SetVisible(false);
- throbber_->Stop();
- Layout();
+ install_button_->StopThrobber();
+ install_button_->SetText(
+ l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION));
}
void SuggestedExtensionsRowView::OnEnabledChanged() {
title_link_->SetEnabled(enabled());
- stars_->SetVisible(enabled());
- install_button_->SetVisible(enabled());
+ stars_->SetEnabled(enabled());
+ install_button_->SetEnabled(enabled());
View::OnEnabledChanged();
Layout();
}
@@ -439,8 +561,6 @@ void SuggestedExtensionsRowView::PaintChildren(gfx::Canvas* canvas) {
// A view that contains suggested extensions from the Chrome Web Store that
// provide an intent service matching the action/type pair.
-// This view also displays the "More suggestions" link which searches the
-// Chrome Web Store for more extensions.
class SuggestedExtensionsView : public views::View {
public:
SuggestedExtensionsView(const WebIntentPickerModel* model,
@@ -460,6 +580,9 @@ class SuggestedExtensionsView : public views::View {
// Hide the install throbber. This function re-enables all buttons and links.
void StopThrobber();
+ protected:
+ virtual void OnEnabledChanged() OVERRIDE;
+
private:
const WebIntentPickerModel* model_;
SuggestedExtensionsRowView::Delegate* delegate_;
@@ -518,6 +641,11 @@ void SuggestedExtensionsView::StopThrobber() {
}
}
+void SuggestedExtensionsView::OnEnabledChanged() {
+ EnableChildViews(this, enabled());
+ View::OnEnabledChanged();
+}
+
} // namespace
// WebIntentPickerViews --------------------------------------------------------
@@ -557,6 +685,8 @@ class WebIntentPickerViews : public views::ButtonListener,
virtual void SetActionString(const string16& action) OVERRIDE;
virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE;
virtual void OnExtensionInstallFailure(const std::string& id) OVERRIDE;
+ virtual void OnInlineDispositionWebContentsLoaded(
+ content::WebContents* web_contents) OVERRIDE;
// WebIntentPickerModelObserver implementation.
virtual void OnModelChanged(WebIntentPickerModel* model) OVERRIDE;
@@ -625,6 +755,10 @@ class WebIntentPickerViews : public views::ButtonListener,
// A weak pointer to the choose another service link.
views::Link* choose_another_service_link_;
+ // Set to true when displaying the inline disposition web contents. Used to
+ // prevent laying out the inline disposition widgets twice.
+ bool displaying_web_contents_;
+
DISALLOW_COPY_AND_ASSIGN(WebIntentPickerViews);
};
@@ -653,7 +787,8 @@ WebIntentPickerViews::WebIntentPickerViews(Browser* browser,
contents_(NULL),
window_(NULL),
more_suggestions_link_(NULL),
- choose_another_service_link_(NULL) {
+ choose_another_service_link_(NULL),
+ displaying_web_contents_(false) {
model_->set_observer(this);
InitContents();
@@ -733,58 +868,10 @@ void WebIntentPickerViews::OnExtensionInstallFailure(const std::string& id) {
// TODO(binji): What to display to user on failure?
}
-void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) {
- if (model->GetInstalledServiceCount() == 0) {
- suggestions_label_->SetText(l10n_util::GetStringUTF16(
- IDS_INTENT_PICKER_GET_MORE_SERVICES_NONE_INSTALLED));
- } else {
- suggestions_label_->SetText(
- l10n_util::GetStringUTF16(IDS_INTENT_PICKER_GET_MORE_SERVICES));
- }
-
- service_buttons_->Update();
- extensions_->Update();
- contents_->Layout();
- SizeToContents();
-}
-
-void WebIntentPickerViews::OnFaviconChanged(
- WebIntentPickerModel* model, size_t index) {
- service_buttons_->Update();
- contents_->Layout();
- SizeToContents();
-}
-
-void WebIntentPickerViews::OnExtensionIconChanged(
- WebIntentPickerModel* model,
- const string16& extension_id) {
- extensions_->Update();
- contents_->Layout();
- SizeToContents();
-}
-
-void WebIntentPickerViews::OnInlineDisposition(
- WebIntentPickerModel* model, const GURL& url) {
- WebContents* web_contents = WebContents::Create(
- browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL);
- inline_disposition_delegate_.reset(new WebIntentInlineDispositionDelegate);
- web_contents->SetDelegate(inline_disposition_delegate_.get());
-
- const WebIntentPickerModel::InstalledService* service =
- model->GetInstalledServiceWithURL(url);
- DCHECK(service);
-
- // Must call this immediately after WebContents creation to avoid race
- // with load.
- delegate_->OnInlineDispositionWebContentsCreated(web_contents);
-
- TabContentsContainer* tab_contents_container = new TabContentsContainer;
-
- web_contents->GetController().LoadURL(
- url,
- content::Referrer(),
- content::PAGE_TRANSITION_START_PAGE,
- std::string());
+void WebIntentPickerViews::OnInlineDispositionWebContentsLoaded(
+ content::WebContents* web_contents) {
+ if (displaying_web_contents_)
+ return;
// Replace the picker with the inline disposition.
contents_->RemoveAllChildViews(true);
@@ -813,6 +900,9 @@ void WebIntentPickerViews::OnInlineDisposition(
full_cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
GridLayout::USE_PREF, 0, 0);
+ const WebIntentPickerModel::InstalledService* service =
+ model_->GetInstalledServiceWithURL(model_->inline_disposition_url());
+
// Header row.
grid_layout->StartRow(0, 0);
views::ImageView* icon = new views::ImageView();
@@ -834,17 +924,77 @@ void WebIntentPickerViews::OnInlineDisposition(
// Inline web contents row.
grid_layout->StartRow(0, 1);
+ TabContentsContainer* tab_contents_container = new TabContentsContainer;
grid_layout->AddView(tab_contents_container, 1, 1, GridLayout::CENTER,
GridLayout::CENTER, kDialogMinWidth, 140);
// The contents can only be changed after the child is added to view
// hierarchy.
tab_contents_container->ChangeWebContents(web_contents);
+ contents_->Layout();
+ SizeToContents();
+ displaying_web_contents_ = true;
+}
+
+void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) {
+ if (model->GetInstalledServiceCount() == 0) {
+ suggestions_label_->SetText(l10n_util::GetStringUTF16(
+ IDS_INTENT_PICKER_GET_MORE_SERVICES_NONE_INSTALLED));
+ } else {
+ suggestions_label_->SetText(
+ l10n_util::GetStringUTF16(IDS_INTENT_PICKER_GET_MORE_SERVICES));
+ }
+
+ service_buttons_->Update();
+ extensions_->Update();
+ contents_->Layout();
+ SizeToContents();
+}
+
+void WebIntentPickerViews::OnFaviconChanged(
+ WebIntentPickerModel* model, size_t index) {
+ service_buttons_->Update();
+ contents_->Layout();
+ SizeToContents();
+}
+void WebIntentPickerViews::OnExtensionIconChanged(
+ WebIntentPickerModel* model,
+ const string16& extension_id) {
+ extensions_->Update();
contents_->Layout();
SizeToContents();
}
+void WebIntentPickerViews::OnInlineDisposition(
+ WebIntentPickerModel* model, const GURL& url) {
+ WebContents* web_contents = WebContents::Create(
+ browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL);
+ inline_disposition_delegate_.reset(
+ new WebIntentInlineDispositionDelegate(this));
+ web_contents->SetDelegate(inline_disposition_delegate_.get());
+
+ const WebIntentPickerModel::InstalledService* service =
+ model->GetInstalledServiceWithURL(url);
+ DCHECK(service);
+
+ // Must call this immediately after WebContents creation to avoid race
+ // with load.
+ delegate_->OnInlineDispositionWebContentsCreated(web_contents);
+ web_contents->GetController().LoadURL(
+ url,
+ content::Referrer(),
+ content::PAGE_TRANSITION_START_PAGE,
+ std::string());
+
+ // Disable all buttons and show throbber.
+ service_buttons_->SetEnabled(false);
+ service_buttons_->StartThrobber(url);
+ extensions_->SetEnabled(false);
+ more_suggestions_link_->SetEnabled(false);
+ contents_->Layout();
+}
+
void WebIntentPickerViews::OnServiceButtonClicked(
const WebIntentPickerModel::InstalledService& service) {
delegate_->OnServiceChosen(service.url, service.disposition);
« no previous file with comments | « chrome/browser/ui/intents/web_intent_picker.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698