summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/edit_search_engine_dialog.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/gtk/edit_search_engine_dialog.cc')
-rw-r--r--chrome/browser/gtk/edit_search_engine_dialog.cc255
1 files changed, 255 insertions, 0 deletions
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 <gtk/gtk.h>
+
+#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<gpointer>(LowercaseInsertTextHandler), data);
+ gtk_editable_insert_text(editable, result.c_str(), result.size(), position);
+ g_signal_handlers_unblock_by_func(G_OBJECT(editable),
+ reinterpret_cast<gpointer>(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<GtkDialogFlags>(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<std::string::size_type>(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);
+}