extension_uninstall_dialog_view.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
27namespace {
28
29const int kRightColumnWidth = 210;
30const int kIconSize = 64;
31
32class ExtensionUninstallDialogDelegateView;
33
34// Returns parent window for extension uninstall dialog.
35gfx::NativeWindow GetParent(Browser* browser) {
36  if (browser && browser->window())
37    return browser->window()->GetNativeWindow();
38  return NULL;
39}
40
41// Views implementation of the uninstall dialog.
42class ExtensionUninstallDialogViews
43    : public extensions::ExtensionUninstallDialog {
44 public:
45  ExtensionUninstallDialogViews(
46      Profile* profile,
47      Browser* browser,
48      extensions::ExtensionUninstallDialog::Delegate* delegate);
49  virtual ~ExtensionUninstallDialogViews();
50
51  // Forwards the accept and cancels to the delegate.
52  void ExtensionUninstallAccepted();
53  void ExtensionUninstallCanceled();
54
55  ExtensionUninstallDialogDelegateView* view() { return view_; }
56
57 private:
58  virtual void Show() OVERRIDE;
59
60  ExtensionUninstallDialogDelegateView* view_;
61  bool show_in_app_list_;
62
63  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogViews);
64};
65
66// The dialog's view, owned by the views framework.
67class ExtensionUninstallDialogDelegateView : public views::DialogDelegateView {
68 public:
69  ExtensionUninstallDialogDelegateView(
70      ExtensionUninstallDialogViews* dialog_view,
71      const extensions::Extension* extension,
72      const extensions::Extension* triggering_extension,
73      gfx::ImageSkia* icon);
74  virtual ~ExtensionUninstallDialogDelegateView();
75
76  // Called when the ExtensionUninstallDialog has been destroyed to make sure
77  // we invalidate pointers.
78  void DialogDestroyed() { dialog_ = NULL; }
79
80 private:
81  // views::DialogDelegate:
82  virtual base::string16 GetDialogButtonLabel(
83      ui::DialogButton button) const OVERRIDE;
84  virtual int GetDefaultDialogButton() const OVERRIDE {
85    // Default to accept when triggered via chrome://extensions page.
86    return triggered_by_extension_ ?
87        ui::DIALOG_BUTTON_CANCEL : ui::DIALOG_BUTTON_OK;
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() const OVERRIDE;
100
101  virtual void Layout() OVERRIDE;
102
103  ExtensionUninstallDialogViews* dialog_;
104
105  views::ImageView* icon_;
106  views::Label* heading_;
107  bool triggered_by_extension_;
108
109  DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogDelegateView);
110};
111
112ExtensionUninstallDialogViews::ExtensionUninstallDialogViews(
113    Profile* profile,
114    Browser* browser,
115    extensions::ExtensionUninstallDialog::Delegate* delegate)
116    : extensions::ExtensionUninstallDialog(profile, browser, delegate),
117      view_(NULL),
118      show_in_app_list_(!browser) {
119}
120
121ExtensionUninstallDialogViews::~ExtensionUninstallDialogViews() {
122  // Close the widget (the views framework will delete view_).
123  if (view_) {
124    view_->DialogDestroyed();
125    view_->GetWidget()->CloseNow();
126  }
127}
128
129void ExtensionUninstallDialogViews::Show() {
130  // TODO(tapted): A true |desktop_type| needs to be passed in at creation time
131  // to remove reliance on GetActiveDesktop(). http://crbug.com/308360
132  gfx::NativeWindow parent = show_in_app_list_ ?
133      AppListService::Get(chrome::GetActiveDesktop())->GetAppListWindow() :
134      GetParent(browser_);
135  if (browser_ && !parent) {
136    delegate_->ExtensionUninstallCanceled();
137    return;
138  }
139
140  view_ = new ExtensionUninstallDialogDelegateView(
141      this, extension_, triggering_extension_, &icon_);
142  CreateBrowserModalDialogViews(view_, parent)->Show();
143}
144
145void ExtensionUninstallDialogViews::ExtensionUninstallAccepted() {
146  // The widget gets destroyed when the dialog is accepted.
147  view_ = NULL;
148  delegate_->ExtensionUninstallAccepted();
149}
150
151void ExtensionUninstallDialogViews::ExtensionUninstallCanceled() {
152  // The widget gets destroyed when the dialog is canceled.
153  view_ = NULL;
154  delegate_->ExtensionUninstallCanceled();
155}
156
157ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView(
158    ExtensionUninstallDialogViews* dialog_view,
159    const extensions::Extension* extension,
160    const extensions::Extension* triggering_extension,
161    gfx::ImageSkia* icon)
162    : dialog_(dialog_view),
163      triggered_by_extension_(triggering_extension != NULL) {
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(base::UTF8ToUTF16(dialog_->GetHeadingText()));
174  heading_->SetMultiLine(true);
175  heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
176  AddChildView(heading_);
177}
178
179ExtensionUninstallDialogDelegateView::~ExtensionUninstallDialogDelegateView() {
180}
181
182base::string16 ExtensionUninstallDialogDelegateView::GetDialogButtonLabel(
183    ui::DialogButton button) const {
184  return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
185      IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON : IDS_CANCEL);
186}
187
188bool ExtensionUninstallDialogDelegateView::Accept() {
189  if (dialog_)
190    dialog_->ExtensionUninstallAccepted();
191  return true;
192}
193
194bool ExtensionUninstallDialogDelegateView::Cancel() {
195  if (dialog_)
196    dialog_->ExtensionUninstallCanceled();
197  return true;
198}
199
200base::string16 ExtensionUninstallDialogDelegateView::GetWindowTitle() const {
201  return l10n_util::GetStringUTF16(IDS_EXTENSION_UNINSTALL_PROMPT_TITLE);
202}
203
204gfx::Size ExtensionUninstallDialogDelegateView::GetPreferredSize() const {
205  int width = kRightColumnWidth;
206  width += kIconSize;
207  width += views::kButtonHEdgeMarginNew * 2;
208  width += views::kRelatedControlHorizontalSpacing;
209
210  int height = views::kPanelVertMargin * 2;
211  height += heading_->GetHeightForWidth(kRightColumnWidth);
212
213  return gfx::Size(width,
214                   std::max(height, kIconSize + views::kPanelVertMargin * 2));
215}
216
217void ExtensionUninstallDialogDelegateView::Layout() {
218  int x = views::kButtonHEdgeMarginNew;
219  int y = views::kPanelVertMargin;
220
221  heading_->SizeToFit(kRightColumnWidth);
222
223  if (heading_->height() <= kIconSize) {
224    icon_->SetBounds(x, y, kIconSize, kIconSize);
225    x += kIconSize;
226    x += views::kRelatedControlHorizontalSpacing;
227
228    heading_->SetX(x);
229    heading_->SetY(y + (kIconSize - heading_->height()) / 2);
230  } else {
231    icon_->SetBounds(x,
232                     y + (heading_->height() - kIconSize) / 2,
233                     kIconSize,
234                     kIconSize);
235    x += kIconSize;
236    x += views::kRelatedControlHorizontalSpacing;
237
238    heading_->SetX(x);
239    heading_->SetY(y);
240  }
241}
242
243}  // namespace
244
245// static
246extensions::ExtensionUninstallDialog*
247extensions::ExtensionUninstallDialog::Create(Profile* profile,
248                                             Browser* browser,
249                                             Delegate* delegate) {
250  return new ExtensionUninstallDialogViews(profile, browser, delegate);
251}
252