OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/gtk/bookmark_editor_gtk.h" | 5 #include "chrome/browser/gtk/bookmark_editor_gtk.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 | 8 |
9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/gfx/gtk_util.h" | 11 #include "base/gfx/gtk_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "chrome/browser/gtk/bookmark_tree_model.h" | 14 #include "chrome/browser/gtk/bookmark_tree_model.h" |
15 #include "chrome/browser/bookmarks/bookmark_utils.h" | 15 #include "chrome/browser/bookmarks/bookmark_utils.h" |
16 #include "chrome/browser/history/history.h" | 16 #include "chrome/browser/history/history.h" |
17 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
18 #include "chrome/browser/net/url_fixer_upper.h" | 18 #include "chrome/browser/net/url_fixer_upper.h" |
19 #include "googleurl/src/gurl.h" | 19 #include "googleurl/src/gurl.h" |
20 #include "grit/chromium_strings.h" | 20 #include "grit/chromium_strings.h" |
21 #include "grit/generated_resources.h" | 21 #include "grit/generated_resources.h" |
22 #include "grit/locale_settings.h" | 22 #include "grit/locale_settings.h" |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 // Background color of text field when URL is invalid. | 26 // Background color of text field when URL is invalid. |
27 const GdkColor kErrorColor = GDK_COLOR_RGB(0xFF, 0xBC, 0xBC); | 27 const GdkColor kErrorColor = GDK_COLOR_RGB(0xFF, 0xBC, 0xBC); |
28 | 28 |
29 // Preferred width of the tree. | 29 // Preferred initial dimensions, in pixels, of the folder tree. |
30 static const int kTreeWidth = 300; | 30 static const int kTreeWidth = 300; |
31 static const int kTreeHeight = 150; | 31 static const int kTreeHeight = 150; |
32 | 32 |
33 } // namespace | 33 } // namespace |
34 | 34 |
35 // static | 35 // static |
36 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, | 36 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, |
37 Profile* profile, | 37 Profile* profile, |
38 BookmarkNode* parent, | 38 BookmarkNode* parent, |
39 BookmarkNode* node, | 39 BookmarkNode* node, |
(...skipping 29 matching lines...) Expand all Loading... |
69 // tree will reference a deleted model. | 69 // tree will reference a deleted model. |
70 | 70 |
71 bb_model_->RemoveObserver(this); | 71 bb_model_->RemoveObserver(this); |
72 } | 72 } |
73 | 73 |
74 void BookmarkEditorGtk::Init(GtkWindow* parent_window) { | 74 void BookmarkEditorGtk::Init(GtkWindow* parent_window) { |
75 bb_model_ = profile_->GetBookmarkModel(); | 75 bb_model_ = profile_->GetBookmarkModel(); |
76 DCHECK(bb_model_); | 76 DCHECK(bb_model_); |
77 bb_model_->AddObserver(this); | 77 bb_model_->AddObserver(this); |
78 | 78 |
79 // TODO(erg): Redo this entire class as a normal GtkWindow with it's modality | |
80 // manually set to TRUE because using the stock GtkDialog class gives me | |
81 // almost no control over the buttons on the bottom. | |
82 dialog_ = gtk_dialog_new_with_buttons( | 79 dialog_ = gtk_dialog_new_with_buttons( |
83 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_TITLE).c_str(), | 80 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_TITLE).c_str(), |
84 parent_window, | 81 parent_window, |
85 GTK_DIALOG_MODAL, | 82 GTK_DIALOG_MODAL, |
| 83 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, |
| 84 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, |
86 NULL); | 85 NULL); |
| 86 gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE); |
87 | 87 |
88 if (show_tree_) { | 88 if (show_tree_) { |
89 // We want the New Folder button to not automatically dismiss the dialog so | |
90 // we have to do that manually. gtk_dialog_add_button() always makes the | |
91 // button dismiss the dialog box. This isn't 100% accurate to what I want; | |
92 // see above about redoing this as a GtkWindow. | |
93 GtkWidget* action_area = GTK_DIALOG(dialog_)->action_area; | 89 GtkWidget* action_area = GTK_DIALOG(dialog_)->action_area; |
94 new_folder_button_ = gtk_button_new_with_label("New Folder"); | 90 GtkWidget* new_folder_button = gtk_button_new_with_label( |
95 g_signal_connect(new_folder_button_, "clicked", | 91 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_BUTTON).c_str()); |
| 92 g_signal_connect(new_folder_button, "clicked", |
96 G_CALLBACK(OnNewFolderClicked), this); | 93 G_CALLBACK(OnNewFolderClicked), this); |
97 gtk_box_pack_start(GTK_BOX(action_area), new_folder_button_, | 94 gtk_container_add(GTK_CONTAINER(action_area), new_folder_button); |
98 FALSE, FALSE, 0); | 95 gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(action_area), |
| 96 new_folder_button, TRUE); |
99 } | 97 } |
100 | 98 |
101 close_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_), | |
102 GTK_STOCK_CANCEL, | |
103 GTK_RESPONSE_REJECT); | |
104 ok_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_), | |
105 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); | |
106 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT); | 99 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT); |
107 | 100 |
108 // The GTK dialog content area layout (overview) | 101 // The GTK dialog content area layout (overview) |
109 // | 102 // |
110 // +- GtkVBox |content_area| --------------------------------------+ | 103 // +- GtkVBox |vbox| ----------------------------------------------+ |
111 // |+- GtkTable |table| ------------------------------------------+| | 104 // |+- GtkTable |table| ------------------------------------------+| |
112 // ||+- GtkLabel ------+ +- GtkEntry |name_entry_| --------------+|| | 105 // ||+- GtkLabel ------+ +- GtkEntry |name_entry_| --------------+|| |
113 // ||| | | ||| | 106 // ||| | | ||| |
114 // ||+-----------------+ +---------------------------------------+|| | 107 // ||+-----------------+ +---------------------------------------+|| |
115 // ||+- GtkLabel ------+ +- GtkEntry |url_entry_| ---------------+|| | 108 // ||+- GtkLabel ------+ +- GtkEntry |url_entry_| ---------------+|| |
116 // ||| | | ||| | 109 // ||| | | ||| |
117 // ||+-----------------+ +---------------------------------------+|| | 110 // ||+-----------------+ +---------------------------------------+|| |
118 // |+-------------------------------------------------------------+| | 111 // |+-------------------------------------------------------------+| |
119 // |+- GtkScrollWindow |scroll_window| ---------------------------+| | 112 // |+- GtkScrollWindow |scroll_window| ---------------------------+| |
120 // ||+- GtkTreeView |tree_view_| --------------------------------+|| | 113 // ||+- GtkTreeView |tree_view_| --------------------------------+|| |
121 // |||+- GtkTreeViewColumn |name_column| -----------------------+||| | 114 // |||+- GtkTreeViewColumn |name_column| -----------------------+||| |
122 // |||| |||| | 115 // |||| |||| |
123 // |||| |||| | 116 // |||| |||| |
124 // |||| |||| | 117 // |||| |||| |
125 // |||| |||| | 118 // |||| |||| |
126 // |||+---------------------------------------------------------+||| | 119 // |||+---------------------------------------------------------+||| |
127 // ||+-----------------------------------------------------------+|| | 120 // ||+-----------------------------------------------------------+|| |
128 // |+-------------------------------------------------------------+| | 121 // |+-------------------------------------------------------------+| |
129 // +---------------------------------------------------------------+ | 122 // +---------------------------------------------------------------+ |
130 GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox; | 123 GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox; |
131 gtk_container_set_border_width(GTK_CONTAINER(content_area), 12); | 124 gtk_box_set_spacing(GTK_BOX(content_area), 18); |
| 125 |
| 126 GtkWidget* vbox = gtk_vbox_new(FALSE, 12); |
| 127 |
132 GtkWidget* table = gtk_table_new(2, 2, FALSE); | 128 GtkWidget* table = gtk_table_new(2, 2, FALSE); |
| 129 gtk_table_set_col_spacing(GTK_TABLE(table), 0, 12); |
| 130 gtk_table_set_row_spacings(GTK_TABLE(table), 6); |
133 | 131 |
134 GtkWidget* label = gtk_label_new( | 132 GtkWidget* label = gtk_label_new( |
135 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NAME_LABEL).c_str()); | 133 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NAME_LABEL).c_str()); |
| 134 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
136 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), | 135 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), |
137 0, 1, 0, 1, | 136 0, 1, 0, 1, |
138 (GtkAttachOptions)(GTK_SHRINK), | 137 (GtkAttachOptions)(GTK_FILL), |
139 (GtkAttachOptions)(GTK_SHRINK), | 138 (GtkAttachOptions)(GTK_FILL), |
140 12, 0); | 139 0, 0); |
141 name_entry_ = gtk_entry_new(); | 140 name_entry_ = gtk_entry_new(); |
142 gtk_entry_set_text(GTK_ENTRY(name_entry_), | 141 gtk_entry_set_text(GTK_ENTRY(name_entry_), |
143 node_ ? WideToUTF8(node_->GetTitle()).c_str() : ""); | 142 node_ ? WideToUTF8(node_->GetTitle()).c_str() : ""); |
144 g_signal_connect(G_OBJECT(name_entry_), "changed", | 143 g_signal_connect(G_OBJECT(name_entry_), "changed", |
145 G_CALLBACK(OnEntryChanged), this); | 144 G_CALLBACK(OnEntryChanged), this); |
146 g_object_set(G_OBJECT(name_entry_), "activates-default", TRUE, NULL); | 145 gtk_entry_set_activates_default(GTK_ENTRY(name_entry_), TRUE); |
147 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(name_entry_), | 146 gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(name_entry_), |
148 1, 2, 0, 1, | 147 1, 2, 0, 1); |
149 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), | |
150 (GtkAttachOptions)(GTK_FILL), | |
151 0, 0); | |
152 | 148 |
153 label = gtk_label_new( | 149 label = gtk_label_new( |
154 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_URL_LABEL).c_str()); | 150 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_URL_LABEL).c_str()); |
| 151 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
155 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), | 152 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), |
156 0, 1, 1, 2, | 153 0, 1, 1, 2, |
157 (GtkAttachOptions)(GTK_SHRINK), | 154 (GtkAttachOptions)(GTK_FILL), |
158 (GtkAttachOptions)(GTK_SHRINK), | 155 (GtkAttachOptions)(GTK_FILL), |
159 12, 0); | 156 0, 0); |
160 url_entry_ = gtk_entry_new(); | 157 url_entry_ = gtk_entry_new(); |
161 gtk_entry_set_text(GTK_ENTRY(url_entry_), | 158 gtk_entry_set_text(GTK_ENTRY(url_entry_), |
162 node_ ? node_->GetURL().spec().c_str() : ""); | 159 node_ ? node_->GetURL().spec().c_str() : ""); |
163 g_signal_connect(G_OBJECT(url_entry_), "changed", | 160 g_signal_connect(G_OBJECT(url_entry_), "changed", |
164 G_CALLBACK(OnEntryChanged), this); | 161 G_CALLBACK(OnEntryChanged), this); |
165 g_object_set(G_OBJECT(url_entry_), "activates-default", TRUE, NULL); | 162 gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE); |
166 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(url_entry_), | 163 gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(url_entry_), |
167 1, 2, 1, 2, | 164 1, 2, 1, 2); |
168 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), | |
169 (GtkAttachOptions)(GTK_FILL), | |
170 0, 0); | |
171 | 165 |
172 gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0); | 166 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); |
173 | 167 |
174 if (show_tree_) { | 168 if (show_tree_) { |
175 GtkTreeIter selected_iter; | 169 GtkTreeIter selected_iter; |
176 int selected_id = node_ ? node_->GetParent()->id() : 0; | 170 int selected_id = node_ ? node_->GetParent()->id() : 0; |
177 bookmark_utils::BuildTreeStoreFrom(bb_model_, selected_id, &tree_store_, | 171 bookmark_utils::BuildTreeStoreFrom(bb_model_, selected_id, &tree_store_, |
178 &selected_iter); | 172 &selected_iter); |
179 | 173 |
180 // TODO(erg): Figure out how to place icons here. | 174 // TODO(erg): Figure out how to place icons here. |
181 GtkTreeViewColumn* name_column = | 175 GtkTreeViewColumn* name_column = |
182 gtk_tree_view_column_new_with_attributes( | 176 gtk_tree_view_column_new_with_attributes( |
183 "Folder", gtk_cell_renderer_text_new(), "text", 0, NULL); | 177 "Folder", gtk_cell_renderer_text_new(), "text", 0, NULL); |
184 | 178 |
185 tree_view_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store_)); | 179 tree_view_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store_)); |
186 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view_), FALSE); | 180 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view_), FALSE); |
187 gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view_), name_column, -1); | 181 gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view_), name_column, -1); |
188 gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight); | 182 gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight); |
189 | 183 |
190 tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_)); | 184 tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_)); |
191 | 185 |
192 if (selected_id) { | 186 if (selected_id) { |
193 GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store_), | 187 GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store_), |
194 &selected_iter); | 188 &selected_iter); |
195 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path); | 189 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path); |
196 gtk_tree_selection_select_path(tree_selection_, path); | 190 gtk_tree_selection_select_path(tree_selection_, path); |
197 gtk_tree_path_free(path); | 191 gtk_tree_path_free(path); |
198 } | 192 } |
199 | 193 |
200 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL); | 194 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL); |
201 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), | 195 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), |
202 GTK_POLICY_NEVER, | 196 GTK_POLICY_NEVER, |
203 GTK_POLICY_AUTOMATIC); | 197 GTK_POLICY_AUTOMATIC); |
| 198 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window), |
| 199 GTK_SHADOW_ETCHED_IN); |
204 gtk_container_add(GTK_CONTAINER(scroll_window), tree_view_); | 200 gtk_container_add(GTK_CONTAINER(scroll_window), tree_view_); |
205 gtk_box_pack_start(GTK_BOX(content_area), scroll_window, TRUE, TRUE, 12); | 201 |
| 202 gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0); |
206 } | 203 } |
207 | 204 |
| 205 gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0); |
| 206 |
208 g_signal_connect(dialog_, "response", | 207 g_signal_connect(dialog_, "response", |
209 G_CALLBACK(OnResponse), this); | 208 G_CALLBACK(OnResponse), this); |
210 g_signal_connect(dialog_, "delete-event", | 209 g_signal_connect(dialog_, "delete-event", |
211 G_CALLBACK(OnWindowDeleteEvent), this); | 210 G_CALLBACK(OnWindowDeleteEvent), this); |
212 g_signal_connect(dialog_, "destroy", | 211 g_signal_connect(dialog_, "destroy", |
213 G_CALLBACK(OnWindowDestroy), this); | 212 G_CALLBACK(OnWindowDestroy), this); |
214 } | 213 } |
215 | 214 |
216 void BookmarkEditorGtk::Show() { | 215 void BookmarkEditorGtk::Show() { |
217 // Manually call our OnEntryChanged handler to set the initial state. | 216 // Manually call our OnEntryChanged handler to set the initial state. |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 BookmarkEditorGtk* dialog) { | 357 BookmarkEditorGtk* dialog) { |
359 MessageLoop::current()->DeleteSoon(FROM_HERE, dialog); | 358 MessageLoop::current()->DeleteSoon(FROM_HERE, dialog); |
360 } | 359 } |
361 | 360 |
362 // static | 361 // static |
363 void BookmarkEditorGtk::OnEntryChanged(GtkEditable* entry, | 362 void BookmarkEditorGtk::OnEntryChanged(GtkEditable* entry, |
364 BookmarkEditorGtk* dialog) { | 363 BookmarkEditorGtk* dialog) { |
365 const GURL url(dialog->GetInputURL()); | 364 const GURL url(dialog->GetInputURL()); |
366 if (!url.is_valid()) { | 365 if (!url.is_valid()) { |
367 gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, &kErrorColor); | 366 gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, &kErrorColor); |
368 gtk_widget_set_sensitive(GTK_WIDGET(dialog->ok_button_), false); | 367 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->dialog_), |
| 368 GTK_RESPONSE_ACCEPT, FALSE); |
369 } else { | 369 } else { |
370 gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, NULL); | 370 gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, NULL); |
371 gtk_widget_set_sensitive(GTK_WIDGET(dialog->ok_button_), true); | 371 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->dialog_), |
| 372 GTK_RESPONSE_ACCEPT, TRUE); |
372 } | 373 } |
373 } | 374 } |
374 | 375 |
375 // static | 376 // static |
376 void BookmarkEditorGtk::OnNewFolderClicked(GtkWidget* button, | 377 void BookmarkEditorGtk::OnNewFolderClicked(GtkWidget* button, |
377 BookmarkEditorGtk* dialog) { | 378 BookmarkEditorGtk* dialog) { |
378 // TODO(erg): Make the inserted item here editable and edit it. If that's | 379 // TODO(erg): Make the inserted item here editable and edit it. If that's |
379 // impossible (it's probably possible), fall back on the folder editor. | 380 // impossible (it's probably possible), fall back on the folder editor. |
380 GtkTreeIter iter; | 381 GtkTreeIter iter; |
381 if (!gtk_tree_selection_get_selected(dialog->tree_selection_, | 382 if (!gtk_tree_selection_get_selected(dialog->tree_selection_, |
382 NULL, | 383 NULL, |
383 &iter)) { | 384 &iter)) { |
384 NOTREACHED() << "Something should always be selected"; | 385 NOTREACHED() << "Something should always be selected"; |
385 return; | 386 return; |
386 } | 387 } |
387 | 388 |
388 GtkTreeIter new_item_iter; | 389 GtkTreeIter new_item_iter; |
389 dialog->AddNewGroup(&iter, &new_item_iter); | 390 dialog->AddNewGroup(&iter, &new_item_iter); |
390 | 391 |
391 GtkTreePath* path = gtk_tree_model_get_path( | 392 GtkTreePath* path = gtk_tree_model_get_path( |
392 GTK_TREE_MODEL(dialog->tree_store_), &new_item_iter); | 393 GTK_TREE_MODEL(dialog->tree_store_), &new_item_iter); |
393 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dialog->tree_view_), path); | 394 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dialog->tree_view_), path); |
394 gtk_tree_selection_select_path(dialog->tree_selection_, path); | 395 gtk_tree_selection_select_path(dialog->tree_selection_, path); |
395 gtk_tree_path_free(path); | 396 gtk_tree_path_free(path); |
396 } | 397 } |
OLD | NEW |