| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ash/shelf/shelf_view.h" | 5 #include "ash/shelf/shelf_view.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <memory> |
| 8 | 9 |
| 9 #include "ash/ash_constants.h" | 10 #include "ash/ash_constants.h" |
| 10 #include "ash/ash_switches.h" | 11 #include "ash/ash_switches.h" |
| 11 #include "ash/drag_drop/drag_image_view.h" | 12 #include "ash/drag_drop/drag_image_view.h" |
| 12 #include "ash/metrics/user_metrics_recorder.h" | 13 #include "ash/metrics/user_metrics_recorder.h" |
| 13 #include "ash/scoped_target_root_window.h" | 14 #include "ash/scoped_target_root_window.h" |
| 14 #include "ash/shelf/app_list_button.h" | 15 #include "ash/shelf/app_list_button.h" |
| 15 #include "ash/shelf/overflow_bubble.h" | 16 #include "ash/shelf/overflow_bubble.h" |
| 16 #include "ash/shelf/overflow_bubble_view.h" | 17 #include "ash/shelf/overflow_bubble_view.h" |
| 17 #include "ash/shelf/overflow_button.h" | 18 #include "ash/shelf/overflow_button.h" |
| 18 #include "ash/shelf/shelf.h" | 19 #include "ash/shelf/shelf.h" |
| 19 #include "ash/shelf/shelf_button.h" | 20 #include "ash/shelf/shelf_button.h" |
| 20 #include "ash/shelf/shelf_constants.h" | 21 #include "ash/shelf/shelf_constants.h" |
| 21 #include "ash/shelf/shelf_delegate.h" | 22 #include "ash/shelf/shelf_delegate.h" |
| 22 #include "ash/shelf/shelf_icon_observer.h" | 23 #include "ash/shelf/shelf_icon_observer.h" |
| 23 #include "ash/shelf/shelf_item_delegate_manager.h" | 24 #include "ash/shelf/shelf_item_delegate_manager.h" |
| 24 #include "ash/shelf/shelf_menu_model.h" | 25 #include "ash/shelf/shelf_menu_model.h" |
| 25 #include "ash/shelf/shelf_model.h" | 26 #include "ash/shelf/shelf_model.h" |
| 26 #include "ash/shelf/shelf_widget.h" | 27 #include "ash/shelf/shelf_widget.h" |
| 27 #include "ash/shell.h" | 28 #include "ash/shell.h" |
| 28 #include "ash/shell_delegate.h" | 29 #include "ash/shell_delegate.h" |
| 29 #include "ash/wm/coordinate_conversion.h" | 30 #include "ash/wm/coordinate_conversion.h" |
| 30 #include "base/auto_reset.h" | 31 #include "base/auto_reset.h" |
| 31 #include "base/memory/scoped_ptr.h" | |
| 32 #include "base/metrics/histogram.h" | 32 #include "base/metrics/histogram.h" |
| 33 #include "grit/ash_strings.h" | 33 #include "grit/ash_strings.h" |
| 34 #include "ui/accessibility/ax_view_state.h" | 34 #include "ui/accessibility/ax_view_state.h" |
| 35 #include "ui/aura/client/screen_position_client.h" | 35 #include "ui/aura/client/screen_position_client.h" |
| 36 #include "ui/aura/window.h" | 36 #include "ui/aura/window.h" |
| 37 #include "ui/aura/window_event_dispatcher.h" | 37 #include "ui/aura/window_event_dispatcher.h" |
| 38 #include "ui/base/l10n/l10n_util.h" | 38 #include "ui/base/l10n/l10n_util.h" |
| 39 #include "ui/base/models/simple_menu_model.h" | 39 #include "ui/base/models/simple_menu_model.h" |
| 40 #include "ui/base/resource/resource_bundle.h" | 40 #include "ui/base/resource/resource_bundle.h" |
| 41 #include "ui/compositor/layer.h" | 41 #include "ui/compositor/layer.h" |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 view_->layer()->SetOpacity(1 - animation->GetCurrentValue()); | 323 view_->layer()->SetOpacity(1 - animation->GetCurrentValue()); |
| 324 view_->layer()->ScheduleDraw(); | 324 view_->layer()->ScheduleDraw(); |
| 325 } | 325 } |
| 326 void AnimationEnded(const Animation* animation) override { | 326 void AnimationEnded(const Animation* animation) override { |
| 327 shelf_view_->OnFadeOutAnimationEnded(); | 327 shelf_view_->OnFadeOutAnimationEnded(); |
| 328 } | 328 } |
| 329 void AnimationCanceled(const Animation* animation) override {} | 329 void AnimationCanceled(const Animation* animation) override {} |
| 330 | 330 |
| 331 private: | 331 private: |
| 332 ShelfView* shelf_view_; | 332 ShelfView* shelf_view_; |
| 333 scoped_ptr<views::View> view_; | 333 std::unique_ptr<views::View> view_; |
| 334 | 334 |
| 335 DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate); | 335 DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate); |
| 336 }; | 336 }; |
| 337 | 337 |
| 338 // AnimationDelegate used to trigger fading an element in. When an item is | 338 // AnimationDelegate used to trigger fading an element in. When an item is |
| 339 // inserted this delegate is attached to the animation that expands the size of | 339 // inserted this delegate is attached to the animation that expands the size of |
| 340 // the item. When done it kicks off another animation to fade the item in. | 340 // the item. When done it kicks off another animation to fade the item in. |
| 341 class ShelfView::StartFadeAnimationDelegate : public gfx::AnimationDelegate { | 341 class ShelfView::StartFadeAnimationDelegate : public gfx::AnimationDelegate { |
| 342 public: | 342 public: |
| 343 StartFadeAnimationDelegate(ShelfView* host, | 343 StartFadeAnimationDelegate(ShelfView* host, |
| (...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 view->set_context_menu_controller(this); | 1001 view->set_context_menu_controller(this); |
| 1002 ConfigureChildView(view); | 1002 ConfigureChildView(view); |
| 1003 return view; | 1003 return view; |
| 1004 } | 1004 } |
| 1005 | 1005 |
| 1006 void ShelfView::FadeIn(views::View* view) { | 1006 void ShelfView::FadeIn(views::View* view) { |
| 1007 view->SetVisible(true); | 1007 view->SetVisible(true); |
| 1008 view->layer()->SetOpacity(0); | 1008 view->layer()->SetOpacity(0); |
| 1009 AnimateToIdealBounds(); | 1009 AnimateToIdealBounds(); |
| 1010 bounds_animator_->SetAnimationDelegate( | 1010 bounds_animator_->SetAnimationDelegate( |
| 1011 view, | 1011 view, std::unique_ptr<gfx::AnimationDelegate>( |
| 1012 scoped_ptr<gfx::AnimationDelegate>(new FadeInAnimationDelegate(view))); | 1012 new FadeInAnimationDelegate(view))); |
| 1013 } | 1013 } |
| 1014 | 1014 |
| 1015 void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) { | 1015 void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) { |
| 1016 DCHECK(!dragging()); | 1016 DCHECK(!dragging()); |
| 1017 DCHECK(drag_view_); | 1017 DCHECK(drag_view_); |
| 1018 drag_pointer_ = pointer; | 1018 drag_pointer_ = pointer; |
| 1019 start_drag_index_ = view_model_->GetIndexOfView(drag_view_); | 1019 start_drag_index_ = view_model_->GetIndexOfView(drag_view_); |
| 1020 | 1020 |
| 1021 if (start_drag_index_== -1) { | 1021 if (start_drag_index_== -1) { |
| 1022 CancelDrag(-1); | 1022 CancelDrag(-1); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1363 } | 1363 } |
| 1364 | 1364 |
| 1365 void ShelfView::StartFadeInLastVisibleItem() { | 1365 void ShelfView::StartFadeInLastVisibleItem() { |
| 1366 // If overflow button is visible and there is a valid new last item, fading | 1366 // If overflow button is visible and there is a valid new last item, fading |
| 1367 // the new last item in after sliding animation is finished. | 1367 // the new last item in after sliding animation is finished. |
| 1368 if (overflow_button_->visible() && last_visible_index_ >= 0) { | 1368 if (overflow_button_->visible() && last_visible_index_ >= 0) { |
| 1369 views::View* last_visible_view = view_model_->view_at(last_visible_index_); | 1369 views::View* last_visible_view = view_model_->view_at(last_visible_index_); |
| 1370 last_visible_view->layer()->SetOpacity(0); | 1370 last_visible_view->layer()->SetOpacity(0); |
| 1371 bounds_animator_->SetAnimationDelegate( | 1371 bounds_animator_->SetAnimationDelegate( |
| 1372 last_visible_view, | 1372 last_visible_view, |
| 1373 scoped_ptr<gfx::AnimationDelegate>( | 1373 std::unique_ptr<gfx::AnimationDelegate>( |
| 1374 new StartFadeAnimationDelegate(this, last_visible_view))); | 1374 new StartFadeAnimationDelegate(this, last_visible_view))); |
| 1375 } | 1375 } |
| 1376 } | 1376 } |
| 1377 | 1377 |
| 1378 void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const { | 1378 void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const { |
| 1379 const int first_overflow_index = last_visible_index_ + 1; | 1379 const int first_overflow_index = last_visible_index_ + 1; |
| 1380 const int last_overflow_index = last_hidden_index_; | 1380 const int last_overflow_index = last_hidden_index_; |
| 1381 DCHECK_LE(first_overflow_index, last_overflow_index); | 1381 DCHECK_LE(first_overflow_index, last_overflow_index); |
| 1382 DCHECK_LT(last_overflow_index, view_model_->view_size()); | 1382 DCHECK_LT(last_overflow_index, view_model_->view_size()); |
| 1383 | 1383 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1543 CalculateIdealBounds(&ideal_bounds); | 1543 CalculateIdealBounds(&ideal_bounds); |
| 1544 view->SetBoundsRect(view_model_->ideal_bounds(model_index)); | 1544 view->SetBoundsRect(view_model_->ideal_bounds(model_index)); |
| 1545 | 1545 |
| 1546 // The first animation moves all the views to their target position. |view| | 1546 // The first animation moves all the views to their target position. |view| |
| 1547 // is hidden, so it visually appears as though we are providing space for | 1547 // is hidden, so it visually appears as though we are providing space for |
| 1548 // it. When done we'll fade the view in. | 1548 // it. When done we'll fade the view in. |
| 1549 AnimateToIdealBounds(); | 1549 AnimateToIdealBounds(); |
| 1550 if (model_index <= last_visible_index_ || | 1550 if (model_index <= last_visible_index_ || |
| 1551 model_index >= model_->FirstPanelIndex()) { | 1551 model_index >= model_->FirstPanelIndex()) { |
| 1552 bounds_animator_->SetAnimationDelegate( | 1552 bounds_animator_->SetAnimationDelegate( |
| 1553 view, | 1553 view, std::unique_ptr<gfx::AnimationDelegate>( |
| 1554 scoped_ptr<gfx::AnimationDelegate>( | 1554 new StartFadeAnimationDelegate(this, view))); |
| 1555 new StartFadeAnimationDelegate(this, view))); | |
| 1556 } else { | 1555 } else { |
| 1557 // Undo the hiding if animation does not run. | 1556 // Undo the hiding if animation does not run. |
| 1558 view->layer()->SetOpacity(1.0f); | 1557 view->layer()->SetOpacity(1.0f); |
| 1559 } | 1558 } |
| 1560 } | 1559 } |
| 1561 | 1560 |
| 1562 void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) { | 1561 void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) { |
| 1563 if (id == context_menu_id_) | 1562 if (id == context_menu_id_) |
| 1564 launcher_menu_runner_.reset(); | 1563 launcher_menu_runner_.reset(); |
| 1565 { | 1564 { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1579 last_hidden_index_ = std::min(last_hidden_index_, | 1578 last_hidden_index_ = std::min(last_hidden_index_, |
| 1580 view_model_->view_size() - 1); | 1579 view_model_->view_size() - 1); |
| 1581 UpdateOverflowRange(overflow_bubble_->shelf_view()); | 1580 UpdateOverflowRange(overflow_bubble_->shelf_view()); |
| 1582 } | 1581 } |
| 1583 | 1582 |
| 1584 if (view->visible()) { | 1583 if (view->visible()) { |
| 1585 // The first animation fades out the view. When done we'll animate the rest | 1584 // The first animation fades out the view. When done we'll animate the rest |
| 1586 // of the views to their target location. | 1585 // of the views to their target location. |
| 1587 bounds_animator_->AnimateViewTo(view, view->bounds()); | 1586 bounds_animator_->AnimateViewTo(view, view->bounds()); |
| 1588 bounds_animator_->SetAnimationDelegate( | 1587 bounds_animator_->SetAnimationDelegate( |
| 1589 view, | 1588 view, std::unique_ptr<gfx::AnimationDelegate>( |
| 1590 scoped_ptr<gfx::AnimationDelegate>( | 1589 new FadeOutAnimationDelegate(this, view))); |
| 1591 new FadeOutAnimationDelegate(this, view))); | |
| 1592 } else { | 1590 } else { |
| 1593 // We don't need to show a fade out animation for invisible |view|. When an | 1591 // We don't need to show a fade out animation for invisible |view|. When an |
| 1594 // item is ripped out from the shelf, its |view| is already invisible. | 1592 // item is ripped out from the shelf, its |view| is already invisible. |
| 1595 AnimateToIdealBounds(); | 1593 AnimateToIdealBounds(); |
| 1596 } | 1594 } |
| 1597 | 1595 |
| 1598 if (view == tooltip_.GetCurrentAnchorView()) | 1596 if (view == tooltip_.GetCurrentAnchorView()) |
| 1599 tooltip_.Close(); | 1597 tooltip_.Close(); |
| 1600 } | 1598 } |
| 1601 | 1599 |
| 1602 void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) { | 1600 void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) { |
| 1603 const ShelfItem& item(model_->items()[model_index]); | 1601 const ShelfItem& item(model_->items()[model_index]); |
| 1604 if (old_item.type != item.type) { | 1602 if (old_item.type != item.type) { |
| 1605 // Type changed, swap the views. | 1603 // Type changed, swap the views. |
| 1606 model_index = CancelDrag(model_index); | 1604 model_index = CancelDrag(model_index); |
| 1607 scoped_ptr<views::View> old_view(view_model_->view_at(model_index)); | 1605 std::unique_ptr<views::View> old_view(view_model_->view_at(model_index)); |
| 1608 bounds_animator_->StopAnimatingView(old_view.get()); | 1606 bounds_animator_->StopAnimatingView(old_view.get()); |
| 1609 // Removing and re-inserting a view in our view model will strip the ideal | 1607 // Removing and re-inserting a view in our view model will strip the ideal |
| 1610 // bounds from the item. To avoid recalculation of everything the bounds | 1608 // bounds from the item. To avoid recalculation of everything the bounds |
| 1611 // get remembered and restored after the insertion to the previous value. | 1609 // get remembered and restored after the insertion to the previous value. |
| 1612 gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index); | 1610 gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index); |
| 1613 view_model_->Remove(model_index); | 1611 view_model_->Remove(model_index); |
| 1614 views::View* new_view = CreateViewForItem(item); | 1612 views::View* new_view = CreateViewForItem(item); |
| 1615 AddChildView(new_view); | 1613 AddChildView(new_view); |
| 1616 view_model_->Add(new_view, model_index); | 1614 view_model_->Add(new_view, model_index); |
| 1617 view_model_->set_ideal_bounds(model_index, old_ideal_bounds); | 1615 view_model_->set_ideal_bounds(model_index, old_ideal_bounds); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1685 // animating open due to the first click, then immediately minimizes due to | 1683 // animating open due to the first click, then immediately minimizes due to |
| 1686 // the second click. The user most likely intended to open or minimize the | 1684 // the second click. The user most likely intended to open or minimize the |
| 1687 // item once, not do both. | 1685 // item once, not do both. |
| 1688 if (event.flags() & ui::EF_IS_DOUBLE_CLICK) | 1686 if (event.flags() & ui::EF_IS_DOUBLE_CLICK) |
| 1689 return; | 1687 return; |
| 1690 | 1688 |
| 1691 { | 1689 { |
| 1692 ScopedTargetRootWindow scoped_target( | 1690 ScopedTargetRootWindow scoped_target( |
| 1693 sender->GetWidget()->GetNativeView()->GetRootWindow()); | 1691 sender->GetWidget()->GetNativeView()->GetRootWindow()); |
| 1694 // Slow down activation animations if shift key is pressed. | 1692 // Slow down activation animations if shift key is pressed. |
| 1695 scoped_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations; | 1693 std::unique_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations; |
| 1696 if (event.IsShiftDown()) { | 1694 if (event.IsShiftDown()) { |
| 1697 slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode( | 1695 slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode( |
| 1698 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); | 1696 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); |
| 1699 } | 1697 } |
| 1700 | 1698 |
| 1701 // Collect usage statistics before we decide what to do with the click. | 1699 // Collect usage statistics before we decide what to do with the click. |
| 1702 switch (model_->items()[view_index].type) { | 1700 switch (model_->items()[view_index].type) { |
| 1703 case TYPE_APP_SHORTCUT: | 1701 case TYPE_APP_SHORTCUT: |
| 1704 case TYPE_WINDOWED_APP: | 1702 case TYPE_WINDOWED_APP: |
| 1705 case TYPE_PLATFORM_APP: | 1703 case TYPE_PLATFORM_APP: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1732 if (performed_action != ShelfItemDelegate::kNewWindowCreated) | 1730 if (performed_action != ShelfItemDelegate::kNewWindowCreated) |
| 1733 ShowListMenuForView(model_->items()[view_index], sender, event); | 1731 ShowListMenuForView(model_->items()[view_index], sender, event); |
| 1734 } | 1732 } |
| 1735 } | 1733 } |
| 1736 | 1734 |
| 1737 void ShelfView::ShowListMenuForView(const ShelfItem& item, | 1735 void ShelfView::ShowListMenuForView(const ShelfItem& item, |
| 1738 views::View* source, | 1736 views::View* source, |
| 1739 const ui::Event& event) { | 1737 const ui::Event& event) { |
| 1740 ShelfItemDelegate* item_delegate = | 1738 ShelfItemDelegate* item_delegate = |
| 1741 item_manager_->GetShelfItemDelegate(item.id); | 1739 item_manager_->GetShelfItemDelegate(item.id); |
| 1742 scoped_ptr<ui::MenuModel> list_menu_model( | 1740 std::unique_ptr<ui::MenuModel> list_menu_model( |
| 1743 item_delegate->CreateApplicationMenu(event.flags())); | 1741 item_delegate->CreateApplicationMenu(event.flags())); |
| 1744 | 1742 |
| 1745 // Make sure we have a menu and it has at least two items in addition to the | 1743 // Make sure we have a menu and it has at least two items in addition to the |
| 1746 // application title and the 3 spacing separators. | 1744 // application title and the 3 spacing separators. |
| 1747 if (!list_menu_model.get() || list_menu_model->GetItemCount() <= 5) | 1745 if (!list_menu_model.get() || list_menu_model->GetItemCount() <= 5) |
| 1748 return; | 1746 return; |
| 1749 | 1747 |
| 1750 context_menu_id_ = item.id; | 1748 context_menu_id_ = item.id; |
| 1751 ShowMenu(list_menu_model.get(), source, gfx::Point(), false, | 1749 ShowMenu(list_menu_model.get(), source, gfx::Point(), false, |
| 1752 ui::GetMenuSourceTypeForEvent(event)); | 1750 ui::GetMenuSourceTypeForEvent(event)); |
| 1753 } | 1751 } |
| 1754 | 1752 |
| 1755 void ShelfView::ShowContextMenuForView(views::View* source, | 1753 void ShelfView::ShowContextMenuForView(views::View* source, |
| 1756 const gfx::Point& point, | 1754 const gfx::Point& point, |
| 1757 ui::MenuSourceType source_type) { | 1755 ui::MenuSourceType source_type) { |
| 1758 const ShelfItem* item = ShelfItemForView(source); | 1756 const ShelfItem* item = ShelfItemForView(source); |
| 1759 if (!item) { | 1757 if (!item) { |
| 1760 Shell::GetInstance()->ShowContextMenu(point, source_type); | 1758 Shell::GetInstance()->ShowContextMenu(point, source_type); |
| 1761 return; | 1759 return; |
| 1762 } | 1760 } |
| 1763 | 1761 |
| 1764 scoped_ptr<ui::MenuModel> context_menu_model( | 1762 std::unique_ptr<ui::MenuModel> context_menu_model( |
| 1765 Shell::GetInstance()->delegate()->CreateContextMenu(shelf_, item)); | 1763 Shell::GetInstance()->delegate()->CreateContextMenu(shelf_, item)); |
| 1766 if (!context_menu_model) | 1764 if (!context_menu_model) |
| 1767 return; | 1765 return; |
| 1768 | 1766 |
| 1769 context_menu_id_ = item ? item->id : 0; | 1767 context_menu_id_ = item ? item->id : 0; |
| 1770 ShowMenu(context_menu_model.get(), source, point, true, source_type); | 1768 ShowMenu(context_menu_model.get(), source, point, true, source_type); |
| 1771 } | 1769 } |
| 1772 | 1770 |
| 1773 void ShelfView::ShowMenu(ui::MenuModel* menu_model, | 1771 void ShelfView::ShowMenu(ui::MenuModel* menu_model, |
| 1774 views::View* source, | 1772 views::View* source, |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1878 | 1876 |
| 1879 int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const { | 1877 int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const { |
| 1880 const gfx::Rect bounds = GetBoundsInScreen(); | 1878 const gfx::Rect bounds = GetBoundsInScreen(); |
| 1881 int distance = shelf_->SelectValueForShelfAlignment( | 1879 int distance = shelf_->SelectValueForShelfAlignment( |
| 1882 bounds.y() - coordinate.y(), coordinate.x() - bounds.right(), | 1880 bounds.y() - coordinate.y(), coordinate.x() - bounds.right(), |
| 1883 bounds.x() - coordinate.x()); | 1881 bounds.x() - coordinate.x()); |
| 1884 return distance > 0 ? distance : 0; | 1882 return distance > 0 ? distance : 0; |
| 1885 } | 1883 } |
| 1886 | 1884 |
| 1887 } // namespace ash | 1885 } // namespace ash |
| OLD | NEW |