Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(490)

Side by Side Diff: chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h"
6
7 #include <gtk/gtk.h>
8
9 #include <set>
10
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/bookmarks/bookmark_expanded_state_tracker.h"
17 #include "chrome/browser/bookmarks/bookmark_model.h"
18 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
19 #include "chrome/browser/bookmarks/bookmark_utils.h"
20 #include "chrome/browser/history/history_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
23 #include "chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.h"
24 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
25 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
26 #include "chrome/browser/ui/gtk/gtk_util.h"
27 #include "chrome/browser/ui/gtk/menu_gtk.h"
28 #include "chrome/common/net/url_fixer_upper.h"
29 #include "components/user_prefs/user_prefs.h"
30 #include "grit/chromium_strings.h"
31 #include "grit/generated_resources.h"
32 #include "grit/locale_settings.h"
33 #include "ui/base/gtk/gtk_hig_constants.h"
34 #include "ui/base/l10n/l10n_util.h"
35 #include "ui/base/models/simple_menu_model.h"
36 #include "ui/gfx/gtk_util.h"
37 #include "ui/gfx/image/image.h"
38 #include "ui/gfx/point.h"
39 #include "url/gurl.h"
40
41 namespace {
42
43 // Background color of text field when URL is invalid.
44 const GdkColor kErrorColor = GDK_COLOR_RGB(0xFF, 0xBC, 0xBC);
45
46 // Preferred initial dimensions, in pixels, of the folder tree.
47 const int kTreeWidth = 300;
48 const int kTreeHeight = 150;
49
50 typedef std::set<int64> ExpandedNodeIDs;
51
52 // Used by ExpandNodes.
53 struct ExpandNodesData {
54 const ExpandedNodeIDs* ids;
55 GtkWidget* tree_view;
56 };
57
58 // Expands all the nodes in |pointer_data| (which is a ExpandNodesData). This is
59 // intended for use by gtk_tree_model_foreach to expand a particular set of
60 // nodes.
61 gboolean ExpandNodes(GtkTreeModel* model,
62 GtkTreePath* path,
63 GtkTreeIter* iter,
64 gpointer pointer_data) {
65 ExpandNodesData* data = reinterpret_cast<ExpandNodesData*>(pointer_data);
66 int64 node_id = GetIdFromTreeIter(model, iter);
67 if (data->ids->find(node_id) != data->ids->end())
68 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(data->tree_view), path);
69 return FALSE; // Indicates we want to continue iterating.
70 }
71
72 // Used by SaveExpandedNodes.
73 struct SaveExpandedNodesData {
74 // Filled in by SaveExpandedNodes.
75 BookmarkExpandedStateTracker::Nodes nodes;
76 BookmarkModel* bookmark_model;
77 };
78
79 // Adds the node at |path| to |pointer_data| (which is a SaveExpandedNodesData).
80 // This is intended for use with gtk_tree_view_map_expanded_rows to save all
81 // the expanded paths.
82 void SaveExpandedNodes(GtkTreeView* tree_view,
83 GtkTreePath* path,
84 gpointer pointer_data) {
85 SaveExpandedNodesData* data =
86 reinterpret_cast<SaveExpandedNodesData*>(pointer_data);
87 GtkTreeIter iter;
88 gtk_tree_model_get_iter(gtk_tree_view_get_model(tree_view), &iter, path);
89 const BookmarkNode* node = data->bookmark_model->GetNodeByID(
90 GetIdFromTreeIter(gtk_tree_view_get_model(tree_view), &iter));
91 if (node)
92 data->nodes.insert(node);
93 }
94
95 } // namespace
96
97 class BookmarkEditorGtk::ContextMenuController
98 : public ui::SimpleMenuModel::Delegate {
99 public:
100 explicit ContextMenuController(BookmarkEditorGtk* editor)
101 : editor_(editor),
102 running_menu_for_root_(false) {
103 menu_model_.reset(new ui::SimpleMenuModel(this));
104 menu_model_->AddItemWithStringId(COMMAND_EDIT, IDS_EDIT);
105 menu_model_->AddItemWithStringId(COMMAND_DELETE, IDS_DELETE);
106 menu_model_->AddItemWithStringId(
107 COMMAND_NEW_FOLDER,
108 IDS_BOOKMARK_EDITOR_NEW_FOLDER_MENU_ITEM);
109 menu_.reset(new MenuGtk(NULL, menu_model_.get()));
110 }
111 virtual ~ContextMenuController() {}
112
113 void RunMenu(const gfx::Point& point, guint32 event_time) {
114 const BookmarkNode* selected_node = GetSelectedNode();
115 if (selected_node)
116 running_menu_for_root_ = selected_node->parent()->is_root();
117 menu_->PopupAsContext(point, event_time);
118 }
119
120 void Cancel() {
121 editor_ = NULL;
122 menu_->Cancel();
123 }
124
125 private:
126 enum ContextMenuCommand {
127 COMMAND_DELETE,
128 COMMAND_EDIT,
129 COMMAND_NEW_FOLDER
130 };
131
132 // Overridden from ui::SimpleMenuModel::Delegate:
133 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
134 if (editor_ == NULL)
135 return false;
136
137 switch (command_id) {
138 case COMMAND_DELETE:
139 case COMMAND_EDIT:
140 return !running_menu_for_root_;
141 case COMMAND_NEW_FOLDER:
142 return true;
143 }
144 return false;
145 }
146
147 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
148 return false;
149 }
150
151 virtual bool GetAcceleratorForCommandId(
152 int command_id,
153 ui::Accelerator* accelerator) OVERRIDE {
154 return false;
155 }
156
157 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
158 if (!editor_)
159 return;
160
161 switch (command_id) {
162 case COMMAND_DELETE: {
163 GtkTreeIter iter;
164 GtkTreeModel* model = NULL;
165 if (!gtk_tree_selection_get_selected(editor_->tree_selection_,
166 &model,
167 &iter)) {
168 break;
169 }
170 const BookmarkNode* selected_node = GetNodeAt(model, &iter);
171 if (selected_node) {
172 DCHECK(selected_node->is_folder());
173 // Deleting an existing bookmark folder. Confirm if it has other
174 // bookmarks.
175 if (!selected_node->empty()) {
176 if (!chrome::ConfirmDeleteBookmarkNode(selected_node,
177 GTK_WINDOW(editor_->dialog_)))
178 break;
179 }
180 editor_->deletes_.push_back(selected_node->id());
181 }
182 gtk_tree_store_remove(editor_->tree_store_, &iter);
183 break;
184 }
185 case COMMAND_EDIT: {
186 GtkTreeIter iter;
187 if (!gtk_tree_selection_get_selected(editor_->tree_selection_,
188 NULL,
189 &iter)) {
190 return;
191 }
192
193 GtkTreePath* path = gtk_tree_model_get_path(
194 GTK_TREE_MODEL(editor_->tree_store_), &iter);
195 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(editor_->tree_view_), path);
196
197 // Make the folder name editable.
198 gtk_tree_view_set_cursor(GTK_TREE_VIEW(editor_->tree_view_), path,
199 gtk_tree_view_get_column(GTK_TREE_VIEW(editor_->tree_view_), 0),
200 TRUE);
201
202 gtk_tree_path_free(path);
203 break;
204 }
205 case COMMAND_NEW_FOLDER:
206 editor_->NewFolder();
207 break;
208 default:
209 NOTREACHED();
210 break;
211 }
212 }
213
214 const BookmarkNode* GetNodeAt(GtkTreeModel* model, GtkTreeIter* iter) const {
215 int64 id = GetIdFromTreeIter(model, iter);
216 return (id > 0) ? editor_->bb_model_->GetNodeByID(id) : NULL;
217 }
218
219 const BookmarkNode* GetSelectedNode() const {
220 GtkTreeModel* model;
221 GtkTreeIter iter;
222 if (!gtk_tree_selection_get_selected(editor_->tree_selection_,
223 &model,
224 &iter)) {
225 return NULL;
226 }
227
228 return GetNodeAt(model, &iter);
229 }
230
231 // The model and view for the right click context menu.
232 scoped_ptr<ui::SimpleMenuModel> menu_model_;
233 scoped_ptr<MenuGtk> menu_;
234
235 // The context menu was brought up for. Set to NULL when the menu is canceled.
236 BookmarkEditorGtk* editor_;
237
238 // If true, we're running the menu for the bookmark bar or other bookmarks
239 // nodes.
240 bool running_menu_for_root_;
241
242 DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
243 };
244
245 // static
246 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd,
247 Profile* profile,
248 const EditDetails& details,
249 Configuration configuration) {
250 DCHECK(profile);
251 BookmarkEditorGtk* editor =
252 new BookmarkEditorGtk(parent_hwnd,
253 profile,
254 details.parent_node,
255 details,
256 configuration);
257 editor->Show();
258 }
259
260 BookmarkEditorGtk::BookmarkEditorGtk(
261 GtkWindow* window,
262 Profile* profile,
263 const BookmarkNode* parent,
264 const EditDetails& details,
265 BookmarkEditor::Configuration configuration)
266 : profile_(profile),
267 dialog_(NULL),
268 parent_(parent),
269 details_(details),
270 running_menu_for_root_(false),
271 show_tree_(configuration == SHOW_TREE) {
272 DCHECK(profile);
273 Init(window);
274 }
275
276 BookmarkEditorGtk::~BookmarkEditorGtk() {
277 // The tree model is deleted before the view. Reset the model otherwise the
278 // tree will reference a deleted model.
279
280 bb_model_->RemoveObserver(this);
281 }
282
283 void BookmarkEditorGtk::Init(GtkWindow* parent_window) {
284 bb_model_ = BookmarkModelFactory::GetForProfile(profile_);
285 DCHECK(bb_model_);
286 bb_model_->AddObserver(this);
287
288 dialog_ = gtk_dialog_new_with_buttons(
289 l10n_util::GetStringUTF8(details_.GetWindowTitleId()).c_str(),
290 parent_window,
291 GTK_DIALOG_MODAL,
292 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
293 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
294 NULL);
295 #if !GTK_CHECK_VERSION(2, 22, 0)
296 gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE);
297 #endif
298
299 if (show_tree_) {
300 GtkWidget* action_area = gtk_dialog_get_action_area(GTK_DIALOG(dialog_));
301 new_folder_button_ = gtk_button_new_with_label(
302 l10n_util::GetStringUTF8(
303 IDS_BOOKMARK_EDITOR_NEW_FOLDER_BUTTON).c_str());
304 g_signal_connect(new_folder_button_, "clicked",
305 G_CALLBACK(OnNewFolderClickedThunk), this);
306 gtk_container_add(GTK_CONTAINER(action_area), new_folder_button_);
307 gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(action_area),
308 new_folder_button_, TRUE);
309 }
310
311 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
312
313 // The GTK dialog content area layout (overview)
314 //
315 // +- GtkVBox |vbox| ----------------------------------------------+
316 // |+- GtkTable |table| ------------------------------------------+|
317 // ||+- GtkLabel ------+ +- GtkEntry |name_entry_| --------------+||
318 // ||| | | |||
319 // ||+-----------------+ +---------------------------------------+||
320 // ||+- GtkLabel ------+ +- GtkEntry |url_entry_| ---------------+|| *
321 // ||| | | |||
322 // ||+-----------------+ +---------------------------------------+||
323 // |+-------------------------------------------------------------+|
324 // |+- GtkScrollWindow |scroll_window| ---------------------------+|
325 // ||+- GtkTreeView |tree_view_| --------------------------------+||
326 // |||+- GtkTreeViewColumn |name_column| -----------------------+|||
327 // |||| ||||
328 // |||| ||||
329 // |||| ||||
330 // |||| ||||
331 // |||+---------------------------------------------------------+|||
332 // ||+-----------------------------------------------------------+||
333 // |+-------------------------------------------------------------+|
334 // +---------------------------------------------------------------+
335 //
336 // * The url and corresponding label are not shown if creating a new folder.
337 GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_));
338 gtk_box_set_spacing(GTK_BOX(content_area), ui::kContentAreaSpacing);
339
340 GtkWidget* vbox = gtk_vbox_new(FALSE, 12);
341
342 name_entry_ = gtk_entry_new();
343 std::string title;
344 GURL url;
345 if (details_.type == EditDetails::EXISTING_NODE) {
346 title = base::UTF16ToUTF8(details_.existing_node->GetTitle());
347 url = details_.existing_node->url();
348 } else if (details_.type == EditDetails::NEW_FOLDER) {
349 title = l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME);
350 } else if (details_.type == EditDetails::NEW_URL) {
351 url = details_.url;
352 title = base::UTF16ToUTF8(details_.title);
353 }
354 gtk_entry_set_text(GTK_ENTRY(name_entry_), title.c_str());
355 g_signal_connect(name_entry_, "changed",
356 G_CALLBACK(OnEntryChangedThunk), this);
357 gtk_entry_set_activates_default(GTK_ENTRY(name_entry_), TRUE);
358
359 GtkWidget* table;
360 if (details_.GetNodeType() != BookmarkNode::FOLDER) {
361 url_entry_ = gtk_entry_new();
362 PrefService* prefs =
363 profile_ ? user_prefs::UserPrefs::Get(profile_) : NULL;
364 gtk_entry_set_text(
365 GTK_ENTRY(url_entry_),
366 base::UTF16ToUTF8(
367 chrome::FormatBookmarkURLForDisplay(url, prefs)).c_str());
368 g_signal_connect(url_entry_, "changed",
369 G_CALLBACK(OnEntryChangedThunk), this);
370 gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE);
371 table = gtk_util::CreateLabeledControlsGroup(NULL,
372 l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_NAME_LABEL).c_str(),
373 name_entry_,
374 l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_URL_LABEL).c_str(),
375 url_entry_,
376 NULL);
377
378 } else {
379 url_entry_ = NULL;
380 table = gtk_util::CreateLabeledControlsGroup(NULL,
381 l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_NAME_LABEL).c_str(),
382 name_entry_,
383 NULL);
384 }
385
386 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
387
388 if (show_tree_) {
389 GtkTreeIter selected_iter;
390 int64 selected_id = 0;
391 if (details_.type == EditDetails::EXISTING_NODE)
392 selected_id = details_.existing_node->parent()->id();
393 else if (parent_)
394 selected_id = parent_->id();
395 tree_store_ = MakeFolderTreeStore();
396 AddToTreeStore(bb_model_, selected_id, tree_store_, &selected_iter);
397 tree_view_ = MakeTreeViewForStore(tree_store_);
398 gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight);
399 tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_));
400 g_signal_connect(tree_view_, "button-press-event",
401 G_CALLBACK(OnTreeViewButtonPressEventThunk), this);
402
403 BookmarkExpandedStateTracker::Nodes expanded_nodes =
404 bb_model_->expanded_state_tracker()->GetExpandedNodes();
405 if (!expanded_nodes.empty()) {
406 ExpandedNodeIDs ids;
407 for (BookmarkExpandedStateTracker::Nodes::iterator i =
408 expanded_nodes.begin(); i != expanded_nodes.end(); ++i) {
409 ids.insert((*i)->id());
410 }
411 ExpandNodesData data = { &ids, tree_view_ };
412 gtk_tree_model_foreach(GTK_TREE_MODEL(tree_store_), &ExpandNodes,
413 reinterpret_cast<gpointer>(&data));
414 }
415
416 GtkTreePath* path = NULL;
417 if (selected_id) {
418 path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store_),
419 &selected_iter);
420 } else {
421 // We don't have a selected parent (Probably because we're making a new
422 // bookmark). Select the first item in the list.
423 path = gtk_tree_path_new_from_string("0");
424 }
425
426 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path);
427 gtk_tree_selection_select_path(tree_selection_, path);
428 gtk_tree_path_free(path);
429
430 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL);
431 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window),
432 GTK_POLICY_NEVER,
433 GTK_POLICY_AUTOMATIC);
434 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window),
435 GTK_SHADOW_ETCHED_IN);
436 gtk_container_add(GTK_CONTAINER(scroll_window), tree_view_);
437
438 gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
439
440 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_)),
441 "changed", G_CALLBACK(OnSelectionChangedThunk), this);
442 }
443
444 gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0);
445
446 g_signal_connect(dialog_, "response",
447 G_CALLBACK(OnResponseThunk), this);
448 g_signal_connect(dialog_, "delete-event",
449 G_CALLBACK(OnWindowDeleteEventThunk), this);
450 g_signal_connect(dialog_, "destroy",
451 G_CALLBACK(OnWindowDestroyThunk), this);
452 }
453
454 void BookmarkEditorGtk::Show() {
455 // Manually call our OnEntryChanged handler to set the initial state.
456 OnEntryChanged(NULL);
457
458 gtk_util::ShowDialog(dialog_);
459 }
460
461 void BookmarkEditorGtk::Close() {
462 // Under the model that we've inherited from Windows, dialogs can receive
463 // more than one Close() call inside the current message loop event.
464 if (dialog_) {
465 gtk_widget_destroy(dialog_);
466 dialog_ = NULL;
467 }
468 }
469
470 void BookmarkEditorGtk::BookmarkNodeMoved(BookmarkModel* model,
471 const BookmarkNode* old_parent,
472 int old_index,
473 const BookmarkNode* new_parent,
474 int new_index) {
475 Reset();
476 }
477
478 void BookmarkEditorGtk::BookmarkNodeAdded(BookmarkModel* model,
479 const BookmarkNode* parent,
480 int index) {
481 Reset();
482 }
483
484 void BookmarkEditorGtk::BookmarkNodeRemoved(BookmarkModel* model,
485 const BookmarkNode* parent,
486 int index,
487 const BookmarkNode* node) {
488 if ((details_.type == EditDetails::EXISTING_NODE &&
489 details_.existing_node->HasAncestor(node)) ||
490 (parent_ && parent_->HasAncestor(node))) {
491 // The node, or its parent was removed. Close the dialog.
492 Close();
493 } else {
494 Reset();
495 }
496 }
497
498 void BookmarkEditorGtk::BookmarkAllNodesRemoved(BookmarkModel* model) {
499 Reset();
500 }
501
502 void BookmarkEditorGtk::BookmarkNodeChildrenReordered(
503 BookmarkModel* model, const BookmarkNode* node) {
504 Reset();
505 }
506
507 void BookmarkEditorGtk::Reset() {
508 // TODO(erg): The windows implementation tries to be smart. For now, just
509 // close the window.
510 Close();
511 }
512
513 GURL BookmarkEditorGtk::GetInputURL() const {
514 if (!url_entry_)
515 return GURL(); // Happens when we're editing a folder.
516 return URLFixerUpper::FixupURL(gtk_entry_get_text(GTK_ENTRY(url_entry_)),
517 std::string());
518 }
519
520 base::string16 BookmarkEditorGtk::GetInputTitle() const {
521 return base::UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(name_entry_)));
522 }
523
524 void BookmarkEditorGtk::ApplyEdits() {
525 DCHECK(bb_model_->loaded());
526
527 GtkTreeIter currently_selected_iter;
528 if (show_tree_) {
529 if (!gtk_tree_selection_get_selected(tree_selection_, NULL,
530 &currently_selected_iter)) {
531 ApplyEdits(NULL);
532 return;
533 }
534 }
535
536 ApplyEdits(&currently_selected_iter);
537 }
538
539 void BookmarkEditorGtk::ApplyEdits(GtkTreeIter* selected_parent) {
540 // We're going to apply edits to the bookmark bar model, which will call us
541 // back. Normally when a structural edit occurs we reset the tree model.
542 // We don't want to do that here, so we remove ourselves as an observer.
543 bb_model_->RemoveObserver(this);
544
545 GURL new_url(GetInputURL());
546 base::string16 new_title(GetInputTitle());
547
548 if (!show_tree_ || !selected_parent) {
549 // TODO: this is wrong. Just because there is no selection doesn't mean new
550 // folders weren't added.
551 BookmarkEditor::ApplyEditsWithNoFolderChange(
552 bb_model_, parent_, details_, new_title, new_url);
553 return;
554 }
555
556 // Create the new folders and update the titles.
557 const BookmarkNode* new_parent = CommitTreeStoreDifferencesBetween(
558 bb_model_, tree_store_, selected_parent);
559
560 SaveExpandedNodesData data;
561 data.bookmark_model = bb_model_;
562 gtk_tree_view_map_expanded_rows(GTK_TREE_VIEW(tree_view_),
563 &SaveExpandedNodes,
564 reinterpret_cast<gpointer>(&data));
565 bb_model_->expanded_state_tracker()->SetExpandedNodes(data.nodes);
566
567 if (!new_parent) {
568 // Bookmarks must be parented.
569 NOTREACHED();
570 return;
571 }
572
573 BookmarkEditor::ApplyEditsWithPossibleFolderChange(
574 bb_model_, new_parent, details_, new_title, new_url);
575
576 // Remove the folders that were removed. This has to be done after all the
577 // other changes have been committed.
578 bookmark_utils::DeleteBookmarkFolders(bb_model_, deletes_);
579 }
580
581 void BookmarkEditorGtk::AddNewFolder(GtkTreeIter* parent, GtkTreeIter* child) {
582 gtk_tree_store_append(tree_store_, child, parent);
583 gtk_tree_store_set(
584 tree_store_,
585 child,
586 FOLDER_ICON, GtkThemeService::GetFolderIcon(true).ToGdkPixbuf(),
587 FOLDER_NAME,
588 l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME).c_str(),
589 ITEM_ID, static_cast<int64>(0),
590 IS_EDITABLE, TRUE,
591 -1);
592 }
593
594 void BookmarkEditorGtk::OnSelectionChanged(GtkWidget* selection) {
595 if (!gtk_tree_selection_get_selected(tree_selection_, NULL, NULL))
596 gtk_widget_set_sensitive(new_folder_button_, FALSE);
597 else
598 gtk_widget_set_sensitive(new_folder_button_, TRUE);
599 }
600
601 void BookmarkEditorGtk::OnResponse(GtkWidget* dialog, int response_id) {
602 if (response_id == GTK_RESPONSE_ACCEPT)
603 ApplyEdits();
604
605 Close();
606 }
607
608 gboolean BookmarkEditorGtk::OnWindowDeleteEvent(GtkWidget* widget,
609 GdkEvent* event) {
610 Close();
611
612 // Return true to prevent the gtk dialog from being destroyed. Close will
613 // destroy it for us and the default gtk_dialog_delete_event_handler() will
614 // force the destruction without us being able to stop it.
615 return TRUE;
616 }
617
618 void BookmarkEditorGtk::OnWindowDestroy(GtkWidget* widget) {
619 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
620 }
621
622 void BookmarkEditorGtk::OnEntryChanged(GtkWidget* entry) {
623 gboolean can_close = TRUE;
624 if (details_.GetNodeType() != BookmarkNode::FOLDER) {
625 if (GetInputURL().is_valid()) {
626 gtk_widget_modify_base(url_entry_, GTK_STATE_NORMAL, NULL);
627 } else {
628 gtk_widget_modify_base(url_entry_, GTK_STATE_NORMAL, &kErrorColor);
629 can_close = FALSE;
630 }
631 }
632 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT,
633 can_close);
634 }
635
636 void BookmarkEditorGtk::OnNewFolderClicked(GtkWidget* button) {
637 NewFolder();
638 }
639
640 gboolean BookmarkEditorGtk::OnTreeViewButtonPressEvent(GtkWidget* widget,
641 GdkEventButton* event) {
642 if (event->button == 3) {
643 if (!menu_controller_.get())
644 menu_controller_.reset(new ContextMenuController(this));
645 menu_controller_->RunMenu(gfx::Point(event->x_root, event->y_root),
646 event->time);
647 }
648
649 return FALSE;
650 }
651
652 void BookmarkEditorGtk::NewFolder() {
653 GtkTreeIter iter;
654 if (!gtk_tree_selection_get_selected(tree_selection_,
655 NULL,
656 &iter)) {
657 NOTREACHED() << "Something should always be selected if New Folder " <<
658 "is clicked";
659 return;
660 }
661
662 GtkTreeIter new_item_iter;
663 AddNewFolder(&iter, &new_item_iter);
664
665 GtkTreePath* path = gtk_tree_model_get_path(
666 GTK_TREE_MODEL(tree_store_), &new_item_iter);
667 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path);
668
669 // Make the folder name editable.
670 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree_view_), path,
671 gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view_), 0),
672 TRUE);
673
674 gtk_tree_path_free(path);
675 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698