15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/date/date_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/tray_constants.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ash/system/tray/tray_utils.h"
1168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/i18n/rtl.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/time_formatting.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ash_strings.h"
16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/i18n/unicode/datefmt.h"
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/i18n/unicode/dtptngen.h"
18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/border.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/label.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/box_layout.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/grid_layout.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace tray {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount of slop to add into the timer to make sure we're into the next minute
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when the timer goes off.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTimerSlopSeconds = 1;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Text color of the vertical clock minutes.
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const SkColor kVerticalClockMinuteColor = SkColorSetRGB(0xBA, 0xBA, 0xBA);
36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Padding between the left edge of the shelf and the left edge of the vertical
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// clock.
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kVerticalClockLeftPadding = 9;
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Offset used to bring the minutes line closer to the hours line in the
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// vertical clock.
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kVerticalClockMinutesTopOffset = -4;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 FormatDate(const base::Time& time) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::UnicodeString date_string;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<icu::DateFormat> formatter(
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::string16(date_string.getBuffer(),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  static_cast<size_t>(date_string.length()));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 FormatDayOfWeek(const base::Time& time) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode status = U_ZERO_ERROR;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<icu::DateTimePatternGenerator> generator(
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icu::DateTimePatternGenerator::createInstance(status));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(U_SUCCESS(status));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char kBasePattern[] = "EEE";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::UnicodeString generated_pattern =
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      generator->getBestPattern(icu::UnicodeString(kBasePattern), status);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(U_SUCCESS(status));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::SimpleDateFormat simple_formatter(generated_pattern, status);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(U_SUCCESS(status));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::UnicodeString date_string;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  simple_formatter.format(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<UDate>(time.ToDoubleT() * 1000), date_string, status);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(U_SUCCESS(status));
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::string16(
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      date_string.getBuffer(), static_cast<size_t>(date_string.length()));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::Label* CreateLabel() {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Label* label = new views::Label;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return label;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseDateTimeView::~BaseDateTimeView() {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseDateTimeView::UpdateText() {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time now = base::Time::Now();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateTextInternal(now);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetTimer(now);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BaseDateTimeView::BaseDateTimeView() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetTimer(base::Time::Now());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseDateTimeView::SetTimer(const base::Time& now) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to set the timer to go off at the next change of the minute. We don't
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to have the timer go off more than necessary since that will cause
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the CPU to wake up and consume power.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time::Exploded exploded;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  now.LocalExplode(&exploded);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Often this will be called at minute boundaries, and we'll actually want
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 60 seconds from now.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int seconds_left = 60 - exploded.second;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (seconds_left == 0)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seconds_left = 60;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure that the timer fires on the next minute. Without this, if it is
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // called just a teeny bit early, then it will skip the next minute.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  seconds_left += kTimerSlopSeconds;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::TimeDelta::FromSeconds(seconds_left),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, &BaseDateTimeView::UpdateText);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseDateTimeView::ChildPreferredSizeChanged(views::View* child) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreferredSizeChanged();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BaseDateTimeView::OnLocaleChanged() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateText();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)DateView::DateView()
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : hour_type_(ash::Shell::GetInstance()->system_tray_delegate()->
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 GetHourClockType()),
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      action_(TrayDate::NONE) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetLayoutManager(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new views::BoxLayout(
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          views::BoxLayout::kVertical, 0, 0, 0));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  date_label_ = CreateLabel();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  date_label_->SetEnabledColor(kHeaderTextColorNormal);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateTextInternal(base::Time::Now());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(date_label_);
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SetFocusable(false);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DateView::~DateView() {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid DateView::SetAction(TrayDate::DateAction action) {
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (action == action_)
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (IsMouseHovered()) {
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    date_label_->SetEnabledColor(
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        action == TrayDate::NONE ? kHeaderTextColorNormal :
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                   kHeaderTextColorHover);
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SchedulePaint();
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  action_ = action;
1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SetFocusable(action_ != TrayDate::NONE);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DateView::UpdateTimeFormat() {
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  hour_type_ =
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ash::Shell::GetInstance()->system_tray_delegate()->GetHourClockType();
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateText();
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::HourClockType DateView::GetHourTypeForTesting() const {
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return hour_type_;
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DateView::UpdateTextInternal(const base::Time& now) {
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetAccessibleName(
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeFormatFriendlyDate(now) +
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::ASCIIToUTF16(", ") +
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeFormatTimeOfDayWithHourClockType(
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          now, hour_type_, base::kKeepAmPm));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  date_label_->SetText(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringFUTF16(
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IDS_ASH_STATUS_TRAY_DATE, FormatDayOfWeek(now), FormatDate(now)));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DateView::PerformAction(const ui::Event& event) {
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (action_ == TrayDate::NONE)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (action_ == TrayDate::SHOW_DATE_SETTINGS)
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ash::Shell::GetInstance()->system_tray_delegate()->ShowDateSettings();
1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  else if (action_ == TrayDate::SET_SYSTEM_TIME)
1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ash::Shell::GetInstance()->system_tray_delegate()->ShowSetTimeDialog();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DateView::OnMouseEntered(const ui::MouseEvent& event) {
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (action_ == TrayDate::NONE)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  date_label_->SetEnabledColor(kHeaderTextColorHover);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DateView::OnMouseExited(const ui::MouseEvent& event) {
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (action_ == TrayDate::NONE)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  date_label_->SetEnabledColor(kHeaderTextColorNormal);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TimeView::TimeView(TrayDate::ClockLayout clock_layout)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : hour_type_(ash::Shell::GetInstance()->system_tray_delegate()->
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 GetHourClockType()) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetupLabels();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateTextInternal(base::Time::Now());
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateClockLayout(clock_layout);
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetFocusable(false);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TimeView::~TimeView() {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TimeView::UpdateTimeFormat() {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hour_type_ =
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ash::Shell::GetInstance()->system_tray_delegate()->GetHourClockType();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateText();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::HourClockType TimeView::GetHourTypeForTesting() const {
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return hour_type_;
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TimeView::UpdateTextInternal(const base::Time& now) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just in case |now| is null, do NOT update time; otherwise, it will
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // crash icu code by calling into base::TimeFormatTimeOfDayWithHourClockType,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // see details in crbug.com/147570.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (now.is_null()) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Received null value from base::Time |now| in argument";
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::string16 current_time = base::TimeFormatTimeOfDayWithHourClockType(
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now, hour_type_, base::kDropAmPm);
238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  horizontal_label_->SetText(current_time);
239d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  horizontal_label_->SetTooltipText(base::TimeFormatFriendlyDate(now));
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calculate vertical clock layout labels.
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t colon_pos = current_time.find(base::ASCIIToUTF16(":"));
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::string16 hour = current_time.substr(0, colon_pos);
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::string16 minute = current_time.substr(colon_pos + 1);
24568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Sometimes pad single-digit hours with a zero for aesthetic reasons.
24768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (hour.length() == 1 &&
24868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      hour_type_ == base::k24HourClock &&
24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !base::i18n::IsRTL())
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    hour = base::ASCIIToUTF16("0") + hour;
25168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  vertical_label_hours_->SetText(hour);
253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  vertical_label_minutes_->SetText(minute);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TimeView::PerformAction(const ui::Event& event) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TimeView::OnMousePressed(const ui::MouseEvent& event) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let the event fall through.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TimeView::UpdateClockLayout(TrayDate::ClockLayout clock_layout){
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetBorderFromLayout(clock_layout);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (clock_layout == TrayDate::HORIZONTAL_CLOCK) {
269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    RemoveChildView(vertical_label_hours_.get());
270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    RemoveChildView(vertical_label_minutes_.get());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLayoutManager(
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
273d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    AddChildView(horizontal_label_.get());
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
275d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    RemoveChildView(horizontal_label_.get());
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::GridLayout* layout = new views::GridLayout(this);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetLayoutManager(layout);
278d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const int kColumnId = 0;
279d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    views::ColumnSet* columns = layout->AddColumnSet(kColumnId);
280d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    columns->AddPaddingColumn(0, kVerticalClockLeftPadding);
28168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       0, views::GridLayout::USE_PREF, 0, 0);
283d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    layout->AddPaddingRow(0, kTrayLabelItemVerticalPaddingVerticalAlignment);
284d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    layout->StartRow(0, kColumnId);
285d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    layout->AddView(vertical_label_hours_.get());
286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    layout->StartRow(0, kColumnId);
287d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    layout->AddView(vertical_label_minutes_.get());
288d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    layout->AddPaddingRow(0, kTrayLabelItemVerticalPaddingVerticalAlignment);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TimeView::SetBorderFromLayout(TrayDate::ClockLayout clock_layout) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (clock_layout == TrayDate::HORIZONTAL_CLOCK)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetBorder(views::Border::CreateEmptyBorder(
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        0,
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kTrayLabelItemHorizontalPaddingBottomAlignment,
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        0,
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kTrayLabelItemHorizontalPaddingBottomAlignment));
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetBorder(views::Border::NullBorder());
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TimeView::SetupLabels() {
305d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  horizontal_label_.reset(CreateLabel());
306d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetupLabel(horizontal_label_.get());
307d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  vertical_label_hours_.reset(CreateLabel());
308d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetupLabel(vertical_label_hours_.get());
309d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  vertical_label_minutes_.reset(CreateLabel());
310d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetupLabel(vertical_label_minutes_.get());
311d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  vertical_label_minutes_->SetEnabledColor(kVerticalClockMinuteColor);
312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Pull the minutes up closer to the hours by using a negative top border.
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  vertical_label_minutes_->SetBorder(views::Border::CreateEmptyBorder(
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kVerticalClockMinutesTopOffset, 0, 0, 0));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TimeView::SetupLabel(views::Label* label) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label->set_owned_by_client();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetupLabelForTray(label);
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  label->SetFontList(label->font_list().DeriveWithStyle(
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      label->font_list().GetFontStyle() & ~gfx::Font::BOLD));
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace tray
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
326