• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "base/basictypes.h"
6 #include "base/compiler_specific.h"
7 #include "base/string_util.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/extensions/extension_install_dialog.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser_list.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/browser/ui/views/window.h"
14 #include "chrome/common/extensions/extension.h"
15 #include "grit/generated_resources.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "views/controls/image_view.h"
18 #include "views/controls/label.h"
19 #include "views/layout/layout_constants.h"
20 #include "views/view.h"
21 #include "views/window/dialog_delegate.h"
22 #include "views/window/window.h"
23 
24 namespace {
25 
26 // Size of extension icon in top left of dialog.
27 const int kIconSize = 69;
28 
29 // Width of the white permission box. This also is the max width of all
30 // elements in the right column of the dialog in the case where the extension
31 // requests permissions.
32 const int kPermissionBoxWidth = 270;
33 
34 // Width of the right column of the dialog when the extension requests no
35 // permissions.
36 const int kNoPermissionsRightColumnWidth = 210;
37 
38 // Width of the gray border around the permission box.
39 const int kPermissionBoxBorderWidth = 1;
40 
41 // Width of the horizontal padding inside the permission box border.
42 const int kPermissionBoxHorizontalPadding = 10;
43 
44 // Width of the vertical padding inside the permission box border.
45 const int kPermissionBoxVerticalPadding = 11;
46 
47 // The max width of the individual permission strings inside the permission
48 // box.
49 const int kPermissionLabelWidth =
50     kPermissionBoxWidth -
51     kPermissionBoxBorderWidth * 2 -
52     kPermissionBoxHorizontalPadding * 2;
53 
54 // Heading font size correction.
55 #if defined(CROS_FONTS_USING_BCI)
56 const int kHeadingFontSizeDelta = 0;
57 #else
58 const int kHeadingFontSizeDelta = 1;
59 #endif
60 
61 }  // namespace
62 
63 // Implements the extension installation dialog for TOOLKIT_VIEWS.
64 class ExtensionInstallDialogView : public views::View,
65                                    public views::DialogDelegate {
66  public:
67   ExtensionInstallDialogView(ExtensionInstallUI::Delegate* delegate,
68                              const Extension* extension,
69                              SkBitmap* icon,
70                              const std::vector<string16>& permissions,
71                              ExtensionInstallUI::PromptType type);
72   virtual ~ExtensionInstallDialogView();
73 
74  private:
75   // views::View:
76   virtual gfx::Size GetPreferredSize() OVERRIDE;
77   virtual void Layout() OVERRIDE;
78 
79   // views::DialogDelegate:
80   virtual std::wstring GetDialogButtonLabel(
81       MessageBoxFlags::DialogButton button) const OVERRIDE;
82   virtual int GetDefaultDialogButton() const OVERRIDE;
83   virtual bool Cancel() OVERRIDE;
84   virtual bool Accept() OVERRIDE;
85 
86   // views::WindowDelegate:
87   virtual bool IsModal() const OVERRIDE;
88   virtual std::wstring GetWindowTitle() const OVERRIDE;
89   virtual views::View* GetContentsView() OVERRIDE;
90 
91   // The delegate that we will call back to when the user accepts or rejects
92   // the installation.
93   ExtensionInstallUI::Delegate* delegate_;
94 
95   // Displays the extension's icon.
96   views::ImageView* icon_;
97 
98   // Displays the main heading "Install FooBar?".
99   views::Label* heading_;
100 
101   // Displays the permission box header "The extension will have access to:".
102   views::Label* will_have_access_to_;
103 
104   // The white box containing the list of permissions the extension requires.
105   // This can be NULL if the extension requires no permissions.
106   views::View* permission_box_;
107 
108   // The labels describing each of the permissions the extension requires.
109   std::vector<views::Label*> permissions_;
110 
111   // The width of the right column of the dialog. Will be either
112   // kPermissionBoxWidth or kNoPermissionsRightColumnWidth, depending on
113   // whether the extension requires any permissions.
114   int right_column_width_;
115 
116   // The type of install dialog, which must be INSTALL_PROMPT or
117   // RE_ENABLE_PROMPT.
118   ExtensionInstallUI::PromptType type_;
119 
120   DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogView);
121 };
122 
ExtensionInstallDialogView(ExtensionInstallUI::Delegate * delegate,const Extension * extension,SkBitmap * icon,const std::vector<string16> & permissions,ExtensionInstallUI::PromptType type)123 ExtensionInstallDialogView::ExtensionInstallDialogView(
124     ExtensionInstallUI::Delegate* delegate,
125     const Extension* extension,
126     SkBitmap* icon,
127     const std::vector<string16>& permissions,
128     ExtensionInstallUI::PromptType type)
129     : delegate_(delegate),
130       icon_(NULL),
131       heading_(NULL),
132       will_have_access_to_(NULL),
133       permission_box_(NULL),
134       right_column_width_(0),
135       type_(type) {
136   // Scale down to icon size, but allow smaller icons (don't scale up).
137   gfx::Size size(icon->width(), icon->height());
138   if (size.width() > kIconSize || size.height() > kIconSize)
139     size = gfx::Size(kIconSize, kIconSize);
140   icon_ = new views::ImageView();
141   icon_->SetImageSize(size);
142   icon_->SetImage(*icon);
143   icon_->SetHorizontalAlignment(views::ImageView::CENTER);
144   icon_->SetVerticalAlignment(views::ImageView::CENTER);
145   AddChildView(icon_);
146 
147   heading_ = new views::Label(UTF16ToWide(
148       l10n_util::GetStringFUTF16(ExtensionInstallUI::kHeadingIds[type_],
149                                  UTF8ToUTF16(extension->name()))));
150   heading_->SetFont(heading_->font().DeriveFont(kHeadingFontSizeDelta,
151                                                 gfx::Font::BOLD));
152   heading_->SetMultiLine(true);
153   heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
154   AddChildView(heading_);
155 
156   if (permissions.empty()) {
157     right_column_width_ = kNoPermissionsRightColumnWidth;
158   } else {
159     right_column_width_ = kPermissionBoxWidth;
160     will_have_access_to_ = new views::Label(UTF16ToWide(
161         l10n_util::GetStringUTF16(ExtensionInstallUI::kWarningIds[type_])));
162     will_have_access_to_->SetMultiLine(true);
163     will_have_access_to_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
164     AddChildView(will_have_access_to_);
165 
166     permission_box_ = new views::View();
167     permission_box_->set_background(
168         views::Background::CreateSolidBackground(SK_ColorWHITE));
169     permission_box_->set_border(
170         views::Border::CreateSolidBorder(kPermissionBoxBorderWidth,
171                                          SK_ColorLTGRAY));
172     AddChildView(permission_box_);
173   }
174 
175   for (size_t i = 0; i < permissions.size(); ++i) {
176     views::Label* label = new views::Label(UTF16ToWide(permissions[i]));
177     label->SetMultiLine(true);
178     label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
179     permission_box_->AddChildView(label);
180     permissions_.push_back(label);
181   }
182 }
183 
~ExtensionInstallDialogView()184 ExtensionInstallDialogView::~ExtensionInstallDialogView() {
185 }
186 
GetPreferredSize()187 gfx::Size ExtensionInstallDialogView::GetPreferredSize() {
188   int width = views::kPanelHorizMargin * 2;
189   width += kIconSize;
190   width += views::kPanelHorizMargin;  // Gutter.
191   width += right_column_width_;
192 
193   int height = views::kPanelVertMargin * 2;
194   height += heading_->GetHeightForWidth(right_column_width_);
195 
196   if (permission_box_) {
197     height += views::kRelatedControlVerticalSpacing;
198     height += will_have_access_to_->GetHeightForWidth(right_column_width_);
199 
200     height += views::kRelatedControlVerticalSpacing;
201     height += kPermissionBoxBorderWidth * 2;
202     height += kPermissionBoxVerticalPadding * 2;
203 
204     for (size_t i = 0; i < permissions_.size(); ++i) {
205       if (i > 0)
206         height += views::kRelatedControlVerticalSpacing;
207       height += permissions_[0]->GetHeightForWidth(kPermissionLabelWidth);
208     }
209   }
210 
211   return gfx::Size(width,
212                    std::max(height, kIconSize + views::kPanelVertMargin * 2));
213 }
214 
Layout()215 void ExtensionInstallDialogView::Layout() {
216   int x = views::kPanelHorizMargin;
217   int y = views::kPanelVertMargin;
218 
219   icon_->SetBounds(x, y, kIconSize, kIconSize);
220   x += kIconSize;
221   x += views::kPanelHorizMargin;
222 
223   heading_->SizeToFit(right_column_width_);
224   heading_->SetX(x);
225 
226   // If there's no special permissions, we do a slightly different layout with
227   // the heading centered vertically wrt the icon.
228   if (!permission_box_) {
229     heading_->SetY((GetPreferredSize().height() - heading_->height()) / 2);
230     return;
231   }
232 
233   // Otherwise, do the layout with the permission box.
234   heading_->SetY(y);
235   y += heading_->height();
236 
237   y += views::kRelatedControlVerticalSpacing;
238   will_have_access_to_->SizeToFit(right_column_width_);
239   will_have_access_to_->SetX(x);
240   will_have_access_to_->SetY(y);
241   y += will_have_access_to_->height();
242 
243   y += views::kRelatedControlVerticalSpacing;
244   permission_box_->SetX(x);
245   permission_box_->SetY(y);
246 
247   // First we layout the labels inside the permission box, so that we know how
248   // big the box will have to be.
249   int label_x = kPermissionBoxBorderWidth + kPermissionBoxHorizontalPadding;
250   int label_y = kPermissionBoxBorderWidth + kPermissionBoxVerticalPadding;
251   int permission_box_height = kPermissionBoxBorderWidth * 2;
252   permission_box_height += kPermissionBoxVerticalPadding * 2;
253 
254   for (size_t i = 0; i < permissions_.size(); ++i) {
255     if (i > 0) {
256       label_y += views::kRelatedControlVerticalSpacing;
257       permission_box_height += views::kPanelVertMargin;
258     }
259 
260     permissions_[i]->SizeToFit(kPermissionLabelWidth);
261     permissions_[i]->SetX(label_x);
262     permissions_[i]->SetY(label_y);
263 
264     label_y += permissions_[i]->height();
265     permission_box_height += permissions_[i]->height();
266   }
267 
268   // Now finally we can size the permission box itself.
269   permission_box_->SetBounds(permission_box_->x(), permission_box_->y(),
270                              right_column_width_, permission_box_height);
271 }
272 
GetDialogButtonLabel(MessageBoxFlags::DialogButton button) const273 std::wstring ExtensionInstallDialogView::GetDialogButtonLabel(
274     MessageBoxFlags::DialogButton button) const {
275   switch (button) {
276     case MessageBoxFlags::DIALOGBUTTON_OK:
277       return UTF16ToWide(
278           l10n_util::GetStringUTF16(ExtensionInstallUI::kButtonIds[type_]));
279     case MessageBoxFlags::DIALOGBUTTON_CANCEL:
280       return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CANCEL));
281     default:
282       NOTREACHED();
283       return std::wstring();
284   }
285 }
286 
GetDefaultDialogButton() const287 int ExtensionInstallDialogView::GetDefaultDialogButton() const {
288   return MessageBoxFlags::DIALOGBUTTON_CANCEL;
289 }
290 
Cancel()291 bool ExtensionInstallDialogView::Cancel() {
292   delegate_->InstallUIAbort();
293   return true;
294 }
295 
Accept()296 bool ExtensionInstallDialogView::Accept() {
297   delegate_->InstallUIProceed();
298   return true;
299 }
300 
IsModal() const301 bool ExtensionInstallDialogView::IsModal() const {
302   return true;
303 }
304 
GetWindowTitle() const305 std::wstring ExtensionInstallDialogView::GetWindowTitle() const {
306   return UTF16ToWide(
307       l10n_util::GetStringUTF16(ExtensionInstallUI::kTitleIds[type_]));
308 }
309 
GetContentsView()310 views::View* ExtensionInstallDialogView::GetContentsView() {
311   return this;
312 }
313 
ShowExtensionInstallDialog(Profile * profile,ExtensionInstallUI::Delegate * delegate,const Extension * extension,SkBitmap * icon,const std::vector<string16> & permissions,ExtensionInstallUI::PromptType type)314 void ShowExtensionInstallDialog(
315     Profile* profile,
316     ExtensionInstallUI::Delegate* delegate,
317     const Extension* extension,
318     SkBitmap* icon,
319     const std::vector<string16>& permissions,
320     ExtensionInstallUI::PromptType type) {
321 #if defined(OS_CHROMEOS)
322   // Use a normal browser window as parent on ChromeOS.
323   Browser* browser = BrowserList::FindBrowserWithType(profile,
324                                                       Browser::TYPE_NORMAL,
325                                                       true);
326 #else
327   Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
328 #endif
329   if (!browser) {
330     delegate->InstallUIAbort();
331     return;
332   }
333 
334   BrowserWindow* browser_window = browser->window();
335   if (!browser_window) {
336     delegate->InstallUIAbort();
337     return;
338   }
339 
340   ExtensionInstallDialogView* dialog = new ExtensionInstallDialogView(
341       delegate, extension, icon, permissions, type);
342 
343   views::Window* window =  browser::CreateViewsWindow(
344       browser_window->GetNativeHandle(), gfx::Rect(), dialog);
345 
346   window->Show();
347 }
348