tray_details_view.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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
3// found in the LICENSE file.
4
5#include "ash/system/tray/tray_details_view.h"
6
7#include "ash/system/tray/fixed_sized_scroll_view.h"
8#include "ash/system/tray/system_tray.h"
9#include "ash/system/tray/system_tray_item.h"
10#include "ash/system/tray/tray_constants.h"
11#include "ui/gfx/canvas.h"
12#include "ui/views/background.h"
13#include "ui/views/border.h"
14#include "ui/views/controls/scroll_view.h"
15#include "ui/views/layout/box_layout.h"
16
17namespace ash {
18
19class ScrollSeparator : public views::View {
20 public:
21  ScrollSeparator() {}
22
23  virtual ~ScrollSeparator() {}
24
25 private:
26  // Overriden from views::View.
27  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
28    canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
29  }
30  virtual gfx::Size GetPreferredSize() OVERRIDE {
31    return gfx::Size(1, kTrayPopupScrollSeparatorHeight);
32  }
33
34  DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
35};
36
37class ScrollBorder : public views::Border {
38 public:
39  ScrollBorder() {}
40  virtual ~ScrollBorder() {}
41
42  void set_visible(bool visible) { visible_ = visible; }
43
44 private:
45  // Overridden from views::Border.
46  virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE {
47    if (!visible_)
48      return;
49    canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1),
50                     kBorderLightColor);
51  }
52
53  virtual gfx::Insets GetInsets() const OVERRIDE {
54    return gfx::Insets(0, 0, 1, 0);
55  }
56
57  virtual gfx::Size GetMinimumSize() const OVERRIDE {
58    return gfx::Size(0, 1);
59  }
60
61  bool visible_;
62
63  DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
64};
65
66TrayDetailsView::TrayDetailsView(SystemTrayItem* owner)
67    : owner_(owner),
68      footer_(NULL),
69      scroller_(NULL),
70      scroll_content_(NULL),
71      scroll_border_(NULL) {
72  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
73      0, 0, 0));
74  set_background(views::Background::CreateSolidBackground(kBackgroundColor));
75}
76
77TrayDetailsView::~TrayDetailsView() {
78}
79
80void TrayDetailsView::CreateSpecialRow(int string_id,
81                                       ViewClickListener* listener) {
82  DCHECK(!footer_);
83  footer_ = new SpecialPopupRow();
84  footer_->SetTextLabel(string_id, listener);
85  AddChildViewAt(footer_, child_count());
86}
87
88void TrayDetailsView::CreateScrollableList() {
89  DCHECK(!scroller_);
90  scroll_content_ = new views::View;
91  scroll_content_->SetLayoutManager(new views::BoxLayout(
92      views::BoxLayout::kVertical, 0, 0, 1));
93  scroller_ = new FixedSizedScrollView;
94  scroller_->SetContentsView(scroll_content_);
95
96  // Note: |scroller_| takes ownership of |scroll_border_|.
97  scroll_border_ = new ScrollBorder;
98  scroller_->SetBorder(scoped_ptr<views::Border>(scroll_border_));
99
100  AddChildView(scroller_);
101}
102
103void TrayDetailsView::AddScrollSeparator() {
104  DCHECK(scroll_content_);
105  // Do not draw the separator if it is the very first item
106  // in the scrollable list.
107  if (scroll_content_->has_children())
108    scroll_content_->AddChildView(new ScrollSeparator);
109}
110
111void TrayDetailsView::Reset() {
112  RemoveAllChildViews(true);
113  footer_ = NULL;
114  scroller_ = NULL;
115  scroll_content_ = NULL;
116}
117
118void TrayDetailsView::TransitionToDefaultView() {
119  // Cache pointer to owner in this function scope. TrayDetailsView will be
120  // deleted after called ShowDefaultView.
121  SystemTrayItem* owner = owner_;
122  if (footer_ && footer_->content() && footer_->content()->HasFocus())
123    owner->set_restore_focus(true);
124  owner->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
125  owner->set_restore_focus(false);
126}
127
128void TrayDetailsView::Layout() {
129  if (bounds().IsEmpty()) {
130    views::View::Layout();
131    return;
132  }
133
134  if (scroller_) {
135    scroller_->set_fixed_size(gfx::Size());
136    gfx::Size size = GetPreferredSize();
137
138    // Set the scroller to fill the space above the bottom row, so that the
139    // bottom row of the detailed view will always stay just above the footer.
140    gfx::Size scroller_size = scroll_content_->GetPreferredSize();
141    scroller_->set_fixed_size(
142        gfx::Size(width() + scroller_->GetScrollBarWidth(),
143                  scroller_size.height() - (size.height() - height())));
144  }
145
146  views::View::Layout();
147
148  if (footer_) {
149    // Always make sure the footer element is bottom aligned.
150    gfx::Rect fbounds = footer_->bounds();
151    fbounds.set_y(height() - footer_->height());
152    footer_->SetBoundsRect(fbounds);
153  }
154}
155
156void TrayDetailsView::OnPaintBorder(gfx::Canvas* canvas) {
157  if (scroll_border_) {
158    int index = GetIndexOf(scroller_);
159    if (index < child_count() - 1 && child_at(index + 1) != footer_)
160      scroll_border_->set_visible(true);
161    else
162      scroll_border_->set_visible(false);
163  }
164
165  views::View::OnPaintBorder(canvas);
166}
167
168}  // namespace ash
169