diff options
author | hbono@chromium.org <hbono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-21 06:28:47 +0000 |
---|---|---|
committer | hbono@chromium.org <hbono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-21 06:28:47 +0000 |
commit | 235b2197b020160e95dcf6456dce9ba45a396fbe (patch) | |
tree | a27bf229bfa268947c06630e20bd26e73e58af4e | |
parent | 51718596075d217dc0c8ffdb6bd624fe068fd0c9 (diff) | |
download | chromium_src-235b2197b020160e95dcf6456dce9ba45a396fbe.zip chromium_src-235b2197b020160e95dcf6456dce9ba45a396fbe.tar.gz chromium_src-235b2197b020160e95dcf6456dce9ba45a396fbe.tar.bz2 |
Add a bubble menu to views.
This change adds a new class ConfirmBubble, which is a simple wrapper class to the Bubble class so we can use a bubble menu as we use an infobar menu. (This menu is to be used for asking whether to integrate the Spelling service to Chrome.)
BUG=99130
TEST=none
Review URL: http://codereview.chromium.org/8060006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106685 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/ui/confirm_bubble_model.cc | 61 | ||||
-rw-r--r-- | chrome/browser/ui/confirm_bubble_model.h | 77 | ||||
-rw-r--r-- | chrome/browser/ui/views/confirm_bubble_view.cc | 162 | ||||
-rw-r--r-- | chrome/browser/ui/views/confirm_bubble_view.h | 71 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 |
5 files changed, 375 insertions, 0 deletions
diff --git a/chrome/browser/ui/confirm_bubble_model.cc b/chrome/browser/ui/confirm_bubble_model.cc new file mode 100644 index 0000000..9501b2b --- /dev/null +++ b/chrome/browser/ui/confirm_bubble_model.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2011 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 "chrome/browser/ui/confirm_bubble_model.h" + +#include "base/logging.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +#if defined(TOOLKIT_VIEWS) +#include "chrome/browser/ui/views/confirm_bubble_view.h" +#include "ui/gfx/rect.h" +#include "views/widget/widget.h" +#endif + +ConfirmBubbleModel::ConfirmBubbleModel() { +} + +ConfirmBubbleModel::~ConfirmBubbleModel() { +} + +int ConfirmBubbleModel::GetButtons() const { + return BUTTON_OK | BUTTON_CANCEL; +} + +string16 ConfirmBubbleModel::GetButtonLabel(BubbleButton button) const { + return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_OK : IDS_CANCEL); +} + +void ConfirmBubbleModel::Accept() { +} + +void ConfirmBubbleModel::Cancel() { +} + +string16 ConfirmBubbleModel::GetLinkText() const { + return string16(); +} + +void ConfirmBubbleModel::LinkClicked() { +} + +void ConfirmBubbleModel::Show(gfx::NativeView view, + const gfx::Point& origin, + ConfirmBubbleModel* model) { +#if defined(TOOLKIT_VIEWS) + views::Widget* parent = views::Widget::GetTopLevelWidgetForNativeView(view); + if (!parent) + return; + + ConfirmBubbleView* bubble_view = new ConfirmBubbleView(model); + Bubble* bubble = Bubble::Show(parent, gfx::Rect(origin, gfx::Size()), + views::BubbleBorder::NONE, + bubble_view, bubble_view); + bubble->SizeToContents(); +#else + NOTIMPLEMENTED(); // Bug 99130: Implement it. +#endif +} + diff --git a/chrome/browser/ui/confirm_bubble_model.h b/chrome/browser/ui/confirm_bubble_model.h new file mode 100644 index 0000000..4253c38 --- /dev/null +++ b/chrome/browser/ui/confirm_bubble_model.h @@ -0,0 +1,77 @@ +// Copyright (c) 2011 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 CHROME_BROWSER_UI_CONFIRM_BUBBLE_MODEL_H_ +#define CHROME_BROWSER_UI_CONFIRM_BUBBLE_MODEL_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/string16.h" +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Image; +class Point; +} + +// An interface implemented by objects wishing to control an ConfirmBubbleView. +// To use this class to implement a bubble menu, we need two steps: +// 1. Implement a class derived from this class. +// 2. Call ConfirmBubbleModel::Show() with the class implemented in 1. +class ConfirmBubbleModel { + public: + enum BubbleButton { + BUTTON_NONE = 0, + BUTTON_OK = 1 << 0, + BUTTON_CANCEL = 1 << 1, + }; + + ConfirmBubbleModel(); + virtual ~ConfirmBubbleModel(); + + // Returns the title string and the message string to be displayed for this + // bubble menu. These must not be empty strings. + virtual string16 GetTitle() const = 0; + virtual string16 GetMessageText() const = 0; + + // Returns an icon for the bubble. This image should be owned by the + // ResourceBundle and callers should not take ownership of it. Must not return + // NULL. + virtual gfx::Image* GetIcon() const = 0; + + // Return the buttons to be shown for this bubble menu. This function returns + // a combination of BubbleButton values, e.g. when we show both an OK button + // and a cancel button, it should return (BUTTON_OK | BUTTON_CANCEL). (This is + // the default implementation.) + virtual int GetButtons() const; + + // Return the label for the specified button. The default implementation + // returns "OK" for the OK button and "Cancel" for the Cancel button. + virtual string16 GetButtonLabel(BubbleButton button) const; + + // Called when the OK button is pressed. + virtual void Accept(); + + // Called when the Cancel button is pressed. + virtual void Cancel(); + + // Returns the text of the link to be displayed, if any. Otherwise returns + // and empty string. + virtual string16 GetLinkText() const; + + // Called when the Link is clicked. + virtual void LinkClicked(); + + // Creates a bubble and shows it with its top center at the specified + // |origin|. A bubble created by this function takes ownership of the + // specified |model|. + static void Show(gfx::NativeView view, + const gfx::Point& origin, + ConfirmBubbleModel* model); + + private: + DISALLOW_COPY_AND_ASSIGN(ConfirmBubbleModel); +}; + +#endif // CHROME_BROWSER_UI_CONFIRM_BUBBLE_MODEL_H_ diff --git a/chrome/browser/ui/views/confirm_bubble_view.cc b/chrome/browser/ui/views/confirm_bubble_view.cc new file mode 100644 index 0000000..110938d --- /dev/null +++ b/chrome/browser/ui/views/confirm_bubble_view.cc @@ -0,0 +1,162 @@ +// Copyright (c) 2011 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 "chrome/browser/ui/views/confirm_bubble_view.h" + +#include "chrome/browser/ui/confirm_bubble_model.h" +#include "grit/theme_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image.h" +#include "views/controls/button/image_button.h" +#include "views/controls/button/text_button.h" +#include "views/controls/image_view.h" +#include "views/controls/label.h" +#include "views/controls/link.h" +#include "views/layout/grid_layout.h" +#include "views/layout/layout_constants.h" + +namespace { + +// Maximum width for the message field. We will wrap the message text when its +// width is wider than this. +const int kMaxMessageWidth = 400; + +} // namespace + +ConfirmBubbleView::ConfirmBubbleView(ConfirmBubbleModel* model) + : model_(model) { + DCHECK(model); +} + +ConfirmBubbleView::~ConfirmBubbleView() { +} + +void ConfirmBubbleView::BubbleClosing(Bubble* bubble, bool closed_by_escape) { +} + +bool ConfirmBubbleView::CloseOnEscape() { + return true; +} + +bool ConfirmBubbleView::FadeInOnShow() { + return false; +} + +void ConfirmBubbleView::ButtonPressed(views::Button* sender, + const views::Event& event) { + if (sender->tag() == ConfirmBubbleModel::BUTTON_OK) + model_->Accept(); + else if (sender->tag() == ConfirmBubbleModel::BUTTON_CANCEL) + model_->Cancel(); + GetWidget()->Close(); +} + +void ConfirmBubbleView::LinkClicked(views::Link* source, int event_flags) { + model_->LinkClicked(); +} + +void ConfirmBubbleView::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (!is_add || child != this) + return; + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + views::GridLayout* layout = new views::GridLayout(this); + SetLayoutManager(layout); + + // Add the icon, the title label and the close button to the first row. + views::ColumnSet* cs = layout->AddColumnSet(0); + cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); + cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing); + cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + + layout->StartRow(0, 0); + gfx::Image* icon_image = model_->GetIcon(); + DCHECK(icon_image); + views::ImageView* icon_view = new views::ImageView; + icon_view->SetImage(icon_image->ToSkBitmap()); + layout->AddView(icon_view); + + const string16 title_text = model_->GetTitle(); + DCHECK(!title_text.empty()); + views::Label* title_label = new views::Label(title_text); + title_label->SetFont(bundle.GetFont(ResourceBundle::MediumFont)); + title_label->SetBackgroundColor(Bubble::kBackgroundColor); + layout->AddView(title_label); + + views::ImageButton* close_button = new views::ImageButton(this); + const SkBitmap* close_image = + bundle.GetImageNamed(IDR_INFO_BUBBLE_CLOSE).ToSkBitmap(); + close_button->SetImage(views::CustomButton::BS_NORMAL, close_image); + close_button->set_tag(ConfirmBubbleModel::BUTTON_NONE); + layout->AddView(close_button); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Add the message label to the second row. + cs = layout->AddColumnSet(1); + const string16 message_text = model_->GetMessageText(); + DCHECK(!message_text.empty()); + views::Label* message_label = new views::Label(message_text); + int message_width = + std::min(kMaxMessageWidth, message_label->GetPreferredSize().width()); + cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, + views::GridLayout::FIXED, message_width, false); + message_label->SetBounds(0, 0, message_width, 0); + message_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + message_label->SetMultiLine(true); + message_label->SetBackgroundColor(Bubble::kBackgroundColor); + layout->StartRow(0, 1); + layout->AddView(message_label); + + // Add the the link label to the third row if it exists. + const string16 link_text = model_->GetLinkText(); + if (!link_text.empty()) { + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + layout->StartRow(0, 1); + views::Link* link_label = new views::Link(link_text); + link_label->set_listener(this); + link_label->SetBackgroundColor(Bubble::kBackgroundColor); + layout->AddView(link_label); + } + layout->AddPaddingRow(0, views::kLabelToControlVerticalSpacing); + + // Add the ok button and the cancel button to the third (or fourth) row if we + // have either of them. + bool has_ok_button = !!(model_->GetButtons() & ConfirmBubbleModel::BUTTON_OK); + bool has_cancel_button = + !!(model_->GetButtons() & ConfirmBubbleModel::BUTTON_CANCEL); + if (has_ok_button || has_cancel_button) { + cs = layout->AddColumnSet(2); + cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing); + if (has_ok_button) { + cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + if (has_cancel_button) + cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); + } + if (has_cancel_button) { + cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + } + layout->StartRow(0, 2); + if (has_ok_button) { + views::TextButton* ok_button = new views::NativeTextButton( + this, model_->GetButtonLabel(ConfirmBubbleModel::BUTTON_OK)); + ok_button->set_tag(ConfirmBubbleModel::BUTTON_OK); + layout->AddView(ok_button); + } + if (has_cancel_button) { + views::TextButton* cancel_button = new views::NativeTextButton( + this, model_->GetButtonLabel(ConfirmBubbleModel::BUTTON_CANCEL)); + cancel_button->set_tag(ConfirmBubbleModel::BUTTON_CANCEL); + layout->AddView(cancel_button); + } + } +} diff --git a/chrome/browser/ui/views/confirm_bubble_view.h b/chrome/browser/ui/views/confirm_bubble_view.h new file mode 100644 index 0000000..89ecd89 --- /dev/null +++ b/chrome/browser/ui/views/confirm_bubble_view.h @@ -0,0 +1,71 @@ +// Copyright (c) 2011 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 CHROME_BROWSER_UI_VIEWS_CONFIRM_BUBBLE_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_CONFIRM_BUBBLE_VIEW_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/views/bubble/bubble.h" +#include "views/controls/button/button.h" +#include "views/controls/link_listener.h" +#include "views/view.h" + +class ConfirmBubbleModel; + +// A class that implements a bubble that consists of the following items: +// * one icon ("icon") +// * one title text ("title") +// * one message text ("message") +// * one optional link ("link") +// * two optional buttons ("ok" and "cancel") +// +// This bubble is convenient when we wish to ask transient, non-blocking +// questions. Unlike a dialog, a bubble menu disappears when we click outside of +// its window to avoid blocking user operations. A bubble is laid out as +// follows: +// +// +------------------------+ +// | icon title x | +// | message | +// | link | +// | [OK] [Cancel] | +// +------------------------+ +// +class ConfirmBubbleView : public BubbleDelegate, + public views::ButtonListener, + public views::LinkListener, + public views::View { + public: + explicit ConfirmBubbleView(ConfirmBubbleModel* model); + + protected: + virtual ~ConfirmBubbleView(); + + // BubbleDelegate implementation. + virtual void BubbleClosing(Bubble* bubble, bool closed_by_escape) OVERRIDE; + virtual bool CloseOnEscape() OVERRIDE; + virtual bool FadeInOnShow() OVERRIDE; + + // views::ButtonListener implementation. + virtual void ButtonPressed(views::Button* sender, + const views::Event& event) OVERRIDE; + + // views::LinkListener implementation. + virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; + + // views::View implementation. + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) OVERRIDE; + + private: + // The model to customize this bubble view. + scoped_ptr<ConfirmBubbleModel> model_; + + DISALLOW_COPY_AND_ASSIGN(ConfirmBubbleView); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_CONFIRM_BUBBLE_VIEW_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 30eb746..28cb4d0 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2841,6 +2841,8 @@ 'browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm', 'browser/ui/collected_cookies_infobar_delegate.cc', 'browser/ui/collected_cookies_infobar_delegate.h', + 'browser/ui/confirm_bubble_model.cc', + 'browser/ui/confirm_bubble_model.h', 'browser/ui/content_settings/content_setting_bubble_model.cc', 'browser/ui/content_settings/content_setting_bubble_model.h', 'browser/ui/content_settings/content_setting_image_model.cc', @@ -3280,6 +3282,8 @@ 'browser/ui/views/chrome_views_delegate.h', 'browser/ui/views/collected_cookies_win.cc', 'browser/ui/views/collected_cookies_win.h', + 'browser/ui/views/confirm_bubble_view.cc', + 'browser/ui/views/confirm_bubble_view.h', 'browser/ui/views/constrained_html_delegate_gtk.cc', 'browser/ui/views/constrained_html_delegate_views.cc', 'browser/ui/views/constrained_window_views.cc', |