diff options
author | kuan@chromium.org <kuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-29 16:41:53 +0000 |
---|---|---|
committer | kuan@chromium.org <kuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-29 16:41:53 +0000 |
commit | 8db841ac0528a7eba71e89260526da9ba33dbb54 (patch) | |
tree | 79501d52aa828b2bbaf87e91064f978851d702d2 /chrome/browser/views/infobars/translate_infobars.cc | |
parent | 89e29d25efa776ed1f564e576d764fd3e9ddecfc (diff) | |
download | chromium_src-8db841ac0528a7eba71e89260526da9ba33dbb54.zip chromium_src-8db841ac0528a7eba71e89260526da9ba33dbb54.tar.gz chromium_src-8db841ac0528a7eba71e89260526da9ba33dbb54.tar.bz2 |
implement error state for translate infobar
- this cl implements the UI on Windows and the partial backend of IPC messaging to include error type
- implement error state
- add translate error types
- use a structure as details for IPC messaging between render view and browser so as to include error type (was using std::pair)
- translate delegate handles error state and provides mapping to error messages
- infobar handles visual error states
- modify background painting to handle normal and error backgrounds, and animation of cross-fading between the 2 backgrounds
- infobar now stores state (and translation_pending flag) that it's currently displaying to user, instead of just relying on TransateInfoBarDelegate's
- if infobar receives PAGE_TRANSLAED notification before delegate does (possible because order is not fixed), delegate's state won't be updated to be used by infobar.
- after all the observers have received the notification, both infobar and delegate will end up with matching states, so there's no worries of out-of-sync.
- update unittests accordingly
- update mac and linux code accordingly to make build pass
- jay will implement the remaining backend to pass actual translate error types to the IPC message (tracked by bug 37778)
BUG=38548
TEST=none yet, until bug 37778 is also fixed.
Review URL: http://codereview.chromium.org/1321003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42953 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views/infobars/translate_infobars.cc')
-rw-r--r-- | chrome/browser/views/infobars/translate_infobars.cc | 257 |
1 files changed, 214 insertions, 43 deletions
diff --git a/chrome/browser/views/infobars/translate_infobars.cc b/chrome/browser/views/infobars/translate_infobars.cc index 60e0f62..040642e 100644 --- a/chrome/browser/views/infobars/translate_infobars.cc +++ b/chrome/browser/views/infobars/translate_infobars.cc @@ -9,12 +9,14 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" +#include "app/slide_animation.h" #include "base/utf_string_conversions.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/common/notification_service.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/translate/languages_menu_model.h" #include "chrome/browser/translate/options_menu_model.h" +#include "chrome/browser/translate/page_translated_details.h" #include "gfx/canvas.h" #include "grit/app_resources.h" #include "grit/generated_resources.h" @@ -234,15 +236,34 @@ bool TranslateTextButton::OnMousePressed(const views::MouseEvent& e) { TranslateInfoBar::TranslateInfoBar(TranslateInfoBarDelegate* delegate) : InfoBar(delegate), + state_(TranslateInfoBarDelegate::kTranslateNone), + translation_pending_(false), label_1_(NULL), label_2_(NULL), label_3_(NULL), translating_label_(NULL), + error_label_(NULL), accept_button_(NULL), deny_button_(NULL), target_language_menu_button_(NULL), revert_button_(NULL), + retry_button_(NULL), swapped_language_placeholders_(false) { + // Clear background set in base class InfoBarBackground, so that we can + // handle special background requirements for translate infobar. + set_background(NULL); + + // Initialize backgrounds. + normal_background_.reset( + new InfoBarBackground(InfoBarDelegate::PAGE_ACTION_TYPE)); + error_background_.reset( + new InfoBarBackground(InfoBarDelegate::ERROR_TYPE)); + + // Initialize slide animation for transitioning to and from error state. + error_animation_.reset(new SlideAnimation(this)); + error_animation_->SetTweenType(SlideAnimation::NONE); + error_animation_->SetSlideDuration(500); + // Initialize icon. icon_ = new views::ImageView; SkBitmap* image = delegate->GetIcon(); @@ -263,7 +284,8 @@ TranslateInfoBar::TranslateInfoBar(TranslateInfoBarDelegate* delegate) AddChildView(options_menu_button_); // Create state-dependent controls. - UpdateState(GetDelegate()->state()); + UpdateState(GetDelegate()->state(), GetDelegate()->translation_pending(), + GetDelegate()->error_type()); // Register for PAGE_TRANSLATED notification. notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, @@ -277,10 +299,17 @@ TranslateInfoBar::~TranslateInfoBar() { } void TranslateInfoBar::UpdateState( - TranslateInfoBarDelegate::TranslateState new_state) { + TranslateInfoBarDelegate::TranslateState new_state, + bool new_translation_pending, TranslateErrors::Type error_type) { + if (state_ == new_state && translation_pending_ == new_translation_pending) + return; + + TranslateInfoBarDelegate::TranslateState old_state = state_; + state_ = new_state; + translation_pending_ = new_translation_pending; + // Create and initialize state-dependent controls if necessary. - bool translation_pending = GetDelegate()->translation_pending(); - switch (new_state) { + switch (state_) { case TranslateInfoBarDelegate::kAfterTranslate: if (!target_language_menu_button_) { CreateLabels(); @@ -313,33 +342,85 @@ void TranslateInfoBar::UpdateState( } break; + case TranslateInfoBarDelegate::kTranslateError: { + string16 error_message_utf16 = GetDelegate()->GetErrorMessage(error_type); + std::wstring error_message = UTF16ToWideHack(error_message_utf16); + if (error_label_) { + error_label_->SetText(error_message); + } else { + error_label_ = CreateLabel(error_message); + AddChildView(error_label_); + } + if (!retry_button_) { + retry_button_ = new TranslateTextButton(this, + IDS_TRANSLATE_INFOBAR_RETRY); + AddChildView(retry_button_); + } + break; + } + default: NOTREACHED() << "Invalid translate state change"; break; } // If translation is pending, create "Translating..." label. - if (translation_pending && !translating_label_) { + if (translation_pending_ && !translating_label_) { translating_label_ = CreateLabel( l10n_util::GetString(IDS_TRANSLATE_INFOBAR_TRANSLATING)); AddChildView(translating_label_); } - // Determine visibility of state-dependent controls. + // Determine visibility of controls. + if (label_1_) + label_1_->SetVisible( + state_ != TranslateInfoBarDelegate::kTranslateError); + if (label_2_) + label_2_->SetVisible( + state_ != TranslateInfoBarDelegate::kTranslateError); + if (label_3_ && !label_3_->GetText().empty()) + label_3_->SetVisible( + state_ != TranslateInfoBarDelegate::kTranslateError); if (accept_button_) - accept_button_->SetVisible(!translation_pending && - new_state == TranslateInfoBarDelegate::kBeforeTranslate); + accept_button_->SetVisible(!translation_pending_ && + state_ == TranslateInfoBarDelegate::kBeforeTranslate); if (deny_button_) - deny_button_->SetVisible(!translation_pending && - new_state == TranslateInfoBarDelegate::kBeforeTranslate); + deny_button_->SetVisible(!translation_pending_ && + state_ == TranslateInfoBarDelegate::kBeforeTranslate); if (target_language_menu_button_) target_language_menu_button_->SetVisible( - new_state == TranslateInfoBarDelegate::kAfterTranslate); + state_ == TranslateInfoBarDelegate::kAfterTranslate); if (revert_button_) - revert_button_->SetVisible(!translation_pending && - new_state == TranslateInfoBarDelegate::kAfterTranslate); + revert_button_->SetVisible(!translation_pending_ && + state_ == TranslateInfoBarDelegate::kAfterTranslate); if (translating_label_) - translating_label_->SetVisible(translation_pending); + translating_label_->SetVisible(translation_pending_); + if (error_label_) + error_label_->SetVisible(!translation_pending_ && + state_ == TranslateInfoBarDelegate::kTranslateError); + if (retry_button_) + retry_button_->SetVisible(!translation_pending_ && + state_ == TranslateInfoBarDelegate::kTranslateError); + if (options_menu_button_) + options_menu_button_->SetVisible( + state_ != TranslateInfoBarDelegate::kTranslateError); + if (original_language_menu_button_) + original_language_menu_button_->SetVisible( + state_ != TranslateInfoBarDelegate::kTranslateError); + if (target_language_menu_button_) + target_language_menu_button_->SetVisible( + state_ != TranslateInfoBarDelegate::kTranslateError); + + // If background should change per state, trigger animation of transition + // accordingly. + if (old_state != TranslateInfoBarDelegate::kTranslateError && + state_ == TranslateInfoBarDelegate::kTranslateError) + error_animation_->Show(); // Transition to error state. + else if (old_state == TranslateInfoBarDelegate::kTranslateError && + state_ != TranslateInfoBarDelegate::kTranslateError) + error_animation_->Hide(); // Transition from error state. + else + error_animation_->Stop(); // No transition. // Trigger layout and repaint. Layout(); @@ -357,19 +438,45 @@ void TranslateInfoBar::Layout() { icon_->SetBounds(InfoBar::kHorizontalPadding, InfoBar::OffsetY(this, icon_ps), icon_ps.width(), icon_ps.height()); + // Check if translation is pending. + gfx::Size translating_ps; + if (translation_pending_) + translating_ps = translating_label_->GetPreferredSize(); + int translating_width = translating_ps.width(); + + // Handle error state. + if (state_ == TranslateInfoBarDelegate::kTranslateError) { + int available_text_width = std::max(GetAvailableWidth(), 0); + if (translation_pending_) { // Layout "Translating..." label. + translating_label_->SetBounds(icon_->bounds().right() + + InfoBar::kIconLabelSpacing, InfoBar::OffsetY(this, translating_ps), + std::min(translating_width, available_text_width), + translating_ps.height()); + } else { // Layout error label and retry button. + gfx::Size error_ps = error_label_->GetPreferredSize(); + error_label_->SetBounds(icon_->bounds().right() + + InfoBar::kIconLabelSpacing, InfoBar::OffsetY(this, error_ps), + std::min(error_ps.width(), available_text_width), error_ps.height()); + gfx::Size retry_ps = retry_button_->GetPreferredSize(); + retry_button_->SetBounds(error_label_->bounds().right() + + InfoBar::kEndOfLabelSpacing, InfoBar::OffsetY(this, retry_ps), + retry_ps.width(), retry_ps.height()); + } + return; + } + + // Handle normal states. // Layout the options menu button on right of bar. int available_width = InfoBar::GetAvailableWidth(); gfx::Size options_ps = options_menu_button_->GetPreferredSize(); options_menu_button_->SetBounds(available_width - options_ps.width(), OffsetY(this, options_ps), options_ps.width(), options_ps.height()); - TranslateInfoBarDelegate::TranslateState state = GetDelegate()->state(); - // Layout the controls between icon and options i.e. labels, original language // menu button, and if available, target language menu button. views::MenuButton* button1 = original_language_menu_button_; views::MenuButton* button2 = - (state == TranslateInfoBarDelegate::kAfterTranslate ? + (state_ == TranslateInfoBarDelegate::kAfterTranslate ? target_language_menu_button_ : NULL); if (button2 && swapped_language_placeholders_) { button1 = button2; @@ -380,16 +487,11 @@ void TranslateInfoBar::Layout() { gfx::Size label1_ps = label_1_->GetPreferredSize(); gfx::Size label2_ps = label_2_->GetPreferredSize(); gfx::Size label3_ps; - gfx::Size translating_ps; if (label_3_) label3_ps = label_3_->GetPreferredSize(); - bool translation_pending = GetDelegate()->translation_pending(); - if (translation_pending) - translating_ps = translating_label_->GetPreferredSize(); int text1_width = label1_ps.width(); int text2_width = label2_ps.width(); int text3_width = label3_ps.width(); - int translating_width = translating_ps.width(); int total_text_width = text1_width + text2_width + text3_width + translating_width; if (total_text_width > available_text_width) { @@ -431,7 +533,7 @@ void TranslateInfoBar::Layout() { } // If no translation is pending, layout revert button. - if (!translation_pending && revert_button_) { + if (!translation_pending_ && revert_button_) { gfx::Size revert_ps = revert_button_->GetPreferredSize(); revert_button_->SetBounds(prev_right + InfoBar::kEndOfLabelSpacing, OffsetY(this, revert_ps), revert_ps.width(), revert_ps.height()); @@ -440,8 +542,8 @@ void TranslateInfoBar::Layout() { // If translate state is kBeforeTranslate with no pending translation, // layout accept and deny butons. - if (state == TranslateInfoBarDelegate::kBeforeTranslate && - !translation_pending) { + if (state_ == TranslateInfoBarDelegate::kBeforeTranslate && + !translation_pending_) { gfx::Size accept_ps = accept_button_->GetPreferredSize(); accept_button_->SetBounds(prev_right + InfoBar::kEndOfLabelSpacing, OffsetY(this, accept_ps), accept_ps.width(), accept_ps.height()); @@ -452,7 +554,7 @@ void TranslateInfoBar::Layout() { } // If translation is pending, layout "Translating..." label. - if (translation_pending) { + if (translation_pending_) { translating_label_->SetBounds( prev_right + InfoBar::kEndOfLabelSpacing, InfoBar::OffsetY(this, translating_ps), @@ -460,10 +562,47 @@ void TranslateInfoBar::Layout() { } } +void TranslateInfoBar::PaintBackground(gfx::Canvas* canvas) { + // If we're not animating, simply paint background for current state. + if (!error_animation_->IsAnimating()) { + GetBackground(state_)->Paint(canvas, this); + return; + } + + // Animate cross-fading between error and normal states; + // since all normal states use the same background, just use kAfterTranslate. + if (error_animation_->IsShowing()) { // Transitioning to error state. + // Fade out normal state. + FadeBackground(canvas, 1.0 - error_animation_->GetCurrentValue(), + TranslateInfoBarDelegate::kAfterTranslate); + // Fade in error state. + FadeBackground(canvas, error_animation_->GetCurrentValue(), + TranslateInfoBarDelegate::kTranslateError); + } else { // Transitioning from error state. + // Fade out error state. + FadeBackground(canvas, error_animation_->GetCurrentValue(), + TranslateInfoBarDelegate::kTranslateError); + // Fade in normal state. + FadeBackground(canvas, 1.0 - error_animation_->GetCurrentValue(), + TranslateInfoBarDelegate::kAfterTranslate); + } +} + // TranslateInfoBar, InfoBar overrides: ---------------------------------------- int TranslateInfoBar::GetAvailableWidth() const { - gfx::Size icon_ps = icon_->GetPreferredSize(); + int available_width = InfoBar::GetAvailableWidth() - + icon_->bounds().right() - InfoBar::kIconLabelSpacing; + + // Handle the simplest state - error state, with the least no. of controls. + if (state_ == TranslateInfoBarDelegate::kTranslateError) { + if (!translation_pending_) + available_width -= InfoBar::kEndOfLabelSpacing + + retry_button_->bounds().width(); + return available_width; + } + + // Handle the normal states, which have more controls. // For language button, reserve spacing before and after it. gfx::Size language_ps = original_language_menu_button_->GetPreferredSize(); int language_spacing = InfoBar::kButtonInLabelSpacing + @@ -480,17 +619,14 @@ int TranslateInfoBar::GetAvailableWidth() const { (label_3_ ? InfoBar::kButtonInLabelSpacing + InfoBar::kEndOfLabelSpacing : (target_language_menu_button_ ? InfoBar::kEndOfLabelSpacing : InfoBar::kButtonButtonSpacing)); - int available_width = (InfoBar::GetAvailableWidth() - - options_ps.width() - options_spacing - - language_ps.width() - language_spacing - - icon_->bounds().right() - InfoBar::kIconLabelSpacing); - TranslateInfoBarDelegate::TranslateState state = GetDelegate()->state(); - if (state == TranslateInfoBarDelegate::kBeforeTranslate) { + available_width -= options_ps.width() + options_spacing + + language_ps.width() + language_spacing; + if (state_ == TranslateInfoBarDelegate::kBeforeTranslate) { gfx::Size accept_ps = accept_button_->GetPreferredSize(); gfx::Size deny_ps = deny_button_->GetPreferredSize(); available_width -= accept_ps.width() + InfoBar::kEndOfLabelSpacing + deny_ps.width() + InfoBar::kButtonButtonSpacing; - } else if (state == TranslateInfoBarDelegate::kAfterTranslate) { + } else if (state_ == TranslateInfoBarDelegate::kAfterTranslate) { gfx::Size target_ps = target_language_menu_button_->GetPreferredSize(); available_width -= target_ps.width() + InfoBar::kButtonInLabelSpacing; } @@ -511,7 +647,7 @@ void TranslateInfoBar::RunMenu(views::View* source, const gfx::Point& pt) { } case kMenuIDOriginalLanguage: { - if (!translating_label_ || !translating_label_->IsVisible()) { + if (!translation_pending_) { if (!original_language_menu_model_.get()) { original_language_menu_model_.reset( new LanguagesMenuModel(this, GetDelegate(), true)); @@ -527,7 +663,7 @@ void TranslateInfoBar::RunMenu(views::View* source, const gfx::Point& pt) { } case kMenuIDTargetLanguage: { - if (!translating_label_ || !translating_label_->IsVisible()) { + if (!translation_pending_) { if (!target_language_menu_model_.get()) { target_language_menu_model_.reset( new LanguagesMenuModel(this, GetDelegate(), false)); @@ -626,9 +762,10 @@ void TranslateInfoBar::ExecuteCommand(int command_id) { void TranslateInfoBar::ButtonPressed( views::Button* sender, const views::Event& event) { - if (sender == accept_button_) { + if (sender == accept_button_ || sender == retry_button_) { GetDelegate()->Translate(); - UpdateState(GetDelegate()->state()); + UpdateState(GetDelegate()->state(), GetDelegate()->translation_pending(), + GetDelegate()->error_type()); UMA_HISTOGRAM_COUNTS("Translate.Translate", 1); } else if (sender == deny_button_) { GetDelegate()->TranslationDeclined(); @@ -641,6 +778,15 @@ void TranslateInfoBar::ButtonPressed( } } +// TranslateInfoBar, AnimationDelegate overrides: ------------------------------ + +void TranslateInfoBar::AnimationProgressed(const Animation* animation) { + if (animation == error_animation_.get()) + SchedulePaint(); + else + InfoBar::AnimationProgressed(animation); +} + // TranslateInfoBar, NotificationObserver overrides: --------------------------- void TranslateInfoBar::Observe(NotificationType type, @@ -650,7 +796,12 @@ void TranslateInfoBar::Observe(NotificationType type, TabContents* tab = Source<TabContents>(source).ptr(); if (tab != GetDelegate()->tab_contents()) return; - UpdateState(TranslateInfoBarDelegate::kAfterTranslate); + PageTranslatedDetails* page_translated_details = + Details<PageTranslatedDetails>(details).ptr(); + UpdateState((page_translated_details->error_type == TranslateErrors::NONE ? + TranslateInfoBarDelegate::kAfterTranslate : + TranslateInfoBarDelegate::kTranslateError), false, + page_translated_details->error_type); } // TranslateInfoBar, private: -------------------------------------------------- @@ -659,7 +810,7 @@ void TranslateInfoBar::CreateLabels() { // Determine text for labels. std::vector<size_t> offsets; string16 message_text_utf16; - GetDelegate()->GetMessageText(&message_text_utf16, &offsets, + GetDelegate()->GetMessageText(state_, &message_text_utf16, &offsets, &swapped_language_placeholders_); std::wstring message_text = UTF16ToWideHack(message_text_utf16); @@ -691,6 +842,8 @@ void TranslateInfoBar::CreateLabels() { label_3_ = CreateLabel(label_3); AddChildView(label_3_); } + } else if (label_3_) { + label_3_->SetText(std::wstring()); } } @@ -772,21 +925,39 @@ void TranslateInfoBar::OnLanguageModified(views::MenuButton* menu_button, // Selecting an item from the "from language" menu in the before translate // phase shouldn't trigger translation - http://crbug.com/36666 - if (GetDelegate()->state() == TranslateInfoBarDelegate::kAfterTranslate) { + if (state_ == TranslateInfoBarDelegate::kAfterTranslate) { GetDelegate()->Translate(); - UpdateState(GetDelegate()->state()); + UpdateState(GetDelegate()->state(), GetDelegate()->translation_pending(), + GetDelegate()->error_type()); } Layout(); SchedulePaint(); } +void TranslateInfoBar::FadeBackground(gfx::Canvas* canvas, + double animation_value, TranslateInfoBarDelegate::TranslateState state) { + // Draw background into an offscreen buffer with alpha value per animation + // value, then blend it back into the current canvas. + canvas->saveLayerAlpha(NULL, static_cast<int>(animation_value * 255), + SkCanvas::kARGB_NoClipLayer_SaveFlag); + canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); + GetBackground(state)->Paint(canvas, this); + canvas->restore(); +} + inline TranslateInfoBarDelegate* TranslateInfoBar::GetDelegate() const { return static_cast<TranslateInfoBarDelegate*>(delegate()); } +inline InfoBarBackground* TranslateInfoBar::GetBackground( + TranslateInfoBarDelegate::TranslateState state) const { + return (state == TranslateInfoBarDelegate::kTranslateError ? + error_background_.get() : normal_background_.get()); +} + inline int TranslateInfoBar::GetSpacingAfterFirstLanguageButton() const { - return (GetDelegate()->state() == TranslateInfoBarDelegate::kAfterTranslate ? + return (state_ == TranslateInfoBarDelegate::kAfterTranslate ? kButtonInLabelSpacing : 10); } |