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