Extract code handling PrinterProviderAPI from PrintPreviewHandler
[chromium-blink-merge.git] / ios / chrome / browser / translate / before_translate_infobar_controller.mm
blob8b98d4b830151e9e8c429752dffed19b19528cf5
1 // Copyright 2013 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.
5 #include "ios/chrome/browser/translate/before_translate_infobar_controller.h"
7 #import <UIKit/UIKit.h>
9 #include "base/logging.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/translate/core/browser/translate_infobar_delegate.h"
13 #include "grit/components_strings.h"
14 #include "ios/chrome/browser/translate/translate_infobar_tags.h"
15 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
16 #import "ios/public/provider/chrome/browser/ui/infobar_view_delegate.h"
17 #import "ios/public/provider/chrome/browser/ui/infobar_view_protocol.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/gfx/image/image.h"
21 namespace {
23 CGFloat kNavigationBarHeight = 44;
24 CGFloat kUIPickerHeight = 216;
25 CGFloat kUIPickerFontSize = 26;
26 NSTimeInterval kPickerAnimationDurationInSeconds = 0.2;
28 }  // namespace
30 // The class is a data source and delegate to the UIPickerView that contains the
31 // language list.
32 @interface LanguagePickerController
33     : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate> {
34   __weak translate::TranslateInfoBarDelegate* _translateInfoBarDelegate;
35   NSInteger _initialRow;   // Displayed in bold font.
36   NSInteger _disabledRow;  // Grayed out.
38 @end
40 @implementation LanguagePickerController
42 - (instancetype)initWithDelegate:(translate::TranslateInfoBarDelegate*)
43                                      translateInfoBarDelegate
44                       initialRow:(NSInteger)initialRow
45                      disabledRow:(NSInteger)disabledRow {
46   if ((self = [super init])) {
47     _translateInfoBarDelegate = translateInfoBarDelegate;
48     _initialRow = initialRow;
49     _disabledRow = disabledRow;
50   }
51   return self;
54 #pragma mark -
55 #pragma mark UIPickerViewDataSource
57 - (NSInteger)pickerView:(UIPickerView*)pickerView
58     numberOfRowsInComponent:(NSInteger)component {
59   NSUInteger numRows = _translateInfoBarDelegate->num_languages();
60   return numRows;
63 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView {
64   return 1;
67 #pragma mark -
68 #pragma mark UIPickerViewDelegate
70 - (UIView*)pickerView:(UIPickerView*)pickerView
71            viewForRow:(NSInteger)row
72          forComponent:(NSInteger)component
73           reusingView:(UIView*)view {
74   DCHECK_EQ(0, component);
75   UILabel* label = [view isKindOfClass:[UILabel class]]
76                        ? (UILabel*)view
77                        : [[[UILabel alloc] init] autorelease];
78   [label setText:base::SysUTF16ToNSString(
79                      _translateInfoBarDelegate->language_name_at(row))];
80   [label setTextAlignment:NSTextAlignmentCenter];
81   UIFont* font = [UIFont systemFontOfSize:kUIPickerFontSize];
82   BOOL enabled = YES;
83   if (row == _initialRow)
84     font = [UIFont boldSystemFontOfSize:kUIPickerFontSize];
85   else if (row == _disabledRow)
86     enabled = NO;
87   [label setFont:font];
88   [label setEnabled:enabled];
89   return label;
92 @end
94 @interface BeforeTranslateInfoBarController ()
96 // Action for any of the user defined buttons.
97 - (void)infoBarButtonDidPress:(id)sender;
98 // Action for any of the user defined links.
99 - (void)infobarLinkDidPress:(NSNumber*)tag;
100 // Action for the language selection "Done" button.
101 - (void)languageSelectionDone;
102 // Dismisses the language selection view.
103 - (void)dismissLanguageSelectionView;
105 @end
107 @implementation BeforeTranslateInfoBarController {
108   __weak translate::TranslateInfoBarDelegate* _translateInfoBarDelegate;
109   // A fullscreen view that catches all touch events and contains a UIPickerView
110   // and a UINavigationBar.
111   base::scoped_nsobject<UIView> _languageSelectionView;
112   // Stores whether the user is currently choosing in the UIPickerView the
113   // original language, or the target language.
114   NSUInteger _languageSelectionType;
115   // The language picker.
116   base::scoped_nsobject<UIPickerView> _languagePicker;
117   // Navigation bar associated with the picker with "Done" and "Cancel" buttons.
118   base::scoped_nsobject<UINavigationBar> _navigationBar;
119   // The controller of the languagePicker. Needs to be an ivar because
120   // |_languagePicker| does not retain it.
121   base::scoped_nsobject<LanguagePickerController> _languagePickerController;
124 #pragma mark -
125 #pragma mark InfoBarControllerProtocol
127 - (void)layoutForDelegate:(infobars::InfoBarDelegate*)delegate
128                     frame:(CGRect)frame {
129   _translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate();
130   infobars::InfoBarDelegate* infoBarDelegate =
131       static_cast<infobars::InfoBarDelegate*>(_translateInfoBarDelegate);
132   DCHECK(!infoBarView_);
133   infoBarView_.reset([ios::GetChromeBrowserProvider()->CreateInfoBarView()
134       initWithFrame:frame
135            delegate:delegate_
136           isWarning:infoBarDelegate->GetInfoBarType() ==
137                     infobars::InfoBarDelegate::WARNING_TYPE]);
138   // Icon
139   gfx::Image icon = _translateInfoBarDelegate->GetIcon();
140   if (!icon.IsEmpty())
141     [infoBarView_ addLeftIcon:icon.ToUIImage()];
143   // Main text.
144   [self updateInfobarLabel];
146   // Close button.
147   [infoBarView_ addCloseButtonWithTag:TranslateInfoBarIOSTag::BEFORE_DENY
148                                target:self
149                                action:@selector(infoBarButtonDidPress:)];
150   // Other buttons.
151   NSString* buttonAccept = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_ACCEPT);
152   NSString* buttonDeny = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_DENY);
153   [infoBarView_ addButton1:buttonAccept
154                       tag1:TranslateInfoBarIOSTag::BEFORE_ACCEPT
155                    button2:buttonDeny
156                       tag2:TranslateInfoBarIOSTag::BEFORE_DENY
157                     target:self
158                     action:@selector(infoBarButtonDidPress:)];
161 - (void)updateInfobarLabel {
162   NSString* originalLanguage =
163       base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
164           _translateInfoBarDelegate->original_language_index()));
165   NSString* targetLanguage =
166       base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
167           _translateInfoBarDelegate->target_language_index()));
168   base::string16 originalLanguageWithLink =
169       base::SysNSStringToUTF16([[infoBarView_ class]
170           stringAsLink:originalLanguage
171                    tag:TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE]);
172   base::string16 targetLanguageWithLink =
173       base::SysNSStringToUTF16([[infoBarView_ class]
174           stringAsLink:targetLanguage
175                    tag:TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE]);
176   NSString* label =
177       l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_IOS,
178                               originalLanguageWithLink, targetLanguageWithLink);
179   [infoBarView_ addLabel:label
180                   target:self
181                   action:@selector(infobarLinkDidPress:)];
184 - (void)languageSelectionDone {
185   size_t selectedRow = [_languagePicker selectedRowInComponent:0];
186   if (_languageSelectionType ==
187           TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE &&
188       selectedRow != _translateInfoBarDelegate->target_language_index()) {
189     _translateInfoBarDelegate->UpdateOriginalLanguageIndex(selectedRow);
190   }
191   if (_languageSelectionType ==
192           TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE &&
193       selectedRow != _translateInfoBarDelegate->original_language_index()) {
194     _translateInfoBarDelegate->UpdateTargetLanguageIndex(selectedRow);
195   }
196   [self updateInfobarLabel];
197   [self dismissLanguageSelectionView];
200 - (void)dismissLanguageSelectionView {
201   DCHECK_EQ(_languagePicker == nil, _navigationBar == nil);
202   if (_languagePicker == nil)
203     return;
204   // Sets the picker's delegate and data source to nil, because the
205   // |_languagePickerController| may be destroyed before the picker is hidden,
206   // and even though the interactions with the picker are disabled, it might
207   // still be turning and requesting data from the data source or calling the
208   // delegate.
209   [_languagePicker setDataSource:nil];
210   [_languagePicker setDelegate:nil];
211   _languagePickerController.reset();
212   // Animate the picker away.
213   CGRect languagePickerFrame = [_languagePicker frame];
214   CGRect navigationBarFrame = [_navigationBar frame];
215   const CGFloat animationHeight =
216       languagePickerFrame.size.height + navigationBarFrame.size.height;
217   languagePickerFrame.origin.y += animationHeight;
218   navigationBarFrame.origin.y += animationHeight;
219   auto blockLanguagePicker(_languagePicker);
220   auto blockNavigationBar(_navigationBar);
221   _languagePicker.reset();
222   _navigationBar.reset();
223   void (^animations)(void) = ^{
224     blockLanguagePicker.get().frame = languagePickerFrame;
225     blockNavigationBar.get().frame = navigationBarFrame;
226   };
227   auto blockSelectionView(_languageSelectionView);
228   _languageSelectionView.reset();
229   void (^completion)(BOOL finished) = ^(BOOL finished) {
230     [blockSelectionView removeFromSuperview];
231   };
232   [UIView animateWithDuration:kPickerAnimationDurationInSeconds
233                    animations:animations
234                    completion:completion];
237 #pragma mark - Handling of User Events
239 - (void)infoBarButtonDidPress:(id)sender {
240   // This press might have occurred after the user has already pressed a button,
241   // in which case the view has been detached from the delegate and this press
242   // should be ignored.
243   if (!delegate_) {
244     return;
245   }
246   if ([sender isKindOfClass:[UIButton class]]) {
247     NSUInteger buttonId = static_cast<UIButton*>(sender).tag;
248     DCHECK(buttonId == TranslateInfoBarIOSTag::BEFORE_ACCEPT ||
249            buttonId == TranslateInfoBarIOSTag::BEFORE_DENY);
250     delegate_->InfoBarButtonDidPress(buttonId);
251   }
254 - (void)infobarLinkDidPress:(NSNumber*)tag {
255   DCHECK([tag isKindOfClass:[NSNumber class]]);
256   _languageSelectionType = [tag unsignedIntegerValue];
257   DCHECK(_languageSelectionType ==
258              TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE ||
259          _languageSelectionType ==
260              TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE);
261   if (_languagePicker != nil)
262     return;  // The UIPickerView is already up.
264   // Creates and adds the view containing the UIPickerView and the
265   // UINavigationBar.
266   UIView* parentView =
267       [[UIApplication sharedApplication] keyWindow].rootViewController.view;
268   // Convert the parent frame to handle device rotation.
269   CGRect parentFrame =
270       CGRectApplyAffineTransform([parentView frame], [parentView transform]);
271   const CGFloat totalPickerHeight = kUIPickerHeight + kNavigationBarHeight;
272   CGRect languageSelectionViewFrame =
273       CGRectMake(0, parentFrame.size.height - totalPickerHeight,
274                  parentFrame.size.width, totalPickerHeight);
275   _languageSelectionView.reset(
276       [[UIView alloc] initWithFrame:languageSelectionViewFrame]);
277   [_languageSelectionView
278       setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
279                           UIViewAutoresizingFlexibleTopMargin];
280   [parentView addSubview:_languageSelectionView];
282   // Creates the navigation bar and its buttons.
283   CGRect finalPickerFrame = CGRectMake(
284       0, [_languageSelectionView frame].size.height - kUIPickerHeight,
285       [_languageSelectionView frame].size.width, kUIPickerHeight);
286   CGRect finalNavigationBarFrame = CGRectMake(
287       0, 0, [_languageSelectionView frame].size.width, kNavigationBarHeight);
288   // The language picker animates from the bottom of the screen.
289   CGRect initialPickerFrame = finalPickerFrame;
290   initialPickerFrame.origin.y += totalPickerHeight;
291   CGRect initialNavigationBarFrame = finalNavigationBarFrame;
292   initialNavigationBarFrame.origin.y += totalPickerHeight;
294   _navigationBar.reset(
295       [[UINavigationBar alloc] initWithFrame:initialNavigationBarFrame]);
296   const UIViewAutoresizing resizingMask =
297       UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
298   [_navigationBar setAutoresizingMask:resizingMask];
299   base::scoped_nsobject<UIBarButtonItem> doneButton([[UIBarButtonItem alloc]
300       initWithBarButtonSystemItem:UIBarButtonSystemItemDone
301                            target:self
302                            action:@selector(languageSelectionDone)]);
303   base::scoped_nsobject<UIBarButtonItem> cancelButton([[UIBarButtonItem alloc]
304       initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
305                            target:self
306                            action:@selector(dismissLanguageSelectionView)]);
307   base::scoped_nsobject<UINavigationItem> item(
308       [[UINavigationItem alloc] initWithTitle:nil]);
309   [item setRightBarButtonItem:doneButton];
310   [item setLeftBarButtonItem:cancelButton];
311   [item setHidesBackButton:YES];
312   [_navigationBar pushNavigationItem:item animated:NO];
314   // Creates the PickerView and its controller.
315   NSInteger selectedRow;
316   NSInteger disabledRow;
317   if (_languageSelectionType ==
318       TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE) {
319     selectedRow = _translateInfoBarDelegate->original_language_index();
320     disabledRow = _translateInfoBarDelegate->target_language_index();
321   } else {
322     selectedRow = _translateInfoBarDelegate->target_language_index();
323     disabledRow = _translateInfoBarDelegate->original_language_index();
324   }
325   _languagePickerController.reset([[LanguagePickerController alloc]
326       initWithDelegate:_translateInfoBarDelegate
327             initialRow:selectedRow
328            disabledRow:disabledRow]);
329   _languagePicker.reset(
330       [[UIPickerView alloc] initWithFrame:initialPickerFrame]);
331   [_languagePicker setAutoresizingMask:resizingMask];
332   [_languagePicker setShowsSelectionIndicator:YES];
333   [_languagePicker setDataSource:_languagePickerController];
334   [_languagePicker setDelegate:_languagePickerController];
335   [_languagePicker setShowsSelectionIndicator:YES];
336   [_languagePicker setBackgroundColor:[infoBarView_ backgroundColor]];
337   [_languagePicker selectRow:selectedRow inComponent:0 animated:NO];
339   auto blockLanguagePicker(_languagePicker);
340   auto blockNavigationBar(_navigationBar);
341   [UIView animateWithDuration:kPickerAnimationDurationInSeconds
342                    animations:^{
343                      blockLanguagePicker.get().frame = finalPickerFrame;
344                      blockNavigationBar.get().frame = finalNavigationBarFrame;
345                    }];
347   // Add the subviews.
348   [_languageSelectionView addSubview:_languagePicker];
349   [_languageSelectionView addSubview:_navigationBar];
352 - (void)removeView {
353   [super removeView];
354   [self dismissLanguageSelectionView];
357 - (void)detachView {
358   [super detachView];
359   [self dismissLanguageSelectionView];
362 @end