From d0cc9fb540e7d11f8b154d513bf0a1c75460245c Mon Sep 17 00:00:00 2001 From: "ben@chromium.org" Date: Tue, 23 Jun 2009 02:26:16 +0000 Subject: Rejiggers the keyword editor so that the UI is independent of the model rather than being derived from it. This reduces the spaghetti somewhat. Also decouples the notion of a native view hierarchy from the location in TabContents::PageHasOSDD where the template URL fetcher is spawned. The Template URL Fetcher now simply retains a reference to the TabContents that created it. If the TabContents is destroyed before the fetch completes, we just discard the data retrieved without adding a keyword. BUG=none TEST=none Review URL: http://codereview.chromium.org/140054 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19003 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/browser.cc | 45 ++-- chrome/browser/browser.h | 18 +- chrome/browser/browser_window.h | 9 +- chrome/browser/cocoa/browser_window_cocoa.h | 2 + chrome/browser/cocoa/browser_window_cocoa.mm | 6 + chrome/browser/gtk/browser_window_gtk.cc | 6 + chrome/browser/gtk/browser_window_gtk.h | 2 + chrome/browser/gtk/edit_keyword_controller.cc | 252 ------------------- chrome/browser/gtk/edit_keyword_controller.h | 73 ------ chrome/browser/gtk/edit_search_engine_dialog.cc | 255 +++++++++++++++++++ chrome/browser/gtk/edit_search_engine_dialog.h | 77 ++++++ chrome/browser/gtk/keyword_editor_view.cc | 4 +- chrome/browser/gtk/keyword_editor_view.h | 6 +- .../search_engines/edit_keyword_controller_base.cc | 130 ---------- .../search_engines/edit_keyword_controller_base.h | 99 -------- .../edit_search_engine_controller.cc | 136 ++++++++++ .../search_engines/edit_search_engine_controller.h | 86 +++++++ .../browser/search_engines/template_url_fetcher.cc | 54 ++-- .../browser/search_engines/template_url_fetcher.h | 2 +- chrome/browser/tab_contents/tab_contents.cc | 3 +- .../browser/tab_contents/tab_contents_delegate.h | 14 +- chrome/browser/views/browser_dialogs.h | 11 + chrome/browser/views/edit_keyword_controller.cc | 273 --------------------- chrome/browser/views/edit_keyword_controller.h | 107 -------- chrome/browser/views/edit_search_engine_dialog.cc | 261 ++++++++++++++++++++ chrome/browser/views/edit_search_engine_dialog.h | 104 ++++++++ chrome/browser/views/frame/browser_view.cc | 6 + chrome/browser/views/frame/browser_view.h | 2 + chrome/browser/views/keyword_editor_view.cc | 14 +- chrome/browser/views/keyword_editor_view.h | 6 +- 30 files changed, 1057 insertions(+), 1006 deletions(-) delete mode 100644 chrome/browser/gtk/edit_keyword_controller.cc delete mode 100644 chrome/browser/gtk/edit_keyword_controller.h create mode 100644 chrome/browser/gtk/edit_search_engine_dialog.cc create mode 100644 chrome/browser/gtk/edit_search_engine_dialog.h delete mode 100644 chrome/browser/search_engines/edit_keyword_controller_base.cc delete mode 100644 chrome/browser/search_engines/edit_keyword_controller_base.h create mode 100644 chrome/browser/search_engines/edit_search_engine_controller.cc create mode 100644 chrome/browser/search_engines/edit_search_engine_controller.h delete mode 100644 chrome/browser/views/edit_keyword_controller.cc delete mode 100644 chrome/browser/views/edit_keyword_controller.h create mode 100644 chrome/browser/views/edit_search_engine_dialog.cc create mode 100644 chrome/browser/views/edit_search_engine_dialog.h (limited to 'chrome/browser') diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 4bf03ea..141356a 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1182,26 +1182,6 @@ void Browser::OpenHelpTab() { false, NULL); } -void Browser::OnStartDownload(DownloadItem* download) { - if (!window()) - return; - - // GetDownloadShelf creates the download shelf if it was not yet created. - window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download)); - -// TODO(port): port for mac. -#if defined(OS_WIN) || defined(OS_LINUX) - // Don't show the animation for "Save file" downloads. - if (download->total_bytes() > 0) { - TabContents* current_tab = GetSelectedTabContents(); - // We make this check for the case of minimized windows, unit tests, etc. - if (platform_util::IsVisible(current_tab->GetNativeView()) && - Animation::ShouldRenderRichAnimation()) - DownloadStartedAnimation::Show(current_tab); - } -#endif -} - /////////////////////////////////////////////////////////////////////////////// // static @@ -1957,6 +1937,31 @@ int Browser::GetExtraRenderViewHeight() const { return window_->GetExtraRenderViewHeight(); } +void Browser::OnStartDownload(DownloadItem* download) { + if (!window()) + return; + + // GetDownloadShelf creates the download shelf if it was not yet created. + window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download)); + +// TODO(port): port for mac. +#if defined(OS_WIN) || defined(OS_LINUX) + // Don't show the animation for "Save file" downloads. + if (download->total_bytes() > 0) { + TabContents* current_tab = GetSelectedTabContents(); + // We make this check for the case of minimized windows, unit tests, etc. + if (platform_util::IsVisible(current_tab->GetNativeView()) && + Animation::ShouldRenderRichAnimation()) + DownloadStartedAnimation::Show(current_tab); + } +#endif +} + +void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) { + window()->ConfirmAddSearchProvider(template_url, profile); +} + /////////////////////////////////////////////////////////////////////////////// // Browser, SelectFileDialog::Listener implementation: diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 666cc2cc..bdaf9f9 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -373,7 +373,6 @@ class Browser : public TabStripModelDelegate, void OpenAboutChromeDialog(); void OpenHelpTab(); - virtual void OnStartDownload(DownloadItem* download); virtual void UpdateDownloadShelfVisibility(bool visible); ///////////////////////////////////////////////////////////////////////////// @@ -471,29 +470,28 @@ class Browser : public TabStripModelDelegate, virtual bool IsPopup(TabContents* source); virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); virtual void URLStarredChanged(TabContents* source, bool starred); - - // A mouse event occurred; motion==true is mouse movement, motion==false - // is the mouse leaving the view. - virtual void ContentsMouseEvent(TabContents* source, bool motion); virtual void UpdateTargetURL(TabContents* source, const GURL& url); - + virtual void ContentsMouseEvent(TabContents* source, bool motion); virtual void ContentsZoomChange(bool zoom_in); virtual void TabContentsFocused(TabContents* tab_content); virtual bool IsApplication() const; virtual void ConvertContentsToApplication(TabContents* source); virtual bool ShouldDisplayURLField(); - virtual void BeforeUnloadFired(TabContents* source, - bool proceed, - bool* proceed_to_fire_unload); virtual gfx::Rect GetRootWindowResizerRect() const; virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate, gfx::NativeWindow parent_window); + virtual void BeforeUnloadFired(TabContents* source, + bool proceed, + bool* proceed_to_fire_unload); virtual void SetFocusToLocationBar(); virtual void RenderWidgetShowing(); - virtual ExtensionFunctionDispatcher *CreateExtensionFunctionDispatcher( + virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher( RenderViewHost* render_view_host, const std::string& extension_id); virtual int GetExtraRenderViewHeight() const; + virtual void OnStartDownload(DownloadItem* download); + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile); // Overridden from SelectFileDialog::Listener: virtual void FileSelected(const FilePath& path, int index, void* params); diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index d11db56..2c558aa 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -12,11 +12,13 @@ class BrowserWindowTesting; class DownloadShelf; class FindBar; class GURL; -class LocationBar; class HtmlDialogUIDelegate; +class LocationBar; +class Profile; class StatusBubble; class TabContents; class TabContentsContainer; +class TemplateURL; namespace gfx { class Rect; @@ -129,6 +131,11 @@ class BrowserWindow { // provided here since the functionality is Windows-specific. virtual void DisableInactiveFrame() {} + // Shows a confirmation dialog box for adding a search engine described by + // |template_url|. + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) = 0; + // Shows or hides the bookmark bar depending on its current visibility. virtual void ToggleBookmarkBar() = 0; diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h index 047a73e..9a332ff 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.h +++ b/chrome/browser/cocoa/browser_window_cocoa.h @@ -53,6 +53,8 @@ class BrowserWindowCocoa : public BrowserWindow, virtual void FocusToolbar(); virtual bool IsBookmarkBarVisible() const; virtual gfx::Rect GetRootWindowResizerRect() const; + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile); virtual void ToggleBookmarkBar(); virtual void ShowAboutChromeDialog(); virtual void ShowTaskManager(); diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index 047dffc..1f7c799 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -136,6 +136,12 @@ gfx::Rect BrowserWindowCocoa::GetRootWindowResizerRect() const { return gfx::Rect(NSRectToCGRect(tabRect)); } +void BrowserWindowCocoa::ConfirmAddSearchProvider( + const TemplateURL* template_url, + Profile* profile) { + NOTIMPLEMENTED(); +} + LocationBar* BrowserWindowCocoa::GetLocationBar() const { return [controller_ locationBar]; } diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index dba4d27..a1d8f2a 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -30,6 +30,7 @@ #include "chrome/browser/gtk/browser_toolbar_gtk.h" #include "chrome/browser/gtk/clear_browsing_data_dialog_gtk.h" #include "chrome/browser/gtk/download_shelf_gtk.h" +#include "chrome/browser/gtk/edit_search_engine_dialog.h" #include "chrome/browser/gtk/find_bar_gtk.h" #include "chrome/browser/gtk/go_button_gtk.h" #include "chrome/browser/gtk/import_dialog_gtk.h" @@ -606,6 +607,11 @@ gfx::Rect BrowserWindowGtk::GetRootWindowResizerRect() const { return gfx::Rect(); } +void BrowserWindowGtk::ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) { + new EditSearchEngineDialog(window_, template_url, NULL, profile); +} + void BrowserWindowGtk::ToggleBookmarkBar() { bookmark_utils::ToggleWhenVisible(browser_->profile()); } diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h index e0bbc47..1ed5439 100644 --- a/chrome/browser/gtk/browser_window_gtk.h +++ b/chrome/browser/gtk/browser_window_gtk.h @@ -73,6 +73,8 @@ class BrowserWindowGtk : public BrowserWindow, virtual void FocusToolbar(); virtual bool IsBookmarkBarVisible() const; virtual gfx::Rect GetRootWindowResizerRect() const; + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile); virtual void ToggleBookmarkBar(); virtual void ShowAboutChromeDialog(); virtual void ShowTaskManager(); diff --git a/chrome/browser/gtk/edit_keyword_controller.cc b/chrome/browser/gtk/edit_keyword_controller.cc deleted file mode 100644 index a43e555..0000000 --- a/chrome/browser/gtk/edit_keyword_controller.cc +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (c) 2009 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/gtk/edit_keyword_controller.h" - -#include - -#include "app/l10n_util.h" -#include "app/resource_bundle.h" -#include "base/string_util.h" -#include "chrome/browser/net/url_fixer_upper.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" -#include "chrome/common/gtk_util.h" -#include "googleurl/src/gurl.h" -#include "grit/app_resources.h" -#include "grit/generated_resources.h" -#include "grit/theme_resources.h" - -namespace { - -std::string GetDisplayURL(const TemplateURL& turl) { - return turl.url() ? WideToUTF8(turl.url()->DisplayURL()) : std::string(); -} - -GtkWidget* CreateEntryImageHBox(GtkWidget* entry, GtkWidget* image) { - GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); - gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); - return hbox; -} - -// Forces text to lowercase when connected to an editable's "insert-text" -// signal. (Like views Textfield::STYLE_LOWERCASE.) -void LowercaseInsertTextHandler(GtkEditable *editable, const gchar *text, - gint length, gint *position, gpointer data) { - string16 original_text = UTF8ToUTF16(text); - string16 lower_text = l10n_util::ToLower(original_text); - if (lower_text != original_text) { - std::string result = UTF16ToUTF8(lower_text); - // Prevent ourselves getting called recursively about our own edit. - g_signal_handlers_block_by_func(G_OBJECT(editable), - reinterpret_cast(LowercaseInsertTextHandler), data); - gtk_editable_insert_text(editable, result.c_str(), result.size(), position); - g_signal_handlers_unblock_by_func(G_OBJECT(editable), - reinterpret_cast(LowercaseInsertTextHandler), data); - // We've inserted our modified version, stop the defalut handler from - // inserting the original. - g_signal_stop_emission_by_name(G_OBJECT(editable), "insert_text"); - } -} - -} // namespace - -// static -void EditKeywordControllerBase::Create(gfx::NativeWindow parent_window, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile) { - new EditKeywordController(parent_window, template_url, delegate, profile); -} - -EditKeywordController::EditKeywordController( - GtkWindow* parent_window, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile) - : EditKeywordControllerBase(template_url, delegate, profile) { - Init(parent_window); -} - -void EditKeywordController::Init(GtkWindow* parent_window) { - dialog_ = gtk_dialog_new_with_buttons( - l10n_util::GetStringUTF8( - template_url() ? - IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE : - IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE).c_str(), - parent_window, - static_cast(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - NULL); - - ok_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_), - GTK_STOCK_OK, GTK_RESPONSE_OK); - gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK); - - // The dialog layout hierarchy looks like this: - // - // \ GtkVBox |dialog_->vbox| - // +-\ GtkTable |controls| - // | +-\ row 0 - // | | +- GtkLabel - // | | +-\ GtkHBox - // | | +- GtkEntry |title_entry_| - // | | +- GtkImage |title_image_| - // | +-\ row 1 - // | | +- GtkLabel - // | | +-\ GtkHBox - // | | +- GtkEntry |keyword_entry_| - // | | +- GtkImage |keyword_image_| - // | +-\ row 2 - // | +- GtkLabel - // | +-\ GtkHBox - // | +- GtkEntry |url_entry_| - // | +- GtkImage |url_image_| - // +- GtkLabel |description_label| - - title_entry_ = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(title_entry_), TRUE); - g_signal_connect(G_OBJECT(title_entry_), "changed", - G_CALLBACK(OnEntryChanged), this); - - keyword_entry_ = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(keyword_entry_), TRUE); - g_signal_connect(G_OBJECT(keyword_entry_), "changed", - G_CALLBACK(OnEntryChanged), this); - g_signal_connect(G_OBJECT(keyword_entry_), "insert-text", - G_CALLBACK(LowercaseInsertTextHandler), NULL); - - url_entry_ = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE); - g_signal_connect(G_OBJECT(url_entry_), "changed", - G_CALLBACK(OnEntryChanged), this); - - title_image_ = gtk_image_new_from_pixbuf(NULL); - keyword_image_ = gtk_image_new_from_pixbuf(NULL); - url_image_ = gtk_image_new_from_pixbuf(NULL); - - if (template_url()) { - gtk_entry_set_text(GTK_ENTRY(title_entry_), - WideToUTF8(template_url()->short_name()).c_str()); - gtk_entry_set_text(GTK_ENTRY(keyword_entry_), - WideToUTF8(template_url()->keyword()).c_str()); - gtk_entry_set_text(GTK_ENTRY(url_entry_), - GetDisplayURL(*template_url()).c_str()); - // We don't allow users to edit prepopulated URLs. - gtk_editable_set_editable(GTK_EDITABLE(url_entry_), - template_url()->prepopulate_id() == 0); - } - - GtkWidget* controls = gtk_util::CreateLabeledControlsGroup( - l10n_util::GetStringUTF8( - IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_LABEL).c_str(), - CreateEntryImageHBox(title_entry_, title_image_), - l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_LABEL).c_str(), - CreateEntryImageHBox(keyword_entry_, keyword_image_), - l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_URL_LABEL).c_str(), - CreateEntryImageHBox(url_entry_, url_image_), - NULL); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), controls, - FALSE, FALSE, 0); - - // On RTL UIs (such as Arabic and Hebrew) the description text is not - // displayed correctly since it contains the substring "%s". This substring - // is not interpreted by the Unicode BiDi algorithm as an LTR string and - // therefore the end result is that the following right to left text is - // displayed: ".three two s% one" (where 'one', 'two', etc. are words in - // Hebrew). - // - // In order to fix this problem we transform the substring "%s" so that it - // is displayed correctly when rendered in an RTL context. - std::string description = - l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_URL_DESCRIPTION_LABEL); - if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { - const std::string reversed_percent("s%"); - std::wstring::size_type percent_index = - description.find("%s", static_cast(0)); - if (percent_index != std::string::npos) - description.replace(percent_index, - reversed_percent.length(), - reversed_percent); - } - - GtkWidget* description_label = gtk_label_new(description.c_str()); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), description_label, - FALSE, FALSE, 0); - - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), - gtk_util::kContentAreaSpacing); - - EnableControls(); - - gtk_widget_show_all(dialog_); - - g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); - g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroy), this); -} - -std::wstring EditKeywordController::GetURLInput() const { - return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(url_entry_))); -} - -std::wstring EditKeywordController::GetKeywordInput() const { - return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(keyword_entry_))); -} - -std::wstring EditKeywordController::GetTitleInput() const { - return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(title_entry_))); -} - -void EditKeywordController::EnableControls() { - gtk_widget_set_sensitive(ok_button_, - IsKeywordValid() && IsTitleValid() && IsURLValid()); - UpdateImage(keyword_image_, IsKeywordValid(), - IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT); - UpdateImage(url_image_, IsURLValid(), IDS_SEARCH_ENGINES_INVALID_URL_TT); - UpdateImage(title_image_, IsTitleValid(), - IDS_SEARCH_ENGINES_INVALID_TITLE_TT); -} - -void EditKeywordController::UpdateImage(GtkWidget* image, - bool is_valid, - int invalid_message_id) { - if (is_valid) { - gtk_widget_set_has_tooltip(image, FALSE); - gtk_image_set_from_pixbuf(GTK_IMAGE(image), - ResourceBundle::GetSharedInstance().GetPixbufNamed( - IDR_INPUT_GOOD)); - } else { - gtk_widget_set_tooltip_text( - image, l10n_util::GetStringUTF8(invalid_message_id).c_str()); - gtk_image_set_from_pixbuf(GTK_IMAGE(image), - ResourceBundle::GetSharedInstance().GetPixbufNamed( - IDR_INPUT_ALERT)); - } -} - -// static -void EditKeywordController::OnEntryChanged( - GtkEditable* editable, EditKeywordController* window) { - window->EnableControls(); -} - -// static -void EditKeywordController::OnResponse(GtkDialog* dialog, int response_id, - EditKeywordController* window) { - if (response_id == GTK_RESPONSE_OK) { - window->AcceptAddOrEdit(); - } else { - window->CleanUpCancelledAdd(); - } - gtk_widget_destroy(window->dialog_); -} - -// static -void EditKeywordController::OnWindowDestroy( - GtkWidget* widget, EditKeywordController* window) { - MessageLoop::current()->DeleteSoon(FROM_HERE, window); -} diff --git a/chrome/browser/gtk/edit_keyword_controller.h b/chrome/browser/gtk/edit_keyword_controller.h deleted file mode 100644 index 86dc525..0000000 --- a/chrome/browser/gtk/edit_keyword_controller.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2009 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_GTK_EDIT_KEYWORD_CONTROLLER_H_ -#define CHROME_BROWSER_GTK_EDIT_KEYWORD_CONTROLLER_H_ - -#include - -#include "base/basictypes.h" -#include "chrome/browser/search_engines/edit_keyword_controller_base.h" - -class Profile; -class TemplateURL; - -class EditKeywordController : public EditKeywordControllerBase { - public: - EditKeywordController(GtkWindow* parent_window, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile); - - protected: - // EditKeywordControllerBase overrides - virtual std::wstring GetURLInput() const; - virtual std::wstring GetKeywordInput() const; - virtual std::wstring GetTitleInput() const; - - private: - // Create and show the window. - void Init(GtkWindow* parent_window); - - // Set sensitivity of buttons based on entry state. - void EnableControls(); - - // Updates the tooltip and image of the image view based on is_valid. If - // is_valid is false the tooltip of the image view is set to the message with - // id invalid_message_id, otherwise the tooltip is set to the empty text. - void UpdateImage(GtkWidget* image, bool is_valid, int invalid_message_id); - - // Callback for entry changes. - static void OnEntryChanged(GtkEditable* editable, - EditKeywordController* window); - - // Callback for dialog buttons. - static void OnResponse(GtkDialog* dialog, int response_id, - EditKeywordController* window); - - // Callback for window destruction. - static void OnWindowDestroy(GtkWidget* widget, - EditKeywordController* window); - - // The dialog window. - GtkWidget* dialog_; - - // Text entries for each field. - GtkWidget* title_entry_; - GtkWidget* keyword_entry_; - GtkWidget* url_entry_; - - // Images showing whether each entry is okay or has errors. - GtkWidget* title_image_; - GtkWidget* keyword_image_; - GtkWidget* url_image_; - - // The ok button (we need a reference to it so we can de-activate it when the - // entries are not all filled in.) - GtkWidget* ok_button_; - - DISALLOW_COPY_AND_ASSIGN(EditKeywordController); -}; - -#endif // CHROME_BROWSER_GTK_EDIT_KEYWORD_CONTROLLER_GTK_H_ diff --git a/chrome/browser/gtk/edit_search_engine_dialog.cc b/chrome/browser/gtk/edit_search_engine_dialog.cc new file mode 100644 index 0000000..40f3cc7 --- /dev/null +++ b/chrome/browser/gtk/edit_search_engine_dialog.cc @@ -0,0 +1,255 @@ +// Copyright (c) 2009 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/gtk/edit_search_engine_dialog.h" + +#include + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/string_util.h" +#include "chrome/browser/net/url_fixer_upper.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/search_engines/edit_search_engine_controller.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/common/gtk_util.h" +#include "googleurl/src/gurl.h" +#include "grit/app_resources.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" + +namespace { + +std::string GetDisplayURL(const TemplateURL& turl) { + return turl.url() ? WideToUTF8(turl.url()->DisplayURL()) : std::string(); +} + +GtkWidget* CreateEntryImageHBox(GtkWidget* entry, GtkWidget* image) { + GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); + return hbox; +} + +// Forces text to lowercase when connected to an editable's "insert-text" +// signal. (Like views Textfield::STYLE_LOWERCASE.) +void LowercaseInsertTextHandler(GtkEditable *editable, const gchar *text, + gint length, gint *position, gpointer data) { + string16 original_text = UTF8ToUTF16(text); + string16 lower_text = l10n_util::ToLower(original_text); + if (lower_text != original_text) { + std::string result = UTF16ToUTF8(lower_text); + // Prevent ourselves getting called recursively about our own edit. + g_signal_handlers_block_by_func(G_OBJECT(editable), + reinterpret_cast(LowercaseInsertTextHandler), data); + gtk_editable_insert_text(editable, result.c_str(), result.size(), position); + g_signal_handlers_unblock_by_func(G_OBJECT(editable), + reinterpret_cast(LowercaseInsertTextHandler), data); + // We've inserted our modified version, stop the defalut handler from + // inserting the original. + g_signal_stop_emission_by_name(G_OBJECT(editable), "insert_text"); + } +} + +} // namespace + +EditSearchEngineDialog::EditSearchEngineDialog( + GtkWindow* parent_window, + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile) + : controller_(new EditSearchEngineController(template_url, delegate, + profile)) { + Init(parent_window); +} + +void EditSearchEngineDialog::Init(GtkWindow* parent_window) { + dialog_ = gtk_dialog_new_with_buttons( + l10n_util::GetStringUTF8( + controller_->template_url() ? + IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE : + IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE).c_str(), + parent_window, + static_cast(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + NULL); + + ok_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_), + GTK_STOCK_OK, GTK_RESPONSE_OK); + gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK); + + // The dialog layout hierarchy looks like this: + // + // \ GtkVBox |dialog_->vbox| + // +-\ GtkTable |controls| + // | +-\ row 0 + // | | +- GtkLabel + // | | +-\ GtkHBox + // | | +- GtkEntry |title_entry_| + // | | +- GtkImage |title_image_| + // | +-\ row 1 + // | | +- GtkLabel + // | | +-\ GtkHBox + // | | +- GtkEntry |keyword_entry_| + // | | +- GtkImage |keyword_image_| + // | +-\ row 2 + // | +- GtkLabel + // | +-\ GtkHBox + // | +- GtkEntry |url_entry_| + // | +- GtkImage |url_image_| + // +- GtkLabel |description_label| + + title_entry_ = gtk_entry_new(); + gtk_entry_set_activates_default(GTK_ENTRY(title_entry_), TRUE); + g_signal_connect(G_OBJECT(title_entry_), "changed", + G_CALLBACK(OnEntryChanged), this); + + keyword_entry_ = gtk_entry_new(); + gtk_entry_set_activates_default(GTK_ENTRY(keyword_entry_), TRUE); + g_signal_connect(G_OBJECT(keyword_entry_), "changed", + G_CALLBACK(OnEntryChanged), this); + g_signal_connect(G_OBJECT(keyword_entry_), "insert-text", + G_CALLBACK(LowercaseInsertTextHandler), NULL); + + url_entry_ = gtk_entry_new(); + gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE); + g_signal_connect(G_OBJECT(url_entry_), "changed", + G_CALLBACK(OnEntryChanged), this); + + title_image_ = gtk_image_new_from_pixbuf(NULL); + keyword_image_ = gtk_image_new_from_pixbuf(NULL); + url_image_ = gtk_image_new_from_pixbuf(NULL); + + if (controller_->template_url()) { + gtk_entry_set_text( + GTK_ENTRY(title_entry_), + WideToUTF8(controller_->template_url()->short_name()).c_str()); + gtk_entry_set_text( + GTK_ENTRY(keyword_entry_), + WideToUTF8(controller_->template_url()->keyword()).c_str()); + gtk_entry_set_text( + GTK_ENTRY(url_entry_), + GetDisplayURL(*controller_->template_url()).c_str()); + // We don't allow users to edit prepopulated URLs. + gtk_editable_set_editable( + GTK_EDITABLE(url_entry_), + controller_->template_url()->prepopulate_id() == 0); + } + + GtkWidget* controls = gtk_util::CreateLabeledControlsGroup( + l10n_util::GetStringUTF8( + IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_LABEL).c_str(), + CreateEntryImageHBox(title_entry_, title_image_), + l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_LABEL).c_str(), + CreateEntryImageHBox(keyword_entry_, keyword_image_), + l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_URL_LABEL).c_str(), + CreateEntryImageHBox(url_entry_, url_image_), + NULL); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), controls, + FALSE, FALSE, 0); + + // On RTL UIs (such as Arabic and Hebrew) the description text is not + // displayed correctly since it contains the substring "%s". This substring + // is not interpreted by the Unicode BiDi algorithm as an LTR string and + // therefore the end result is that the following right to left text is + // displayed: ".three two s% one" (where 'one', 'two', etc. are words in + // Hebrew). + // + // In order to fix this problem we transform the substring "%s" so that it + // is displayed correctly when rendered in an RTL context. + std::string description = + l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_URL_DESCRIPTION_LABEL); + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { + const std::string reversed_percent("s%"); + std::wstring::size_type percent_index = + description.find("%s", static_cast(0)); + if (percent_index != std::string::npos) + description.replace(percent_index, + reversed_percent.length(), + reversed_percent); + } + + GtkWidget* description_label = gtk_label_new(description.c_str()); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), description_label, + FALSE, FALSE, 0); + + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), + gtk_util::kContentAreaSpacing); + + EnableControls(); + + gtk_widget_show_all(dialog_); + + g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); + g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroy), this); +} + +std::wstring EditSearchEngineDialog::GetTitleInput() const { + return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(title_entry_))); +} + +std::wstring EditSearchEngineDialog::GetKeywordInput() const { + return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(keyword_entry_))); +} + +std::wstring EditSearchEngineDialog::GetURLInput() const { + return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(url_entry_))); +} + +void EditSearchEngineDialog::EnableControls() { + gtk_widget_set_sensitive(ok_button_, + controller_->IsKeywordValid(GetKeywordInput()) && + controller_->IsTitleValid(GetTitleInput()) && + controller_->IsURLValid(GetURLInput())); + UpdateImage(keyword_image_, controller_->IsKeywordValid(GetKeywordInput()), + IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT); + UpdateImage(url_image_, controller_->IsURLValid(GetURLInput()), + IDS_SEARCH_ENGINES_INVALID_URL_TT); + UpdateImage(title_image_, controller_->IsTitleValid(GetTitleInput()), + IDS_SEARCH_ENGINES_INVALID_TITLE_TT); +} + +void EditSearchEngineDialog::UpdateImage(GtkWidget* image, + bool is_valid, + int invalid_message_id) { + if (is_valid) { + gtk_widget_set_has_tooltip(image, FALSE); + gtk_image_set_from_pixbuf(GTK_IMAGE(image), + ResourceBundle::GetSharedInstance().GetPixbufNamed( + IDR_INPUT_GOOD)); + } else { + gtk_widget_set_tooltip_text( + image, l10n_util::GetStringUTF8(invalid_message_id).c_str()); + gtk_image_set_from_pixbuf(GTK_IMAGE(image), + ResourceBundle::GetSharedInstance().GetPixbufNamed( + IDR_INPUT_ALERT)); + } +} + +// static +void EditSearchEngineDialog::OnEntryChanged( + GtkEditable* editable, EditSearchEngineDialog* window) { + window->EnableControls(); +} + +// static +void EditSearchEngineDialog::OnResponse(GtkDialog* dialog, int response_id, + EditSearchEngineDialog* window) { + if (response_id == GTK_RESPONSE_OK) { + window->controller_->AcceptAddOrEdit(window->GetTitleInput(), + window->GetKeywordInput(), + window->GetURLInput()); + } else { + window->controller_->CleanUpCancelledAdd(); + } + gtk_widget_destroy(window->dialog_); +} + +// static +void EditSearchEngineDialog::OnWindowDestroy( + GtkWidget* widget, EditSearchEngineDialog* window) { + MessageLoop::current()->DeleteSoon(FROM_HERE, window); +} diff --git a/chrome/browser/gtk/edit_search_engine_dialog.h b/chrome/browser/gtk/edit_search_engine_dialog.h new file mode 100644 index 0000000..9635d9f --- /dev/null +++ b/chrome/browser/gtk/edit_search_engine_dialog.h @@ -0,0 +1,77 @@ +// Copyright (c) 2009 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_GTK_EDIT_SEARCH_ENGINE_DIALOG_H_ +#define CHROME_BROWSER_GTK_EDIT_SEARCH_ENGINE_DIALOG_H_ + +#include +#include + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" + +class EditSearchEngineController; +class EditSearchEngineControllerDelegate; +class Profile; +class TemplateURL; + +class EditSearchEngineDialog { + public: + EditSearchEngineDialog(GtkWindow* parent_window, + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile); + + private: + // Create and show the window. + void Init(GtkWindow* parent_window); + + // Retrieve the user input in the various fields. + std::wstring GetTitleInput() const; + std::wstring GetKeywordInput() const; + std::wstring GetURLInput() const; + + // Set sensitivity of buttons based on entry state. + void EnableControls(); + + // Updates the tooltip and image of the image view based on is_valid. If + // is_valid is false the tooltip of the image view is set to the message with + // id invalid_message_id, otherwise the tooltip is set to the empty text. + void UpdateImage(GtkWidget* image, bool is_valid, int invalid_message_id); + + // Callback for entry changes. + static void OnEntryChanged(GtkEditable* editable, + EditSearchEngineDialog* window); + + // Callback for dialog buttons. + static void OnResponse(GtkDialog* dialog, int response_id, + EditSearchEngineDialog* window); + + // Callback for window destruction. + static void OnWindowDestroy(GtkWidget* widget, + EditSearchEngineDialog* window); + + // The dialog window. + GtkWidget* dialog_; + + // Text entries for each field. + GtkWidget* title_entry_; + GtkWidget* keyword_entry_; + GtkWidget* url_entry_; + + // Images showing whether each entry is okay or has errors. + GtkWidget* title_image_; + GtkWidget* keyword_image_; + GtkWidget* url_image_; + + // The ok button (we need a reference to it so we can de-activate it when the + // entries are not all filled in.) + GtkWidget* ok_button_; + + scoped_ptr controller_; + + DISALLOW_COPY_AND_ASSIGN(EditSearchEngineDialog); +}; + +#endif // CHROME_BROWSER_GTK_EDIT_SEARCH_ENGINE_DIALOG_H_ diff --git a/chrome/browser/gtk/keyword_editor_view.cc b/chrome/browser/gtk/keyword_editor_view.cc index 45de403..8ce4156 100644 --- a/chrome/browser/gtk/keyword_editor_view.cc +++ b/chrome/browser/gtk/keyword_editor_view.cc @@ -5,7 +5,7 @@ #include "chrome/browser/gtk/keyword_editor_view.h" #include "app/l10n_util.h" -#include "chrome/browser/gtk/edit_keyword_controller.h" +#include "chrome/browser/gtk/edit_search_engine_dialog.h" #include "chrome/browser/profile.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/search_engines/template_url.h" @@ -203,7 +203,7 @@ void KeywordEditorView::OnSelectionChanged( // static void KeywordEditorView::OnAddButtonClicked(GtkButton* button, KeywordEditorView* editor) { - EditKeywordControllerBase::Create( + new EditSearchEngineDialog( GTK_WINDOW(gtk_widget_get_toplevel(editor->dialog_)), NULL, editor, diff --git a/chrome/browser/gtk/keyword_editor_view.h b/chrome/browser/gtk/keyword_editor_view.h index 6705948..bac83115 100644 --- a/chrome/browser/gtk/keyword_editor_view.h +++ b/chrome/browser/gtk/keyword_editor_view.h @@ -8,20 +8,20 @@ #include #include "base/basictypes.h" -#include "chrome/browser/search_engines/edit_keyword_controller_base.h" +#include "chrome/browser/search_engines/edit_search_engine_controller.h" #include "chrome/browser/search_engines/template_url_model.h" class Profile; class KeywordEditorView : public TemplateURLModelObserver, - public EditKeywordControllerBase::Delegate { + public EditSearchEngineControllerDelegate { public: virtual ~KeywordEditorView(); // Create (if necessary) and show the keyword editor window. static void Show(Profile* profile); - // Overriden from EditKeywordControllerBase::Delegate. + // Overriden from EditSearchEngineControllerDelegate. virtual void OnEditedKeyword(const TemplateURL* template_url, const std::wstring& title, const std::wstring& keyword, diff --git a/chrome/browser/search_engines/edit_keyword_controller_base.cc b/chrome/browser/search_engines/edit_keyword_controller_base.cc deleted file mode 100644 index 8206d1d..0000000 --- a/chrome/browser/search_engines/edit_keyword_controller_base.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2009 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/search_engines/edit_keyword_controller_base.h" - -#include "chrome/browser/metrics/user_metrics.h" -#include "chrome/browser/net/url_fixer_upper.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" - -EditKeywordControllerBase::EditKeywordControllerBase( - const TemplateURL* template_url, - Delegate* edit_keyword_delegate, - Profile* profile) - : template_url_(template_url), - edit_keyword_delegate_(edit_keyword_delegate), - profile_(profile) { - DCHECK(profile_); -} - -bool EditKeywordControllerBase::IsTitleValid() const { - return !GetTitleInput().empty(); -} - -bool EditKeywordControllerBase::IsURLValid() const { - std::wstring url = GetURL(); - if (url.empty()) - return false; - - // Use TemplateURLRef to extract the search placeholder. - TemplateURLRef template_ref(url, 0, 0); - if (!template_ref.IsValid()) - return false; - - if (!template_ref.SupportsReplacement()) - return GURL(WideToUTF16Hack(url)).is_valid(); - - // If the url has a search term, replace it with a random string and make - // sure the resulting URL is valid. We don't check the validity of the url - // with the search term as that is not necessarily valid. - return GURL(WideToUTF8(template_ref.ReplaceSearchTerms(TemplateURL(), L"a", - TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()))).is_valid(); -} - -std::wstring EditKeywordControllerBase::GetURL() const { - std::wstring url; - TrimWhitespace(TemplateURLRef::DisplayURLToURLRef(GetURLInput()), - TRIM_ALL, &url); - if (url.empty()) - return url; - - // Parse the string as a URL to determine the scheme. If we need to, add the - // scheme. As the scheme may be expanded (as happens with {google:baseURL}) - // we need to replace the search terms before testing for the scheme. - TemplateURL t_url; - t_url.SetURL(url, 0, 0); - std::wstring expanded_url = - t_url.url()->ReplaceSearchTerms(t_url, L"x", 0, std::wstring()); - url_parse::Parsed parts; - std::string scheme( - URLFixerUpper::SegmentURL(WideToUTF8(expanded_url), &parts)); - if(!parts.scheme.is_valid()) { - scheme.append("://"); - url.insert(0, UTF8ToWide(scheme)); - } - - return url; -} - -bool EditKeywordControllerBase::IsKeywordValid() const { - std::wstring keyword = GetKeywordInput(); - if (keyword.empty()) - return true; // Always allow no keyword. - const TemplateURL* turl_with_keyword = - profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword); - return (turl_with_keyword == NULL || turl_with_keyword == template_url_); -} - -void EditKeywordControllerBase::AcceptAddOrEdit() { - std::wstring url_string = GetURL(); - DCHECK(!url_string.empty()); - std::wstring keyword = GetKeywordInput(); - - const TemplateURL* existing = - profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword); - if (existing && - (!edit_keyword_delegate_ || existing != template_url_)) { - // An entry may have been added with the same keyword string while the - // user edited the dialog, either automatically or by the user (if we're - // confirming a JS addition, they could have the Options dialog open at the - // same time). If so, just ignore this add. - // TODO(pamg): Really, we should modify the entry so this later one - // overwrites it. But we don't expect this case to be common. - CleanUpCancelledAdd(); - return; - } - - if (!edit_keyword_delegate_) { - // Confiming an entry we got from JS. We have a template_url_, but it - // hasn't yet been added to the model. - DCHECK(template_url_); - // const_cast is ugly, but this is the same thing the TemplateURLModel - // does in a similar situation (updating an existing TemplateURL with - // data from a new one). - TemplateURL* modifiable_url = const_cast(template_url_); - modifiable_url->set_short_name(GetTitleInput()); - modifiable_url->set_keyword(keyword); - modifiable_url->SetURL(url_string, 0, 0); - // TemplateURLModel takes ownership of template_url_. - profile_->GetTemplateURLModel()->Add(modifiable_url); - UserMetrics::RecordAction(L"KeywordEditor_AddKeywordJS", profile_); - } else { - // Adding or modifying an entry via the Delegate. - edit_keyword_delegate_->OnEditedKeyword(template_url_, - GetTitleInput(), - GetKeywordInput(), - url_string); - } -} - -void EditKeywordControllerBase::CleanUpCancelledAdd() { - if (!edit_keyword_delegate_ && template_url_) { - // When we have no Delegate, we know that the template_url_ hasn't yet been - // added to the model, so we need to clean it up. - delete template_url_; - template_url_ = NULL; - } -} diff --git a/chrome/browser/search_engines/edit_keyword_controller_base.h b/chrome/browser/search_engines/edit_keyword_controller_base.h deleted file mode 100644 index d01f6e9..0000000 --- a/chrome/browser/search_engines/edit_keyword_controller_base.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2009 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_SEARCH_ENGINES_EDIT_KEYWORD_CONTROLLER_BASE_H_ -#define CHROME_BROWSER_SEARCH_ENGINES_EDIT_KEYWORD_CONTROLLER_BASE_H_ - -#include - -#include "base/gfx/native_widget_types.h" - -class Profile; -class TemplateURL; - -// EditKeywordControllerBase provides the platform independent logic and -// interface for implementing a dialog for editing keyword searches. -class EditKeywordControllerBase { - public: - class Delegate { - public: - virtual ~Delegate() {} - - // Invoked from the EditKeywordController when the user accepts the edits. - // NOTE: |template_url| is the value supplied to EditKeywordController's - // constructor, and may be null. A null value indicates a new TemplateURL - // should be created rather than modifying an existing TemplateURL. - virtual void OnEditedKeyword(const TemplateURL* template_url, - const std::wstring& title, - const std::wstring& keyword, - const std::wstring& url) = 0; - }; - - // Create and show the platform's implementation of the dialog. - static void Create(gfx::NativeWindow parent_window, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile); - - // The |template_url| and/or |edit_keyword_delegate| may be NULL. - EditKeywordControllerBase(const TemplateURL* template_url, - Delegate* edit_keyword_delegate, - Profile* profile); - virtual ~EditKeywordControllerBase() {} - - protected: - // Interface to platform specific view - virtual std::wstring GetURLInput() const = 0; - virtual std::wstring GetKeywordInput() const = 0; - virtual std::wstring GetTitleInput() const = 0; - - // Check if content of Title entry is valid. - bool IsTitleValid() const; - - // Returns true if the currently input URL is valid. The URL is valid if it - // contains no search terms and is a valid url, or if it contains a search - // term and replacing that search term with a character results in a valid - // url. - bool IsURLValid() const; - - // Fixes up and returns the URL the user has input. The returned URL is - // suitable for use by TemplateURL. - std::wstring GetURL() const; - - // Returns whether the currently entered keyword is valid. The keyword is - // valid if it is non-empty and does not conflict with an existing entry. - // NOTE: this is just the keyword, not the title and url. - bool IsKeywordValid() const; - - // Deletes an unused TemplateURL, if its add was cancelled and it's not - // already owned by the TemplateURLModel. - void AcceptAddOrEdit(); - - // Deletes an unused TemplateURL, if its add was cancelled and it's not - // already owned by the TemplateURLModel. - void CleanUpCancelledAdd(); - - const TemplateURL* template_url() const { - return template_url_; - } - - const Profile* profile() const { - return profile_; - } - - private: - // The TemplateURL we're displaying information for. It may be NULL. If we - // have a keyword_editor_view, we assume that this TemplateURL is already in - // the TemplateURLModel; if not, we assume it isn't. - const TemplateURL* template_url_; - - // We may have been created by this, in which case we will call back to it on - // success to add/modify the entry. May be NULL. - Delegate* edit_keyword_delegate_; - - // Profile whose TemplateURLModel we're modifying. - Profile* profile_; -}; - -#endif // CHROME_BROWSER_SEARCH_ENGINES_EDIT_KEYWORD_CONTROLLER_BASE_H_ diff --git a/chrome/browser/search_engines/edit_search_engine_controller.cc b/chrome/browser/search_engines/edit_search_engine_controller.cc new file mode 100644 index 0000000..110af38 --- /dev/null +++ b/chrome/browser/search_engines/edit_search_engine_controller.cc @@ -0,0 +1,136 @@ +// Copyright (c) 2009 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/search_engines/edit_search_engine_controller.h" + +#include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/net/url_fixer_upper.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" + +EditSearchEngineController::EditSearchEngineController( + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* edit_keyword_delegate, + Profile* profile) + : template_url_(template_url), + edit_keyword_delegate_(edit_keyword_delegate), + profile_(profile) { + DCHECK(profile_); +} + +bool EditSearchEngineController::IsTitleValid( + const std::wstring& title_input) const { + return !title_input.empty(); +} + +bool EditSearchEngineController::IsURLValid( + const std::wstring& url_input) const { + std::wstring url = GetFixedUpURL(url_input); + if (url.empty()) + return false; + + // Use TemplateURLRef to extract the search placeholder. + TemplateURLRef template_ref(url, 0, 0); + if (!template_ref.IsValid()) + return false; + + if (!template_ref.SupportsReplacement()) + return GURL(WideToUTF16Hack(url)).is_valid(); + + // If the url has a search term, replace it with a random string and make + // sure the resulting URL is valid. We don't check the validity of the url + // with the search term as that is not necessarily valid. + return GURL(WideToUTF8(template_ref.ReplaceSearchTerms(TemplateURL(), L"a", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()))).is_valid(); +} + +bool EditSearchEngineController::IsKeywordValid( + const std::wstring& keyword_input) const { + if (keyword_input.empty()) + return true; // Always allow no keyword. + const TemplateURL* turl_with_keyword = + profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_input); + return (turl_with_keyword == NULL || turl_with_keyword == template_url_); +} + +void EditSearchEngineController::AcceptAddOrEdit( + const std::wstring& title_input, + const std::wstring& keyword_input, + const std::wstring& url_input) { + std::wstring url_string = GetFixedUpURL(url_input); + DCHECK(!url_string.empty()); + + const TemplateURL* existing = + profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_input); + if (existing && + (!edit_keyword_delegate_ || existing != template_url_)) { + // An entry may have been added with the same keyword string while the + // user edited the dialog, either automatically or by the user (if we're + // confirming a JS addition, they could have the Options dialog open at the + // same time). If so, just ignore this add. + // TODO(pamg): Really, we should modify the entry so this later one + // overwrites it. But we don't expect this case to be common. + CleanUpCancelledAdd(); + return; + } + + if (!edit_keyword_delegate_) { + // Confiming an entry we got from JS. We have a template_url_, but it + // hasn't yet been added to the model. + DCHECK(template_url_); + // const_cast is ugly, but this is the same thing the TemplateURLModel + // does in a similar situation (updating an existing TemplateURL with + // data from a new one). + TemplateURL* modifiable_url = const_cast(template_url_); + modifiable_url->set_short_name(title_input); + modifiable_url->set_keyword(keyword_input); + modifiable_url->SetURL(url_string, 0, 0); + // TemplateURLModel takes ownership of template_url_. + profile_->GetTemplateURLModel()->Add(modifiable_url); + UserMetrics::RecordAction(L"KeywordEditor_AddKeywordJS", profile_); + } else { + // Adding or modifying an entry via the Delegate. + edit_keyword_delegate_->OnEditedKeyword(template_url_, + title_input, + keyword_input, + url_string); + } +} + +void EditSearchEngineController::CleanUpCancelledAdd() { + if (!edit_keyword_delegate_ && template_url_) { + // When we have no Delegate, we know that the template_url_ hasn't yet been + // added to the model, so we need to clean it up. + delete template_url_; + template_url_ = NULL; + } +} + +std::wstring EditSearchEngineController::GetFixedUpURL( + const std::wstring& url_input) const { + std::wstring url; + TrimWhitespace(TemplateURLRef::DisplayURLToURLRef(url_input), + TRIM_ALL, &url); + if (url.empty()) + return url; + + // Parse the string as a URL to determine the scheme. If we need to, add the + // scheme. As the scheme may be expanded (as happens with {google:baseURL}) + // we need to replace the search terms before testing for the scheme. + TemplateURL t_url; + t_url.SetURL(url, 0, 0); + std::wstring expanded_url = + t_url.url()->ReplaceSearchTerms(t_url, L"x", 0, std::wstring()); + url_parse::Parsed parts; + std::string scheme( + URLFixerUpper::SegmentURL(WideToUTF8(expanded_url), &parts)); + if(!parts.scheme.is_valid()) { + scheme.append("://"); + url.insert(0, UTF8ToWide(scheme)); + } + + return url; +} + diff --git a/chrome/browser/search_engines/edit_search_engine_controller.h b/chrome/browser/search_engines/edit_search_engine_controller.h new file mode 100644 index 0000000..6333dbf --- /dev/null +++ b/chrome/browser/search_engines/edit_search_engine_controller.h @@ -0,0 +1,86 @@ +// Copyright (c) 2009 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_SEARCH_ENGINES_EDIT_SEARCH_ENGINE_CONTROLLER_H_ +#define CHROME_BROWSER_SEARCH_ENGINES_EDIT_SEARCH_ENGINE_CONTROLLER_H_ + +#include + +#include "base/gfx/native_widget_types.h" + +class Profile; +class TemplateURL; + +class EditSearchEngineControllerDelegate { + public: + // Invoked from the EditSearchEngineController when the user accepts the + // edits. NOTE: |template_url| is the value supplied to + // EditSearchEngineController's constructor, and may be NULL. A NULL value + // indicates a new TemplateURL should be created rather than modifying an + // existing TemplateURL. + virtual void OnEditedKeyword(const TemplateURL* template_url, + const std::wstring& title, + const std::wstring& keyword, + const std::wstring& url) = 0; +}; + +// EditSearchEngineController provides the core platform independent logic +// for the Edit Search Engine dialog. +class EditSearchEngineController { + public: + // The |template_url| and/or |edit_keyword_delegate| may be NULL. + EditSearchEngineController( + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* edit_keyword_delegate, + Profile* profile); + ~EditSearchEngineController() {} + + // Returns true if the value of |title_input| is a valid search engine name. + bool IsTitleValid(const std::wstring& title_input) const; + + // Returns true if the value of |url_input| represents a valid search engine + // URL. The URL is valid if it contains no search terms and is a valid + // url, or if it contains a search term and replacing that search term with a + // character results in a valid url. + bool IsURLValid(const std::wstring& url_input) const; + + // Returns true if the value of |keyword_input| represents a valid keyword. + // The keyword is valid if it is non-empty and does not conflict with an + // existing entry. NOTE: this is just the keyword, not the title and url. + bool IsKeywordValid(const std::wstring& keyword_input) const; + + // Completes the add or edit of a search engine. + void AcceptAddOrEdit(const std::wstring& title_input, + const std::wstring& keyword_input, + const std::wstring& url_input); + + // Deletes an unused TemplateURL, if its add was cancelled and it's not + // already owned by the TemplateURLModel. + void CleanUpCancelledAdd(); + + // Accessors. + const TemplateURL* template_url() const { return template_url_; } + const Profile* profile() const { return profile_; } + + private: + // Fixes up and returns the URL the user has input. The returned URL is + // suitable for use by TemplateURL. + std::wstring GetFixedUpURL(const std::wstring& url_input) const; + + // The TemplateURL we're displaying information for. It may be NULL. If we + // have a keyword_editor_view, we assume that this TemplateURL is already in + // the TemplateURLModel; if not, we assume it isn't. + const TemplateURL* template_url_; + + // We may have been created by this, in which case we will call back to it on + // success to add/modify the entry. May be NULL. + EditSearchEngineControllerDelegate* edit_keyword_delegate_; + + // Profile whose TemplateURLModel we're modifying. + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(EditSearchEngineController); +}; + +#endif // CHROME_BROWSER_SEARCH_ENGINES_EDIT_SEARCH_ENGINE_CONTROLLER_H_ diff --git a/chrome/browser/search_engines/template_url_fetcher.cc b/chrome/browser/search_engines/template_url_fetcher.cc index 8b14aa3..d881d92 100644 --- a/chrome/browser/search_engines/template_url_fetcher.cc +++ b/chrome/browser/search_engines/template_url_fetcher.cc @@ -8,19 +8,24 @@ #include "chrome/browser/net/url_fetcher.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/edit_keyword_controller_base.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/search_engines/template_url_parser.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_delegate.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" // RequestDelegate ------------------------------------------------------------ -class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate { +class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate, + public NotificationObserver { public: RequestDelegate(TemplateURLFetcher* fetcher, const std::wstring& keyword, const GURL& osdd_url, const GURL& favicon_url, - gfx::NativeWindow parent_window, + TabContents* source, bool autodetected) : ALLOW_THIS_IN_INITIALIZER_LIST(url_fetcher_(osdd_url, URLFetcher::GET, this)), @@ -29,11 +34,15 @@ class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate { osdd_url_(osdd_url), favicon_url_(favicon_url), autodetected_(autodetected), - parent_window_(parent_window) { + source_(source) { url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext()); url_fetcher_.Start(); + registrar_.Add(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source(source_)); } + // URLFetcher::Delegate: // If data contains a valid OSDD, a TemplateURL is created and added to // the TemplateURLModel. virtual void OnURLFetchComplete(const URLFetcher* source, @@ -43,6 +52,15 @@ class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate { const ResponseCookies& cookies, const std::string& data); + // NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED); + DCHECK(source == Source(source_)); + source_ = NULL; + } + // URL of the OSDD. const GURL& url() const { return osdd_url_; } @@ -57,9 +75,12 @@ class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate { const GURL favicon_url_; bool autodetected_; - // Used to determine where to place a confirmation dialog. May be NULL, - // in which case the confirmation will be centered in the screen if needed. - gfx::NativeWindow parent_window_; + // The TabContents where this request originated. Can be NULL if the + // originating tab is closed. If NULL, the engine is not added. + TabContents* source_; + + // Handles registering for our notifications. + NotificationRegistrar registrar_; DISALLOW_COPY_AND_ASSIGN(RequestDelegate); }; @@ -118,18 +139,15 @@ void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete( // Mark the keyword as replaceable so it can be removed if necessary. template_url->set_safe_for_autoreplace(true); model->Add(template_url.release()); - } else { -#if defined(OS_WIN) || !defined(TOOLKIT_VIEWS) + } else if (source_ && source_->delegate()) { // Confirm addition and allow user to edit default choices. It's ironic // that only *non*-autodetected additions get confirmed, but the user // expects feedback that his action did something. - // The edit controller will take care of adding the URL to the model, - // which takes ownership, or of deleting it if the add is cancelled. - EditKeywordControllerBase::Create(parent_window_, - template_url.release(), - NULL, // no KeywordEditorView - fetcher_->profile()); -#endif + // The source TabContents' delegate takes care of adding the URL to the + // model, which takes ownership, or of deleting it if the add is + // cancelled. + source_->delegate()->ConfirmAddSearchProvider(template_url.release(), + fetcher_->profile()); } } fetcher_->RequestCompleted(this); @@ -148,7 +166,7 @@ TemplateURLFetcher::~TemplateURLFetcher() { void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword, const GURL& osdd_url, const GURL& favicon_url, - const gfx::NativeWindow parent_window, + TabContents* source, bool autodetected) { DCHECK(!keyword.empty() && osdd_url.is_valid()); // Make sure we aren't already downloading this request. @@ -159,7 +177,7 @@ void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword, } requests_->push_back( - new RequestDelegate(this, keyword, osdd_url, favicon_url, parent_window, + new RequestDelegate(this, keyword, osdd_url, favicon_url, source, autodetected)); } diff --git a/chrome/browser/search_engines/template_url_fetcher.h b/chrome/browser/search_engines/template_url_fetcher.h index 48264dc..c6527d6 100644 --- a/chrome/browser/search_engines/template_url_fetcher.h +++ b/chrome/browser/search_engines/template_url_fetcher.h @@ -29,7 +29,7 @@ class TemplateURLFetcher { void ScheduleDownload(const std::wstring& keyword, const GURL& osdd_url, const GURL& favicon_url, - const gfx::NativeWindow parent_window, + TabContents* source, bool autodetected); private: diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 53e074c..bde80b1 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -2032,12 +2032,11 @@ void TabContents::PageHasOSDD(RenderViewHost* render_view_host, // Download the OpenSearch description document. If this is successful a // new keyword will be created when done. - gfx::NativeWindow ancestor = view_->GetTopLevelNativeWindow(); profile()->GetTemplateURLFetcher()->ScheduleDownload( keyword, url, base_entry->favicon().url(), - ancestor, + this, autodetected); } diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h index 2fdaa7a..b93de6e 100644 --- a/chrome/browser/tab_contents/tab_contents_delegate.h +++ b/chrome/browser/tab_contents/tab_contents_delegate.h @@ -15,10 +15,12 @@ class DownloadItem; class ExtensionFunctionDispatcher; +class GURL; +class HtmlDialogUIDelegate; +class Profile; class RenderViewHost; class TabContents; -class HtmlDialogUIDelegate; -class GURL; +class TemplateURL; // Objects implement this interface to get notified about changes in the // TabContents and to provide necessary functionality. @@ -158,7 +160,7 @@ class TabContentsDelegate { // This is used when the contents is an extension that needs to route // api calls through to the Browser process. - virtual ExtensionFunctionDispatcher *CreateExtensionFunctionDispatcher( + virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher( RenderViewHost* render_view_host, const std::string& extension_id) { return NULL; @@ -197,6 +199,12 @@ class TabContentsDelegate { // Returns the renderer's current preferences settings. RendererPreferences GetRendererPrefs() const { return renderer_preferences_; } + // Shows a confirmation UI that the specified |template_url| is to be added as + // a search engine. + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) { + } + protected: ~TabContentsDelegate() {} RendererPreferences renderer_preferences_; diff --git a/chrome/browser/views/browser_dialogs.h b/chrome/browser/views/browser_dialogs.h index fd81d7b..9f33f64 100644 --- a/chrome/browser/views/browser_dialogs.h +++ b/chrome/browser/views/browser_dialogs.h @@ -14,6 +14,7 @@ class Browser; class BrowserView; +class EditSearchEngineControllerDelegate; class FindBar; class GURL; class HtmlDialogUIDelegate; @@ -85,6 +86,16 @@ void ShowNewProfileDialog(); // Shows the Task Manager. void ShowTaskManager(); +// Shows a dialog box that allows a search engine to be edited. |template_url| +// is the search engine being edited. If it is NULL, then the dialog will add a +// new search engine with the data the user supplies. |delegate| is an object +// to be notified when the user is done editing, or NULL. If NULL, the dialog +// will update the model with the user's edits directly. +void EditSearchEngine(gfx::NativeWindow parent, + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile); + } // namespace browser #endif // CHROME_BROWSER_VIEWS_BROWSER_DIALOGS_H_ diff --git a/chrome/browser/views/edit_keyword_controller.cc b/chrome/browser/views/edit_keyword_controller.cc deleted file mode 100644 index 7258b2d..0000000 --- a/chrome/browser/views/edit_keyword_controller.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) 2009 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/views/edit_keyword_controller.h" - -#include "app/l10n_util.h" -#include "app/resource_bundle.h" -#include "base/string_util.h" -#include "chrome/browser/search_engines/template_url.h" -#include "googleurl/src/gurl.h" -#include "grit/app_resources.h" -#include "grit/generated_resources.h" -#include "grit/theme_resources.h" -#include "views/controls/label.h" -#include "views/controls/image_view.h" -#include "views/controls/table/table_view.h" -#include "views/grid_layout.h" -#include "views/standard_layout.h" -#include "views/window/window.h" - -using views::GridLayout; -using views::ImageView; -using views::Textfield; - - -namespace { -// Converts a URL as understood by TemplateURL to one appropriate for display -// to the user. -std::wstring GetDisplayURL(const TemplateURL& turl) { - return turl.url() ? turl.url()->DisplayURL() : std::wstring(); -} -} // namespace - -// static -void EditKeywordControllerBase::Create(gfx::NativeWindow parent_window, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile) { - EditKeywordController* controller = - new EditKeywordController(parent_window, template_url, delegate, profile); - controller->Show(); -} - -EditKeywordController::EditKeywordController( - HWND parent, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile) - : EditKeywordControllerBase(template_url, delegate, profile), - parent_(parent) { - Init(); -} - -void EditKeywordController::Show() { - // Window interprets an empty rectangle as needing to query the content for - // the size as well as centering relative to the parent. - views::Window::CreateChromeWindow(::IsWindow(parent_) ? parent_ : NULL, - gfx::Rect(), this); - window()->Show(); - GetDialogClientView()->UpdateDialogButtons(); - title_tf_->SelectAll(); - title_tf_->RequestFocus(); -} - -bool EditKeywordController::IsModal() const { - // If we were called without a KeywordEditorView, and our associated - // window happens to have gone away while the TemplateURLFetcher was - // loading, we might not have a valid parent anymore. - // ::IsWindow() returns a BOOL, which is a typedef for an int and causes a - // warning if we try to return it or cast it as a bool. - if (::IsWindow(parent_)) - return true; - return false; -} - -std::wstring EditKeywordController::GetWindowTitle() const { - return l10n_util::GetString(template_url() ? - IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE : - IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE); -} - -bool EditKeywordController::IsDialogButtonEnabled( - MessageBoxFlags::DialogButton button) const { - if (button == MessageBoxFlags::DIALOGBUTTON_OK) { - return (IsKeywordValid() && IsTitleValid() && IsURLValid()); - } - return true; -} - -void EditKeywordController::DeleteDelegate() { - // User canceled the save, delete us. - delete this; -} - -bool EditKeywordController::Cancel() { - CleanUpCancelledAdd(); - return true; -} - -bool EditKeywordController::Accept() { - AcceptAddOrEdit(); - return true; -} - -views::View* EditKeywordController::GetContentsView() { - return view_; -} - -void EditKeywordController::ContentsChanged(Textfield* sender, - const std::wstring& new_contents) { - GetDialogClientView()->UpdateDialogButtons(); - UpdateImageViews(); -} - -bool EditKeywordController::HandleKeystroke( - Textfield* sender, - const views::Textfield::Keystroke& key) { - return false; -} - -void EditKeywordController::Init() { - // Create the views we'll need. - view_ = new views::View(); - if (template_url()) { - title_tf_ = CreateTextfield(template_url()->short_name(), false); - keyword_tf_ = CreateTextfield(template_url()->keyword(), true); - url_tf_ = CreateTextfield(GetDisplayURL(*template_url()), false); - // We don't allow users to edit prepopulate URLs. This is done as - // occasionally we need to update the URL of prepopulated TemplateURLs. - url_tf_->SetReadOnly(template_url()->prepopulate_id() != 0); - } else { - title_tf_ = CreateTextfield(std::wstring(), false); - keyword_tf_ = CreateTextfield(std::wstring(), true); - url_tf_ = CreateTextfield(std::wstring(), false); - } - title_iv_ = new ImageView(); - keyword_iv_ = new ImageView(); - url_iv_ = new ImageView(); - - UpdateImageViews(); - - const int related_x = kRelatedControlHorizontalSpacing; - const int related_y = kRelatedControlVerticalSpacing; - const int unrelated_y = kUnrelatedControlVerticalSpacing; - - // View and GridLayout take care of deleting GridLayout for us. - GridLayout* layout = CreatePanelGridLayout(view_); - view_->SetLayoutManager(layout); - - // Define the structure of the layout. - - // For the buttons. - views::ColumnSet* column_set = layout->AddColumnSet(0); - column_set->AddPaddingColumn(1, 0); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, related_x); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); - column_set->LinkColumnSizes(1, 3, -1); - - // For the Textfields. - column_set = layout->AddColumnSet(1); - column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, related_x); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, related_x); - column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); - - // For the description. - column_set = layout->AddColumnSet(2); - column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, - GridLayout::USE_PREF, 0, 0); - - // Add the contents. - layout->StartRow(0, 1); - layout->AddView(CreateLabel(IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_LABEL)); - layout->AddView(title_tf_); - layout->AddView(title_iv_); - - layout->StartRowWithPadding(0, 1, 0, related_y); - layout->AddView(CreateLabel(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_LABEL)); - layout->AddView(keyword_tf_); - layout->AddView(keyword_iv_); - - layout->StartRowWithPadding(0, 1, 0, related_y); - layout->AddView(CreateLabel(IDS_SEARCH_ENGINES_EDITOR_URL_LABEL)); - layout->AddView(url_tf_); - layout->AddView(url_iv_); - - // On RTL UIs (such as Arabic and Hebrew) the description text is not - // displayed correctly since it contains the substring "%s". This substring - // is not interpreted by the Unicode BiDi algorithm as an LTR string and - // therefore the end result is that the following right to left text is - // displayed: ".three two s% one" (where 'one', 'two', etc. are words in - // Hebrew). - // - // In order to fix this problem we transform the substring "%s" so that it - // is displayed correctly when rendered in an RTL context. - layout->StartRowWithPadding(0, 2, 0, unrelated_y); - std::wstring description = - l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_URL_DESCRIPTION_LABEL); - if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { - const std::wstring reversed_percent(L"s%"); - std::wstring::size_type percent_index = - description.find(L"%s", static_cast(0)); - if (percent_index != std::wstring::npos) - description.replace(percent_index, - reversed_percent.length(), - reversed_percent); - } - - views::Label* description_label = new views::Label(description); - description_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - layout->AddView(description_label); - - layout->AddPaddingRow(0, related_y); -} - -views::Label* EditKeywordController::CreateLabel(int message_id) { - views::Label* label = new views::Label(l10n_util::GetString(message_id)); - label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - return label; -} - -Textfield* EditKeywordController::CreateTextfield(const std::wstring& text, - bool lowercase) { - Textfield* text_field = new Textfield( - lowercase ? Textfield::STYLE_LOWERCASE : Textfield::STYLE_DEFAULT); - text_field->SetText(text); - text_field->SetController(this); - return text_field; -} - -std::wstring EditKeywordController::GetURLInput() const { - return url_tf_->text(); -} - -std::wstring EditKeywordController::GetKeywordInput() const { - return keyword_tf_->text(); -} - -std::wstring EditKeywordController::GetTitleInput() const { - return title_tf_->text(); -} - -void EditKeywordController::UpdateImageViews() { - UpdateImageView(keyword_iv_, IsKeywordValid(), - IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT); - UpdateImageView(url_iv_, IsURLValid(), IDS_SEARCH_ENGINES_INVALID_URL_TT); - UpdateImageView(title_iv_, IsTitleValid(), - IDS_SEARCH_ENGINES_INVALID_TITLE_TT); -} - -void EditKeywordController::UpdateImageView(ImageView* image_view, - bool is_valid, - int invalid_message_id) { - if (is_valid) { - image_view->SetTooltipText(std::wstring()); - image_view->SetImage( - ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_INPUT_GOOD)); - } else { - image_view->SetTooltipText(l10n_util::GetString(invalid_message_id)); - image_view->SetImage( - ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_INPUT_ALERT)); - } -} diff --git a/chrome/browser/views/edit_keyword_controller.h b/chrome/browser/views/edit_keyword_controller.h deleted file mode 100644 index fe79f4f..0000000 --- a/chrome/browser/views/edit_keyword_controller.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2009 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. - -// EditKeywordController provides text fields for editing a keyword: the title, -// url and actual keyword. It is used by the KeywordEditorView of the Options -// dialog, and also on its own to confirm the addition of a keyword added by -// the ExternalJSObject via the RenderView. - -#ifndef CHROME_BROWSER_VIEWS_EDIT_KEYWORD_CONTROLLER_H_ -#define CHROME_BROWSER_VIEWS_EDIT_KEYWORD_CONTROLLER_H_ - -#include - -#include "chrome/browser/search_engines/edit_keyword_controller_base.h" -#include "views/controls/textfield/textfield.h" -#include "views/window/dialog_delegate.h" - -namespace views { -class Label; -class ImageView; -class Window; -} - -class Profile; -class TemplateURL; -class TemplateURLModel; - -class EditKeywordController : public views::Textfield::Controller, - public views::DialogDelegate, - public EditKeywordControllerBase { - public: - // The |template_url| and/or |delegate| may be NULL. - EditKeywordController(HWND parent, - const TemplateURL* template_url, - Delegate* delegate, - Profile* profile); - - virtual ~EditKeywordController() {} - - // Shows the dialog to the user. EditKeywordController takes care of - // deleting itself after show has been invoked. - void Show(); - - // DialogDelegate overrides. - virtual bool IsModal() const; - virtual std::wstring GetWindowTitle() const; - virtual bool IsDialogButtonEnabled( - MessageBoxFlags::DialogButton button) const; - virtual void DeleteDelegate(); - virtual bool Cancel(); - virtual bool Accept(); - virtual views::View* GetContentsView(); - - // views::Textfield::Controller overrides. Updates whether the user can - // accept the dialog as well as updating image views showing whether value is - // valid. - virtual void ContentsChanged(views::Textfield* sender, - const std::wstring& new_contents); - virtual bool HandleKeystroke(views::Textfield* sender, - const views::Textfield::Keystroke& key); - - private: - void Init(); - - // Create a Label containing the text with the specified message id. - views::Label* CreateLabel(int message_id); - - // Creates a text field with the specified text. If |lowercase| is true, the - // Textfield is configured to map all input to lower case. - views::Textfield* CreateTextfield(const std::wstring& text, bool lowercase); - - // EditKeywordControllerBase overrides - virtual std::wstring GetURLInput() const; - virtual std::wstring GetKeywordInput() const; - virtual std::wstring GetTitleInput() const; - - // Invokes UpdateImageView for each of the images views. - void UpdateImageViews(); - - // Updates the tooltip and image of the image view based on is_valid. If - // is_valid is false the tooltip of the image view is set to the message with - // id invalid_message_id, otherwise the tooltip is set to the empty text. - void UpdateImageView(views::ImageView* image_view, - bool is_valid, - int invalid_message_id); - - // Used to parent window to. May be NULL or an invalid window. - HWND parent_; - - // View containing the buttons, text fields ... - views::View* view_; - - // Text fields. - views::Textfield* title_tf_; - views::Textfield* keyword_tf_; - views::Textfield* url_tf_; - - // Shows error images. - views::ImageView* title_iv_; - views::ImageView* keyword_iv_; - views::ImageView* url_iv_; - - DISALLOW_COPY_AND_ASSIGN(EditKeywordController); -}; - -#endif // CHROME_BROWSER_VIEWS_EDIT_KEYWORD_CONTROLLER_H_ diff --git a/chrome/browser/views/edit_search_engine_dialog.cc b/chrome/browser/views/edit_search_engine_dialog.cc new file mode 100644 index 0000000..18d3c6f --- /dev/null +++ b/chrome/browser/views/edit_search_engine_dialog.cc @@ -0,0 +1,261 @@ +// Copyright (c) 2009 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/views/edit_search_engine_dialog.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/string_util.h" +#include "chrome/browser/search_engines/edit_search_engine_controller.h" +#include "chrome/browser/search_engines/template_url.h" +#include "googleurl/src/gurl.h" +#include "grit/app_resources.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "views/controls/label.h" +#include "views/controls/image_view.h" +#include "views/controls/table/table_view.h" +#include "views/grid_layout.h" +#include "views/standard_layout.h" +#include "views/window/window.h" + +using views::GridLayout; +using views::ImageView; +using views::Textfield; + + +namespace { +// Converts a URL as understood by TemplateURL to one appropriate for display +// to the user. +std::wstring GetDisplayURL(const TemplateURL& turl) { + return turl.url() ? turl.url()->DisplayURL() : std::wstring(); +} +} // namespace + +namespace browser { + +void EditSearchEngine(gfx::NativeWindow parent, + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile) { + EditSearchEngineDialog::Show(parent, template_url, delegate, profile); +} + +} // namespace browser + +EditSearchEngineDialog::EditSearchEngineDialog( + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile) + : controller_(new EditSearchEngineController(template_url, + delegate, + profile)) { + Init(); +} + +// static +void EditSearchEngineDialog::Show(gfx::NativeWindow parent, + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile) { + EditSearchEngineDialog* contents = + new EditSearchEngineDialog(template_url, delegate, profile); + // Window interprets an empty rectangle as needing to query the content for + // the size as well as centering relative to the parent. + views::Window::CreateChromeWindow(parent, gfx::Rect(), contents); + contents->window()->Show(); + contents->GetDialogClientView()->UpdateDialogButtons(); + contents->title_tf_->SelectAll(); + contents->title_tf_->RequestFocus(); +} + +bool EditSearchEngineDialog::IsModal() const { + return true; +} + +std::wstring EditSearchEngineDialog::GetWindowTitle() const { + return l10n_util::GetString(controller_->template_url() ? + IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE : + IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE); +} + +bool EditSearchEngineDialog::IsDialogButtonEnabled( + MessageBoxFlags::DialogButton button) const { + if (button == MessageBoxFlags::DIALOGBUTTON_OK) { + return (controller_->IsKeywordValid(keyword_tf_->text()) && + controller_->IsTitleValid(title_tf_->text()) && + controller_->IsURLValid(url_tf_->text())); + } + return true; +} + +bool EditSearchEngineDialog::Cancel() { + controller_->CleanUpCancelledAdd(); + return true; +} + +bool EditSearchEngineDialog::Accept() { + controller_->AcceptAddOrEdit(keyword_tf_->text(), title_tf_->text(), + url_tf_->text()); + return true; +} + +views::View* EditSearchEngineDialog::GetContentsView() { + return this; +} + +void EditSearchEngineDialog::ContentsChanged(Textfield* sender, + const std::wstring& new_contents) { + GetDialogClientView()->UpdateDialogButtons(); + UpdateImageViews(); +} + +bool EditSearchEngineDialog::HandleKeystroke( + Textfield* sender, + const views::Textfield::Keystroke& key) { + return false; +} + +void EditSearchEngineDialog::Init() { + // Create the views we'll need. + if (controller_->template_url()) { + title_tf_ = + CreateTextfield(controller_->template_url()->short_name(), false); + keyword_tf_ = CreateTextfield(controller_->template_url()->keyword(), true); + url_tf_ = + CreateTextfield(GetDisplayURL(*controller_->template_url()), false); + // We don't allow users to edit prepopulate URLs. This is done as + // occasionally we need to update the URL of prepopulated TemplateURLs. + url_tf_->SetReadOnly(controller_->template_url()->prepopulate_id() != 0); + } else { + title_tf_ = CreateTextfield(std::wstring(), false); + keyword_tf_ = CreateTextfield(std::wstring(), true); + url_tf_ = CreateTextfield(std::wstring(), false); + } + title_iv_ = new ImageView(); + keyword_iv_ = new ImageView(); + url_iv_ = new ImageView(); + + UpdateImageViews(); + + const int related_x = kRelatedControlHorizontalSpacing; + const int related_y = kRelatedControlVerticalSpacing; + const int unrelated_y = kUnrelatedControlVerticalSpacing; + + // View and GridLayout take care of deleting GridLayout for us. + GridLayout* layout = CreatePanelGridLayout(this); + SetLayoutManager(layout); + + // Define the structure of the layout. + + // For the buttons. + views::ColumnSet* column_set = layout->AddColumnSet(0); + column_set->AddPaddingColumn(1, 0); + column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, related_x); + column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->LinkColumnSizes(1, 3, -1); + + // For the Textfields. + column_set = layout->AddColumnSet(1); + column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, related_x); + column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, related_x); + column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + + // For the description. + column_set = layout->AddColumnSet(2); + column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + + // Add the contents. + layout->StartRow(0, 1); + layout->AddView(CreateLabel(IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_LABEL)); + layout->AddView(title_tf_); + layout->AddView(title_iv_); + + layout->StartRowWithPadding(0, 1, 0, related_y); + layout->AddView(CreateLabel(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_LABEL)); + layout->AddView(keyword_tf_); + layout->AddView(keyword_iv_); + + layout->StartRowWithPadding(0, 1, 0, related_y); + layout->AddView(CreateLabel(IDS_SEARCH_ENGINES_EDITOR_URL_LABEL)); + layout->AddView(url_tf_); + layout->AddView(url_iv_); + + // On RTL UIs (such as Arabic and Hebrew) the description text is not + // displayed correctly since it contains the substring "%s". This substring + // is not interpreted by the Unicode BiDi algorithm as an LTR string and + // therefore the end result is that the following right to left text is + // displayed: ".three two s% one" (where 'one', 'two', etc. are words in + // Hebrew). + // + // In order to fix this problem we transform the substring "%s" so that it + // is displayed correctly when rendered in an RTL context. + layout->StartRowWithPadding(0, 2, 0, unrelated_y); + std::wstring description = + l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_URL_DESCRIPTION_LABEL); + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { + const std::wstring reversed_percent(L"s%"); + std::wstring::size_type percent_index = + description.find(L"%s", static_cast(0)); + if (percent_index != std::wstring::npos) + description.replace(percent_index, + reversed_percent.length(), + reversed_percent); + } + + views::Label* description_label = new views::Label(description); + description_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + layout->AddView(description_label); + + layout->AddPaddingRow(0, related_y); +} + +views::Label* EditSearchEngineDialog::CreateLabel(int message_id) { + views::Label* label = new views::Label(l10n_util::GetString(message_id)); + label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + return label; +} + +Textfield* EditSearchEngineDialog::CreateTextfield(const std::wstring& text, + bool lowercase) { + Textfield* text_field = new Textfield( + lowercase ? Textfield::STYLE_LOWERCASE : Textfield::STYLE_DEFAULT); + text_field->SetText(text); + text_field->SetController(this); + return text_field; +} + +void EditSearchEngineDialog::UpdateImageViews() { + UpdateImageView(keyword_iv_, controller_->IsKeywordValid(keyword_tf_->text()), + IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT); + UpdateImageView(url_iv_, controller_->IsURLValid(url_tf_->text()), + IDS_SEARCH_ENGINES_INVALID_URL_TT); + UpdateImageView(title_iv_, controller_->IsTitleValid(title_tf_->text()), + IDS_SEARCH_ENGINES_INVALID_TITLE_TT); +} + +void EditSearchEngineDialog::UpdateImageView(ImageView* image_view, + bool is_valid, + int invalid_message_id) { + if (is_valid) { + image_view->SetTooltipText(std::wstring()); + image_view->SetImage( + ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_INPUT_GOOD)); + } else { + image_view->SetTooltipText(l10n_util::GetString(invalid_message_id)); + image_view->SetImage( + ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_INPUT_ALERT)); + } +} diff --git a/chrome/browser/views/edit_search_engine_dialog.h b/chrome/browser/views/edit_search_engine_dialog.h new file mode 100644 index 0000000..9f12cc1 --- /dev/null +++ b/chrome/browser/views/edit_search_engine_dialog.h @@ -0,0 +1,104 @@ +// Copyright (c) 2009 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. + +// EditSearchEngineDialog provides text fields for editing a keyword: the title, +// url and actual keyword. It is used by the KeywordEditorView of the Options +// dialog, and also on its own to confirm the addition of a keyword added by +// the ExternalJSObject via the RenderView. + +#ifndef CHROME_BROWSER_VIEWS_EDIT_SEARCH_ENGINE_DIALOG_H_ +#define CHROME_BROWSER_VIEWS_EDIT_SEARCH_ENGINE_DIALOG_H_ + +#include + +#include "views/controls/textfield/textfield.h" +#include "views/window/dialog_delegate.h" + +namespace views { +class Label; +class ImageView; +class Window; +} + +class EditSearchEngineController; +class EditSearchEngineControllerDelegate; +class Profile; +class TemplateURL; +class TemplateURLModel; + +class EditSearchEngineDialog : public views::View, + public views::Textfield::Controller, + public views::DialogDelegate { + public: + // The |template_url| and/or |delegate| may be NULL. + EditSearchEngineDialog(const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile); + virtual ~EditSearchEngineDialog() {} + + // Shows the dialog to the user. + static void Show(gfx::NativeWindow parent, + const TemplateURL* template_url, + EditSearchEngineControllerDelegate* delegate, + Profile* profile); + + // views::DialogDelegate overrides. + virtual bool IsModal() const; + virtual std::wstring GetWindowTitle() const; + virtual bool IsDialogButtonEnabled( + MessageBoxFlags::DialogButton button) const; + virtual bool Cancel(); + virtual bool Accept(); + virtual views::View* GetContentsView(); + + // views::Textfield::Controller overrides. Updates whether the user can + // accept the dialog as well as updating image views showing whether value is + // valid. + virtual void ContentsChanged(views::Textfield* sender, + const std::wstring& new_contents); + virtual bool HandleKeystroke(views::Textfield* sender, + const views::Textfield::Keystroke& key); + + private: + void Init(); + + // Create a Label containing the text with the specified message id. + views::Label* CreateLabel(int message_id); + + // Creates a text field with the specified text. If |lowercase| is true, the + // Textfield is configured to map all input to lower case. + views::Textfield* CreateTextfield(const std::wstring& text, bool lowercase); + + // Invokes UpdateImageView for each of the images views. + void UpdateImageViews(); + + // Updates the tooltip and image of the image view based on is_valid. If + // is_valid is false the tooltip of the image view is set to the message with + // id invalid_message_id, otherwise the tooltip is set to the empty text. + void UpdateImageView(views::ImageView* image_view, + bool is_valid, + int invalid_message_id); + + // Used to parent window to. May be NULL or an invalid window. + HWND parent_; + + // View containing the buttons, text fields ... + views::View* view_; + + // Text fields. + views::Textfield* title_tf_; + views::Textfield* keyword_tf_; + views::Textfield* url_tf_; + + // Shows error images. + views::ImageView* title_iv_; + views::ImageView* keyword_iv_; + views::ImageView* url_iv_; + + scoped_ptr controller_; + + DISALLOW_COPY_AND_ASSIGN(EditSearchEngineDialog); +}; + +#endif // CHROME_BROWSER_VIEWS_EDIT_SEARCH_ENGINE_DIALOG_H_ diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index bfb85f8..ea96ac1 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -809,6 +809,12 @@ void BrowserView::DisableInactiveFrame() { frame_->GetWindow()->DisableInactiveRendering(); } +void BrowserView::ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) { + browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url, NULL, + profile); +} + void BrowserView::ToggleBookmarkBar() { bookmark_utils::ToggleWhenVisible(browser_->profile()); } diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index 03b75a3..4ca85c4 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -213,6 +213,8 @@ class BrowserView : public BrowserWindow, virtual bool IsBookmarkBarVisible() const; virtual gfx::Rect GetRootWindowResizerRect() const; virtual void DisableInactiveFrame(); + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile); virtual void ToggleBookmarkBar(); virtual void ShowAboutChromeDialog(); virtual void ShowTaskManager(); diff --git a/chrome/browser/views/keyword_editor_view.cc b/chrome/browser/views/keyword_editor_view.cc index bfe3065..bfdd65d 100644 --- a/chrome/browser/views/keyword_editor_view.cc +++ b/chrome/browser/views/keyword_editor_view.cc @@ -16,7 +16,7 @@ #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" -#include "chrome/browser/views/edit_keyword_controller.h" +#include "chrome/browser/views/browser_dialogs.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" #include "googleurl/src/gurl.h" @@ -584,10 +584,8 @@ void KeywordEditorView::OnDoubleClick() { void KeywordEditorView::ButtonPressed(views::Button* sender) { if (sender == add_button_) { - EditKeywordController* controller = - new EditKeywordController(GetWidget()->GetNativeView(), NULL, this, - profile_); - controller->Show(); + browser::EditSearchEngine(GetWindow()->GetNativeWindow(), NULL, this, + profile_); } else if (sender == remove_button_) { DCHECK(table_view_->SelectedRowCount() > 0); // Remove the observer while we modify the model, that way we don't need to @@ -613,10 +611,8 @@ void KeywordEditorView::ButtonPressed(views::Button* sender) { const int selected_row = table_view_->FirstSelectedRow(); const TemplateURL* template_url = &table_model_->GetTemplateURL(selected_row); - EditKeywordController* controller = - new EditKeywordController(GetWidget()->GetNativeView(), template_url, - this, profile_); - controller->Show(); + browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url, + this, profile_); } else if (sender == make_default_button_) { MakeDefaultSearchProvider(); } else { diff --git a/chrome/browser/views/keyword_editor_view.h b/chrome/browser/views/keyword_editor_view.h index a0b56ad..c906d65 100644 --- a/chrome/browser/views/keyword_editor_view.h +++ b/chrome/browser/views/keyword_editor_view.h @@ -9,7 +9,7 @@ #include #include "app/table_model.h" -#include "chrome/browser/search_engines/edit_keyword_controller_base.h" +#include "chrome/browser/search_engines/edit_search_engine_controller.h" #include "chrome/browser/search_engines/template_url_model.h" #include "views/controls/button/button.h" #include "views/controls/table/table_view_observer.h" @@ -121,7 +121,7 @@ class KeywordEditorView : public views::View, public views::ButtonListener, public TemplateURLModelObserver, public views::DialogDelegate, - public EditKeywordControllerBase::Delegate { + public EditSearchEngineControllerDelegate { friend class KeywordEditorViewTest; FRIEND_TEST(KeywordEditorViewTest, MakeDefault); public: @@ -132,7 +132,7 @@ class KeywordEditorView : public views::View, explicit KeywordEditorView(Profile* profile); virtual ~KeywordEditorView(); - // Overridden from EditKeywordControllerBase::Delegate. + // Overridden from EditSearchEngineControllerDelegate. // Calls AddTemplateURL or ModifyTemplateURL as appropriate. virtual void OnEditedKeyword(const TemplateURL* template_url, const std::wstring& title, -- cgit v1.1