extension_uninstall_dialog_view.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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    return ui::DIALOG_BUTTON_CANCEL;
88  }
89  virtual bool Accept() OVERRIDE;
90  virtual bool Cancel() OVERRIDE;
91
92  // views::WidgetDelegate:
93  virtual ui::ModalType GetModalType() const OVERRIDE {
94    return ui::MODAL_TYPE_WINDOW;
95  }
96  virtual base::string16 GetWindowTitle() const OVERRIDE;
97
98  // views::View:
99  virtual gfx::Size GetPreferredSize() OVERRIDE;
100
101  virtual void Layout() OVERRIDE;
102
103  ExtensionUninstallDialogViews* dialog_;
104
105  views::ImageView* icon_;
106  views::Label* heading_;
107
108  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogDelegateView);
109};
110
111ExtensionUninstallDialogViews::ExtensionUninstallDialogViews(
112    Profile* profile,
113    Browser* browser,
114    ExtensionUninstallDialog::Delegate* delegate)
115    : ExtensionUninstallDialog(profile, browser, delegate),
116      view_(NULL),
117      show_in_app_list_(!browser) {
118}
119
120ExtensionUninstallDialogViews::~ExtensionUninstallDialogViews() {
121  // Close the widget (the views framework will delete view_).
122  if (view_) {
123    view_->DialogDestroyed();
124    view_->GetWidget()->CloseNow();
125  }
126}
127
128void ExtensionUninstallDialogViews::Show() {
129  // TODO(tapted): A true |desktop_type| needs to be passed in at creation time
130  // to remove reliance on GetActiveDesktop(). http://crbug.com/308360
131  gfx::NativeWindow parent = show_in_app_list_ ?
132      AppListService::Get(chrome::GetActiveDesktop())->GetAppListWindow() :
133      GetParent(browser_);
134  if (browser_ && !parent) {
135    delegate_->ExtensionUninstallCanceled();
136    return;
137  }
138
139  view_ = new ExtensionUninstallDialogDelegateView(
140      this, extension_, triggering_extension_, &icon_);
141  CreateBrowserModalDialogViews(view_, parent)->Show();
142}
143
144void ExtensionUninstallDialogViews::ExtensionUninstallAccepted() {
145  // The widget gets destroyed when the dialog is accepted.
146  view_ = NULL;
147  delegate_->ExtensionUninstallAccepted();
148}
149
150void ExtensionUninstallDialogViews::ExtensionUninstallCanceled() {
151  // The widget gets destroyed when the dialog is canceled.
152  view_ = NULL;
153  delegate_->ExtensionUninstallCanceled();
154}
155
156ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView(
157    ExtensionUninstallDialogViews* dialog_view,
158    const extensions::Extension* extension,
159    const extensions::Extension* triggering_extension,
160    gfx::ImageSkia* icon)
161    : dialog_(dialog_view) {
162  // Scale down to icon size, but allow smaller icons (don't scale up).
163  gfx::Size size(icon->width(), icon->height());
164  if (size.width() > kIconSize || size.height() > kIconSize)
165    size = gfx::Size(kIconSize, kIconSize);
166  icon_ = new views::ImageView();
167  icon_->SetImageSize(size);
168  icon_->SetImage(*icon);
169  AddChildView(icon_);
170
171  heading_ = new views::Label(base::UTF8ToUTF16(dialog_->GetHeadingText()));
172  heading_->SetMultiLine(true);
173  heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
174  AddChildView(heading_);
175}
176
177ExtensionUninstallDialogDelegateView::~ExtensionUninstallDialogDelegateView() {
178}
179
180base::string16 ExtensionUninstallDialogDelegateView::GetDialogButtonLabel(
181    ui::DialogButton button) const {
182  return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
183      IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON : IDS_CANCEL);
184}
185
186bool ExtensionUninstallDialogDelegateView::Accept() {
187  if (dialog_)
188    dialog_->ExtensionUninstallAccepted();
189  return true;
190}
191
192bool ExtensionUninstallDialogDelegateView::Cancel() {
193  if (dialog_)
194    dialog_->ExtensionUninstallCanceled();
195  return true;
196}
197
198base::string16 ExtensionUninstallDialogDelegateView::GetWindowTitle() const {
199  return l10n_util::GetStringUTF16(IDS_EXTENSION_UNINSTALL_PROMPT_TITLE);
200}
201
202gfx::Size ExtensionUninstallDialogDelegateView::GetPreferredSize() {
203  int width = kRightColumnWidth;
204  width += kIconSize;
205  width += views::kButtonHEdgeMarginNew * 2;
206  width += views::kRelatedControlHorizontalSpacing;
207
208  int height = views::kPanelVertMargin * 2;
209  height += heading_->GetHeightForWidth(kRightColumnWidth);
210
211  return gfx::Size(width,
212                   std::max(height, kIconSize + views::kPanelVertMargin * 2));
213}
214
215void ExtensionUninstallDialogDelegateView::Layout() {
216  int x = views::kButtonHEdgeMarginNew;
217  int y = views::kPanelVertMargin;
218
219  heading_->SizeToFit(kRightColumnWidth);
220
221  if (heading_->height() <= kIconSize) {
222    icon_->SetBounds(x, y, kIconSize, kIconSize);
223    x += kIconSize;
224    x += views::kRelatedControlHorizontalSpacing;
225
226    heading_->SetX(x);
227    heading_->SetY(y + (kIconSize - heading_->height()) / 2);
228  } else {
229    icon_->SetBounds(x,
230                     y + (heading_->height() - kIconSize) / 2,
231                     kIconSize,
232                     kIconSize);
233    x += kIconSize;
234    x += views::kRelatedControlHorizontalSpacing;
235
236    heading_->SetX(x);
237    heading_->SetY(y);
238  }
239}
240
241}  // namespace
242
243// static
244ExtensionUninstallDialog* ExtensionUninstallDialog::Create(
245    Profile* profile,
246    Browser* browser,
247    Delegate* delegate) {
248  return new ExtensionUninstallDialogViews(profile, browser, delegate);
249}
250