Chromium Code Reviews| Index: chrome/browser/ui/views/echo_dialog_views_chromeos.cc |
| diff --git a/chrome/browser/ui/views/echo_dialog_views_chromeos.cc b/chrome/browser/ui/views/echo_dialog_views_chromeos.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2ff62c47c50a59ae02d706f1d30eee7f651c1f1d |
| --- /dev/null |
| +++ b/chrome/browser/ui/views/echo_dialog_views_chromeos.cc |
| @@ -0,0 +1,413 @@ |
| +// 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. |
| + |
| +#include "chrome/browser/ui/views/echo_dialog_views_chromeos.h" |
| + |
| +#include "chrome/browser/ui/echo_dialog_listener_chromeos.h" |
| +#include "grit/generated_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#include "ui/base/text/text_elider.h" |
| +#include "ui/views/controls/label.h" |
| +#include "ui/views/controls/link.h" |
| +#include "ui/views/layout/box_layout.h" |
| +#include "ui/views/widget/widget.h" |
| +#include "ui/views/window/dialog_client_view.h" |
| + |
| +namespace { |
| + |
| +const int kDialogContentWidth = 350; |
| + |
| +const int kDialogContentTopInset = 20; |
| +const int kDialogContentLeftInset = 20; |
| +const int kDialogContentBottomInset = 20; |
| +const int kDialogContentRightInset = 100; |
| + |
| +const int kLinkLeftInset = 5; |
| + |
| +// Dialog text has medium sized font. |
| +gfx::Font GetDefaultFontForEcho() { |
| + return ui::ResourceBundle::GetSharedInstance().GetFont( |
| + ui::ResourceBundle::MediumFont); |
| +} |
| + |
| +// Label that shows the service name label. |
| +// The label should have underlined text and display tooltip on hover. |
| +class EchoServiceNameLabel : public views::Label { |
| + public: |
| + EchoServiceNameLabel(const string16& label, const string16& tooltip) |
| + : views::Label(label) { |
| + SetTooltipText(tooltip); |
| + SetMultiLine(false); |
| + SetFont(GetDefaultFontForEcho().DeriveFont(0, gfx::Font::UNDERLINE)); |
| + } |
| + virtual ~EchoServiceNameLabel() {} |
| + |
| + // views::Label override. |
| + // Label have HitTestRect return false by default. To be able to show a |
| + // tooltip, this should be overriden. |
| + virtual bool HitTestRect(const gfx::Rect& rect) const { |
|
sky
2013/02/26 21:28:48
This is a bug in Label, it should be fixed there.
tbarzic
2013/02/26 23:08:50
ok, I'll upload a cl to fix this in label
tbarzic
2013/03/18 18:21:58
Done.
|
| + return GetLocalBounds().Intersects(rect); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(EchoServiceNameLabel); |
| +}; |
| + |
| +// A helper view that contains horizontal set of labels representing one row of |
| +// the dialog text content. The number of labels is not limited, but their |
| +// combined width will be smaller than |kDialogContentWidth|. |
| +class EchoDialogContentRowView : public views::View { |
| + public: |
| + EchoDialogContentRowView() { |
| + SetLayoutManager( |
| + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); |
| + } |
| + |
| + virtual ~EchoDialogContentRowView() {} |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(EchoDialogContentRowView); |
| +}; |
| + |
| +// View representing text content of the dialog. It consists of set of |
| +// vertically laid out |EchoDialogContentRowView| views with limited width. The |
| +// rows are filled with text pieces that should be displayed using different |
| +// styles. |
| +class EchoDialogContentView : public views::View { |
|
sky
2013/02/26 21:28:48
Is there a reason not to use label directly? If yo
tbarzic
2013/02/26 23:08:50
It's also the label types are different: only part
sky
2013/02/27 00:38:35
2013/02/26 23:08:50, tbarzic wrote:
|
| + public: |
| + explicit EchoDialogContentView(views::LinkListener* listener); |
| + virtual ~EchoDialogContentView() {} |
| + |
| + // Creates text pieces that represent the content shown in the dialog when |
| + // echo extension is enabled to redeem offers. |
| + // |
| + // General layout of the dialog in this case is: |
| + // |
| + // -------------------------------------------------------------- |
| + // | ----------------- ---------------- ----------------- | |
| + // | | normal text 1 | | service name | | normal text 2 | | |
| + // | ----------------- ---------------- ----------------- | |
| + // | ---------------------------------------------------------- | |
| + // | | normal text 2 | | |
| + // | ---------------------------------------------------------- | |
| + // | ----------------- --------------------- | |
| + // | | normal text 2 | | 'More info' link | | |
| + // | ----------------- --------------------- | |
| + // -------------------------------------------------------------- |
| + // |
| + // Where 'normal text' is predetermined text of type TEXT_PIECE_LABEL, |
| + // 'service name' equals |service_name| and is of type |
| + // TEXT_PIECE_SERVICE_NAME_LABEL. Hovering over the 'service name' label will |
| + // display tooltip whose content equals |origin|. |
| + // Note that the labels may be broken up, preferably at word delimiters (this |
| + // is not possible for words that are too long). |
| + void InitializeForEnabledEcho(const string16& service_name, |
| + const string16& origin); |
| + |
| + // Creates text pieces that represent the content shown in the dialog when |
| + // echo extension is not allowed to redeem offers. |
| + // |
| + // General layout of the dialog in this case is: |
| + // |
| + // -------------------------------------------------------------- |
| + // | ---------------------------------------------------------- | |
| + // | | normal text 1 | | |
| + // | ---------------------------------------------------------- | |
| + // | ----------------- --------------------- | |
| + // | | normal text 1 | | 'More info' link | | |
| + // | ----------------- --------------------- | |
| + // -------------------------------------------------------------- |
| + // |
| + // With the same parts as for the enabled echo. |
| + void InitializeForDisabledEcho(); |
| + |
| + // Creates layout with text pieces initialized in |
| + // |InitializeFor{Disabled|Enabled}Echo|. |
| + void SetupLayout(); |
| + |
| + private: |
| + enum TextPieceType { |
| + TEXT_PIECE_INVALID, |
| + TEXT_PIECE_LABEL, |
| + TEXT_PIECE_SERVICE_NAME_LABEL, |
| + TEXT_PIECE_LINK |
| + }; |
| + |
| + // Information about a text piece that should be shown in the dialog. |
| + struct TextPieceInfo { |
| + TextPieceInfo() : type(TEXT_PIECE_INVALID) {} |
| + TextPieceInfo(const string16& label, |
| + TextPieceType type) |
| + : label(label), |
| + type(type) { |
| + } |
| + |
| + string16 label; |
| + TextPieceType type; |
| + }; |
| + |
| + // Adds text piece described with |info| to the |current_row|. |
| + // If the whole text piece doesn't fit in the row, the row is filled with as |
| + // much of words from the text piece as possible. New row are created and |
| + // filled with text pieces content until the whole text piece is added to the |
| + // layout. |
| + // Upon completion |current_row| will be set to the last added row. |
| + void SetupTextPieceLayout(const TextPieceInfo& info, |
| + EchoDialogContentRowView** current_row); |
| + // Creates a label view for text piece of type |type| with content |text|. |
| + // |at_row_start| is set if the text_piece would be the first text piece in |
| + // the row. Links are added additional padding if they are not at the row |
| + // start. |
| + views::Label* CreateTextPieceView(TextPieceType type, |
| + const string16& label, |
| + bool at_row_start); |
| + |
| + string16 service_origin_; |
| + // Listener invoked when a label of type link is clicked. |
| + views::LinkListener* link_listener_; |
| + // Dialog content divided into pieces with different display stype. |
| + std::vector<TextPieceInfo> text_pieces_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(EchoDialogContentView); |
| +}; |
| + |
| +EchoDialogContentView::EchoDialogContentView(views::LinkListener* link_listener) |
| + : link_listener_(link_listener) { |
| + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0 ,0)); |
| +} |
| + |
| +void EchoDialogContentView::InitializeForEnabledEcho( |
| + const string16& service_name, |
| + const string16& origin) { |
| + service_origin_ = origin; |
| + |
| + size_t service_name_offset = 0; |
| + string16 text = l10n_util::GetStringFUTF16(IDS_ECHO_CONSENT_DIALOG_TEXT, |
| + service_name, |
| + &service_name_offset); |
| + |
| + text_pieces_.push_back( |
| + TextPieceInfo(text.substr(0, service_name_offset), TEXT_PIECE_LABEL)); |
| + text_pieces_.push_back( |
| + TextPieceInfo(service_name, TEXT_PIECE_SERVICE_NAME_LABEL)); |
| + text_pieces_.push_back( |
| + TextPieceInfo(text.substr(service_name_offset + service_name.length()), |
| + TEXT_PIECE_LABEL)); |
| + text_pieces_.push_back(TextPieceInfo( |
| + l10n_util::GetStringUTF16(IDS_OFFERS_CONSENT_INFOBAR_LABEL_LEARN_MORE), |
| + TEXT_PIECE_LINK)); |
| +} |
| + |
| +void EchoDialogContentView::InitializeForDisabledEcho() { |
| + text_pieces_.push_back(TextPieceInfo( |
| + l10n_util::GetStringUTF16(IDS_ECHO_DISABLED_CONSENT_DIALOG_TEXT), |
| + TEXT_PIECE_LABEL)); |
| + text_pieces_.push_back(TextPieceInfo( |
| + l10n_util::GetStringUTF16(IDS_OFFERS_CONSENT_INFOBAR_LABEL_LEARN_MORE), |
| + TEXT_PIECE_LINK)); |
| +} |
| + |
| +void EchoDialogContentView::SetupLayout() { |
| + EchoDialogContentRowView* current_row = new EchoDialogContentRowView(); |
| + AddChildView(current_row); |
| + for (size_t i= 0; i < text_pieces_.size(); ++i) |
| + SetupTextPieceLayout(text_pieces_[i], ¤t_row); |
| + |
| + set_border(views::Border::CreateEmptyBorder(kDialogContentTopInset, |
| + kDialogContentLeftInset, |
| + kDialogContentBottomInset, |
| + kDialogContentRightInset)); |
| +} |
| + |
| +void EchoDialogContentView::SetupTextPieceLayout( |
| + const TextPieceInfo& info, |
| + EchoDialogContentRowView** current_row) { |
| + if (info.label.empty()) |
| + return; |
| + |
| + gfx::Size current_size = (*current_row)->GetPreferredSize(); |
| + |
| + scoped_ptr<views::Label> text_piece( |
| + CreateTextPieceView(info.type, info.label, current_size.width() == 0)); |
| + gfx::Size text_piece_size = text_piece->GetPreferredSize(); |
| + |
| + // If the while label can fit in the free space in the current row, just add |
| + // it and return. |
| + if (text_piece_size.width() + current_size.width() < kDialogContentWidth) { |
| + (*current_row)->AddChildView(text_piece.release()); |
| + return; |
| + } |
| + |
| + string16 residue = info.label; |
| + gfx::Font text_piece_font = text_piece->font(); |
| + std::vector<string16> lines; |
| + |
| + // Fill up the free space in the current row. |IGNORE_LONG_WORDS| is used to |
| + // ensure words don't get broken in pieces. This step can be skipped if the |
| + // current row is empty. |
| + if (current_size.width() > 0) { |
| + ui::ElideRectangleText(info.label, text_piece_font, |
| + kDialogContentWidth - current_size.width(), text_piece_size.height(), |
| + ui::IGNORE_LONG_WORDS, &lines); |
| + if (!lines[0].empty()) { |
| + text_piece->SetText(lines[0]); |
| + (*current_row)->AddChildView(text_piece.release()); |
| + |
| + // Compute the part of the text piece that still has to be added to the |
| + // view layout. |
| + residue = info.label.substr(lines[0].length()); |
| + TrimWhitespace(residue, TRIM_LEADING, &residue); |
| + } |
| + } |
| + |
| + // Brake up the rest of the text piece into lines shorter than |
| + // |kEchoPromtWidth|, so they can fit in a single row. Use INT_MAX so the |
| + // number of lines is not limited. |
| + ui::ElideRectangleText(residue, text_piece_font, kDialogContentWidth, INT_MAX, |
| + ui::WRAP_LONG_WORDS, &lines); |
| + |
| + // Add lines one by one to the layout. |
| + for (size_t i = 0; i < lines.size(); ++i) { |
| + if ((*current_row)->GetPreferredSize().width() > 0) { |
| + *current_row = new EchoDialogContentRowView(); |
| + AddChildView(*current_row); |
| + } |
| + (*current_row)->AddChildView(CreateTextPieceView(info.type, lines[i], |
| + true)); |
| + } |
| +} |
| + |
| +views::Label* EchoDialogContentView::CreateTextPieceView(TextPieceType type, |
| + const string16& text, |
| + bool at_row_start) { |
| + switch (type) { |
| + case TEXT_PIECE_LABEL: |
| + { |
| + views::Label* label = new views::Label(text); |
| + label->SetMultiLine(false); |
| + label->SetFont(GetDefaultFontForEcho()); |
| + return label; |
| + } |
| + case TEXT_PIECE_SERVICE_NAME_LABEL: |
| + return new EchoServiceNameLabel(text, service_origin_); |
| + case TEXT_PIECE_LINK: |
| + { |
| + views::Link* link = new views::Link(text); |
| + link->set_listener(link_listener_); |
| + link->SetUnderline(false); |
| + link->SetFont(GetDefaultFontForEcho()); |
| + if (!at_row_start) { |
| + link->set_border( |
| + views::Border::CreateEmptyBorder(0, kLinkLeftInset, 0, 0)); |
| + } |
| + return link; |
| + } |
| + default: |
| + NOTREACHED(); |
| + return NULL; |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +EchoDialogView::EchoDialogView(EchoDialogListener* listener) |
| + : listener_(listener), |
| + ok_button_label_id_(0), |
| + cancel_button_label_id_(0) { |
| + SetLayoutManager( |
| + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0 ,0)); |
| +} |
| + |
| +EchoDialogView::~EchoDialogView() {} |
| + |
| +void EchoDialogView::InitForEnabledEcho(const string16& service_name, |
| + const string16& origin) { |
| + ok_button_label_id_ = IDS_OFFERS_CONSENT_INFOBAR_ENABLE_BUTTON; |
| + cancel_button_label_id_ = IDS_OFFERS_CONSENT_INFOBAR_DISABLE_BUTTON; |
| + |
| + EchoDialogContentView* dialog_content = new EchoDialogContentView(this); |
| + dialog_content->InitializeForEnabledEcho(service_name, origin); |
| + dialog_content->SetupLayout(); |
| + |
| + AddChildView(dialog_content); |
| +} |
| + |
| +void EchoDialogView::InitForDisabledEcho() { |
| + ok_button_label_id_ = 0; |
| + cancel_button_label_id_ = IDS_ECHO_CONSENT_DISMISS_BUTTON; |
| + |
| + EchoDialogContentView* dialog_content = new EchoDialogContentView(this); |
| + dialog_content->InitializeForDisabledEcho(); |
| + dialog_content->SetupLayout(); |
| + |
| + AddChildView(dialog_content); |
| +} |
| + |
| +void EchoDialogView::Show(gfx::NativeWindow parent) { |
| + DCHECK(cancel_button_label_id_); |
| + |
| + views::DialogDelegateView::CreateDialogWidget(this, parent, parent); |
| + set_border(views::Border::CreateEmptyBorder(0, 0, 10, 0)); |
| + GetWidget()->Show(); |
| +} |
| + |
| +int EchoDialogView::GetDefaultDialogButton() const { |
| + return ui::DIALOG_BUTTON_NONE; |
| +} |
| + |
| +int EchoDialogView::GetDialogButtons() const { |
| + int buttons = ui::DIALOG_BUTTON_NONE; |
| + if (ok_button_label_id_) |
| + buttons |= ui::DIALOG_BUTTON_OK; |
| + if (cancel_button_label_id_) |
| + buttons |= ui::DIALOG_BUTTON_CANCEL; |
| + return buttons; |
| +} |
| + |
| +bool EchoDialogView::Accept() { |
| + if (listener_) { |
| + listener_->OnAccept(); |
| + listener_ = NULL; |
| + } |
| + return true; |
| +} |
| + |
| +bool EchoDialogView::Cancel() { |
| + if (listener_) { |
| + listener_->OnCancel(); |
| + listener_ = NULL; |
| + } |
| + return true; |
| +} |
| + |
| +string16 EchoDialogView::GetDialogButtonLabel(ui::DialogButton button) const { |
| + if (button == ui::DIALOG_BUTTON_OK && ok_button_label_id_) |
| + return l10n_util::GetStringUTF16(ok_button_label_id_); |
| + if (button == ui::DIALOG_BUTTON_CANCEL && cancel_button_label_id_) |
| + return l10n_util::GetStringUTF16(cancel_button_label_id_); |
| + return string16(); |
| +} |
| + |
| +ui::ModalType EchoDialogView::GetModalType() const { |
| + return ui::MODAL_TYPE_WINDOW; |
| +} |
| + |
| +bool EchoDialogView::ShouldShowWindowTitle() const { |
| + return false; |
| +} |
| + |
| +bool EchoDialogView::ShouldShowWindowIcon() const { |
| + return false; |
| +} |
| + |
| +void EchoDialogView::LinkClicked(views::Link* source, int event_flags) { |
| + if (!listener_) |
| + return; |
| + listener_->OnMoreInfoLinkClicked(); |
| +} |
| + |
| +EchoDialog* EchoDialog::Create(EchoDialogListener* listener) { |
| + return new EchoDialogView(listener); |
| +} |