OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import <Cocoa/Cocoa.h> |
| 6 #import "chrome/browser/cocoa/translate/translate_infobar_base.h" |
| 7 |
| 8 #include "app/l10n_util.h" |
| 9 #include "base/histogram.h" |
| 10 #include "base/logging.h" // for NOTREACHED() |
| 11 #include "base/mac_util.h" |
| 12 #include "base/sys_string_conversions.h" |
| 13 #include "chrome/app/chrome_dll_resource.h" |
| 14 #import "chrome/browser/cocoa/hover_close_button.h" |
| 15 #include "chrome/browser/cocoa/infobar.h" |
| 16 #import "chrome/browser/cocoa/infobar_controller.h" |
| 17 #import "chrome/browser/cocoa/infobar_gradient_view.h" |
| 18 #include "chrome/browser/cocoa/translate/after_translate_infobar_controller.h" |
| 19 #import "chrome/browser/cocoa/translate/before_translate_infobar_controller.h" |
| 20 #include "chrome/browser/cocoa/translate/translate_message_infobar_controller.h" |
| 21 #include "chrome/browser/translate/translate_infobars_delegates.h" |
| 22 #include "grit/generated_resources.h" |
| 23 #include "grit/locale_settings.h" |
| 24 #include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
| 25 |
| 26 using TranslateInfoBarUtilities::MoveControl; |
| 27 using TranslateInfoBarUtilities::VerticallyCenterView; |
| 28 using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing; |
| 29 using TranslateInfoBarUtilities::CreateLabel; |
| 30 using TranslateInfoBarUtilities::AddMenuItem; |
| 31 |
| 32 // Colors for translate infobar gradient background. |
| 33 const int kGreyTopColor[] = {0xC0, 0xC0, 0xC0}; |
| 34 const int kGreyBottomColor[] = {0xCC, 0xCC, 0xCC}; |
| 35 |
| 36 #pragma mark TranslateInfoBarUtilities helper functions. |
| 37 |
| 38 namespace TranslateInfoBarUtilities { |
| 39 |
| 40 // Move the |toMove| view |spacing| pixels before/after the |anchor| view. |
| 41 // |after| signifies the side of |anchor| on which to place |toMove|. |
| 42 void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after) { |
| 43 NSRect anchorFrame = [anchor frame]; |
| 44 NSRect toMoveFrame = [toMove frame]; |
| 45 |
| 46 // At the time of this writing, OS X doesn't natively support BiDi UIs, but |
| 47 // it doesn't hurt to be forward looking. |
| 48 bool toRight = after; |
| 49 |
| 50 if (toRight) { |
| 51 toMoveFrame.origin.x = NSMaxX(anchorFrame) + spacing; |
| 52 } else { |
| 53 // Place toMove to theleft of anchor. |
| 54 toMoveFrame.origin.x = NSMinX(anchorFrame) - |
| 55 spacing - NSWidth(toMoveFrame); |
| 56 } |
| 57 [toMove setFrame:toMoveFrame]; |
| 58 } |
| 59 |
| 60 // Check that the control |before| is ordered visually before the |after| |
| 61 // control. |
| 62 // Also, check that there is space between them. |
| 63 bool VerifyControlOrderAndSpacing(id before, id after) { |
| 64 NSRect beforeFrame = [before frame]; |
| 65 NSRect afterFrame = [after frame]; |
| 66 return NSMinX(afterFrame) >= NSMaxX(beforeFrame); |
| 67 } |
| 68 |
| 69 // Vertically center |toMove| in its container. |
| 70 void VerticallyCenterView(NSView *toMove) { |
| 71 NSRect superViewFrame = [[toMove superview] frame]; |
| 72 NSRect viewFrame = [toMove frame]; |
| 73 viewFrame.origin.y = |
| 74 floor((NSHeight(superViewFrame) - NSHeight(viewFrame))/2.0); |
| 75 [toMove setFrame:viewFrame]; |
| 76 } |
| 77 |
| 78 // Creates a label control in the style we need for the translate infobar's |
| 79 // labels within |bounds|. |
| 80 NSTextField* CreateLabel(NSRect bounds) { |
| 81 NSTextField* ret = [[NSTextField alloc] initWithFrame:bounds]; |
| 82 [ret setEditable:NO]; |
| 83 [ret setDrawsBackground:NO]; |
| 84 [ret setBordered:NO]; |
| 85 return ret; |
| 86 } |
| 87 |
| 88 // Adds an item with the specified properties to |menu|. |
| 89 void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title, |
| 90 int tag, bool enabled, bool checked) { |
| 91 NSMenuItem* item = [[[NSMenuItem alloc] |
| 92 initWithTitle:title |
| 93 action:selector |
| 94 keyEquivalent:@""] autorelease]; |
| 95 [item setTag:tag]; |
| 96 [menu addItem:item]; |
| 97 [item setTarget:target]; |
| 98 if (checked) |
| 99 [item setState:NSOnState]; |
| 100 if (!enabled) |
| 101 [item setEnabled:NO]; |
| 102 } |
| 103 |
| 104 } // namespace TranslateInfoBarUtilities |
| 105 |
| 106 // For compilation purposes until the linux port goes through and |
| 107 // the files can be removed. |
| 108 InfoBar* TranslateInfoBarDelegate::CreateInfoBar() { |
| 109 NOTREACHED(); |
| 110 return NULL; |
| 111 } |
| 112 |
| 113 // TranslateInfoBarDelegate views specific method: |
| 114 InfoBar* TranslateInfoBarDelegate2::CreateInfoBar() { |
| 115 TranslateInfoBarControllerBase* infobar_controller = NULL; |
| 116 switch (type_) { |
| 117 case BEFORE_TRANSLATE: |
| 118 infobar_controller = |
| 119 [[BeforeTranslateInfobarController alloc] initWithDelegate:this]; |
| 120 break; |
| 121 case AFTER_TRANSLATE: |
| 122 infobar_controller = |
| 123 [[AfterTranslateInfobarController alloc] initWithDelegate:this]; |
| 124 break; |
| 125 case TRANSLATING: |
| 126 case TRANSLATION_ERROR: |
| 127 infobar_controller = |
| 128 [[TranslateMessageInfobarController alloc] initWithDelegate:this]; |
| 129 break; |
| 130 default: |
| 131 NOTREACHED(); |
| 132 } |
| 133 return new InfoBar(infobar_controller); |
| 134 } |
| 135 |
| 136 @interface TranslateInfoBarControllerBase (Private) |
| 137 |
| 138 // Removes all controls so that layout can add in only the controls |
| 139 // required. |
| 140 - (void)clearAllControls; |
| 141 |
| 142 // Create all the various controls we need for the toolbar. |
| 143 - (void)constructViews; |
| 144 |
| 145 // Reloads text for all labels for the current state. |
| 146 - (void)loadLabelText:(TranslateErrors::Type)error; |
| 147 |
| 148 // Makes the infobar grey. |
| 149 - (void)setInfoBarGradientColor; |
| 150 |
| 151 // Main function to update the toolbar graphic state and data model after |
| 152 // the state has changed. |
| 153 // Controls are moved around as needed and visibility changed to match the |
| 154 // current state. |
| 155 - (void)updateState; |
| 156 |
| 157 // Called when the source or target language selection changes in a menu. |
| 158 // |newLanguageIdx| is the index of the newly selected item in the appropriate |
| 159 // menu. |
| 160 - (void)sourceLanguageModified:(NSInteger)newLanguageIdx; |
| 161 - (void)targetLanguageModified:(NSInteger)newLanguageIdx; |
| 162 |
| 163 // Completely rebuild "from" and "to" language menus from the data model. |
| 164 - (void)populateLanguageMenus; |
| 165 |
| 166 @end |
| 167 |
| 168 #pragma mark TranslateInfoBarController class |
| 169 |
| 170 @implementation TranslateInfoBarControllerBase |
| 171 |
| 172 - (id)initWithDelegate:(InfoBarDelegate*)delegate { |
| 173 if ((self = [super initWithDelegate:delegate])) { |
| 174 originalLanguageMenuModel_.reset( |
| 175 new LanguagesMenuModel2([self delegate], |
| 176 LanguagesMenuModel2::ORIGINAL)); |
| 177 |
| 178 targetLanguageMenuModel_.reset( |
| 179 new LanguagesMenuModel2([self delegate], |
| 180 LanguagesMenuModel2::TARGET)); |
| 181 optionsMenuModel_.reset(new OptionsMenuModel2([self delegate])); |
| 182 } |
| 183 return self; |
| 184 } |
| 185 |
| 186 - (TranslateInfoBarDelegate2*)delegate { |
| 187 return reinterpret_cast<TranslateInfoBarDelegate2*>(delegate_); |
| 188 } |
| 189 |
| 190 - (void)constructViews { |
| 191 // Using a zero or very large frame causes GTMUILocalizerAndLayoutTweaker |
| 192 // to not resize the view properly so we take the bounds of the first label |
| 193 // which is contained in the nib. |
| 194 NSRect bogusFrame = [label_ frame]; |
| 195 label1_.reset(CreateLabel(bogusFrame)); |
| 196 label2_.reset(CreateLabel(bogusFrame)); |
| 197 label3_.reset(CreateLabel(bogusFrame)); |
| 198 |
| 199 optionsPopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame |
| 200 pullsDown:YES]); |
| 201 fromLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame |
| 202 pullsDown:NO]); |
| 203 toLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame |
| 204 pullsDown:NO]); |
| 205 showOriginalButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]); |
| 206 tryAgainButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]); |
| 207 } |
| 208 |
| 209 - (void)sourceLanguageModified:(NSInteger)newLanguageIdx { |
| 210 DCHECK_GT(newLanguageIdx, -1); |
| 211 if (newLanguageIdx == [self delegate]->original_language_index()) |
| 212 return; |
| 213 [self delegate]->SetOriginalLanguage(newLanguageIdx); |
| 214 int commandId = IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + newLanguageIdx; |
| 215 int newMenuIdx = [fromLanguagePopUp_ indexOfItemWithTag:commandId]; |
| 216 [fromLanguagePopUp_ selectItemAtIndex:newMenuIdx]; |
| 217 } |
| 218 |
| 219 - (void)targetLanguageModified:(NSInteger)newLanguageIdx { |
| 220 DCHECK_GT(newLanguageIdx, -1); |
| 221 if (newLanguageIdx == [self delegate]->target_language_index()) |
| 222 return; |
| 223 [self delegate]->SetTargetLanguage(newLanguageIdx); |
| 224 int commandId = IDC_TRANSLATE_TARGET_LANGUAGE_BASE + newLanguageIdx; |
| 225 int newMenuIdx = [toLanguagePopUp_ indexOfItemWithTag:commandId]; |
| 226 [toLanguagePopUp_ selectItemAtIndex:newMenuIdx]; |
| 227 } |
| 228 |
| 229 - (void)loadLabelText { |
| 230 // Do nothing by default, should be implemented by subclasses. |
| 231 } |
| 232 |
| 233 - (void)updateState { |
| 234 [self loadLabelText]; |
| 235 [self clearAllControls]; |
| 236 [self showVisibleControls:[self visibleControls]]; |
| 237 [self layout]; |
| 238 } |
| 239 |
| 240 - (void)setInfoBarGradientColor { |
| 241 // Use grey gradient for the infobars. |
| 242 NSColor* startingColor = |
| 243 [NSColor colorWithCalibratedRed:kGreyTopColor[0] / 255.0 |
| 244 green:kGreyTopColor[1] / 255.0 |
| 245 blue:kGreyTopColor[2] / 255.0 |
| 246 alpha:1.0]; |
| 247 NSColor* endingColor = |
| 248 [NSColor colorWithCalibratedRed:kGreyBottomColor[0] / 255.0 |
| 249 green:kGreyBottomColor[1] / 255.0 |
| 250 blue:kGreyBottomColor[2] / 255.0 |
| 251 alpha:1.0]; |
| 252 NSGradient* translateInfoBarGradient = |
| 253 [[[NSGradient alloc] initWithStartingColor:startingColor |
| 254 endingColor:endingColor] autorelease]; |
| 255 |
| 256 [infoBarView_ setGradient:translateInfoBarGradient]; |
| 257 } |
| 258 |
| 259 - (void)removeOkCancelButtons { |
| 260 // Removing okButton_ & cancelButton_ from the view may cause them |
| 261 // to be released and since we can still access them from other areas |
| 262 // in the code later, we need them to be nil when this happens. |
| 263 [okButton_ removeFromSuperview]; |
| 264 okButton_ = nil; |
| 265 [cancelButton_ removeFromSuperview]; |
| 266 cancelButton_ = nil; |
| 267 } |
| 268 |
| 269 - (void)clearAllControls { |
| 270 // Step 1: remove all controls from the infobar so we have a clean slate. |
| 271 NSArray *allControls = [NSArray arrayWithObjects:label2_.get(), label3_.get(), |
| 272 fromLanguagePopUp_.get(), toLanguagePopUp_.get(), |
| 273 showOriginalButton_.get(), tryAgainButton_.get(), nil]; |
| 274 |
| 275 for (NSControl* control in allControls) { |
| 276 if ([control superview]) |
| 277 [control removeFromSuperview]; |
| 278 } |
| 279 } |
| 280 |
| 281 - (void)showVisibleControls:(NSArray*)visibleControls { |
| 282 NSRect optionsFrame = [optionsPopUp_ frame]; |
| 283 for (NSControl* control in visibleControls) { |
| 284 [GTMUILocalizerAndLayoutTweaker sizeToFitView:control]; |
| 285 [control setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin | |
| 286 NSViewMaxYMargin]; |
| 287 |
| 288 // Need to check if a view is already attached since |label1_| is always |
| 289 // parented and we don't want to add it again. |
| 290 if (![control superview]) |
| 291 [infoBarView_ addSubview:control]; |
| 292 |
| 293 if ([control isKindOfClass:[NSButton class]]) |
| 294 VerticallyCenterView(control); |
| 295 |
| 296 // Make "from" and "to" language popup menus the same size as the options |
| 297 // menu. |
| 298 // We don't autosize since some languages names are really long causing |
| 299 // the toolbar to overflow. |
| 300 if ([control isKindOfClass:[NSPopUpButton class]]) |
| 301 [control setFrame:optionsFrame]; |
| 302 } |
| 303 } |
| 304 |
| 305 - (void)layout { |
| 306 |
| 307 } |
| 308 |
| 309 - (NSArray*)visibleControls { |
| 310 return [NSArray array]; |
| 311 } |
| 312 |
| 313 - (void) rebuildOptionsMenu { |
| 314 // The options model doesn't know how to handle state transitions, so rebuild |
| 315 // it each time through here. |
| 316 optionsMenuModel_.reset( |
| 317 new OptionsMenuModel2([self delegate])); |
| 318 |
| 319 [optionsPopUp_ removeAllItems]; |
| 320 // Set title. |
| 321 NSString* optionsLabel = |
| 322 l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_OPTIONS); |
| 323 [optionsPopUp_ addItemWithTitle:optionsLabel]; |
| 324 |
| 325 // Populate options menu. |
| 326 NSMenu* optionsMenu = [optionsPopUp_ menu]; |
| 327 [optionsMenu setAutoenablesItems:NO]; |
| 328 for (int i = 0; i < optionsMenuModel_->GetItemCount(); ++i) { |
| 329 NSString* title = base::SysUTF16ToNSString( |
| 330 optionsMenuModel_->GetLabelAt(i)); |
| 331 int cmd = optionsMenuModel_->GetCommandIdAt(i); |
| 332 bool checked = optionsMenuModel_->IsItemCheckedAt(i); |
| 333 bool enabled = optionsMenuModel_->IsEnabledAt(i); |
| 334 AddMenuItem(optionsMenu, |
| 335 self, |
| 336 @selector(optionsMenuChanged:), |
| 337 title, |
| 338 cmd, |
| 339 enabled, |
| 340 checked); |
| 341 } |
| 342 } |
| 343 |
| 344 - (void)populateLanguageMenus { |
| 345 NSMenu* originalLanguageMenu = [fromLanguagePopUp_ menu]; |
| 346 [originalLanguageMenu setAutoenablesItems:NO]; |
| 347 int selectedMenuIndex = 0; |
| 348 int selectedLangIndex = [self delegate]->original_language_index(); |
| 349 for (int i = 0; i < originalLanguageMenuModel_->GetItemCount(); ++i) { |
| 350 NSString* title = base::SysUTF16ToNSString( |
| 351 originalLanguageMenuModel_->GetLabelAt(i)); |
| 352 int cmd = originalLanguageMenuModel_->GetCommandIdAt(i); |
| 353 bool checked = (cmd == selectedLangIndex); |
| 354 if (checked) |
| 355 selectedMenuIndex = i; |
| 356 bool enabled = originalLanguageMenuModel_->IsEnabledAt(i); |
| 357 cmd += IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE; |
| 358 AddMenuItem(originalLanguageMenu, |
| 359 self, |
| 360 @selector(languageMenuChanged:), |
| 361 title, |
| 362 cmd, |
| 363 enabled, |
| 364 checked); |
| 365 } |
| 366 [fromLanguagePopUp_ selectItemAtIndex:selectedMenuIndex]; |
| 367 |
| 368 NSMenu* targetLanguageMenu = [toLanguagePopUp_ menu]; |
| 369 [targetLanguageMenu setAutoenablesItems:NO]; |
| 370 selectedLangIndex = [self delegate]->target_language_index(); |
| 371 for (int i = 0; i < targetLanguageMenuModel_->GetItemCount(); ++i) { |
| 372 NSString* title = base::SysUTF16ToNSString( |
| 373 targetLanguageMenuModel_->GetLabelAt(i)); |
| 374 int cmd = targetLanguageMenuModel_->GetCommandIdAt(i); |
| 375 bool checked = (cmd == selectedLangIndex); |
| 376 if (checked) |
| 377 selectedMenuIndex = i; |
| 378 bool enabled = targetLanguageMenuModel_->IsEnabledAt(i); |
| 379 cmd += IDC_TRANSLATE_TARGET_LANGUAGE_BASE; |
| 380 AddMenuItem(targetLanguageMenu, |
| 381 self, |
| 382 @selector(languageMenuChanged:), |
| 383 title, |
| 384 cmd, |
| 385 enabled, |
| 386 checked); |
| 387 } |
| 388 [toLanguagePopUp_ selectItemAtIndex:selectedMenuIndex]; |
| 389 } |
| 390 |
| 391 - (void)addAdditionalControls { |
| 392 using l10n_util::GetNSString; |
| 393 using l10n_util::GetNSStringWithFixup; |
| 394 |
| 395 // Get layout information from the NIB. |
| 396 NSRect okButtonFrame = [okButton_ frame]; |
| 397 NSRect cancelButtonFrame = [cancelButton_ frame]; |
| 398 spaceBetweenControls_ = NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame); |
| 399 |
| 400 // Set infobar background color. |
| 401 [self setInfoBarGradientColor]; |
| 402 |
| 403 // Instantiate additional controls. |
| 404 [self constructViews]; |
| 405 |
| 406 // Set ourselves as the delegate for the options menu so we can populate it |
| 407 // dynamically. |
| 408 [[optionsPopUp_ menu] setDelegate:self]; |
| 409 |
| 410 // Replace label_ with label1_ so we get a consistent look between all the |
| 411 // labels we display in the translate view. |
| 412 [[label_ superview] replaceSubview:label_ with:label1_.get()]; |
| 413 label_.reset(); // Now released. |
| 414 |
| 415 // Populate contextual menus. |
| 416 [self rebuildOptionsMenu]; |
| 417 [self populateLanguageMenus]; |
| 418 |
| 419 // Set OK & Cancel text. |
| 420 [okButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_ACCEPT)]; |
| 421 [cancelButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_DENY)]; |
| 422 |
| 423 // Set up "Show original" and "Try again" buttons. |
| 424 [showOriginalButton_ setBezelStyle:NSRoundRectBezelStyle]; |
| 425 [showOriginalButton_ setFrame:okButtonFrame]; |
| 426 [tryAgainButton_ setBezelStyle:NSRoundRectBezelStyle]; |
| 427 [tryAgainButton_ setFrame:okButtonFrame]; |
| 428 |
| 429 [showOriginalButton_ setTarget:self]; |
| 430 [showOriginalButton_ setAction:@selector(showOriginal:)]; |
| 431 [tryAgainButton_ setTarget:self]; |
| 432 [tryAgainButton_ setAction:@selector(ok:)]; |
| 433 |
| 434 [showOriginalButton_ |
| 435 setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_REVERT)]; |
| 436 [tryAgainButton_ |
| 437 setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_RETRY)]; |
| 438 |
| 439 // Add and configure controls that are visible in all modes. |
| 440 [optionsPopUp_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin | |
| 441 NSViewMaxYMargin]; |
| 442 // Add "options" popup z-ordered below all other controls so when we |
| 443 // resize the toolbar it doesn't hide them. |
| 444 [infoBarView_ addSubview:optionsPopUp_ |
| 445 positioned:NSWindowBelow |
| 446 relativeTo:nil]; |
| 447 [GTMUILocalizerAndLayoutTweaker sizeToFitView:optionsPopUp_]; |
| 448 MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false); |
| 449 VerticallyCenterView(optionsPopUp_); |
| 450 |
| 451 // Show and place GUI elements. |
| 452 [self updateState]; |
| 453 } |
| 454 |
| 455 // Called when "Translate" button is clicked. |
| 456 - (IBAction)ok:(id)sender { |
| 457 TranslateInfoBarDelegate2* delegate = [self delegate]; |
| 458 TranslateInfoBarDelegate2::Type state = delegate->type(); |
| 459 DCHECK(state == TranslateInfoBarDelegate2::BEFORE_TRANSLATE || |
| 460 state == TranslateInfoBarDelegate2::TRANSLATION_ERROR); |
| 461 delegate->Translate(); |
| 462 UMA_HISTOGRAM_COUNTS("Translate.Translate", 1); |
| 463 } |
| 464 |
| 465 // Called when someone clicks on the "Nope" button. |
| 466 - (IBAction)cancel:(id)sender { |
| 467 DCHECK( |
| 468 [self delegate]->type() == TranslateInfoBarDelegate2::BEFORE_TRANSLATE); |
| 469 [self delegate]->TranslationDeclined(); |
| 470 UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslate", 1); |
| 471 [super dismiss:nil]; |
| 472 } |
| 473 |
| 474 - (IBAction)showOriginal:(id)sender { |
| 475 [self delegate]->RevertTranslation(); |
| 476 } |
| 477 |
| 478 // Called when any of the language drop down menus are changed. |
| 479 - (void)languageMenuChanged:(id)item { |
| 480 if ([item respondsToSelector:@selector(tag)]) { |
| 481 int cmd = [item tag]; |
| 482 if (cmd >= IDC_TRANSLATE_TARGET_LANGUAGE_BASE) { |
| 483 cmd -= IDC_TRANSLATE_TARGET_LANGUAGE_BASE; |
| 484 [self targetLanguageModified:cmd]; |
| 485 return; |
| 486 } else if (cmd >= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) { |
| 487 cmd -= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE; |
| 488 [self sourceLanguageModified:cmd]; |
| 489 return; |
| 490 } |
| 491 } |
| 492 NOTREACHED() << "Language menu was changed with a bad language ID"; |
| 493 } |
| 494 |
| 495 // Called when the options menu is changed. |
| 496 - (void)optionsMenuChanged:(id)item { |
| 497 if ([item respondsToSelector:@selector(tag)]) { |
| 498 int cmd = [item tag]; |
| 499 // Danger Will Robinson! : This call can release the infobar (e.g. invoking |
| 500 // "About Translate" can open a new tab). |
| 501 // Do not access member variables after this line! |
| 502 optionsMenuModel_->ExecuteCommand(cmd); |
| 503 } else { |
| 504 NOTREACHED(); |
| 505 } |
| 506 } |
| 507 |
| 508 #pragma mark NSMenuDelegate |
| 509 |
| 510 // Invoked by virtue of us being set as the delegate for the options menu. |
| 511 - (void)menuNeedsUpdate:(NSMenu *)menu { |
| 512 [self rebuildOptionsMenu]; |
| 513 } |
| 514 |
| 515 @end |
| 516 |
| 517 @implementation TranslateInfoBarControllerBase (TestingAPI) |
| 518 |
| 519 - (NSMenu*)optionsMenu { |
| 520 return [optionsPopUp_ menu]; |
| 521 } |
| 522 |
| 523 - (NSButton*)tryAgainButton { |
| 524 return tryAgainButton_.get(); |
| 525 } |
| 526 |
| 527 - (bool)verifyLayout { |
| 528 // All the controls available to translate infobars, except the options popup. |
| 529 // The options popup is shown/hidden instead of actually removed. This gets |
| 530 // checked in the subclasses. |
| 531 NSArray* allControls = [NSArray arrayWithObjects:label1_.get(), |
| 532 fromLanguagePopUp_.get(), label2_.get(), toLanguagePopUp_.get(), |
| 533 label3_.get(), showOriginalButton_.get(), tryAgainButton_.get(), nil]; |
| 534 NSArray* visibleControls = [self visibleControls]; |
| 535 |
| 536 // Step 1: Make sure control visibility is what we expect. |
| 537 for (NSUInteger i = 0; i < [allControls count]; ++i) { |
| 538 id control = [allControls objectAtIndex:i]; |
| 539 bool hasSuperView = [control superview]; |
| 540 bool expectedVisibility = [visibleControls containsObject:control]; |
| 541 |
| 542 if (expectedVisibility != hasSuperView) { |
| 543 NSString *title = @""; |
| 544 if ([control isKindOfClass:[NSPopUpButton class]]) { |
| 545 title = [[[control menu] itemAtIndex:0] title]; |
| 546 } |
| 547 |
| 548 LOG(ERROR) << |
| 549 "State: " << [self description] << |
| 550 " Control @" << i << (hasSuperView ? " has" : " doesn't have") << |
| 551 " a superview" << [[control description] UTF8String] << |
| 552 " Title=" << [title UTF8String]; |
| 553 return false; |
| 554 } |
| 555 } |
| 556 |
| 557 // Step 2: Check that controls are ordered correctly with no overlap. |
| 558 id previousControl = nil; |
| 559 for (NSUInteger i = 0; i < [visibleControls count]; ++i) { |
| 560 id control = [visibleControls objectAtIndex:i]; |
| 561 if (previousControl && !VerifyControlOrderAndSpacing(previousControl, contro
l)) { |
| 562 NSString *title = @""; |
| 563 if ([control isKindOfClass:[NSPopUpButton class]]) { |
| 564 title = [[[control menu] itemAtIndex:0] title]; |
| 565 } |
| 566 LOG(ERROR) << |
| 567 "State: " << [self description] << |
| 568 " Control @" << i << " not ordered correctly: " << |
| 569 [[control description] UTF8String] <<[title UTF8String]; |
| 570 return false; |
| 571 } |
| 572 previousControl = control; |
| 573 } |
| 574 |
| 575 return true; |
| 576 } |
| 577 |
| 578 @end // TranslateInfoBarControllerBase (TestingAPI) |
| 579 |
OLD | NEW |