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