diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-27 01:44:33 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-27 01:44:33 +0000 |
commit | 5cb702d7e5c903fa35029aa1daf63269b947801a (patch) | |
tree | 93264fb268e2ee695a7033bea33436c5fec33ce2 /chrome | |
parent | 3dfc7a41b5e87e3fb1b99836e26a8a62aa3efcfe (diff) | |
download | chromium_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.cc | 310 | ||||
-rw-r--r-- | chrome/browser/gtk/keyword_editor_view.h | 66 |
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); }; |