Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: ash/system/drive/tray_drive.cc

Issue 10214013: Created uber tray UI for monitoring ongoing WebDrive sync operations (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/drive/tray_drive.h"
6
7 #include <vector>
8
9 #include "ash/shell.h"
10 #include "ash/system/tray/system_tray.h"
11 #include "ash/system/tray/system_tray_delegate.h"
12 #include "ash/system/tray/tray_constants.h"
13 #include "ash/system/tray/tray_item_more.h"
14 #include "ash/system/tray/tray_item_view.h"
15 #include "ash/system/tray/tray_views.h"
16 #include "base/logging.h"
17 #include "base/string_number_conversions.h"
18 #include "base/utf_string_conversions.h"
19 #include "base/stl_util.h"
20 #include "grit/ash_strings.h"
21 #include "grit/ui_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/gfx/font.h"
25 #include "ui/gfx/image/image.h"
26 #include "ui/views/controls/button/image_button.h"
27 #include "ui/views/controls/label.h"
28 #include "ui/views/controls/progress_bar.h"
29 #include "ui/views/layout/box_layout.h"
30 #include "ui/views/layout/grid_layout.h"
31
32 namespace ash {
33
34 namespace internal {
35
36 namespace {
37
38 const int kSidePadding = 8;
39 const int kHorizontalPadding = 6;
40 const int kVerticalPadding = 6;
41 const int kProgressBarWidth = 100;
42 const int kProgressBarHeight = 8;
43
44 string16 GetTrayLabel(const ash::DriveOperationStatusList& list) {
45 return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DRIVE_SYNCING,
46 base::IntToString16(static_cast<int>(list.size())));
47 }
48
49 ash::DriveOperationStatusList* GetCurrentOperationList() {
50 ash::SystemTrayDelegate* delegate =
51 ash::Shell::GetInstance()->tray_delegate();
52 ash::DriveOperationStatusList* list = new ash::DriveOperationStatusList();
53 delegate->GetDriveOperationStatusList(list);
54 return list;
55 }
56
57 }
58
59 namespace tray {
60
61
62 class DriveDefaultView : public TrayItemMore {
63 public:
64 DriveDefaultView(SystemTrayItem* owner,
65 const DriveOperationStatusList* list)
66 : TrayItemMore(owner) {
67 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
68
69 SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DRIVE).ToSkBitmap());
70 Update(list);
71 }
72
73 virtual ~DriveDefaultView() {}
74
75 void Update(const DriveOperationStatusList* list) {
76 DCHECK(list);
77 string16 label = GetTrayLabel(*list);
78 SetLabel(label);
79 SetAccessibleName(label);
80 }
81
82 private:
83 DISALLOW_COPY_AND_ASSIGN(DriveDefaultView);
84 };
85
86 class DriveDetailedView : public views::View,
87 public ViewClickListener {
88 public:
89 DriveDetailedView(SystemTrayItem* owner,
90 const DriveOperationStatusList* list)
91 : header_(NULL),
92 operations_(NULL),
93 settings_(NULL),
94 in_progress_img_(NULL),
95 done_img_(NULL),
96 failed_img_(NULL) {
97 SetLayoutManager(new views::BoxLayout(
98 views::BoxLayout::kVertical, 0, 0, 0));
99 set_background(views::Background::CreateSolidBackground(kBackgroundColor));
100
101 in_progress_img_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
102 IDR_AURA_UBER_TRAY_DRIVE);
103 done_img_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
104 IDR_AURA_UBER_TRAY_DRIVE_DONE);
105 failed_img_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
106 IDR_AURA_UBER_TRAY_DRIVE_FAILED);
107
108 Update(list);
109 }
110
111 virtual ~DriveDetailedView() {
112 STLDeleteValues(&update_map_);
113 }
114
115 void Update(const DriveOperationStatusList* list) {
116 AppendHeaderEntry(list);
117 AppendOperationList(list);
118 AppendSettings();
119 ChildPreferredSizeChanged(operations_);
120 SchedulePaint();
121 }
122
123 private:
124
125 class OperationProgressBar : public views::ProgressBar {
126 public:
127 OperationProgressBar() {}
128 private:
129
130 // Overridden from View:
131 virtual gfx::Size GetPreferredSize() OVERRIDE {
132 return gfx::Size(kProgressBarWidth, kProgressBarHeight);
133 }
134
135 DISALLOW_COPY_AND_ASSIGN(OperationProgressBar);
136 };
137
138 class RowView : public views::View,
139 public views::ButtonListener {
140 public:
141 RowView(DriveDetailedView* parent,
142 ash::DriveOperationStatus::OperationState state,
143 double progress,
144 const FilePath& file_path)
145 : parent_(parent),
146 status_img_(NULL),
147 label_container_(NULL),
148 progress_bar_(NULL),
149 cancel_button_(NULL),
150 file_path_(file_path) {
151 // Status image.
152 status_img_ = new views::ImageView();
153 AddChildView(status_img_);
154
155 label_container_ = new views::View();
156 label_container_->SetLayoutManager(new views::BoxLayout(
157 views::BoxLayout::kVertical, 0, 0, kVerticalPadding));
158 views::Label* label = new views::Label(
159 UTF8ToUTF16(file_path.BaseName().value()));
160 label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
161 label_container_->AddChildView(label);
162 // Add progress bar.
163 progress_bar_ = new OperationProgressBar();
164 label_container_->AddChildView(progress_bar_);
165
166 AddChildView(label_container_);
167
168 cancel_button_ = new views::ImageButton(this);
169 cancel_button_->SetImage(views::ImageButton::BS_NORMAL,
170 ResourceBundle::GetSharedInstance().GetBitmapNamed(
171 IDR_AURA_UBER_TRAY_DRIVE_CANCEL));
172
173 UpdateStatus(state, progress);
174 AddChildView(cancel_button_);
175 }
176
177 void UpdateStatus(ash::DriveOperationStatus::OperationState state,
178 double progress) {
179 status_img_->SetImage(parent_->GetImageForState(state));
180 progress_bar_->SetValue(progress);
181 cancel_button_->SetVisible(
182 state == ash::DriveOperationStatus::OPERATION_IN_PROGRESS ||
183 state == ash::DriveOperationStatus::OPERATION_SUSPENDED);
184 }
185
186 private:
187
188 // views::View overrides.
189 virtual gfx::Size GetPreferredSize() OVERRIDE {
190 return gfx::Size(
191 status_img_->GetPreferredSize().width() +
192 label_container_->GetPreferredSize().width() +
193 cancel_button_->GetPreferredSize().width() +
194 2 * kSidePadding + 2 * kHorizontalPadding,
195 std::max(status_img_->GetPreferredSize().height(),
196 std::max(label_container_->GetPreferredSize().height(),
197 cancel_button_->GetPreferredSize().height())) +
198 2 * kVerticalPadding);
199 }
200
201 virtual void Layout() OVERRIDE {
202 gfx::Rect child_area(GetLocalBounds());
203 if (child_area.IsEmpty())
204 return;
205
206 int pos_x = child_area.x() + kSidePadding;
207 int pos_y = child_area.y() + kVerticalPadding;
208
209 gfx::Rect bounds_status(
210 gfx::Point(pos_x,
211 pos_y + (child_area.height() - 2 * kVerticalPadding -
212 status_img_->GetPreferredSize().height())/2),
213 status_img_->GetPreferredSize());
214 status_img_->SetBoundsRect(bounds_status.Intersect(child_area));
215 pos_x += status_img_->bounds().width() + kHorizontalPadding;
216
217 gfx::Rect bounds_label(pos_x,
218 pos_y,
219 child_area.width() - 2 * kSidePadding -
220 2 * kHorizontalPadding -
221 status_img_->GetPreferredSize().width() -
222 cancel_button_->GetPreferredSize().width(),
223 label_container_->GetPreferredSize().height());
224 label_container_->SetBoundsRect(bounds_label.Intersect(child_area));
225 pos_x += label_container_->bounds().width() + kHorizontalPadding;
226
227 gfx::Rect bounds_button(
228 gfx::Point(pos_x,
229 pos_y + (child_area.height() - 2 * kVerticalPadding -
230 cancel_button_->GetPreferredSize().height())/2),
231 cancel_button_->GetPreferredSize());
232 cancel_button_->SetBoundsRect(bounds_button.Intersect(child_area));
233 }
234
235 // views::ButtonListener overrides.
236 virtual void ButtonPressed(views::Button* sender,
237 const views::Event& event) OVERRIDE {
238 DCHECK(sender == cancel_button_);
239 parent_->OnCancelOperation(file_path_);
240 }
241
242 DriveDetailedView* parent_;
243 views::ImageView* status_img_;
244 views::View* label_container_;
245 views::ProgressBar* progress_bar_;
246 views::ImageButton* cancel_button_;
247 FilePath file_path_;
248
249 DISALLOW_COPY_AND_ASSIGN(RowView);
250 };
251
252 void AppendHeaderEntry(const DriveOperationStatusList* list) {
253 if (header_)
254 return;
255 header_ = CreateDetailedHeaderEntry(IDS_ASH_STATUS_TRAY_DRIVE, this);
256 AddChildView(header_);
257 }
258
259 SkBitmap* GetImageForState(ash::DriveOperationStatus::OperationState state) {
260 switch (state) {
261 case ash::DriveOperationStatus::OPERATION_NOT_STARTED:
262 case ash::DriveOperationStatus::OPERATION_STARTED:
263 case ash::DriveOperationStatus::OPERATION_IN_PROGRESS:
264 case ash::DriveOperationStatus::OPERATION_SUSPENDED:
265 return in_progress_img_;
266 case ash::DriveOperationStatus::OPERATION_COMPLETED:
267 return done_img_;
268 case ash::DriveOperationStatus::OPERATION_FAILED:
269 return failed_img_;
270 }
271 return failed_img_;
272 }
273
274 virtual void OnCancelOperation(const FilePath& file_path) {
275 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate();
276 delegate->CancelDriveOperation(file_path);
277 }
278
279 void AppendOperationList(const DriveOperationStatusList* list) {
280 if (!operations_) {
281 operations_ = new views::View;
282 operations_->SetLayoutManager(new views::BoxLayout(
283 views::BoxLayout::kVertical, 0, 0, 1));
284 AddChildView(operations_);
285 }
286
287 // Apply the update.
288 std::set<FilePath> new_set;
289 for (DriveOperationStatusList::const_iterator it = list->begin();
290 it != list->end(); ++it) {
291 const DriveOperationStatus& operation = *it;
292
293 new_set.insert(operation.file_path);
294 std::map<FilePath, RowView*>::iterator existing_item =
295 update_map_.find(operation.file_path);
296
297 if (existing_item != update_map_.end()) {
298 existing_item->second->UpdateStatus(operation.state,
299 operation.progress);
300 } else {
301 RowView* row_view = new RowView(this,
302 operation.state,
303 operation.progress,
304 operation.file_path);
305
306 update_map_[operation.file_path] = row_view;
307 operations_->AddChildView(row_view);
308 }
309 }
310
311 // Remove items from the list that haven't been added or modified with this
312 // update batch.
313 std::set<FilePath> remove_set;
314 for (std::map<FilePath, RowView*>::iterator update_iter =
315 update_map_.begin();
316 update_iter != update_map_.end(); ++update_iter) {
317 if (new_set.find(update_iter->first) == new_set.end()) {
318 remove_set.insert(update_iter->first);
319 }
320 }
321
322 for (std::set<FilePath>::iterator removed_iter = remove_set.begin();
323 removed_iter != remove_set.end(); ++removed_iter) {
324 delete update_map_[*removed_iter];
325 update_map_.erase(*removed_iter);
326 }
327 }
328
329 void AppendSettings() {
330 HoverHighlightView* container = new HoverHighlightView(this);
331 container->set_fixed_height(kTrayPopupItemHeight);
332 container->AddLabel(ui::ResourceBundle::GetSharedInstance().
333 GetLocalizedString(IDS_ASH_STATUS_TRAY_DRIVE_SETTINGS),
334 gfx::Font::NORMAL);
335 AddChildView(container);
336 settings_ = container;
337 }
338
339 // Overridden from ViewClickListener.
340 virtual void ClickedOn(views::View* sender) OVERRIDE {
341 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate();
342 if (sender == header_) {
343 Shell::GetInstance()->tray()->ShowDefaultView();
344 } else if (sender == settings_) {
345 delegate->ShowDriveSettings();
346 }
347 }
348
349 // Maps operation entries to their file paths.
350 std::map<FilePath, RowView*> update_map_;
351 views::View* header_;
352 views::View* operations_;
353 views::View* settings_;
354 SkBitmap* in_progress_img_;
355 SkBitmap* done_img_;
356 SkBitmap* failed_img_;
357
358 DISALLOW_COPY_AND_ASSIGN(DriveDetailedView);
359 };
360
361 } // namespace tray
362
363 TrayDrive::TrayDrive() :
364 TrayImageItem(IDR_AURA_UBER_TRAY_DRIVE_LIGHT),
365 default_(NULL),
366 detailed_(NULL) {
367 }
368
369 TrayDrive::~TrayDrive() {
370 }
371
372 bool TrayDrive::GetInitialVisibility() {
373 scoped_ptr<DriveOperationStatusList> list(GetCurrentOperationList());
374 return list->size() > 0;
375 }
376
377 views::View* TrayDrive::CreateDefaultView(user::LoginStatus status) {
378 DCHECK(!default_);
379
380 if (status != user::LOGGED_IN_USER && status != user::LOGGED_IN_OWNER)
381 return NULL;
382
383 scoped_ptr<DriveOperationStatusList> list(GetCurrentOperationList());
384 if (!list->size())
385 return NULL;
386
387 default_ = new tray::DriveDefaultView(this, list.get());
388 return default_;
389 }
390
391 views::View* TrayDrive::CreateDetailedView(user::LoginStatus status) {
392 DCHECK(!detailed_);
393
394 if (status != user::LOGGED_IN_USER && status != user::LOGGED_IN_OWNER)
395 return NULL;
396
397 scoped_ptr<DriveOperationStatusList> list(GetCurrentOperationList());
398 if (!list->size())
399 return NULL;
400
401 detailed_ = new tray::DriveDetailedView(this, list.get());
402 return detailed_;
403 }
404
405 void TrayDrive::DestroyDefaultView() {
406 default_ = NULL;
407 }
408
409 void TrayDrive::DestroyDetailedView() {
410 detailed_ = NULL;
411 }
412
413 void TrayDrive::UpdateAfterLoginStatusChange(user::LoginStatus status) {
414 if (status == user::LOGGED_IN_USER || status == user::LOGGED_IN_OWNER)
415 return;
416
417 tray_view()->SetVisible(false);
418 DestroyDefaultView();
419 DestroyDetailedView();
420 }
421
422 void TrayDrive::OnDriveRefresh(const DriveOperationStatusList& list) {
423 tray_view()->SetVisible(list.size() > 0);
424 tray_view()->SchedulePaint();
425
426 if (default_)
427 default_->Update(&list);
428
429 if (detailed_)
430 detailed_->Update(&list);
431 }
432
433 } // namespace internal
434 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698