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

Side by Side Diff: chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm

Issue 2164483006: [MacViews] Implemented text context menu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed tapted's comments and made things work Created 4 years 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu _mac.h" 5 #include "chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu _mac.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
10 #include "base/mac/mac_util.h" 10 #include "base/mac/mac_util.h"
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 }; 176 };
177 177
178 // Obj-C bridge class that is the target of all items in the context menu. 178 // Obj-C bridge class that is the target of all items in the context menu.
179 // Relies on the tag being set to the command id. 179 // Relies on the tag being set to the command id.
180 180
181 RenderViewContextMenuMac::RenderViewContextMenuMac( 181 RenderViewContextMenuMac::RenderViewContextMenuMac(
182 content::RenderFrameHost* render_frame_host, 182 content::RenderFrameHost* render_frame_host,
183 const content::ContextMenuParams& params, 183 const content::ContextMenuParams& params,
184 NSView* parent_view) 184 NSView* parent_view)
185 : RenderViewContextMenu(render_frame_host, params), 185 : RenderViewContextMenu(render_frame_host, params),
186 speech_submenu_model_(this), 186 parent_view_(parent_view),
187 bidi_submenu_model_(this), 187 text_services_context_menu_(this) {
188 parent_view_(parent_view) {
189 std::unique_ptr<ToolkitDelegate> delegate(new ToolkitDelegateMac(this)); 188 std::unique_ptr<ToolkitDelegate> delegate(new ToolkitDelegateMac(this));
190 set_toolkit_delegate(std::move(delegate)); 189 set_toolkit_delegate(std::move(delegate));
191 } 190 }
192 191
193 RenderViewContextMenuMac::~RenderViewContextMenuMac() { 192 RenderViewContextMenuMac::~RenderViewContextMenuMac() {
194 } 193 }
195 194
196 void RenderViewContextMenuMac::Show() { 195 void RenderViewContextMenuMac::Show() {
197 menu_controller_.reset( 196 menu_controller_.reset(
198 [[MenuController alloc] initWithModel:&menu_model_ 197 [[MenuController alloc] initWithModel:&menu_model_
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 stopwatch.Start(); 237 stopwatch.Start();
239 // Show the menu. 238 // Show the menu.
240 [NSMenu popUpContextMenu:[menu_controller_ menu] 239 [NSMenu popUpContextMenu:[menu_controller_ menu]
241 withEvent:clickEvent 240 withEvent:clickEvent
242 forView:parent_view_]; 241 forView:parent_view_];
243 stopwatch.Stop(); 242 stopwatch.Stop();
244 } 243 }
245 } 244 }
246 245
247 void RenderViewContextMenuMac::ExecuteCommand(int command_id, int event_flags) { 246 void RenderViewContextMenuMac::ExecuteCommand(int command_id, int event_flags) {
248 switch (command_id) { 247 switch (command_id) {
tapted 2016/12/13 05:11:22 no need to switch here
spqchan 2016/12/15 23:29:00 Done.
249 case IDC_CONTENT_CONTEXT_LOOK_UP: 248 default:
250 LookUpInDictionary(); 249 if (text_services_context_menu_.IsTextServicesCommandId(command_id)) {
251 break; 250 return text_services_context_menu_.ExecuteCommand(command_id,
251 event_flags);
252 }
252 253
253 case IDC_CONTENT_CONTEXT_SPEECH_START_SPEAKING:
254 StartSpeaking();
255 break;
256
257 case IDC_CONTENT_CONTEXT_SPEECH_STOP_SPEAKING:
258 StopSpeaking();
259 break;
260
261 case IDC_WRITING_DIRECTION_DEFAULT:
262 // WebKit's current behavior is for this menu item to always be disabled.
263 NOTREACHED();
264 break;
265
266 case IDC_WRITING_DIRECTION_RTL:
267 case IDC_WRITING_DIRECTION_LTR: {
268 content::RenderViewHost* view_host = GetRenderViewHost();
269 blink::WebTextDirection dir = blink::WebTextDirectionLeftToRight;
270 if (command_id == IDC_WRITING_DIRECTION_RTL)
271 dir = blink::WebTextDirectionRightToLeft;
272 view_host->GetWidget()->UpdateTextDirection(dir);
273 view_host->GetWidget()->NotifyTextDirection();
274 RenderViewContextMenu::RecordUsedItem(command_id);
275 break;
276 }
277
278 default:
279 RenderViewContextMenu::ExecuteCommand(command_id, event_flags); 254 RenderViewContextMenu::ExecuteCommand(command_id, event_flags);
280 break; 255 break;
281 } 256 }
282 } 257 }
283 258
284 bool RenderViewContextMenuMac::IsCommandIdChecked(int command_id) const { 259 bool RenderViewContextMenuMac::IsCommandIdChecked(int command_id) const {
285 switch (command_id) { 260 if (text_services_context_menu_.IsTextServicesCommandId(command_id))
286 case IDC_WRITING_DIRECTION_DEFAULT: 261 return text_services_context_menu_.IsCommandIdChecked(command_id);
287 return params_.writing_direction_default &
288 blink::WebContextMenuData::CheckableMenuItemChecked;
289 case IDC_WRITING_DIRECTION_RTL:
290 return params_.writing_direction_right_to_left &
291 blink::WebContextMenuData::CheckableMenuItemChecked;
292 case IDC_WRITING_DIRECTION_LTR:
293 return params_.writing_direction_left_to_right &
294 blink::WebContextMenuData::CheckableMenuItemChecked;
295 262
296 default: 263 return RenderViewContextMenu::IsCommandIdChecked(command_id);
297 return RenderViewContextMenu::IsCommandIdChecked(command_id);
298 }
299 } 264 }
300 265
301 bool RenderViewContextMenuMac::IsCommandIdEnabled(int command_id) const { 266 bool RenderViewContextMenuMac::IsCommandIdEnabled(int command_id) const {
302 switch (command_id) { 267 if (text_services_context_menu_.IsTextServicesCommandId(command_id))
tapted 2016/12/13 05:11:22 Is it only IDS_CONTENT_CONTEXT_LOOK_UP that comes
spqchan 2016/12/15 23:29:00 Yes, only lookup goes through here. I'm a bit conf
303 case IDC_CONTENT_CONTEXT_LOOK_UP: 268 return text_services_context_menu_.IsCommandIdEnabled(command_id);
304 // This is OK because the menu is not shown when it isn't
305 // appropriate.
306 return true;
307 269
308 case IDC_CONTENT_CONTEXT_SPEECH_START_SPEAKING: 270 return RenderViewContextMenu::IsCommandIdEnabled(command_id);
309 // This is OK because the menu is not shown when it isn't
310 // appropriate.
311 return true;
312
313 case IDC_CONTENT_CONTEXT_SPEECH_STOP_SPEAKING: {
314 content::RenderWidgetHostView* view =
315 GetRenderViewHost()->GetWidget()->GetView();
316 return view && view->IsSpeaking();
317 }
318
319 case IDC_WRITING_DIRECTION_DEFAULT: // Provided to match OS defaults.
320 return params_.writing_direction_default &
321 blink::WebContextMenuData::CheckableMenuItemEnabled;
322 case IDC_WRITING_DIRECTION_RTL:
323 return params_.writing_direction_right_to_left &
324 blink::WebContextMenuData::CheckableMenuItemEnabled;
325 case IDC_WRITING_DIRECTION_LTR:
326 return params_.writing_direction_left_to_right &
327 blink::WebContextMenuData::CheckableMenuItemEnabled;
328
329 default:
330 return RenderViewContextMenu::IsCommandIdEnabled(command_id);
331 }
332 } 271 }
333 272
334 void RenderViewContextMenuMac::AppendPlatformEditableItems() { 273 void RenderViewContextMenuMac::AppendPlatformEditableItems() {
335 // OS X provides a contextual menu to set writing direction for BiDi 274 // OS X provides a contextual menu to set writing direction for BiDi
336 // languages. 275 // languages.
337 // This functionality is exposed as a keyboard shortcut on Windows & Linux. 276 // This functionality is exposed as a keyboard shortcut on Windows & Linux.
338 AppendBidiSubMenu(); 277 text_services_context_menu_.AppendPlatformEditableItems(&menu_model_);
339 } 278 }
340 279
341 void RenderViewContextMenuMac::InitToolkitMenu() { 280 void RenderViewContextMenuMac::InitToolkitMenu() {
342 if (params_.selection_text.empty()) 281 if (params_.selection_text.empty())
343 return; 282 return;
344 283
345 if (params_.link_url.is_empty()) { 284 if (params_.link_url.is_empty()) {
346 // In case the user has selected a word that triggers spelling suggestions, 285 // In case the user has selected a word that triggers spelling suggestions,
347 // show the dictionary lookup under the group that contains the command to 286 // show the dictionary lookup under the group that contains the command to
348 // “Add to Dictionary.” 287 // “Add to Dictionary.”
349 int index = menu_model_.GetIndexOfCommandId( 288 int index = menu_model_.GetIndexOfCommandId(
350 IDC_SPELLCHECK_ADD_TO_DICTIONARY); 289 IDC_SPELLCHECK_ADD_TO_DICTIONARY);
351 if (index < 0) { 290 if (index < 0) {
352 index = 0; 291 index = 0;
353 } else { 292 } else {
354 while (menu_model_.GetTypeAt(index) != ui::MenuModel::TYPE_SEPARATOR) { 293 while (menu_model_.GetTypeAt(index) != ui::MenuModel::TYPE_SEPARATOR) {
355 index++; 294 index++;
356 } 295 }
357 index += 1; // Place it below the separator. 296 index += 1; // Place it below the separator.
tapted 2016/12/13 05:11:22 I think the "it" here is IDS_CONTENT_CONTEXT_LOOK_
spqchan 2016/12/15 23:29:00 I'm a bit confused. I'm pretty sure that this sect
tapted 2016/12/16 07:01:19 The problem is that all the code between `if (para
358 } 297 }
359 298
360 base::string16 printable_selection_text = PrintableSelectionText();
361 EscapeAmpersands(&printable_selection_text);
362 menu_model_.InsertItemAt(
363 index++,
364 IDC_CONTENT_CONTEXT_LOOK_UP,
365 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_LOOK_UP,
366 printable_selection_text));
367 menu_model_.InsertSeparatorAt(index++, ui::NORMAL_SEPARATOR); 299 menu_model_.InsertSeparatorAt(index++, ui::NORMAL_SEPARATOR);
368 } 300 }
369 301
370 content::RenderWidgetHostView* view = 302 text_services_context_menu_.AppendToContextMenu(&menu_model_);
371 GetRenderViewHost()->GetWidget()->GetView();
372 if (view && view->SupportsSpeech()) {
373 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
374 speech_submenu_model_.AddItemWithStringId(
375 IDC_CONTENT_CONTEXT_SPEECH_START_SPEAKING,
376 IDS_SPEECH_START_SPEAKING_MAC);
377 speech_submenu_model_.AddItemWithStringId(
378 IDC_CONTENT_CONTEXT_SPEECH_STOP_SPEAKING,
379 IDS_SPEECH_STOP_SPEAKING_MAC);
380 menu_model_.AddSubMenu(
381 IDC_CONTENT_CONTEXT_SPEECH_MENU,
382 l10n_util::GetStringUTF16(IDS_SPEECH_MAC),
383 &speech_submenu_model_);
384 }
385 } 303 }
386 304
387 void RenderViewContextMenuMac::CancelToolkitMenu() { 305 void RenderViewContextMenuMac::CancelToolkitMenu() {
388 [menu_controller_ cancel]; 306 [menu_controller_ cancel];
389 } 307 }
390 308
391 void RenderViewContextMenuMac::UpdateToolkitMenuItem( 309 void RenderViewContextMenuMac::UpdateToolkitMenuItem(
392 int command_id, 310 int command_id,
393 bool enabled, 311 bool enabled,
394 bool hidden, 312 bool hidden,
395 const base::string16& title) { 313 const base::string16& title) {
396 NSMenuItem* item = GetMenuItemByID(&menu_model_, [menu_controller_ menu], 314 NSMenuItem* item = GetMenuItemByID(&menu_model_, [menu_controller_ menu],
397 command_id); 315 command_id);
398 if (!item) 316 if (!item)
399 return; 317 return;
400 318
401 // Update the returned NSMenuItem directly so we can update it immediately. 319 // Update the returned NSMenuItem directly so we can update it immediately.
402 [item setEnabled:enabled]; 320 [item setEnabled:enabled];
403 [item setTitle:base::SysUTF16ToNSString(title)]; 321 [item setTitle:base::SysUTF16ToNSString(title)];
404 [item setHidden:hidden]; 322 [item setHidden:hidden];
405 [[item menu] itemChanged:item]; 323 [[item menu] itemChanged:item];
406 } 324 }
407 325
408 void RenderViewContextMenuMac::AppendBidiSubMenu() { 326 base::string16 RenderViewContextMenuMac::GetSelectedText() const {
409 bidi_submenu_model_.AddCheckItem(IDC_WRITING_DIRECTION_DEFAULT, 327 return params_.selection_text;
410 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT)); 328 }
411 bidi_submenu_model_.AddCheckItem(IDC_WRITING_DIRECTION_LTR,
412 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR));
413 bidi_submenu_model_.AddCheckItem(IDC_WRITING_DIRECTION_RTL,
414 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL));
415 329
416 menu_model_.AddSubMenu( 330 void RenderViewContextMenuMac::OnSpeakRequested() {
417 IDC_WRITING_DIRECTION_MENU, 331 content::RenderWidgetHostView* view =
418 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU), 332 GetRenderViewHost()->GetWidget()->GetView();
419 &bidi_submenu_model_); 333 if (view)
334 view->SpeakSelection();
335 }
336
337 bool RenderViewContextMenuMac::IsLookUpAvailable() const {
338 return params_.link_url.is_empty();
420 } 339 }
421 340
422 void RenderViewContextMenuMac::LookUpInDictionary() { 341 void RenderViewContextMenuMac::LookUpInDictionary() {
423 content::RenderWidgetHostView* view = 342 content::RenderWidgetHostView* view =
424 GetRenderViewHost()->GetWidget()->GetView(); 343 GetRenderViewHost()->GetWidget()->GetView();
425 if (view) 344 if (view)
426 view->ShowDefinitionForSelection(); 345 view->ShowDefinitionForSelection();
427 } 346 }
428 347
429 void RenderViewContextMenuMac::StartSpeaking() { 348 bool RenderViewContextMenuMac::IsWritingDirectionEnabled(
430 content::RenderWidgetHostView* view = 349 ui::WritingDirection direction) const {
431 GetRenderViewHost()->GetWidget()->GetView(); 350 switch (direction) {
432 if (view) 351 case ui::WritingDirection::DEFAULT:
433 view->SpeakSelection(); 352 return params_.writing_direction_default &
353 blink::WebContextMenuData::CheckableMenuItemEnabled;
354 case ui::WritingDirection::RTL:
355 return params_.writing_direction_right_to_left &
356 blink::WebContextMenuData::CheckableMenuItemEnabled;
357 case ui::WritingDirection::LTR:
358 return params_.writing_direction_left_to_right &
359 blink::WebContextMenuData::CheckableMenuItemEnabled;
360 }
434 } 361 }
435 362
436 void RenderViewContextMenuMac::StopSpeaking() { 363 bool RenderViewContextMenuMac::IsWritingDirectionChecked(
437 content::RenderWidgetHostView* view = 364 ui::WritingDirection direction) const {
438 GetRenderViewHost()->GetWidget()->GetView(); 365 switch (direction) {
439 if (view) 366 case ui::WritingDirection::DEFAULT:
440 view->StopSpeaking(); 367 return params_.writing_direction_default &
368 blink::WebContextMenuData::CheckableMenuItemChecked;
369 case ui::WritingDirection::RTL:
370 return params_.writing_direction_right_to_left &
371 blink::WebContextMenuData::CheckableMenuItemChecked;
372 case ui::WritingDirection::LTR:
373 return params_.writing_direction_left_to_right &
374 blink::WebContextMenuData::CheckableMenuItemChecked;
375 }
441 } 376 }
377
378 void RenderViewContextMenuMac::UpdateTextDirection(
379 ui::WritingDirection direction) {
380 if (direction == ui::WritingDirection::DEFAULT)
tapted 2016/12/13 05:11:22 nit: DCHECK_NE(ui::WritingDirection::DEFAULT, dire
spqchan 2016/12/15 23:29:00 Done.
381 NOTREACHED();
382
383 content::RenderViewHost* view_host = GetRenderViewHost();
384 blink::WebTextDirection dir = blink::WebTextDirectionLeftToRight;
385 int command_id = IDC_WRITING_DIRECTION_LTR;
386 if (direction == ui::WritingDirection::RTL) {
387 dir = blink::WebTextDirectionRightToLeft;
388 command_id = IDC_WRITING_DIRECTION_RTL;
389 }
390
391 view_host->GetWidget()->UpdateTextDirection(dir);
392 view_host->GetWidget()->NotifyTextDirection();
393
394 RenderViewContextMenu::RecordUsedItem(command_id);
395 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698