extension_uninstall_dialog_view.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/extension_uninstall_dialog.h"
6
7#include "base/basictypes.h"
8#include "base/compiler_specific.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "chrome/browser/ui/app_list/app_list_service.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/browser_window.h"
14#include "chrome/browser/ui/views/constrained_window_views.h"
15#include "extensions/common/extension.h"
16#include "grit/generated_resources.h"
17#include "ui/base/l10n/l10n_util.h"
18#include "ui/compositor/compositor.h"
19#include "ui/compositor/layer.h"
20#include "ui/views/controls/image_view.h"
21#include "ui/views/controls/label.h"
22#include "ui/views/layout/layout_constants.h"
23#include "ui/views/view.h"
24#include "ui/views/widget/widget.h"
25#include "ui/views/window/dialog_delegate.h"
26
27#if defined(USE_ASH)
28#include "ash/shell.h"
29#endif
30
31namespace {
32
33const int kRightColumnWidth = 210;
34const int kIconSize = 69;
35
36class ExtensionUninstallDialogDelegateView;
37
38// Returns parent window for extension uninstall dialog.
39gfx::NativeWindow GetParent(Browser* browser) {
40  if (browser && browser->window())
41    return browser->window()->GetNativeWindow();
42  return NULL;
43}
44
45// Views implementation of the uninstall dialog.
46class ExtensionUninstallDialogViews : public ExtensionUninstallDialog {
47 public:
48  ExtensionUninstallDialogViews(Profile* profile,
49                                Browser* browser,
50                                ExtensionUninstallDialog::Delegate* delegate);
51  virtual ~ExtensionUninstallDialogViews();
52
53  // Forwards the accept and cancels to the delegate.
54  void ExtensionUninstallAccepted();
55  void ExtensionUninstallCanceled();
56
57  ExtensionUninstallDialogDelegateView* view() { return view_; }
58
59 private:
60  virtual void Show() OVERRIDE;
61
62  ExtensionUninstallDialogDelegateView* view_;
63  bool show_in_app_list_;
64
65  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogViews);
66};
67
68// The dialog's view, owned by the views framework.
69class ExtensionUninstallDialogDelegateView : public views::DialogDelegateView {
70 public:
71  ExtensionUninstallDialogDelegateView(
72      ExtensionUninstallDialogViews* dialog_view,
73      const extensions::Extension* extension,
74      const extensions::Extension* triggering_extension,
75      gfx::ImageSkia* icon);
76  virtual ~ExtensionUninstallDialogDelegateView();
77
78  // Called when the ExtensionUninstallDialog has been destroyed to make sure
79  // we invalidate pointers.
80  void DialogDestroyed() { dialog_ = NULL; }
81
82 private:
83  // views::DialogDelegate:
84  virtual base::string16 GetDialogButtonLabel(
85      ui::DialogButton button) const OVERRIDE;
86  virtual int GetDefaultDialogButton() const OVERRIDE {
87    // Default to accept when triggered via chrome://extensions page.
88    return triggered_by_extension_ ?
89        ui::DIALOG_BUTTON_CANCEL : ui::DIALOG_BUTTON_OK;
90  }
91  virtual bool Accept() OVERRIDE;
92  virtual bool Cancel() OVERRIDE;
93
94  // views::WidgetDelegate:
95  virtual ui::ModalType GetModalType() const OVERRIDE {
96    return ui::MODAL_TYPE_WINDOW;
97  }
98  virtual base::string16 GetWindowTitle() const OVERRIDE;
99
100  // views::View:
101  virtual gfx::Size GetPreferredSize() const OVERRIDE;
102
103  virtual void Layout() OVERRIDE;
104
105  ExtensionUninstallDialogViews* dialog_;
106
107  views::ImageView* icon_;
108  views::Label* heading_;
109  bool triggered_by_extension_;
110
111  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogDelegateView);
112};
113
114ExtensionUninstallDialogViews::ExtensionUninstallDialogViews(
115    Profile* profile,
116    Browser* browser,
117    ExtensionUninstallDialog::Delegate* delegate)
118    : ExtensionUninstallDialog(profile, browser, delegate),
119      view_(NULL),
120      show_in_app_list_(!browser) {
121}
122
123ExtensionUninstallDialogViews::~ExtensionUninstallDialogViews() {
124  // Close the widget (the views framework will delete view_).
125  if (view_) {
126    view_->DialogDestroyed();
127    view_->GetWidget()->CloseNow();
128  }
129}
130
131void ExtensionUninstallDialogViews::Show() {
132  // TODO(tapted): A true |desktop_type| needs to be passed in at creation time
133  // to remove reliance on GetActiveDesktop(). http://crbug.com/308360
134  gfx::NativeWindow parent = show_in_app_list_ ?
135      AppListService::Get(chrome::GetActiveDesktop())->GetAppListWindow() :
136      GetParent(browser_);
137  if (browser_ && !parent) {
138    delegate_->ExtensionUninstallCanceled();
139    return;
140  }
141
142  view_ = new ExtensionUninstallDialogDelegateView(
143      this, extension_, triggering_extension_, &icon_);
144  CreateBrowserModalDialogViews(view_, parent)->Show();
145}
146
147void ExtensionUninstallDialogViews::ExtensionUninstallAccepted() {
148  // The widget gets destroyed when the dialog is accepted.
149  view_ = NULL;
150  delegate_->ExtensionUninstallAccepted();
151}
152
153void ExtensionUninstallDialogViews::ExtensionUninstallCanceled() {
154  // The widget gets destroyed when the dialog is canceled.
155  view_ = NULL;
156  delegate_->ExtensionUninstallCanceled();
157}
158
159ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView(
160    ExtensionUninstallDialogViews* dialog_view,
161    const extensions::Extension* extension,
162    const extensions::Extension* triggering_extension,
163    gfx::ImageSkia* icon)
164    : dialog_(dialog_view),
165      triggered_by_extension_(triggering_extension != NULL) {
166  // Scale down to icon size, but allow smaller icons (don't scale up).
167  gfx::Size size(icon->width(), icon->height());
168  if (size.width() > kIconSize || size.height() > kIconSize)
169    size = gfx::Size(kIconSize, kIconSize);
170  icon_ = new views::ImageView();
171  icon_->SetImageSize(size);
172  icon_->SetImage(*icon);
173  AddChildView(icon_);
174
175  heading_ = new views::Label(base::UTF8ToUTF16(dialog_->GetHeadingText()));
176  heading_->SetMultiLine(true);
177  heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
178  AddChildView(heading_);
179}
180
181ExtensionUninstallDialogDelegateView::~ExtensionUninstallDialogDelegateView() {
182}
183
184base::string16 ExtensionUninstallDialogDelegateView::GetDialogButtonLabel(
185    ui::DialogButton button) const {
186  return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
187      IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON : IDS_CANCEL);
188}
189
190bool ExtensionUninstallDialogDelegateView::Accept() {
191  if (dialog_)
192    dialog_->ExtensionUninstallAccepted();
193  return true;
194}
195
196bool ExtensionUninstallDialogDelegateView::Cancel() {
197  if (dialog_)
198    dialog_->ExtensionUninstallCanceled();
199  return true;
200}
201
202base::string16 ExtensionUninstallDialogDelegateView::GetWindowTitle() const {
203  return l10n_util::GetStringUTF16(IDS_EXTENSION_UNINSTALL_PROMPT_TITLE);
204}
205
206gfx::Size ExtensionUninstallDialogDelegateView::GetPreferredSize() const {
207  int width = kRightColumnWidth;
208  width += kIconSize;
209  width += views::kButtonHEdgeMarginNew * 2;
210  width += views::kRelatedControlHorizontalSpacing;
211
212  int height = views::kPanelVertMargin * 2;
213  height += heading_->GetHeightForWidth(kRightColumnWidth);
214
215  return gfx::Size(width,
216                   std::max(height, kIconSize + views::kPanelVertMargin * 2));
217}
218
219void ExtensionUninstallDialogDelegateView::Layout() {
220  int x = views::kButtonHEdgeMarginNew;
221  int y = views::kPanelVertMargin;
222
223  heading_->SizeToFit(kRightColumnWidth);
224
225  if (heading_->height() <= kIconSize) {
226    icon_->SetBounds(x, y, kIconSize, kIconSize);
227    x += kIconSize;
228    x += views::kRelatedControlHorizontalSpacing;
229
230    heading_->SetX(x);
231    heading_->SetY(y + (kIconSize - heading_->height()) / 2);
232  } else {
233    icon_->SetBounds(x,
234                     y + (heading_->height() - kIconSize) / 2,
235                     kIconSize,
236                     kIconSize);
237    x += kIconSize;
238    x += views::kRelatedControlHorizontalSpacing;
239
240    heading_->SetX(x);
241    heading_->SetY(y);
242  }
243}
244
245}  // namespace
246
247// static
248ExtensionUninstallDialog* ExtensionUninstallDialog::Create(
249    Profile* profile,
250    Browser* browser,
251    Delegate* delegate) {
252  return new ExtensionUninstallDialogViews(profile, browser, delegate);
253}
254