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

Side by Side Diff: chrome/browser/cocoa/translate/translate_infobar_base.mm

Issue 2815013: Refactor the translate infobars on mac to match the new windows code. (Closed)
Patch Set: Move unittest stuff back to class files Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/translate/translate_infobar_base.h ('k') | chrome/browser/cocoa/translate/translate_infobar_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698