extension_uninstall_dialog_view.cc revision e4256316f8b5e8d1ec0df1f7762771622a53fa63
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/views/constrained_window_views.h" 13#include "chrome/grit/generated_resources.h" 14#include "extensions/common/extension.h" 15#include "ui/aura/window_tracker.h" 16#include "ui/base/l10n/l10n_util.h" 17#include "ui/compositor/compositor.h" 18#include "ui/compositor/layer.h" 19#include "ui/views/controls/image_view.h" 20#include "ui/views/controls/label.h" 21#include "ui/views/layout/layout_constants.h" 22#include "ui/views/view.h" 23#include "ui/views/widget/widget.h" 24#include "ui/views/window/dialog_delegate.h" 25 26namespace { 27 28const int kRightColumnWidth = 210; 29const int kIconSize = 64; 30 31class ExtensionUninstallDialogDelegateView; 32 33// Views implementation of the uninstall dialog. 34class ExtensionUninstallDialogViews 35 : public extensions::ExtensionUninstallDialog { 36 public: 37 ExtensionUninstallDialogViews( 38 Profile* profile, 39 aura::Window* parent, 40 extensions::ExtensionUninstallDialog::Delegate* delegate); 41 virtual ~ExtensionUninstallDialogViews(); 42 43 // Called when the ExtensionUninstallDialogDelegate has been destroyed to make 44 // sure we invalidate pointers. 45 void DialogDelegateDestroyed() { view_ = NULL; } 46 47 // Forwards the accept and cancels to the delegate. 48 void ExtensionUninstallAccepted(); 49 void ExtensionUninstallCanceled(); 50 51 private: 52 virtual void Show() OVERRIDE; 53 54 ExtensionUninstallDialogDelegateView* view_; 55 56 // The dialog's parent window. 57 aura::Window* parent_; 58 59 // Tracks whether |parent_| got destroyed. 60 aura::WindowTracker parent_window_tracker_; 61 62 DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogViews); 63}; 64 65// The dialog's view, owned by the views framework. 66class ExtensionUninstallDialogDelegateView : public views::DialogDelegateView { 67 public: 68 ExtensionUninstallDialogDelegateView( 69 ExtensionUninstallDialogViews* dialog_view, 70 const extensions::Extension* extension, 71 const extensions::Extension* triggering_extension, 72 gfx::ImageSkia* image); 73 virtual ~ExtensionUninstallDialogDelegateView(); 74 75 // Called when the ExtensionUninstallDialog has been destroyed to make sure 76 // we invalidate pointers. 77 void DialogDestroyed() { dialog_ = NULL; } 78 79 private: 80 // views::DialogDelegate: 81 virtual base::string16 GetDialogButtonLabel( 82 ui::DialogButton button) const OVERRIDE; 83 virtual int GetDefaultDialogButton() const OVERRIDE { 84 // Default to accept when triggered via chrome://extensions page. 85 return triggered_by_extension_ ? 86 ui::DIALOG_BUTTON_CANCEL : ui::DIALOG_BUTTON_OK; 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() const OVERRIDE; 99 100 virtual void Layout() OVERRIDE; 101 102 ExtensionUninstallDialogViews* dialog_; 103 104 views::ImageView* icon_; 105 views::Label* heading_; 106 bool triggered_by_extension_; 107 108 DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogDelegateView); 109}; 110 111ExtensionUninstallDialogViews::ExtensionUninstallDialogViews( 112 Profile* profile, 113 aura::Window* parent, 114 extensions::ExtensionUninstallDialog::Delegate* delegate) 115 : extensions::ExtensionUninstallDialog(profile, delegate), 116 view_(NULL), 117 parent_(parent) { 118 if (parent_) 119 parent_window_tracker_.Add(parent_); 120} 121 122ExtensionUninstallDialogViews::~ExtensionUninstallDialogViews() { 123 // Close the widget (the views framework will delete view_). 124 if (view_) { 125 view_->DialogDestroyed(); 126 view_->GetWidget()->CloseNow(); 127 } 128} 129 130void ExtensionUninstallDialogViews::Show() { 131 if (parent_ && !parent_window_tracker_.Contains(parent_)) { 132 delegate_->ExtensionUninstallCanceled(); 133 return; 134 } 135 136 view_ = new ExtensionUninstallDialogDelegateView( 137 this, extension_, triggering_extension_, &icon_); 138 CreateBrowserModalDialogViews(view_, parent_)->Show(); 139} 140 141void ExtensionUninstallDialogViews::ExtensionUninstallAccepted() { 142 // The widget gets destroyed when the dialog is accepted. 143 view_->DialogDestroyed(); 144 view_ = NULL; 145 delegate_->ExtensionUninstallAccepted(); 146} 147 148void ExtensionUninstallDialogViews::ExtensionUninstallCanceled() { 149 // The widget gets destroyed when the dialog is canceled. 150 view_->DialogDestroyed(); 151 view_ = NULL; 152 delegate_->ExtensionUninstallCanceled(); 153} 154 155ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView( 156 ExtensionUninstallDialogViews* dialog_view, 157 const extensions::Extension* extension, 158 const extensions::Extension* triggering_extension, 159 gfx::ImageSkia* image) 160 : dialog_(dialog_view), 161 triggered_by_extension_(triggering_extension != NULL) { 162 // Scale down to icon size, but allow smaller icons (don't scale up). 163 gfx::Size size(image->width(), image->height()); 164 if (size.width() > kIconSize || size.height() > kIconSize) 165 size = gfx::Size(kIconSize, kIconSize); 166 icon_ = new views::ImageView(); 167 icon_->SetImageSize(size); 168 icon_->SetImage(*image); 169 AddChildView(icon_); 170 171 heading_ = new views::Label(base::UTF8ToUTF16(dialog_->GetHeadingText())); 172 heading_->SetMultiLine(true); 173 heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 174 AddChildView(heading_); 175} 176 177ExtensionUninstallDialogDelegateView::~ExtensionUninstallDialogDelegateView() { 178 // If we're here, 2 things could have happened. Either the user closed the 179 // dialog nicely and one of ExtensionUninstallAccepted or 180 // ExtensionUninstallCanceled has been called (in which case dialog_ will be 181 // NULL), *or* neither of them have been called and we are being forced closed 182 // by our parent widget. In this case, we need to make sure to notify dialog_ 183 // not to call us again, since we're about to be freed by the Widget 184 // framework. 185 if (dialog_) 186 dialog_->DialogDelegateDestroyed(); 187} 188 189base::string16 ExtensionUninstallDialogDelegateView::GetDialogButtonLabel( 190 ui::DialogButton button) const { 191 return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ? 192 IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON : IDS_CANCEL); 193} 194 195bool ExtensionUninstallDialogDelegateView::Accept() { 196 if (dialog_) 197 dialog_->ExtensionUninstallAccepted(); 198 return true; 199} 200 201bool ExtensionUninstallDialogDelegateView::Cancel() { 202 if (dialog_) 203 dialog_->ExtensionUninstallCanceled(); 204 return true; 205} 206 207base::string16 ExtensionUninstallDialogDelegateView::GetWindowTitle() const { 208 return l10n_util::GetStringUTF16(IDS_EXTENSION_UNINSTALL_PROMPT_TITLE); 209} 210 211gfx::Size ExtensionUninstallDialogDelegateView::GetPreferredSize() const { 212 int width = kRightColumnWidth; 213 width += kIconSize; 214 width += views::kButtonHEdgeMarginNew * 2; 215 width += views::kRelatedControlHorizontalSpacing; 216 217 int height = views::kPanelVertMargin * 2; 218 height += heading_->GetHeightForWidth(kRightColumnWidth); 219 220 return gfx::Size(width, 221 std::max(height, kIconSize + views::kPanelVertMargin * 2)); 222} 223 224void ExtensionUninstallDialogDelegateView::Layout() { 225 int x = views::kButtonHEdgeMarginNew; 226 int y = views::kPanelVertMargin; 227 228 heading_->SizeToFit(kRightColumnWidth); 229 230 if (heading_->height() <= kIconSize) { 231 icon_->SetBounds(x, y, kIconSize, kIconSize); 232 x += kIconSize; 233 x += views::kRelatedControlHorizontalSpacing; 234 235 heading_->SetX(x); 236 heading_->SetY(y + (kIconSize - heading_->height()) / 2); 237 } else { 238 icon_->SetBounds(x, 239 y + (heading_->height() - kIconSize) / 2, 240 kIconSize, 241 kIconSize); 242 x += kIconSize; 243 x += views::kRelatedControlHorizontalSpacing; 244 245 heading_->SetX(x); 246 heading_->SetY(y); 247 } 248} 249 250} // namespace 251 252// static 253extensions::ExtensionUninstallDialog* 254extensions::ExtensionUninstallDialog::Create(Profile* profile, 255 gfx::NativeWindow parent, 256 Delegate* delegate) { 257 return new ExtensionUninstallDialogViews(profile, parent, delegate); 258} 259