Sort unlaunched apps on app list start page by apps grid order.
[chromium-blink-merge.git] / ui / views / controls / message_box_view.cc
blob1993f6d1d56b131b919a32851403f0446a944600
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
3 // found in the LICENSE file.
5 #include "ui/views/controls/message_box_view.h"
7 #include "base/i18n/rtl.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "ui/accessibility/ax_view_state.h"
12 #include "ui/base/clipboard/clipboard.h"
13 #include "ui/base/clipboard/scoped_clipboard_writer.h"
14 #include "ui/views/controls/button/checkbox.h"
15 #include "ui/views/controls/label.h"
16 #include "ui/views/controls/link.h"
17 #include "ui/views/controls/scroll_view.h"
18 #include "ui/views/controls/textfield/textfield.h"
19 #include "ui/views/layout/box_layout.h"
20 #include "ui/views/layout/grid_layout.h"
21 #include "ui/views/layout/layout_constants.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/window/client_view.h"
24 #include "ui/views/window/dialog_delegate.h"
26 namespace {
28 const int kDefaultMessageWidth = 320;
30 // Paragraph separators are defined in
31 // http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBidiClass.txt
33 // # Bidi_Class=Paragraph_Separator
35 // 000A ; B # Cc <control-000A>
36 // 000D ; B # Cc <control-000D>
37 // 001C..001E ; B # Cc [3] <control-001C>..<control-001E>
38 // 0085 ; B # Cc <control-0085>
39 // 2029 ; B # Zp PARAGRAPH SEPARATOR
40 bool IsParagraphSeparator(base::char16 c) {
41 return ( c == 0x000A || c == 0x000D || c == 0x001C || c == 0x001D ||
42 c == 0x001E || c == 0x0085 || c == 0x2029);
45 // Splits |text| into a vector of paragraphs.
46 // Given an example "\nabc\ndef\n\n\nhij\n", the split results should be:
47 // "", "abc", "def", "", "", "hij", and "".
48 void SplitStringIntoParagraphs(const base::string16& text,
49 std::vector<base::string16>* paragraphs) {
50 paragraphs->clear();
52 size_t start = 0;
53 for (size_t i = 0; i < text.length(); ++i) {
54 if (IsParagraphSeparator(text[i])) {
55 paragraphs->push_back(text.substr(start, i - start));
56 start = i + 1;
59 paragraphs->push_back(text.substr(start, text.length() - start));
62 } // namespace
64 namespace views {
66 ///////////////////////////////////////////////////////////////////////////////
67 // MessageBoxView, public:
69 // static
70 const char MessageBoxView::kViewClassName[] = "MessageBoxView";
72 MessageBoxView::InitParams::InitParams(const base::string16& message)
73 : options(NO_OPTIONS),
74 message(message),
75 message_width(kDefaultMessageWidth),
76 inter_row_vertical_spacing(kRelatedControlVerticalSpacing) {}
78 MessageBoxView::InitParams::~InitParams() {
81 MessageBoxView::MessageBoxView(const InitParams& params)
82 : prompt_field_(NULL),
83 checkbox_(NULL),
84 link_(NULL),
85 message_width_(params.message_width) {
86 Init(params);
89 MessageBoxView::~MessageBoxView() {}
91 base::string16 MessageBoxView::GetInputText() {
92 return prompt_field_ ? prompt_field_->text() : base::string16();
95 bool MessageBoxView::IsCheckBoxSelected() {
96 return checkbox_ ? checkbox_->checked() : false;
99 void MessageBoxView::SetCheckBoxLabel(const base::string16& label) {
100 if (!checkbox_)
101 checkbox_ = new Checkbox(label);
102 else
103 checkbox_->SetText(label);
104 ResetLayoutManager();
107 void MessageBoxView::SetCheckBoxSelected(bool selected) {
108 if (!checkbox_)
109 return;
110 checkbox_->SetChecked(selected);
113 void MessageBoxView::SetLink(const base::string16& text,
114 LinkListener* listener) {
115 if (text.empty()) {
116 DCHECK(!listener);
117 delete link_;
118 link_ = NULL;
119 } else {
120 DCHECK(listener);
121 if (!link_) {
122 link_ = new Link();
123 link_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
125 link_->SetText(text);
126 link_->set_listener(listener);
128 ResetLayoutManager();
131 void MessageBoxView::GetAccessibleState(ui::AXViewState* state) {
132 state->role = ui::AX_ROLE_ALERT;
135 ///////////////////////////////////////////////////////////////////////////////
136 // MessageBoxView, View overrides:
138 void MessageBoxView::ViewHierarchyChanged(
139 const ViewHierarchyChangedDetails& details) {
140 if (details.child == this && details.is_add) {
141 if (prompt_field_)
142 prompt_field_->SelectAll(true);
144 NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
148 bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
149 // We only accepts Ctrl-C.
150 DCHECK(accelerator.key_code() == 'C' && accelerator.IsCtrlDown());
152 // We must not intercept Ctrl-C when we have a text box and it's focused.
153 if (prompt_field_ && prompt_field_->HasFocus())
154 return false;
156 ui::ScopedClipboardWriter scw(ui::CLIPBOARD_TYPE_COPY_PASTE);
157 base::string16 text = message_labels_[0]->text();
158 for (size_t i = 1; i < message_labels_.size(); ++i)
159 text += message_labels_[i]->text();
160 scw.WriteText(text);
161 return true;
164 const char* MessageBoxView::GetClassName() const {
165 return kViewClassName;
168 ///////////////////////////////////////////////////////////////////////////////
169 // MessageBoxView, private:
171 void MessageBoxView::Init(const InitParams& params) {
172 if (params.options & DETECT_DIRECTIONALITY) {
173 std::vector<base::string16> texts;
174 SplitStringIntoParagraphs(params.message, &texts);
175 for (size_t i = 0; i < texts.size(); ++i) {
176 Label* message_label = new Label(texts[i]);
177 // Avoid empty multi-line labels, which have a height of 0.
178 message_label->SetMultiLine(!texts[i].empty());
179 message_label->SetAllowCharacterBreak(true);
180 message_label->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
181 message_labels_.push_back(message_label);
183 } else {
184 Label* message_label = new Label(params.message);
185 message_label->SetMultiLine(true);
186 message_label->SetAllowCharacterBreak(true);
187 message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
188 message_labels_.push_back(message_label);
191 if (params.options & HAS_PROMPT_FIELD) {
192 prompt_field_ = new Textfield;
193 prompt_field_->SetText(params.default_prompt);
196 inter_row_vertical_spacing_ = params.inter_row_vertical_spacing;
198 ResetLayoutManager();
201 void MessageBoxView::ResetLayoutManager() {
202 // Initialize the Grid Layout Manager used for this dialog box.
203 GridLayout* layout = GridLayout::CreatePanel(this);
204 SetLayoutManager(layout);
206 // Add the column set for the message displayed at the top of the dialog box.
207 const int message_column_view_set_id = 0;
208 ColumnSet* column_set = layout->AddColumnSet(message_column_view_set_id);
209 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
210 GridLayout::FIXED, message_width_, 0);
212 // Column set for extra elements, if any.
213 const int extra_column_view_set_id = 1;
214 if (prompt_field_ || checkbox_ || link_) {
215 column_set = layout->AddColumnSet(extra_column_view_set_id);
216 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
217 GridLayout::USE_PREF, 0, 0);
220 const int kMaxScrollViewHeight = 600;
221 views::View* message_contents = new views::View();
222 message_contents->SetLayoutManager(
223 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
224 for (size_t i = 0; i < message_labels_.size(); ++i)
225 message_contents->AddChildView(message_labels_[i]);
226 ScrollView* scroll_view = new views::ScrollView();
227 scroll_view->ClipHeightTo(0, kMaxScrollViewHeight);
228 scroll_view->SetContents(message_contents);
229 layout->StartRow(0, message_column_view_set_id);
230 layout->AddView(scroll_view);
232 if (prompt_field_) {
233 layout->AddPaddingRow(0, inter_row_vertical_spacing_);
234 layout->StartRow(0, extra_column_view_set_id);
235 layout->AddView(prompt_field_);
238 if (checkbox_) {
239 layout->AddPaddingRow(0, inter_row_vertical_spacing_);
240 layout->StartRow(0, extra_column_view_set_id);
241 layout->AddView(checkbox_);
244 if (link_) {
245 layout->AddPaddingRow(0, inter_row_vertical_spacing_);
246 layout->StartRow(0, extra_column_view_set_id);
247 layout->AddView(link_);
251 } // namespace views