summaryrefslogtreecommitdiffstats
path: root/ash/launcher
diff options
context:
space:
mode:
authordcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-19 23:54:39 +0000
committerdcheng@chromium.org <dcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-19 23:54:39 +0000
commit813d646b7778d251fd9f418a8e61cb0ee214b8ec (patch)
treeb8061b2299de38db1a879f14f6725ea78883b09e /ash/launcher
parent16c5072cbc556b3eac9ec1560c7e57fc375f1058 (diff)
downloadchromium_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.cc8
-rw-r--r--ash/launcher/launcher.h4
-rw-r--r--ash/launcher/launcher_icon_observer.h28
-rw-r--r--ash/launcher/launcher_view.cc42
-rw-r--r--ash/launcher/launcher_view.h11
-rw-r--r--ash/launcher/launcher_view_unittest.cc104
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