blob: c256cac02a7984e6db61da2c43446a88240cc4e2 [file] [log] [blame]
// 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 "ui/app_list/views/app_list_view.h"
#include "base/strings/string_util.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/app_list_view_delegate.h"
#include "ui/app_list/pagination_model.h"
#include "ui/app_list/signin_delegate.h"
#include "ui/app_list/views/app_list_background.h"
#include "ui/app_list/views/app_list_main_view.h"
#include "ui/app_list/views/search_box_view.h"
#include "ui/app_list/views/signin_view.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
#if defined(USE_AURA)
#include "ui/aura/window.h"
#endif
namespace app_list {
namespace {
// The distance between the arrow tip and edge of the anchor view.
const int kArrowOffset = 10;
} // namespace
////////////////////////////////////////////////////////////////////////////////
// AppListView:
AppListView::AppListView(AppListViewDelegate* delegate)
: model_(new AppListModel),
delegate_(delegate),
app_list_main_view_(NULL),
signin_view_(NULL) {
if (delegate_)
delegate_->SetModel(model_.get());
if (GetSigninDelegate())
GetSigninDelegate()->AddObserver(this);
}
AppListView::~AppListView() {
if (GetSigninDelegate())
GetSigninDelegate()->RemoveObserver(this);
// Models are going away, ensure their references are cleared.
RemoveAllChildViews(true);
}
void AppListView::InitAsBubble(gfx::NativeView parent,
PaginationModel* pagination_model,
views::View* anchor,
const gfx::Point& anchor_point,
views::BubbleBorder::Arrow arrow,
bool border_accepts_events) {
app_list_main_view_ = new AppListMainView(delegate_.get(),
model_.get(),
pagination_model,
anchor);
AddChildView(app_list_main_view_);
#if defined(USE_AURA)
app_list_main_view_->SetPaintToLayer(true);
app_list_main_view_->SetFillsBoundsOpaquely(false);
app_list_main_view_->layer()->SetMasksToBounds(true);
#endif
signin_view_ = new SigninView(
GetSigninDelegate(),
app_list_main_view_->GetPreferredSize().width());
AddChildView(signin_view_);
OnSigninStatusChanged();
set_anchor_view(anchor);
set_anchor_rect(gfx::Rect(anchor_point, gfx::Size()));
set_color(kContentsBackgroundColor);
set_margins(gfx::Insets());
set_move_with_anchor(true);
set_parent_window(parent);
set_close_on_deactivate(false);
set_close_on_esc(false);
set_anchor_view_insets(gfx::Insets(kArrowOffset, kArrowOffset,
kArrowOffset, kArrowOffset));
set_border_accepts_events(border_accepts_events);
set_shadow(views::BubbleBorder::BIG_SHADOW);
views::BubbleDelegateView::CreateBubble(this);
SetBubbleArrow(arrow);
#if defined(USE_AURA)
GetWidget()->GetNativeWindow()->layer()->SetMasksToBounds(true);
GetBubbleFrameView()->set_background(new AppListBackground(
GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
app_list_main_view_));
set_background(NULL);
#else
set_background(new AppListBackground(
GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
app_list_main_view_));
// On non-aura the bubble has two widgets, and it's possible for the border
// to be shown independently in odd situations. Explicitly hide the bubble
// widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
// window manager do not have the SWP_SHOWWINDOW flag set which would cause
// the border to be shown. See http://crbug.com/231687 .
GetWidget()->Hide();
#endif
}
void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
SizeToContents(); // Recalcuates with new border.
GetBubbleFrameView()->SchedulePaint();
}
void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
set_anchor_rect(gfx::Rect(anchor_point, gfx::Size()));
SizeToContents(); // Repositions view relative to the anchor.
}
void AppListView::SetDragAndDropHostOfCurrentAppList(
app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
}
void AppListView::ShowWhenReady() {
app_list_main_view_->ShowAppListWhenReady();
}
void AppListView::Close() {
app_list_main_view_->Close();
if (delegate_)
delegate_->Dismiss();
else
GetWidget()->Close();
}
void AppListView::UpdateBounds() {
SizeToContents();
}
gfx::Size AppListView::GetPreferredSize() {
return app_list_main_view_->GetPreferredSize();
}
bool AppListView::ShouldHandleSystemCommands() const {
return true;
}
void AppListView::Prerender() {
app_list_main_view_->Prerender();
}
void AppListView::OnSigninStatusChanged() {
const bool needs_signin =
GetSigninDelegate() && GetSigninDelegate()->NeedSignin();
signin_view_->SetVisible(needs_signin);
app_list_main_view_->SetVisible(!needs_signin);
}
views::View* AppListView::GetInitiallyFocusedView() {
return app_list_main_view_->search_box_view()->search_box();
}
gfx::ImageSkia AppListView::GetWindowIcon() {
if (delegate_)
return delegate_->GetWindowIcon();
return gfx::ImageSkia();
}
bool AppListView::WidgetHasHitTestMask() const {
return true;
}
void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
DCHECK(mask);
mask->addRect(gfx::RectToSkRect(
GetBubbleFrameView()->GetContentsBounds()));
}
bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
// The accelerator is added by BubbleDelegateView.
if (accelerator.key_code() == ui::VKEY_ESCAPE) {
if (app_list_main_view_->search_box_view()->HasSearch())
app_list_main_view_->search_box_view()->ClearSearch();
else
Close();
return true;
}
return false;
}
void AppListView::Layout() {
const gfx::Rect contents_bounds = GetContentsBounds();
app_list_main_view_->SetBoundsRect(contents_bounds);
signin_view_->SetBoundsRect(contents_bounds);
}
void AppListView::OnWidgetDestroying(views::Widget* widget) {
BubbleDelegateView::OnWidgetDestroying(widget);
if (delegate_ && widget == GetWidget())
delegate_->ViewClosing();
}
void AppListView::OnWidgetActivationChanged(views::Widget* widget,
bool active) {
// Do not called inherited function as the bubble delegate auto close
// functionality is not used.
if (delegate_ && widget == GetWidget())
delegate_->ViewActivationChanged(active);
}
void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
bool visible) {
BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
if (widget != GetWidget())
return;
// We clear the search when hiding so the next time the app list appears it is
// not showing search results.
if (!visible)
app_list_main_view_->search_box_view()->ClearSearch();
// Whether we need to signin or not may have changed since last time we were
// shown.
Layout();
}
void AppListView::OnSigninSuccess() {
OnSigninStatusChanged();
}
SigninDelegate* AppListView::GetSigninDelegate() {
return delegate_ ? delegate_->GetSigninDelegate() : NULL;
}
} // namespace app_list