diff options
author | dcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-19 23:54:39 +0000 |
---|---|---|
committer | dcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-19 23:54:39 +0000 |
commit | 813d646b7778d251fd9f418a8e61cb0ee214b8ec (patch) | |
tree | b8061b2299de38db1a879f14f6725ea78883b09e /ash/launcher | |
parent | 16c5072cbc556b3eac9ec1560c7e57fc375f1058 (diff) | |
download | chromium_src-813d646b7778d251fd9f418a8e61cb0ee214b8ec.zip chromium_src-813d646b7778d251fd9f418a8e61cb0ee214b8ec.tar.gz chromium_src-813d646b7778d251fd9f418a8e61cb0ee214b8ec.tar.bz2 |
Implement LauncherIconObserver.
This will be used to listen for changes in the launcher view so that panels can be correctly drawn over the corresponding launcher icon.
BUG=124115
TEST=aura_shell_unittests
Review URL: https://chromiumcodereview.appspot.com/10116011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133089 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/launcher')
-rw-r--r-- | ash/launcher/launcher.cc | 8 | ||||
-rw-r--r-- | ash/launcher/launcher.h | 4 | ||||
-rw-r--r-- | ash/launcher/launcher_icon_observer.h | 28 | ||||
-rw-r--r-- | ash/launcher/launcher_view.cc | 42 | ||||
-rw-r--r-- | ash/launcher/launcher_view.h | 11 | ||||
-rw-r--r-- | ash/launcher/launcher_view_unittest.cc | 104 |
6 files changed, 190 insertions, 7 deletions
diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc index 5516442..afb05dc 100644 --- a/ash/launcher/launcher.cc +++ b/ash/launcher/launcher.cc @@ -186,6 +186,14 @@ gfx::Rect Launcher::GetScreenBoundsOfItemIconForWindow(aura::Window* window) { bounds.height()); } +void Launcher::AddIconObserver(LauncherIconObserver* observer) { + launcher_view_->AddIconObserver(observer); +} + +void Launcher::RemoveIconObserver(LauncherIconObserver* observer) { + launcher_view_->RemoveIconObserver(observer); +} + bool Launcher::IsShowingMenu() const { return launcher_view_->IsShowingMenu(); } diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h index ebc56b8..7955b07 100644 --- a/ash/launcher/launcher.h +++ b/ash/launcher/launcher.h @@ -30,6 +30,7 @@ class FocusCycler; class LauncherView; } +class LauncherIconObserver; class LauncherDelegate; class LauncherModel; @@ -56,6 +57,9 @@ class ASH_EXPORT Launcher : public internal::BackgroundAnimatorDelegate { // no item for the specified window an empty rect is returned. gfx::Rect GetScreenBoundsOfItemIconForWindow(aura::Window* window); + void AddIconObserver(LauncherIconObserver* observer); + void RemoveIconObserver(LauncherIconObserver* observer); + // Returns true if the Launcher is showing a context menu. bool IsShowingMenu() const; diff --git a/ash/launcher/launcher_icon_observer.h b/ash/launcher/launcher_icon_observer.h new file mode 100644 index 0000000..5b24e92 --- /dev/null +++ b/ash/launcher/launcher_icon_observer.h @@ -0,0 +1,28 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_LAUNCHER_LAUNCHER_ICON_OBSERVER_H_ +#define ASH_LAUNCHER_LAUNCHER_ICON_OBSERVER_H_ +#pragma once + +#include "base/basictypes.h" + +namespace ash { + +class ASH_EXPORT LauncherIconObserver { + public: + LauncherIconObserver() {} + + // Invoked when any icon on launcher changes position. + virtual void OnLauncherIconPositionsChanged() = 0; + + protected: + virtual ~LauncherIconObserver() {} + + DISALLOW_COPY_AND_ASSIGN(LauncherIconObserver); +}; + +} // namespace ash + +#endif // ASH_LAUNCHER_LAUNCHER_ICON_OBSERVER_H_ diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc index f844b7e..d19d334 100644 --- a/ash/launcher/launcher_view.cc +++ b/ash/launcher/launcher_view.cc @@ -6,6 +6,7 @@ #include "ash/launcher/launcher_button.h" #include "ash/launcher/launcher_delegate.h" +#include "ash/launcher/launcher_icon_observer.h" #include "ash/launcher/launcher_model.h" #include "ash/launcher/tabbed_launcher_button.h" #include "ash/shell.h" @@ -255,6 +256,7 @@ LauncherView::LauncherView(LauncherModel* model, LauncherDelegate* delegate) : model_(model), delegate_(delegate), view_model_(new views::ViewModel), + last_visible_index_(-1), overflow_button_(NULL), dragging_(NULL), drag_view_(NULL), @@ -305,7 +307,7 @@ void LauncherView::Init() { gfx::Rect LauncherView::GetIdealBoundsOfItemIcon(LauncherID id) { int index = model_->ItemIndexByID(id); - if (index == -1 || !view_model_->view_at(index)->visible()) + if (index == -1 || index > last_visible_index_) return gfx::Rect(); const gfx::Rect& ideal_bounds(view_model_->ideal_bounds(index)); DCHECK_NE(TYPE_APP_LIST, model_->items()[index].type); @@ -364,19 +366,19 @@ void LauncherView::CalculateIdealBounds(IdealBounds* bounds) { } bounds->overflow_bounds.set_size(gfx::Size(kButtonWidth, kButtonHeight)); - int last_visible_index = DetermineLastVisibleIndex( + last_visible_index_ = DetermineLastVisibleIndex( available_width - kLeadingInset - bounds->overflow_bounds.width() - kButtonSpacing - kButtonWidth); bool show_overflow = - (last_visible_index + 1 != view_model_->view_size()); + (last_visible_index_ + 1 != view_model_->view_size()); int app_list_index = view_model_->view_size() - 1; if (overflow_button_->visible() != show_overflow) { // Only change visibility of the views if the visibility of the overflow // button changes. Otherwise we'll effect the insertion animation, which // changes the visibility. - for (int i = 0; i <= last_visible_index; ++i) + for (int i = 0; i <= last_visible_index_; ++i) view_model_->view_at(i)->SetVisible(true); - for (int i = last_visible_index + 1; i < view_model_->view_size(); ++i) { + for (int i = last_visible_index_ + 1; i < view_model_->view_size(); ++i) { if (i != app_list_index) view_model_->view_at(i)->SetVisible(false); } @@ -386,8 +388,8 @@ void LauncherView::CalculateIdealBounds(IdealBounds* bounds) { DCHECK_NE(0, view_model_->view_size()); // We always want the app list visible. gfx::Rect app_list_bounds = view_model_->ideal_bounds(app_list_index); - x = last_visible_index == -1 ? - kLeadingInset : view_model_->ideal_bounds(last_visible_index).right(); + x = last_visible_index_ == -1 ? + kLeadingInset : view_model_->ideal_bounds(last_visible_index_).right(); app_list_bounds.set_x(x); view_model_->set_ideal_bounds(app_list_index, app_list_bounds); x = app_list_bounds.right() + kButtonSpacing; @@ -404,6 +406,14 @@ int LauncherView::DetermineLastVisibleIndex(int max_x) { return index; } +void LauncherView::AddIconObserver(LauncherIconObserver* observer) { + observers_.AddObserver(observer); +} + +void LauncherView::RemoveIconObserver(LauncherIconObserver* observer) { + observers_.RemoveObserver(observer); +} + void LauncherView::AnimateToIdealBounds() { IdealBounds ideal_bounds; CalculateIdealBounds(&ideal_bounds); @@ -541,6 +551,9 @@ void LauncherView::ContinueDrag(const views::MouseEvent& event) { view_model_->Move(current_index, target_index); AnimateToIdealBounds(); bounds_animator_->StopAnimatingView(drag_view_); + + FOR_EACH_OBSERVER(LauncherIconObserver, observers_, + OnLauncherIconPositionsChanged()); } bool LauncherView::SameDragType(LauncherItemType typea, @@ -662,6 +675,8 @@ gfx::Size LauncherView::GetPreferredSize() { void LauncherView::OnBoundsChanged(const gfx::Rect& previous_bounds) { LayoutToIdealBounds(); + FOR_EACH_OBSERVER(LauncherIconObserver, observers_, + OnLauncherIconPositionsChanged()); } views::FocusTraversable* LauncherView::GetPaneFocusTraversable() { @@ -693,6 +708,9 @@ void LauncherView::LauncherItemAdded(int model_index) { bounds_animator_->SetAnimationDelegate( view, new StartFadeAnimationDelegate(this, view), true); } + + FOR_EACH_OBSERVER(LauncherIconObserver, observers_, + OnLauncherIconPositionsChanged()); } void LauncherView::LauncherItemRemoved(int model_index, LauncherID id) { @@ -708,6 +726,14 @@ void LauncherView::LauncherItemRemoved(int model_index, LauncherID id) { bounds_animator_->AnimateViewTo(view, view->bounds()); bounds_animator_->SetAnimationDelegate( view, new FadeOutAnimationDelegate(this, view), true); + + // The animation will eventually update the ideal bounds, but we want to + // force an update immediately so we can notify launcher icon observers. + IdealBounds ideal_bounds; + CalculateIdealBounds(&ideal_bounds); + + FOR_EACH_OBSERVER(LauncherIconObserver, observers_, + OnLauncherIconPositionsChanged()); } void LauncherView::LauncherItemChanged(int model_index, @@ -757,6 +783,8 @@ void LauncherView::LauncherItemChanged(int model_index, void LauncherView::LauncherItemMoved(int start_index, int target_index) { view_model_->Move(start_index, target_index); AnimateToIdealBounds(); + FOR_EACH_OBSERVER(LauncherIconObserver, observers_, + OnLauncherIconPositionsChanged()); } void LauncherView::LauncherItemWillChange(int index) { diff --git a/ash/launcher/launcher_view.h b/ash/launcher/launcher_view.h index dc1d8d1..f367c3a 100644 --- a/ash/launcher/launcher_view.h +++ b/ash/launcher/launcher_view.h @@ -11,6 +11,7 @@ #include "ash/launcher/launcher_button_host.h" #include "ash/launcher/launcher_model_observer.h" +#include "base/observer_list.h" #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/button.h" #include "ui/views/focus/focus_manager.h" @@ -27,6 +28,7 @@ namespace ash { class LauncherDelegate; struct LauncherItem; +class LauncherIconObserver; class LauncherModel; namespace internal { @@ -66,6 +68,9 @@ class ASH_EXPORT LauncherView : public views::View, // isn't know. gfx::Rect GetIdealBoundsOfItemIcon(LauncherID id); + void AddIconObserver(LauncherIconObserver* observer); + void RemoveIconObserver(LauncherIconObserver* observer); + // Returns true if we're showing a menu. bool IsShowingMenu() const; @@ -169,6 +174,10 @@ class ASH_EXPORT LauncherView : public views::View, // item in |model_|. scoped_ptr<views::ViewModel> view_model_; + // Last index of a launcher button that is visible + // (does not go into overflow). + int last_visible_index_; + scoped_ptr<views::BoundsAnimator> bounds_animator_; views::ImageButton* overflow_button_; @@ -198,6 +207,8 @@ class ASH_EXPORT LauncherView : public views::View, scoped_ptr<views::MenuRunner> launcher_menu_runner_; #endif + ObserverList<LauncherIconObserver> observers_; + DISALLOW_COPY_AND_ASSIGN(LauncherView); }; diff --git a/ash/launcher/launcher_view_unittest.cc b/ash/launcher/launcher_view_unittest.cc new file mode 100644 index 0000000..78836f6 --- /dev/null +++ b/ash/launcher/launcher_view_unittest.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/launcher/launcher_view.h" + +#include "ash/ash_switches.h" +#include "ash/launcher/launcher.h" +#include "ash/launcher/launcher_icon_observer.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/test_launcher_delegate.h" +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/compiler_specific.h" +#include "ui/aura/window.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +namespace { + +class TestLauncherIconObserver : public LauncherIconObserver { + public: + TestLauncherIconObserver() : count_(0) { + Shell::GetInstance()->launcher()->AddIconObserver(this); + } + + virtual ~TestLauncherIconObserver() { + Shell::GetInstance()->launcher()->RemoveIconObserver(this); + } + + // LauncherIconObserver implementation. + void OnLauncherIconPositionsChanged() OVERRIDE { + count_++; + } + + int count() const { return count_; } + void Reset() { count_ = 0; } + + private: + int count_; + + DISALLOW_COPY_AND_ASSIGN(TestLauncherIconObserver); +}; + +class LauncherViewTest : public ash::test::AshTestBase { + public: + LauncherViewTest() {} + virtual ~LauncherViewTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + observer_.reset(new TestLauncherIconObserver); + } + + virtual void TearDown() OVERRIDE { + observer_.reset(); + AshTestBase::TearDown(); + } + + TestLauncherIconObserver* observer() { return observer_.get(); } + + private: + scoped_ptr<TestLauncherIconObserver> observer_; + + DISALLOW_COPY_AND_ASSIGN(LauncherViewTest); +}; + +TEST_F(LauncherViewTest, AddRemove) { + ash::test::TestLauncherDelegate* launcher_delegate = + ash::test::TestLauncherDelegate::instance(); + ASSERT_TRUE(launcher_delegate); + + views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = gfx::Rect(0, 0, 200, 200); + + scoped_ptr<views::Widget> widget(new views::Widget()); + widget->Init(params); + launcher_delegate->AddLauncherItem(widget->GetNativeWindow()); + EXPECT_EQ(1, observer()->count()); + observer()->Reset(); + + widget->Show(); + widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow()); + EXPECT_EQ(1, observer()->count()); + observer()->Reset(); +} + +TEST_F(LauncherViewTest, BoundsChanged) { + Launcher* launcher = Shell::GetInstance()->launcher(); + int total_width = launcher->widget()->GetWindowScreenBounds().width(); + ASSERT_GT(total_width, 0); + launcher->SetStatusWidth(total_width / 2); + EXPECT_EQ(1, observer()->count()); + observer()->Reset(); +} + +} // namespace + +} // namespace ash |