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

Side by Side Diff: ash/system/date/date_view.cc

Issue 2061123004: mash: Move //ash/system/date to //ash/common (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@uma
Patch Set: rebase again Created 4 years, 6 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
« no previous file with comments | « ash/system/date/date_view.h ('k') | ash/system/date/date_view_unittest.cc » ('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/date/date_view.h"
6
7 #include "ash/common/system/tray/system_tray_delegate.h"
8 #include "ash/common/system/tray/tray_constants.h"
9 #include "ash/common/system/tray/tray_utils.h"
10 #include "ash/common/wm_shell.h"
11 #include "base/i18n/rtl.h"
12 #include "base/i18n/time_formatting.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "grit/ash_strings.h"
16 #include "third_party/icu/source/i18n/unicode/datefmt.h"
17 #include "third_party/icu/source/i18n/unicode/dtptngen.h"
18 #include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
19 #include "ui/accessibility/ax_view_state.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/ui_base_switches_util.h"
22 #include "ui/views/border.h"
23 #include "ui/views/controls/label.h"
24 #include "ui/views/layout/box_layout.h"
25 #include "ui/views/layout/grid_layout.h"
26 #include "ui/views/widget/widget.h"
27
28 namespace ash {
29 namespace tray {
30 namespace {
31
32 // Amount of slop to add into the timer to make sure we're into the next minute
33 // when the timer goes off.
34 const int kTimerSlopSeconds = 1;
35
36 // Text color of the vertical clock minutes.
37 const SkColor kVerticalClockMinuteColor = SkColorSetRGB(0xBA, 0xBA, 0xBA);
38
39 // Padding between the left edge of the shelf and the left edge of the vertical
40 // clock.
41 const int kVerticalClockLeftPadding = 9;
42
43 // Offset used to bring the minutes line closer to the hours line in the
44 // vertical clock.
45 const int kVerticalClockMinutesTopOffset = -4;
46
47 base::string16 FormatDate(const base::Time& time) {
48 icu::UnicodeString date_string;
49 std::unique_ptr<icu::DateFormat> formatter(
50 icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
51 formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
52 return base::string16(date_string.getBuffer(),
53 static_cast<size_t>(date_string.length()));
54 }
55
56 base::string16 FormatDayOfWeek(const base::Time& time) {
57 UErrorCode status = U_ZERO_ERROR;
58 std::unique_ptr<icu::DateTimePatternGenerator> generator(
59 icu::DateTimePatternGenerator::createInstance(status));
60 DCHECK(U_SUCCESS(status));
61 const char kBasePattern[] = "EEE";
62 icu::UnicodeString generated_pattern =
63 generator->getBestPattern(icu::UnicodeString(kBasePattern), status);
64 DCHECK(U_SUCCESS(status));
65 icu::SimpleDateFormat simple_formatter(generated_pattern, status);
66 DCHECK(U_SUCCESS(status));
67 icu::UnicodeString date_string;
68 simple_formatter.format(
69 static_cast<UDate>(time.ToDoubleT() * 1000), date_string, status);
70 DCHECK(U_SUCCESS(status));
71 return base::string16(
72 date_string.getBuffer(), static_cast<size_t>(date_string.length()));
73 }
74
75 views::Label* CreateLabel() {
76 views::Label* label = new views::Label;
77 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
78 label->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255));
79 return label;
80 }
81
82 } // namespace
83
84 BaseDateTimeView::~BaseDateTimeView() {
85 timer_.Stop();
86 }
87
88 void BaseDateTimeView::UpdateText() {
89 base::Time now = base::Time::Now();
90 UpdateTextInternal(now);
91 SchedulePaint();
92 SetTimer(now);
93 }
94
95 void BaseDateTimeView::GetAccessibleState(ui::AXViewState* state) {
96 ActionableView::GetAccessibleState(state);
97 state->role = ui::AX_ROLE_TIME;
98 }
99
100 BaseDateTimeView::BaseDateTimeView()
101 : hour_type_(WmShell::Get()->system_tray_delegate()->GetHourClockType()) {
102 SetTimer(base::Time::Now());
103 SetFocusBehavior(FocusBehavior::NEVER);
104 }
105
106 void BaseDateTimeView::SetTimer(const base::Time& now) {
107 // Try to set the timer to go off at the next change of the minute. We don't
108 // want to have the timer go off more than necessary since that will cause
109 // the CPU to wake up and consume power.
110 base::Time::Exploded exploded;
111 now.LocalExplode(&exploded);
112
113 // Often this will be called at minute boundaries, and we'll actually want
114 // 60 seconds from now.
115 int seconds_left = 60 - exploded.second;
116 if (seconds_left == 0)
117 seconds_left = 60;
118
119 // Make sure that the timer fires on the next minute. Without this, if it is
120 // called just a teeny bit early, then it will skip the next minute.
121 seconds_left += kTimerSlopSeconds;
122
123 timer_.Stop();
124 timer_.Start(
125 FROM_HERE, base::TimeDelta::FromSeconds(seconds_left),
126 this, &BaseDateTimeView::UpdateText);
127 }
128
129 void BaseDateTimeView::UpdateTextInternal(const base::Time& now) {
130 SetAccessibleName(base::TimeFormatTimeOfDayWithHourClockType(
131 now, hour_type_, base::kKeepAmPm) +
132 base::ASCIIToUTF16(", ") +
133 base::TimeFormatFriendlyDate(now));
134
135 NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
136 }
137
138 void BaseDateTimeView::ChildPreferredSizeChanged(views::View* child) {
139 PreferredSizeChanged();
140 }
141
142 void BaseDateTimeView::OnLocaleChanged() {
143 UpdateText();
144 }
145
146 ///////////////////////////////////////////////////////////////////////////////
147
148 DateView::DateView() : action_(TrayDate::NONE) {
149 SetLayoutManager(
150 new views::BoxLayout(
151 views::BoxLayout::kVertical, 0, 0, 0));
152 date_label_ = CreateLabel();
153 date_label_->SetEnabledColor(kHeaderTextColorNormal);
154 UpdateTextInternal(base::Time::Now());
155 AddChildView(date_label_);
156 }
157
158 DateView::~DateView() {
159 }
160
161 void DateView::SetAction(TrayDate::DateAction action) {
162 if (action == action_)
163 return;
164 if (IsMouseHovered()) {
165 date_label_->SetEnabledColor(
166 action == TrayDate::NONE ? kHeaderTextColorNormal :
167 kHeaderTextColorHover);
168 SchedulePaint();
169 }
170 action_ = action;
171 SetFocusBehavior(action_ != TrayDate::NONE ? FocusBehavior::ALWAYS
172 : FocusBehavior::NEVER);
173 }
174
175 void DateView::UpdateTimeFormat() {
176 hour_type_ = WmShell::Get()->system_tray_delegate()->GetHourClockType();
177 UpdateText();
178 }
179
180 base::HourClockType DateView::GetHourTypeForTesting() const {
181 return hour_type_;
182 }
183
184 void DateView::SetActive(bool active) {
185 date_label_->SetEnabledColor(active ? kHeaderTextColorHover
186 : kHeaderTextColorNormal);
187 SchedulePaint();
188 }
189
190 void DateView::UpdateTextInternal(const base::Time& now) {
191 BaseDateTimeView::UpdateTextInternal(now);
192 date_label_->SetText(
193 l10n_util::GetStringFUTF16(
194 IDS_ASH_STATUS_TRAY_DATE, FormatDayOfWeek(now), FormatDate(now)));
195 }
196
197 bool DateView::PerformAction(const ui::Event& event) {
198 if (action_ == TrayDate::NONE)
199 return false;
200 if (action_ == TrayDate::SHOW_DATE_SETTINGS)
201 WmShell::Get()->system_tray_delegate()->ShowDateSettings();
202 else if (action_ == TrayDate::SET_SYSTEM_TIME)
203 WmShell::Get()->system_tray_delegate()->ShowSetTimeDialog();
204 return true;
205 }
206
207 void DateView::OnMouseEntered(const ui::MouseEvent& event) {
208 if (action_ == TrayDate::NONE)
209 return;
210 SetActive(true);
211 }
212
213 void DateView::OnMouseExited(const ui::MouseEvent& event) {
214 if (action_ == TrayDate::NONE)
215 return;
216 SetActive(false);
217 }
218
219 void DateView::OnGestureEvent(ui::GestureEvent* event) {
220 if (switches::IsTouchFeedbackEnabled()) {
221 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
222 SetActive(true);
223 } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
224 event->type() == ui::ET_GESTURE_END) {
225 SetActive(false);
226 }
227 }
228 BaseDateTimeView::OnGestureEvent(event);
229 }
230
231 ///////////////////////////////////////////////////////////////////////////////
232
233 TimeView::TimeView(TrayDate::ClockLayout clock_layout) {
234 SetupLabels();
235 UpdateTextInternal(base::Time::Now());
236 UpdateClockLayout(clock_layout);
237 }
238
239 TimeView::~TimeView() {
240 }
241
242 void TimeView::UpdateTimeFormat() {
243 hour_type_ = WmShell::Get()->system_tray_delegate()->GetHourClockType();
244 UpdateText();
245 }
246
247 base::HourClockType TimeView::GetHourTypeForTesting() const {
248 return hour_type_;
249 }
250
251 void TimeView::UpdateTextInternal(const base::Time& now) {
252 // Just in case |now| is null, do NOT update time; otherwise, it will
253 // crash icu code by calling into base::TimeFormatTimeOfDayWithHourClockType,
254 // see details in crbug.com/147570.
255 if (now.is_null()) {
256 LOG(ERROR) << "Received null value from base::Time |now| in argument";
257 return;
258 }
259
260 BaseDateTimeView::UpdateTextInternal(now);
261 base::string16 current_time = base::TimeFormatTimeOfDayWithHourClockType(
262 now, hour_type_, base::kDropAmPm);
263 horizontal_label_->SetText(current_time);
264 horizontal_label_->SetTooltipText(base::TimeFormatFriendlyDate(now));
265
266 // Calculate vertical clock layout labels.
267 size_t colon_pos = current_time.find(base::ASCIIToUTF16(":"));
268 base::string16 hour = current_time.substr(0, colon_pos);
269 base::string16 minute = current_time.substr(colon_pos + 1);
270
271 // Sometimes pad single-digit hours with a zero for aesthetic reasons.
272 if (hour.length() == 1 &&
273 hour_type_ == base::k24HourClock &&
274 !base::i18n::IsRTL())
275 hour = base::ASCIIToUTF16("0") + hour;
276
277 vertical_label_hours_->SetText(hour);
278 vertical_label_minutes_->SetText(minute);
279 Layout();
280 }
281
282 bool TimeView::PerformAction(const ui::Event& event) {
283 return false;
284 }
285
286 bool TimeView::OnMousePressed(const ui::MouseEvent& event) {
287 // Let the event fall through.
288 return false;
289 }
290
291 void TimeView::UpdateClockLayout(TrayDate::ClockLayout clock_layout) {
292 SetBorderFromLayout(clock_layout);
293 if (clock_layout == TrayDate::HORIZONTAL_CLOCK) {
294 RemoveChildView(vertical_label_hours_.get());
295 RemoveChildView(vertical_label_minutes_.get());
296 SetLayoutManager(
297 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
298 AddChildView(horizontal_label_.get());
299 } else {
300 RemoveChildView(horizontal_label_.get());
301 views::GridLayout* layout = new views::GridLayout(this);
302 SetLayoutManager(layout);
303 const int kColumnId = 0;
304 views::ColumnSet* columns = layout->AddColumnSet(kColumnId);
305 columns->AddPaddingColumn(0, kVerticalClockLeftPadding);
306 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
307 0, views::GridLayout::USE_PREF, 0, 0);
308 layout->AddPaddingRow(0, kTrayLabelItemVerticalPaddingVerticalAlignment);
309 layout->StartRow(0, kColumnId);
310 layout->AddView(vertical_label_hours_.get());
311 layout->StartRow(0, kColumnId);
312 layout->AddView(vertical_label_minutes_.get());
313 layout->AddPaddingRow(0, kTrayLabelItemVerticalPaddingVerticalAlignment);
314 }
315 Layout();
316 }
317
318 void TimeView::SetBorderFromLayout(TrayDate::ClockLayout clock_layout) {
319 if (clock_layout == TrayDate::HORIZONTAL_CLOCK)
320 SetBorder(views::Border::CreateEmptyBorder(
321 0,
322 kTrayLabelItemHorizontalPaddingBottomAlignment,
323 0,
324 kTrayLabelItemHorizontalPaddingBottomAlignment));
325 else
326 SetBorder(views::Border::NullBorder());
327 }
328
329 void TimeView::SetupLabels() {
330 horizontal_label_.reset(CreateLabel());
331 SetupLabel(horizontal_label_.get());
332 vertical_label_hours_.reset(CreateLabel());
333 SetupLabel(vertical_label_hours_.get());
334 vertical_label_minutes_.reset(CreateLabel());
335 SetupLabel(vertical_label_minutes_.get());
336 vertical_label_minutes_->SetEnabledColor(kVerticalClockMinuteColor);
337 // Pull the minutes up closer to the hours by using a negative top border.
338 vertical_label_minutes_->SetBorder(views::Border::CreateEmptyBorder(
339 kVerticalClockMinutesTopOffset, 0, 0, 0));
340 }
341
342 void TimeView::SetupLabel(views::Label* label) {
343 label->set_owned_by_client();
344 SetupLabelForTray(label);
345 label->SetElideBehavior(gfx::NO_ELIDE);
346 }
347
348 } // namespace tray
349 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/date/date_view.h ('k') | ash/system/date/date_view_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698