1// Copyright 2018 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 "ios/chrome/browser/ui/translate/legacy_translate_infobar_mediator.h"
6
7#include <memory>
8
9#include "base/check.h"
10#include "base/scoped_observer.h"
11#include "base/strings/sys_string_conversions.h"
12#include "components/strings/grit/components_strings.h"
13#include "components/translate/core/browser/translate_infobar_delegate.h"
14#include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
15#import "ios/chrome/browser/translate/language_selection_context.h"
16#import "ios/chrome/browser/translate/language_selection_handler.h"
17#import "ios/chrome/browser/translate/translate_option_selection_handler.h"
18#import "ios/chrome/browser/ui/list_model/list_model.h"
19#import "ios/chrome/browser/ui/popup_menu/public/popup_menu_consumer.h"
20#import "ios/chrome/browser/ui/translate/cells/select_language_popup_menu_item.h"
21#import "ios/chrome/browser/ui/translate/cells/translate_popup_menu_item.h"
22#import "ios/chrome/browser/ui/translate/translate_notification_handler.h"
23#import "ios/chrome/browser/web_state_list/web_state_list.h"
24#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
25#include "ui/base/l10n/l10n_util.h"
26
27#if !defined(__has_feature) || !__has_feature(objc_arc)
28#error "This file requires ARC support."
29#endif
30
31@interface LegacyTranslateInfobarMediator () <WebStateListObserving> {
32  // WebStateList observers.
33  std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge;
34  std::unique_ptr<ScopedObserver<WebStateList, WebStateListObserver>>
35      _scopedWebStateListObserver;
36}
37
38// Presents and dismisses the language selection UI as well as the translate
39// option selection UI.
40@property(nonatomic, weak)
41    id<LanguageSelectionHandler, TranslateOptionSelectionHandler>
42        selectionHandler;
43
44// Presents and dismisses translate related notification UI.
45@property(nonatomic, weak) id<TranslateNotificationHandler> notificationHandler;
46
47@end
48
49@implementation LegacyTranslateInfobarMediator
50
51- (instancetype)
52    initWithSelectionHandler:
53        (id<LanguageSelectionHandler, TranslateOptionSelectionHandler>)
54            selectionHandler
55         notificationHandler:
56             (id<TranslateNotificationHandler>)notificationHandler {
57  DCHECK(selectionHandler);
58  DCHECK(notificationHandler);
59  if ((self = [super init])) {
60    _selectionHandler = selectionHandler;
61    _notificationHandler = notificationHandler;
62  }
63  return self;
64}
65
66#pragma mark - Public methods
67
68- (void)disconnect {
69  self.webStateList = nil;
70}
71
72#pragma mark - Properties
73
74- (void)setWebStateList:(WebStateList*)webStateList {
75  if (_webStateList == webStateList)
76    return;
77
78  if (_webStateList) {
79    [self removeWebStateListObserver];
80
81    // Uninstall delegates for each WebState in WebStateList.
82    for (int i = 0; i < self.webStateList->count(); i++) {
83      [self uninstallDelegatesForWebState:self.webStateList->GetWebStateAt(i)];
84    }
85  }
86
87  _webStateList = webStateList;
88
89  if (_webStateList) {
90    // Install delegates for each WebState in WebStateList.
91    for (int i = 0; i < _webStateList->count(); i++) {
92      [self installDelegatesForWebState:_webStateList->GetWebStateAt(i)];
93    }
94
95    [self addWebStateListObserver];
96  }
97}
98
99- (void)setConsumer:(id<PopupMenuConsumer>)consumer {
100  _consumer = consumer;
101  [_consumer setPopupMenuItems:self.items];
102}
103
104#pragma mark - Private
105
106// Returns the menu items for either the language selection popup menu or the
107// translate option selection popup menu.
108- (NSArray<NSArray<TableViewItem<PopupMenuItem>*>*>*)items {
109  if (self.type == TranslatePopupMenuTypeLanguageSelection) {
110    return [self languageSelectionItems];
111  }
112  return [self translateOptionSelectionItems];
113}
114
115// Returns the menu items for the language selection popup menu.
116- (NSArray<NSArray<TableViewItem<PopupMenuItem>*>*>*)languageSelectionItems {
117  NSMutableArray* items = [NSMutableArray array];
118  for (size_t index = 0; index < self.infobarDelegate->num_languages();
119       index++) {
120    if (index == self.unavailableLanguageIndex)
121      continue;
122
123    SelectLanguagePopupMenuItem* item =
124        [[SelectLanguagePopupMenuItem alloc] initWithType:kItemTypeEnumZero];
125    item.actionIdentifier = PopupMenuActionSelectLanguage;
126    item.title =
127        base::SysUTF16ToNSString(self.infobarDelegate->language_name_at(index));
128    item.languageCode =
129        base::SysUTF8ToNSString(self.infobarDelegate->language_code_at(index));
130    [items addObject:item];
131  }
132
133  return @[ items ];
134}
135
136// Returns the menu items for the translate option selection popup menu.
137- (NSArray<NSArray<TableViewItem<PopupMenuItem>*>*>*)
138    translateOptionSelectionItems {
139  base::string16 originalLanguageName =
140      self.infobarDelegate->original_language_name();
141
142  TranslatePopupMenuItem* selectTargetLanguageItem =
143      [[TranslatePopupMenuItem alloc] initWithType:kItemTypeEnumZero];
144  selectTargetLanguageItem.actionIdentifier =
145      PopupMenuActionChangeTargetLanguage;
146  selectTargetLanguageItem.title = base::SysUTF16ToNSString(
147      l10n_util::GetStringUTF16(IDS_TRANSLATE_INFOBAR_OPTIONS_MORE_LANGUAGE));
148
149  TranslatePopupMenuItem* alwaysTranslateLanguageItem =
150      [[TranslatePopupMenuItem alloc] initWithType:kItemTypeEnumZero];
151  alwaysTranslateLanguageItem.actionIdentifier =
152      PopupMenuActionAlwaysTranslateSourceLanguage;
153  alwaysTranslateLanguageItem.title =
154      base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
155          IDS_TRANSLATE_INFOBAR_OPTIONS_ALWAYS, originalLanguageName));
156  alwaysTranslateLanguageItem.selected =
157      self.infobarDelegate->ShouldAlwaysTranslate();
158
159  TranslatePopupMenuItem* neverTranslateLanguageItem =
160      [[TranslatePopupMenuItem alloc] initWithType:kItemTypeEnumZero];
161  neverTranslateLanguageItem.actionIdentifier =
162      PopupMenuActionNeverTranslateSourceLanguage;
163  neverTranslateLanguageItem.title =
164      base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
165          IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_LANG,
166          originalLanguageName));
167
168  TranslatePopupMenuItem* neverTranslateSiteItem =
169      [[TranslatePopupMenuItem alloc] initWithType:kItemTypeEnumZero];
170  neverTranslateSiteItem.actionIdentifier = PopupMenuActionNeverTranslateSite;
171  neverTranslateSiteItem.title =
172      base::SysUTF16ToNSString(l10n_util::GetStringUTF16(
173          IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_SITE));
174
175  TranslatePopupMenuItem* selectSourceLanguageItem =
176      [[TranslatePopupMenuItem alloc] initWithType:kItemTypeEnumZero];
177  selectSourceLanguageItem.actionIdentifier =
178      PopupMenuActionChangeSourceLanguage;
179  selectSourceLanguageItem.title =
180      base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
181          IDS_TRANSLATE_INFOBAR_OPTIONS_NOT_SOURCE_LANGUAGE,
182          originalLanguageName));
183
184  return @[
185    @[ selectTargetLanguageItem ],
186    @[
187      alwaysTranslateLanguageItem, neverTranslateLanguageItem,
188      neverTranslateSiteItem, selectSourceLanguageItem
189    ]
190  ];
191}
192
193// Adds observer for WebStateList.
194- (void)addWebStateListObserver {
195  _webStateListObserverBridge =
196      std::make_unique<WebStateListObserverBridge>(self);
197  _scopedWebStateListObserver =
198      std::make_unique<ScopedObserver<WebStateList, WebStateListObserver>>(
199          _webStateListObserverBridge.get());
200  _scopedWebStateListObserver->Add(self.webStateList);
201}
202
203// Removes observer for WebStateList.
204- (void)removeWebStateListObserver {
205  _scopedWebStateListObserver.reset();
206  _webStateListObserverBridge.reset();
207}
208
209// Installs delegates for |webState|.
210- (void)installDelegatesForWebState:(web::WebState*)webState {
211  if (ChromeIOSTranslateClient::FromWebState(webState)) {
212    ChromeIOSTranslateClient::FromWebState(webState)
213        ->set_language_selection_handler(self.selectionHandler);
214    ChromeIOSTranslateClient::FromWebState(webState)
215        ->set_translate_option_selection_handler(self.selectionHandler);
216    ChromeIOSTranslateClient::FromWebState(webState)
217        ->set_translate_notification_handler(self.notificationHandler);
218  }
219}
220
221// Uninstalls delegates for |webState|.
222- (void)uninstallDelegatesForWebState:(web::WebState*)webState {
223  if (ChromeIOSTranslateClient::FromWebState(webState)) {
224    ChromeIOSTranslateClient::FromWebState(webState)
225        ->set_language_selection_handler(nil);
226    ChromeIOSTranslateClient::FromWebState(webState)
227        ->set_translate_option_selection_handler(nil);
228    ChromeIOSTranslateClient::FromWebState(webState)
229        ->set_translate_notification_handler(nil);
230  }
231}
232
233#pragma mark - WebStateListObserving
234
235- (void)webStateList:(WebStateList*)webStateList
236    didInsertWebState:(web::WebState*)webState
237              atIndex:(int)index
238           activating:(BOOL)activating {
239  [self installDelegatesForWebState:webState];
240}
241
242- (void)webStateList:(WebStateList*)webStateList
243    didReplaceWebState:(web::WebState*)oldWebState
244          withWebState:(web::WebState*)newWebState
245               atIndex:(int)index {
246  [self uninstallDelegatesForWebState:oldWebState];
247  [self installDelegatesForWebState:newWebState];
248}
249
250- (void)webStateList:(WebStateList*)webStateList
251    didDetachWebState:(web::WebState*)webState
252              atIndex:(int)index {
253  [self uninstallDelegatesForWebState:webState];
254}
255
256@end
257