extension_uninstall_dialog_view.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 "chrome/common/extensions/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// TODO(estade): remove this when UseNewStyle() is the default.
39int HorizontalMargin() {
40  return views::DialogDelegate::UseNewStyle() ? views::kButtonHEdgeMarginNew :
41                                                views::kPanelHorizMargin;
42}
43
44// Returns parent window for extension uninstall dialog.
45gfx::NativeWindow GetParent(Browser* browser) {
46  if (browser && browser->window())
47    return browser->window()->GetNativeWindow();
48  return NULL;
49}
50
51// Views implementation of the uninstall dialog.
52class ExtensionUninstallDialogViews : public ExtensionUninstallDialog {
53 public:
54  ExtensionUninstallDialogViews(Profile* profile,
55                                Browser* browser,
56                                ExtensionUninstallDialog::Delegate* delegate);
57  virtual ~ExtensionUninstallDialogViews();
58
59  // Forwards the accept and cancels to the delegate.
60  void ExtensionUninstallAccepted();
61  void ExtensionUninstallCanceled();
62
63  ExtensionUninstallDialogDelegateView* view() { return view_; }
64
65 private:
66  virtual void Show() OVERRIDE;
67
68  ExtensionUninstallDialogDelegateView* view_;
69  bool show_in_app_list_;
70
71  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogViews);
72};
73
74// The dialog's view, owned by the views framework.
75class ExtensionUninstallDialogDelegateView : public views::DialogDelegateView {
76 public:
77  ExtensionUninstallDialogDelegateView(
78      ExtensionUninstallDialogViews* dialog_view,
79      const extensions::Extension* extension,
80      gfx::ImageSkia* icon);
81  virtual ~ExtensionUninstallDialogDelegateView();
82
83  // Called when the ExtensionUninstallDialog has been destroyed to make sure
84  // we invalidate pointers.
85  void DialogDestroyed() { dialog_ = NULL; }
86
87 private:
88  // views::DialogDelegate:
89  virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
90  virtual int GetDefaultDialogButton() const OVERRIDE {
91    return ui::DIALOG_BUTTON_CANCEL;
92  }
93  virtual bool Accept() OVERRIDE;
94  virtual bool Cancel() OVERRIDE;
95
96  // views::WidgetDelegate:
97  virtual ui::ModalType GetModalType() const OVERRIDE {
98    return ui::MODAL_TYPE_WINDOW;
99  }
100  virtual string16 GetWindowTitle() const OVERRIDE;
101
102  // views::View:
103  virtual gfx::Size GetPreferredSize() OVERRIDE;
104
105  virtual void Layout() OVERRIDE;
106
107  ExtensionUninstallDialogViews* dialog_;
108
109  views::ImageView* icon_;
110  views::Label* heading_;
111
112  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogDelegateView);
113};
114
115ExtensionUninstallDialogViews::ExtensionUninstallDialogViews(
116    Profile* profile,
117    Browser* browser,
118    ExtensionUninstallDialog::Delegate* delegate)
119    : ExtensionUninstallDialog(profile, browser, delegate),
120      view_(NULL),
121      show_in_app_list_(!browser) {
122}
123
124ExtensionUninstallDialogViews::~ExtensionUninstallDialogViews() {
125  // Close the widget (the views framework will delete view_).
126  if (view_) {
127    view_->DialogDestroyed();
128    view_->GetWidget()->CloseNow();
129  }
130}
131
132void ExtensionUninstallDialogViews::Show() {
133  // TODO(tapted): A true |desktop_type| needs to be passed in at creation time
134  // to remove reliance on GetActiveDesktop(). http://crbug.com/308360
135  gfx::NativeWindow parent = show_in_app_list_ ?
136      AppListService::Get(chrome::GetActiveDesktop())->GetAppListWindow() :
137      GetParent(browser_);
138  if (browser_ && !parent) {
139    delegate_->ExtensionUninstallCanceled();
140    return;
141  }
142
143  view_ = new ExtensionUninstallDialogDelegateView(this, 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    gfx::ImageSkia* icon)
163    : dialog_(dialog_view) {
164  // Scale down to icon size, but allow smaller icons (don't scale up).
165  gfx::Size size(icon->width(), icon->height());
166  if (size.width() > kIconSize || size.height() > kIconSize)
167    size = gfx::Size(kIconSize, kIconSize);
168  icon_ = new views::ImageView();
169  icon_->SetImageSize(size);
170  icon_->SetImage(*icon);
171  AddChildView(icon_);
172
173  heading_ = new views::Label(
174      l10n_util::GetStringFUTF16(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING,
175                                 UTF8ToUTF16(extension->name())));
176  heading_->SetMultiLine(true);
177  AddChildView(heading_);
178}
179
180ExtensionUninstallDialogDelegateView::~ExtensionUninstallDialogDelegateView() {
181}
182
183string16 ExtensionUninstallDialogDelegateView::GetDialogButtonLabel(
184    ui::DialogButton button) const {
185  return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
186      IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON : IDS_CANCEL);
187}
188
189bool ExtensionUninstallDialogDelegateView::Accept() {
190  if (dialog_)
191    dialog_->ExtensionUninstallAccepted();
192  return true;
193}
194
195bool ExtensionUninstallDialogDelegateView::Cancel() {
196  if (dialog_)
197    dialog_->ExtensionUninstallCanceled();
198  return true;
199}
200
201string16 ExtensionUninstallDialogDelegateView::GetWindowTitle() const {
202  return l10n_util::GetStringUTF16(IDS_EXTENSION_UNINSTALL_PROMPT_TITLE);
203}
204
205gfx::Size ExtensionUninstallDialogDelegateView::GetPreferredSize() {
206  int width = kRightColumnWidth;
207  width += kIconSize;
208  width += HorizontalMargin() * 2;
209  width += views::kRelatedControlHorizontalSpacing;
210
211  int height = views::kPanelVertMargin * 2;
212  height += heading_->GetHeightForWidth(kRightColumnWidth);
213
214  return gfx::Size(width,
215                   std::max(height, kIconSize + views::kPanelVertMargin * 2));
216}
217
218void ExtensionUninstallDialogDelegateView::Layout() {
219  int x = HorizontalMargin();
220  int y = views::kPanelVertMargin;
221
222  heading_->SizeToFit(kRightColumnWidth);
223
224  if (heading_->height() <= kIconSize) {
225    icon_->SetBounds(x, y, kIconSize, kIconSize);
226    x += kIconSize;
227    x += views::kRelatedControlHorizontalSpacing;
228
229    heading_->SetX(x);
230    heading_->SetY(y + (kIconSize - heading_->height()) / 2);
231  } else {
232    icon_->SetBounds(x,
233                     y + (heading_->height() - kIconSize) / 2,
234                     kIconSize,
235                     kIconSize);
236    x += kIconSize;
237    x += views::kRelatedControlHorizontalSpacing;
238
239    heading_->SetX(x);
240    heading_->SetY(y);
241  }
242}
243
244}  // namespace
245
246// static
247ExtensionUninstallDialog* ExtensionUninstallDialog::Create(
248    Profile* profile,
249    Browser* browser,
250    Delegate* delegate) {
251  return new ExtensionUninstallDialogViews(profile, browser, delegate);
252}
253