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