OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/system/chromeos/tray_display.h" | 5 #include "ash/system/chromeos/tray_display.h" |
6 | 6 |
7 #include "ash/display/display_controller.h" | 7 #include "ash/display/display_controller.h" |
8 #include "ash/display/display_manager.h" | 8 #include "ash/display/display_manager.h" |
9 #include "ash/shell.h" | 9 #include "ash/shell.h" |
10 #include "ash/system/tray/fixed_sized_image_view.h" | 10 #include "ash/system/tray/fixed_sized_image_view.h" |
11 #include "ash/system/tray/system_tray.h" | 11 #include "ash/system/tray/system_tray.h" |
12 #include "ash/system/tray/system_tray_delegate.h" | 12 #include "ash/system/tray/system_tray_delegate.h" |
13 #include "ash/system/tray/tray_constants.h" | 13 #include "ash/system/tray/tray_constants.h" |
14 #include "ash/system/tray/tray_notification_view.h" | 14 #include "ash/system/tray/tray_notification_view.h" |
15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
16 #include "grit/ash_resources.h" | 16 #include "grit/ash_resources.h" |
17 #include "grit/ash_strings.h" | 17 #include "grit/ash_strings.h" |
18 #include "ui/base/l10n/l10n_util.h" | 18 #include "ui/base/l10n/l10n_util.h" |
19 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
20 #include "ui/views/controls/label.h" | 20 #include "ui/views/controls/label.h" |
21 #include "ui/views/layout/box_layout.h" | 21 #include "ui/views/layout/box_layout.h" |
22 | 22 |
23 namespace ash { | 23 namespace ash { |
24 namespace internal { | 24 namespace internal { |
25 namespace { | 25 namespace { |
26 | 26 |
27 TrayDisplayMode GetCurrentTrayDisplayMode() { | 27 DisplayManager* GetDisplayManager() { |
28 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); | 28 return Shell::GetInstance()->display_manager(); |
29 if (display_manager->GetNumDisplays() > 1) | 29 } |
30 return TRAY_DISPLAY_EXTENDED; | |
31 | 30 |
32 if (display_manager->IsMirrored()) | 31 base::string16 GetDisplayName(int64 display_id) { |
33 return TRAY_DISPLAY_MIRRORED; | 32 return UTF8ToUTF16(GetDisplayManager()->GetDisplayNameForId(display_id)); |
33 } | |
34 | 34 |
35 int64 first_id = display_manager->first_display_id(); | 35 base::string16 GetDisplaySize(int64 display_id) { |
36 if (display_manager->HasInternalDisplay() && | 36 return UTF8ToUTF16( |
37 !display_manager->IsInternalDisplayId(first_id)) { | 37 GetDisplayManager()->GetDisplayForId(display_id).size().ToString()); |
38 return TRAY_DISPLAY_DOCKED; | 38 } |
39 } | |
40 | 39 |
41 return TRAY_DISPLAY_SINGLE; | 40 bool ShouldShowResolution(int64 display_id) { |
41 if (!GetDisplayManager()->GetDisplayForId(display_id).is_valid()) | |
42 return false; | |
43 | |
44 const DisplayInfo& display_info = | |
45 GetDisplayManager()->GetDisplayInfo(display_id); | |
46 return display_info.rotation() != gfx::Display::ROTATE_0 || | |
47 display_info.ui_scale() != 1.0f; | |
42 } | 48 } |
43 | 49 |
44 // Returns the name of the currently connected external display. | 50 // Returns the name of the currently connected external display. |
45 base::string16 GetExternalDisplayName() { | 51 base::string16 GetExternalDisplayName() { |
46 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); | 52 DisplayManager* display_manager = GetDisplayManager(); |
47 int64 external_id = display_manager->mirrored_display().id(); | 53 int64 external_id = display_manager->mirrored_display().id(); |
48 | 54 |
49 if (external_id == gfx::Display::kInvalidDisplayID) { | 55 if (external_id == gfx::Display::kInvalidDisplayID) { |
50 int64 internal_display_id = gfx::Display::InternalDisplayId(); | 56 int64 internal_display_id = gfx::Display::InternalDisplayId(); |
51 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { | 57 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { |
52 int64 id = display_manager->GetDisplayAt(i)->id(); | 58 int64 id = display_manager->GetDisplayAt(i)->id(); |
53 if (id != internal_display_id) { | 59 if (id != internal_display_id) { |
54 external_id = id; | 60 external_id = id; |
55 break; | 61 break; |
56 } | 62 } |
57 } | 63 } |
58 } | 64 } |
59 if (external_id != gfx::Display::kInvalidDisplayID) | 65 |
60 return UTF8ToUTF16(display_manager->GetDisplayNameForId(external_id)); | 66 if (external_id == gfx::Display::kInvalidDisplayID) |
61 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); | 67 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); |
68 | |
69 // The external display name may have an annotation of "(width x height)" in | |
70 // case that the display is rotated or its resolution is changed. | |
71 base::string16 name = GetDisplayName(external_id); | |
72 if (ShouldShowResolution(external_id)) | |
73 name += UTF8ToUTF16(" (") + GetDisplaySize(external_id) + UTF8ToUTF16(")"); | |
oshima
2013/06/19 18:20:31
Any RTL issue here? (I think it's ok, but just dou
Jun Mukai
2013/06/19 23:42:35
looks okay to me
| |
74 | |
75 return name; | |
62 } | 76 } |
63 | 77 |
64 class DisplayViewBase { | 78 base::string16 GetTrayDisplayMessage() { |
65 public: | 79 DisplayManager* display_manager = GetDisplayManager(); |
66 DisplayViewBase(user::LoginStatus login_status) | 80 if (display_manager->GetNumDisplays() > 1) { |
67 : login_status_(login_status) { | 81 if (GetDisplayManager()->HasInternalDisplay()) { |
68 label_ = new views::Label(); | 82 return l10n_util::GetStringFUTF16( |
69 label_->SetMultiLine(true); | 83 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetExternalDisplayName()); |
70 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 84 } |
85 return l10n_util::GetStringUTF16( | |
86 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL); | |
71 } | 87 } |
72 | 88 |
73 virtual ~DisplayViewBase() { | 89 if (display_manager->IsMirrored()) { |
90 if (GetDisplayManager()->HasInternalDisplay()) { | |
91 return l10n_util::GetStringFUTF16( | |
92 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetExternalDisplayName()); | |
93 } | |
94 return l10n_util::GetStringUTF16( | |
95 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL); | |
74 } | 96 } |
75 | 97 |
76 protected: | 98 int64 first_id = display_manager->first_display_id(); |
77 void OpenSettings() { | 99 if (display_manager->HasInternalDisplay() && |
78 if (login_status_ == ash::user::LOGGED_IN_USER || | 100 !display_manager->IsInternalDisplayId(first_id)) { |
79 login_status_ == ash::user::LOGGED_IN_OWNER || | 101 return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED); |
80 login_status_ == ash::user::LOGGED_IN_GUEST) { | |
81 ash::Shell::GetInstance()->system_tray_delegate()->ShowDisplaySettings(); | |
82 } | |
83 } | 102 } |
84 | 103 |
85 bool UpdateLabelText() { | 104 return base::string16(); |
86 switch (GetCurrentTrayDisplayMode()) { | 105 } |
87 case TRAY_DISPLAY_SINGLE: | 106 |
88 // TODO(oshima|mukai): Support single display mode for overscan | 107 void OpenSettings(user::LoginStatus login_status) { |
89 // alignment. | 108 if (login_status == ash::user::LOGGED_IN_USER || |
90 return false; | 109 login_status == ash::user::LOGGED_IN_OWNER || |
91 case TRAY_DISPLAY_EXTENDED: | 110 login_status == ash::user::LOGGED_IN_GUEST) { |
92 if (Shell::GetInstance()->display_manager()->HasInternalDisplay()) { | 111 ash::Shell::GetInstance()->system_tray_delegate()->ShowDisplaySettings(); |
93 label_->SetText(l10n_util::GetStringFUTF16( | |
94 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetExternalDisplayName())); | |
95 } else { | |
96 label_->SetText(l10n_util::GetStringUTF16( | |
97 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL)); | |
98 } | |
99 break; | |
100 case TRAY_DISPLAY_MIRRORED: | |
101 if (Shell::GetInstance()->display_manager()->HasInternalDisplay()) { | |
102 label_->SetText(l10n_util::GetStringFUTF16( | |
103 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetExternalDisplayName())); | |
104 } else { | |
105 label_->SetText(l10n_util::GetStringUTF16( | |
106 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL)); | |
107 } | |
108 break; | |
109 case TRAY_DISPLAY_DOCKED: | |
110 label_->SetText(l10n_util::GetStringUTF16( | |
111 IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED)); | |
112 break; | |
113 } | |
114 return true; | |
115 } | 112 } |
116 | 113 } |
117 views::Label* label() { return label_; } | |
118 | |
119 private: | |
120 user::LoginStatus login_status_; | |
121 views::Label* label_; | |
122 | |
123 DISALLOW_COPY_AND_ASSIGN(DisplayViewBase); | |
124 }; | |
125 | 114 |
126 } // namespace | 115 } // namespace |
127 | 116 |
128 class DisplayView : public DisplayViewBase, | 117 class DisplayView : public ash::internal::ActionableView { |
129 public ash::internal::ActionableView { | |
130 public: | 118 public: |
131 explicit DisplayView(user::LoginStatus login_status) | 119 explicit DisplayView(user::LoginStatus login_status) |
132 : DisplayViewBase(login_status) { | 120 : login_status_(login_status) { |
133 SetLayoutManager(new | 121 SetLayoutManager(new |
134 views::BoxLayout(views::BoxLayout::kHorizontal, | 122 views::BoxLayout(views::BoxLayout::kHorizontal, |
135 ash::kTrayPopupPaddingHorizontal, 0, | 123 ash::kTrayPopupPaddingHorizontal, 0, |
136 ash::kTrayPopupPaddingBetweenItems)); | 124 ash::kTrayPopupPaddingBetweenItems)); |
137 | 125 |
138 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | 126 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
139 image_ = | 127 image_ = |
140 new ash::internal::FixedSizedImageView(0, ash::kTrayPopupItemHeight); | 128 new ash::internal::FixedSizedImageView(0, ash::kTrayPopupItemHeight); |
141 image_->SetImage( | 129 image_->SetImage( |
142 bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY).ToImageSkia()); | 130 bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY).ToImageSkia()); |
143 AddChildView(image_); | 131 AddChildView(image_); |
144 AddChildView(label()); | 132 |
133 label_ = new views::Label(); | |
134 label_->SetMultiLine(true); | |
135 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
136 AddChildView(label_); | |
145 Update(); | 137 Update(); |
146 } | 138 } |
147 | 139 |
148 virtual ~DisplayView() {} | 140 virtual ~DisplayView() {} |
149 | 141 |
150 void Update() { | 142 void Update() { |
151 SetVisible(UpdateLabelText()); | 143 base::string16 message = GetTrayDisplayMessage(); |
144 if (message.empty()) | |
145 message = GetInternalDisplayInfo(); | |
146 SetVisible(!message.empty()); | |
147 label_->SetText(message); | |
152 } | 148 } |
153 | 149 |
154 private: | 150 private: |
151 base::string16 GetInternalDisplayInfo() const { | |
152 int64 first_id = GetDisplayManager()->first_display_id(); | |
153 if (!ShouldShowResolution(first_id)) | |
154 return base::string16(); | |
155 | |
156 return l10n_util::GetStringFUTF16( | |
157 IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY, | |
158 GetDisplayName(first_id), | |
159 GetDisplaySize(first_id)); | |
160 } | |
161 | |
155 // Overridden from ActionableView. | 162 // Overridden from ActionableView. |
156 virtual bool PerformAction(const ui::Event& event) OVERRIDE { | 163 virtual bool PerformAction(const ui::Event& event) OVERRIDE { |
157 OpenSettings(); | 164 OpenSettings(login_status_); |
158 return true; | 165 return true; |
159 } | 166 } |
160 | 167 |
161 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { | 168 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { |
162 int label_max_width = bounds().width() - kTrayPopupPaddingHorizontal * 2 - | 169 int label_max_width = bounds().width() - kTrayPopupPaddingHorizontal * 2 - |
163 kTrayPopupPaddingBetweenItems - image_->GetPreferredSize().width(); | 170 kTrayPopupPaddingBetweenItems - image_->GetPreferredSize().width(); |
164 label()->SizeToFit(label_max_width); | 171 label_->SizeToFit(label_max_width); |
165 PreferredSizeChanged(); | 172 PreferredSizeChanged(); |
166 } | 173 } |
167 | 174 |
175 // Overridden from views::View. | |
176 virtual bool GetTooltipText(const gfx::Point& p, | |
177 string16* tooltip) const OVERRIDE { | |
178 base::string16 tray_message = GetTrayDisplayMessage(); | |
179 base::string16 internal_message = GetInternalDisplayInfo(); | |
180 if (tray_message.empty() && internal_message.empty()) | |
181 return false; | |
182 | |
183 *tooltip = tray_message + base::string16(1, '\n') + internal_message; | |
oshima
2013/06/19 18:20:31
RTL?
Jun Mukai
2013/06/19 23:42:35
linebreak won't suffer from RTL issue.
| |
184 return true; | |
185 } | |
186 | |
187 user::LoginStatus login_status_; | |
168 views::ImageView* image_; | 188 views::ImageView* image_; |
189 views::Label* label_; | |
169 | 190 |
170 DISALLOW_COPY_AND_ASSIGN(DisplayView); | 191 DISALLOW_COPY_AND_ASSIGN(DisplayView); |
171 }; | 192 }; |
172 | 193 |
173 class DisplayNotificationView : public DisplayViewBase, | 194 class DisplayNotificationView : public TrayNotificationView { |
174 public TrayNotificationView { | |
175 public: | 195 public: |
176 DisplayNotificationView(user::LoginStatus login_status, | 196 DisplayNotificationView(user::LoginStatus login_status, |
177 TrayDisplay* tray_item) | 197 TrayDisplay* tray_item, |
178 : DisplayViewBase(login_status), | 198 const base::string16& message) |
179 TrayNotificationView(tray_item, IDR_AURA_UBER_TRAY_DISPLAY) { | 199 : TrayNotificationView(tray_item, IDR_AURA_UBER_TRAY_DISPLAY), |
180 InitView(label()); | 200 login_status_(login_status) { |
181 StartAutoCloseTimer(kTrayPopupAutoCloseDelayForTextInSeconds); | 201 StartAutoCloseTimer(kTrayPopupAutoCloseDelayForTextInSeconds); |
182 Update(); | 202 Update(message); |
183 } | 203 } |
184 | 204 |
185 virtual ~DisplayNotificationView() {} | 205 virtual ~DisplayNotificationView() {} |
186 | 206 |
187 void Update() { | 207 void Update(const base::string16& message) { |
188 if (UpdateLabelText()) | 208 if (message.empty()) { |
209 owner()->HideNotificationView(); | |
210 } else { | |
211 views::Label* label = new views::Label(message); | |
212 label->SetMultiLine(true); | |
213 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
214 UpdateView(label); | |
189 RestartAutoCloseTimer(); | 215 RestartAutoCloseTimer(); |
190 else | 216 } |
191 owner()->HideNotificationView(); | |
192 } | 217 } |
193 | 218 |
194 // Overridden from TrayNotificationView: | 219 // Overridden from TrayNotificationView: |
195 virtual void OnClickAction() OVERRIDE { | 220 virtual void OnClickAction() OVERRIDE { |
196 OpenSettings(); | 221 OpenSettings(login_status_); |
197 } | 222 } |
198 | 223 |
199 private: | 224 private: |
225 user::LoginStatus login_status_; | |
226 | |
200 DISALLOW_COPY_AND_ASSIGN(DisplayNotificationView); | 227 DISALLOW_COPY_AND_ASSIGN(DisplayNotificationView); |
201 }; | 228 }; |
202 | 229 |
203 TrayDisplay::TrayDisplay(SystemTray* system_tray) | 230 TrayDisplay::TrayDisplay(SystemTray* system_tray) |
204 : SystemTrayItem(system_tray), | 231 : SystemTrayItem(system_tray), |
205 default_(NULL), | 232 default_(NULL), |
206 notification_(NULL), | 233 notification_(NULL) { |
207 current_mode_(GetCurrentTrayDisplayMode()) { | 234 current_message_ = GetDisplayMessageForNotification(); |
208 Shell::GetInstance()->display_controller()->AddObserver(this); | 235 Shell::GetInstance()->display_controller()->AddObserver(this); |
209 } | 236 } |
210 | 237 |
211 TrayDisplay::~TrayDisplay() { | 238 TrayDisplay::~TrayDisplay() { |
212 Shell::GetInstance()->display_controller()->RemoveObserver(this); | 239 Shell::GetInstance()->display_controller()->RemoveObserver(this); |
213 } | 240 } |
214 | 241 |
242 base::string16 TrayDisplay::GetDisplayMessageForNotification() { | |
243 DisplayManager* display_manager = GetDisplayManager(); | |
244 std::map<int64, DisplayInfo> old_info; | |
245 old_info.swap(display_info_); | |
246 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { | |
247 int64 id = display_manager->GetDisplayAt(i)->id(); | |
248 display_info_[id] = display_manager->GetDisplayInfo(id); | |
249 } | |
250 | |
251 if (display_info_.size() == old_info.size()) { | |
252 for (std::map<int64, DisplayInfo>::const_iterator iter = | |
253 display_info_.begin(); iter != display_info_.end(); ++iter) { | |
254 std::map<int64, DisplayInfo>::const_iterator old_iter = | |
255 old_info.find(iter->first); | |
256 if (old_iter == old_info.end()) | |
257 break; | |
258 | |
259 if (iter->second.ui_scale() != old_iter->second.ui_scale()) { | |
260 return l10n_util::GetStringFUTF16( | |
261 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, | |
262 GetDisplayName(iter->first), | |
263 GetDisplaySize(iter->first)); | |
264 } | |
265 if (iter->second.rotation() != old_iter->second.rotation()) { | |
266 return l10n_util::GetStringFUTF16( | |
267 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetDisplayName(iter->first)); | |
268 } | |
269 } | |
270 } | |
271 | |
272 return GetTrayDisplayMessage(); | |
273 } | |
274 | |
215 views::View* TrayDisplay::CreateDefaultView(user::LoginStatus status) { | 275 views::View* TrayDisplay::CreateDefaultView(user::LoginStatus status) { |
216 DCHECK(default_ == NULL); | 276 DCHECK(default_ == NULL); |
217 default_ = new DisplayView(status); | 277 default_ = new DisplayView(status); |
218 return default_; | 278 return default_; |
219 } | 279 } |
220 | 280 |
221 views::View* TrayDisplay::CreateNotificationView(user::LoginStatus status) { | 281 views::View* TrayDisplay::CreateNotificationView(user::LoginStatus status) { |
222 DCHECK(notification_ == NULL); | 282 DCHECK(notification_ == NULL); |
223 notification_ = new DisplayNotificationView(status, this); | 283 notification_ = new DisplayNotificationView(status, this, current_message_); |
224 return notification_; | 284 return notification_; |
225 } | 285 } |
226 | 286 |
227 void TrayDisplay::DestroyDefaultView() { | 287 void TrayDisplay::DestroyDefaultView() { |
228 default_ = NULL; | 288 default_ = NULL; |
229 } | 289 } |
230 | 290 |
231 void TrayDisplay::DestroyNotificationView() { | 291 void TrayDisplay::DestroyNotificationView() { |
232 notification_ = NULL; | 292 notification_ = NULL; |
233 } | 293 } |
234 | 294 |
235 bool TrayDisplay::ShouldShowLauncher() const { | 295 bool TrayDisplay::ShouldShowLauncher() const { |
236 return false; | 296 return false; |
237 } | 297 } |
238 | 298 |
239 void TrayDisplay::OnDisplayConfigurationChanged() { | 299 void TrayDisplay::OnDisplayConfigurationChanged() { |
240 TrayDisplayMode new_mode = GetCurrentTrayDisplayMode(); | 300 // TODO(mukai): do not show the notification when the configuration changed |
241 if (current_mode_ != new_mode && new_mode != TRAY_DISPLAY_SINGLE) { | 301 // due to the user operation on display settings page. |
242 if (notification_) | 302 current_message_ = GetDisplayMessageForNotification(); |
243 notification_->Update(); | 303 if (notification_) |
244 else | 304 notification_->Update(current_message_); |
245 ShowNotificationView(); | 305 else if (!current_message_.empty()) |
246 } | 306 ShowNotificationView(); |
247 current_mode_ = new_mode; | |
248 } | 307 } |
249 | 308 |
250 } // namespace internal | 309 } // namespace internal |
251 } // namespace ash | 310 } // namespace ash |
OLD | NEW |