desktop_media_picker_views.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2013 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.
4
5#include "chrome/browser/media/desktop_media_picker.h"
6
7#include "base/callback.h"
8#include "chrome/browser/media/desktop_media_list.h"
9#include "chrome/browser/media/desktop_media_list_observer.h"
10#include "chrome/browser/ui/ash/ash_util.h"
11#include "chrome/browser/ui/views/constrained_window_views.h"
12#include "components/web_modal/web_contents_modal_dialog_manager.h"
13#include "content/public/browser/browser_thread.h"
14#include "grit/generated_resources.h"
15#include "ui/aura/window_tree_host.h"
16#include "ui/base/l10n/l10n_util.h"
17#include "ui/events/event_constants.h"
18#include "ui/events/keycodes/keyboard_codes.h"
19#include "ui/gfx/canvas.h"
20#include "ui/native_theme/native_theme.h"
21#include "ui/views/background.h"
22#include "ui/views/bubble/bubble_frame_view.h"
23#include "ui/views/controls/image_view.h"
24#include "ui/views/controls/label.h"
25#include "ui/views/controls/scroll_view.h"
26#include "ui/views/layout/box_layout.h"
27#include "ui/views/layout/layout_constants.h"
28#include "ui/views/widget/widget.h"
29#include "ui/views/window/dialog_client_view.h"
30#include "ui/views/window/dialog_delegate.h"
31#include "ui/wm/core/shadow_types.h"
32
33using content::DesktopMediaID;
34
35namespace {
36
37const int kThumbnailWidth = 160;
38const int kThumbnailHeight = 100;
39const int kThumbnailMargin = 10;
40const int kLabelHeight = 40;
41const int kListItemWidth = kThumbnailMargin * 2 + kThumbnailWidth;
42const int kListItemHeight =
43    kThumbnailMargin * 2 + kThumbnailHeight + kLabelHeight;
44const int kListColumns = 3;
45const int kTotalListWidth = kListColumns * kListItemWidth;
46
47const int kDesktopMediaSourceViewGroupId = 1;
48
49const char kDesktopMediaSourceViewClassName[] =
50    "DesktopMediaPicker_DesktopMediaSourceView";
51
52content::DesktopMediaID::Id AcceleratedWidgetToDesktopMediaId(
53    gfx::AcceleratedWidget accelerated_widget) {
54#if defined(OS_WIN)
55  return reinterpret_cast<content::DesktopMediaID::Id>(accelerated_widget);
56#else
57  return static_cast<content::DesktopMediaID::Id>(accelerated_widget);
58#endif
59}
60
61int GetMediaListViewHeightForRows(size_t rows) {
62  return kListItemHeight * rows;
63}
64
65class DesktopMediaListView;
66class DesktopMediaPickerDialogView;
67class DesktopMediaPickerViews;
68
69// View used for each item in DesktopMediaListView. Shows a single desktop media
70// source as a thumbnail with the title under it.
71class DesktopMediaSourceView : public views::View {
72 public:
73  DesktopMediaSourceView(DesktopMediaListView* parent,
74                         DesktopMediaID source_id);
75  virtual ~DesktopMediaSourceView();
76
77  // Updates thumbnail and title from |source|.
78  void SetName(const base::string16& name);
79  void SetThumbnail(const gfx::ImageSkia& thumbnail);
80
81  // Id for the source shown by this View.
82  const DesktopMediaID& source_id() const {
83    return source_id_;
84  }
85
86  // Returns true if the source is selected.
87  bool is_selected() const { return selected_; }
88
89  // Updates selection state of the element. If |selected| is true then also
90  // calls SetSelected(false) for the source view that was selected before that
91  // (if any).
92  void SetSelected(bool selected);
93
94  // views::View interface.
95  virtual const char* GetClassName() const OVERRIDE;
96  virtual void Layout() OVERRIDE;
97  virtual views::View* GetSelectedViewForGroup(int group) OVERRIDE;
98  virtual bool IsGroupFocusTraversable() const OVERRIDE;
99  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
100  virtual void OnFocus() OVERRIDE;
101  virtual void OnBlur() OVERRIDE;
102  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
103  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
104
105 private:
106  DesktopMediaListView* parent_;
107  DesktopMediaID source_id_;
108
109  views::ImageView* image_view_;
110  views::Label* label_;
111
112  bool selected_;
113
114  DISALLOW_COPY_AND_ASSIGN(DesktopMediaSourceView);
115};
116
117// View that shows list of desktop media sources available from
118// DesktopMediaList.
119class DesktopMediaListView : public views::View,
120                             public DesktopMediaListObserver {
121 public:
122  DesktopMediaListView(DesktopMediaPickerDialogView* parent,
123                       scoped_ptr<DesktopMediaList> media_list);
124  virtual ~DesktopMediaListView();
125
126  void StartUpdating(content::DesktopMediaID::Id dialog_window_id);
127
128  // Called by DesktopMediaSourceView when selection has changed.
129  void OnSelectionChanged();
130
131  // Called by DesktopMediaSourceView when a source has been double-clicked.
132  void OnDoubleClick();
133
134  // Returns currently selected source.
135  DesktopMediaSourceView* GetSelection();
136
137  // views::View overrides.
138  virtual gfx::Size GetPreferredSize() const OVERRIDE;
139  virtual void Layout() OVERRIDE;
140  virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
141
142 private:
143  // DesktopMediaList::Observer interface
144  virtual void OnSourceAdded(int index) OVERRIDE;
145  virtual void OnSourceRemoved(int index) OVERRIDE;
146  virtual void OnSourceMoved(int old_index, int new_index) OVERRIDE;
147  virtual void OnSourceNameChanged(int index) OVERRIDE;
148  virtual void OnSourceThumbnailChanged(int index) OVERRIDE;
149
150  DesktopMediaPickerDialogView* parent_;
151  scoped_ptr<DesktopMediaList> media_list_;
152
153  DISALLOW_COPY_AND_ASSIGN(DesktopMediaListView);
154};
155
156// Dialog view used for DesktopMediaPickerViews.
157class DesktopMediaPickerDialogView : public views::DialogDelegateView {
158 public:
159  DesktopMediaPickerDialogView(content::WebContents* parent_web_contents,
160                               gfx::NativeWindow context,
161                               gfx::NativeWindow parent_window,
162                               DesktopMediaPickerViews* parent,
163                               const base::string16& app_name,
164                               const base::string16& target_name,
165                               scoped_ptr<DesktopMediaList> media_list);
166  virtual ~DesktopMediaPickerDialogView();
167
168  // Called by parent (DesktopMediaPickerViews) when it's destroyed.
169  void DetachParent();
170
171  // Called by DesktopMediaListView.
172  void OnSelectionChanged();
173  void OnDoubleClick();
174
175  // views::View overrides.
176  virtual gfx::Size GetPreferredSize() const OVERRIDE;
177  virtual void Layout() OVERRIDE;
178
179  // views::DialogDelegateView overrides.
180  virtual ui::ModalType GetModalType() const OVERRIDE;
181  virtual base::string16 GetWindowTitle() const OVERRIDE;
182  virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE;
183  virtual base::string16 GetDialogButtonLabel(
184      ui::DialogButton button) const OVERRIDE;
185  virtual bool Accept() OVERRIDE;
186  virtual void DeleteDelegate() OVERRIDE;
187
188  void OnMediaListRowsChanged();
189
190 private:
191  DesktopMediaPickerViews* parent_;
192  base::string16 app_name_;
193
194  views::Label* label_;
195  views::ScrollView* scroll_view_;
196  DesktopMediaListView* list_view_;
197
198  DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerDialogView);
199};
200
201// Implementation of DesktopMediaPicker for Views.
202class DesktopMediaPickerViews : public DesktopMediaPicker {
203 public:
204  DesktopMediaPickerViews();
205  virtual ~DesktopMediaPickerViews();
206
207  void NotifyDialogResult(DesktopMediaID source);
208
209  // DesktopMediaPicker overrides.
210  virtual void Show(content::WebContents* web_contents,
211                    gfx::NativeWindow context,
212                    gfx::NativeWindow parent,
213                    const base::string16& app_name,
214                    const base::string16& target_name,
215                    scoped_ptr<DesktopMediaList> media_list,
216                    const DoneCallback& done_callback) OVERRIDE;
217
218 private:
219  DoneCallback callback_;
220
221  // The |dialog_| is owned by the corresponding views::Widget instance.
222  // When DesktopMediaPickerViews is destroyed the |dialog_| is destroyed
223  // asynchronously by closing the widget.
224  DesktopMediaPickerDialogView* dialog_;
225
226  DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerViews);
227};
228
229DesktopMediaSourceView::DesktopMediaSourceView(
230    DesktopMediaListView* parent,
231    DesktopMediaID source_id)
232    : parent_(parent),
233      source_id_(source_id),
234      image_view_(new views::ImageView()),
235      label_(new views::Label()),
236      selected_(false)  {
237  AddChildView(image_view_);
238  AddChildView(label_);
239  SetFocusable(true);
240}
241
242DesktopMediaSourceView::~DesktopMediaSourceView() {}
243
244void DesktopMediaSourceView::SetName(const base::string16& name) {
245  label_->SetText(name);
246}
247
248void DesktopMediaSourceView::SetThumbnail(const gfx::ImageSkia& thumbnail) {
249  image_view_->SetImage(thumbnail);
250}
251
252void DesktopMediaSourceView::SetSelected(bool selected) {
253  if (selected == selected_)
254    return;
255  selected_ = selected;
256
257  if (selected) {
258    // Unselect all other sources.
259    Views neighbours;
260    parent()->GetViewsInGroup(GetGroup(), &neighbours);
261    for (Views::iterator i(neighbours.begin()); i != neighbours.end(); ++i) {
262      if (*i != this) {
263        DCHECK_EQ((*i)->GetClassName(), kDesktopMediaSourceViewClassName);
264        DesktopMediaSourceView* source_view =
265            static_cast<DesktopMediaSourceView*>(*i);
266        source_view->SetSelected(false);
267      }
268    }
269
270    const SkColor bg_color = GetNativeTheme()->GetSystemColor(
271        ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor);
272    set_background(views::Background::CreateSolidBackground(bg_color));
273
274    parent_->OnSelectionChanged();
275  } else {
276    set_background(NULL);
277  }
278
279  SchedulePaint();
280}
281
282const char* DesktopMediaSourceView::GetClassName() const {
283  return kDesktopMediaSourceViewClassName;
284}
285
286void DesktopMediaSourceView::Layout() {
287  image_view_->SetBounds(kThumbnailMargin, kThumbnailMargin,
288                         kThumbnailWidth, kThumbnailHeight);
289  label_->SetBounds(kThumbnailMargin, kThumbnailHeight + kThumbnailMargin,
290                    kThumbnailWidth, kLabelHeight);
291}
292
293views::View* DesktopMediaSourceView::GetSelectedViewForGroup(int group) {
294  Views neighbours;
295  parent()->GetViewsInGroup(group, &neighbours);
296  if (neighbours.empty())
297    return NULL;
298
299  for (Views::iterator i(neighbours.begin()); i != neighbours.end(); ++i) {
300    DCHECK_EQ((*i)->GetClassName(), kDesktopMediaSourceViewClassName);
301    DesktopMediaSourceView* source_view =
302        static_cast<DesktopMediaSourceView*>(*i);
303    if (source_view->selected_)
304      return source_view;
305  }
306  return NULL;
307}
308
309bool DesktopMediaSourceView::IsGroupFocusTraversable() const {
310  return false;
311}
312
313void DesktopMediaSourceView::OnPaint(gfx::Canvas* canvas) {
314  View::OnPaint(canvas);
315  if (HasFocus()) {
316    gfx::Rect bounds(GetLocalBounds());
317    bounds.Inset(kThumbnailMargin / 2, kThumbnailMargin / 2);
318    canvas->DrawFocusRect(bounds);
319  }
320}
321
322void DesktopMediaSourceView::OnFocus() {
323  View::OnFocus();
324  SetSelected(true);
325  ScrollRectToVisible(gfx::Rect(size()));
326  // We paint differently when focused.
327  SchedulePaint();
328}
329
330void DesktopMediaSourceView::OnBlur() {
331  View::OnBlur();
332  // We paint differently when focused.
333  SchedulePaint();
334}
335
336bool DesktopMediaSourceView::OnMousePressed(const ui::MouseEvent& event) {
337  if (event.GetClickCount() == 1) {
338    RequestFocus();
339  } else if (event.GetClickCount() == 2) {
340    RequestFocus();
341    parent_->OnDoubleClick();
342  }
343  return true;
344}
345
346void DesktopMediaSourceView::OnGestureEvent(ui::GestureEvent* event) {
347  if (event->type() == ui::ET_GESTURE_TAP &&
348      event->details().tap_count() == 2) {
349    RequestFocus();
350    parent_->OnDoubleClick();
351    event->SetHandled();
352    return;
353  }
354
355  // Detect tap gesture using ET_GESTURE_TAP_DOWN so the view also gets focused
356  // on the long tap (when the tap gesture starts).
357  if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
358    RequestFocus();
359    event->SetHandled();
360  }
361}
362
363DesktopMediaListView::DesktopMediaListView(
364    DesktopMediaPickerDialogView* parent,
365    scoped_ptr<DesktopMediaList> media_list)
366    : parent_(parent),
367      media_list_(media_list.Pass()) {
368  media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
369}
370
371DesktopMediaListView::~DesktopMediaListView() {}
372
373void DesktopMediaListView::StartUpdating(
374    content::DesktopMediaID::Id dialog_window_id) {
375  media_list_->SetViewDialogWindowId(dialog_window_id);
376  media_list_->StartUpdating(this);
377}
378
379void DesktopMediaListView::OnSelectionChanged() {
380  parent_->OnSelectionChanged();
381}
382
383void DesktopMediaListView::OnDoubleClick() {
384  parent_->OnDoubleClick();
385}
386
387DesktopMediaSourceView* DesktopMediaListView::GetSelection() {
388  for (int i = 0; i < child_count(); ++i) {
389    DesktopMediaSourceView* source_view =
390        static_cast<DesktopMediaSourceView*>(child_at(i));
391    DCHECK_EQ(source_view->GetClassName(), kDesktopMediaSourceViewClassName);
392    if (source_view->is_selected())
393      return source_view;
394  }
395  return NULL;
396}
397
398gfx::Size DesktopMediaListView::GetPreferredSize() const {
399  int total_rows = (child_count() + kListColumns - 1) / kListColumns;
400  return gfx::Size(kTotalListWidth, GetMediaListViewHeightForRows(total_rows));
401}
402
403void DesktopMediaListView::Layout() {
404  int x = 0;
405  int y = 0;
406
407  for (int i = 0; i < child_count(); ++i) {
408    if (x + kListItemWidth > kTotalListWidth) {
409      x = 0;
410      y += kListItemHeight;
411    }
412
413    View* source_view = child_at(i);
414    source_view->SetBounds(x, y, kListItemWidth, kListItemHeight);
415
416    x += kListItemWidth;
417  }
418
419  y += kListItemHeight;
420  SetSize(gfx::Size(kTotalListWidth, y));
421}
422
423bool DesktopMediaListView::OnKeyPressed(const ui::KeyEvent& event) {
424  int position_increment = 0;
425  switch (event.key_code()) {
426    case ui::VKEY_UP:
427      position_increment = -kListColumns;
428      break;
429    case ui::VKEY_DOWN:
430      position_increment = kListColumns;
431      break;
432    case ui::VKEY_LEFT:
433      position_increment = -1;
434      break;
435    case ui::VKEY_RIGHT:
436      position_increment = 1;
437      break;
438    default:
439      return false;
440  }
441
442  if (position_increment != 0) {
443    DesktopMediaSourceView* selected = GetSelection();
444    DesktopMediaSourceView* new_selected = NULL;
445
446    if (selected) {
447      int index = GetIndexOf(selected);
448      int new_index = index + position_increment;
449      if (new_index >= child_count())
450        new_index = child_count() - 1;
451      else if (new_index < 0)
452        new_index = 0;
453      if (index != new_index) {
454        new_selected =
455            static_cast<DesktopMediaSourceView*>(child_at(new_index));
456      }
457    } else if (has_children()) {
458      new_selected = static_cast<DesktopMediaSourceView*>(child_at(0));
459    }
460
461    if (new_selected) {
462      GetFocusManager()->SetFocusedView(new_selected);
463    }
464
465    return true;
466  }
467
468  return false;
469}
470
471void DesktopMediaListView::OnSourceAdded(int index) {
472  const DesktopMediaList::Source& source = media_list_->GetSource(index);
473  DesktopMediaSourceView* source_view =
474      new DesktopMediaSourceView(this, source.id);
475  source_view->SetName(source.name);
476  source_view->SetGroup(kDesktopMediaSourceViewGroupId);
477  AddChildViewAt(source_view, index);
478
479  PreferredSizeChanged();
480
481  if (child_count() % kListColumns == 1)
482    parent_->OnMediaListRowsChanged();
483}
484
485void DesktopMediaListView::OnSourceRemoved(int index) {
486  DesktopMediaSourceView* view =
487      static_cast<DesktopMediaSourceView*>(child_at(index));
488  DCHECK(view);
489  DCHECK_EQ(view->GetClassName(), kDesktopMediaSourceViewClassName);
490  bool was_selected = view->is_selected();
491  RemoveChildView(view);
492  delete view;
493
494  if (was_selected)
495    OnSelectionChanged();
496
497  PreferredSizeChanged();
498
499  if (child_count() % kListColumns == 0)
500    parent_->OnMediaListRowsChanged();
501}
502
503void DesktopMediaListView::OnSourceMoved(int old_index, int new_index) {
504  DesktopMediaSourceView* view =
505      static_cast<DesktopMediaSourceView*>(child_at(old_index));
506  ReorderChildView(view, new_index);
507  PreferredSizeChanged();
508}
509
510void DesktopMediaListView::OnSourceNameChanged(int index) {
511  const DesktopMediaList::Source& source = media_list_->GetSource(index);
512  DesktopMediaSourceView* source_view =
513      static_cast<DesktopMediaSourceView*>(child_at(index));
514  source_view->SetName(source.name);
515}
516
517void DesktopMediaListView::OnSourceThumbnailChanged(int index) {
518  const DesktopMediaList::Source& source = media_list_->GetSource(index);
519  DesktopMediaSourceView* source_view =
520      static_cast<DesktopMediaSourceView*>(child_at(index));
521  source_view->SetThumbnail(source.thumbnail);
522}
523
524DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
525    content::WebContents* parent_web_contents,
526    gfx::NativeWindow context,
527    gfx::NativeWindow parent_window,
528    DesktopMediaPickerViews* parent,
529    const base::string16& app_name,
530    const base::string16& target_name,
531    scoped_ptr<DesktopMediaList> media_list)
532    : parent_(parent),
533      app_name_(app_name),
534      label_(new views::Label()),
535      scroll_view_(views::ScrollView::CreateScrollViewWithBorder()),
536      list_view_(new DesktopMediaListView(this, media_list.Pass())) {
537  if (app_name == target_name) {
538    label_->SetText(
539        l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TEXT, app_name));
540  } else {
541    label_->SetText(l10n_util::GetStringFUTF16(
542        IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED, app_name, target_name));
543  }
544  label_->SetMultiLine(true);
545  label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
546  AddChildView(label_);
547
548  scroll_view_->SetContents(list_view_);
549  scroll_view_->ClipHeightTo(
550      GetMediaListViewHeightForRows(1), GetMediaListViewHeightForRows(2));
551  AddChildView(scroll_view_);
552
553  // If |parent_web_contents| is set, the picker will be shown modal to the
554  // web contents. Otherwise, a new dialog widget inside |parent_window| will be
555  // created for the picker. Note that |parent_window| may also be NULL if
556  // parent web contents is not set. In this case the picker will be parented
557  // by a root window.
558  views::Widget* widget = NULL;
559  if (parent_web_contents)
560    widget = CreateWebModalDialogViews(this, parent_web_contents);
561  else
562    widget = DialogDelegate::CreateDialogWidget(this, context, parent_window);
563
564  // DesktopMediaList needs to know the ID of the picker window which
565  // matches the ID it gets from the OS. Depending on the OS and configuration
566  // we get this ID differently.
567  content::DesktopMediaID::Id dialog_window_id = 0;
568
569  // If there is |parent_window| or |parent_web_contents|, the picker window
570  // is embedded in the parent and does not have its own native window id, so we
571  // do not filter in that case.
572  if (!parent_window && !parent_web_contents) {
573#if defined(USE_ASH)
574    if (chrome::IsNativeWindowInAsh(widget->GetNativeWindow())) {
575      dialog_window_id = content::DesktopMediaID::RegisterAuraWindow(
576          widget->GetNativeWindow()).id;
577      DCHECK_NE(dialog_window_id, 0);
578    }
579#endif
580
581    if (dialog_window_id == 0) {
582      dialog_window_id = AcceleratedWidgetToDesktopMediaId(
583          widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
584    }
585  }
586
587  list_view_->StartUpdating(dialog_window_id);
588
589  if (parent_web_contents) {
590    web_modal::WebContentsModalDialogManager* manager =
591        web_modal::WebContentsModalDialogManager::FromWebContents(
592            parent_web_contents);
593    manager->ShowModalDialog(widget->GetNativeView());
594  } else {
595    widget->Show();
596  }
597}
598
599DesktopMediaPickerDialogView::~DesktopMediaPickerDialogView() {}
600
601void DesktopMediaPickerDialogView::DetachParent() {
602  parent_ = NULL;
603}
604
605gfx::Size DesktopMediaPickerDialogView::GetPreferredSize() const {
606  static const size_t kDialogViewWidth = 600;
607  const gfx::Insets title_insets = views::BubbleFrameView::GetTitleInsets();
608  size_t label_height =
609      label_->GetHeightForWidth(kDialogViewWidth - title_insets.height() * 2);
610
611  return gfx::Size(kDialogViewWidth,
612                   views::kPanelVertMargin * 2 + label_height +
613                       views::kPanelVerticalSpacing +
614                       scroll_view_->GetPreferredSize().height());
615}
616
617void DesktopMediaPickerDialogView::Layout() {
618  // DialogDelegate uses the bubble style frame.
619  const gfx::Insets title_insets = views::BubbleFrameView::GetTitleInsets();
620  gfx::Rect rect = GetLocalBounds();
621
622  rect.Inset(title_insets.left(), views::kPanelVertMargin);
623
624  gfx::Rect label_rect(rect.x(), rect.y(), rect.width(),
625                       label_->GetHeightForWidth(rect.width()));
626  label_->SetBoundsRect(label_rect);
627
628  int scroll_view_top = label_rect.bottom() + views::kPanelVerticalSpacing;
629  scroll_view_->SetBounds(
630      rect.x(), scroll_view_top,
631      rect.width(), rect.height() - scroll_view_top);
632}
633
634ui::ModalType DesktopMediaPickerDialogView::GetModalType() const {
635  return ui::MODAL_TYPE_CHILD;
636}
637
638base::string16 DesktopMediaPickerDialogView::GetWindowTitle() const {
639  return l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TITLE, app_name_);
640}
641
642bool DesktopMediaPickerDialogView::IsDialogButtonEnabled(
643    ui::DialogButton button) const {
644  if (button == ui::DIALOG_BUTTON_OK)
645    return list_view_->GetSelection() != NULL;
646  return true;
647}
648
649base::string16 DesktopMediaPickerDialogView::GetDialogButtonLabel(
650    ui::DialogButton button) const {
651  return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ?
652      IDS_DESKTOP_MEDIA_PICKER_SHARE : IDS_CANCEL);
653}
654
655bool DesktopMediaPickerDialogView::Accept() {
656  DesktopMediaSourceView* selection = list_view_->GetSelection();
657
658  // Ok button should only be enabled when a source is selected.
659  DCHECK(selection);
660
661  DesktopMediaID source;
662  if (selection)
663    source = selection->source_id();
664
665  if (parent_)
666    parent_->NotifyDialogResult(source);
667
668  // Return true to close the window.
669  return true;
670}
671
672void DesktopMediaPickerDialogView::DeleteDelegate() {
673  // If the dialog is being closed then notify the parent about it.
674  if (parent_)
675    parent_->NotifyDialogResult(DesktopMediaID());
676  delete this;
677}
678
679void DesktopMediaPickerDialogView::OnSelectionChanged() {
680  GetDialogClientView()->UpdateDialogButtons();
681}
682
683void DesktopMediaPickerDialogView::OnDoubleClick() {
684  // This will call Accept() and close the dialog.
685  GetDialogClientView()->AcceptWindow();
686}
687
688void DesktopMediaPickerDialogView::OnMediaListRowsChanged() {
689  gfx::Rect widget_bound = GetWidget()->GetWindowBoundsInScreen();
690
691  int new_height = widget_bound.height() - scroll_view_->height() +
692      scroll_view_->GetPreferredSize().height();
693
694  GetWidget()->CenterWindow(gfx::Size(widget_bound.width(), new_height));
695}
696
697DesktopMediaPickerViews::DesktopMediaPickerViews() : dialog_(NULL) {
698}
699
700DesktopMediaPickerViews::~DesktopMediaPickerViews() {
701  if (dialog_) {
702    dialog_->DetachParent();
703    dialog_->GetWidget()->Close();
704  }
705}
706
707void DesktopMediaPickerViews::Show(content::WebContents* web_contents,
708                                   gfx::NativeWindow context,
709                                   gfx::NativeWindow parent,
710                                   const base::string16& app_name,
711                                   const base::string16& target_name,
712                                   scoped_ptr<DesktopMediaList> media_list,
713                                   const DoneCallback& done_callback) {
714  callback_ = done_callback;
715  dialog_ = new DesktopMediaPickerDialogView(
716      web_contents, context, parent, this, app_name, target_name,
717      media_list.Pass());
718}
719
720void DesktopMediaPickerViews::NotifyDialogResult(DesktopMediaID source) {
721  // Once this method is called the |dialog_| will close and destroy itself.
722  dialog_->DetachParent();
723  dialog_ = NULL;
724
725  DCHECK(!callback_.is_null());
726
727  // Notify the |callback_| asynchronously because it may need to destroy
728  // DesktopMediaPicker.
729  content::BrowserThread::PostTask(
730      content::BrowserThread::UI, FROM_HERE,
731      base::Bind(callback_, source));
732  callback_.Reset();
733}
734
735}  // namespace
736
737// static
738scoped_ptr<DesktopMediaPicker> DesktopMediaPicker::Create() {
739  return scoped_ptr<DesktopMediaPicker>(new DesktopMediaPickerViews());
740}
741