summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-27 01:44:33 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-27 01:44:33 +0000
commit5cb702d7e5c903fa35029aa1daf63269b947801a (patch)
tree93264fb268e2ee695a7033bea33436c5fec33ce2 /chrome
parent3dfc7a41b5e87e3fb1b99836e26a8a62aa3efcfe (diff)
downloadchromium_src-5cb702d7e5c903fa35029aa1daf63269b947801a.zip
chromium_src-5cb702d7e5c903fa35029aa1daf63269b947801a.tar.gz
chromium_src-5cb702d7e5c903fa35029aa1daf63269b947801a.tar.bz2
Finish the gtk search engine manager.
BUG=13326 TEST=Open options, click search engines manage button, try adding, removing, making default, etc. Review URL: http://codereview.chromium.org/147243 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19449 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/gtk/keyword_editor_view.cc310
-rw-r--r--chrome/browser/gtk/keyword_editor_view.h66
2 files changed, 353 insertions, 23 deletions
diff --git a/chrome/browser/gtk/keyword_editor_view.cc b/chrome/browser/gtk/keyword_editor_view.cc
index 8ce4156..62e20b6 100644
--- a/chrome/browser/gtk/keyword_editor_view.cc
+++ b/chrome/browser/gtk/keyword_editor_view.cc
@@ -5,11 +5,14 @@
#include "chrome/browser/gtk/keyword_editor_view.h"
#include "app/l10n_util.h"
+#include "base/gfx/gtk_util.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/keyword_editor_controller.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_table_model.h"
#include "chrome/common/gtk_util.h"
#include "grit/generated_resources.h"
@@ -19,11 +22,20 @@ namespace {
const int kDialogDefaultWidth = 450;
const int kDialogDefaultHeight = 450;
+// How many rows should be added to an index into the |table_model_| to get the
+// corresponding row in |list_store_|
+const int kFirstGroupRowOffset = 2;
+const int kSecondGroupRowOffset = 5;
+
// Column ids for |list_store_|.
enum {
COL_FAVICON,
COL_TITLE,
COL_KEYWORD,
+ COL_IS_HEADER,
+ COL_IS_SEPARATOR,
+ COL_WEIGHT,
+ COL_WEIGHT_SET,
COL_COUNT,
};
@@ -49,24 +61,28 @@ void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
const std::wstring& title,
const std::wstring& keyword,
const std::wstring& url) {
- NOTIMPLEMENTED();
+ if (template_url) {
+ controller_->ModifyTemplateURL(template_url, title, keyword, url);
+
+ // Force the make default button to update.
+ EnableControls();
+ } else {
+ SelectModelRow(controller_->AddTemplateURL(title, keyword, url));
+ }
}
KeywordEditorView::~KeywordEditorView() {
- url_model_->RemoveObserver(this);
+ controller_->url_model()->RemoveObserver(this);
}
KeywordEditorView::KeywordEditorView(Profile* profile)
: profile_(profile),
- url_model_(profile->GetTemplateURLModel()) {
+ controller_(new KeywordEditorController(profile)),
+ table_model_(controller_->table_model()) {
Init();
}
void KeywordEditorView::Init() {
- DCHECK(url_model_);
- url_model_->Load();
- url_model_->AddObserver(this);
-
dialog_ = gtk_dialog_new_with_buttons(
l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE).c_str(),
NULL,
@@ -95,9 +111,18 @@ void KeywordEditorView::Init() {
list_store_ = gtk_list_store_new(COL_COUNT,
GDK_TYPE_PIXBUF,
G_TYPE_STRING,
- G_TYPE_STRING);
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_BOOLEAN);
tree_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_), TRUE);
+ gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(tree_),
+ OnCheckRowIsSeparator,
+ NULL, NULL);
+ g_signal_connect(G_OBJECT(tree_), "row-activated",
+ G_CALLBACK(OnRowActivated), this);
gtk_container_add(GTK_CONTAINER(scroll_window), tree_);
GtkTreeViewColumn* title_column = gtk_tree_view_column_new();
@@ -109,6 +134,10 @@ void KeywordEditorView::Init() {
gtk_tree_view_column_pack_start(title_column, title_renderer, TRUE);
gtk_tree_view_column_add_attribute(title_column, title_renderer, "text",
COL_TITLE);
+ gtk_tree_view_column_add_attribute(title_column, title_renderer, "weight",
+ COL_WEIGHT);
+ gtk_tree_view_column_add_attribute(title_column, title_renderer, "weight-set",
+ COL_WEIGHT_SET);
gtk_tree_view_column_set_title(
title_column, l10n_util::GetStringUTF8(
IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN).c_str());
@@ -124,6 +153,8 @@ void KeywordEditorView::Init() {
selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_));
gtk_tree_selection_set_mode(selection_, GTK_SELECTION_SINGLE);
+ gtk_tree_selection_set_select_function(selection_, OnSelectionFilter,
+ NULL, NULL);
g_signal_connect(G_OBJECT(selection_), "changed",
G_CALLBACK(OnSelectionChanged), this);
@@ -157,6 +188,10 @@ void KeywordEditorView::Init() {
gtk_box_pack_start(GTK_BOX(button_box), make_default_button_, FALSE, FALSE,
0);
+ controller_->url_model()->AddObserver(this);
+ table_model_->SetObserver(this);
+ table_model_->Reload();
+
EnableControls();
gtk_widget_show_all(dialog_);
@@ -166,18 +201,198 @@ void KeywordEditorView::Init() {
}
void KeywordEditorView::EnableControls() {
- bool enable = gtk_tree_selection_count_selected_rows(selection_) == 1;
+ bool can_edit = false;
bool can_make_default = false;
bool can_remove = false;
- // TODO(mattm)
- gtk_widget_set_sensitive(add_button_, url_model_->loaded());
- gtk_widget_set_sensitive(edit_button_, enable);
- gtk_widget_set_sensitive(remove_button_, can_make_default);
- gtk_widget_set_sensitive(make_default_button_, can_remove);
+ int model_row = GetSelectedModelRow();
+ if (model_row != -1) {
+ can_edit = true;
+ const TemplateURL* selected_url = controller_->GetTemplateURL(model_row);
+ can_make_default = controller_->CanMakeDefault(selected_url);
+ can_remove = controller_->CanRemove(selected_url);
+ }
+ gtk_widget_set_sensitive(add_button_, controller_->loaded());
+ gtk_widget_set_sensitive(edit_button_, can_edit);
+ gtk_widget_set_sensitive(remove_button_, can_remove);
+ gtk_widget_set_sensitive(make_default_button_, can_make_default);
+}
+
+void KeywordEditorView::SetColumnValues(int model_row, GtkTreeIter* iter) {
+ SkBitmap bitmap = table_model_->GetIcon(model_row);
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
+ gtk_list_store_set(
+ list_store_, iter,
+ COL_FAVICON, pixbuf,
+ // Dunno why, even with COL_WEIGHT_SET to FALSE here, the weight still
+ // has an effect. So we just set it to normal.
+ COL_WEIGHT, PANGO_WEIGHT_NORMAL,
+ COL_WEIGHT_SET, TRUE,
+ COL_TITLE, WideToUTF8(table_model_->GetText(
+ model_row, IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN)).c_str(),
+ COL_KEYWORD, WideToUTF8(table_model_->GetText(
+ model_row, IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN)).c_str(),
+ -1);
+}
+
+int KeywordEditorView::GetListStoreRowForModelRow(int model_row) const {
+ if (model_row < model_second_group_index_)
+ return model_row + kFirstGroupRowOffset;
+ else
+ return model_row + kSecondGroupRowOffset;
+}
+
+int KeywordEditorView::GetModelRowForPath(GtkTreePath* path) const {
+ gint* indices = gtk_tree_path_get_indices(path);
+ if (!indices) {
+ NOTREACHED();
+ return -1;
+ }
+ if (indices[0] >= model_second_group_index_ + kSecondGroupRowOffset)
+ return indices[0] - kSecondGroupRowOffset;
+ return indices[0] - kFirstGroupRowOffset;
+}
+
+int KeywordEditorView::GetModelRowForIter(GtkTreeIter* iter) const {
+ GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(list_store_),
+ iter);
+ int model_row = GetModelRowForPath(path);
+ gtk_tree_path_free(path);
+ return model_row;
+}
+
+int KeywordEditorView::GetSelectedModelRow() const {
+ GtkTreeIter iter;
+ if (!gtk_tree_selection_get_selected(selection_, NULL, &iter))
+ return -1;
+ return GetModelRowForIter(&iter);
+}
+
+void KeywordEditorView::SelectModelRow(int model_row) {
+ int row = GetListStoreRowForModelRow(model_row);
+ GtkTreeIter iter;
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
+ &iter, NULL, row)) {
+ NOTREACHED();
+ return;
+ }
+ GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(list_store_),
+ &iter);
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree_), path, NULL, FALSE);
+ gtk_tree_path_free(path);
+}
+
+void KeywordEditorView::AddNodeToList(int model_row) {
+ GtkTreeIter iter;
+ int row = GetListStoreRowForModelRow(model_row);
+ if (row == 0) {
+ gtk_list_store_prepend(list_store_, &iter);
+ } else {
+ GtkTreeIter sibling;
+ gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_), &sibling,
+ NULL, row - 1);
+ gtk_list_store_insert_after(list_store_, &iter, &sibling);
+ }
+
+ SetColumnValues(model_row, &iter);
+}
+
+void KeywordEditorView::OnModelChanged() {
+ model_second_group_index_ = table_model_->last_search_engine_index();
+ gtk_list_store_clear(list_store_);
+
+ TableModel::Groups groups(table_model_->GetGroups());
+ if (groups.size() != 2) {
+ NOTREACHED();
+ return;
+ }
+
+ GtkTreeIter iter;
+ // First group title.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(
+ list_store_, &iter,
+ COL_WEIGHT, PANGO_WEIGHT_BOLD,
+ COL_WEIGHT_SET, TRUE,
+ COL_TITLE, WideToUTF8(groups[0].title).c_str(),
+ COL_IS_HEADER, TRUE,
+ -1);
+ // First group separator.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(
+ list_store_, &iter,
+ COL_IS_HEADER, TRUE,
+ COL_IS_SEPARATOR, TRUE,
+ -1);
+
+ // Blank row between groups.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(
+ list_store_, &iter,
+ COL_IS_HEADER, TRUE,
+ -1);
+ // Second group title.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(
+ list_store_, &iter,
+ COL_WEIGHT, PANGO_WEIGHT_BOLD,
+ COL_WEIGHT_SET, TRUE,
+ COL_TITLE, WideToUTF8(groups[1].title).c_str(),
+ COL_IS_HEADER, TRUE,
+ -1);
+ // Second group separator.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(
+ list_store_, &iter,
+ COL_IS_HEADER, TRUE,
+ COL_IS_SEPARATOR, TRUE,
+ -1);
+
+ for (int i = 0; i < table_model_->RowCount(); ++i)
+ AddNodeToList(i);
+}
+
+void KeywordEditorView::OnItemsChanged(int start, int length) {
+ DCHECK(model_second_group_index_ == table_model_->last_search_engine_index());
+ GtkTreeIter iter;
+ for (int i = 0; i < length; ++i) {
+ int row = GetListStoreRowForModelRow(start + i);
+ bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
+ &iter, NULL, row);
+ if (!rv) {
+ NOTREACHED();
+ return;
+ }
+ SetColumnValues(start + i, &iter);
+ rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
+ }
+}
+
+void KeywordEditorView::OnItemsAdded(int start, int length) {
+ model_second_group_index_ = table_model_->last_search_engine_index();
+ for (int i = 0; i < length; ++i) {
+ AddNodeToList(start + i);
+ }
+}
+
+void KeywordEditorView::OnItemsRemoved(int start, int length) {
+ // This is quite likely not correct with removing multiple in one call, but
+ // that shouldn't happen since we only can select and modify/remove one at a
+ // time.
+ DCHECK(length == 1);
+ for (int i = 0; i < length; ++i) {
+ int row = GetListStoreRowForModelRow(start + i);
+ GtkTreeIter iter;
+ if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_), &iter,
+ NULL, row)) {
+ NOTREACHED();
+ return;
+ }
+ gtk_list_store_remove(list_store_, &iter);
+ }
+ model_second_group_index_ = table_model_->last_search_engine_index();
}
void KeywordEditorView::OnTemplateURLModelChanged() {
- // TODO(mattm): repopulate table
EnableControls();
}
@@ -195,12 +410,45 @@ void KeywordEditorView::OnResponse(GtkDialog* dialog, int response_id,
}
// static
+gboolean KeywordEditorView::OnCheckRowIsSeparator(GtkTreeModel* model,
+ GtkTreeIter* iter,
+ gpointer user_data) {
+ gboolean is_separator;
+ gtk_tree_model_get(model, iter, COL_IS_SEPARATOR, &is_separator, -1);
+ return is_separator;
+}
+
+//static
+gboolean KeywordEditorView::OnSelectionFilter(GtkTreeSelection *selection,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ gboolean path_currently_selected,
+ gpointer user_data) {
+ GtkTreeIter iter;
+ if (!gtk_tree_model_get_iter(model, &iter, path)) {
+ NOTREACHED();
+ return TRUE;
+ }
+ gboolean is_header;
+ gtk_tree_model_get(model, &iter, COL_IS_HEADER, &is_header, -1);
+ return !is_header;
+}
+
+// static
void KeywordEditorView::OnSelectionChanged(
GtkTreeSelection *selection, KeywordEditorView* editor) {
editor->EnableControls();
}
// static
+void KeywordEditorView::OnRowActivated(GtkTreeView* tree_view,
+ GtkTreePath* path,
+ GtkTreeViewColumn* column,
+ KeywordEditorView* editor) {
+ OnEditButtonClicked(NULL, editor);
+}
+
+// static
void KeywordEditorView::OnAddButtonClicked(GtkButton* button,
KeywordEditorView* editor) {
new EditSearchEngineDialog(
@@ -213,17 +461,43 @@ void KeywordEditorView::OnAddButtonClicked(GtkButton* button,
// static
void KeywordEditorView::OnEditButtonClicked(GtkButton* button,
KeywordEditorView* editor) {
- // TODO(mattm)
+ int model_row = editor->GetSelectedModelRow();
+ if (model_row == -1) {
+ NOTREACHED();
+ return;
+ }
+ new EditSearchEngineDialog(
+ GTK_WINDOW(gtk_widget_get_toplevel(editor->dialog_)),
+ editor->controller_->GetTemplateURL(model_row),
+ editor,
+ editor->profile_);
}
// static
void KeywordEditorView::OnRemoveButtonClicked(GtkButton* button,
KeywordEditorView* editor) {
- // TODO(mattm)
+ int model_row = editor->GetSelectedModelRow();
+ if (model_row == -1) {
+ NOTREACHED();
+ return;
+ }
+ editor->controller_->RemoveTemplateURL(model_row);
+ if (model_row >= editor->table_model_->RowCount())
+ model_row = editor->table_model_->RowCount() - 1;
+ if (model_row >= 0)
+ editor->SelectModelRow(model_row);
}
// static
void KeywordEditorView::OnMakeDefaultButtonClicked(GtkButton* button,
KeywordEditorView* editor) {
- // TODO(mattm)
+ int model_row = editor->GetSelectedModelRow();
+ if (model_row == -1) {
+ NOTREACHED();
+ return;
+ }
+ int new_index = editor->controller_->MakeDefaultTemplateURL(model_row);
+ if (new_index > 0) {
+ editor->SelectModelRow(new_index);
+ }
}
diff --git a/chrome/browser/gtk/keyword_editor_view.h b/chrome/browser/gtk/keyword_editor_view.h
index bac83115..0ee4fee 100644
--- a/chrome/browser/gtk/keyword_editor_view.h
+++ b/chrome/browser/gtk/keyword_editor_view.h
@@ -7,13 +7,17 @@
#include <gtk/gtk.h>
+#include "app/table_model_observer.h"
#include "base/basictypes.h"
#include "chrome/browser/search_engines/edit_search_engine_controller.h"
#include "chrome/browser/search_engines/template_url_model.h"
+class KeywordEditorController;
class Profile;
+class TemplateURLTableModel;
-class KeywordEditorView : public TemplateURLModelObserver,
+class KeywordEditorView : public TableModelObserver,
+ public TemplateURLModelObserver,
public EditSearchEngineControllerDelegate {
public:
virtual ~KeywordEditorView();
@@ -33,6 +37,35 @@ class KeywordEditorView : public TemplateURLModelObserver,
// Enable buttons based on selection state.
void EnableControls();
+ // Set the column values for |row| of |table_model_| in the |list_store_| at
+ // |iter|.
+ void SetColumnValues(int row, GtkTreeIter* iter);
+
+ // Get the row number in the GtkListStore corresponding to |model_row|.
+ int GetListStoreRowForModelRow(int model_row) const;
+
+ // Get the row number in the TemplateURLTableModel corresponding to |path|.
+ int GetModelRowForPath(GtkTreePath* path) const;
+
+ // Get the row number in the TemplateURLTableModel corresponding to |iter|.
+ int GetModelRowForIter(GtkTreeIter* iter) const;
+
+ // Get the row number in the TemplateURLTableModel of the current selection,
+ // or -1 if no row is selected.
+ int GetSelectedModelRow() const;
+
+ // Select the row in the |tree_| corresponding to |model_row|.
+ void SelectModelRow(int model_row);
+
+ // Add the values from |row| of |table_model_|.
+ void AddNodeToList(int row);
+
+ // TableModelObserver implementation.
+ virtual void OnModelChanged();
+ virtual void OnItemsChanged(int start, int length);
+ virtual void OnItemsAdded(int start, int length);
+ virtual void OnItemsRemoved(int start, int length);
+
// TemplateURLModelObserver notification.
virtual void OnTemplateURLModelChanged();
@@ -43,11 +76,28 @@ class KeywordEditorView : public TemplateURLModelObserver,
static void OnResponse(GtkDialog* dialog, int response_id,
KeywordEditorView* window);
+ // Callback checking whether a row should be drawn as a separator.
+ static gboolean OnCheckRowIsSeparator(GtkTreeModel* model,
+ GtkTreeIter* iter,
+ gpointer user_data);
+
+ // Callback checking whether a row may be selected. We use some rows in the
+ // table as headers/separators for the groups, which should not be selectable.
+ static gboolean OnSelectionFilter(GtkTreeSelection* selection,
+ GtkTreeModel* model,
+ GtkTreePath* path,
+ gboolean path_currently_selected,
+ gpointer user_data);
+
// Callback for when user selects something.
static void OnSelectionChanged(GtkTreeSelection *selection,
KeywordEditorView* editor);
- // Callbacks for buttons modifying the table.
+ // Callbacks for user actions modifying the table.
+ static void OnRowActivated(GtkTreeView* tree_view,
+ GtkTreePath* path,
+ GtkTreeViewColumn* column,
+ KeywordEditorView* editor);
static void OnAddButtonClicked(GtkButton* button,
KeywordEditorView* editor);
static void OnEditButtonClicked(GtkButton* button,
@@ -74,9 +124,15 @@ class KeywordEditorView : public TemplateURLModelObserver,
// The profile.
Profile* profile_;
- // Model containing TemplateURLs. We listen for changes on this and propagate
- // them to the table model.
- TemplateURLModel* url_model_;
+ scoped_ptr<KeywordEditorController> controller_;
+
+ TemplateURLTableModel* table_model_;
+
+ // We store our own index of the start of the second group within the model,
+ // as when OnItemsRemoved is called the value in the model is already updated
+ // but we need the old value to know which row to remove from the
+ // |list_store_|.
+ int model_second_group_index_;
DISALLOW_COPY_AND_ASSIGN(KeywordEditorView);
};