// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/views/window/dialog_delegate.h" #include "base/logging.h" #include "ui/accessibility/ax_view_state.h" #include "ui/base/l10n/l10n_util.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/bubble/bubble_border.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" #include "ui/views/window/dialog_client_view.h" #if defined(OS_WIN) #include "ui/base/win/shell.h" #endif namespace views { //////////////////////////////////////////////////////////////////////////////// // DialogDelegate: DialogDelegate::DialogDelegate() : supports_new_style_(true) { } DialogDelegate::~DialogDelegate() { } // static Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate, gfx::NativeWindow context, gfx::NativeView parent) { return CreateDialogWidgetWithBounds(delegate, context, parent, gfx::Rect()); } // static Widget* DialogDelegate::CreateDialogWidgetWithBounds(WidgetDelegate* delegate, gfx::NativeWindow context, gfx::NativeView parent, const gfx::Rect& bounds) { views::Widget* widget = new views::Widget; views::Widget::InitParams params; params.delegate = delegate; params.bounds = bounds; DialogDelegate* dialog = delegate->AsDialogDelegate(); #if defined(OS_LINUX) && !defined(OS_CHROMEOS) // The new style doesn't support unparented dialogs on Linux desktop. if (dialog) dialog->supports_new_style_ &= parent != NULL; #elif defined(OS_WIN) // The new style doesn't support unparented dialogs on Windows Classic themes. if (dialog && !ui::win::IsAeroGlassEnabled()) dialog->supports_new_style_ &= parent != NULL; #endif if (!dialog || dialog->UseNewStyleForThisDialog()) { params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; params.remove_standard_frame = true; #if !defined(OS_MACOSX) // Except on Mac, the bubble frame includes its own shadow; remove any // native shadowing. On Mac, the window server provides the shadow. params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; #endif } params.context = context; params.parent = parent; #if !defined(OS_MACOSX) // Web-modal (ui::MODAL_TYPE_CHILD) dialogs with parents are marked as child // widgets to prevent top-level window behavior (independent movement, etc). // On Mac, however, the parent may be a native window (not a views::Widget), // and so the dialog must be considered top-level to gain focus and input // method behaviors. params.child = parent && (delegate->GetModalType() == ui::MODAL_TYPE_CHILD); #endif widget->Init(params); return widget; } View* DialogDelegate::CreateExtraView() { return NULL; } bool DialogDelegate::GetExtraViewPadding(int* padding) { return false; } View* DialogDelegate::CreateTitlebarExtraView() { return NULL; } View* DialogDelegate::CreateFootnoteView() { return NULL; } bool DialogDelegate::Cancel() { return true; } bool DialogDelegate::Accept(bool window_closing) { return Accept(); } bool DialogDelegate::Accept() { return true; } bool DialogDelegate::Close() { int buttons = GetDialogButtons(); if ((buttons & ui::DIALOG_BUTTON_CANCEL) || (buttons == ui::DIALOG_BUTTON_NONE)) { return Cancel(); } return Accept(true); } base::string16 DialogDelegate::GetDialogTitle() const { return GetWindowTitle(); } int DialogDelegate::GetDialogButtons() const { return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; } int DialogDelegate::GetDefaultDialogButton() const { if (GetDialogButtons() & ui::DIALOG_BUTTON_OK) return ui::DIALOG_BUTTON_OK; if (GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL) return ui::DIALOG_BUTTON_CANCEL; return ui::DIALOG_BUTTON_NONE; } bool DialogDelegate::ShouldDefaultButtonBeBlue() const { return false; } base::string16 DialogDelegate::GetDialogButtonLabel( ui::DialogButton button) const { if (button == ui::DIALOG_BUTTON_OK) return l10n_util::GetStringUTF16(IDS_APP_OK); if (button == ui::DIALOG_BUTTON_CANCEL) { if (GetDialogButtons() & ui::DIALOG_BUTTON_OK) return l10n_util::GetStringUTF16(IDS_APP_CANCEL); return l10n_util::GetStringUTF16(IDS_APP_CLOSE); } NOTREACHED(); return base::string16(); } bool DialogDelegate::IsDialogButtonEnabled(ui::DialogButton button) const { return true; } View* DialogDelegate::GetInitiallyFocusedView() { // Focus the default button if any. const DialogClientView* dcv = GetDialogClientView(); int default_button = GetDefaultDialogButton(); if (default_button == ui::DIALOG_BUTTON_NONE) return NULL; if ((default_button & GetDialogButtons()) == 0) { // The default button is a button we don't have. NOTREACHED(); return NULL; } if (default_button & ui::DIALOG_BUTTON_OK) return dcv->ok_button(); if (default_button & ui::DIALOG_BUTTON_CANCEL) return dcv->cancel_button(); return NULL; } DialogDelegate* DialogDelegate::AsDialogDelegate() { return this; } ClientView* DialogDelegate::CreateClientView(Widget* widget) { return new DialogClientView(widget, GetContentsView()); } NonClientFrameView* DialogDelegate::CreateNonClientFrameView(Widget* widget) { if (UseNewStyleForThisDialog()) return CreateDialogFrameView(widget); return WidgetDelegate::CreateNonClientFrameView(widget); } // static NonClientFrameView* DialogDelegate::CreateDialogFrameView(Widget* widget) { BubbleFrameView* frame = new BubbleFrameView(gfx::Insets()); #if defined(OS_MACOSX) // On Mac, dialogs have no border stroke and use a shadow provided by the OS. const BubbleBorder::Shadow kShadow = BubbleBorder::NO_ASSETS; #else const BubbleBorder::Shadow kShadow = BubbleBorder::SMALL_SHADOW; #endif scoped_ptr border( new BubbleBorder(BubbleBorder::FLOAT, kShadow, SK_ColorRED)); border->set_use_theme_background_color(true); frame->SetBubbleBorder(border.Pass()); DialogDelegate* delegate = widget->widget_delegate()->AsDialogDelegate(); if (delegate) { View* titlebar_view = delegate->CreateTitlebarExtraView(); if (titlebar_view) frame->SetTitlebarExtraView(titlebar_view); } return frame; } bool DialogDelegate::UseNewStyleForThisDialog() const { return supports_new_style_; } const DialogClientView* DialogDelegate::GetDialogClientView() const { return GetWidget()->client_view()->AsDialogClientView(); } DialogClientView* DialogDelegate::GetDialogClientView() { return GetWidget()->client_view()->AsDialogClientView(); } ui::AXRole DialogDelegate::GetAccessibleWindowRole() const { return ui::AX_ROLE_DIALOG; } //////////////////////////////////////////////////////////////////////////////// // DialogDelegateView: DialogDelegateView::DialogDelegateView() { // A WidgetDelegate should be deleted on DeleteDelegate. set_owned_by_client(); } DialogDelegateView::~DialogDelegateView() {} void DialogDelegateView::DeleteDelegate() { delete this; } Widget* DialogDelegateView::GetWidget() { return View::GetWidget(); } const Widget* DialogDelegateView::GetWidget() const { return View::GetWidget(); } View* DialogDelegateView::GetContentsView() { return this; } void DialogDelegateView::GetAccessibleState(ui::AXViewState* state) { state->name = GetDialogTitle(); state->role = ui::AX_ROLE_DIALOG; } void DialogDelegateView::ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) { if (details.is_add && details.child == this && GetWidget()) NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); } } // namespace views