Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: chrome/browser/ui/views/web_intent_picker_views.cc

Issue 11044020: Make Web Intents picker in Views conform to latest mocks (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Address comments Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <algorithm>
6 #include <vector> 6 #include <vector>
7 7
8 #include "base/memory/scoped_vector.h" 8 #include "base/memory/scoped_vector.h"
9 #include "base/time.h" 9 #include "base/time.h"
10 #include "base/timer.h"
10 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/download/download_util.h"
11 #include "chrome/browser/tab_contents/tab_util.h" 13 #include "chrome/browser/tab_contents/tab_util.h"
12 #include "chrome/browser/ui/browser_finder.h" 14 #include "chrome/browser/ui/browser_finder.h"
13 #include "chrome/browser/ui/browser_navigator.h" 15 #include "chrome/browser/ui/browser_navigator.h"
16 #include "chrome/browser/ui/constrained_window_constants.h"
14 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" 17 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h"
15 #include "chrome/browser/ui/intents/web_intent_picker.h" 18 #include "chrome/browser/ui/intents/web_intent_picker.h"
16 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" 19 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
17 #include "chrome/browser/ui/intents/web_intent_picker_model.h" 20 #include "chrome/browser/ui/intents/web_intent_picker_model.h"
18 #include "chrome/browser/ui/intents/web_intent_picker_model_observer.h" 21 #include "chrome/browser/ui/intents/web_intent_picker_model_observer.h"
19 #include "chrome/browser/ui/tab_contents/tab_contents.h" 22 #include "chrome/browser/ui/tab_contents/tab_contents.h"
20 #include "chrome/browser/ui/views/constrained_window_views.h" 23 #include "chrome/browser/ui/views/constrained_window_views.h"
21 #include "chrome/browser/ui/views/frame/browser_view.h" 24 #include "chrome/browser/ui/views/frame/browser_view.h"
22 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" 25 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
23 #include "chrome/browser/ui/views/toolbar_view.h" 26 #include "chrome/browser/ui/views/toolbar_view.h"
(...skipping 15 matching lines...) Expand all
39 #include "ui/gfx/canvas.h" 42 #include "ui/gfx/canvas.h"
40 #include "ui/gfx/image/image.h" 43 #include "ui/gfx/image/image.h"
41 #include "ui/gfx/image/image_skia_operations.h" 44 #include "ui/gfx/image/image_skia_operations.h"
42 #include "ui/views/border.h" 45 #include "ui/views/border.h"
43 #include "ui/views/controls/button/image_button.h" 46 #include "ui/views/controls/button/image_button.h"
44 #include "ui/views/controls/button/text_button.h" 47 #include "ui/views/controls/button/text_button.h"
45 #include "ui/views/controls/image_view.h" 48 #include "ui/views/controls/image_view.h"
46 #include "ui/views/controls/label.h" 49 #include "ui/views/controls/label.h"
47 #include "ui/views/controls/link.h" 50 #include "ui/views/controls/link.h"
48 #include "ui/views/controls/link_listener.h" 51 #include "ui/views/controls/link_listener.h"
52 #include "ui/views/controls/separator.h"
49 #include "ui/views/controls/throbber.h" 53 #include "ui/views/controls/throbber.h"
50 #include "ui/views/controls/webview/webview.h" 54 #include "ui/views/controls/webview/webview.h"
51 #include "ui/views/layout/box_layout.h" 55 #include "ui/views/layout/box_layout.h"
52 #include "ui/views/layout/fill_layout.h" 56 #include "ui/views/layout/fill_layout.h"
53 #include "ui/views/layout/grid_layout.h" 57 #include "ui/views/layout/grid_layout.h"
54 #include "ui/views/layout/layout_constants.h" 58 #include "ui/views/layout/layout_constants.h"
55 #include "ui/views/view.h" 59 #include "ui/views/view.h"
56 #include "ui/views/widget/widget.h" 60 #include "ui/views/widget/widget.h"
57 #include "ui/views/window/dialog_delegate.h" 61 #include "ui/views/window/dialog_delegate.h"
58 #include "ui/views/window/non_client_view.h" 62 #include "ui/views/window/non_client_view.h"
59 63
60 using content::WebContents; 64 using content::WebContents;
61 using views::GridLayout; 65 using views::GridLayout;
62 66
63 namespace { 67 namespace {
64 68
65 // The color used to dim disabled elements. 69 // The color used to dim disabled elements.
66 const SkColor kHalfOpacityWhite = SkColorSetARGB(128, 255, 255, 255); 70 const SkColor kHalfOpacityWhite = SkColorSetARGB(128, 255, 255, 255);
67 71
72 // The color used to display an enabled label.
73 const SkColor kEnabledLabelColor = SkColorSetRGB(51, 51, 51);
74
75 // The color used to display an enabled link.
76 const SkColor kEnabledLinkColor = SkColorSetRGB(17, 85, 204);
77
68 // The color used to display a disabled link. 78 // The color used to display a disabled link.
69 const SkColor kDisabledLinkColor = SkColorSetRGB(128, 128, 128); 79 const SkColor kDisabledLinkColor = SkColorSetRGB(128, 128, 128);
70 80
71 // The time between successive throbber frames in milliseconds. 81 // The time between successive throbber frames in milliseconds.
72 const int kThrobberFrameTimeMs = 50; 82 const int kThrobberFrameTimeMs = 50;
73 83
74 // Width of IntentView action button in pixels 84 // Width of IntentView action button in pixels
75 const int kButtonWidth = 130; 85 const int kButtonWidth = 130;
76 86
77 // Minimum number of action buttons - fill up with suggestions as needed. 87 // Minimum number of action buttons - fill up with suggestions as needed.
78 const int kMinRowCount = 4; 88 const int kMinRowCount = 4;
79 89
80 // Maximum number of action buttons - do not add suggestions to reach. 90 // Maximum number of action buttons - do not add suggestions to reach.
81 const int kMaxRowCount = 8; 91 const int kMaxRowCount = 8;
82 92
93 // The vertical padding around the UI elements in the waiting view.
94 const int kWaitingViewVerticalPadding = 40;
95
83 // Enables or disables all child views of |view|. 96 // Enables or disables all child views of |view|.
84 void EnableChildViews(views::View* view, bool enabled) { 97 void EnableChildViews(views::View* view, bool enabled) {
85 for (int i = 0; i < view->child_count(); ++i) { 98 for (int i = 0; i < view->child_count(); ++i) {
86 views::View* child = view->child_at(i); 99 views::View* child = view->child_at(i);
87 child->SetEnabled(enabled); 100 child->SetEnabled(enabled);
88 } 101 }
89 } 102 }
90 103
91 // Create a "close" button. 104 // Create a "close" button.
92 views::ImageButton* CreateCloseButton(views::ButtonListener* listener) { 105 views::ImageButton* CreateCloseButton(views::ButtonListener* listener) {
93 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 106 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
94 views::ImageButton* close_button = new views::ImageButton(listener); 107 views::ImageButton* close_button = new views::ImageButton(listener);
95 close_button->SetImage(views::CustomButton::BS_NORMAL, 108 close_button->SetImage(views::CustomButton::BS_NORMAL,
96 rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X)); 109 rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X));
97 close_button->SetImage(views::CustomButton::BS_HOT, 110 close_button->SetImage(views::CustomButton::BS_HOT,
98 rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER)); 111 rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER));
99 close_button->SetImage(views::CustomButton::BS_PUSHED, 112 close_button->SetImage(views::CustomButton::BS_PUSHED,
100 rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER)); 113 rb.GetImageSkiaNamed(IDR_SHARED_IMAGES_X_HOVER));
101 return close_button; 114 return close_button;
102 } 115 }
103 // SarsView ------------------------------------------------------------------- 116
117 // Creates a label.
118 views::Label* CreateLabel() {
119 views::Label* label = new views::Label();
120 label->SetEnabledColor(kEnabledLabelColor);
121 label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
122 return label;
123 }
124
125 // Creates a title-style label.
126 views::Label* CreateTitleLabel() {
127 views::Label* label = CreateLabel();
128 label->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
129 ui::ResourceBundle::MediumFont));
130 const int kLabelBuiltinTopPadding = 5;
131 label->set_border(views::Border::CreateEmptyBorder(
132 WebIntentPicker::kContentAreaBorder -
133 ConstrainedWindowConstants::kCloseButtonPadding -
134 kLabelBuiltinTopPadding,
135 0, 0, 0));
136 return label;
137 }
138
139 // Creates a link.
140 views::Link* CreateLink() {
141 views::Link* link = new views::Link();
142 link->SetEnabledColor(kEnabledLinkColor);
143 link->SetDisabledColor(kDisabledLinkColor);
144 link->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
145 return link;
146 }
147
148 // Creates a header for the inline disposition dialog.
149 views::View* CreateInlineDispositionHeader(
150 views::ImageView* app_icon,
151 views::Label* app_title,
152 views::Link* use_another_service_link) {
153 views::View* header = new views::View();
154 views::GridLayout* grid_layout = new views::GridLayout(header);
155 const int kIconBuiltinTopPadding = 6;
156 grid_layout->SetInsets(
157 WebIntentPicker::kContentAreaBorder -
158 ConstrainedWindowConstants::kCloseButtonPadding -
159 kIconBuiltinTopPadding,
160 0, 0, 0);
161 header->SetLayoutManager(grid_layout);
162 views::ColumnSet* header_cs = grid_layout->AddColumnSet(0);
163 header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
164 GridLayout::USE_PREF, 0, 0); // App icon.
165 header_cs->AddPaddingColumn(0, WebIntentPicker::kIconTextPadding);
166 header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
167 GridLayout::USE_PREF, 0, 0); // App title.
168 header_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing);
169 header_cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
170 GridLayout::USE_PREF, 0, 0); // Use another app link.
171 grid_layout->StartRow(0, 0);
172 grid_layout->AddView(app_icon);
173 grid_layout->AddView(app_title);
174 grid_layout->AddView(use_another_service_link);
175 header->Layout();
176 return header;
177 }
178
179 // Checks whether the inline disposition dialog should show the link for using
180 // another service.
181 bool IsUseAnotherServiceVisible(WebIntentPickerModel* model) {
182 DCHECK(model);
183 return model->show_use_another_service() &&
184 (model->GetInstalledServiceCount() > 1 ||
185 model->GetSuggestedExtensionCount());
186 }
187
188
189 // StarsView -------------------------------------------------------------------
104 190
105 // A view that displays 5 stars: empty, full or half full, given a rating in 191 // A view that displays 5 stars: empty, full or half full, given a rating in
106 // the range [0,5]. 192 // the range [0,5].
107 class StarsView : public views::View { 193 class StarsView : public views::View {
108 public: 194 public:
109 explicit StarsView(double rating); 195 explicit StarsView(double rating);
110 virtual ~StarsView(); 196 virtual ~StarsView();
111 197
112 private: 198 private:
113 // The star rating to display, in the range [0,5]. 199 // The star rating to display, in the range [0,5].
(...skipping 20 matching lines...) Expand all
134 // TODO(binji): Add tooltip with text rating 220 // TODO(binji): Add tooltip with text rating
135 // "Average Rating: X.XX stars (YYYYY)" 221 // "Average Rating: X.XX stars (YYYYY)"
136 // Y = "1: Hated it, 2: Disliked it, 3: It was okay, 4: Liked it, 222 // Y = "1: Hated it, 2: Disliked it, 3: It was okay, 4: Liked it,
137 // 5: Loved it" 223 // 5: Loved it"
138 // Choose Y based on rounded X. 224 // Choose Y based on rounded X.
139 } 225 }
140 226
141 StarsView::~StarsView() { 227 StarsView::~StarsView() {
142 } 228 }
143 229
230
144 // ThrobberNativeTextButton ---------------------------------------------------- 231 // ThrobberNativeTextButton ----------------------------------------------------
145 232
146 // A native text button that can display a throbber in place of its icon. Much 233 // A native text button that can display a throbber in place of its icon. Much
147 // of the logic of this class is copied from ui/views/controls/throbber.h. 234 // of the logic of this class is copied from ui/views/controls/throbber.h.
148 class ThrobberNativeTextButton : public views::NativeTextButton { 235 class ThrobberNativeTextButton : public views::NativeTextButton {
149 public: 236 public:
150 ThrobberNativeTextButton(views::ButtonListener* listener, 237 ThrobberNativeTextButton(views::ButtonListener* listener,
151 const string16& text); 238 const string16& text);
152 virtual ~ThrobberNativeTextButton(); 239 virtual ~ThrobberNativeTextButton();
153 240
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 this_frame_ = gfx::ImageSkiaOperations::ExtractSubset(*frames_, subset_rect); 348 this_frame_ = gfx::ImageSkiaOperations::ExtractSubset(*frames_, subset_rect);
262 return this_frame_; 349 return this_frame_;
263 } 350 }
264 351
265 void ThrobberNativeTextButton::Run() { 352 void ThrobberNativeTextButton::Run() {
266 DCHECK(running_); 353 DCHECK(running_);
267 354
268 SchedulePaint(); 355 SchedulePaint();
269 } 356 }
270 357
358
359 // SpinnerProgressIndicator ----------------------------------------------------
360 class SpinnerProgressIndicator : public views::View {
361 public:
362 SpinnerProgressIndicator();
363 virtual ~SpinnerProgressIndicator();
364
365 void SetPercentDone(int percent);
366 void SetIndeterminate(bool indetereminate);
367
368 // Overridden from views::View.
369 virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
370 virtual gfx::Size GetPreferredSize() OVERRIDE;
371
372 private:
373 void UpdateTimer();
374 int GetProgressAngle();
375
376 static const int kTimerIntervalMs = 1000 / 30;
377 static const int kSpinRateDegreesPerSecond = 270;
378
379 int percent_done_;
380 int indeterminate_;
381
382 base::TimeTicks start_time_;
383 base::RepeatingTimer<SpinnerProgressIndicator> timer_;
384
385 DISALLOW_COPY_AND_ASSIGN(SpinnerProgressIndicator);
386 };
387
388 SpinnerProgressIndicator::SpinnerProgressIndicator()
389 : percent_done_(0),
390 indeterminate_(true) {}
391
392 SpinnerProgressIndicator::~SpinnerProgressIndicator() {
393 }
394
395 void SpinnerProgressIndicator::SetPercentDone(int percent) {
396 percent_done_ = percent;
397 SchedulePaint();
398 UpdateTimer();
399 }
400
401 void SpinnerProgressIndicator::SetIndeterminate(bool indetereminate) {
402 indeterminate_ = indetereminate;
403 SchedulePaint();
404 UpdateTimer();
405 }
406
407 void SpinnerProgressIndicator::Paint(gfx::Canvas* canvas) {
408 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
409 gfx::ImageSkia* fg = rb.GetImageSkiaNamed(IDR_WEB_INTENT_PROGRESS_FOREGROUND);
410 gfx::ImageSkia* bg = rb.GetImageSkiaNamed(IDR_WEB_INTENT_PROGRESS_BACKGROUND);
411 download_util::PaintCustomDownloadProgress(
412 canvas,
413 *bg,
414 *fg,
415 fg->width(),
416 bounds(),
417 GetProgressAngle(),
418 indeterminate_ ? -1 : percent_done_);
419 }
420
421 gfx::Size SpinnerProgressIndicator::GetPreferredSize() {
422 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
423 gfx::ImageSkia* fg = rb.GetImageSkiaNamed(IDR_WEB_INTENT_PROGRESS_FOREGROUND);
424 return fg->size();
425 }
426
427 void SpinnerProgressIndicator::UpdateTimer() {
428 if (!parent() || !indeterminate_) {
429 timer_.Stop();
430 return;
431 }
432
433 if (!timer_.IsRunning()) {
434 start_time_ = base::TimeTicks::Now();
435 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimerIntervalMs),
436 this, &SpinnerProgressIndicator::SchedulePaint);
437 }
438 }
439
440 int SpinnerProgressIndicator::GetProgressAngle() {
441 if (!indeterminate_)
442 return download_util::kStartAngleDegrees;
443 base::TimeDelta delta = base::TimeTicks::Now() - start_time_;
444 int angle = delta.InSecondsF() * kSpinRateDegreesPerSecond;
445 return angle % 360;
446 }
447
448
271 // WaitingView ---------------------------------------------------------- 449 // WaitingView ----------------------------------------------------------
272 class WaitingView : public views::View { 450 class WaitingView : public views::View {
273 public: 451 public:
274 WaitingView(views::ButtonListener* listener, bool use_close_button); 452 WaitingView(views::ButtonListener* listener, bool use_close_button);
453 virtual ~WaitingView();
275 454
276 private: 455 private:
277 DISALLOW_COPY_AND_ASSIGN(WaitingView); 456 DISALLOW_COPY_AND_ASSIGN(WaitingView);
278 }; 457 };
279 458
280 WaitingView::WaitingView(views::ButtonListener* listener, 459 WaitingView::WaitingView(views::ButtonListener* listener,
281 bool use_close_button) { 460 bool use_close_button) {
282 views::GridLayout* layout = new views::GridLayout(this); 461 views::GridLayout* layout = new views::GridLayout(this);
283 layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0)); 462 layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0));
284 layout->SetInsets(WebIntentPicker::kContentAreaBorder, 463 const int kMessageBuiltinBottomPadding = 3;
285 WebIntentPicker::kContentAreaBorder, 464 layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding,
286 WebIntentPicker::kContentAreaBorder, 465 0,
287 WebIntentPicker::kContentAreaBorder); 466 kWaitingViewVerticalPadding - kMessageBuiltinBottomPadding,
467 0);
288 SetLayoutManager(layout); 468 SetLayoutManager(layout);
289 469
290 views::ColumnSet* cs = layout->AddColumnSet(0); 470 enum GridLayoutColumnSets {
291 views::ColumnSet* header_cs = NULL; 471 HEADER_ROW,
292 if (use_close_button) { 472 CONTENT_ROW,
293 header_cs = layout->AddColumnSet(1); 473 };
294 header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); 474 views::ColumnSet* header_cs = layout->AddColumnSet(HEADER_ROW);
295 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 475 header_cs->AddPaddingColumn(1, 1);
296 GridLayout::USE_PREF, 0, 0); // Close Button. 476 header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0,
297 } 477 GridLayout::USE_PREF, 0, 0);
298 cs->AddPaddingColumn(0, views::kPanelHorizIndentation); 478 header_cs->AddPaddingColumn(
299 cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 479 0, ConstrainedWindowConstants::kCloseButtonPadding);
300 1, GridLayout::USE_PREF, 0, 0);
301 cs->AddPaddingColumn(0, views::kPanelHorizIndentation);
302 480
303 // Create throbber. 481 views::ColumnSet* content_cs = layout->AddColumnSet(CONTENT_ROW);
304 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 482 content_cs->AddPaddingColumn(0, views::kPanelHorizIndentation);
305 const gfx::ImageSkia* frames = 483 content_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 1,
306 rb.GetImageNamed(IDR_SPEECH_INPUT_SPINNER).ToImageSkia(); 484 GridLayout::USE_PREF, 0, 0);
307 views::Throbber* throbber = new views::Throbber(kThrobberFrameTimeMs, true); 485 content_cs->AddPaddingColumn(0, views::kPanelHorizIndentation);
308 throbber->SetFrames(frames);
309 throbber->Start();
310 486
311 // Create text. 487 // Close button
312 views::Label* label = new views::Label(); 488 layout->StartRow(0, HEADER_ROW);
489 views::ImageButton* close_button = CreateCloseButton(listener);
490 layout->AddView(close_button);
491 close_button->SetVisible(use_close_button);
492
493 // Throbber
494 layout->AddPaddingRow(0,
495 kWaitingViewVerticalPadding -
496 ConstrainedWindowConstants::kCloseButtonPadding -
497 close_button->GetPreferredSize().height());
498 layout->StartRow(0, CONTENT_ROW);
499 SpinnerProgressIndicator* throbber = new SpinnerProgressIndicator();
500 layout->AddView(throbber);
501
502 // Message
503 const int kMessageBuiltinTopPadding = 5;
504 layout->AddPaddingRow(0,
505 ConstrainedWindowConstants::kRowPadding -
506 kMessageBuiltinTopPadding);
507 layout->StartRow(0, CONTENT_ROW);
508 views::Label* label = CreateLabel();
313 label->SetHorizontalAlignment(views::Label::ALIGN_CENTER); 509 label->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
314 label->SetFont(rb.GetFont(ui::ResourceBundle::MediumBoldFont));
315 label->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_WAIT_FOR_CWS)); 510 label->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_WAIT_FOR_CWS));
511 layout->AddView(label);
316 512
317 // Layout the view. 513 // Start the throbber.
318 if (use_close_button) { 514 throbber->SetIndeterminate(true);
319 layout->StartRow(0, 1);
320 layout->AddView(CreateCloseButton(listener));
321 }
322
323 layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing);
324 layout->StartRow(0, 0);
325 layout->AddView(throbber);
326 layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing);
327 layout->StartRow(0, 0);
328 layout->AddView(label);
329 layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing);
330 } 515 }
331 516
332 // SuggestedExtensionsLayout --------------------------------------------------- 517 WaitingView::~WaitingView() {
333
334 // TODO(groby): Extremely fragile code, relies on order and number of fields.
335 // Would probably be better off as GridLayout or similar. Also see review
336 // comments on http://codereview.chromium.org/10909183
337
338 // A LayoutManager used by a row of the IntentsView. It is similar
339 // to a BoxLayout, but it right aligns the rightmost view (which is the install
340 // button). It also uses the maximum height of all views in the row as a
341 // preferred height so it doesn't change when the install button is hidden.
342 class SuggestedExtensionsLayout : public views::LayoutManager {
343 public:
344 SuggestedExtensionsLayout();
345 virtual ~SuggestedExtensionsLayout();
346
347 // Implementation of views::LayoutManager.
348 virtual void Layout(views::View* host) OVERRIDE;
349 virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE;
350
351 private:
352 DISALLOW_COPY_AND_ASSIGN(SuggestedExtensionsLayout);
353 };
354
355 SuggestedExtensionsLayout::SuggestedExtensionsLayout() {
356 } 518 }
357 519
358 SuggestedExtensionsLayout::~SuggestedExtensionsLayout() {
359 }
360
361 void SuggestedExtensionsLayout::Layout(views::View* host) {
362 gfx::Rect child_area(host->GetLocalBounds());
363 child_area.Inset(host->GetInsets());
364 int x = child_area.x();
365 int y = child_area.y();
366
367 for (int i = 0; i < host->child_count(); ++i) {
368 views::View* child = host->child_at(i);
369 if (!child->visible())
370 continue;
371 gfx::Size size(child->GetPreferredSize());
372 gfx::Rect child_bounds(x, y, size.width(), child_area.height());
373 if (i == host->child_count() - 1) {
374 // Last child (the install button) should be right aligned.
375 child_bounds.set_x(std::max(child_area.width() - size.width(), x));
376 } else if (i == 1) {
377 // Label is considered fixed width, to align ratings widget.
378 DCHECK_LE(size.width(), WebIntentPicker::kTitleLinkMaxWidth);
379 x += WebIntentPicker::kTitleLinkMaxWidth +
380 views::kRelatedControlHorizontalSpacing;
381 } else {
382 x += size.width() + views::kRelatedControlHorizontalSpacing;
383 }
384 // Clamp child view bounds to |child_area|.
385 child->SetBoundsRect(child_bounds.Intersect(child_area));
386 }
387 }
388
389 gfx::Size SuggestedExtensionsLayout::GetPreferredSize(views::View* host) {
390 int width = 0;
391 int height = 0;
392 for (int i = 0; i < host->child_count(); ++i) {
393 views::View* child = host->child_at(i);
394 gfx::Size size(child->GetPreferredSize());
395 // The preferred height includes visible and invisible children. This
396 // prevents jank when a child is hidden.
397 height = std::max(height, size.height());
398 if (!child->visible())
399 continue;
400 if (i != 0)
401 width += views::kRelatedControlHorizontalSpacing;
402 }
403 gfx::Insets insets(host->GetInsets());
404 return gfx::Size(width + insets.width(), height + insets.height());
405 }
406 520
407 // IntentRowView -------------------------------------------------- 521 // IntentRowView --------------------------------------------------
408 522
409 // A view for each row in the IntentsView. It displays information 523 // A view for each row in the IntentsView. It displays information
410 // for both installed and suggested intent handlers. 524 // for both installed and suggested intent handlers.
411 class IntentRowView : public views::View, 525 class IntentRowView : public views::View,
412 public views::ButtonListener, 526 public views::ButtonListener,
413 public views::LinkListener { 527 public views::LinkListener {
414 public: 528 public:
415 enum ActionType { 529 enum ActionType {
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 WebIntentPicker::kTitleLinkMaxWidth, 652 WebIntentPicker::kTitleLinkMaxWidth,
539 ui::ELIDE_AT_END); 653 ui::ELIDE_AT_END);
540 654
541 const gfx::ImageSkia* icon = NULL; 655 const gfx::ImageSkia* icon = NULL;
542 StarsView* stars = NULL; 656 StarsView* stars = NULL;
543 views::Label* label = NULL; 657 views::Label* label = NULL;
544 IntentRowView* view; 658 IntentRowView* view;
545 if (service != NULL) { 659 if (service != NULL) {
546 view = new IntentRowView(ACTION_INVOKE, tag); 660 view = new IntentRowView(ACTION_INVOKE, tag);
547 icon = service->favicon.ToImageSkia(); 661 icon = service->favicon.ToImageSkia();
548 label = new views::Label(elided_title); 662 label = CreateLabel();
663 label->SetText(elided_title);
549 } else { 664 } else {
550 view = new IntentRowView(ACTION_INSTALL, tag); 665 view = new IntentRowView(ACTION_INSTALL, tag);
551 view->extension_id_ = extension->id; 666 view->extension_id_ = extension->id;
552 icon = extension->icon.ToImageSkia(); 667 icon = extension->icon.ToImageSkia();
553 views::Link* link = new views::Link(elided_title); 668 views::Link* link = CreateLink();
669 link->SetText(elided_title);
554 link->set_listener(view); 670 link->set_listener(view);
555 label = link; 671 label = link;
556 stars = new StarsView(extension->average_rating); 672 stars = new StarsView(extension->average_rating);
557 } 673 }
558 674
559 view->delegate_ = delegate; 675 view->delegate_ = delegate;
560 676
561 view->SetLayoutManager(new SuggestedExtensionsLayout); 677 views::GridLayout* grid_layout = new views::GridLayout(view);
678 view->SetLayoutManager(grid_layout);
679
680 views::ColumnSet* columns = grid_layout->AddColumnSet(0);
681 columns->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
682 GridLayout::USE_PREF, 0, 0); // Icon.
683 columns->AddPaddingColumn(0, WebIntentPicker::kIconTextPadding);
684 columns->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
685 GridLayout::FIXED, WebIntentPicker::kTitleLinkMaxWidth, 0);
686 const int kStarRatingHorizontalSpacing = 20;
687 columns->AddPaddingColumn(0, kStarRatingHorizontalSpacing);
688 if (stars != NULL) {
689 columns->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
690 GridLayout::USE_PREF, 0, 0); // Star rating.
691 columns->AddPaddingColumn(0, kStarRatingHorizontalSpacing);
692 }
693 columns->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
694 GridLayout::FIXED, preferred_width, 0); // Button.
695
696 grid_layout->StartRow(0, 0);
562 697
563 view->icon_ = new views::ImageView(); 698 view->icon_ = new views::ImageView();
564
565 view->icon_->SetImage(icon); 699 view->icon_->SetImage(icon);
566 view->AddChildView(view->icon_); 700 grid_layout->AddView(view->icon_);
567 701
568 view->title_link_ = label; 702 view->title_link_ = label;
569 view->AddChildView(view->title_link_); 703 grid_layout->AddView(view->title_link_);
570 704
571 if (stars != NULL) { 705 if (stars != NULL) {
572 view->stars_ = stars; 706 view->stars_ = stars;
573 view->AddChildView(view->stars_); 707 grid_layout->AddView(view->stars_);
574 } 708 }
575 709
576 view->install_button_ = new ThrobberNativeTextButton( 710 view->install_button_ = new ThrobberNativeTextButton(
577 view, view->GetActionButtonMessage()); 711 view, view->GetActionButtonMessage());
578 view->install_button_->set_preferred_width(preferred_width); 712 view->install_button_->set_preferred_width(preferred_width);
579 view->AddChildView(view->install_button_); 713 grid_layout->AddView(view->install_button_);
580 714
581 return view; 715 return view;
582 } 716 }
583 717
584 IntentRowView::~IntentRowView() {} 718 IntentRowView::~IntentRowView() {}
585 719
586 void IntentRowView::ButtonPressed(views::Button* sender, 720 void IntentRowView::ButtonPressed(views::Button* sender,
587 const ui::Event& event) { 721 const ui::Event& event) {
588 if (type_ == ACTION_INSTALL) 722 if (type_ == ACTION_INSTALL)
589 delegate_->OnExtensionInstallClicked(extension_id_); 723 delegate_->OnExtensionInstallClicked(extension_id_);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 if (type_ == ACTION_INVOKE) 768 if (type_ == ACTION_INVOKE)
635 message_id = IDS_INTENT_PICKER_SELECT_INTENT; 769 message_id = IDS_INTENT_PICKER_SELECT_INTENT;
636 else if (type_ == ACTION_INSTALL) 770 else if (type_ == ACTION_INSTALL)
637 message_id = IDS_INTENT_PICKER_INSTALL_EXTENSION; 771 message_id = IDS_INTENT_PICKER_INSTALL_EXTENSION;
638 else 772 else
639 NOTREACHED(); 773 NOTREACHED();
640 774
641 return l10n_util::GetStringUTF16(message_id); 775 return l10n_util::GetStringUTF16(message_id);
642 } 776 }
643 777
778
644 // IntentsView ----------------------------------------------------- 779 // IntentsView -----------------------------------------------------
645 780
646 // A view that contains both installed services and suggested extensions 781 // A view that contains both installed services and suggested extensions
647 // from the Chrome Web Store that provide an intent service matching the 782 // from the Chrome Web Store that provide an intent service matching the
648 // action/type pair. 783 // action/type pair.
649 class IntentsView : public views::View { 784 class IntentsView : public views::View {
650 public: 785 public:
651 IntentsView(const WebIntentPickerModel* model, 786 IntentsView(const WebIntentPickerModel* model,
652 IntentRowView::Delegate* delegate); 787 IntentRowView::Delegate* delegate);
653 788
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 void IntentsView::Update() { 830 void IntentsView::Update() {
696 RemoveAllChildViews(true); 831 RemoveAllChildViews(true);
697 832
698 ThrobberNativeTextButton size_helper( 833 ThrobberNativeTextButton size_helper(
699 NULL, l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION)); 834 NULL, l10n_util::GetStringUTF16(IDS_INTENT_PICKER_INSTALL_EXTENSION));
700 size_helper.SetText( 835 size_helper.SetText(
701 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_SELECT_INTENT)); 836 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_SELECT_INTENT));
702 button_width_ = std::max( 837 button_width_ = std::max(
703 kButtonWidth, size_helper.GetPreferredSize().width()); 838 kButtonWidth, size_helper.GetPreferredSize().width());
704 839
705 views::BoxLayout* layout = new views::BoxLayout( 840 const int kAppRowVerticalSpacing = 10;
706 views::BoxLayout::kVertical, 0, 0, views::kRelatedControlVerticalSpacing); 841 views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kVertical,
842 0, 0, kAppRowVerticalSpacing);
707 SetLayoutManager(layout); 843 SetLayoutManager(layout);
708 844
709 int available_rows = kMaxRowCount; 845 int available_rows = kMaxRowCount;
710 846
711 for (size_t i = 0; 847 for (size_t i = 0;
712 available_rows > 0 && i < model_->GetInstalledServiceCount(); 848 available_rows > 0 && i < model_->GetInstalledServiceCount();
713 ++i, --available_rows) { 849 ++i, --available_rows) {
714 const WebIntentPickerModel::InstalledService& service = 850 const WebIntentPickerModel::InstalledService& service =
715 model_->GetInstalledServiceAt(i); 851 model_->GetInstalledServiceAt(i);
716 AddChildView(IntentRowView::CreateHandlerRow(&service, NULL, i, 852 AddChildView(IntentRowView::CreateHandlerRow(&service, NULL, i,
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 return old_width - kButtonWidth + button_width_; 884 return old_width - kButtonWidth + button_width_;
749 } 885 }
750 886
751 void IntentsView::OnEnabledChanged() { 887 void IntentsView::OnEnabledChanged() {
752 EnableChildViews(this, enabled()); 888 EnableChildViews(this, enabled());
753 View::OnEnabledChanged(); 889 View::OnEnabledChanged();
754 } 890 }
755 891
756 } // namespace 892 } // namespace
757 893
894
758 // WebIntentPickerViews -------------------------------------------------------- 895 // WebIntentPickerViews --------------------------------------------------------
759 896
760 // Views implementation of WebIntentPicker. 897 // Views implementation of WebIntentPicker.
761 class WebIntentPickerViews : public views::ButtonListener, 898 class WebIntentPickerViews : public views::ButtonListener,
762 public views::DialogDelegate, 899 public views::WidgetDelegate,
763 public views::LinkListener, 900 public views::LinkListener,
764 public WebIntentPicker, 901 public WebIntentPicker,
765 public WebIntentPickerModelObserver, 902 public WebIntentPickerModelObserver,
766 public IntentRowView::Delegate { 903 public IntentRowView::Delegate {
767 public: 904 public:
768 WebIntentPickerViews(TabContents* tab_contents, 905 WebIntentPickerViews(TabContents* tab_contents,
769 WebIntentPickerDelegate* delegate, 906 WebIntentPickerDelegate* delegate,
770 WebIntentPickerModel* model); 907 WebIntentPickerModel* model);
771 virtual ~WebIntentPickerViews(); 908 virtual ~WebIntentPickerViews();
772 909
773 // views::ButtonListener implementation. 910 // views::ButtonListener implementation.
774 // This method is called when the user cancels the picker dialog. 911 // This method is called when the user cancels the picker dialog.
775 virtual void ButtonPressed(views::Button* sender, 912 virtual void ButtonPressed(views::Button* sender,
776 const ui::Event& event) OVERRIDE; 913 const ui::Event& event) OVERRIDE;
777 914
778 // views::DialogDelegate implementation. 915 // views::WidgetDelegate implementation.
779 virtual void WindowClosing() OVERRIDE; 916 virtual void WindowClosing() OVERRIDE;
780 virtual void DeleteDelegate() OVERRIDE; 917 virtual void DeleteDelegate() OVERRIDE;
781 virtual views::Widget* GetWidget() OVERRIDE; 918 virtual views::Widget* GetWidget() OVERRIDE;
782 virtual const views::Widget* GetWidget() const OVERRIDE; 919 virtual const views::Widget* GetWidget() const OVERRIDE;
783 virtual views::View* GetContentsView() OVERRIDE; 920 virtual views::View* GetContentsView() OVERRIDE;
784 virtual int GetDialogButtons() const OVERRIDE;
785 virtual bool Cancel() OVERRIDE;
786 921
787 // LinkListener implementation. 922 // LinkListener implementation.
788 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; 923 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
789 924
790 // WebIntentPicker implementation. 925 // WebIntentPicker implementation.
791 virtual void Close() OVERRIDE; 926 virtual void Close() OVERRIDE;
792 virtual void SetActionString(const string16& action) OVERRIDE; 927 virtual void SetActionString(const string16& action) OVERRIDE;
793 virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE; 928 virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE;
794 virtual void OnExtensionInstallFailure(const std::string& id) OVERRIDE; 929 virtual void OnExtensionInstallFailure(const std::string& id) OVERRIDE;
795 virtual void OnInlineDispositionAutoResize(const gfx::Size& size) OVERRIDE; 930 virtual void OnInlineDispositionAutoResize(const gfx::Size& size) OVERRIDE;
(...skipping 14 matching lines...) Expand all
810 virtual void OnExtensionInstallClicked( 945 virtual void OnExtensionInstallClicked(
811 const std::string& extension_id) OVERRIDE; 946 const std::string& extension_id) OVERRIDE;
812 virtual void OnExtensionLinkClicked( 947 virtual void OnExtensionLinkClicked(
813 const std::string& extension_id, 948 const std::string& extension_id,
814 WindowOpenDisposition disposition) OVERRIDE; 949 WindowOpenDisposition disposition) OVERRIDE;
815 virtual void OnActionButtonClicked( 950 virtual void OnActionButtonClicked(
816 IntentRowView::ActionType type, 951 IntentRowView::ActionType type,
817 size_t tag) OVERRIDE; 952 size_t tag) OVERRIDE;
818 953
819 private: 954 private:
955 enum WebIntentPickerViewsState {
956 INITIAL,
957 WAITING,
958 NO_SERVICES,
959 LIST_SERVICES,
960 INLINE_SERVICE,
961 } state_;
962
820 // Update picker contents to reflect the current state of the model. 963 // Update picker contents to reflect the current state of the model.
821 void UpdateContents(); 964 void UpdateContents();
822 965
966 // Shows a spinner and notifies the user that we are waiting for information
967 // from the Chrome Web Store.
968 void ShowWaitingForSuggestions();
969
823 // Updates the dialog with the list of available services, suggestions, 970 // Updates the dialog with the list of available services, suggestions,
824 // and a nice link to CWS to find more suggestions. This is the "Main" 971 // and a nice link to CWS to find more suggestions. This is the "Main"
825 // view of the picker. 972 // view of the picker.
826 void ShowAvailableServices(); 973 void ShowAvailableServices();
827 974
828 // Informs the user that there are no services available to handle 975 // Informs the user that there are no services available to handle
829 // the intent, and that there are no suggestions from the Chrome Web Store. 976 // the intent, and that there are no suggestions from the Chrome Web Store.
830 void ShowNoServicesMessage(); 977 void ShowNoServicesMessage();
831 978
832 // Restore the contents of the picker to the initial contents. 979 // Restore the contents of the picker to the initial contents.
833 void ResetContents(); 980 void ResetContents();
834 981
835 // Resize the constrained window to the size of its contents. 982 // Resize the constrained window to the size of its contents.
836 void SizeToContents(); 983 void SizeToContents();
837 984
838 // Clear the contents of the picker. 985 // Clear the contents of the picker.
839 void ClearContents(); 986 void ClearContents();
840 987
841 // Returns the service selection question text used in the title 988 // Returns the service selection question text used in the title
842 // of the picker. 989 // of the picker.
843 const string16 GetActionTitle(); 990 const string16 GetActionTitle();
844 991
992 // Refresh the icon for the inline disposition service that is being
993 // displayed.
994 void RefreshInlineServiceIcon();
995
996 // Refresh the extensions control in the picker.
997 void RefreshExtensions();
998
845 // A weak pointer to the WebIntentPickerDelegate to notify when the user 999 // A weak pointer to the WebIntentPickerDelegate to notify when the user
846 // chooses a service or cancels. 1000 // chooses a service or cancels.
847 WebIntentPickerDelegate* delegate_; 1001 WebIntentPickerDelegate* delegate_;
848 1002
849 // A weak pointer to the picker model. 1003 // A weak pointer to the picker model.
850 WebIntentPickerModel* model_; 1004 WebIntentPickerModel* model_;
851 1005
852 // A weak pointer to the action string label. 1006 // A weak pointer to the action string label.
853 // Created locally, owned by Views. 1007 // Created locally, owned by Views.
854 views::Label* action_label_; 1008 views::Label* action_label_;
855 1009
856 // A weak pointer to the header label for the extension suggestions.
857 // Created locally, owned by Views.
858 views::Label* suggestions_label_;
859
860 // A weak pointer to the intents view. 1010 // A weak pointer to the intents view.
861 // Created locally, owned by Views view hierarchy. 1011 // Created locally, owned by Views view hierarchy.
862 IntentsView* extensions_; 1012 IntentsView* extensions_;
863 1013
864 // Delegate for inline disposition tab contents. 1014 // Delegate for inline disposition tab contents.
865 scoped_ptr<WebIntentInlineDispositionDelegate> inline_disposition_delegate_; 1015 scoped_ptr<WebIntentInlineDispositionDelegate> inline_disposition_delegate_;
866 1016
867 // A weak pointer to the TabContents this picker is in. 1017 // A weak pointer to the TabContents this picker is in.
868 TabContents* tab_contents_; 1018 TabContents* tab_contents_;
869 1019
870 // A weak pointer to the WebView that hosts the WebContents being displayed. 1020 // A weak pointer to the WebView that hosts the WebContents being displayed.
871 // Created locally, owned by Views. 1021 // Created locally, owned by Views.
872 views::WebView* webview_; 1022 views::WebView* webview_;
873 1023
874 // A weak pointer to the view that contains all other views in the picker. 1024 // A weak pointer to the view that contains all other views in the picker.
875 // Created locally, owned by Views. 1025 // Created locally, owned by Views.
876 views::View* contents_; 1026 views::View* contents_;
877 1027
878 // A weak pointer to the constrained window. 1028 // A weak pointer to the constrained window.
879 // Created locally, owned by Views. 1029 // Created locally, owned by Views.
880 ConstrainedWindowViews* window_; 1030 ConstrainedWindowViews* window_;
881 1031
882 // A weak pointer to the more suggestions link. 1032 // A weak pointer to the more suggestions link.
883 // Created locally, owned by Views. 1033 // Created locally, owned by Views.
884 views::Link* more_suggestions_link_; 1034 views::Link* more_suggestions_link_;
885 1035
1036 // The icon for the inline disposition service.
1037 views::ImageView* inline_service_icon_;
1038
886 // A weak pointer to the choose another service link. 1039 // A weak pointer to the choose another service link.
887 // Created locally, owned by Views. 1040 // Created locally, owned by Views.
888 views::Link* choose_another_service_link_; 1041 views::Link* choose_another_service_link_;
889 1042
890 // Weak pointer to "Waiting for CWS" display. Owned by parent view. 1043 // Weak pointer to "Waiting for CWS" display. Owned by parent view.
891 WaitingView* waiting_view_; 1044 WaitingView* waiting_view_;
892 1045
893 // Set to true when displaying the inline disposition web contents. Used to
894 // prevent laying out the inline disposition widgets twice.
895 bool displaying_web_contents_;
896
897 // The text for the current action. 1046 // The text for the current action.
898 string16 action_text_; 1047 string16 action_text_;
899 1048
900 // Ownership of the WebContents we are displaying in the inline disposition. 1049 // Ownership of the WebContents we are displaying in the inline disposition.
901 scoped_ptr<WebContents> inline_web_contents_; 1050 scoped_ptr<WebContents> inline_web_contents_;
902 1051
903 // Indicate if dialog should display its own close button. 1052 // Indicate if dialog should display its own close button.
904 // TODO(groby): Only relevant until new ConstrainedWindow is implemented, 1053 // TODO(groby): Only relevant until new ConstrainedWindow is implemented,
905 // from then on always true. 1054 // from then on always true.
906 bool use_close_button_; 1055 bool use_close_button_;
907 1056
908 // Signals if the picker can be closed. False during extension install. 1057 // Signals if the picker can be closed. False during extension install.
909 bool can_close_; 1058 bool can_close_;
910 1059
911 DISALLOW_COPY_AND_ASSIGN(WebIntentPickerViews); 1060 DISALLOW_COPY_AND_ASSIGN(WebIntentPickerViews);
912 }; 1061 };
913 1062
914 // static 1063 // static
915 WebIntentPicker* WebIntentPicker::Create(content::WebContents* web_contents, 1064 WebIntentPicker* WebIntentPicker::Create(content::WebContents* web_contents,
916 WebIntentPickerDelegate* delegate, 1065 WebIntentPickerDelegate* delegate,
917 WebIntentPickerModel* model) { 1066 WebIntentPickerModel* model) {
918 TabContents* tab_contents = TabContents::FromWebContents(web_contents); 1067 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
919 return new WebIntentPickerViews(tab_contents, delegate, model); 1068 return new WebIntentPickerViews(tab_contents, delegate, model);
920 } 1069 }
921 1070
922 WebIntentPickerViews::WebIntentPickerViews(TabContents* tab_contents, 1071 WebIntentPickerViews::WebIntentPickerViews(TabContents* tab_contents,
923 WebIntentPickerDelegate* delegate, 1072 WebIntentPickerDelegate* delegate,
924 WebIntentPickerModel* model) 1073 WebIntentPickerModel* model)
925 : delegate_(delegate), 1074 : state_(INITIAL),
1075 delegate_(delegate),
926 model_(model), 1076 model_(model),
927 action_label_(NULL), 1077 action_label_(NULL),
928 suggestions_label_(NULL),
929 extensions_(NULL), 1078 extensions_(NULL),
930 tab_contents_(tab_contents), 1079 tab_contents_(tab_contents),
931 webview_(new views::WebView(tab_contents->profile())), 1080 webview_(new views::WebView(tab_contents->profile())),
932 window_(NULL), 1081 window_(NULL),
933 more_suggestions_link_(NULL), 1082 more_suggestions_link_(NULL),
1083 inline_service_icon_(NULL),
934 choose_another_service_link_(NULL), 1084 choose_another_service_link_(NULL),
935 waiting_view_(NULL), 1085 waiting_view_(NULL),
936 displaying_web_contents_(false),
937 can_close_(true) { 1086 can_close_(true) {
938 bool enable_chrome_style = chrome::IsFramelessConstrainedDialogEnabled(); 1087 bool enable_chrome_style = chrome::IsFramelessConstrainedDialogEnabled();
939 use_close_button_ = enable_chrome_style; 1088 use_close_button_ = enable_chrome_style;
940 1089
941 model_->set_observer(this); 1090 model_->set_observer(this);
942 contents_ = new views::View(); 1091 contents_ = new views::View();
1092 contents_->set_background(views::Background::CreateSolidBackground(
1093 ConstrainedWindow::GetBackgroundColor()));
1094
943 // Show the dialog. 1095 // Show the dialog.
944 window_ = new ConstrainedWindowViews(tab_contents->web_contents(), 1096 window_ = new ConstrainedWindowViews(tab_contents->web_contents(), this,
945 this, 1097 enable_chrome_style, gfx::Insets());
946 enable_chrome_style);
947
948 UpdateContents(); 1098 UpdateContents();
949 } 1099 }
950 1100
951 WebIntentPickerViews::~WebIntentPickerViews() { 1101 WebIntentPickerViews::~WebIntentPickerViews() {
952 model_->set_observer(NULL); 1102 model_->set_observer(NULL);
953 } 1103 }
954 1104
955 void WebIntentPickerViews::ButtonPressed(views::Button* sender, 1105 void WebIntentPickerViews::ButtonPressed(views::Button* sender,
956 const ui::Event& event) { 1106 const ui::Event& event) {
957 delegate_->OnUserCancelledPickerDialog(); 1107 delegate_->OnUserCancelledPickerDialog();
(...skipping 12 matching lines...) Expand all
970 } 1120 }
971 1121
972 const views::Widget* WebIntentPickerViews::GetWidget() const { 1122 const views::Widget* WebIntentPickerViews::GetWidget() const {
973 return contents_->GetWidget(); 1123 return contents_->GetWidget();
974 } 1124 }
975 1125
976 views::View* WebIntentPickerViews::GetContentsView() { 1126 views::View* WebIntentPickerViews::GetContentsView() {
977 return contents_; 1127 return contents_;
978 } 1128 }
979 1129
980 int WebIntentPickerViews::GetDialogButtons() const {
981 return ui::DIALOG_BUTTON_NONE;
982 }
983
984 bool WebIntentPickerViews::Cancel() {
985 return can_close_;
986 }
987
988 void WebIntentPickerViews::LinkClicked(views::Link* source, int event_flags) { 1130 void WebIntentPickerViews::LinkClicked(views::Link* source, int event_flags) {
989 if (source == more_suggestions_link_) { 1131 if (source == more_suggestions_link_) {
990 delegate_->OnSuggestionsLinkClicked( 1132 delegate_->OnSuggestionsLinkClicked(
991 chrome::DispositionFromEventFlags(event_flags)); 1133 chrome::DispositionFromEventFlags(event_flags));
992 } else if (source == choose_another_service_link_) { 1134 } else if (source == choose_another_service_link_) {
993 // Signal cancellation of inline disposition. 1135 // Signal cancellation of inline disposition.
994 delegate_->OnChooseAnotherService(); 1136 delegate_->OnChooseAnotherService();
995 ResetContents(); 1137 ResetContents();
996 } else { 1138 } else {
997 NOTREACHED(); 1139 NOTREACHED();
998 } 1140 }
999 } 1141 }
1000 1142
1001 void WebIntentPickerViews::Close() { 1143 void WebIntentPickerViews::Close() {
1002 window_->CloseConstrainedWindow(); 1144 window_->CloseConstrainedWindow();
1003 } 1145 }
1004 1146
1005 void WebIntentPickerViews::SetActionString(const string16& action) { 1147 void WebIntentPickerViews::SetActionString(const string16& action) {
1006 action_text_ = action; 1148 action_text_ = action;
1007 1149 if (action_label_) {
1008 if (action_label_)
1009 action_label_->SetText(GetActionTitle()); 1150 action_label_->SetText(GetActionTitle());
1010 contents_->Layout(); 1151 contents_->Layout();
1011 SizeToContents(); 1152 SizeToContents();
1153 }
1012 } 1154 }
1013 1155
1014 void WebIntentPickerViews::OnExtensionInstallSuccess(const std::string& id) { 1156 void WebIntentPickerViews::OnExtensionInstallSuccess(const std::string& id) {
1015 can_close_ = true; 1157 can_close_ = true;
1016 } 1158 }
1017 1159
1018 void WebIntentPickerViews::OnExtensionInstallFailure(const std::string& id) { 1160 void WebIntentPickerViews::OnExtensionInstallFailure(const std::string& id) {
1019 extensions_->StopThrobber(); 1161 extensions_->StopThrobber();
1162 extensions_->SetEnabled(true);
1020 more_suggestions_link_->SetEnabled(true); 1163 more_suggestions_link_->SetEnabled(true);
1021 can_close_ = true; 1164 can_close_ = true;
1022 contents_->Layout(); 1165 contents_->Layout();
1023 SizeToContents(); 1166 SizeToContents();
1024 1167
1025 // TODO(binji): What to display to user on failure? 1168 // TODO(binji): What to display to user on failure?
1026 } 1169 }
1027 1170
1028 void WebIntentPickerViews::OnInlineDispositionAutoResize( 1171 void WebIntentPickerViews::OnInlineDispositionAutoResize(
1029 const gfx::Size& size) { 1172 const gfx::Size& size) {
1030 webview_->SetPreferredSize(size); 1173 webview_->SetPreferredSize(size);
1031 contents_->Layout(); 1174 contents_->Layout();
1032 SizeToContents(); 1175 SizeToContents();
1033 } 1176 }
1034 1177
1035 void WebIntentPickerViews::OnPendingAsyncCompleted() { 1178 void WebIntentPickerViews::OnPendingAsyncCompleted() {
1036 UpdateContents(); 1179 UpdateContents();
1037 } 1180 }
1038 1181
1039 void WebIntentPickerViews::ShowNoServicesMessage() { 1182 void WebIntentPickerViews::ShowNoServicesMessage() {
1183 if (state_ == NO_SERVICES)
1184 return;
1185 state_ = NO_SERVICES;
1186
1040 ClearContents(); 1187 ClearContents();
1188 views::GridLayout* layout = new views::GridLayout(contents_);
1189 layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0));
1190 const int kContentBuiltinBottomPadding = 3;
1191 layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding,
1192 0,
1193 ConstrainedWindowConstants::kClientBottomPadding -
1194 kContentBuiltinBottomPadding,
1195 0);
1196 contents_->SetLayoutManager(layout);
1041 1197
1042 views::GridLayout* grid_layout = new views::GridLayout(contents_); 1198 enum GridLayoutColumnSets {
1043 contents_->SetLayoutManager(grid_layout); 1199 HEADER_ROW,
1200 CONTENT_ROW,
1201 };
1202 views::ColumnSet* header_cs = layout->AddColumnSet(HEADER_ROW);
1203 header_cs->AddPaddingColumn(
1204 0, ConstrainedWindowConstants::kHorizontalPadding);
1205 header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
1206 GridLayout::USE_PREF, 0, 0); // Title
1207 header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0,
1208 GridLayout::USE_PREF, 0, 0); // Close button
1209 header_cs->AddPaddingColumn(
1210 0, ConstrainedWindowConstants::kCloseButtonPadding);
1044 1211
1045 grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, 1212 views::ColumnSet* content_cs = layout->AddColumnSet(CONTENT_ROW);
1046 kContentAreaBorder, kContentAreaBorder); 1213 content_cs->AddPaddingColumn(
1047 views::ColumnSet* main_cs = grid_layout->AddColumnSet(0); 1214 0, ConstrainedWindowConstants::kHorizontalPadding);
1048 main_cs->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1, 1215 content_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
1049 GridLayout::USE_PREF, 0, 0); 1216 GridLayout::USE_PREF, 0, 0); // Body
1217 content_cs->AddPaddingColumn(
1218 0, ConstrainedWindowConstants::kHorizontalPadding);
1050 1219
1051 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 1220 // Header
1221 layout->StartRow(0, HEADER_ROW);
1222 views::Label* title = CreateTitleLabel();
1223 title->SetText(l10n_util::GetStringUTF16(
1224 IDS_INTENT_PICKER_NO_SERVICES_TITLE));
1225 layout->AddView(title);
1052 1226
1053 grid_layout->StartRow(0, 0); 1227 views::ImageButton* close_button = CreateCloseButton(this);
1054 views::Label* header = new views::Label(); 1228 layout->AddView(close_button);
1055 header->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 1229 close_button->SetVisible(use_close_button_);
1056 header->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
1057 header->SetText(l10n_util::GetStringUTF16(
1058 IDS_INTENT_PICKER_NO_SERVICES_TITLE));
1059 grid_layout->AddView(header);
1060 1230
1061 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 1231 // Content
1232 const int kHeaderBuiltinBottomPadding = 4;
1233 const int kContentBuiltinTopPadding = 5;
1234 layout->AddPaddingRow(0,
1235 ConstrainedWindowConstants::kRowPadding -
1236 kHeaderBuiltinBottomPadding -
1237 kContentBuiltinTopPadding);
1238 layout->StartRow(0, CONTENT_ROW);
1239 views::Label* body = CreateLabel();
1240 body->SetMultiLine(true);
1241 body->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_NO_SERVICES));
1242 layout->AddView(body);
1062 1243
1063 grid_layout->StartRow(0, 0); 1244 int height = contents_->GetHeightForWidth(WebIntentPicker::kWindowMinWidth);
1064 views::Label* body = new views::Label(); 1245 contents_->SetSize(gfx::Size(WebIntentPicker::kWindowMinWidth, height));
1065 body->SetMultiLine(true); 1246 contents_->Layout();
1066 body->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
1067 body->SetText(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_NO_SERVICES));
1068 grid_layout->AddView(body);
1069
1070 int height = contents_->GetHeightForWidth(kWindowMinWidth);
1071 contents_->SetSize(gfx::Size(kWindowMinWidth, height));
1072 } 1247 }
1073 1248
1074 void WebIntentPickerViews::OnInlineDispositionWebContentsLoaded( 1249 void WebIntentPickerViews::OnInlineDispositionWebContentsLoaded(
1075 content::WebContents* web_contents) { 1250 content::WebContents* web_contents) {
1076 if (displaying_web_contents_) 1251 if (state_ == INLINE_SERVICE)
1077 return; 1252 return;
1253 state_ = INLINE_SERVICE;
1078 1254
1079 // Replace the picker with the inline disposition. 1255 // Replace the picker with the inline disposition.
1080 ClearContents(); 1256 ClearContents();
1081
1082 views::GridLayout* grid_layout = new views::GridLayout(contents_); 1257 views::GridLayout* grid_layout = new views::GridLayout(contents_);
1258 grid_layout->set_minimum_size(gfx::Size(WebIntentPicker::kWindowMinWidth, 0));
1259 grid_layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding, 0,
1260 ConstrainedWindowConstants::kClientBottomPadding, 0);
1083 contents_->SetLayoutManager(grid_layout); 1261 contents_->SetLayoutManager(grid_layout);
1084 1262
1085 grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, 1263 enum GridLayoutColumnSets {
1086 kContentAreaBorder, kContentAreaBorder); 1264 HEADER_ROW,
1087 views::ColumnSet* header_cs = grid_layout->AddColumnSet(0); 1265 SEPARATOR_ROW,
1088 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 1266 WEB_CONTENTS_ROW,
1089 GridLayout::USE_PREF, 0, 0); // Icon. 1267 };
1090 header_cs->AddPaddingColumn(0, 4); 1268 views::ColumnSet* header_cs = grid_layout->AddColumnSet(HEADER_ROW);
1091 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 1269 header_cs->AddPaddingColumn(
1092 GridLayout::USE_PREF, 0, 0); // Title. 1270 0, ConstrainedWindowConstants::kHorizontalPadding);
1093 header_cs->AddPaddingColumn(0, 4); 1271 header_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
1094 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 1272 GridLayout::USE_PREF, 0, 0); // Icon, title, link.
1095 GridLayout::USE_PREF, 0, 0); // Link. 1273 header_cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
1096 header_cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); 1274 header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0,
1097 if (use_close_button_) { 1275 GridLayout::USE_PREF, 0, 0); // Close button.
1098 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 1276 header_cs->AddPaddingColumn(
1099 GridLayout::USE_PREF, 0, 0); // Close Button. 1277 0, ConstrainedWindowConstants::kCloseButtonPadding);
1100 }
1101 1278
1102 views::ColumnSet* full_cs = grid_layout->AddColumnSet(1); 1279 views::ColumnSet* sep_cs = grid_layout->AddColumnSet(SEPARATOR_ROW);
1103 full_cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0, 1280 sep_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
1104 GridLayout::USE_PREF, 0, 0); 1281 GridLayout::USE_PREF, 0, 0); // Separator.
1282
1283 views::ColumnSet* contents_cs = grid_layout->AddColumnSet(WEB_CONTENTS_ROW);
1284 contents_cs->AddPaddingColumn(0, 1);
1285 contents_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 1,
1286 GridLayout::USE_PREF, 0, 0); // Web contents.
1287 contents_cs->AddPaddingColumn(0, 1);
1288
1289 // Header.
1290 grid_layout->StartRow(0, HEADER_ROW);
1105 1291
1106 const WebIntentPickerModel::InstalledService* service = 1292 const WebIntentPickerModel::InstalledService* service =
1107 model_->GetInstalledServiceWithURL(model_->inline_disposition_url()); 1293 model_->GetInstalledServiceWithURL(model_->inline_disposition_url());
1108 1294
1109 // Header row. 1295 if (!inline_service_icon_)
1110 grid_layout->StartRow(0, 0); 1296 inline_service_icon_ = new views::ImageView();
1111 views::ImageView* icon = new views::ImageView(); 1297 inline_service_icon_->SetImage(service->favicon.ToImageSkia());
1112 icon->SetImage(service->favicon.ToImageSkia());
1113 grid_layout->AddView(icon);
1114 1298
1115 string16 elided_title = ui::ElideText( 1299 views::Label* title = CreateLabel();
1116 service->title, gfx::Font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END); 1300 title->SetText(ui::ElideText(
1117 views::Label* title = new views::Label(elided_title); 1301 service->title, title->font(), kTitleLinkMaxWidth, ui::ELIDE_AT_END));
1118 grid_layout->AddView(title);
1119 // Add link for "choose another service" if other suggestions are available
1120 // or if more than one (the current) service is installed.
1121 if (model_->GetInstalledServiceCount() > 1 ||
1122 model_->GetSuggestedExtensionCount()) {
1123 choose_another_service_link_ = new views::Link(
1124 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE));
1125 grid_layout->AddView(choose_another_service_link_);
1126 choose_another_service_link_->set_listener(this);
1127 }
1128 1302
1129 if (use_close_button_) 1303 if (!choose_another_service_link_)
1130 grid_layout->AddView(CreateCloseButton(this)); 1304 choose_another_service_link_ = CreateLink();
1305 choose_another_service_link_->SetText(l10n_util::GetStringUTF16(
1306 IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE));
1307 choose_another_service_link_->set_listener(this);
1131 1308
1132 // Inline web contents row. 1309 grid_layout->AddView(CreateInlineDispositionHeader(
1133 grid_layout->StartRow(0, 1); 1310 inline_service_icon_, title, choose_another_service_link_));
1134 grid_layout->AddView(webview_, 1, 1, GridLayout::CENTER, 1311 choose_another_service_link_->SetVisible(IsUseAnotherServiceVisible(model_));
1135 GridLayout::CENTER, 0, 0); 1312
1313 views::ImageButton* close_button = CreateCloseButton(this);
1314 grid_layout->AddView(close_button);
1315 close_button->SetVisible(use_close_button_);
1316
1317 // Separator.
1318 const int kHeaderBuiltinBottomPadding = 4;
1319 grid_layout->AddPaddingRow(0,
1320 ConstrainedWindowConstants::kRowPadding -
1321 kHeaderBuiltinBottomPadding);
1322 grid_layout->StartRow(0, SEPARATOR_ROW);
1323 grid_layout->AddView(new views::Separator());
1324
1325 // Inline web contents.
1326 const int kSeparatorBottomPadding = 3;
1327 grid_layout->AddPaddingRow(0, kSeparatorBottomPadding);
1328 grid_layout->StartRow(0, WEB_CONTENTS_ROW);
1329 grid_layout->AddView(webview_);
1330
1136 contents_->Layout(); 1331 contents_->Layout();
1137 SizeToContents(); 1332 SizeToContents();
1138 displaying_web_contents_ = true;
1139 } 1333 }
1140 1334
1141 void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) { 1335 void WebIntentPickerViews::OnModelChanged(WebIntentPickerModel* model) {
1142 if (waiting_view_ && !model->IsWaitingForSuggestions()) 1336 if (state_ == WAITING && !model->IsWaitingForSuggestions())
1143 UpdateContents(); 1337 UpdateContents();
1144 1338
1145 if (suggestions_label_) { 1339 if (choose_another_service_link_) {
1146 string16 label_text = model->GetSuggestionsLinkText(); 1340 choose_another_service_link_->SetVisible(IsUseAnotherServiceVisible(model));
1147 suggestions_label_->SetText(label_text); 1341 contents_->Layout();
1148 suggestions_label_->SetVisible(!label_text.empty()); 1342 SizeToContents();
1149 } 1343 }
1150 1344
1151 if (extensions_) 1345 if (extensions_)
1152 extensions_->Update(); 1346 RefreshExtensions();
1153 contents_->Layout();
1154 SizeToContents();
1155 } 1347 }
1156 1348
1157 void WebIntentPickerViews::OnFaviconChanged(WebIntentPickerModel* model, 1349 void WebIntentPickerViews::OnFaviconChanged(WebIntentPickerModel* model,
1158 size_t index) { 1350 size_t index) {
1159 // TODO(groby): Update favicons on extensions_; 1351 // TODO(groby): Update favicons on extensions_;
1160 contents_->Layout(); 1352 if (inline_service_icon_)
1161 SizeToContents(); 1353 RefreshInlineServiceIcon();
1354 if (extensions_)
1355 RefreshExtensions();
1162 } 1356 }
1163 1357
1164 void WebIntentPickerViews::OnExtensionIconChanged( 1358 void WebIntentPickerViews::OnExtensionIconChanged(
1165 WebIntentPickerModel* model, 1359 WebIntentPickerModel* model,
1166 const std::string& extension_id) { 1360 const std::string& extension_id) {
1167 if (extensions_) 1361 OnFaviconChanged(model, -1);
1168 extensions_->Update();
1169
1170 contents_->Layout();
1171 SizeToContents();
1172 } 1362 }
1173 1363
1174 void WebIntentPickerViews::OnInlineDisposition( 1364 void WebIntentPickerViews::OnInlineDisposition(
1175 const string16&, const GURL& url) { 1365 const string16&, const GURL& url) {
1176 if (!webview_) 1366 if (!webview_)
1177 webview_ = new views::WebView(tab_contents_->profile()); 1367 webview_ = new views::WebView(tab_contents_->profile());
1178 1368
1179 inline_web_contents_.reset(delegate_->CreateWebContentsForInlineDisposition( 1369 inline_web_contents_.reset(delegate_->CreateWebContentsForInlineDisposition(
1180 tab_contents_->profile(), url)); 1370 tab_contents_->profile(), url));
1181 // Does not take ownership, so we keep a scoped_ptr 1371 // Does not take ownership, so we keep a scoped_ptr
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1219 IntentRowView::ActionType type, size_t tag) { 1409 IntentRowView::ActionType type, size_t tag) {
1220 DCHECK_EQ(IntentRowView::ACTION_INVOKE, type); 1410 DCHECK_EQ(IntentRowView::ACTION_INVOKE, type);
1221 const WebIntentPickerModel::InstalledService& service = 1411 const WebIntentPickerModel::InstalledService& service =
1222 model_->GetInstalledServiceAt(tag); 1412 model_->GetInstalledServiceAt(tag);
1223 delegate_->OnServiceChosen(service.url, service.disposition, 1413 delegate_->OnServiceChosen(service.url, service.disposition,
1224 WebIntentPickerDelegate::kEnableDefaults); 1414 WebIntentPickerDelegate::kEnableDefaults);
1225 } 1415 }
1226 1416
1227 void WebIntentPickerViews::UpdateContents() { 1417 void WebIntentPickerViews::UpdateContents() {
1228 if (model_ && model_->IsWaitingForSuggestions()) { 1418 if (model_ && model_->IsWaitingForSuggestions()) {
1229 ClearContents(); 1419 ShowWaitingForSuggestions();
1230 contents_->SetLayoutManager(new views::FillLayout());
1231 waiting_view_ = new WaitingView(this, use_close_button_);
1232 contents_->AddChildView(waiting_view_);
1233 int height = contents_->GetHeightForWidth(kWindowMinWidth);
1234 contents_->SetSize(gfx::Size(kWindowMinWidth, height));
1235 contents_->Layout();
1236 } else if (model_->GetInstalledServiceCount() || 1420 } else if (model_->GetInstalledServiceCount() ||
1237 model_->GetSuggestedExtensionCount()) { 1421 model_->GetSuggestedExtensionCount()) {
1238 ShowAvailableServices(); 1422 ShowAvailableServices();
1239 } else { 1423 } else {
1240 ShowNoServicesMessage(); 1424 ShowNoServicesMessage();
1241 } 1425 }
1242 SizeToContents(); 1426 SizeToContents();
1243 } 1427 }
1244 1428
1429 void WebIntentPickerViews::ShowWaitingForSuggestions() {
1430 if (state_ == WAITING)
1431 return;
1432 state_ = WAITING;
1433 ClearContents();
1434 contents_->SetLayoutManager(new views::FillLayout());
1435 waiting_view_ = new WaitingView(this, use_close_button_);
1436 contents_->AddChildView(waiting_view_);
1437 int height = contents_->GetHeightForWidth(kWindowMinWidth);
1438 contents_->SetSize(gfx::Size(kWindowMinWidth, height));
1439 contents_->Layout();
1440 }
1441
1245 const string16 WebIntentPickerViews::GetActionTitle() { 1442 const string16 WebIntentPickerViews::GetActionTitle() {
1246 return (!action_text_.empty()) ? 1443 return action_text_.empty() ?
1247 action_text_ : 1444 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_CHOOSE_SERVICE) :
1248 l10n_util::GetStringUTF16(IDS_INTENT_PICKER_CHOOSE_SERVICE); 1445 action_text_;
1249 } 1446 }
1250 1447
1251 void WebIntentPickerViews::ShowAvailableServices() { 1448 void WebIntentPickerViews::ShowAvailableServices() {
1252 enum {
1253 kHeaderRowColumnSet, // Column set for header layout.
1254 kFullWidthColumnSet, // Column set with a single full-width column.
1255 kIndentedFullWidthColumnSet, // Single full-width column, indented.
1256 };
1257
1258 ClearContents(); 1449 ClearContents();
1259 displaying_web_contents_ = false; 1450 state_ = LIST_SERVICES;
1260
1261 extensions_ = new IntentsView(model_, this); 1451 extensions_ = new IntentsView(model_, this);
1452 gfx::Size min_size = gfx::Size(extensions_->AdjustWidth(kWindowMinWidth), 0);
1262 1453
1263 views::GridLayout* grid_layout = new views::GridLayout(contents_); 1454 views::GridLayout* grid_layout = new views::GridLayout(contents_);
1455 grid_layout->set_minimum_size(min_size);
1456 const int kIconBuiltinBottomPadding = 4;
1457 grid_layout->SetInsets(ConstrainedWindowConstants::kCloseButtonPadding,
1458 0,
1459 ConstrainedWindowConstants::kClientBottomPadding -
1460 kIconBuiltinBottomPadding,
1461 0);
1264 contents_->SetLayoutManager(grid_layout); 1462 contents_->SetLayoutManager(grid_layout);
1265 1463
1266 grid_layout->set_minimum_size( 1464 enum GridLayoutColumnSets {
1267 gfx::Size(extensions_->AdjustWidth(kWindowMinWidth), 0)); 1465 HEADER_ROW,
1268 grid_layout->SetInsets(kContentAreaBorder, kContentAreaBorder, 1466 CONTENT_ROW,
1269 kContentAreaBorder, kContentAreaBorder); 1467 };
1270 views::ColumnSet* header_cs = grid_layout->AddColumnSet(kHeaderRowColumnSet); 1468 views::ColumnSet* header_cs = grid_layout->AddColumnSet(HEADER_ROW);
1469 header_cs->AddPaddingColumn(
1470 0, ConstrainedWindowConstants::kHorizontalPadding);
1271 header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1, 1471 header_cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
1272 GridLayout::USE_PREF, 0, 0); // Title. 1472 GridLayout::USE_PREF, 0, 0); // Action title
1273 if (use_close_button_) { 1473 header_cs->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0,
1274 header_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing); 1474 GridLayout::USE_PREF, 0, 0); // Close button
1275 header_cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 1475 header_cs->AddPaddingColumn(
1276 GridLayout::USE_PREF, 0, 0); // Close Button. 1476 0, ConstrainedWindowConstants::kCloseButtonPadding);
1277 }
1278 1477
1279 views::ColumnSet* full_cs = grid_layout->AddColumnSet(kFullWidthColumnSet); 1478 views::ColumnSet* content_cs = grid_layout->AddColumnSet(CONTENT_ROW);
1280 full_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, 1479 content_cs->AddPaddingColumn(
1281 GridLayout::USE_PREF, 0, 0); 1480 0, ConstrainedWindowConstants::kHorizontalPadding);
1481 content_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
1482 GridLayout::USE_PREF, 0, 0); // Content.
1483 content_cs->AddPaddingColumn(
1484 0, ConstrainedWindowConstants::kHorizontalPadding);
1282 1485
1283 views::ColumnSet* indent_cs = 1486 // Header.
1284 grid_layout->AddColumnSet(kIndentedFullWidthColumnSet); 1487 grid_layout->StartRow(0, HEADER_ROW);
1285 indent_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing); 1488 if (!action_label_)
1286 indent_cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, 1489 action_label_ = CreateTitleLabel();
1287 GridLayout::USE_PREF, 0, 0); 1490 action_label_->SetText(GetActionTitle());
1288
1289 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1290
1291 // Header row.
1292 grid_layout->StartRow(0, kHeaderRowColumnSet);
1293 action_label_ = new views::Label(GetActionTitle());
1294 action_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
1295 action_label_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
1296 grid_layout->AddView(action_label_); 1491 grid_layout->AddView(action_label_);
1297 1492
1298 if (use_close_button_) 1493 views::ImageButton* close_button = CreateCloseButton(this);
1299 grid_layout->AddView(CreateCloseButton(this)); 1494 grid_layout->AddView(close_button);
1495 close_button->SetVisible(use_close_button_);
1300 1496
1301 // Padding row. 1497 // Extensions.
1302 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 1498 const int kHeaderBuiltinBottomPadding = 4;
1303 1499 grid_layout->AddPaddingRow(0,
1304 // Row with app suggestions label. 1500 ConstrainedWindowConstants::kRowPadding -
1305 grid_layout->StartRow(0, kIndentedFullWidthColumnSet); 1501 kHeaderBuiltinBottomPadding);
1306 suggestions_label_ = new views::Label(); 1502 grid_layout->StartRow(0, CONTENT_ROW);
1307 suggestions_label_->SetVisible(false);
1308 suggestions_label_->SetMultiLine(true);
1309 suggestions_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
1310 grid_layout->AddView(suggestions_label_);
1311
1312 // Padding row.
1313 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1314
1315 // Row with extension suggestions.
1316 grid_layout->StartRow(0, kIndentedFullWidthColumnSet);
1317 grid_layout->AddView(extensions_); 1503 grid_layout->AddView(extensions_);
1318 1504
1319 // Padding row.
1320 grid_layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1321 1505
1322 // Row with "more suggestions" link. 1506 // Row with "more suggestions" link.
1323 grid_layout->StartRow(0, kFullWidthColumnSet); 1507 const int kIconBuiltinTopPadding = 6;
1508 grid_layout->AddPaddingRow(0,
1509 ConstrainedWindowConstants::kRowPadding -
1510 kIconBuiltinTopPadding);
1511 grid_layout->StartRow(0, CONTENT_ROW);
1324 views::View* more_view = new views::View(); 1512 views::View* more_view = new views::View();
1325 more_view->SetLayoutManager( 1513 more_view->SetLayoutManager(new views::BoxLayout(
1326 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 1514 views::BoxLayout::kHorizontal, 0, 0, kIconTextPadding));
1327 views::kRelatedControlHorizontalSpacing));
1328 views::ImageView* icon = new views::ImageView(); 1515 views::ImageView* icon = new views::ImageView();
1329 icon->SetImage(rb.GetImageNamed(IDR_WEBSTORE_ICON_16).ToImageSkia()); 1516 icon->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
1517 IDR_WEBSTORE_ICON_16));
1330 more_view->AddChildView(icon); 1518 more_view->AddChildView(icon);
1331 more_suggestions_link_ = new views::Link( 1519 if (!more_suggestions_link_)
1332 l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE)); 1520 more_suggestions_link_ = CreateLink();
1333 more_suggestions_link_->SetDisabledColor(kDisabledLinkColor); 1521 more_suggestions_link_->SetText(
1522 l10n_util::GetStringUTF16(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE));
1334 more_suggestions_link_->set_listener(this); 1523 more_suggestions_link_->set_listener(this);
1335 more_view->AddChildView(more_suggestions_link_); 1524 more_view->AddChildView(more_suggestions_link_);
1336 grid_layout->AddView(more_view, 1, 1, 1525 grid_layout->AddView(more_view, 1, 1,
1337 GridLayout::LEADING, GridLayout::CENTER); 1526 GridLayout::LEADING, GridLayout::CENTER);
1527
1338 contents_->Layout(); 1528 contents_->Layout();
1339 } 1529 }
1340 1530
1341 void WebIntentPickerViews::ResetContents() { 1531 void WebIntentPickerViews::ResetContents() {
1342 // Abandon both web contents and webview. 1532 // Abandon both web contents and webview.
1343 webview_->SetWebContents(NULL); 1533 webview_->SetWebContents(NULL);
1344 inline_web_contents_.reset(); 1534 inline_web_contents_.reset();
1345 webview_ = NULL; 1535 webview_ = NULL;
1346 1536
1347 // Re-initialize the UI. 1537 // Re-initialize the UI.
1348 UpdateContents(); 1538 UpdateContents();
1349 1539
1350 // Restore previous state. 1540 // Restore previous state.
1351 extensions_->Update(); 1541 if (extensions_)
1352 action_label_->SetText(action_text_); 1542 extensions_->Update();
1543 if (action_label_)
1544 action_label_->SetText(action_text_);
1353 contents_->Layout(); 1545 contents_->Layout();
1354 SizeToContents(); 1546 SizeToContents();
1355 } 1547 }
1356 1548
1357 void WebIntentPickerViews::SizeToContents() { 1549 void WebIntentPickerViews::SizeToContents() {
1358 gfx::Size client_size = contents_->GetPreferredSize(); 1550 gfx::Size client_size = contents_->GetPreferredSize();
1359 gfx::Rect client_bounds(client_size); 1551 gfx::Rect client_bounds(client_size);
1360 gfx::Rect new_window_bounds = window_->non_client_view()->frame_view()-> 1552 gfx::Rect new_window_bounds = window_->non_client_view()->frame_view()->
1361 GetWindowBoundsForClientBounds(client_bounds); 1553 GetWindowBoundsForClientBounds(client_bounds);
1362 window_->CenterWindow(new_window_bounds.size()); 1554 window_->CenterWindow(new_window_bounds.size());
1363 } 1555 }
1364 1556
1365 void WebIntentPickerViews::ClearContents() { 1557 void WebIntentPickerViews::ClearContents() {
1366 DCHECK(contents_); 1558 DCHECK(contents_);
1367 // The call RemoveAllChildViews(true) deletes all children of |contents|. If 1559 // The call RemoveAllChildViews(true) deletes all children of |contents|. If
1368 // we do not set our weak pointers to NULL, then they will continue to point 1560 // we do not set our weak pointers to NULL, then they will continue to point
1369 // to where the deleted objects used to be, i.e. unitialized memory. This 1561 // to where the deleted objects used to be, i.e. unitialized memory. This
1370 // would cause hard-to-explain crashes. 1562 // would cause hard-to-explain crashes.
1371 contents_->RemoveAllChildViews(true); 1563 contents_->RemoveAllChildViews(true);
1372 action_label_ = NULL; 1564 action_label_ = NULL;
1373 suggestions_label_ = NULL;
1374 extensions_ = NULL; 1565 extensions_ = NULL;
1375 more_suggestions_link_ = NULL; 1566 more_suggestions_link_ = NULL;
1567 inline_service_icon_ = NULL;
1376 choose_another_service_link_ = NULL; 1568 choose_another_service_link_ = NULL;
1377 } 1569 }
1570
1571 void WebIntentPickerViews::RefreshInlineServiceIcon() {
1572 DCHECK(inline_service_icon_);
1573 const WebIntentPickerModel::InstalledService* inline_service =
1574 model_->GetInstalledServiceWithURL(model_->inline_disposition_url());
1575 if (inline_service)
1576 inline_service_icon_->SetImage(inline_service->favicon.ToImageSkia());
1577 }
1578
1579 void WebIntentPickerViews::RefreshExtensions() {
1580 DCHECK(extensions_);
1581 extensions_->Update();
1582 contents_->Layout();
1583 SizeToContents();
1584 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698