diff options
-rw-r--r-- | chrome/browser/bookmarks/bookmark_context_menu_controller.cc | 18 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_input_window_dialog_controller.cc | 145 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h | 57 | ||||
-rw-r--r-- | chrome/browser/ui/input_window_dialog.h | 62 | ||||
-rw-r--r-- | chrome/browser/ui/input_window_dialog_gtk.cc | 109 | ||||
-rw-r--r-- | chrome/browser/ui/input_window_dialog_gtk.h | 52 | ||||
-rw-r--r-- | chrome/browser/ui/input_window_dialog_linux.cc | 23 | ||||
-rw-r--r-- | chrome/browser/ui/input_window_dialog_views.cc | 274 | ||||
-rw-r--r-- | chrome/browser/ui/views/bookmarks/bookmark_context_menu_controller_views.cc | 18 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 8 |
10 files changed, 756 insertions, 10 deletions
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller.cc b/chrome/browser/bookmarks/bookmark_context_menu_controller.cc index 04c00eb..0335e59 100644 --- a/chrome/browser/bookmarks/bookmark_context_menu_controller.cc +++ b/chrome/browser/bookmarks/bookmark_context_menu_controller.cc @@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/bookmarks/bookmark_editor.h" +#include "chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" @@ -140,11 +141,18 @@ void BookmarkContextMenuController::ExecuteCommand(int id) { break; } - BookmarkEditor::Show( - parent_window_, - profile_, - BookmarkEditor::EditDetails::EditNode(selection_[0]), - BookmarkEditor::SHOW_TREE); + if (selection_[0]->is_url()) { + BookmarkEditor::Show( + parent_window_, + profile_, + BookmarkEditor::EditDetails::EditNode(selection_[0]), + BookmarkEditor::SHOW_TREE); + } else { + BookmarkInputWindowDialogController::Show( + profile_, + parent_window_, + BookmarkEditor::EditDetails::EditNode(selection_[0])); + } break; case IDC_BOOKMARK_BAR_REMOVE: { diff --git a/chrome/browser/bookmarks/bookmark_input_window_dialog_controller.cc b/chrome/browser/bookmarks/bookmark_input_window_dialog_controller.cc new file mode 100644 index 0000000..19e265e --- /dev/null +++ b/chrome/browser/bookmarks/bookmark_input_window_dialog_controller.cc @@ -0,0 +1,145 @@ +// 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 "chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h" + +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/profiles/profile.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { +string16 GetWindowTitle(const BookmarkEditor::EditDetails& details) { + int title_id = 0; + switch (details.type) { + case BookmarkEditor::EditDetails::EXISTING_NODE: + if (details.existing_node->is_url()) { + title_id = IDS_BOOKMARK_EDITOR_TITLE; + } else { + title_id = IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE; + } + break; + case BookmarkEditor::EditDetails::NEW_URL: + title_id = IDS_BOOKMARK_EDITOR_TITLE; + break; + case BookmarkEditor::EditDetails::NEW_FOLDER: + title_id = IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW; + break; + default: + NOTREACHED(); + break; + } + return l10n_util::GetStringUTF16(title_id); +} +} // namespace + +BookmarkInputWindowDialogController::~BookmarkInputWindowDialogController() { + if (model_) + model_->RemoveObserver(this); +} + +// static +void BookmarkInputWindowDialogController::Show( + Profile* profile, + gfx::NativeWindow wnd, + const BookmarkEditor::EditDetails& details) { + // BookmarkInputWindowDialogController deletes itself when done. + new BookmarkInputWindowDialogController(profile, wnd, details); +} + +BookmarkInputWindowDialogController::BookmarkInputWindowDialogController( + Profile* profile, + gfx::NativeWindow wnd, + const BookmarkEditor::EditDetails& details) + : model_(profile->GetBookmarkModel()), + details_(details) { + + model_->AddObserver(this); + + InputWindowDialog::LabelContentsPairs label_contents_pairs; + string16 name_label = + l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT_FOLDER_LABEL); + if ((details.type == BookmarkEditor::EditDetails::EXISTING_NODE && + details.existing_node->is_url()) || + details.type == BookmarkEditor::EditDetails::NEW_URL) { + string16 url_label = + l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_URL_LABEL); + string16 name; + GURL url; + if (details.type == BookmarkEditor::EditDetails::NEW_URL) { + bookmark_utils::GetURLAndTitleToBookmarkFromCurrentTab(profile, + &url, + &name); + } else { + url = details.existing_node->url(); + name = details.existing_node->GetTitle(); + } + label_contents_pairs.push_back(std::make_pair(name_label, name)); + label_contents_pairs.push_back(std::make_pair(url_label, + UTF8ToUTF16(url.spec()))); + } else { + string16 name = (details.type == BookmarkEditor::EditDetails::NEW_FOLDER) ? + l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME) : + details.existing_node->GetTitle(); + label_contents_pairs.push_back(std::make_pair(name_label, name)); + } + + const InputWindowDialog::ButtonType button_type = + (details.type == BookmarkEditor::EditDetails::NEW_URL || + details.type == BookmarkEditor::EditDetails::NEW_FOLDER) ? + InputWindowDialog::BUTTON_TYPE_ADD : InputWindowDialog::BUTTON_TYPE_SAVE; + dialog_ = InputWindowDialog::Create(wnd, + GetWindowTitle(details), + label_contents_pairs, this, button_type); + dialog_->Show(); +} + +bool BookmarkInputWindowDialogController::IsValid( + const InputWindowDialog::InputTexts& texts) { + if (texts.size() != 1 && texts.size() != 2) { + return false; + } + if (texts[0].empty() || (texts.size() == 2 && texts[1].empty())) { + return false; + } + return true; +} + +void BookmarkInputWindowDialogController::InputAccepted( + const InputWindowDialog::InputTexts& texts) { + if (details_.type == BookmarkEditor::EditDetails::EXISTING_NODE) { + if (details_.existing_node->is_url()) { + DCHECK_EQ(2U, texts.size()); + model_->SetTitle(details_.existing_node, texts[0]); + model_->SetURL(details_.existing_node, GURL(texts[1])); + } else { + DCHECK_EQ(1U, texts.size()); + model_->SetTitle(details_.existing_node, texts[0]); + } + } else if (details_.type == BookmarkEditor::EditDetails::NEW_FOLDER) { + DCHECK_EQ(1U, texts.size()); + // TODO(mazda): Add |details_.urls| to AddFolder. + model_->AddFolder(details_.parent_node, details_.index, texts[0]); + } else if (details_.type == BookmarkEditor::EditDetails::NEW_URL) { + DCHECK_EQ(2U, texts.size()); + model_->AddURL(details_.parent_node, details_.index, texts[0], + GURL(texts[1])); + } +} + +void BookmarkInputWindowDialogController::InputCanceled() { +} + +void BookmarkInputWindowDialogController::BookmarkModelChanged() { +} + +void BookmarkInputWindowDialogController::BookmarkModelBeingDeleted( + BookmarkModel* model) { + model_->RemoveObserver(this); + model_ = NULL; + BookmarkModelChanged(); +} diff --git a/chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h b/chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h new file mode 100644 index 0000000..ec30949 --- /dev/null +++ b/chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_INPUT_WINDOW_DIALOG_CONTROLLER_H_ +#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_INPUT_WINDOW_DIALOG_CONTROLLER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/bookmarks/base_bookmark_model_observer.h" +#include "chrome/browser/bookmarks/bookmark_editor.h" +#include "chrome/browser/ui/input_window_dialog.h" +#include "ui/gfx/native_widget_types.h" + +class Profile; + +// BookmarkInputWindowDialogController manages the editing and/or creation of a +// bookmark page or a bookmark folder. If the user presses ok, the name change +// is committed to the model. +// +// BookmarkInputWindowDialogController deletes itself when the window is closed. +class BookmarkInputWindowDialogController : public InputWindowDialog::Delegate, + public BaseBookmarkModelObserver { + public: + virtual ~BookmarkInputWindowDialogController(); + + static void Show(Profile* profile, + gfx::NativeWindow wnd, + const BookmarkEditor::EditDetails& details); + + private: + BookmarkInputWindowDialogController( + Profile* profile, + gfx::NativeWindow wnd, + const BookmarkEditor::EditDetails& details); + + // InputWindowDialog::Delegate: + virtual bool IsValid(const InputWindowDialog::InputTexts& texts) OVERRIDE; + virtual void InputAccepted( + const InputWindowDialog::InputTexts& texts) OVERRIDE; + virtual void InputCanceled() OVERRIDE; + + // BaseBookmarkModelObserver: + virtual void BookmarkModelChanged() OVERRIDE; + virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE; + + BookmarkModel* model_; + + BookmarkEditor::EditDetails details_; + + InputWindowDialog* dialog_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkInputWindowDialogController); +}; + +#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_INPUT_WINDOW_DIALOG_CONTROLLER_H_ diff --git a/chrome/browser/ui/input_window_dialog.h b/chrome/browser/ui/input_window_dialog.h new file mode 100644 index 0000000..f692569 --- /dev/null +++ b/chrome/browser/ui/input_window_dialog.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_H_ +#define CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_H_ +#pragma once + +#include <vector> + +#include "base/basictypes.h" +#include "base/string16.h" +#include "ui/gfx/native_widget_types.h" + +// Cross platform access to a modal input window. +class InputWindowDialog { + public: + enum ButtonType { + BUTTON_TYPE_ADD, + BUTTON_TYPE_SAVE, + }; + typedef std::vector<std::pair<string16, string16> > LabelContentsPairs; + typedef std::vector<string16> InputTexts; + + class Delegate { + public: + virtual ~Delegate() {} + + // Checks whether |text| is a valid input string. + virtual bool IsValid(const InputTexts& texts) = 0; + + // Callback for when the user clicks the OK button. + virtual void InputAccepted(const InputTexts& texts) = 0; + + // Callback for when the user clicks the Cancel button. + virtual void InputCanceled() = 0; + }; + + // Creates a new input window dialog parented to |parent|. Ownership of + // |delegate| is taken by InputWindowDialog or InputWindowDialog's owner. + static InputWindowDialog* Create( + gfx::NativeWindow parent, + const string16& window_title, + const LabelContentsPairs& label_contents_pairs, + Delegate* delegate, + ButtonType type); + + // Displays the window. + virtual void Show() = 0; + + // Closes the window. + virtual void Close() = 0; + + protected: + InputWindowDialog() {} + virtual ~InputWindowDialog() {} + + private: + DISALLOW_COPY_AND_ASSIGN(InputWindowDialog); +}; + +#endif // CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_H_ diff --git a/chrome/browser/ui/input_window_dialog_gtk.cc b/chrome/browser/ui/input_window_dialog_gtk.cc new file mode 100644 index 0000000..5abb3b2 --- /dev/null +++ b/chrome/browser/ui/input_window_dialog_gtk.cc @@ -0,0 +1,109 @@ +// 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 "chrome/browser/ui/input_window_dialog_gtk.h" + +#include <gtk/gtk.h> +#include "base/message_loop.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/ui/gtk/gtk_util.h" +#include "ui/base/gtk/gtk_signal.h" + +InputWindowDialogGtk::InputWindowDialogGtk(GtkWindow* parent, + const std::string& window_title, + const std::string& label, + const std::string& contents, + Delegate* delegate, + ButtonType type) + : dialog_(gtk_dialog_new_with_buttons( + window_title.c_str(), + parent, + GTK_DIALOG_MODAL, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + type == BUTTON_TYPE_ADD ? GTK_STOCK_ADD : GTK_STOCK_SAVE, + GTK_RESPONSE_ACCEPT, + NULL)), + delegate_(delegate) { + gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT); +#if !GTK_CHECK_VERSION(2, 22, 0) + gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE); +#endif + gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); + + GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_)); + gtk_box_set_spacing(GTK_BOX(content_area), 18); + + GtkWidget* hbox = gtk_hbox_new(FALSE, 6); + GtkWidget* label_widget = gtk_label_new(label.c_str()); + gtk_box_pack_start(GTK_BOX(hbox), label_widget, FALSE, FALSE, 0); + + input_ = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(input_), contents.c_str()); + g_signal_connect(input_, "changed", + G_CALLBACK(OnEntryChangedThunk), this); + g_object_set(G_OBJECT(input_), "activates-default", TRUE, NULL); + gtk_box_pack_start(GTK_BOX(hbox), input_, TRUE, TRUE, 0); + + gtk_widget_show_all(hbox); + + gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0); + + g_signal_connect(dialog_, "response", + G_CALLBACK(OnResponseThunk), this); + g_signal_connect(dialog_, "delete-event", + G_CALLBACK(OnWindowDeleteEventThunk), this); + g_signal_connect(dialog_, "destroy", + G_CALLBACK(OnWindowDestroyThunk), this); +} + +InputWindowDialogGtk::~InputWindowDialogGtk() { +} + +void InputWindowDialogGtk::Show() { + gtk_util::ShowDialog(dialog_); +} + +void InputWindowDialogGtk::Close() { + // Under the model that we've inherited from Windows, dialogs can receive + // more than one Close() call inside the current message loop event. + if (dialog_) { + gtk_widget_destroy(dialog_); + dialog_ = NULL; + } +} + +void InputWindowDialogGtk::OnEntryChanged(GtkEditable* entry) { + string16 value(UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(entry)))); + InputWindowDialog::InputTexts texts; + texts.push_back(value); + gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), + GTK_RESPONSE_ACCEPT, + delegate_->IsValid(texts)); +} + +void InputWindowDialogGtk::OnResponse(GtkWidget* dialog, int response_id) { + if (response_id == GTK_RESPONSE_ACCEPT) { + string16 value(UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(input_)))); + InputTexts texts; + texts.push_back(value); + delegate_->InputAccepted(texts); + } else { + delegate_->InputCanceled(); + } + Close(); +} + +gboolean InputWindowDialogGtk::OnWindowDeleteEvent(GtkWidget* widget, + GdkEvent* event) { + Close(); + + // Return true to prevent the gtk dialog from being destroyed. Close will + // destroy it for us and the default gtk_dialog_delete_event_handler() will + // force the destruction without us being able to stop it. + return TRUE; +} + +void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) { + MessageLoop::current()->DeleteSoon(FROM_HERE, this); +} diff --git a/chrome/browser/ui/input_window_dialog_gtk.h b/chrome/browser/ui/input_window_dialog_gtk.h new file mode 100644 index 0000000..ef11187 --- /dev/null +++ b/chrome/browser/ui/input_window_dialog_gtk.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_GTK_H_ +#define CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_GTK_H_ +#pragma once + +#include <gtk/gtk.h> + +#include <string> + +#include "base/compiler_specific.h" +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/input_window_dialog.h" +#include "ui/base/gtk/gtk_signal.h" + +class InputWindowDialogGtk : public InputWindowDialog { + public: + // Creates a dialog. Takes ownership of |delegate|. + InputWindowDialogGtk(GtkWindow* parent, + const std::string& window_title, + const std::string& label, + const std::string& contents, + Delegate* delegate, + ButtonType type); + virtual ~InputWindowDialogGtk(); + + virtual void Show() OVERRIDE; + virtual void Close() OVERRIDE; + + private: + CHROMEG_CALLBACK_0(InputWindowDialogGtk, void, OnEntryChanged, GtkEditable*); + CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, void, OnResponse, int); + CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, gboolean, + OnWindowDeleteEvent, GdkEvent*); + CHROMEGTK_CALLBACK_0(InputWindowDialogGtk, void, OnWindowDestroy); + + // The underlying gtk dialog window. + GtkWidget* dialog_; + + // The GtkEntry in this form. + GtkWidget* input_; + + // Our delegate. Consumes the window's output. + scoped_ptr<InputWindowDialog::Delegate> delegate_; + + DISALLOW_COPY_AND_ASSIGN(InputWindowDialogGtk); +}; + +#endif // CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_GTK_H_ diff --git a/chrome/browser/ui/input_window_dialog_linux.cc b/chrome/browser/ui/input_window_dialog_linux.cc new file mode 100644 index 0000000..4a91ce3 --- /dev/null +++ b/chrome/browser/ui/input_window_dialog_linux.cc @@ -0,0 +1,23 @@ +// 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 "chrome/browser/ui/input_window_dialog.h" + +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/ui/input_window_dialog_gtk.h" + +InputWindowDialog* InputWindowDialog::Create( + gfx::NativeWindow parent, + const string16& window_title, + const LabelContentsPairs& label_contents_pairs, + Delegate* delegate, + ButtonType type) { + return new InputWindowDialogGtk(parent, + UTF16ToUTF8(window_title), + UTF16ToUTF8(label_contents_pairs[0].first), + UTF16ToUTF8(label_contents_pairs[0].second), + delegate, + type); +} diff --git a/chrome/browser/ui/input_window_dialog_views.cc b/chrome/browser/ui/input_window_dialog_views.cc new file mode 100644 index 0000000..a7bd9f74 --- /dev/null +++ b/chrome/browser/ui/input_window_dialog_views.cc @@ -0,0 +1,274 @@ +// 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 "chrome/browser/ui/input_window_dialog.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop.h" +#include "base/utf_string_conversions.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/controls/textfield/textfield_controller.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/layout/layout_constants.h" +#include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" + +namespace { + +// Width of the text field, in pixels. +const int kTextfieldWidth = 200; + +} // namespace + +// The Views implementation of the cross platform input dialog interface. +class InputWindowDialogViews : public InputWindowDialog { + public: + InputWindowDialogViews(gfx::NativeWindow parent, + const string16& window_title, + const string16& label, + const string16& contents, + Delegate* delegate, + ButtonType type); + virtual ~InputWindowDialogViews(); + + // Overridden from InputWindowDialog: + virtual void Show() OVERRIDE; + virtual void Close() OVERRIDE; + + const string16& window_title() const { return window_title_; } + const string16& label() const { return label_; } + const string16& contents() const { return contents_; } + + Delegate* delegate() { return delegate_.get(); } + ButtonType type() const { return type_; } + + private: + // Our chrome views window. + views::Widget* window_; + + // Strings to feed to the on screen window. + string16 window_title_; + string16 label_; + string16 contents_; + + // Our delegate. Consumes the window's output. + scoped_ptr<InputWindowDialog::Delegate> delegate_; + const ButtonType type_; + + DISALLOW_COPY_AND_ASSIGN(InputWindowDialogViews); +}; + +// ContentView, as the name implies, is the content view for the InputWindow. +// It registers accelerators that accept/cancel the input. +class ContentView : public views::DialogDelegateView, + public views::TextfieldController { + public: + explicit ContentView(InputWindowDialogViews* delegate); + + // views::DialogDelegateView: + virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; + virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE; + virtual bool Accept() OVERRIDE; + virtual bool Cancel() OVERRIDE; + virtual void DeleteDelegate() OVERRIDE; + virtual string16 GetWindowTitle() const OVERRIDE; + virtual ui::ModalType GetModalType() const OVERRIDE; + virtual views::View* GetContentsView() OVERRIDE; + + // views::TextfieldController: + virtual void ContentsChanged(views::Textfield* sender, + const string16& new_contents) OVERRIDE; + virtual bool HandleKeyEvent(views::Textfield*, + const views::KeyEvent&) OVERRIDE; + + protected: + // views::View: + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) OVERRIDE; + + 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. + InputWindowDialogViews* delegate_; + + // Helps us set focus to the first Textfield in the window. + base::WeakPtrFactory<ContentView> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ContentView); +}; + +/////////////////////////////////////////////////////////////////////////////// +// ContentView +ContentView::ContentView(InputWindowDialogViews* delegate) + : delegate_(delegate), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { + DCHECK(delegate_); +} + +/////////////////////////////////////////////////////////////////////////////// +// ContentView, views::DialogDelegate implementation: + +string16 ContentView::GetDialogButtonLabel(ui::DialogButton button) const { + if (button == ui::DIALOG_BUTTON_OK) { + return l10n_util::GetStringUTF16( + delegate_->type() == InputWindowDialog::BUTTON_TYPE_ADD ? IDS_ADD + : IDS_SAVE); + } + return string16(); +} + +bool ContentView::IsDialogButtonEnabled(ui::DialogButton button) const { + if (button == ui::DIALOG_BUTTON_OK) { + InputWindowDialog::InputTexts texts; + texts.push_back(text_field_->text()); + if (!delegate_->delegate()->IsValid(texts)) { + return false; + } + } + return true; +} + +bool ContentView::Accept() { + InputWindowDialog::InputTexts texts; + texts.push_back(text_field_->text()); + delegate_->delegate()->InputAccepted(texts); + delegate_->Close(); + return true; +} + +bool ContentView::Cancel() { + delegate_->delegate()->InputCanceled(); + return true; +} + +void ContentView::DeleteDelegate() { + delete delegate_; +} + +string16 ContentView::GetWindowTitle() const { + return delegate_->window_title(); +} + +ui::ModalType ContentView::GetModalType() const { + return ui::MODAL_TYPE_WINDOW; +} + +views::View* ContentView::GetContentsView() { + return this; +} + +/////////////////////////////////////////////////////////////////////////////// +// ContentView, views::TextfieldController implementation: + +void ContentView::ContentsChanged(views::Textfield* sender, + const string16& new_contents) { + GetDialogClientView()->UpdateDialogButtons(); +} + +bool ContentView::HandleKeyEvent(views::Textfield*, + const views::KeyEvent&) { + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// 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); + + // TODO(sky): Vertical alignment should be baseline. + views::GridLayout* layout = views::GridLayout::CreatePanel(this); + SetLayoutManager(layout); + + views::ColumnSet* c1 = layout->AddColumnSet(0); + c1->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + c1->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); + c1->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 1, + views::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, base::Bind(&ContentView::FocusFirstFocusableControl, + weak_factory_.GetWeakPtr())); +} + +void ContentView::FocusFirstFocusableControl() { + text_field_->SelectAll(); + text_field_->RequestFocus(); +} + +InputWindowDialogViews::InputWindowDialogViews(gfx::NativeWindow parent, + const string16& window_title, + const string16& label, + const string16& contents, + Delegate* delegate, + ButtonType type) + : window_title_(window_title), + label_(label), + contents_(contents), + delegate_(delegate), + type_(type) { + window_ = views::Widget::CreateWindowWithParent(new ContentView(this), + parent); + window_->client_view()->AsDialogClientView()->UpdateDialogButtons(); +} + +InputWindowDialogViews::~InputWindowDialogViews() { +} + +void InputWindowDialogViews::Show() { + window_->Show(); +} + +void InputWindowDialogViews::Close() { + window_->Close(); +} + +// static +InputWindowDialog* InputWindowDialog::Create( + gfx::NativeWindow parent, + const string16& window_title, + const LabelContentsPairs& label_contents_pairs, + Delegate* delegate, + ButtonType type) { + DCHECK_EQ(1U, label_contents_pairs.size()); + return new InputWindowDialogViews(parent, + window_title, + label_contents_pairs[0].first, + label_contents_pairs[0].second, + delegate, + type); +} diff --git a/chrome/browser/ui/views/bookmarks/bookmark_context_menu_controller_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_context_menu_controller_views.cc index 5659024..38587db 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_context_menu_controller_views.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_context_menu_controller_views.cc @@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/bookmarks/bookmark_editor.h" +#include "chrome/browser/bookmarks/bookmark_input_window_dialog_controller.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" @@ -132,11 +133,18 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) { return; } - BookmarkEditor::Show( - parent_widget_->GetNativeWindow(), - profile_, - BookmarkEditor::EditDetails::EditNode(selection_[0]), - BookmarkEditor::SHOW_TREE); + if (selection_[0]->is_url()) { + BookmarkEditor::Show( + parent_widget_->GetNativeWindow(), + profile_, + BookmarkEditor::EditDetails::EditNode(selection_[0]), + BookmarkEditor::SHOW_TREE); + } else { + BookmarkInputWindowDialogController::Show( + profile_, + parent_widget_->GetNativeWindow(), + BookmarkEditor::EditDetails::EditNode(selection_[0])); + } break; case IDC_BOOKMARK_BAR_REMOVE: { diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 5fbe3d6..20acc53 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -293,6 +293,8 @@ 'browser/bookmarks/bookmark_html_writer.h', 'browser/bookmarks/bookmark_index.cc', 'browser/bookmarks/bookmark_index.h', + 'browser/bookmarks/bookmark_input_window_dialog_controller.cc', + 'browser/bookmarks/bookmark_input_window_dialog_controller.h', 'browser/bookmarks/bookmark_model.cc', 'browser/bookmarks/bookmark_model.h', 'browser/bookmarks/bookmark_model_observer.h', @@ -3343,6 +3345,11 @@ 'browser/ui/gtk/view_id_util.h', 'browser/ui/gtk/web_intent_picker_gtk.cc', 'browser/ui/gtk/web_intent_picker_gtk.h', + 'browser/ui/input_window_dialog.h', + 'browser/ui/input_window_dialog_linux.cc', + 'browser/ui/input_window_dialog_gtk.cc', + 'browser/ui/input_window_dialog_gtk.h', + 'browser/ui/input_window_dialog_views.cc', 'browser/ui/intents/web_intent_inline_disposition_delegate.cc', 'browser/ui/intents/web_intent_inline_disposition_delegate.h', 'browser/ui/intents/web_intent_picker.cc', @@ -4545,6 +4552,7 @@ ['exclude', '^browser/renderer_host/render_widget_host_view_views*'], ['exclude', '^browser/tab_contents/web_drag_source_win.cc'], ['exclude', '^browser/tab_contents/web_drag_source_win.h'], + ['exclude', '^browser/ui/input_window_dialog_linux.cc'], ['exclude', '^browser/ui/panels/auto_hiding_desktop_bar_win.cc'], ['exclude', '^browser/ui/tabs/dock_info_win.cc'], ['exclude', '^browser/ui/views/about_ipc_dialog.cc'], |