diff options
author | feldstein@chromium.org <feldstein@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-23 21:12:27 +0000 |
---|---|---|
committer | feldstein@chromium.org <feldstein@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-23 21:12:27 +0000 |
commit | 52efff2f9251cf276eb5453a2a6be79b1669207a (patch) | |
tree | 6906898fe221fa13cbfa59c57912b33fb41305ff | |
parent | 1e9b90157eb384c807a5a34f2662fabdf716b4df (diff) | |
download | chromium_src-52efff2f9251cf276eb5453a2a6be79b1669207a.zip chromium_src-52efff2f9251cf276eb5453a2a6be79b1669207a.tar.gz chromium_src-52efff2f9251cf276eb5453a2a6be79b1669207a.tar.bz2 |
Refactor the translate infobars on mac to match the new windows code.
Breaks it up into 4 different classes instead of 1 class full of switches and if
statements.
BUG=none
TEST=unit_tests.TranslationInfoBarTest
Review URL: http://codereview.chromium.org/2815013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50641 0039d316-1c4b-4281-b951-d872f2087c98
16 files changed, 1014 insertions, 1162 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index 29016d6..947f805 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -56,7 +56,7 @@ #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/search_engines/template_url_prepopulate_data.h" #include "chrome/browser/shell_integration.h" -#if !defined(OS_WIN) +#if !defined(OS_WIN) && !defined(OS_MACOSX) #include "chrome/browser/translate/translate_manager.h" #else #include "chrome/browser/translate/translate_manager2.h" @@ -1210,7 +1210,7 @@ int BrowserMain(const MainFunctionParams& parameters) { return ResultCodes::MACHINE_LEVEL_INSTALL_EXISTS; // Create the TranslateManager singleton. -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) Singleton<TranslateManager2>::get(); #else Singleton<TranslateManager>::get(); diff --git a/chrome/browser/cocoa/translate/after_translate_infobar_controller.h b/chrome/browser/cocoa/translate/after_translate_infobar_controller.h new file mode 100644 index 0000000..ba946c9 --- /dev/null +++ b/chrome/browser/cocoa/translate/after_translate_infobar_controller.h @@ -0,0 +1,11 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/translate/translate_infobar_base.h" + +@interface AfterTranslateInfobarController : TranslateInfoBarControllerBase { + bool swappedLanugageButtons_; +} + +@end diff --git a/chrome/browser/cocoa/translate/after_translate_infobar_controller.mm b/chrome/browser/cocoa/translate/after_translate_infobar_controller.mm new file mode 100644 index 0000000..864898c --- /dev/null +++ b/chrome/browser/cocoa/translate/after_translate_infobar_controller.mm @@ -0,0 +1,59 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/cocoa/translate/after_translate_infobar_controller.h" +#include "base/sys_string_conversions.h" + +using TranslateInfoBarUtilities::MoveControl; + +@implementation AfterTranslateInfobarController + +- (void)loadLabelText { + std::vector<string16> strings; + TranslateInfoBarDelegate2::GetAfterTranslateStrings( + &strings, &swappedLanugageButtons_); + DCHECK(strings.size() == 3U); + NSString* string1 = base::SysUTF16ToNSString(strings[0]); + NSString* string2 = base::SysUTF16ToNSString(strings[1]); + NSString* string3 = base::SysUTF16ToNSString(strings[2]); + + [label1_ setStringValue:string1]; + [label2_ setStringValue:string2]; + [label3_ setStringValue:string3]; +} + +- (void)layout { + [self removeOkCancelButtons]; + [optionsPopUp_ setHidden:NO]; + NSView* firstPopup = fromLanguagePopUp_; + NSView* lastPopup = toLanguagePopUp_; + if (swappedLanugageButtons_) { + firstPopup = toLanguagePopUp_; + lastPopup = fromLanguagePopUp_; + } + NSView* lastControl = lastPopup; + + MoveControl(label1_, firstPopup, 0, true); + MoveControl(firstPopup, label2_, 0, true); + MoveControl(label2_, lastPopup, 0, true); + MoveControl(lastPopup, label3_, 0, true); + lastControl = label3_; + + MoveControl(lastControl, showOriginalButton_, spaceBetweenControls_ * 2, + true); +} + +- (NSArray*)visibleControls { + return [NSArray arrayWithObjects:label1_.get(), fromLanguagePopUp_.get(), + label2_.get(), toLanguagePopUp_.get(), label3_.get(), + showOriginalButton_.get(), nil]; +} + +- (bool)verifyLayout { + if ([optionsPopUp_ isHidden]) + return false; + return [super verifyLayout]; +} + +@end diff --git a/chrome/browser/cocoa/translate/before_translate_infobar_controller.h b/chrome/browser/cocoa/translate/before_translate_infobar_controller.h new file mode 100644 index 0000000..0ff8cc8 --- /dev/null +++ b/chrome/browser/cocoa/translate/before_translate_infobar_controller.h @@ -0,0 +1,11 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/translate/translate_infobar_base.h" + +@interface BeforeTranslateInfobarController : TranslateInfoBarControllerBase { + +} + +@end diff --git a/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm b/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm new file mode 100644 index 0000000..d2d418d --- /dev/null +++ b/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm @@ -0,0 +1,47 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/cocoa/translate/before_translate_infobar_controller.h" + +#include "app/l10n_util.h" +#include "base/sys_string_conversions.h" +#include "grit/generated_resources.h" + +using TranslateInfoBarUtilities::MoveControl; + +@implementation BeforeTranslateInfobarController + +- (void)layout { + [optionsPopUp_ setHidden:NO]; + MoveControl(label1_, fromLanguagePopUp_, 0, true); + MoveControl(fromLanguagePopUp_, label2_, 0, true); + MoveControl(label2_, okButton_, spaceBetweenControls_, true); + MoveControl(okButton_, cancelButton_, spaceBetweenControls_, true); +} + +- (void)loadLabelText { + size_t offset = 0; + string16 text = + l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE, + string16(), &offset); + NSString* string1 = base::SysUTF16ToNSString(text.substr(0, offset)); + NSString* string2 = base::SysUTF16ToNSString(text.substr(offset)); + [label1_ setStringValue:string1]; + [label2_ setStringValue:string2]; + [label3_ setStringValue:@""]; +} + +- (NSArray*)visibleControls { + return [NSArray arrayWithObjects:label1_.get(), fromLanguagePopUp_.get(), + label2_.get(), okButton_, cancelButton_, nil]; + +} + +- (bool)verifyLayout { + if ([optionsPopUp_ isHidden]) + return false; + return [super verifyLayout]; +} + +@end diff --git a/chrome/browser/cocoa/translate/translate_infobar_base.h b/chrome/browser/cocoa/translate/translate_infobar_base.h new file mode 100644 index 0000000..e475be9 --- /dev/null +++ b/chrome/browser/cocoa/translate/translate_infobar_base.h @@ -0,0 +1,143 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_COCOA_TRANSLATE_INFOBAR_BASE_H_ +#define CHROME_BROWSER_COCOA_TRANSLATE_INFOBAR_BASE_H_ + +#import <Cocoa/Cocoa.h> +#import "chrome/browser/cocoa/infobar_controller.h" + +#import "base/cocoa_protocols_mac.h" +#import "base/scoped_nsobject.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/translate/languages_menu_model2.h" +#include "chrome/browser/translate/options_menu_model2.h" +#include "chrome/browser/translate/translate_infobar_delegate2.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/translate_errors.h" + +class TranslateInfoBarMenuModel; + +#pragma mark TranslateInfoBarUtilities helper functions. +namespace TranslateInfoBarUtilities { + +// Move the |toMove| view |spacing| pixels before/after the |anchor| view. +// |after| signifies the side of |anchor| on which to place |toMove|. +void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after); + +// Vertically center |toMove| in its container. +void VerticallyCenterView(NSView *toMove); +// Check that the control |before| is ordered visually before the |after| +// control. +// Also, check that there is space between them. +bool VerifyControlOrderAndSpacing(id before, id after); + +// Creates a label control in the style we need for the translate infobar's +// labels within |bounds|. +NSTextField* CreateLabel(NSRect bounds); + +// Adds an item with the specified properties to |menu|. +void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title, + int tag, bool enabled, bool checked); + +} // namespace + +// The base class for the three translate infobars. This class does all of the +// heavy UI lifting, while deferring to the subclass to tell it what views +// should be shown and where. Subclasses need to implement: +// - (void)layout; +// - (void)loadLabelText; +// - (void)visibleControls; +// - (bool)verifyLayout; // For testing. +@interface TranslateInfoBarControllerBase : InfoBarController<NSMenuDelegate> { + @protected + scoped_nsobject<NSTextField> label1_; + scoped_nsobject<NSTextField> label2_; + scoped_nsobject<NSTextField> label3_; + scoped_nsobject<NSPopUpButton> fromLanguagePopUp_; + scoped_nsobject<NSPopUpButton> toLanguagePopUp_; + scoped_nsobject<NSPopUpButton> optionsPopUp_; + scoped_nsobject<NSButton> showOriginalButton_; + scoped_nsobject<NSButton> tryAgainButton_; + + // In the current locale, are the "from" and "to" language popup menu + // flipped from what they'd appear in English. + bool swappedLanguagePlaceholders_; + + // Space between controls in pixels - read from the NIB. + CGFloat spaceBetweenControls_; + + scoped_ptr<LanguagesMenuModel2> originalLanguageMenuModel_; + scoped_ptr<LanguagesMenuModel2> targetLanguageMenuModel_; + scoped_ptr<OptionsMenuModel2> optionsMenuModel_; +} + +// Returns the delegate as a TranslateInfoBarDelegate. +- (TranslateInfoBarDelegate2*)delegate; + +// Called when the "Show Original" button is pressed. +- (IBAction)showOriginal:(id)sender; + +@end + +@interface TranslateInfoBarControllerBase (ProtectedAPI) + +// Move all the currently visible views into the correct place for the +// current mode. +// Must be implemented by the subclass. +- (void)layout; + +// Loads the text for the 3 labels. There is only one message, but since +// it has controls separating parts of it, it is separated into 3 separate +// labels. +// Must be implemented by the subclass. +- (void)loadLabelText; + +// Returns the controls that are visible in the subclasses infobar. The +// default implementation returns an empty array. The controls should +// be returned in the order they are displayed, otherwise the layout test +// will fail. +// Must be implemented by the subclass. +- (NSArray*)visibleControls; + +// Shows the array of controls provided by the subclass. +- (void)showVisibleControls:(NSArray*)visibleControls; + +// Hides the OK and Cancel buttons. +- (void)removeOkCancelButtons; + +// Called when the source or target language selection changes in a menu. +// |newLanguageIdx| is the index of the newly selected item in the appropriate +// menu. +- (void)sourceLanguageModified:(NSInteger)newLanguageIdx; +- (void)targetLanguageModified:(NSInteger)newLanguageIdx; + +// Called when an item in one of the toolbar's language or options +// menus is selected. +- (void)languageMenuChanged:(id)item; +- (void)optionsMenuChanged:(id)item; + +// Teardown and rebuild the options menu. +- (void)rebuildOptionsMenu; + +@end // TranslateInfoBarControllerBase (ProtectedAPI) + +#pragma mark TestingAPI + +@interface TranslateInfoBarControllerBase (TestingAPI) + +// Verifies that the layout of the infobar is correct. +// Must be implmented by the subclass. +- (bool)verifyLayout; + +// Returns the underlying options menu. +- (NSMenu*)optionsMenu; + +// Returns the "try again" button. +- (NSButton*)tryAgainButton; + +@end // TranslateInfoBarControllerBase (TestingAPI) + + +#endif // CHROME_BROWSER_COCOA_TRANSLATE_INFOBAR_BASE_H_ diff --git a/chrome/browser/cocoa/translate/translate_infobar_base.mm b/chrome/browser/cocoa/translate/translate_infobar_base.mm new file mode 100644 index 0000000..f93a733 --- /dev/null +++ b/chrome/browser/cocoa/translate/translate_infobar_base.mm @@ -0,0 +1,579 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> +#import "chrome/browser/cocoa/translate/translate_infobar_base.h" + +#include "app/l10n_util.h" +#include "base/histogram.h" +#include "base/logging.h" // for NOTREACHED() +#include "base/mac_util.h" +#include "base/sys_string_conversions.h" +#include "chrome/app/chrome_dll_resource.h" +#import "chrome/browser/cocoa/hover_close_button.h" +#include "chrome/browser/cocoa/infobar.h" +#import "chrome/browser/cocoa/infobar_controller.h" +#import "chrome/browser/cocoa/infobar_gradient_view.h" +#include "chrome/browser/cocoa/translate/after_translate_infobar_controller.h" +#import "chrome/browser/cocoa/translate/before_translate_infobar_controller.h" +#include "chrome/browser/cocoa/translate/translate_message_infobar_controller.h" +#include "chrome/browser/translate/translate_infobars_delegates.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" + +using TranslateInfoBarUtilities::MoveControl; +using TranslateInfoBarUtilities::VerticallyCenterView; +using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing; +using TranslateInfoBarUtilities::CreateLabel; +using TranslateInfoBarUtilities::AddMenuItem; + +// Colors for translate infobar gradient background. +const int kGreyTopColor[] = {0xC0, 0xC0, 0xC0}; +const int kGreyBottomColor[] = {0xCC, 0xCC, 0xCC}; + +#pragma mark TranslateInfoBarUtilities helper functions. + +namespace TranslateInfoBarUtilities { + +// Move the |toMove| view |spacing| pixels before/after the |anchor| view. +// |after| signifies the side of |anchor| on which to place |toMove|. +void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after) { + NSRect anchorFrame = [anchor frame]; + NSRect toMoveFrame = [toMove frame]; + + // At the time of this writing, OS X doesn't natively support BiDi UIs, but + // it doesn't hurt to be forward looking. + bool toRight = after; + + if (toRight) { + toMoveFrame.origin.x = NSMaxX(anchorFrame) + spacing; + } else { + // Place toMove to theleft of anchor. + toMoveFrame.origin.x = NSMinX(anchorFrame) - + spacing - NSWidth(toMoveFrame); + } + [toMove setFrame:toMoveFrame]; +} + +// Check that the control |before| is ordered visually before the |after| +// control. +// Also, check that there is space between them. +bool VerifyControlOrderAndSpacing(id before, id after) { + NSRect beforeFrame = [before frame]; + NSRect afterFrame = [after frame]; + return NSMinX(afterFrame) >= NSMaxX(beforeFrame); +} + +// Vertically center |toMove| in its container. +void VerticallyCenterView(NSView *toMove) { + NSRect superViewFrame = [[toMove superview] frame]; + NSRect viewFrame = [toMove frame]; + viewFrame.origin.y = + floor((NSHeight(superViewFrame) - NSHeight(viewFrame))/2.0); + [toMove setFrame:viewFrame]; +} + +// Creates a label control in the style we need for the translate infobar's +// labels within |bounds|. +NSTextField* CreateLabel(NSRect bounds) { + NSTextField* ret = [[NSTextField alloc] initWithFrame:bounds]; + [ret setEditable:NO]; + [ret setDrawsBackground:NO]; + [ret setBordered:NO]; + return ret; +} + +// Adds an item with the specified properties to |menu|. +void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title, + int tag, bool enabled, bool checked) { + NSMenuItem* item = [[[NSMenuItem alloc] + initWithTitle:title + action:selector + keyEquivalent:@""] autorelease]; + [item setTag:tag]; + [menu addItem:item]; + [item setTarget:target]; + if (checked) + [item setState:NSOnState]; + if (!enabled) + [item setEnabled:NO]; +} + +} // namespace TranslateInfoBarUtilities + +// For compilation purposes until the linux port goes through and +// the files can be removed. +InfoBar* TranslateInfoBarDelegate::CreateInfoBar() { + NOTREACHED(); + return NULL; +} + +// TranslateInfoBarDelegate views specific method: +InfoBar* TranslateInfoBarDelegate2::CreateInfoBar() { + TranslateInfoBarControllerBase* infobar_controller = NULL; + switch (type_) { + case BEFORE_TRANSLATE: + infobar_controller = + [[BeforeTranslateInfobarController alloc] initWithDelegate:this]; + break; + case AFTER_TRANSLATE: + infobar_controller = + [[AfterTranslateInfobarController alloc] initWithDelegate:this]; + break; + case TRANSLATING: + case TRANSLATION_ERROR: + infobar_controller = + [[TranslateMessageInfobarController alloc] initWithDelegate:this]; + break; + default: + NOTREACHED(); + } + return new InfoBar(infobar_controller); +} + +@interface TranslateInfoBarControllerBase (Private) + +// Removes all controls so that layout can add in only the controls +// required. +- (void)clearAllControls; + +// Create all the various controls we need for the toolbar. +- (void)constructViews; + +// Reloads text for all labels for the current state. +- (void)loadLabelText:(TranslateErrors::Type)error; + +// Makes the infobar grey. +- (void)setInfoBarGradientColor; + +// Main function to update the toolbar graphic state and data model after +// the state has changed. +// Controls are moved around as needed and visibility changed to match the +// current state. +- (void)updateState; + +// Called when the source or target language selection changes in a menu. +// |newLanguageIdx| is the index of the newly selected item in the appropriate +// menu. +- (void)sourceLanguageModified:(NSInteger)newLanguageIdx; +- (void)targetLanguageModified:(NSInteger)newLanguageIdx; + +// Completely rebuild "from" and "to" language menus from the data model. +- (void)populateLanguageMenus; + +@end + +#pragma mark TranslateInfoBarController class + +@implementation TranslateInfoBarControllerBase + +- (id)initWithDelegate:(InfoBarDelegate*)delegate { + if ((self = [super initWithDelegate:delegate])) { + originalLanguageMenuModel_.reset( + new LanguagesMenuModel2([self delegate], + LanguagesMenuModel2::ORIGINAL)); + + targetLanguageMenuModel_.reset( + new LanguagesMenuModel2([self delegate], + LanguagesMenuModel2::TARGET)); + optionsMenuModel_.reset(new OptionsMenuModel2([self delegate])); + } + return self; +} + +- (TranslateInfoBarDelegate2*)delegate { + return reinterpret_cast<TranslateInfoBarDelegate2*>(delegate_); +} + +- (void)constructViews { + // Using a zero or very large frame causes GTMUILocalizerAndLayoutTweaker + // to not resize the view properly so we take the bounds of the first label + // which is contained in the nib. + NSRect bogusFrame = [label_ frame]; + label1_.reset(CreateLabel(bogusFrame)); + label2_.reset(CreateLabel(bogusFrame)); + label3_.reset(CreateLabel(bogusFrame)); + + optionsPopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame + pullsDown:YES]); + fromLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame + pullsDown:NO]); + toLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame + pullsDown:NO]); + showOriginalButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]); + tryAgainButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]); +} + +- (void)sourceLanguageModified:(NSInteger)newLanguageIdx { + DCHECK_GT(newLanguageIdx, -1); + if (newLanguageIdx == [self delegate]->original_language_index()) + return; + [self delegate]->SetOriginalLanguage(newLanguageIdx); + int commandId = IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + newLanguageIdx; + int newMenuIdx = [fromLanguagePopUp_ indexOfItemWithTag:commandId]; + [fromLanguagePopUp_ selectItemAtIndex:newMenuIdx]; +} + +- (void)targetLanguageModified:(NSInteger)newLanguageIdx { + DCHECK_GT(newLanguageIdx, -1); + if (newLanguageIdx == [self delegate]->target_language_index()) + return; + [self delegate]->SetTargetLanguage(newLanguageIdx); + int commandId = IDC_TRANSLATE_TARGET_LANGUAGE_BASE + newLanguageIdx; + int newMenuIdx = [toLanguagePopUp_ indexOfItemWithTag:commandId]; + [toLanguagePopUp_ selectItemAtIndex:newMenuIdx]; +} + +- (void)loadLabelText { + // Do nothing by default, should be implemented by subclasses. +} + +- (void)updateState { + [self loadLabelText]; + [self clearAllControls]; + [self showVisibleControls:[self visibleControls]]; + [self layout]; +} + +- (void)setInfoBarGradientColor { + // Use grey gradient for the infobars. + NSColor* startingColor = + [NSColor colorWithCalibratedRed:kGreyTopColor[0] / 255.0 + green:kGreyTopColor[1] / 255.0 + blue:kGreyTopColor[2] / 255.0 + alpha:1.0]; + NSColor* endingColor = + [NSColor colorWithCalibratedRed:kGreyBottomColor[0] / 255.0 + green:kGreyBottomColor[1] / 255.0 + blue:kGreyBottomColor[2] / 255.0 + alpha:1.0]; + NSGradient* translateInfoBarGradient = + [[[NSGradient alloc] initWithStartingColor:startingColor + endingColor:endingColor] autorelease]; + + [infoBarView_ setGradient:translateInfoBarGradient]; +} + +- (void)removeOkCancelButtons { + // Removing okButton_ & cancelButton_ from the view may cause them + // to be released and since we can still access them from other areas + // in the code later, we need them to be nil when this happens. + [okButton_ removeFromSuperview]; + okButton_ = nil; + [cancelButton_ removeFromSuperview]; + cancelButton_ = nil; +} + +- (void)clearAllControls { + // Step 1: remove all controls from the infobar so we have a clean slate. + NSArray *allControls = [NSArray arrayWithObjects:label2_.get(), label3_.get(), + fromLanguagePopUp_.get(), toLanguagePopUp_.get(), + showOriginalButton_.get(), tryAgainButton_.get(), nil]; + + for (NSControl* control in allControls) { + if ([control superview]) + [control removeFromSuperview]; + } +} + +- (void)showVisibleControls:(NSArray*)visibleControls { + NSRect optionsFrame = [optionsPopUp_ frame]; + for (NSControl* control in visibleControls) { + [GTMUILocalizerAndLayoutTweaker sizeToFitView:control]; + [control setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin | + NSViewMaxYMargin]; + + // Need to check if a view is already attached since |label1_| is always + // parented and we don't want to add it again. + if (![control superview]) + [infoBarView_ addSubview:control]; + + if ([control isKindOfClass:[NSButton class]]) + VerticallyCenterView(control); + + // Make "from" and "to" language popup menus the same size as the options + // menu. + // We don't autosize since some languages names are really long causing + // the toolbar to overflow. + if ([control isKindOfClass:[NSPopUpButton class]]) + [control setFrame:optionsFrame]; + } +} + +- (void)layout { + +} + +- (NSArray*)visibleControls { + return [NSArray array]; +} + +- (void) rebuildOptionsMenu { + // The options model doesn't know how to handle state transitions, so rebuild + // it each time through here. + optionsMenuModel_.reset( + new OptionsMenuModel2([self delegate])); + + [optionsPopUp_ removeAllItems]; + // Set title. + NSString* optionsLabel = + l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_OPTIONS); + [optionsPopUp_ addItemWithTitle:optionsLabel]; + + // Populate options menu. + NSMenu* optionsMenu = [optionsPopUp_ menu]; + [optionsMenu setAutoenablesItems:NO]; + for (int i = 0; i < optionsMenuModel_->GetItemCount(); ++i) { + NSString* title = base::SysUTF16ToNSString( + optionsMenuModel_->GetLabelAt(i)); + int cmd = optionsMenuModel_->GetCommandIdAt(i); + bool checked = optionsMenuModel_->IsItemCheckedAt(i); + bool enabled = optionsMenuModel_->IsEnabledAt(i); + AddMenuItem(optionsMenu, + self, + @selector(optionsMenuChanged:), + title, + cmd, + enabled, + checked); + } +} + +- (void)populateLanguageMenus { + NSMenu* originalLanguageMenu = [fromLanguagePopUp_ menu]; + [originalLanguageMenu setAutoenablesItems:NO]; + int selectedMenuIndex = 0; + int selectedLangIndex = [self delegate]->original_language_index(); + for (int i = 0; i < originalLanguageMenuModel_->GetItemCount(); ++i) { + NSString* title = base::SysUTF16ToNSString( + originalLanguageMenuModel_->GetLabelAt(i)); + int cmd = originalLanguageMenuModel_->GetCommandIdAt(i); + bool checked = (cmd == selectedLangIndex); + if (checked) + selectedMenuIndex = i; + bool enabled = originalLanguageMenuModel_->IsEnabledAt(i); + cmd += IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE; + AddMenuItem(originalLanguageMenu, + self, + @selector(languageMenuChanged:), + title, + cmd, + enabled, + checked); + } + [fromLanguagePopUp_ selectItemAtIndex:selectedMenuIndex]; + + NSMenu* targetLanguageMenu = [toLanguagePopUp_ menu]; + [targetLanguageMenu setAutoenablesItems:NO]; + selectedLangIndex = [self delegate]->target_language_index(); + for (int i = 0; i < targetLanguageMenuModel_->GetItemCount(); ++i) { + NSString* title = base::SysUTF16ToNSString( + targetLanguageMenuModel_->GetLabelAt(i)); + int cmd = targetLanguageMenuModel_->GetCommandIdAt(i); + bool checked = (cmd == selectedLangIndex); + if (checked) + selectedMenuIndex = i; + bool enabled = targetLanguageMenuModel_->IsEnabledAt(i); + cmd += IDC_TRANSLATE_TARGET_LANGUAGE_BASE; + AddMenuItem(targetLanguageMenu, + self, + @selector(languageMenuChanged:), + title, + cmd, + enabled, + checked); + } + [toLanguagePopUp_ selectItemAtIndex:selectedMenuIndex]; +} + +- (void)addAdditionalControls { + using l10n_util::GetNSString; + using l10n_util::GetNSStringWithFixup; + + // Get layout information from the NIB. + NSRect okButtonFrame = [okButton_ frame]; + NSRect cancelButtonFrame = [cancelButton_ frame]; + spaceBetweenControls_ = NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame); + + // Set infobar background color. + [self setInfoBarGradientColor]; + + // Instantiate additional controls. + [self constructViews]; + + // Set ourselves as the delegate for the options menu so we can populate it + // dynamically. + [[optionsPopUp_ menu] setDelegate:self]; + + // Replace label_ with label1_ so we get a consistent look between all the + // labels we display in the translate view. + [[label_ superview] replaceSubview:label_ with:label1_.get()]; + label_.reset(); // Now released. + + // Populate contextual menus. + [self rebuildOptionsMenu]; + [self populateLanguageMenus]; + + // Set OK & Cancel text. + [okButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_ACCEPT)]; + [cancelButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_DENY)]; + + // Set up "Show original" and "Try again" buttons. + [showOriginalButton_ setBezelStyle:NSRoundRectBezelStyle]; + [showOriginalButton_ setFrame:okButtonFrame]; + [tryAgainButton_ setBezelStyle:NSRoundRectBezelStyle]; + [tryAgainButton_ setFrame:okButtonFrame]; + + [showOriginalButton_ setTarget:self]; + [showOriginalButton_ setAction:@selector(showOriginal:)]; + [tryAgainButton_ setTarget:self]; + [tryAgainButton_ setAction:@selector(ok:)]; + + [showOriginalButton_ + setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_REVERT)]; + [tryAgainButton_ + setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_RETRY)]; + + // Add and configure controls that are visible in all modes. + [optionsPopUp_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin | + NSViewMaxYMargin]; + // Add "options" popup z-ordered below all other controls so when we + // resize the toolbar it doesn't hide them. + [infoBarView_ addSubview:optionsPopUp_ + positioned:NSWindowBelow + relativeTo:nil]; + [GTMUILocalizerAndLayoutTweaker sizeToFitView:optionsPopUp_]; + MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false); + VerticallyCenterView(optionsPopUp_); + + // Show and place GUI elements. + [self updateState]; +} + +// Called when "Translate" button is clicked. +- (IBAction)ok:(id)sender { + TranslateInfoBarDelegate2* delegate = [self delegate]; + TranslateInfoBarDelegate2::Type state = delegate->type(); + DCHECK(state == TranslateInfoBarDelegate2::BEFORE_TRANSLATE || + state == TranslateInfoBarDelegate2::TRANSLATION_ERROR); + delegate->Translate(); + UMA_HISTOGRAM_COUNTS("Translate.Translate", 1); +} + +// Called when someone clicks on the "Nope" button. +- (IBAction)cancel:(id)sender { + DCHECK( + [self delegate]->type() == TranslateInfoBarDelegate2::BEFORE_TRANSLATE); + [self delegate]->TranslationDeclined(); + UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslate", 1); + [super dismiss:nil]; +} + +- (IBAction)showOriginal:(id)sender { + [self delegate]->RevertTranslation(); +} + +// Called when any of the language drop down menus are changed. +- (void)languageMenuChanged:(id)item { + if ([item respondsToSelector:@selector(tag)]) { + int cmd = [item tag]; + if (cmd >= IDC_TRANSLATE_TARGET_LANGUAGE_BASE) { + cmd -= IDC_TRANSLATE_TARGET_LANGUAGE_BASE; + [self targetLanguageModified:cmd]; + return; + } else if (cmd >= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) { + cmd -= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE; + [self sourceLanguageModified:cmd]; + return; + } + } + NOTREACHED() << "Language menu was changed with a bad language ID"; +} + +// Called when the options menu is changed. +- (void)optionsMenuChanged:(id)item { + if ([item respondsToSelector:@selector(tag)]) { + int cmd = [item tag]; + // Danger Will Robinson! : This call can release the infobar (e.g. invoking + // "About Translate" can open a new tab). + // Do not access member variables after this line! + optionsMenuModel_->ExecuteCommand(cmd); + } else { + NOTREACHED(); + } +} + +#pragma mark NSMenuDelegate + +// Invoked by virtue of us being set as the delegate for the options menu. +- (void)menuNeedsUpdate:(NSMenu *)menu { + [self rebuildOptionsMenu]; +} + +@end + +@implementation TranslateInfoBarControllerBase (TestingAPI) + +- (NSMenu*)optionsMenu { + return [optionsPopUp_ menu]; +} + +- (NSButton*)tryAgainButton { + return tryAgainButton_.get(); +} + +- (bool)verifyLayout { + // All the controls available to translate infobars, except the options popup. + // The options popup is shown/hidden instead of actually removed. This gets + // checked in the subclasses. + NSArray* allControls = [NSArray arrayWithObjects:label1_.get(), + fromLanguagePopUp_.get(), label2_.get(), toLanguagePopUp_.get(), + label3_.get(), showOriginalButton_.get(), tryAgainButton_.get(), nil]; + NSArray* visibleControls = [self visibleControls]; + + // Step 1: Make sure control visibility is what we expect. + for (NSUInteger i = 0; i < [allControls count]; ++i) { + id control = [allControls objectAtIndex:i]; + bool hasSuperView = [control superview]; + bool expectedVisibility = [visibleControls containsObject:control]; + + if (expectedVisibility != hasSuperView) { + NSString *title = @""; + if ([control isKindOfClass:[NSPopUpButton class]]) { + title = [[[control menu] itemAtIndex:0] title]; + } + + LOG(ERROR) << + "State: " << [self description] << + " Control @" << i << (hasSuperView ? " has" : " doesn't have") << + " a superview" << [[control description] UTF8String] << + " Title=" << [title UTF8String]; + return false; + } + } + + // Step 2: Check that controls are ordered correctly with no overlap. + id previousControl = nil; + for (NSUInteger i = 0; i < [visibleControls count]; ++i) { + id control = [visibleControls objectAtIndex:i]; + if (previousControl && !VerifyControlOrderAndSpacing(previousControl, control)) { + NSString *title = @""; + if ([control isKindOfClass:[NSPopUpButton class]]) { + title = [[[control menu] itemAtIndex:0] title]; + } + LOG(ERROR) << + "State: " << [self description] << + " Control @" << i << " not ordered correctly: " << + [[control description] UTF8String] <<[title UTF8String]; + return false; + } + previousControl = control; + } + + return true; +} + +@end // TranslateInfoBarControllerBase (TestingAPI) + diff --git a/chrome/browser/cocoa/translate_infobar_unittest.mm b/chrome/browser/cocoa/translate/translate_infobar_unittest.mm index 07e4185..38eb1ac 100644 --- a/chrome/browser/cocoa/translate_infobar_unittest.mm +++ b/chrome/browser/cocoa/translate/translate_infobar_unittest.mm @@ -3,30 +3,44 @@ // found in the LICENSE file. #import <Cocoa/Cocoa.h> -#import "chrome/browser/cocoa/translate_infobar.h" -#include "base/scoped_nsobject.h" -#include "base/string_util.h" -#include "chrome/app/chrome_dll_resource.h" // For translate menu command ids. +#import "base/scoped_nsobject.h" +#import "base/string_util.h" +#import "chrome/app/chrome_dll_resource.h" // For translate menu command ids. +#import "chrome/browser/cocoa/browser_test_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" -#include "chrome/browser/translate/translate_infobars_delegates.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" +#import "chrome/browser/cocoa/infobar.h" +#import "chrome/browser/cocoa/translate/translate_infobar_base.h" +#import "chrome/browser/cocoa/translate/before_translate_infobar_controller.h" +#import "chrome/browser/cocoa/translate/after_translate_infobar_controller.h" +#import "chrome/browser/cocoa/translate/translate_message_infobar_controller.h" +#import "chrome/browser/renderer_host/site_instance.h" +#import "chrome/browser/tab_contents/tab_contents.h" +#import "chrome/browser/translate/translate_infobar_delegate2.h" +#import "ipc/ipc_channel.h" +#import "testing/gmock/include/gmock/gmock.h" +#import "testing/gtest/include/gtest/gtest.h" +#import "testing/platform_test.h" namespace { // All states the translate toolbar can assume. -TranslateInfoBarDelegate::TranslateState kTranslateToolbarStates[] = { - TranslateInfoBarDelegate::kBeforeTranslate, - TranslateInfoBarDelegate::kAfterTranslate, - TranslateInfoBarDelegate::kTranslateError}; +TranslateInfoBarDelegate2::Type kTranslateToolbarStates[] = { + TranslateInfoBarDelegate2::BEFORE_TRANSLATE, + TranslateInfoBarDelegate2::AFTER_TRANSLATE, + TranslateInfoBarDelegate2::TRANSLATING, + TranslateInfoBarDelegate2::TRANSLATION_ERROR +}; -class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate { +class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate2 { public: - MockTranslateInfoBarDelegate() { + MockTranslateInfoBarDelegate(TranslateInfoBarDelegate2::Type type, + TranslateErrors::Type error, + TabContents* contents) + : TranslateInfoBarDelegate2(type, error, contents, "en", "es"){ // Start out in the "Before Translate" state. - UpdateState(kBeforeTranslate, TranslateErrors::NONE); + type_ = type; + } virtual string16 GetDisplayNameForLocale(const std::string& language_code) { @@ -51,45 +65,57 @@ class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate { MOCK_METHOD0(ToggleLanguageBlacklist, void()); MOCK_METHOD0(ToggleSiteBlacklist, void()); MOCK_METHOD0(ToggleAlwaysTranslate, void()); - }; -class TranslationBarInfoTest : public CocoaTest { +class TranslationInfoBarTest : public CocoaTest { public: scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate; - scoped_nsobject<TranslateInfoBarController> infobar_controller; + scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller; + BrowserTestHelper browser_helper_; public: // Each test gets a single Mock translate delegate for the lifetime of // the test. virtual void SetUp() { CocoaTest::SetUp(); - infobar_delegate.reset(new MockTranslateInfoBarDelegate); + CreateInfoBar(); } void CreateInfoBar() { - CreateInfoBar(TranslateInfoBarDelegate::kBeforeTranslate); + CreateInfoBar(TranslateInfoBarDelegate2::BEFORE_TRANSLATE); } - void CreateInfoBar(TranslateInfoBarDelegate::TranslateState initial_state) { - infobar_delegate->UpdateState(initial_state, TranslateErrors::NONE); + void CreateInfoBar(TranslateInfoBarDelegate2::Type type) { + SiteInstance* instance = + SiteInstance::CreateSiteInstance(browser_helper_.profile()); + scoped_ptr<TabContents> tab_contents( + new TabContents(browser_helper_.profile(), + instance, + MSG_ROUTING_NONE, + NULL)); + TranslateErrors::Type error = TranslateErrors::NONE; + if (type == TranslateInfoBarDelegate2::TRANSLATION_ERROR) + error = TranslateErrors::NETWORK; + infobar_delegate.reset( + new MockTranslateInfoBarDelegate(type, error, tab_contents.get())); [[infobar_controller view] removeFromSuperview]; + scoped_ptr<InfoBar> infobar(infobar_delegate->CreateInfoBar()); infobar_controller.reset( - [[TranslateInfoBarController alloc] - initWithDelegate:infobar_delegate.get()]); + reinterpret_cast<TranslateInfoBarControllerBase*>( + infobar->controller())); // Need to call this to get the view to load from nib. [[test_window() contentView] addSubview:[infobar_controller view]]; } }; // Check that we can instantiate a Translate Infobar correctly. -TEST_F(TranslationBarInfoTest, Instantiate) { +TEST_F(TranslationInfoBarTest, Instantiate) { CreateInfoBar(); ASSERT_TRUE(infobar_controller.get()); } // Check that clicking the Translate button calls Translate(). -TEST_F(TranslationBarInfoTest, TranslateCalledOnButtonPress) { +TEST_F(TranslationInfoBarTest, TranslateCalledOnButtonPress) { CreateInfoBar(); EXPECT_CALL(*infobar_delegate, Translate()).Times(1); @@ -98,68 +124,26 @@ TEST_F(TranslationBarInfoTest, TranslateCalledOnButtonPress) { // Check that clicking the "Retry" button calls Translate() when we're // in the error mode - http://crbug.com/41315 . -TEST_F(TranslationBarInfoTest, TranslateCalledInErrorMode) { - CreateInfoBar(); +TEST_F(TranslationInfoBarTest, TranslateCalledInErrorMode) { + CreateInfoBar(TranslateInfoBarDelegate2::TRANSLATION_ERROR); EXPECT_CALL(*infobar_delegate, Translate()).Times(1); - infobar_delegate->UpdateState(TranslateInfoBarDelegate::kTranslateError, - TranslateErrors::NONE); [infobar_controller ok:nil]; } // Check that clicking the "Show Original button calls RevertTranslation(). -TEST_F(TranslationBarInfoTest, RevertCalledOnButtonPress) { +TEST_F(TranslationInfoBarTest, RevertCalledOnButtonPress) { CreateInfoBar(); EXPECT_CALL(*infobar_delegate, RevertTranslation()).Times(1); [infobar_controller showOriginal:nil]; } -// Check that UI is layed out correctly as we transition synchronously through -// toolbar states. -TEST_F(TranslationBarInfoTest, StateTransitions) { - EXPECT_CALL(*infobar_delegate, Translate()) - .Times(0); - CreateInfoBar(); - - for (size_t i = 0; i < arraysize(kTranslateToolbarStates); ++i) { - TranslateInfoBarDelegate::TranslateState state = kTranslateToolbarStates[i]; - TranslateErrors::Type error = TranslateErrors::NONE; - - infobar_delegate->UpdateState(state, error); - - // Pending Translation == false. - if (i != 0) { - // First time around, the toolbar should already be layed out. - [infobar_controller updateState:state - translationPending:false - error:error]; - } - - bool result = - [infobar_controller verifyLayout:state - translationPending:false]; - EXPECT_TRUE(result) << "Layout wrong, for state " << state << - "translatePending=false"; - - // Pending Translation == true. - [infobar_controller updateState:state - translationPending:true - error:error]; - - result = [infobar_controller verifyLayout:state translationPending:true]; - EXPECT_TRUE(result) << "Layout wrong, for state " << state << - "translatePending=true"; - - } -} - // Check that items in the options menu are hooked up correctly. -TEST_F(TranslationBarInfoTest, OptionsMenuItemsHookedUp) { +TEST_F(TranslationInfoBarTest, OptionsMenuItemsHookedUp) { EXPECT_CALL(*infobar_delegate, Translate()) .Times(0); - CreateInfoBar(); [infobar_controller rebuildOptionsMenu]; NSMenu* optionsMenu = [infobar_controller optionsMenu]; @@ -181,19 +165,19 @@ TEST_F(TranslationBarInfoTest, OptionsMenuItemsHookedUp) { { EXPECT_CALL(*infobar_delegate, ToggleAlwaysTranslate()) .Times(1); - [infobar_controller menuItemSelected:alwaysTranslateLanguateItem]; + [infobar_controller optionsMenuChanged:alwaysTranslateLanguateItem]; } { EXPECT_CALL(*infobar_delegate, ToggleLanguageBlacklist()) .Times(1); - [infobar_controller menuItemSelected:neverTranslateLanguateItem]; + [infobar_controller optionsMenuChanged:neverTranslateLanguateItem]; } { EXPECT_CALL(*infobar_delegate, ToggleSiteBlacklist()) .Times(1); - [infobar_controller menuItemSelected:neverTranslateSiteItem]; + [infobar_controller optionsMenuChanged:neverTranslateSiteItem]; } { @@ -205,32 +189,28 @@ TEST_F(TranslationBarInfoTest, OptionsMenuItemsHookedUp) { // Check that selecting a new item from the "Source Language" popup in "before // translate" mode doesn't trigger a translation or change state. // http://crbug.com/36666 -TEST_F(TranslationBarInfoTest, Bug36666) { +TEST_F(TranslationInfoBarTest, Bug36666) { EXPECT_CALL(*infobar_delegate, Translate()) .Times(0); CreateInfoBar(); int arbitrary_index = 2; [infobar_controller sourceLanguageModified:arbitrary_index]; - EXPECT_EQ(infobar_delegate->state(), - TranslateInfoBarDelegate::kBeforeTranslate); - EXPECT_EQ([infobar_controller state], - TranslateInfoBarDelegate::kBeforeTranslate); + EXPECT_CALL(*infobar_delegate, Translate()) + .Times(0); } // Check that the infobar lays itself out correctly when instantiated in // each of the states. // http://crbug.com/36895 -TEST_F(TranslationBarInfoTest, Bug36895) { +TEST_F(TranslationInfoBarTest, Bug36895) { EXPECT_CALL(*infobar_delegate, Translate()) .Times(0); for (size_t i = 0; i < arraysize(kTranslateToolbarStates); ++i) { CreateInfoBar(kTranslateToolbarStates[i]); EXPECT_TRUE( - [infobar_controller verifyLayout:kTranslateToolbarStates[i] - translationPending:false]) << - "Layout wrong, for state #" << i; + [infobar_controller verifyLayout]) << "Layout wrong, for state #" << i; } } diff --git a/chrome/browser/cocoa/translate/translate_message_infobar_controller.h b/chrome/browser/cocoa/translate/translate_message_infobar_controller.h new file mode 100644 index 0000000..9461d00 --- /dev/null +++ b/chrome/browser/cocoa/translate/translate_message_infobar_controller.h @@ -0,0 +1,13 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/translate/translate_infobar_base.h" + +@interface TranslateMessageInfobarController : TranslateInfoBarControllerBase { + // This keeps track of whether the infobar is displaying a message or an + // error. If it is an error it should have a try again button. + TranslateInfoBarDelegate2::Type state_; +} + +@end diff --git a/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm b/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm new file mode 100644 index 0000000..1087820 --- /dev/null +++ b/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm @@ -0,0 +1,54 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/cocoa/translate/translate_message_infobar_controller.h" + +#include "base/sys_string_conversions.h" + +using TranslateInfoBarUtilities::MoveControl; + +@implementation TranslateMessageInfobarController + +- (id)initWithDelegate:(InfoBarDelegate*)delegate { + if ((self = [super initWithDelegate:delegate])) { + TranslateInfoBarDelegate2* delegate = [self delegate]; + if (delegate->IsError()) + state_ = TranslateInfoBarDelegate2::TRANSLATION_ERROR; + else + state_ = TranslateInfoBarDelegate2::TRANSLATING; + } + return self; +} + +- (void)layout { + [optionsPopUp_ setHidden:YES]; + [self removeOkCancelButtons]; + MoveControl(label1_, tryAgainButton_, spaceBetweenControls_ * 2, true); + TranslateInfoBarDelegate2* delegate = [self delegate]; + if (delegate->IsError()) + MoveControl(label1_, tryAgainButton_, spaceBetweenControls_ * 2, true); +} + +- (NSArray*)visibleControls { + NSMutableArray* visibleControls = + [NSMutableArray arrayWithObjects:label1_.get(), nil]; + if (state_ == TranslateInfoBarDelegate2::TRANSLATION_ERROR) + [visibleControls addObject:tryAgainButton_]; + return visibleControls; +} + +- (void)loadLabelText { + TranslateInfoBarDelegate2* delegate = [self delegate]; + string16 messageText = delegate->GetMessageInfoBarText(); + NSString* string1 = base::SysUTF16ToNSString(messageText); + [label1_ setStringValue:string1]; +} + +- (bool)verifyLayout { + if (![optionsPopUp_ isHidden]) + return false; + return [super verifyLayout]; +} + +@end diff --git a/chrome/browser/cocoa/translate_infobar.h b/chrome/browser/cocoa/translate_infobar.h deleted file mode 100644 index b047d5d..0000000 --- a/chrome/browser/cocoa/translate_infobar.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <Cocoa/Cocoa.h> -#import "chrome/browser/cocoa/infobar_controller.h" - -#import "base/cocoa_protocols_mac.h" -#import "base/scoped_nsobject.h" -#include "base/scoped_ptr.h" -#include "chrome/browser/translate/languages_menu_model.h" -#include "chrome/browser/translate/options_menu_model.h" -#include "chrome/browser/translate/translate_infobars_delegates.h" -#include "chrome/common/notification_registrar.h" -#include "chrome/common/translate_errors.h" - -class TranslateInfoBarMenuModel; -class TranslateNotificationObserverBridge; - -// Draws and maintains Translate Infobar GUI. -// The translate bar can be in one of 3 states: -// 1. "Before Translate" - source language popup and translate/cancel buttons -// visible. -// 2. "Translating" - "Translating..." status text visible in address bar. -// 3. "After Translation" - source & target language popups visible. -// -// The following state transitions are supported: -// 1->{2,3} -// 2<->3 -// i.e. Once you've transitioned out of "Before Translate" mode you can't switch -// back, however all other state transitions are supported. -// -// The GUI uses popup menus interspersed in a text label. For localization -// purposes this means we potentially need 3 labels to display the UI (the 3rd -// is only visible in certain locales). -@interface TranslateInfoBarController : InfoBarController<NSMenuDelegate> { - @protected - // Infobar keeps track of the state it is displaying, which should match that - // in the TranslateInfoBarDelegate. UI needs to keep track separately because - // infobar may receive PAGE_TRANSLATED notifications before delegate does, in - // which case, delegate's state is not updated and hence can't be used to - // update display. After the notification is sent out to all observers, both - // infobar and delegate would end up with the same state. - TranslateInfoBarDelegate::TranslateState state_; - - // Is a translation currently in progress. - bool translationPending_; - - scoped_nsobject<NSTextField> label1_; - scoped_nsobject<NSTextField> label2_; - scoped_nsobject<NSTextField> label3_; - scoped_nsobject<NSTextField> translatingLabel_; - scoped_nsobject<NSPopUpButton> fromLanguagePopUp_; - scoped_nsobject<NSPopUpButton> toLanguagePopUp_; - scoped_nsobject<NSPopUpButton> optionsPopUp_; - scoped_nsobject<NSButton> showOriginalButton_; - scoped_nsobject<NSButton> tryAgainButton_; - - // In the current locale, are the "from" and "to" language popup menu - // flipped from what they'd appear in English. - bool swappedLanguagePlaceholders_; - - // Space between controls in pixels - read from the NIB. - CGFloat spaceBetweenControls_; - int numLabelsDisplayed_; - - scoped_ptr<LanguagesMenuModel> original_language_menu_model_; - scoped_ptr<LanguagesMenuModel> target_language_menu_model_; - scoped_ptr<OptionsMenuModel> options_menu_model_; - scoped_ptr<TranslateInfoBarMenuModel> menu_model_; - scoped_ptr<TranslateNotificationObserverBridge> observer_bridge_; -} - -// Called when the "Show Original" button is pressed. -- (IBAction)showOriginal:(id)sender; - -@end - -@interface TranslateInfoBarController (TestingAPI) - -// Main function to update the toolbar graphic state and data model after -// the state has changed. -// Controls are moved around as needed and visibility changed to match the -// current state. -- (void)updateState:(TranslateInfoBarDelegate::TranslateState)newState - translationPending:(bool)newTranslationPending - error:(TranslateErrors::Type)error; - - -// Called when the source or target language selection changes in a menu. -// |newLanguageIdx| is the index of the newly selected item in the appropriate -// menu. -- (void)sourceLanguageModified:(NSInteger)newLanguageIdx; -- (void)targetLanguageModified:(NSInteger)newLanguageIdx; - -// Called when an item in one of the toolbar's menus is selected. -- (void)menuItemSelected:(id)item; - -// Returns the underlying options menu. -- (NSMenu*)optionsMenu; - -// Returns the "try again" button. -- (NSButton*)tryAgainButton; - -// The TranslateInfoBarController's internal idea of the current state. -- (TranslateInfoBarDelegate::TranslateState)state; - -// Verifies that the layout of the infobar is correct for |state|. -- (bool)verifyLayout:(TranslateInfoBarDelegate::TranslateState)state - translationPending:(bool)translationPending; - -// Teardown and rebuild the options menu. -- (void)rebuildOptionsMenu; - -@end diff --git a/chrome/browser/cocoa/translate_infobar.mm b/chrome/browser/cocoa/translate_infobar.mm deleted file mode 100644 index 949967f..0000000 --- a/chrome/browser/cocoa/translate_infobar.mm +++ /dev/null @@ -1,941 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <Cocoa/Cocoa.h> -#import "chrome/browser/cocoa/translate_infobar.h" - -#include "app/l10n_util.h" -#include "base/logging.h" // for NOTREACHED() -#include "base/mac_util.h" -#include "base/sys_string_conversions.h" -#include "chrome/app/chrome_dll_resource.h" -#import "chrome/browser/cocoa/hover_close_button.h" -#include "chrome/browser/cocoa/infobar.h" -#import "chrome/browser/cocoa/infobar_controller.h" -#import "chrome/browser/cocoa/infobar_gradient_view.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/translate/page_translated_details.h" -#include "chrome/common/notification_service.h" -#include "grit/generated_resources.h" -#include "grit/locale_settings.h" -#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" - -// http://crbug.com/46663 disabled since it never worked. -#define DISABLE_VERIFY_CONTROL_ORDER 1 - -// Colors for translate infobar gradient background. -const int kGreyTopColor[] = {0xC0, 0xC0, 0xC0}; -const int kGreyBottomColor[] = {0xCC, 0xCC, 0xCC}; - -#pragma mark Anonymous helper functions. -namespace { - -// Move the |toMove| view |spacing| pixels before/after the |anchor| view. -// |after| signifies the side of |anchor| on which to place |toMove|. -void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after) { - NSRect anchorFrame = [anchor frame]; - NSRect toMoveFrame = [toMove frame]; - - // At the time of this writing, OS X doesn't natively support BiDi UIs, but - // it doesn't hurt to be forward looking. - bool toRight = after; - - if (toRight) { - toMoveFrame.origin.x = NSMaxX(anchorFrame) + spacing; - } else { - // Place toMove to theleft of anchor. - toMoveFrame.origin.x = NSMinX(anchorFrame) - - spacing - NSWidth(toMoveFrame); - } - [toMove setFrame:toMoveFrame]; -} - -// Vertically center |toMove| in its container. -void VerticallyCenterView(NSView *toMove) { - NSRect superViewFrame = [[toMove superview] frame]; - NSRect viewFrame = [toMove frame]; - - viewFrame.origin.y = - floor((NSHeight(superViewFrame) - NSHeight(viewFrame))/2.0); - [toMove setFrame:viewFrame]; -} - -// Check that the control |before| is ordered visually before the |after| -// control. -// Also, check that there is space between them. -// http://crbug.com/46663 the code below seems to be the reverse of this -// comment. -#if !defined(DISABLE_VERIFY_CONTROL_ORDER) -bool VerifyControlOrderAndSpacing(id before, id after) { - CGFloat spaceBetweenControls = 0; - if (before && after) { - // When messaging nil, the rects won't always be zeroed (only sizeof(id) is - // going to be zeroed by the Objective-C runtime, rest will be uninitialized - // memory). - NSRect beforeFrame = [before frame]; - NSRect afterFrame = [after frame]; - spaceBetweenControls = NSMaxX(beforeFrame) - NSMinX(afterFrame); - // RTL case to be used when we have an RTL version of this UI. - // spaceBetweenControls = NSMaxX(afterFrame) - NSMinX(beforeFrame); - - } - - return (spaceBetweenControls >= 0); -} -#endif // !defined(DISABLE_VERIFY_CONTROL_ORDER) - -// Creates a label control in the style we need for the translate infobar's -// labels within |bounds|. -NSTextField* CreateLabel(NSRect bounds) { - NSTextField* ret = [[NSTextField alloc] initWithFrame:bounds]; - [ret setEditable:NO]; - [ret setDrawsBackground:NO]; - [ret setBordered:NO]; - return ret; -} - -// Adds an item with the specified properties to |menu|. -void AddMenuItem(NSMenu *menu, id target, NSString* title, int tag, - bool enabled, bool checked) { - NSMenuItem* item = [[[NSMenuItem alloc] - initWithTitle:title - action:@selector(menuItemSelected:) - keyEquivalent:@""] autorelease]; - [item setTag:tag]; - [menu addItem:item]; - [item setTarget:target]; - if (checked) - [item setState:NSOnState]; - if (!enabled) - [item setEnabled:NO]; -} - -} // namespace - -#pragma mark TranslateInfoBarMenuModel class definition -// Bridge class to handle interfacing with menu controllers from popup -// menus in infobar. -class TranslateInfoBarMenuModel : public menus::SimpleMenuModel::Delegate { - public: - TranslateInfoBarMenuModel(TranslateInfoBarDelegate* delegate, - TranslateInfoBarController* controller) : - translate_delegate_(delegate), - controller_(controller) {} - - // Overridden from menus::SimpleMenuModel::Delegate: - virtual bool IsCommandIdChecked(int command_id) const; - virtual bool IsCommandIdEnabled(int command_id) const; - virtual bool GetAcceleratorForCommandId(int command_id, - menus::Accelerator* accelerator); - virtual void ExecuteCommand(int command_id); - - private: - TranslateInfoBarDelegate* translate_delegate_; // weak - TranslateInfoBarController* controller_; // weak - DISALLOW_COPY_AND_ASSIGN(TranslateInfoBarMenuModel); -}; - -#pragma mark TranslateNotificationObserverBridge class definition -// Bridge class to allow obj-c TranslateInfoBarController to observe -// notifications. -class TranslateNotificationObserverBridge : - public NotificationObserver { - public: - TranslateNotificationObserverBridge( - TranslateInfoBarDelegate* delegate, - TranslateInfoBarController* controller); - - // Overridden from NotificationObserver: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - private: - TranslateInfoBarDelegate* translate_delegate_; // weak - TranslateInfoBarController* controller_; // weak - NotificationRegistrar notification_registrar_; - DISALLOW_COPY_AND_ASSIGN(TranslateNotificationObserverBridge); -}; - -@interface TranslateInfoBarController (Private) - -// Returns the main translate delegate. -- (TranslateInfoBarDelegate*)delegate; - -// Make the infobar grey. -- (void)setInfoBarGradientColor; - -// Reloads text for all labels for the current state. -- (void)loadLabelText:(TranslateErrors::Type)error; - -// Resizes controls and hides/shows them based on state transition. -// Called before layout; -- (void)resizeAndSetControlVisibility; - -// Move all the currently visible views into the correct place for the -// current mode. -- (void)layout; - -// Create all the various controls we need for the toolbar. -- (void)constructViews; - -// Called when the source or target language selection changes in a menu. -// |newLanguageIdx| is the index of the newly selected item in the appropriate -// menu. -- (void)sourceLanguageModified:(NSInteger)newLanguageIdx; -- (void)targetLanguageModified:(NSInteger)newLanguageIdx; - -// Called when the source or target language have changed to update the -// model state and refresh the GUI. -- (void)languageModified; - -// Completely rebuild "from" and "to" language menus from the data model. -- (void)populateLanguageMenus; - -@end - -#pragma mark TranslateInfoBarController class -@implementation TranslateInfoBarController - -- (id)initWithDelegate:(InfoBarDelegate*)delegate { - if ((self = [super initWithDelegate:delegate])) { - state_ = TranslateInfoBarDelegate::kTranslateNone; - - observer_bridge_.reset( - new TranslateNotificationObserverBridge([self delegate], self)); - - original_language_menu_model_.reset( - new LanguagesMenuModel(menu_model_.get(), [self delegate], - /*original_language=*/true)); - - target_language_menu_model_.reset( - new LanguagesMenuModel(menu_model_.get(), [self delegate], - /*original_language=*/false)); - - menu_model_.reset(new TranslateInfoBarMenuModel([self delegate], self)); - } - return self; -} - -- (TranslateInfoBarDelegate*)delegate { - return reinterpret_cast<TranslateInfoBarDelegate*>(delegate_); -} - -- (void)constructViews { - // Using a zero or very large frame causes GTMUILocalizerAndLayoutTweaker - // to not resize the view properly so we take the bounds of the first label - // which is contained in the nib. - NSRect bogusFrame = [label_ frame]; - label1_.reset(CreateLabel(bogusFrame)); - label2_.reset(CreateLabel(bogusFrame)); - label3_.reset(CreateLabel(bogusFrame)); - translatingLabel_.reset(CreateLabel(bogusFrame)); - - optionsPopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame - pullsDown:YES]); - fromLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame - pullsDown:NO]); - toLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame - pullsDown:NO]); - - showOriginalButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]); - tryAgainButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]); -} - -- (void)sourceLanguageModified:(NSInteger)newLanguageIdx { - DCHECK_GT(newLanguageIdx, 0); - - if (newLanguageIdx == [self delegate]->original_lang_index()) - return; - - [self delegate]->ModifyOriginalLanguage(newLanguageIdx); - - int commandId = IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + newLanguageIdx; - int newMenuIdx = [fromLanguagePopUp_ indexOfItemWithTag:commandId]; - [fromLanguagePopUp_ selectItemAtIndex:newMenuIdx]; - - [self languageModified]; -} - -- (void)targetLanguageModified:(NSInteger)newLanguageIdx { - DCHECK_GT(newLanguageIdx, 0); - if (newLanguageIdx == [self delegate]->target_lang_index()) - return; - - [self delegate]->ModifyTargetLanguage(newLanguageIdx); - - int commandId = IDC_TRANSLATE_TARGET_LANGUAGE_BASE + newLanguageIdx; - int newMenuIdx = [toLanguagePopUp_ indexOfItemWithTag:commandId]; - [toLanguagePopUp_ selectItemAtIndex:newMenuIdx]; - - [self languageModified]; -} - -- (void)languageModified { - // Selecting an item from the "from language" menu in the before translate - // phase shouldn't trigger translation - http://crbug.com/36666 - TranslateInfoBarDelegate* delegate = [self delegate]; - if (delegate->state() == TranslateInfoBarDelegate::kAfterTranslate) { - delegate->Translate(); - [self updateState:delegate->state() - translationPending:delegate->translation_pending() - error:delegate->error_type()]; - } -} - -- (void)updateState:(TranslateInfoBarDelegate::TranslateState)newState - translationPending:(bool)newTranslationPending - error:(TranslateErrors::Type)error { - if (state_ == newState && translationPending_ == newTranslationPending) - return; - - state_ = newState; - translationPending_ = newTranslationPending; - - [self loadLabelText:error]; - - [self resizeAndSetControlVisibility]; - [self layout]; -} - -- (void)setInfoBarGradientColor { - // Use grey gradient for the infobars. - NSColor* startingColor = - [NSColor colorWithCalibratedRed:kGreyTopColor[0] / 255.0 - green:kGreyTopColor[1] / 255.0 - blue:kGreyTopColor[2] / 255.0 - alpha:1.0]; - NSColor* endingColor = - [NSColor colorWithCalibratedRed:kGreyBottomColor[0] / 255.0 - green:kGreyBottomColor[1] / 255.0 - blue:kGreyBottomColor[2] / 255.0 - alpha:1.0]; - NSGradient* translateInfoBarGradient = - [[[NSGradient alloc] initWithStartingColor:startingColor - endingColor:endingColor] autorelease]; - - [infoBarView_ setGradient:translateInfoBarGradient]; -} - -- (void)resizeAndSetControlVisibility { - // Step 1: remove all controls from the infobar so we have a clean slate. - NSArray *allControls = [NSArray arrayWithObjects:label2_.get(), label3_.get(), - translatingLabel_.get(), fromLanguagePopUp_.get(), toLanguagePopUp_.get(), - showOriginalButton_.get(), tryAgainButton_.get(), nil]; - - for (NSControl* control in allControls) { - if ([control superview]) - [control removeFromSuperview]; - } - - // OK & Cancel buttons are only visible in "before translate" mode when no - // translation is in progress. - if (state_ != TranslateInfoBarDelegate::kBeforeTranslate || - translationPending_) { - // Removing okButton_ & cancelButton_ from the view may cause them - // to be released and since we can still access them from other areas - // in the code later, we need them to be nil when this happens. - [okButton_ removeFromSuperview]; - okButton_ = nil; - [cancelButton_ removeFromSuperview]; - cancelButton_ = nil; - - } - - // Step 2: Resize all visible controls and add them to the infobar. - NSMutableArray *visibleControls = nil; - - switch (state_) { - case TranslateInfoBarDelegate::kBeforeTranslate: - visibleControls = [NSMutableArray arrayWithObjects:label1_.get(), - label2_.get(), fromLanguagePopUp_.get(), nil]; - - if (!translationPending_) { - [visibleControls addObject:okButton_]; - [visibleControls addObject:cancelButton_]; - } - break; - case TranslateInfoBarDelegate::kAfterTranslate: - visibleControls = [NSMutableArray arrayWithObjects:label1_.get(), - label2_.get(), fromLanguagePopUp_.get(), toLanguagePopUp_.get(), nil]; - if (!translationPending_) { - [visibleControls addObject:showOriginalButton_.get()]; - } - break; - case TranslateInfoBarDelegate::kTranslateError: - visibleControls = [NSMutableArray arrayWithObjects:label1_.get(), nil]; - - if (!translationPending_) { - [visibleControls addObject:tryAgainButton_.get()]; - } - break; - default: - NOTREACHED() << "Invalid translate infobar state"; - break; - } - - if (translationPending_) { - [visibleControls addObject:translatingLabel_]; - } - - if (numLabelsDisplayed_ >= 3) { - [visibleControls addObject:label3_.get()]; - } - - // The options popup is only hidden in the translateError view. - BOOL optionsPopuUpHidden = - (state_ == TranslateInfoBarDelegate::kTranslateError) ? YES : NO; - [optionsPopUp_ setHidden:optionsPopuUpHidden]; - - NSRect optionsFrame = [optionsPopUp_ frame]; - for (NSControl* control in visibleControls) { - [GTMUILocalizerAndLayoutTweaker sizeToFitView:control]; - [control setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin | - NSViewMaxYMargin]; - - // Need to check if a view is already attached since |label1_| is always - // parented and we don't want to add it again. - if (![control superview]) - [infoBarView_ addSubview:control]; - - if ([control isKindOfClass:[NSButton class]]) - VerticallyCenterView(control); - - // Make "from" and "to" language popup menus the same size as the options - // menu. - // We don't autosize since some languages names are really long causing - // the toolbar to overflow. - if ([control isKindOfClass:[NSPopUpButton class]]) - [control setFrame:optionsFrame]; - } -} - -- (void)layout { - if (state_ != TranslateInfoBarDelegate::kAfterTranslate) { - // 3rd label is only displayed in some locales, but should never be - // visible in this stage. - // If it ever is visible then we need to move it into position here. - DCHECK(numLabelsDisplayed_ < 3); - } - - switch (state_) { - case TranslateInfoBarDelegate::kBeforeTranslate: - MoveControl(label1_, fromLanguagePopUp_, 0, true); - MoveControl(fromLanguagePopUp_, label2_, 0, true); - - if (!translationPending_) { - MoveControl(label2_, okButton_, spaceBetweenControls_, true); - MoveControl(okButton_, cancelButton_, spaceBetweenControls_, true); - } else { - MoveControl(label2_, translatingLabel_, spaceBetweenControls_, true); - } - break; - - case TranslateInfoBarDelegate::kAfterTranslate: { - NSView* lastControl = toLanguagePopUp_; - MoveControl(label1_, fromLanguagePopUp_, 0, true); - MoveControl(fromLanguagePopUp_, label2_, 0, true); - MoveControl(label2_, toLanguagePopUp_, 0, true); - if (numLabelsDisplayed_ == 3) { - MoveControl(toLanguagePopUp_, label3_, 0, true); - lastControl = label3_; - } - - if (translationPending_) { - MoveControl(lastControl, translatingLabel_, spaceBetweenControls_ * 2, - true); - } else { - MoveControl(lastControl, showOriginalButton_, spaceBetweenControls_ * 2, - true); - } - - break; - } - - case TranslateInfoBarDelegate::kTranslateError: - if (translationPending_) { - MoveControl(label1_, translatingLabel_, 0, true); - } else { - MoveControl(label1_, tryAgainButton_, spaceBetweenControls_ * 2, true); - } - break; - - default: - NOTREACHED() << "Invalid translate infobar state"; - break; - } -} - -- (void) rebuildOptionsMenu { - // The options model doesn't know how to handle state transitions, so rebuild - // it each time through here. - options_menu_model_.reset( - new OptionsMenuModel(menu_model_.get(), [self delegate])); - - [optionsPopUp_ removeAllItems]; - // Set title. - NSString* optionsLabel = - l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_OPTIONS); - [optionsPopUp_ addItemWithTitle:optionsLabel]; - - // Populate options menu. - NSMenu* optionsMenu = [optionsPopUp_ menu]; - [optionsMenu setAutoenablesItems:NO]; - for (int i = 0; i < options_menu_model_->GetItemCount(); ++i) { - NSString* title = base::SysUTF16ToNSString( - options_menu_model_->GetLabelAt(i)); - int cmd = options_menu_model_->GetCommandIdAt(i); - bool checked = options_menu_model_->IsItemCheckedAt(i); - bool enabled = options_menu_model_->IsEnabledAt(i); - AddMenuItem(optionsMenu, self, title, cmd, enabled, checked); - } -} - -- (void)populateLanguageMenus { - NSMenu* originalLanguageMenu = [fromLanguagePopUp_ menu]; - [originalLanguageMenu setAutoenablesItems:NO]; - int selectedMenuIndex = 0; - int selectedLangIndex = [self delegate]->original_lang_index(); - for (int i = 0; i < original_language_menu_model_->GetItemCount(); ++i) { - NSString* title = base::SysUTF16ToNSString( - original_language_menu_model_->GetLabelAt(i)); - int cmd = original_language_menu_model_->GetCommandIdAt(i); - bool checked = - (cmd - IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) == selectedLangIndex; - if (checked) - selectedMenuIndex = i; - bool enabled = original_language_menu_model_->IsEnabledAt(i); - AddMenuItem(originalLanguageMenu, self, title, cmd, enabled, checked); - } - [fromLanguagePopUp_ selectItemAtIndex:selectedMenuIndex]; - - NSMenu* targetLanguageMenu = [toLanguagePopUp_ menu]; - [targetLanguageMenu setAutoenablesItems:NO]; - selectedLangIndex = [self delegate]->target_lang_index(); - for (int i = 0; i < target_language_menu_model_->GetItemCount(); ++i) { - NSString* title = base::SysUTF16ToNSString( - target_language_menu_model_->GetLabelAt(i)); - int cmd = target_language_menu_model_->GetCommandIdAt(i); - bool checked = - (cmd - IDC_TRANSLATE_TARGET_LANGUAGE_BASE) == selectedLangIndex; - if (checked) - selectedMenuIndex = i; - bool enabled = target_language_menu_model_->IsEnabledAt(i); - AddMenuItem(targetLanguageMenu, self, title, cmd, enabled, checked); - } - [toLanguagePopUp_ selectItemAtIndex:selectedMenuIndex]; -} - -- (void)loadLabelText:(TranslateErrors::Type)error { - numLabelsDisplayed_ = 2; - - NSString* label1Text = @""; - NSString* label2Text = @""; - NSString* label3Text = @""; - - if (state_ == TranslateInfoBarDelegate::kTranslateError) { - // Load an error message, if an error occured and the user clicked - // "try again" then blank all labels. - if (!translationPending_) { - string16 message_text_utf16 = [self delegate]->GetErrorMessage(error); - label1Text = base::SysUTF16ToNSString(message_text_utf16); - } - } else { - string16 message_text_utf16; - std::vector<size_t> offsets; - [self delegate]->GetMessageText(state_, &message_text_utf16, - &offsets, &swappedLanguagePlaceholders_); - - NSString* message_text = base::SysUTF16ToNSString(message_text_utf16); - NSRange label1Range = NSMakeRange(0, offsets[0]); - label1Text = [message_text substringWithRange:label1Range]; - NSRange label2Range = NSMakeRange(offsets[0], - offsets[1] - offsets[0]); - label2Text = [message_text substringWithRange:label2Range]; - - // If this locale requires a 3rd label for the status message. - if (offsets.size() == 3) { - NSRange label3Range = NSMakeRange(offsets[1], - offsets[2] - offsets[1]); - label3Text = [message_text substringWithRange:label3Range]; - numLabelsDisplayed_ = 3; - } - } - - [label1_ setStringValue:label1Text]; - [label2_ setStringValue:label2Text]; - [label3_ setStringValue:label3Text]; -} - -- (void)addAdditionalControls { - using l10n_util::GetNSString; - using l10n_util::GetNSStringWithFixup; - - // Get layout information from the NIB. - NSRect okButtonFrame = [okButton_ frame]; - NSRect cancelButtonFrame = [cancelButton_ frame]; - spaceBetweenControls_ = NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame); - - // Set infobar background color. - [self setInfoBarGradientColor]; - - // Instantiate additional controls. - [self constructViews]; - - // Set ourselves as the delegate for the options menu so we can populate it - // dynamically. - [[optionsPopUp_ menu] setDelegate:self]; - - // Replace label_ with label1_ so we get a consistent look between all the - // labels we display in the translate view. - [[label_ superview] replaceSubview:label_ with:label1_.get()]; - label_.reset(); // Now released. - - // Populate contextual menus. - [self rebuildOptionsMenu]; - [self populateLanguageMenus]; - - // Set OK & Cancel text. - [okButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_ACCEPT)]; - [cancelButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_DENY)]; - [translatingLabel_ - setStringValue:GetNSString(IDS_TRANSLATE_INFOBAR_TRANSLATING)]; - - // Set up "Show original" and "Try again" buttons. - [showOriginalButton_ setBezelStyle:NSRoundRectBezelStyle]; - [showOriginalButton_ setFrame:okButtonFrame]; - [tryAgainButton_ setBezelStyle:NSRoundRectBezelStyle]; - [tryAgainButton_ setFrame:okButtonFrame]; - - [showOriginalButton_ setTarget:self]; - [showOriginalButton_ setAction:@selector(showOriginal:)]; - [tryAgainButton_ setTarget:self]; - [tryAgainButton_ setAction:@selector(ok:)]; - - [showOriginalButton_ - setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_REVERT)]; - [tryAgainButton_ - setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_RETRY)]; - - // Add and configure controls that are visible in all modes. - [optionsPopUp_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin | - NSViewMaxYMargin]; - // Add "options" popup z-ordered below all other controls so when we - // resize the toolbar it doesn't hide them. - [infoBarView_ addSubview:optionsPopUp_ - positioned:NSWindowBelow - relativeTo:nil]; - [GTMUILocalizerAndLayoutTweaker sizeToFitView:optionsPopUp_]; - MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false); - VerticallyCenterView(optionsPopUp_); - - // Show and place GUI elements. - TranslateInfoBarDelegate* delegate = [self delegate]; - [self updateState:delegate->state() - translationPending:delegate->translation_pending() - error:delegate->error_type()]; -} - -// Called when "Translate" button is clicked. -- (IBAction)ok:(id)sender { - TranslateInfoBarDelegate* delegate = [self delegate]; - TranslateInfoBarDelegate::TranslateState state = delegate->state(); - DCHECK(state == TranslateInfoBarDelegate::kBeforeTranslate || - state == TranslateInfoBarDelegate::kTranslateError); - delegate->Translate(); - [self updateState:state - translationPending:delegate->translation_pending() - error:delegate->error_type()]; - UMA_HISTOGRAM_COUNTS("Translate.Translate", 1); -} - -// Called when someone clicks on the "Nope" button. -- (IBAction)cancel:(id)sender { - DCHECK( - [self delegate]->state() == TranslateInfoBarDelegate::kBeforeTranslate); - [self delegate]->TranslationDeclined(); - UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslate", 1); - [super dismiss:nil]; -} - -- (IBAction)showOriginal:(id)sender { - [self delegate]->RevertTranslation(); -} - -- (void)menuItemSelected:(id)item { - if ([item respondsToSelector:@selector(tag)]) { - int cmd = [item tag]; - // Danger Will Robinson! : This call can release the infobar (e.g. invoking - // "About Translate" can open a new tab). - // Do not access member variables after this line! - menu_model_->ExecuteCommand(cmd); - } else { - NOTREACHED(); - } -} - -#pragma mark NSMenuDelegate - -// Invoked by virtue of us being set as the delegate for the options menu. -- (void)menuNeedsUpdate:(NSMenu *)menu { - [self rebuildOptionsMenu]; -} - -#pragma mark TestingAPI -- (NSMenu*)optionsMenu { - return [optionsPopUp_ menu]; -} - -- (NSButton*)tryAgainButton { - return tryAgainButton_.get(); -} - -- (TranslateInfoBarDelegate::TranslateState)state { - return state_; -} - -- (bool)verifyLayout:(TranslateInfoBarDelegate::TranslateState)state - translationPending:(bool)translationPending { - NSArray* allControls = [NSArray arrayWithObjects:label1_.get(), label2_.get(), - label3_.get(), translatingLabel_.get(), fromLanguagePopUp_.get(), - toLanguagePopUp_.get(), optionsPopUp_.get(), closeButton_, - showOriginalButton_.get(), tryAgainButton_.get(), nil]; - - // Sanity check - parameters should match internal state. - if (state != state_) { - LOG(ERROR) << "State mismatch: " << state << " vs " << state_; - return false; - } - - if (translationPending != translationPending_) { - LOG(ERROR) << "Pending Translation mismatch: " << - translationPending << " vs " << translationPending_; - return false; - } - - // Array of all visible controls ordered from start -> end. - NSArray* visibleControls = nil; - - switch (state) { - case TranslateInfoBarDelegate::kBeforeTranslate: - if (translationPending) { - visibleControls = [NSArray arrayWithObjects:label1_.get(), - fromLanguagePopUp_.get(), label2_.get(), translatingLabel_.get(), - optionsPopUp_.get(), closeButton_, nil]; - } else { - visibleControls = [NSArray arrayWithObjects:label1_.get(), - fromLanguagePopUp_.get(), label2_.get(), optionsPopUp_.get(), - closeButton_, nil]; - } - break; - case TranslateInfoBarDelegate::kAfterTranslate: - if (translationPending) { - visibleControls = [NSArray arrayWithObjects:label1_.get(), - fromLanguagePopUp_.get(), label2_.get(), toLanguagePopUp_.get(), - translatingLabel_.get(), optionsPopUp_.get(), closeButton_, nil]; - } else { - visibleControls = [NSArray arrayWithObjects:label1_.get(), - fromLanguagePopUp_.get(), label2_.get(), toLanguagePopUp_.get(), - showOriginalButton_.get(), optionsPopUp_.get(), closeButton_, nil]; - } - break; - case TranslateInfoBarDelegate::kTranslateError: - if (translationPending) { - visibleControls = [NSArray arrayWithObjects:label1_.get(), - translatingLabel_.get(), closeButton_, nil]; - } else { - visibleControls = [NSArray arrayWithObjects:label1_.get(), - tryAgainButton_.get(), closeButton_, nil]; - } - break; - default: - NOTREACHED() << "Unknown state"; - return false; - } - - // Step 1: Make sure control visibility is what we expect. - for (NSUInteger i = 0; i < [allControls count]; ++i) { - id control = [allControls objectAtIndex:i]; - bool hasSuperView = [control superview]; - bool expectedVisibility = [visibleControls containsObject:control]; - - - // Special case the options popup, which we hide rather than removing - // from the superview. - if (control == optionsPopUp_.get()) - hasSuperView = [control isHidden] == NO; - - if (expectedVisibility != hasSuperView) { - NSString *title = @""; - - if ([control isKindOfClass:[NSPopUpButton class]]) { - title = [[[control menu] itemAtIndex:0] title]; - } - - LOG(ERROR) << - "State: " << state << " translationPending " << translationPending << - " Control @" << i << (hasSuperView ? " has" : " doesn't have") << - " a superview" << [[control description] UTF8String] << - " Title=" << [title UTF8String]; - return false; - } - } - - // Step 2: Check that controls are ordered correctly with no overlap. -#if !defined(DISABLE_VERIFY_CONTROL_ORDER) - // http://crbug.com/46663 this appears to be invalid. - // VerifyControlOrderAndSpacing had an unsigned >= 0 bug, so it used to always - // return true. With that bug fixed, this loop now can return a failure. - // Scanning the code, it's not clear how this would pass since not all - // controls are visible and it needs the array order to always match display - // order. - id previousControl = nil; - for (NSUInteger i = 0; i < [allControls count]; ++i) { - id control = [allControls objectAtIndex:i]; - if (!VerifyControlOrderAndSpacing(previousControl, control)) { - LOG(ERROR) << - "State: " << state << " translationPending " << translationPending << - " Control @" << i << " not ordered correctly: " << - [[control description] UTF8String]; - return false; - } - previousControl = control; - } -#endif // !defined(DISABLE_VERIFY_CONTROL_ORDER) - - // Step 3: Check other misc. attributes of layout. - if (state == TranslateInfoBarDelegate::kTranslateError && translationPending) - { - if ([[label1_ stringValue] length] != 0) { - LOG(ERROR) << "Expected empty label1_, instead got" << - [[label1_ description] UTF8String]; - return false; - } - } - - return true; -} - -@end - -#pragma mark CreateInfoBar implementation. -InfoBar* TranslateInfoBarDelegate::CreateInfoBar() { - TranslateInfoBarController* controller = - [[TranslateInfoBarController alloc] initWithDelegate:this]; - return new InfoBar(controller); -} - -#pragma mark menus::SimpleMenuModel::Delegates - -bool TranslateInfoBarMenuModel::IsCommandIdChecked(int command_id) const { - switch (command_id) { - case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG : - return translate_delegate_->IsLanguageBlacklisted(); - - case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE : - return translate_delegate_->IsSiteBlacklisted(); - - case IDC_TRANSLATE_OPTIONS_ALWAYS : - return translate_delegate_->ShouldAlwaysTranslate(); - - default: - NOTREACHED() << "Invalid command_id from menu"; - break; - } - return false; -} - -bool TranslateInfoBarMenuModel::IsCommandIdEnabled(int command_id) const { - switch (command_id) { - case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG : - case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE : - return !translate_delegate_->ShouldAlwaysTranslate(); - - case IDC_TRANSLATE_OPTIONS_ALWAYS : - return (!translate_delegate_->IsLanguageBlacklisted() && - !translate_delegate_->IsSiteBlacklisted()); - - default: - break; - } - return true; -} - -bool TranslateInfoBarMenuModel::GetAcceleratorForCommandId(int command_id, - menus::Accelerator* accelerator) { - return false; -} - -void TranslateInfoBarMenuModel::ExecuteCommand(int command_id) { - if (command_id >= IDC_TRANSLATE_TARGET_LANGUAGE_BASE) { - int language_command_id = - command_id - IDC_TRANSLATE_TARGET_LANGUAGE_BASE; - [controller_ - targetLanguageModified:language_command_id]; - } else if (command_id >= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) { - int language_command_id = - command_id - IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE; - [controller_ - sourceLanguageModified:language_command_id]; - } else { - switch (command_id) { - case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG: - translate_delegate_->ToggleLanguageBlacklist(); - break; - - case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE: - translate_delegate_->ToggleSiteBlacklist(); - break; - - case IDC_TRANSLATE_OPTIONS_ALWAYS: - translate_delegate_->ToggleAlwaysTranslate(); - break; - - case IDC_TRANSLATE_OPTIONS_ABOUT: { - TabContents* tab_contents = translate_delegate_->tab_contents(); - if (tab_contents) { - string16 url = l10n_util::GetStringUTF16( - IDS_ABOUT_GOOGLE_TRANSLATE_URL); - tab_contents->OpenURL(GURL(url), GURL(), NEW_FOREGROUND_TAB, - PageTransition::LINK); - } - break; - } - - default: - NOTREACHED() << "Invalid command id from menu."; - break; - } - } -} - -# pragma mark TranslateInfoBarNotificationObserverBridge - -TranslateNotificationObserverBridge::TranslateNotificationObserverBridge( - TranslateInfoBarDelegate* delegate, - TranslateInfoBarController* controller) : - translate_delegate_(delegate), - controller_(controller) { - // Register for PAGE_TRANSLATED notification. - notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, - Source<TabContents>(translate_delegate_->tab_contents())); -}; - -void TranslateNotificationObserverBridge::Observe(NotificationType type, - const NotificationSource& source, const NotificationDetails& details) { - if (type.value != NotificationType::PAGE_TRANSLATED) - return; - TabContents* tab = Source<TabContents>(source).ptr(); - if (tab != translate_delegate_->tab_contents()) - return; - PageTranslatedDetails* page_translated_details = - Details<PageTranslatedDetails>(details).ptr(); - TranslateErrors::Type error = page_translated_details->error_type; - TranslateInfoBarDelegate::TranslateState newState = - TranslateInfoBarDelegate::kAfterTranslate; - if (page_translated_details->error_type != TranslateErrors::NONE) - newState = TranslateInfoBarDelegate::kTranslateError; - [controller_ updateState:newState translationPending:false error:error]; - -} diff --git a/chrome/browser/translate/translate_infobar_delegate2.cc b/chrome/browser/translate/translate_infobar_delegate2.cc index bc11024..d83f4e0 100644 --- a/chrome/browser/translate/translate_infobar_delegate2.cc +++ b/chrome/browser/translate/translate_infobar_delegate2.cc @@ -57,11 +57,6 @@ TranslateInfoBarDelegate2::TranslateInfoBarDelegate2( iter != language_codes.end(); ++iter) { std::string language_code = *iter; - if (language_code == original_language) - original_language_index_ = iter - language_codes.begin(); - else if (language_code == target_language) - target_language_index_ = iter - language_codes.begin(); - string16 language_name = GetLanguageDisplayableName(language_code); // Insert the language in languages_ in alphabetical order. std::vector<LanguageNamePair>::iterator iter2; @@ -71,6 +66,15 @@ TranslateInfoBarDelegate2::TranslateInfoBarDelegate2( } languages_.insert(iter2, LanguageNamePair(language_code, language_name)); } + for (std::vector<LanguageNamePair>::const_iterator iter = languages_.begin(); + iter != languages_.end(); ++iter) { + std::string language_code = iter->first; + if (language_code == original_language) + original_language_index_ = iter - languages_.begin(); + else if (language_code == target_language) + target_language_index_ = iter - languages_.begin(); + } + DCHECK(original_language_index_ != -1); DCHECK(target_language_index_ != -1); } @@ -300,7 +304,7 @@ void TranslateInfoBarDelegate2::GetAfterTranslateStrings( strings->push_back(text.substr(offsets[1])); } -#if !defined(OS_WIN) && !defined(OS_CHROMEOS) +#if !defined(OS_WIN) && !defined(OS_CHROMEOS) && !defined(OS_MACOSX) // Necessary so we link OK on Mac and Linux while the new translate infobars // are being ported to these platforms. InfoBar* TranslateInfoBarDelegate2::CreateInfoBar() { diff --git a/chrome/browser/translate/translate_infobar_delegate2.h b/chrome/browser/translate/translate_infobar_delegate2.h index 2129776..bb535ad 100644 --- a/chrome/browser/translate/translate_infobar_delegate2.h +++ b/chrome/browser/translate/translate_infobar_delegate2.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE2_H -#define CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE2_H +#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE2_H_ +#define CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE2_H_ #include <string> #include <vector> @@ -129,21 +129,22 @@ class TranslateInfoBarDelegate2 : public InfoBarDelegate { static void GetAfterTranslateStrings(std::vector<string16>* strings, bool* swap_languages); - private: - typedef std::pair<std::string, string16> LanguageNamePair; - - // Gets the host of the page being translated, or an empty string if no URL is - // associated with the current page. - std::string GetPageHost(); - + protected: + // For testing. TranslateInfoBarDelegate2(Type infobar_type, TranslateErrors::Type error, TabContents* tab_contents, const std::string& original_language, const std::string& target_language); - Type type_; + private: + typedef std::pair<std::string, string16> LanguageNamePair; + + // Gets the host of the page being translated, or an empty string if no URL is + // associated with the current page. + std::string GetPageHost(); + // The type of fading animation if any that should be used when showing this // infobar. BackgroundAnimationType background_animation_; @@ -174,5 +175,5 @@ class TranslateInfoBarDelegate2 : public InfoBarDelegate { DISALLOW_COPY_AND_ASSIGN(TranslateInfoBarDelegate2); }; -#endif // CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE2_H +#endif // CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE2_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index c01b309..9c88786 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -900,8 +900,14 @@ 'browser/cocoa/toolbar_controller.mm', 'browser/cocoa/toolbar_view.h', 'browser/cocoa/toolbar_view.mm', - 'browser/cocoa/translate_infobar.h', - 'browser/cocoa/translate_infobar.mm', + 'browser/cocoa/translate/after_translate_infobar_controller.h', + 'browser/cocoa/translate/after_translate_infobar_controller.mm', + 'browser/cocoa/translate/before_translate_infobar_controller.h', + 'browser/cocoa/translate/before_translate_infobar_controller.mm', + 'browser/cocoa/translate/translate_infobar_base.h', + 'browser/cocoa/translate/translate_infobar_base.mm', + 'browser/cocoa/translate/translate_message_infobar_controller.h', + 'browser/cocoa/translate/translate_message_infobar_controller.mm', 'browser/cocoa/ui_localizer.h', 'browser/cocoa/ui_localizer.mm', 'browser/cocoa/url_drop_target.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 2c003f6..3485024 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -754,7 +754,7 @@ 'browser/cocoa/throbber_view_unittest.mm', 'browser/cocoa/toolbar_controller_unittest.mm', 'browser/cocoa/toolbar_view_unittest.mm', - 'browser/cocoa/translate_infobar_unittest.mm', + 'browser/cocoa/translate/translate_infobar_unittest.mm', 'browser/cocoa/vertical_gradient_view_unittest.mm', 'browser/cocoa/view_resizer_pong.h', 'browser/cocoa/view_resizer_pong.mm', |