summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-22 23:06:56 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-22 23:06:56 +0000
commit45e0ff3b78fb3fea23b512b4e5632f86c302510a (patch)
treec9a674242661c4aee6965ca97cde925b01830215
parentf654244048abd59f49f1b6af64050fc80b34c55d (diff)
downloadchromium_src-45e0ff3b78fb3fea23b512b4e5632f86c302510a.zip
chromium_src-45e0ff3b78fb3fea23b512b4e5632f86c302510a.tar.gz
chromium_src-45e0ff3b78fb3fea23b512b4e5632f86c302510a.tar.bz2
Adding new general bubble error message consisting of icon, message and caption. Using this message for the multi signin user error case.
There is still more to do: Unit tests & removal of test code. Beside that feature wise it is now fully functional as requested. BUG=239201 TEST=visual, multiple scenarios Review URL: https://chromiumcodereview.appspot.com/15329005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201627 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/popup_message.cc226
-rw-r--r--ash/popup_message.h83
-rw-r--r--ash/resources/ash_resources.grd2
-rw-r--r--ash/system/user/tray_user.cc43
5 files changed, 344 insertions, 12 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index eab24da..1f19dfd 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -161,6 +161,8 @@
'magnifier/magnifier_constants.h',
'magnifier/partial_magnification_controller.cc',
'magnifier/partial_magnification_controller.h',
+ 'popup_message.cc',
+ 'popup_message.h',
'root_window_controller.cc',
'root_window_controller.h',
'rotator/screen_rotation.cc',
diff --git a/ash/popup_message.cc b/ash/popup_message.cc
new file mode 100644
index 0000000..bd51938
--- /dev/null
+++ b/ash/popup_message.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/popup_message.h"
+
+#include "ash/wm/window_animations.h"
+#include "grit/ash_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/insets.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace {
+const int kMessageTopBottomMargin = 10;
+const int kMessageLeftRightMargin = 10;
+const int kMessageAppearanceDelayMs = 200;
+const int kMessageMinHeight = 29 - 2 * kMessageTopBottomMargin;
+const SkColor kMessageTextColor = SkColorSetRGB(0x22, 0x22, 0x22);
+
+// The maximum width of the Message bubble. Borrowed the value from
+// ash/message/message_controller.cc
+const int kMessageMaxWidth = 250;
+
+// The offset for the Message bubble - making sure that the bubble is flush
+// with the shelf. The offset includes the arrow size in pixels as well as
+// the activation bar and other spacing elements.
+const int kArrowOffsetLeftRight = 11;
+const int kArrowOffsetTopBottom = 7;
+
+// The number of pixels between the icon and the text.
+const int kHorizontalPopupPaddingBetweenItems = 10;
+
+// The number of pixels between the text items.
+const int kVerticalPopupPaddingBetweenItems = 10;
+} // namespace
+
+// The implementation of Message of the launcher.
+class PopupMessage::MessageBubble : public views::BubbleDelegateView {
+ public:
+ MessageBubble(const base::string16& caption,
+ const base::string16& message,
+ IconType message_type,
+ views::View* anchor,
+ views::BubbleBorder::Arrow arrow_orientation,
+ const gfx::Size& size_override,
+ int arrow_offset);
+
+ void Close();
+
+ private:
+ // views::View overrides:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ // Each component (width/height) can force a size override for that component
+ // if not 0.
+ gfx::Size size_override_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageBubble);
+};
+
+PopupMessage::MessageBubble::MessageBubble(const base::string16& caption,
+ const base::string16& message,
+ IconType message_type,
+ views::View* anchor,
+ views::BubbleBorder::Arrow arrow,
+ const gfx::Size& size_override,
+ int arrow_offset)
+ : views::BubbleDelegateView(anchor, arrow),
+ size_override_(size_override) {
+ gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom,
+ kArrowOffsetLeftRight,
+ kArrowOffsetTopBottom,
+ kArrowOffsetLeftRight);
+ // An anchor can have an asymmetrical border for spacing reasons. Adjust the
+ // anchor location for this.
+ if (anchor->border())
+ insets += anchor->border()->GetInsets();
+
+ set_anchor_view_insets(insets);
+ set_close_on_esc(false);
+ set_close_on_deactivate(false);
+ set_use_focusless(true);
+ set_accept_events(false);
+
+ set_margins(gfx::Insets(kMessageTopBottomMargin, kMessageLeftRightMargin,
+ kMessageTopBottomMargin, kMessageLeftRightMargin));
+ set_shadow(views::BubbleBorder::SMALL_SHADOW);
+
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
+ kHorizontalPopupPaddingBetweenItems));
+
+ // Here is the layout:
+ // arrow_offset (if not 0)
+ // |-------------|
+ // | ^
+ // +-------------------------------------------------+
+ // -| |-
+ // icon | [!] Caption in bold which can be multi line | caption_label
+ // -| |-
+ // | Message text which can be multi line | message_label
+ // | as well. |
+ // | |-
+ // +-------------------------------------------------+
+ // |------------details container--------------|
+ // Note that the icon, caption and massage are optional.
+
+ // Add the icon to the first column (if there is one).
+ if (message_type != ICON_NONE) {
+ views::ImageView* icon = new views::ImageView();
+ icon->SetImage(
+ bundle.GetImageNamed(IDR_AURA_WARNING_ICON).ToImageSkia());
+ icon->SetVerticalAlignment(views::ImageView::LEADING);
+ AddChildView(icon);
+ }
+
+ // Create a container for the text items and use it as second column.
+ views::View* details = new views::View();
+ AddChildView(details);
+ details->SetLayoutManager(new views::BoxLayout(
+ views::BoxLayout::kVertical, 0, 0, kVerticalPopupPaddingBetweenItems));
+
+ // The caption label.
+ if (!caption.empty()) {
+ views::Label* caption_label = new views::Label(caption);
+ caption_label->SetMultiLine(true);
+ caption_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ caption_label->SetFont(bundle.GetFont(ui::ResourceBundle::BoldFont));
+ caption_label->SetEnabledColor(kMessageTextColor);
+ details->AddChildView(caption_label);
+ }
+
+ // The message label.
+ if (!message.empty()) {
+ views::Label* message_label = new views::Label(message);
+ message_label->SetMultiLine(true);
+ message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ message_label->SetEnabledColor(kMessageTextColor);
+ details->AddChildView(message_label);
+ }
+ views::BubbleDelegateView::CreateBubble(this);
+
+ // Change the arrow offset if needed.
+ if (arrow_offset) {
+ // With the creation of the bubble, the bubble got already placed (and
+ // possibly re-oriented to fit on the screen). Since it is not possible to
+ // set the arrow offset before the creation, we need to set the offset,
+ // and the orientation variables again and force a re-placement.
+ GetBubbleFrameView()->bubble_border()->set_arrow_offset(arrow_offset);
+ GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
+ SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR);
+ }
+}
+
+void PopupMessage::MessageBubble::Close() {
+ if (GetWidget())
+ GetWidget()->Close();
+}
+
+gfx::Size PopupMessage::MessageBubble::GetPreferredSize() {
+ gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize();
+ // Override the size with either the provided size or adjust it to not
+ // violate our minimum / maximum sizes.
+ if (size_override_.height())
+ pref_size.set_height(size_override_.height());
+ else if (pref_size.height() < kMessageMinHeight)
+ pref_size.set_height(kMessageMinHeight);
+
+ if (size_override_.width())
+ pref_size.set_width(size_override_.width());
+ else if (pref_size.width() > kMessageMaxWidth)
+ pref_size.set_width(kMessageMaxWidth);
+
+ return pref_size;
+}
+
+PopupMessage::PopupMessage(const base::string16& caption,
+ const base::string16& message,
+ IconType message_type,
+ views::View* anchor,
+ views::BubbleBorder::Arrow arrow,
+ const gfx::Size& size_override,
+ int arrow_offset)
+ : view_(NULL) {
+ view_ = new MessageBubble(
+ caption, message, message_type, anchor, arrow, size_override,
+ arrow_offset);
+ widget_ = view_->GetWidget();
+
+ gfx::NativeView native_view = widget_->GetNativeView();
+ views::corewm::SetWindowVisibilityAnimationType(
+ native_view, views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
+ views::corewm::SetWindowVisibilityAnimationTransition(
+ native_view, views::corewm::ANIMATE_HIDE);
+ view_->GetWidget()->Show();
+}
+
+PopupMessage::~PopupMessage() {
+ CancelHidingAnimation();
+ Close();
+}
+
+void PopupMessage::Close() {
+ if (view_) {
+ view_->Close();
+ view_ = NULL;
+ widget_ = NULL;
+ }
+}
+
+void PopupMessage::CancelHidingAnimation() {
+ if (!widget_ || !widget_->GetNativeView())
+ return;
+
+ gfx::NativeView native_view = widget_->GetNativeView();
+ views::corewm::SetWindowVisibilityAnimationTransition(
+ native_view, views::corewm::ANIMATE_NONE);
+}
+
+} // namespace ash
diff --git a/ash/popup_message.h b/ash/popup_message.h
new file mode 100644
index 0000000..76257cb
--- /dev/null
+++ b/ash/popup_message.h
@@ -0,0 +1,83 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_POPUP_MESSAGE_H_
+#define ASH_POPUP_MESSAGE_H_
+
+#include "ash/ash_export.h"
+#include "base/basictypes.h"
+#include "base/string16.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/bubble/bubble_border.h"
+
+namespace views {
+class BubbleDelegateView;
+}
+
+namespace ash {
+
+// PopupMessage shows a message to the user. Since the user is not able to
+// dismiss it, the calling code needs to explictly close and destroy it.
+class ASH_EXPORT PopupMessage {
+ public:
+ enum IconType {
+ ICON_WARNING,
+ ICON_NONE
+ };
+
+ // Creates a message pointing towards |anchor| with the requested
+ // |arrow_orientation|. The message contains an optional |caption| which is
+ // drawn in bold and an optional |message| together with an optional icon of
+ // shape |message_type|. If a component in |size_override| is not 0 the value
+ // is the used as output size. If |arrow_offset| is not 0, the number is the
+ // arrow offset in pixels from the border.
+ //
+ // Here is the layout (arrow given as TOP_LEFT):
+ // |--------|
+ // | Anchor |
+ // |--------|
+ // |-arrow_offset---^
+ // +-------------------------------------------------+
+ // -| |-
+ // icon | [!] Caption in bold which can be multi line | caption_label
+ // -| |-
+ // | Message text which can be multi line | message_label
+ // | as well. |
+ // | |-
+ // +-------------------------------------------------+
+ PopupMessage(const base::string16& caption,
+ const base::string16& message,
+ IconType message_type,
+ views::View* anchor,
+ views::BubbleBorder::Arrow arrow,
+ const gfx::Size& size_override,
+ int arrow_offset);
+ // If the message was not explicitly closed before, it closes the message
+ // without animation.
+ virtual ~PopupMessage();
+
+ // Closes the message with a fade out animation.
+ void Close();
+
+ private:
+ class MessageBubble;
+
+ void CancelHidingAnimation();
+
+ MessageBubble* view_;
+ views::Widget* widget_;
+
+ // Variables of the construction time.
+ views::View* anchor_;
+ base::string16 caption_;
+ base::string16 message_;
+ IconType message_type_;
+ views::BubbleBorder::Arrow arrow_orientation_;
+
+ DISALLOW_COPY_AND_ASSIGN(PopupMessage);
+};
+
+} // namespace ash
+
+#endif // ASH_POPUP_MESSAGE_H_
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index 38cbdeb..4e00cc5 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -47,6 +47,8 @@
<structure type="chrome_scaled_image" name="IDR_AURA_CROS_DEFAULT_THROBBER" file="cros/common/default_throbber.png" />
+ <structure type="chrome_scaled_image" name="IDR_AURA_WARNING_ICON" file="common/alert_small.png" />
+
<structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ACCESSIBILITY" file="cros/status/status_accessibility_mode.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK" file="cros/status/status_accessibility_dark.png" />
<structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH" file="cros/status/status_bluetooth.png" />
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index 51d0901..5c56e90 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -8,6 +8,7 @@
#include <climits>
#include <vector>
+#include "ash/popup_message.h"
#include "ash/session_state_delegate.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
@@ -105,6 +106,9 @@ const int kPublicAccountLogoutButtonBorderImagesHovered[] = {
IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
};
+// Offsetting the popup message relative to the tray menu.
+const int kPopupMessageOffset = 25;
+
} // namespace
namespace ash {
@@ -262,6 +266,7 @@ class UserView : public views::View,
MultiProfileIndex multiprofile_index_;
views::View* user_card_;
views::View* logout_button_;
+ scoped_ptr<ash::PopupMessage> popup_message_;
scoped_ptr<views::Widget> add_menu_option_;
// The mouse watcher which takes care of out of window hover events.
@@ -280,6 +285,9 @@ class AddUserView : public views::CustomButton,
AddUserView(UserCard* owner, views::ButtonListener* listener);
virtual ~AddUserView();
+ // Get the anchor view for a message.
+ views::View* anchor() { return anchor_; }
+
// Overridden from views::ButtonListener.
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
@@ -302,6 +310,9 @@ class AddUserView : public views::CustomButton,
// This is the owner view of this item.
UserCard* owner_;
+ // The anchor view for targetted bubble messages.
+ views::View* anchor_;
+
DISALLOW_COPY_AND_ASSIGN(AddUserView);
};
@@ -591,8 +602,7 @@ UserView::UserView(SystemTrayItem* owner,
UserView::~UserView() {}
void UserView::MouseMovedOutOfHost() {
- // Make sure that the MouseWatcher does not outlive our add menu option.
- DCHECK(!add_menu_option_.get());
+ popup_message_.reset();
mouse_watcher_.reset();
add_menu_option_.reset();
}
@@ -832,6 +842,7 @@ void UserView::AddLoggedInPublicModeUserCardContent(SystemTrayItem* owner) {
void UserView::ToggleAddUserMenuOption() {
if (add_menu_option_.get()) {
+ popup_message_.reset();
mouse_watcher_.reset();
add_menu_option_.reset();
return;
@@ -865,14 +876,21 @@ void UserView::ToggleAddUserMenuOption() {
add_menu_option_->SetBounds(bounds);
// Show the content.
- add_menu_option_->SetContentsView(new AddUserView(
- static_cast<UserCard*>(user_card_), this));
+ AddUserView* add_user_view = new AddUserView(
+ static_cast<UserCard*>(user_card_), this);
+ add_menu_option_->SetContentsView(add_user_view);
add_menu_option_->SetAlwaysOnTop(true);
add_menu_option_->Show();
if (cannot_add_more_users) {
- // TODO(skuhne): Use IDS_ASH_STATUS_TRAY_CAPTION_CANNOT_ADD_USER and
- // IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER when showing the error
- // message that no more users can be added.
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ popup_message_.reset(new PopupMessage(
+ bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAPTION_CANNOT_ADD_USER),
+ bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER),
+ PopupMessage::ICON_WARNING,
+ add_user_view->anchor(),
+ views::BubbleBorder::TOP_LEFT,
+ gfx::Size(parent()->bounds().width() - kPopupMessageOffset, 0),
+ 2 * kPopupMessageOffset));
}
// Find the screen area which encloses both elements and sets then a mouse
// watcher which will close the "menu".
@@ -888,7 +906,8 @@ AddUserView::AddUserView(UserCard* owner, views::ButtonListener* listener)
: CustomButton(listener_),
add_user_(NULL),
listener_(listener),
- owner_(owner) {
+ owner_(owner),
+ anchor_(NULL) {
AddContent();
owner_->ForceBorderVisible(true);
}
@@ -942,13 +961,13 @@ void AddUserView::AddContent() {
views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
AddChildViewAt(add_user_, 0);
- // Add the [+] icon.
+ // Add the [+] icon which is also the anchor for messages.
ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
true);
- // TODO(skuhne): Add the resource and load the proper icon.
+ anchor_ = icon;
icon->SetImage(*ui::ResourceBundle::GetSharedInstance().
- GetImageNamed(IDR_AURA_UBER_TRAY_GUEST_ICON).ToImageSkia(),
+ GetImageNamed(IDR_AURA_UBER_TRAY_ADD_MULTIPROFILE_USER).ToImageSkia(),
gfx::Size(kUserIconSize, kUserIconSize));
add_user_->AddChildView(icon);
@@ -1010,7 +1029,7 @@ views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
// Do not show more UserView's then there are logged in users.
if (multiprofile_index_ >= logged_in_users)
- return NULL;;
+ return NULL;
user_ = new tray::UserView(this, status, multiprofile_index_);
return user_;