OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "ui/message_center/views/message_center_view.h" | 5 #include "ui/message_center/views/message_center_view.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 #include <map> | 8 #include <map> |
9 | 9 |
10 #include "base/memory/weak_ptr.h" | 10 #include "base/memory/weak_ptr.h" |
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 virtual void ResetRepositionSession() OVERRIDE; | 479 virtual void ResetRepositionSession() OVERRIDE; |
480 virtual void ClearAllNotifications( | 480 virtual void ClearAllNotifications( |
481 const gfx::Rect& visible_scroll_rect) OVERRIDE; | 481 const gfx::Rect& visible_scroll_rect) OVERRIDE; |
482 | 482 |
483 // Overridden from views::BoundsAnimatorObserver. | 483 // Overridden from views::BoundsAnimatorObserver. |
484 virtual void OnBoundsAnimatorProgressed( | 484 virtual void OnBoundsAnimatorProgressed( |
485 views::BoundsAnimator* animator) OVERRIDE; | 485 views::BoundsAnimator* animator) OVERRIDE; |
486 virtual void OnBoundsAnimatorDone(views::BoundsAnimator* animator) OVERRIDE; | 486 virtual void OnBoundsAnimatorDone(views::BoundsAnimator* animator) OVERRIDE; |
487 | 487 |
488 private: | 488 private: |
| 489 // Returns the actual index for child of |index|. |
| 490 // RichMessageListView allows to slide down upper notifications, which means |
| 491 // that the upper ones should come above the lower ones. To achieve this, |
| 492 // inversed order is adopted. The top most notification is the last child, |
| 493 // and the bottom most notification is the first child. |
489 int GetActualIndex(int index); | 494 int GetActualIndex(int index); |
490 bool IsValidChild(views::View* child); | 495 bool IsValidChild(views::View* child); |
491 void DoUpdateIfPossible(); | 496 void DoUpdateIfPossible(); |
492 | 497 |
493 // Schedules animation for a child to the specified position. | 498 // Schedules animation for a child to the specified position. |
494 void AnimateChild(views::View* child, int top, int height); | 499 void AnimateChild(views::View* child, int top, int height); |
495 | 500 |
496 // Animate clearing one notification. | 501 // Animate clearing one notification. |
497 void AnimateClearingOneNotification(); | 502 void AnimateClearingOneNotification(); |
498 | 503 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 | 546 |
542 void RichMessageListView::Layout() { | 547 void RichMessageListView::Layout() { |
543 if (animator_.get()) | 548 if (animator_.get()) |
544 return; | 549 return; |
545 | 550 |
546 gfx::Rect child_area = GetContentsBounds(); | 551 gfx::Rect child_area = GetContentsBounds(); |
547 int top = child_area.y(); | 552 int top = child_area.y(); |
548 int between_items = | 553 int between_items = |
549 kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); | 554 kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); |
550 | 555 |
551 for (int i = 0; i < child_count(); ++i) { | 556 for (int i = child_count() - 1; i >= 0; --i) { |
552 views::View* child = child_at(i); | 557 views::View* child = child_at(i); |
553 if (!child->visible()) | 558 if (!child->visible()) |
554 continue; | 559 continue; |
555 int height = child->GetHeightForWidth(child_area.width()); | 560 int height = child->GetHeightForWidth(child_area.width()); |
556 child->SetBounds(child_area.x(), top, child_area.width(), height); | 561 child->SetBounds(child_area.x(), top, child_area.width(), height); |
557 top += height + between_items; | 562 top += height + between_items; |
558 } | 563 } |
559 } | 564 } |
560 | 565 |
561 void RichMessageListView::AddNotificationAt(views::View* view, int i) { | 566 void RichMessageListView::AddNotificationAt(views::View* view, int i) { |
562 AddChildViewAt(view, GetActualIndex(i)); | 567 // Increment by 1 because the default behavior of AddChildViewAt() is to |
| 568 // insert before the specified index. |
| 569 AddChildViewAt(view, GetActualIndex(i) + 1); |
563 if (GetContentsBounds().IsEmpty()) | 570 if (GetContentsBounds().IsEmpty()) |
564 return; | 571 return; |
565 | 572 |
566 adding_views_.insert(view); | 573 adding_views_.insert(view); |
567 DoUpdateIfPossible(); | 574 DoUpdateIfPossible(); |
568 } | 575 } |
569 | 576 |
570 void RichMessageListView::RemoveNotificationAt(int i) { | 577 void RichMessageListView::RemoveNotificationAt(int i) { |
571 views::View* child = child_at(GetActualIndex(i)); | 578 views::View* child = child_at(GetActualIndex(i)); |
572 if (GetContentsBounds().IsEmpty()) { | 579 if (GetContentsBounds().IsEmpty()) { |
573 delete child; | 580 delete child; |
574 } else { | 581 } else { |
575 if (child->layer()) { | 582 if (child->layer()) { |
576 deleting_views_.insert(child); | 583 deleting_views_.insert(child); |
577 } else { | 584 } else { |
578 if (animator_.get()) | 585 if (animator_.get()) |
579 animator_->StopAnimatingView(child); | 586 animator_->StopAnimatingView(child); |
580 delete child; | 587 delete child; |
581 } | 588 } |
582 DoUpdateIfPossible(); | 589 DoUpdateIfPossible(); |
583 } | 590 } |
584 } | 591 } |
585 | 592 |
586 void RichMessageListView::UpdateNotificationAt(views::View* view, int i) { | 593 void RichMessageListView::UpdateNotificationAt(views::View* view, int i) { |
587 views::View* child = child_at(GetActualIndex(i)); | 594 int actual_index = GetActualIndex(i); |
| 595 views::View* child = child_at(actual_index); |
588 if (animator_.get()) | 596 if (animator_.get()) |
589 animator_->StopAnimatingView(child); | 597 animator_->StopAnimatingView(child); |
590 gfx::Rect old_bounds = child->bounds(); | 598 gfx::Rect old_bounds = child->bounds(); |
591 if (deleting_views_.find(child) != deleting_views_.end()) | 599 if (deleting_views_.find(child) != deleting_views_.end()) |
592 deleting_views_.erase(child); | 600 deleting_views_.erase(child); |
593 if (deleted_when_done_.find(child) != deleted_when_done_.end()) | 601 if (deleted_when_done_.find(child) != deleted_when_done_.end()) |
594 deleted_when_done_.erase(child); | 602 deleted_when_done_.erase(child); |
595 delete child; | 603 delete child; |
596 AddChildViewAt(view, i); | 604 AddChildViewAt(view, actual_index); |
597 view->SetBounds(old_bounds.x(), old_bounds.y(), old_bounds.width(), | 605 view->SetBounds(old_bounds.x(), old_bounds.y(), old_bounds.width(), |
598 view->GetHeightForWidth(old_bounds.width())); | 606 view->GetHeightForWidth(old_bounds.width())); |
599 DoUpdateIfPossible(); | 607 DoUpdateIfPossible(); |
600 } | 608 } |
601 | 609 |
602 gfx::Size RichMessageListView::GetPreferredSize() { | 610 gfx::Size RichMessageListView::GetPreferredSize() { |
603 int width = 0; | 611 int width = 0; |
604 for (int i = 0; i < child_count(); i++) { | 612 for (int i = 0; i < child_count(); i++) { |
605 views::View* child = child_at(i); | 613 views::View* child = child_at(i); |
606 if (IsValidChild(child)) | 614 if (IsValidChild(child)) |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 if (has_deferred_task_) { | 698 if (has_deferred_task_) { |
691 has_deferred_task_ = false; | 699 has_deferred_task_ = false; |
692 DoUpdateIfPossible(); | 700 DoUpdateIfPossible(); |
693 } | 701 } |
694 | 702 |
695 if (GetWidget()) | 703 if (GetWidget()) |
696 GetWidget()->SynthesizeMouseMoveEvent(); | 704 GetWidget()->SynthesizeMouseMoveEvent(); |
697 } | 705 } |
698 | 706 |
699 int RichMessageListView::GetActualIndex(int index) { | 707 int RichMessageListView::GetActualIndex(int index) { |
700 for (int i = 0; i < child_count() && i <= index; ++i) | 708 // As is written in the comment in the declaration, this method |
701 index += IsValidChild(child_at(i)) ? 0 : 1; | 709 // returns actual index for the |index|-th valid child from the end. |
702 return std::min(index, child_count()); | 710 int actual_index = child_count() - 1; |
| 711 // Skips the invalid children at last. |
| 712 for (; actual_index > 0; --actual_index) { |
| 713 if (IsValidChild(child_at(actual_index))) |
| 714 break; |
| 715 } |
| 716 // Find the |index|-th valid child from the end. |
| 717 for (; actual_index >= 0 && index > 0; --actual_index) { |
| 718 index -= IsValidChild(child_at(actual_index)) ? 1 : 0; |
| 719 } |
| 720 return actual_index; |
703 } | 721 } |
704 | 722 |
705 bool RichMessageListView::IsValidChild(views::View* child) { | 723 bool RichMessageListView::IsValidChild(views::View* child) { |
706 return child->visible() && | 724 return child->visible() && |
707 deleting_views_.find(child) == deleting_views_.end() && | 725 deleting_views_.find(child) == deleting_views_.end() && |
708 deleted_when_done_.find(child) == deleted_when_done_.end(); | 726 deleted_when_done_.find(child) == deleted_when_done_.end(); |
709 } | 727 } |
710 | 728 |
711 void RichMessageListView::DoUpdateIfPossible() { | 729 void RichMessageListView::DoUpdateIfPossible() { |
712 gfx::Rect child_area = GetContentsBounds(); | 730 gfx::Rect child_area = GetContentsBounds(); |
713 if (child_area.IsEmpty()) | 731 if (child_area.IsEmpty()) |
714 return; | 732 return; |
715 | 733 |
716 if (animator_.get() && animator_->IsAnimating()) { | 734 if (animator_.get() && animator_->IsAnimating()) { |
717 has_deferred_task_ = true; | 735 has_deferred_task_ = true; |
718 return; | 736 return; |
719 } | 737 } |
720 | 738 |
721 if (!animator_.get()) { | 739 if (!animator_.get()) { |
722 animator_.reset(new views::BoundsAnimator(this)); | 740 animator_.reset(new views::BoundsAnimator(this)); |
723 animator_->AddObserver(this); | 741 animator_->AddObserver(this); |
724 } | 742 } |
725 | 743 |
726 if (!clearing_all_views_.empty()) { | 744 if (!clearing_all_views_.empty()) { |
727 AnimateClearingOneNotification(); | 745 AnimateClearingOneNotification(); |
728 return; | 746 return; |
729 } | 747 } |
730 | 748 |
731 int between_items = | 749 int first_index = -1; |
732 kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); | 750 for (int i = 0; i < child_count(); ++i) { |
733 int width = child_area.width(); | |
734 views::View* last_child = NULL; | |
735 for (int i = child_count() - 1; i >= 0; --i) { | |
736 views::View* child = child_at(i); | 751 views::View* child = child_at(i); |
737 if (IsValidChild(child)) { | 752 if (!IsValidChild(child)) { |
738 last_child = child; | 753 AnimateChild(child, child->y(), child->height()); |
| 754 } else if (child->y() < reposition_top_) { |
| 755 first_index = i; |
739 break; | 756 break; |
740 } | 757 } |
741 } | 758 } |
742 | 759 if (first_index > 0) { |
743 if (!last_child || reposition_top_ < last_child->bounds().y()) { | 760 int bottom = reposition_top_ + child_at(first_index)->height(); |
744 const int initial_top = std::max(reposition_top_, child_area.y()); | 761 int between_items = |
745 int top = initial_top; | 762 kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); |
746 for (int i = 0; i < child_count(); ++i) { | 763 for (int i = first_index; i < child_count(); ++i) { |
747 views::View* child = child_at(i); | 764 views::View* child = child_at(i); |
748 if (adding_views_.find(child) == adding_views_.end() && | 765 AnimateChild(child, bottom - child->height(), child->height()); |
749 child->bounds().y() < initial_top) { | 766 bottom -= child->height() + between_items; |
750 continue; | |
751 } | |
752 int height = child->GetHeightForWidth(width); | |
753 AnimateChild(child, top, height); | |
754 if (IsValidChild(child)) | |
755 top += height + between_items; | |
756 } | |
757 } else { | |
758 int bottom = reposition_top_ + last_child->GetHeightForWidth(width); | |
759 for (int i = child_count() - 1; i >= 0; --i) { | |
760 views::View* child = child_at(i); | |
761 int height = child->GetHeightForWidth(child_area.width()); | |
762 AnimateChild(child, bottom - height, height); | |
763 if (IsValidChild(child)) | |
764 bottom -= height + between_items; | |
765 } | 767 } |
766 } | 768 } |
767 adding_views_.clear(); | 769 adding_views_.clear(); |
768 deleting_views_.clear(); | 770 deleting_views_.clear(); |
769 } | 771 } |
770 | 772 |
771 void RichMessageListView::AnimateChild(views::View* child, | 773 void RichMessageListView::AnimateChild(views::View* child, |
772 int top, | 774 int top, |
773 int height) { | 775 int height) { |
774 gfx::Rect child_area = GetContentsBounds(); | 776 gfx::Rect child_area = GetContentsBounds(); |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1193 scroller_->InvalidateLayout(); | 1195 scroller_->InvalidateLayout(); |
1194 PreferredSizeChanged(); | 1196 PreferredSizeChanged(); |
1195 Layout(); | 1197 Layout(); |
1196 } | 1198 } |
1197 | 1199 |
1198 void MessageCenterView::SetNotificationViewForTest(views::View* view) { | 1200 void MessageCenterView::SetNotificationViewForTest(views::View* view) { |
1199 message_list_view_->AddNotificationAt(view, 0); | 1201 message_list_view_->AddNotificationAt(view, 0); |
1200 } | 1202 } |
1201 | 1203 |
1202 } // namespace message_center | 1204 } // namespace message_center |
OLD | NEW |