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

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

Powered by Google App Engine
This is Rietveld 408576698