// Copyright (c) 2011 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 "chrome/browser/ui/input_window_dialog.h" #include "base/compiler_specific.h" #include "base/message_loop.h" #include "base/task.h" #include "grit/generated_resources.h" #include "views/controls/label.h" #include "views/controls/textfield/textfield.h" #include "views/controls/textfield/textfield_controller.h" #include "views/layout/grid_layout.h" #include "views/layout/layout_constants.h" #include "views/window/dialog_delegate.h" #include "views/window/window.h" // Width to make the text field, in pixels. static const int kTextfieldWidth = 200; class ContentView; // The Windows implementation of the cross platform input dialog interface. class WinInputWindowDialog : public InputWindowDialog { public: WinInputWindowDialog(HWND parent, const std::wstring& window_title, const std::wstring& label, const std::wstring& contents, Delegate* delegate); virtual ~WinInputWindowDialog(); virtual void Show(); virtual void Close(); const std::wstring& window_title() const { return window_title_; } const std::wstring& label() const { return label_; } const std::wstring& contents() const { return contents_; } InputWindowDialog::Delegate* delegate() { return delegate_.get(); } private: // Our chrome views window. views::Window* window_; // Strings to feed to the on screen window. std::wstring window_title_; std::wstring label_; std::wstring contents_; // Our delegate. Consumes the window's output. scoped_ptr<InputWindowDialog::Delegate> delegate_; }; // ContentView, as the name implies, is the content view for the InputWindow. // It registers accelerators that accept/cancel the input. class ContentView : public views::View, public views::DialogDelegate, public views::TextfieldController { public: explicit ContentView(WinInputWindowDialog* delegate) : delegate_(delegate), ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)) { DCHECK(delegate_); } // views::DialogDelegate: virtual bool IsDialogButtonEnabled( MessageBoxFlags::DialogButton button) const; virtual bool Accept(); virtual bool Cancel(); virtual void DeleteDelegate(); virtual std::wstring GetWindowTitle() const; virtual bool IsModal() const { return true; } virtual views::View* GetContentsView(); // views::TextfieldController: virtual void ContentsChanged(views::Textfield* sender, const std::wstring& new_contents); virtual bool HandleKeyEvent(views::Textfield*, const views::KeyEvent&) { return false; } protected: // views::View: virtual void ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child); private: // Set up dialog controls and layout. void InitControlLayout(); // Sets focus to the first focusable element within the dialog. void FocusFirstFocusableControl(); // The Textfield that the user can type into. views::Textfield* text_field_; // The delegate that the ContentView uses to communicate changes to the // caller. WinInputWindowDialog* delegate_; // Helps us set focus to the first Textfield in the window. ScopedRunnableMethodFactory<ContentView> focus_grabber_factory_; DISALLOW_COPY_AND_ASSIGN(ContentView); }; /////////////////////////////////////////////////////////////////////////////// // ContentView, views::DialogDelegate implementation: bool ContentView::IsDialogButtonEnabled( MessageBoxFlags::DialogButton button) const { if (button == MessageBoxFlags::DIALOGBUTTON_OK && !delegate_->delegate()->IsValid(text_field_->text())) { return false; } return true; } bool ContentView::Accept() { delegate_->delegate()->InputAccepted(text_field_->text()); return true; } bool ContentView::Cancel() { delegate_->delegate()->InputCanceled(); return true; } void ContentView::DeleteDelegate() { delete delegate_; } std::wstring ContentView::GetWindowTitle() const { return delegate_->window_title(); } views::View* ContentView::GetContentsView() { return this; } /////////////////////////////////////////////////////////////////////////////// // ContentView, views::TextfieldController implementation: void ContentView::ContentsChanged(views::Textfield* sender, const std::wstring& new_contents) { GetDialogClientView()->UpdateDialogButtons(); } /////////////////////////////////////////////////////////////////////////////// // ContentView, protected: void ContentView::ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child) { if (is_add && child == this) InitControlLayout(); } /////////////////////////////////////////////////////////////////////////////// // ContentView, private: void ContentView::InitControlLayout() { text_field_ = new views::Textfield; text_field_->SetText(delegate_->contents()); text_field_->SetController(this); using views::ColumnSet; using views::GridLayout; // TODO(sky): Vertical alignment should be baseline. GridLayout* layout = GridLayout::CreatePanel(this); SetLayoutManager(layout); ColumnSet* c1 = layout->AddColumnSet(0); c1->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); c1->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); c1->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, GridLayout::USE_PREF, kTextfieldWidth, kTextfieldWidth); layout->StartRow(0, 0); views::Label* label = new views::Label(delegate_->label()); layout->AddView(label); layout->AddView(text_field_); MessageLoop::current()->PostTask(FROM_HERE, focus_grabber_factory_.NewRunnableMethod( &ContentView::FocusFirstFocusableControl)); } void ContentView::FocusFirstFocusableControl() { text_field_->SelectAll(); text_field_->RequestFocus(); } WinInputWindowDialog::WinInputWindowDialog(HWND parent, const std::wstring& window_title, const std::wstring& label, const std::wstring& contents, Delegate* delegate) : window_title_(window_title), label_(label), contents_(contents), delegate_(delegate) { window_ = views::Window::CreateChromeWindow(parent, gfx::Rect(), new ContentView(this)); window_->client_view()->AsDialogClientView()->UpdateDialogButtons(); } WinInputWindowDialog::~WinInputWindowDialog() { } void WinInputWindowDialog::Show() { window_->Show(); } void WinInputWindowDialog::Close() { window_->CloseWindow(); } // static InputWindowDialog* InputWindowDialog::Create(HWND parent, const std::wstring& window_title, const std::wstring& label, const std::wstring& contents, Delegate* delegate) { return new WinInputWindowDialog(parent, window_title, label, contents, delegate); }