 Chromium Code Reviews
 Chromium Code Reviews Issue 12317109:
  Add a dialog for getting user consent in the echo redeem flow.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 12317109:
  Add a dialog for getting user consent in the echo redeem flow.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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); | 
| +} |