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