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

Side by Side Diff: views/controls/menu/menu_controller.cc

Issue 6288002: Adds some debugging in code in hopes of figuring out a crash in the (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/chrome
Patch Set: Better comments Created 9 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « views/controls/menu/menu_controller.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 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 "views/controls/menu/menu_controller.h" 5 #include "views/controls/menu/menu_controller.h"
6 6
7 #include "app/l10n_util.h" 7 #include "app/l10n_util.h"
8 #include "base/i18n/rtl.h" 8 #include "base/i18n/rtl.h"
9 #include "base/time.h" 9 #include "base/time.h"
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 } 280 }
281 281
282 // Reset current state. 282 // Reset current state.
283 pending_state_ = State(); 283 pending_state_ = State();
284 state_ = State(); 284 state_ = State();
285 UpdateInitialLocation(bounds, position); 285 UpdateInitialLocation(bounds, position);
286 286
287 owner_ = parent; 287 owner_ = parent;
288 288
289 // Set the selection, which opens the initial menu. 289 // Set the selection, which opens the initial menu.
290 SetSelection(root, true, true); 290 SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
291 291
292 if (!blocking_run_) { 292 if (!blocking_run_) {
293 // Start the timer to hide the menu. This is needed as we get no 293 // Start the timer to hide the menu. This is needed as we get no
294 // notification when the drag has finished. 294 // notification when the drag has finished.
295 StartCancelAllTimer(); 295 StartCancelAllTimer();
296 return NULL; 296 return NULL;
297 } else if (button) { 297 } else if (button) {
298 menu_button_ = button; 298 menu_button_ = button;
299 } 299 }
300 300
301 // Make sure Chrome doesn't attempt to shut down while the menu is showing. 301 // Make sure Chrome doesn't attempt to shut down while the menu is showing.
302 if (ViewsDelegate::views_delegate) 302 if (ViewsDelegate::views_delegate)
303 ViewsDelegate::views_delegate->AddRef(); 303 ViewsDelegate::views_delegate->AddRef();
304 304
305 // We need to turn on nestable tasks as in some situations (pressing alt-f for 305 // We need to turn on nestable tasks as in some situations (pressing alt-f for
306 // one) the menus are run from a task. If we don't do this and are invoked 306 // one) the menus are run from a task. If we don't do this and are invoked
307 // from a task none of the tasks we schedule are processed and the menu 307 // from a task none of the tasks we schedule are processed and the menu
308 // appears totally broken. 308 // appears totally broken.
309 MessageLoopForUI* loop = MessageLoopForUI::current(); 309 MessageLoopForUI* loop = MessageLoopForUI::current();
310 bool did_allow_task_nesting = loop->NestableTasksAllowed(); 310 bool did_allow_task_nesting = loop->NestableTasksAllowed();
311 loop->SetNestableTasksAllowed(true); 311 loop->SetNestableTasksAllowed(true);
312 loop->Run(this); 312 loop->Run(this);
313 loop->SetNestableTasksAllowed(did_allow_task_nesting); 313 loop->SetNestableTasksAllowed(did_allow_task_nesting);
314 314
315 if (ViewsDelegate::views_delegate) 315 if (ViewsDelegate::views_delegate)
316 ViewsDelegate::views_delegate->ReleaseRef(); 316 ViewsDelegate::views_delegate->ReleaseRef();
317 317
318 // Close any open menus. 318 // Close any open menus.
319 SetSelection(NULL, false, true); 319 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
320 320
321 if (nested_menu) { 321 if (nested_menu) {
322 DCHECK(!menu_stack_.empty()); 322 DCHECK(!menu_stack_.empty());
323 // We're running from within a menu, restore the previous state. 323 // We're running from within a menu, restore the previous state.
324 // The menus are already showing, so we don't have to show them. 324 // The menus are already showing, so we don't have to show them.
325 state_ = menu_stack_.back(); 325 state_ = menu_stack_.back();
326 pending_state_ = menu_stack_.back(); 326 pending_state_ = menu_stack_.back();
327 menu_stack_.pop_back(); 327 menu_stack_.pop_back();
328 } else { 328 } else {
329 showing_ = false; 329 showing_ = false;
(...skipping 25 matching lines...) Expand all
355 // If we stopped running because one of the menus was destroyed chances are 355 // If we stopped running because one of the menus was destroyed chances are
356 // the button was also destroyed. 356 // the button was also destroyed.
357 if (exit_type_ != EXIT_DESTROYED && menu_button_) { 357 if (exit_type_ != EXIT_DESTROYED && menu_button_) {
358 menu_button_->SetState(CustomButton::BS_NORMAL); 358 menu_button_->SetState(CustomButton::BS_NORMAL);
359 menu_button_->SchedulePaint(); 359 menu_button_->SchedulePaint();
360 } 360 }
361 361
362 return result; 362 return result;
363 } 363 }
364 364
365 void MenuController::SetSelection(MenuItemView* menu_item,
366 bool open_submenu,
367 bool update_immediately) {
368 size_t paths_differ_at = 0;
369 std::vector<MenuItemView*> current_path;
370 std::vector<MenuItemView*> new_path;
371 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path,
372 &new_path, &paths_differ_at);
373
374 size_t current_size = current_path.size();
375 size_t new_size = new_path.size();
376
377 if (pending_state_.item != menu_item && pending_state_.item) {
378 View* current_hot_view = GetFirstHotTrackedView(pending_state_.item);
379 if (current_hot_view)
380 current_hot_view->SetHotTracked(false);
381 }
382
383 // Notify the old path it isn't selected.
384 for (size_t i = paths_differ_at; i < current_size; ++i)
385 current_path[i]->SetSelected(false);
386
387 // Notify the new path it is selected.
388 for (size_t i = paths_differ_at; i < new_size; ++i)
389 new_path[i]->SetSelected(true);
390
391 if (menu_item && menu_item->GetDelegate())
392 menu_item->GetDelegate()->SelectionChanged(menu_item);
393
394 pending_state_.item = menu_item;
395 pending_state_.submenu_open = open_submenu;
396
397 // Stop timers.
398 StopShowTimer();
399 StopCancelAllTimer();
400
401 if (update_immediately)
402 CommitPendingSelection();
403 else
404 StartShowTimer();
405
406 // Notify an accessibility focus event on all menu items except for the root.
407 if (menu_item &&
408 (MenuDepth(menu_item) != 1 ||
409 menu_item->GetType() != MenuItemView::SUBMENU))
410 menu_item->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS);
411 }
412
413 void MenuController::Cancel(ExitType type) { 365 void MenuController::Cancel(ExitType type) {
414 if (!showing_) { 366 if (!showing_) {
415 // This occurs if we're in the process of notifying the delegate for a drop 367 // This occurs if we're in the process of notifying the delegate for a drop
416 // and the delegate cancels us. 368 // and the delegate cancels us.
417 return; 369 return;
418 } 370 }
419 371
420 MenuItemView* selected = state_.item; 372 MenuItemView* selected = state_.item;
421 exit_type_ = type; 373 exit_type_ = type;
422 374
423 SendMouseReleaseToActiveView(); 375 SendMouseReleaseToActiveView();
424 376
425 // Hide windows immediately. 377 // Hide windows immediately.
426 SetSelection(NULL, false, true); 378 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
427 379
428 if (!blocking_run_) { 380 if (!blocking_run_) {
429 // If we didn't block the caller we need to notify the menu, which 381 // If we didn't block the caller we need to notify the menu, which
430 // triggers deleting us. 382 // triggers deleting us.
431 DCHECK(selected); 383 DCHECK(selected);
432 showing_ = false; 384 showing_ = false;
433 selected->GetRootMenuItem()->DropMenuClosed(true); 385 selected->GetRootMenuItem()->DropMenuClosed(true);
434 // WARNING: the call to MenuClosed deletes us. 386 // WARNING: the call to MenuClosed deletes us.
435 return; 387 return;
436 } 388 }
(...skipping 21 matching lines...) Expand all
458 #if defined(OS_WIN) 410 #if defined(OS_WIN)
459 RepostEvent(source, event); 411 RepostEvent(source, event);
460 // NOTE: not reposting on linux seems fine. 412 // NOTE: not reposting on linux seems fine.
461 #endif 413 #endif
462 414
463 // And close. 415 // And close.
464 Cancel(EXIT_ALL); 416 Cancel(EXIT_ALL);
465 return; 417 return;
466 } 418 }
467 419
468 bool open_submenu = false; 420 // On a press we immediately commit the selection, that way a submenu
421 // pops up immediately rather than after a delay.
422 int selection_types = SELECTION_UPDATE_IMMEDIATELY;
469 if (!part.menu) { 423 if (!part.menu) {
470 part.menu = part.parent; 424 part.menu = part.parent;
471 open_submenu = true; 425 selection_types |= SELECTION_OPEN_SUBMENU;
472 } else { 426 } else {
473 if (part.menu->GetDelegate()->CanDrag(part.menu)) { 427 if (part.menu->GetDelegate()->CanDrag(part.menu)) {
474 possible_drag_ = true; 428 possible_drag_ = true;
475 press_pt_ = event.location(); 429 press_pt_ = event.location();
476 } 430 }
477 if (part.menu->HasSubmenu()) 431 if (part.menu->HasSubmenu())
478 open_submenu = true; 432 selection_types |= SELECTION_OPEN_SUBMENU;
479 } 433 }
480 // On a press we immediately commit the selection, that way a submenu 434 SetSelection(part.menu, selection_types);
481 // pops up immediately rather than after a delay.
482 SetSelection(part.menu, open_submenu, true);
483 } 435 }
484 436
485 void MenuController::OnMouseDragged(SubmenuView* source, 437 void MenuController::OnMouseDragged(SubmenuView* source,
486 const MouseEvent& event) { 438 const MouseEvent& event) {
487 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); 439 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
488 UpdateScrolling(part); 440 UpdateScrolling(part);
489 441
490 if (!blocking_run_) 442 if (!blocking_run_)
491 return; 443 return;
492 444
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 } // else case, someone canceled us, don't do anything 477 } // else case, someone canceled us, don't do anything
526 } 478 }
527 return; 479 return;
528 } 480 }
529 MenuItemView* mouse_menu = NULL; 481 MenuItemView* mouse_menu = NULL;
530 if (part.type == MenuPart::MENU_ITEM) { 482 if (part.type == MenuPart::MENU_ITEM) {
531 if (!part.menu) 483 if (!part.menu)
532 part.menu = source->GetMenuItem(); 484 part.menu = source->GetMenuItem();
533 else 485 else
534 mouse_menu = part.menu; 486 mouse_menu = part.menu;
535 SetSelection(part.menu ? part.menu : state_.item, true, false); 487 SetSelection(part.menu ? part.menu : state_.item, SELECTION_OPEN_SUBMENU);
536 } else if (part.type == MenuPart::NONE) { 488 } else if (part.type == MenuPart::NONE) {
537 ShowSiblingMenu(source, event); 489 ShowSiblingMenu(source, event);
538 } 490 }
539 UpdateActiveMouseView(source, event, mouse_menu); 491 UpdateActiveMouseView(source, event, mouse_menu);
540 } 492 }
541 493
542 void MenuController::OnMouseReleased(SubmenuView* source, 494 void MenuController::OnMouseReleased(SubmenuView* source,
543 const MouseEvent& event) { 495 const MouseEvent& event) {
544 if (!blocking_run_) 496 if (!blocking_run_)
545 return; 497 return;
546 498
547 DCHECK(state_.item); 499 DCHECK(state_.item);
548 possible_drag_ = false; 500 possible_drag_ = false;
549 DCHECK(blocking_run_); 501 DCHECK(blocking_run_);
550 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); 502 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
551 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM && 503 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
552 part.menu)) { 504 part.menu)) {
553 // Set the selection immediately, making sure the submenu is only open 505 // Set the selection immediately, making sure the submenu is only open
554 // if it already was. 506 // if it already was.
555 bool open_submenu = (state_.item == pending_state_.item && 507 int selection_types = SELECTION_UPDATE_IMMEDIATELY;
556 state_.submenu_open); 508 if (state_.item == pending_state_.item && state_.submenu_open)
557 SetSelection(pending_state_.item, open_submenu, true); 509 selection_types |= SELECTION_OPEN_SUBMENU;
510 SetSelection(pending_state_.item, selection_types);
558 gfx::Point loc(event.location()); 511 gfx::Point loc(event.location());
559 View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc); 512 View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc);
560 513
561 // If we open a context menu just return now 514 // If we open a context menu just return now
562 if (part.menu->GetDelegate()->ShowContextMenu( 515 if (part.menu->GetDelegate()->ShowContextMenu(
563 part.menu, part.menu->GetCommand(), loc, true)) { 516 part.menu, part.menu->GetCommand(), loc, true)) {
564 SendMouseReleaseToActiveView(source, event, true); 517 SendMouseReleaseToActiveView(source, event, true);
565 return; 518 return;
566 } 519 }
567 } 520 }
568 521
569 // We can use Ctrl+click or the middle mouse button to recursively open urls 522 // We can use Ctrl+click or the middle mouse button to recursively open urls
570 // for selected folder menu items. If it's only a left click, show the 523 // for selected folder menu items. If it's only a left click, show the
571 // contents of the folder. 524 // contents of the folder.
572 if (!part.is_scroll() && part.menu && 525 if (!part.is_scroll() && part.menu &&
573 !(part.menu->HasSubmenu() && 526 !(part.menu->HasSubmenu() &&
574 (event.GetFlags() == MouseEvent::EF_LEFT_BUTTON_DOWN))) { 527 (event.GetFlags() == MouseEvent::EF_LEFT_BUTTON_DOWN))) {
575 if (active_mouse_view_) { 528 if (active_mouse_view_) {
576 SendMouseReleaseToActiveView(source, event, false); 529 SendMouseReleaseToActiveView(source, event, false);
577 return; 530 return;
578 } 531 }
579 if (part.menu->GetDelegate()->IsTriggerableEvent(event)) { 532 if (part.menu->GetDelegate()->IsTriggerableEvent(event)) {
580 Accept(part.menu, event.GetFlags()); 533 Accept(part.menu, event.GetFlags());
581 return; 534 return;
582 } 535 }
583 } else if (part.type == MenuPart::MENU_ITEM) { 536 } else if (part.type == MenuPart::MENU_ITEM) {
584 // User either clicked on empty space, or a menu that has children. 537 // User either clicked on empty space, or a menu that has children.
585 SetSelection(part.menu ? part.menu : state_.item, true, true); 538 SetSelection(part.menu ? part.menu : state_.item,
539 SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
586 } 540 }
587 SendMouseReleaseToActiveView(source, event, true); 541 SendMouseReleaseToActiveView(source, event, true);
588 } 542 }
589 543
590 void MenuController::OnMouseMoved(SubmenuView* source, 544 void MenuController::OnMouseMoved(SubmenuView* source,
591 const MouseEvent& event) { 545 const MouseEvent& event) {
592 if (showing_submenu_) 546 if (showing_submenu_)
593 return; 547 return;
594 548
595 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y()); 549 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
596 550
597 UpdateScrolling(part); 551 UpdateScrolling(part);
598 552
599 if (!blocking_run_) 553 if (!blocking_run_)
600 return; 554 return;
601 555
602 if (part.type == MenuPart::NONE && ShowSiblingMenu(source, event)) 556 if (part.type == MenuPart::NONE && ShowSiblingMenu(source, event))
603 return; 557 return;
604 558
605 if (part.type == MenuPart::MENU_ITEM && part.menu) { 559 if (part.type == MenuPart::MENU_ITEM && part.menu) {
606 SetSelection(part.menu, true, false); 560 SetSelection(part.menu, SELECTION_OPEN_SUBMENU);
607 } else if (!part.is_scroll() && pending_state_.item && 561 } else if (!part.is_scroll() && pending_state_.item &&
608 (!pending_state_.item->HasSubmenu() || 562 (!pending_state_.item->HasSubmenu() ||
609 !pending_state_.item->GetSubmenu()->IsShowing())) { 563 !pending_state_.item->GetSubmenu()->IsShowing())) {
610 // On exit if the user hasn't selected an item with a submenu, move the 564 // On exit if the user hasn't selected an item with a submenu, move the
611 // selection back to the parent menu item. 565 // selection back to the parent menu item.
612 SetSelection(pending_state_.item->GetParentMenuItem(), true, false); 566 SetSelection(pending_state_.item->GetParentMenuItem(),
567 SELECTION_OPEN_SUBMENU);
613 } 568 }
614 } 569 }
615 570
616 void MenuController::OnMouseEntered(SubmenuView* source, 571 void MenuController::OnMouseEntered(SubmenuView* source,
617 const MouseEvent& event) { 572 const MouseEvent& event) {
618 // MouseEntered is always followed by a mouse moved, so don't need to 573 // MouseEntered is always followed by a mouse moved, so don't need to
619 // do anything here. 574 // do anything here.
620 } 575 }
621 576
622 bool MenuController::GetDropFormats( 577 bool MenuController::GetDropFormats(
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 } 634 }
680 query_menu_item = menu_item; 635 query_menu_item = menu_item;
681 } else { 636 } else {
682 query_menu_item = menu_item->GetParentMenuItem(); 637 query_menu_item = menu_item->GetParentMenuItem();
683 drop_position = MenuDelegate::DROP_ON; 638 drop_position = MenuDelegate::DROP_ON;
684 } 639 }
685 drop_operation = menu_item->GetDelegate()->GetDropOperation( 640 drop_operation = menu_item->GetDelegate()->GetDropOperation(
686 query_menu_item, event, &drop_position); 641 query_menu_item, event, &drop_position);
687 642
688 // If the menu has a submenu, schedule the submenu to open. 643 // If the menu has a submenu, schedule the submenu to open.
689 SetSelection(menu_item, menu_item->HasSubmenu(), false); 644 SetSelection(menu_item, menu_item->HasSubmenu() ? SELECTION_OPEN_SUBMENU :
645 SELECTION_DEFAULT);
690 646
691 if (drop_position == MenuDelegate::DROP_NONE || 647 if (drop_position == MenuDelegate::DROP_NONE ||
692 drop_operation == DragDropTypes::DRAG_NONE) 648 drop_operation == DragDropTypes::DRAG_NONE)
693 menu_item = NULL; 649 menu_item = NULL;
694 } else { 650 } else {
695 SetSelection(source->GetMenuItem(), true, false); 651 SetSelection(source->GetMenuItem(), SELECTION_OPEN_SUBMENU);
696 } 652 }
697 SetDropMenuItem(menu_item, drop_position); 653 SetDropMenuItem(menu_item, drop_position);
698 last_drop_operation_ = drop_operation; 654 last_drop_operation_ = drop_operation;
699 return drop_operation; 655 return drop_operation;
700 } 656 }
701 657
702 void MenuController::OnDragExited(SubmenuView* source) { 658 void MenuController::OnDragExited(SubmenuView* source) {
703 StartCancelAllTimer(); 659 StartCancelAllTimer();
704 660
705 if (drop_target_) { 661 if (drop_target_) {
706 StopShowTimer(); 662 StopShowTimer();
707 SetDropMenuItem(NULL, MenuDelegate::DROP_NONE); 663 SetDropMenuItem(NULL, MenuDelegate::DROP_NONE);
708 } 664 }
709 } 665 }
710 666
711 int MenuController::OnPerformDrop(SubmenuView* source, 667 int MenuController::OnPerformDrop(SubmenuView* source,
712 const DropTargetEvent& event) { 668 const DropTargetEvent& event) {
713 DCHECK(drop_target_); 669 DCHECK(drop_target_);
714 // NOTE: the delegate may delete us after invoking OnPerformDrop, as such 670 // NOTE: the delegate may delete us after invoking OnPerformDrop, as such
715 // we don't call cancel here. 671 // we don't call cancel here.
716 672
717 MenuItemView* item = state_.item; 673 MenuItemView* item = state_.item;
718 DCHECK(item); 674 DCHECK(item);
719 675
720 MenuItemView* drop_target = drop_target_; 676 MenuItemView* drop_target = drop_target_;
721 MenuDelegate::DropPosition drop_position = drop_position_; 677 MenuDelegate::DropPosition drop_position = drop_position_;
722 678
723 // Close all menus, including any nested menus. 679 // Close all menus, including any nested menus.
724 SetSelection(NULL, false, true); 680 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
725 CloseAllNestedMenus(); 681 CloseAllNestedMenus();
726 682
727 // Set state such that we exit. 683 // Set state such that we exit.
728 showing_ = false; 684 showing_ = false;
729 exit_type_ = EXIT_ALL; 685 exit_type_ = EXIT_ALL;
730 686
731 if (!IsBlockingRun()) 687 if (!IsBlockingRun())
732 item->GetRootMenuItem()->DropMenuClosed(false); 688 item->GetRootMenuItem()->DropMenuClosed(false);
733 689
734 // WARNING: the call to MenuClosed deletes us. 690 // WARNING: the call to MenuClosed deletes us.
(...skipping 18 matching lines...) Expand all
753 709
754 StopCancelAllTimer(); 710 StopCancelAllTimer();
755 } 711 }
756 712
757 void MenuController::OnDragExitedScrollButton(SubmenuView* source) { 713 void MenuController::OnDragExitedScrollButton(SubmenuView* source) {
758 StartCancelAllTimer(); 714 StartCancelAllTimer();
759 SetDropMenuItem(NULL, MenuDelegate::DROP_NONE); 715 SetDropMenuItem(NULL, MenuDelegate::DROP_NONE);
760 StopScrolling(); 716 StopScrolling();
761 } 717 }
762 718
719 void MenuController::SetSelection(MenuItemView* menu_item,
720 int selection_types) {
721 size_t paths_differ_at = 0;
722 std::vector<MenuItemView*> current_path;
723 std::vector<MenuItemView*> new_path;
724 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path,
725 &new_path, &paths_differ_at);
726
727 size_t current_size = current_path.size();
728 size_t new_size = new_path.size();
729
730 if (pending_state_.item != menu_item && pending_state_.item) {
731 View* current_hot_view = GetFirstHotTrackedView(pending_state_.item);
732 if (current_hot_view)
733 current_hot_view->SetHotTracked(false);
734 }
735
736 // Notify the old path it isn't selected.
737 for (size_t i = paths_differ_at; i < current_size; ++i)
738 current_path[i]->SetSelected(false);
739
740 // Notify the new path it is selected.
741 for (size_t i = paths_differ_at; i < new_size; ++i)
742 new_path[i]->SetSelected(true);
743
744 if (menu_item && menu_item->GetDelegate())
745 menu_item->GetDelegate()->SelectionChanged(menu_item);
746
747 CHECK(menu_item || (selection_types & SELECTION_EXIT) != 0);
748
749 pending_state_.item = menu_item;
750 pending_state_.submenu_open = (selection_types & SELECTION_OPEN_SUBMENU) != 0;
751
752 // Stop timers.
753 StopShowTimer();
754 StopCancelAllTimer();
755
756 if (selection_types & SELECTION_UPDATE_IMMEDIATELY)
757 CommitPendingSelection();
758 else
759 StartShowTimer();
760
761 // Notify an accessibility focus event on all menu items except for the root.
762 if (menu_item &&
763 (MenuDepth(menu_item) != 1 ||
764 menu_item->GetType() != MenuItemView::SUBMENU))
765 menu_item->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS);
766 }
767
763 // static 768 // static
764 void MenuController::SetActiveInstance(MenuController* controller) { 769 void MenuController::SetActiveInstance(MenuController* controller) {
765 active_instance_ = controller; 770 active_instance_ = controller;
766 } 771 }
767 772
768 #if defined(OS_WIN) 773 #if defined(OS_WIN)
769 bool MenuController::Dispatch(const MSG& msg) { 774 bool MenuController::Dispatch(const MSG& msg) {
770 DCHECK(blocking_run_); 775 DCHECK(blocking_run_);
771 776
772 if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED) { 777 if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED) {
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
1061 gfx::Point screen_menu_loc; 1066 gfx::Point screen_menu_loc;
1062 View::ConvertPointToScreen(button, &screen_menu_loc); 1067 View::ConvertPointToScreen(button, &screen_menu_loc);
1063 // Subtract 1 from the height to make the popup flush with the button border. 1068 // Subtract 1 from the height to make the popup flush with the button border.
1064 UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(), 1069 UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(),
1065 button->width(), button->height() - 1), 1070 button->width(), button->height() - 1),
1066 anchor); 1071 anchor);
1067 alt_menu->PrepareForRun( 1072 alt_menu->PrepareForRun(
1068 has_mnemonics, 1073 has_mnemonics,
1069 source->GetMenuItem()->GetRootMenuItem()->show_mnemonics_); 1074 source->GetMenuItem()->GetRootMenuItem()->show_mnemonics_);
1070 alt_menu->controller_ = this; 1075 alt_menu->controller_ = this;
1071 SetSelection(alt_menu, true, true); 1076 SetSelection(alt_menu, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
1072 return true; 1077 return true;
1073 } 1078 }
1074 1079
1075 void MenuController::CloseAllNestedMenus() { 1080 void MenuController::CloseAllNestedMenus() {
1076 for (std::list<State>::iterator i = menu_stack_.begin(); 1081 for (std::list<State>::iterator i = menu_stack_.begin();
1077 i != menu_stack_.end(); ++i) { 1082 i != menu_stack_.end(); ++i) {
1078 MenuItemView* item = i->item; 1083 MenuItemView* item = i->item;
1079 MenuItemView* last_item = item; 1084 MenuItemView* last_item = item;
1080 while (item) { 1085 while (item) {
1081 CloseMenu(item); 1086 CloseMenu(item);
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
1308 void MenuController::MenuChildrenChanged(MenuItemView* item) { 1313 void MenuController::MenuChildrenChanged(MenuItemView* item) {
1309 DCHECK(item); 1314 DCHECK(item);
1310 DCHECK(item->GetSubmenu()->IsShowing()); 1315 DCHECK(item->GetSubmenu()->IsShowing());
1311 1316
1312 // Currently this only supports adjusting the bounds of the last menu. 1317 // Currently this only supports adjusting the bounds of the last menu.
1313 DCHECK(item == state_.item->GetParentMenuItem()); 1318 DCHECK(item == state_.item->GetParentMenuItem());
1314 1319
1315 // Make sure the submenu isn't showing for the current item (the position may 1320 // Make sure the submenu isn't showing for the current item (the position may
1316 // have changed or the menu removed). This also moves the selection back to 1321 // have changed or the menu removed). This also moves the selection back to
1317 // the parent, which handles the case where the selected item was removed. 1322 // the parent, which handles the case where the selected item was removed.
1318 SetSelection(state_.item->GetParentMenuItem(), true, true); 1323 SetSelection(state_.item->GetParentMenuItem(),
1324 SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
1319 1325
1320 OpenMenuImpl(item, false); 1326 OpenMenuImpl(item, false);
1321 } 1327 }
1322 1328
1323 void MenuController::BuildPathsAndCalculateDiff( 1329 void MenuController::BuildPathsAndCalculateDiff(
1324 MenuItemView* old_item, 1330 MenuItemView* old_item,
1325 MenuItemView* new_item, 1331 MenuItemView* new_item,
1326 std::vector<MenuItemView*>* old_path, 1332 std::vector<MenuItemView*>* old_path,
1327 std::vector<MenuItemView*>* new_path, 1333 std::vector<MenuItemView*>* new_path,
1328 size_t* first_diff_at) { 1334 size_t* first_diff_at) {
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1473 } 1479 }
1474 1480
1475 void MenuController::IncrementSelection(int delta) { 1481 void MenuController::IncrementSelection(int delta) {
1476 MenuItemView* item = pending_state_.item; 1482 MenuItemView* item = pending_state_.item;
1477 DCHECK(item); 1483 DCHECK(item);
1478 if (pending_state_.submenu_open && item->HasSubmenu() && 1484 if (pending_state_.submenu_open && item->HasSubmenu() &&
1479 item->GetSubmenu()->IsShowing()) { 1485 item->GetSubmenu()->IsShowing()) {
1480 // A menu is selected and open, but none of its children are selected, 1486 // A menu is selected and open, but none of its children are selected,
1481 // select the first menu item. 1487 // select the first menu item.
1482 if (item->GetSubmenu()->GetMenuItemCount()) { 1488 if (item->GetSubmenu()->GetMenuItemCount()) {
1483 SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, false); 1489 SetSelection(item->GetSubmenu()->GetMenuItemAt(0), SELECTION_DEFAULT);
1484 ScrollToVisible(item->GetSubmenu()->GetMenuItemAt(0)); 1490 ScrollToVisible(item->GetSubmenu()->GetMenuItemAt(0));
1485 return; 1491 return;
1486 } 1492 }
1487 } 1493 }
1488 1494
1489 if (item->GetChildViewCount()) { 1495 if (item->GetChildViewCount()) {
1490 View* hot_view = GetFirstHotTrackedView(item); 1496 View* hot_view = GetFirstHotTrackedView(item);
1491 if (hot_view) { 1497 if (hot_view) {
1492 hot_view->SetHotTracked(false); 1498 hot_view->SetHotTracked(false);
1493 View* to_make_hot = GetNextFocusableView(item, hot_view, delta == 1); 1499 View* to_make_hot = GetNextFocusableView(item, hot_view, delta == 1);
(...skipping 14 matching lines...) Expand all
1508 MenuItemView* parent = item->GetParentMenuItem(); 1514 MenuItemView* parent = item->GetParentMenuItem();
1509 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); 1515 int parent_count = parent->GetSubmenu()->GetMenuItemCount();
1510 if (parent_count > 1) { 1516 if (parent_count > 1) {
1511 for (int i = 0; i < parent_count; ++i) { 1517 for (int i = 0; i < parent_count; ++i) {
1512 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { 1518 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) {
1513 MenuItemView* to_select = 1519 MenuItemView* to_select =
1514 FindNextSelectableMenuItem(parent, i, delta); 1520 FindNextSelectableMenuItem(parent, i, delta);
1515 if (!to_select) 1521 if (!to_select)
1516 break; 1522 break;
1517 ScrollToVisible(to_select); 1523 ScrollToVisible(to_select);
1518 SetSelection(to_select, false, false); 1524 SetSelection(to_select, SELECTION_DEFAULT);
1519 View* to_make_hot = GetInitialFocusableView(to_select, delta == 1); 1525 View* to_make_hot = GetInitialFocusableView(to_select, delta == 1);
1520 if (to_make_hot) 1526 if (to_make_hot)
1521 to_make_hot->SetHotTracked(true); 1527 to_make_hot->SetHotTracked(true);
1522 break; 1528 break;
1523 } 1529 }
1524 } 1530 }
1525 } 1531 }
1526 } 1532 }
1527 } 1533 }
1528 1534
(...skipping 12 matching lines...) Expand all
1541 if (child->IsVisible()) 1547 if (child->IsVisible())
1542 return child; 1548 return child;
1543 } while (index != start_index); 1549 } while (index != start_index);
1544 return NULL; 1550 return NULL;
1545 } 1551 }
1546 1552
1547 void MenuController::OpenSubmenuChangeSelectionIfCan() { 1553 void MenuController::OpenSubmenuChangeSelectionIfCan() {
1548 MenuItemView* item = pending_state_.item; 1554 MenuItemView* item = pending_state_.item;
1549 if (item->HasSubmenu()) { 1555 if (item->HasSubmenu()) {
1550 if (item->GetSubmenu()->GetMenuItemCount() > 0) { 1556 if (item->GetSubmenu()->GetMenuItemCount() > 0) {
1551 SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, true); 1557 SetSelection(item->GetSubmenu()->GetMenuItemAt(0),
1558 SELECTION_UPDATE_IMMEDIATELY);
1552 } else { 1559 } else {
1553 // No menu items, just show the sub-menu. 1560 // No menu items, just show the sub-menu.
1554 SetSelection(item, true, true); 1561 SetSelection(item, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
1555 } 1562 }
1556 } 1563 }
1557 } 1564 }
1558 1565
1559 void MenuController::CloseSubmenu() { 1566 void MenuController::CloseSubmenu() {
1560 MenuItemView* item = state_.item; 1567 MenuItemView* item = state_.item;
1561 DCHECK(item); 1568 DCHECK(item);
1562 if (!item->GetParentMenuItem()) 1569 if (!item->GetParentMenuItem())
1563 return; 1570 return;
1564 if (item->HasSubmenu() && item->GetSubmenu()->IsShowing()) { 1571 if (item->HasSubmenu() && item->GetSubmenu()->IsShowing()) {
1565 SetSelection(item, false, true); 1572 SetSelection(item, SELECTION_UPDATE_IMMEDIATELY);
1566 } else if (item->GetParentMenuItem()->GetParentMenuItem()) { 1573 } else if (item->GetParentMenuItem()->GetParentMenuItem()) {
1567 SetSelection(item->GetParentMenuItem(), false, true); 1574 SetSelection(item->GetParentMenuItem(), SELECTION_UPDATE_IMMEDIATELY);
1568 } 1575 }
1569 } 1576 }
1570 1577
1571 MenuController::SelectByCharDetails MenuController::FindChildForMnemonic( 1578 MenuController::SelectByCharDetails MenuController::FindChildForMnemonic(
1572 MenuItemView* parent, 1579 MenuItemView* parent,
1573 wchar_t key, 1580 wchar_t key,
1574 bool (*match_function)(MenuItemView* menu, wchar_t mnemonic)) { 1581 bool (*match_function)(MenuItemView* menu, wchar_t mnemonic)) {
1575 SubmenuView* submenu = parent->GetSubmenu(); 1582 SubmenuView* submenu = parent->GetSubmenu();
1576 DCHECK(submenu); 1583 DCHECK(submenu);
1577 SelectByCharDetails details; 1584 SelectByCharDetails details;
(...skipping 21 matching lines...) Expand all
1599 bool MenuController::AcceptOrSelect(MenuItemView* parent, 1606 bool MenuController::AcceptOrSelect(MenuItemView* parent,
1600 const SelectByCharDetails& details) { 1607 const SelectByCharDetails& details) {
1601 // This should only be invoked if there is a match. 1608 // This should only be invoked if there is a match.
1602 DCHECK(details.first_match != -1); 1609 DCHECK(details.first_match != -1);
1603 DCHECK(parent->HasSubmenu()); 1610 DCHECK(parent->HasSubmenu());
1604 SubmenuView* submenu = parent->GetSubmenu(); 1611 SubmenuView* submenu = parent->GetSubmenu();
1605 DCHECK(submenu); 1612 DCHECK(submenu);
1606 if (!details.has_multiple) { 1613 if (!details.has_multiple) {
1607 // There's only one match, activate it (or open if it has a submenu). 1614 // There's only one match, activate it (or open if it has a submenu).
1608 if (submenu->GetMenuItemAt(details.first_match)->HasSubmenu()) { 1615 if (submenu->GetMenuItemAt(details.first_match)->HasSubmenu()) {
1609 SetSelection(submenu->GetMenuItemAt(details.first_match), true, false); 1616 SetSelection(submenu->GetMenuItemAt(details.first_match),
1617 SELECTION_OPEN_SUBMENU);
1610 } else { 1618 } else {
1611 Accept(submenu->GetMenuItemAt(details.first_match), 0); 1619 Accept(submenu->GetMenuItemAt(details.first_match), 0);
1612 return true; 1620 return true;
1613 } 1621 }
1614 } else if (details.index_of_item == -1 || details.next_match == -1) { 1622 } else if (details.index_of_item == -1 || details.next_match == -1) {
1615 SetSelection(submenu->GetMenuItemAt(details.first_match), false, false); 1623 SetSelection(submenu->GetMenuItemAt(details.first_match),
1624 SELECTION_DEFAULT);
1616 } else { 1625 } else {
1617 SetSelection(submenu->GetMenuItemAt(details.next_match), false, false); 1626 SetSelection(submenu->GetMenuItemAt(details.next_match),
1627 SELECTION_DEFAULT);
1618 } 1628 }
1619 return false; 1629 return false;
1620 } 1630 }
1621 1631
1622 bool MenuController::SelectByChar(wchar_t character) { 1632 bool MenuController::SelectByChar(wchar_t character) {
1623 wchar_t char_array[1] = { character }; 1633 wchar_t char_array[1] = { character };
1624 wchar_t key = UTF16ToWide(l10n_util::ToLower(WideToUTF16(char_array)))[0]; 1634 wchar_t key = UTF16ToWide(l10n_util::ToLower(WideToUTF16(char_array)))[0];
1625 MenuItemView* item = pending_state_.item; 1635 MenuItemView* item = pending_state_.item;
1626 if (!item->HasSubmenu() || !item->GetSubmenu()->IsShowing()) 1636 if (!item->HasSubmenu() || !item->GetSubmenu()->IsShowing())
1627 item = item->GetParentMenuItem(); 1637 item = item->GetParentMenuItem();
(...skipping 18 matching lines...) Expand all
1646 details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic); 1656 details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
1647 if (details.first_match != -1) 1657 if (details.first_match != -1)
1648 return AcceptOrSelect(item, details); 1658 return AcceptOrSelect(item, details);
1649 1659
1650 return false; 1660 return false;
1651 } 1661 }
1652 1662
1653 #if defined(OS_WIN) 1663 #if defined(OS_WIN)
1654 void MenuController::RepostEvent(SubmenuView* source, 1664 void MenuController::RepostEvent(SubmenuView* source,
1655 const MouseEvent& event) { 1665 const MouseEvent& event) {
1666 if (!state_.item) {
1667 // We some times get an event after closing all the menus. Ignore it.
1668 // Make sure the menu is in fact not visible. If the menu is visible, then
1669 // we're in a bad state where we think the menu isn't visibile but it is.
1670 CHECK(!source->GetWidget()->IsVisible());
1671 return;
1672 }
1673
1656 gfx::Point screen_loc(event.location()); 1674 gfx::Point screen_loc(event.location());
1657 View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); 1675 View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
1658 HWND window = WindowFromPoint(screen_loc.ToPOINT()); 1676 HWND window = WindowFromPoint(screen_loc.ToPOINT());
1659 if (window) { 1677 if (window) {
1660 // Release the capture. 1678 // Release the capture.
1661 SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu(); 1679 SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu();
1662 submenu->ReleaseCapture(); 1680 submenu->ReleaseCapture();
1663 1681
1664 if (submenu->native_window() && submenu->native_window() && 1682 if (submenu->native_window() && submenu->native_window() &&
1665 GetWindowThreadProcessId(submenu->native_window(), NULL) != 1683 GetWindowThreadProcessId(submenu->native_window(), NULL) !=
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
1817 1835
1818 MouseEvent release_event(Event::ET_MOUSE_RELEASED, -1, -1, 0); 1836 MouseEvent release_event(Event::ET_MOUSE_RELEASED, -1, -1, 0);
1819 // Reset the active_mouse_view_ before sending mouse released. That way if if 1837 // Reset the active_mouse_view_ before sending mouse released. That way if if
1820 // calls back to use we aren't in a weird state. 1838 // calls back to use we aren't in a weird state.
1821 View* active_view = active_mouse_view_; 1839 View* active_view = active_mouse_view_;
1822 active_mouse_view_ = NULL; 1840 active_mouse_view_ = NULL;
1823 active_view->OnMouseReleased(release_event, true); 1841 active_view->OnMouseReleased(release_event, true);
1824 } 1842 }
1825 1843
1826 } // namespace views 1844 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/menu/menu_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698