2008-03-29 Cosimo Cecchi <cosimoc@gnome.org>
[nautilus.git] / src / nautilus-bookmarks-window.c
blob6997910977b27f61c9ed6542de7250c08d336d37
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /*
4 * Nautilus
6 * Copyright (C) 1999, 2000 Eazel, Inc.
8 * Nautilus is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * Nautilus is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Authors: John Sullivan <sullivan@eazel.com>
25 /* nautilus-bookmarks-window.c - implementation of bookmark-editing window.
28 #include <config.h>
29 #include "nautilus-bookmarks-window.h"
30 #include "nautilus-window.h"
31 #include "nautilus-navigation-window.h"
32 #include "nautilus-spatial-window.h"
33 #include <libnautilus-private/nautilus-undo.h>
34 #include <libnautilus-private/nautilus-global-preferences.h>
35 #include <eel/eel-gtk-extensions.h>
36 #include <eel/eel-gnome-extensions.h>
37 #include <libnautilus-private/nautilus-undo-signal-handlers.h>
38 #include <gtk/gtkenums.h>
39 #include <gtk/gtkhbbox.h>
40 #include <gnome.h>
41 #include <libgnomeui/gnome-help.h>
42 #include <glade/glade.h>
44 /* Static variables to keep track of window state. If there were
45 * more than one bookmark-editing window, these would be struct or
46 * class fields.
48 static int bookmark_list_changed_signal_id;
49 static NautilusBookmarkList *bookmarks = NULL;
50 static GtkTreeView *bookmark_list_widget = NULL; /* awkward name to distinguish from NautilusBookmarkList */
51 static GtkListStore *bookmark_list_store = NULL;
52 static GtkListStore *bookmark_empty_list_store = NULL;
53 static GtkTreeSelection *bookmark_selection = NULL;
54 static int selection_changed_id = 0;
55 static GtkWidget *name_field = NULL;
56 static int name_field_changed_signal_id;
57 static GtkWidget *remove_button = NULL;
58 static GtkWidget *jump_button = NULL;
59 static gboolean text_changed = FALSE;
60 static gboolean name_text_changed = FALSE;
61 static GtkWidget *uri_field = NULL;
62 static int uri_field_changed_signal_id;
63 static int row_changed_signal_id;
64 static int row_deleted_signal_id;
65 static int row_activated_signal_id;
66 static int button_pressed_signal_id;
67 static int key_pressed_signal_id;
68 static int jump_button_signal_id;
69 static NautilusApplication *application;
70 static gboolean parent_is_browser_window;
72 /* forward declarations */
73 static guint get_selected_row (void);
74 static gboolean get_selection_exists (void);
75 static void name_or_uri_field_activate (NautilusEntry *entry);
76 static void nautilus_bookmarks_window_restore_geometry (GtkWidget *window);
77 static void on_bookmark_list_changed (NautilusBookmarkList *list,
78 gpointer user_data);
79 static void on_name_field_changed (GtkEditable *editable,
80 gpointer user_data);
81 static void on_remove_button_clicked (GtkButton *button,
82 gpointer user_data);
83 static void on_jump_button_clicked (GtkButton *button,
84 gpointer user_data);
85 static void on_row_changed (GtkListStore *store,
86 GtkTreePath *path,
87 GtkTreeIter *iter,
88 gpointer user_data);
89 static void on_row_deleted (GtkListStore *store,
90 GtkTreePath *path,
91 gpointer user_data);
92 static void on_row_activated (GtkTreeView *view,
93 GtkTreePath *path,
94 GtkTreeViewColumn *column,
95 gpointer user_data);
96 static gboolean on_button_pressed (GtkTreeView *view,
97 GdkEventButton *event,
98 gpointer user_data);
99 static gboolean on_key_pressed (GtkTreeView *view,
100 GdkEventKey *event,
101 gpointer user_data);
102 static void on_selection_changed (GtkTreeSelection *treeselection,
103 gpointer user_data);
105 static gboolean on_text_field_focus_out_event (GtkWidget *widget,
106 GdkEventFocus *event,
107 gpointer user_data);
108 static void on_uri_field_changed (GtkEditable *editable,
109 gpointer user_data);
110 static gboolean on_window_delete_event (GtkWidget *widget,
111 GdkEvent *event,
112 gpointer user_data);
113 static void on_window_hide_event (GtkWidget *widget,
114 gpointer user_data);
115 static void on_window_destroy_event (GtkWidget *widget,
116 gpointer user_data);
117 static void repopulate (void);
118 static void set_up_close_accelerator (GtkWidget *window);
119 static void open_selected_bookmark (gpointer user_data, GdkScreen *screen);
120 static void update_bookmark_from_text (void);
122 /* We store a pointer to the bookmark in a column so when an item is moved
123 with DnD we know which item it is. However we have to be careful to keep
124 this in sync with the actual bookmark. Note that
125 nautilus_bookmark_list_insert_item() makes a copy of the bookmark, so we
126 have to fetch the new copy and update our pointer. */
127 #define BOOKMARK_LIST_COLUMN_ICON 0
128 #define BOOKMARK_LIST_COLUMN_NAME 1
129 #define BOOKMARK_LIST_COLUMN_BOOKMARK 2
130 #define BOOKMARK_LIST_COLUMN_STYLE 3
131 #define BOOKMARK_LIST_COLUMN_COUNT 4
133 /* layout constants */
135 /* Keep window from shrinking down ridiculously small; numbers are somewhat arbitrary */
136 #define BOOKMARKS_WINDOW_MIN_WIDTH 300
137 #define BOOKMARKS_WINDOW_MIN_HEIGHT 100
139 /* Larger size initially; user can stretch or shrink (but not shrink below min) */
140 #define BOOKMARKS_WINDOW_INITIAL_WIDTH 500
141 #define BOOKMARKS_WINDOW_INITIAL_HEIGHT 200
143 static void
144 nautilus_bookmarks_window_response_callback (GtkDialog *dialog,
145 int response_id,
146 gpointer callback_data)
148 if (response_id == GTK_RESPONSE_HELP) {
149 GError *error = NULL;
151 gnome_help_display_desktop_on_screen (
152 NULL, "user-guide", "user-guide.xml", "gosnautilus-36",
153 gtk_window_get_screen (GTK_WINDOW (dialog)), &error);
155 if (error) {
156 GtkWidget *err_dialog;
157 err_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
158 GTK_DIALOG_DESTROY_WITH_PARENT,
159 GTK_MESSAGE_ERROR,
160 GTK_BUTTONS_OK,
161 _("There was an error displaying help: \n%s"),
162 error->message);
164 g_signal_connect (G_OBJECT (err_dialog),
165 "response", G_CALLBACK (gtk_widget_destroy),
166 NULL);
167 gtk_window_set_resizable (GTK_WINDOW (err_dialog), FALSE);
168 gtk_widget_show (err_dialog);
169 g_error_free (error);
171 } else if (response_id == GTK_RESPONSE_CLOSE) {
172 gtk_widget_hide (GTK_WIDGET (dialog));
176 static GtkListStore *
177 create_bookmark_store (void)
179 return gtk_list_store_new (BOOKMARK_LIST_COLUMN_COUNT,
180 GDK_TYPE_PIXBUF,
181 G_TYPE_STRING,
182 G_TYPE_OBJECT,
183 PANGO_TYPE_STYLE);
186 static void
187 setup_empty_list (void)
189 GtkTreeIter iter;
191 bookmark_empty_list_store = create_bookmark_store ();
192 gtk_list_store_append (bookmark_empty_list_store, &iter);
194 gtk_list_store_set (bookmark_empty_list_store, &iter,
195 BOOKMARK_LIST_COLUMN_NAME, _("No bookmarks defined"),
196 BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_ITALIC,
197 -1);
200 static void
201 bookmarks_set_empty (gboolean empty)
203 GtkTreeIter iter;
205 if (empty) {
206 gtk_tree_view_set_model (bookmark_list_widget,
207 GTK_TREE_MODEL (bookmark_empty_list_store));
208 gtk_widget_set_sensitive (GTK_WIDGET (bookmark_list_widget), FALSE);
209 } else {
210 gtk_tree_view_set_model (bookmark_list_widget,
211 GTK_TREE_MODEL (bookmark_list_store));
212 gtk_widget_set_sensitive (GTK_WIDGET (bookmark_list_widget), TRUE);
214 if (nautilus_bookmark_list_length (bookmarks) > 0 &&
215 !get_selection_exists ()) {
216 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (bookmark_list_store),
217 &iter, NULL, 0);
218 gtk_tree_selection_select_iter (bookmark_selection, &iter);
222 on_selection_changed (bookmark_selection, NULL);
225 static void
226 edit_bookmarks_dialog_reset_signals (gpointer data,
227 GObject *obj)
229 g_signal_handler_disconnect (GTK_OBJECT (jump_button),
230 jump_button_signal_id);
231 g_signal_handler_disconnect (GTK_OBJECT (bookmark_list_widget),
232 row_activated_signal_id);
233 jump_button_signal_id =
234 g_signal_connect (jump_button, "clicked",
235 G_CALLBACK (on_jump_button_clicked), NULL);
236 row_activated_signal_id =
237 g_signal_connect (bookmark_list_widget, "row_activated",
238 G_CALLBACK (on_row_activated), NULL);
242 * create_bookmarks_window:
244 * Create a new bookmark-editing window.
245 * @list: The NautilusBookmarkList that this window will edit.
247 * Return value: A pointer to the new window.
249 GtkWindow *
250 create_bookmarks_window (NautilusBookmarkList *list, GObject *undo_manager_source)
252 GtkWidget *window;
253 GtkTreeViewColumn *col;
254 GtkCellRenderer *rend;
255 GladeXML *gui;
257 bookmarks = list;
259 gui = eel_glade_get_file (GLADEDIR "/nautilus-bookmarks-window.glade",
260 NULL, NULL,
261 "bookmarks_dialog", &window,
262 "bookmark_tree_view", &bookmark_list_widget,
263 "bookmark_delete_button", &remove_button,
264 "bookmark_jump_button", &jump_button,
265 NULL);
266 if (!gui) {
267 return NULL;
270 application = NAUTILUS_WINDOW (undo_manager_source)->application;
272 if (NAUTILUS_IS_NAVIGATION_WINDOW (undo_manager_source)) {
273 parent_is_browser_window = TRUE;
274 } else {
275 parent_is_browser_window = FALSE;
278 set_up_close_accelerator (window);
279 nautilus_undo_share_undo_manager (G_OBJECT (window), undo_manager_source);
281 gtk_window_set_wmclass (GTK_WINDOW (window), "bookmarks", "Nautilus");
282 nautilus_bookmarks_window_restore_geometry (window);
284 g_object_weak_ref (G_OBJECT (undo_manager_source), edit_bookmarks_dialog_reset_signals,
285 undo_manager_source);
287 bookmark_list_widget = GTK_TREE_VIEW (glade_xml_get_widget (gui, "bookmark_tree_view"));
289 rend = gtk_cell_renderer_pixbuf_new ();
290 col = gtk_tree_view_column_new_with_attributes ("Icon",
291 rend,
292 "pixbuf",
293 BOOKMARK_LIST_COLUMN_ICON,
294 NULL);
295 gtk_tree_view_append_column (bookmark_list_widget,
296 GTK_TREE_VIEW_COLUMN (col));
297 gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (col),
298 NAUTILUS_ICON_SIZE_SMALLER);
300 rend = gtk_cell_renderer_text_new ();
301 col = gtk_tree_view_column_new_with_attributes ("Icon",
302 rend,
303 "text",
304 BOOKMARK_LIST_COLUMN_NAME,
305 "style",
306 BOOKMARK_LIST_COLUMN_STYLE,
307 NULL);
308 gtk_tree_view_append_column (bookmark_list_widget,
309 GTK_TREE_VIEW_COLUMN (col));
311 bookmark_list_store = create_bookmark_store ();
312 setup_empty_list ();
313 gtk_tree_view_set_model (bookmark_list_widget,
314 GTK_TREE_MODEL (bookmark_empty_list_store));
316 bookmark_selection =
317 GTK_TREE_SELECTION (gtk_tree_view_get_selection (bookmark_list_widget));
319 name_field = nautilus_entry_new ();
321 gtk_widget_show (name_field);
322 gtk_box_pack_start (GTK_BOX (glade_xml_get_widget (gui, "bookmark_name_placeholder")),
323 name_field, TRUE, TRUE, 0);
324 nautilus_undo_editable_set_undo_key (GTK_EDITABLE (name_field), TRUE);
326 gtk_label_set_mnemonic_widget (
327 GTK_LABEL (glade_xml_get_widget (gui, "bookmark_name_label")),
328 name_field);
330 uri_field = nautilus_entry_new ();
331 gtk_widget_show (uri_field);
332 gtk_box_pack_start (GTK_BOX (glade_xml_get_widget (gui, "bookmark_location_placeholder")),
333 uri_field, TRUE, TRUE, 0);
334 nautilus_undo_editable_set_undo_key (GTK_EDITABLE (uri_field), TRUE);
336 gtk_label_set_mnemonic_widget (
337 GTK_LABEL (glade_xml_get_widget (gui, "bookmark_location_label")),
338 uri_field);
340 bookmark_list_changed_signal_id =
341 g_signal_connect (bookmarks, "contents_changed",
342 G_CALLBACK (on_bookmark_list_changed), NULL);
343 row_changed_signal_id =
344 g_signal_connect (bookmark_list_store, "row_changed",
345 G_CALLBACK (on_row_changed), NULL);
346 row_deleted_signal_id =
347 g_signal_connect (bookmark_list_store, "row_deleted",
348 G_CALLBACK (on_row_deleted), NULL);
349 row_activated_signal_id =
350 g_signal_connect (bookmark_list_widget, "row_activated",
351 G_CALLBACK (on_row_activated), undo_manager_source);
352 button_pressed_signal_id =
353 g_signal_connect (bookmark_list_widget, "button_press_event",
354 G_CALLBACK (on_button_pressed), NULL);
355 key_pressed_signal_id =
356 g_signal_connect (bookmark_list_widget, "key_press_event",
357 G_CALLBACK (on_key_pressed), NULL);
358 selection_changed_id =
359 g_signal_connect (bookmark_selection, "changed",
360 G_CALLBACK (on_selection_changed), NULL);
362 g_signal_connect (window, "delete_event",
363 G_CALLBACK (on_window_delete_event), NULL);
364 g_signal_connect (window, "hide",
365 G_CALLBACK (on_window_hide_event), NULL);
366 g_signal_connect (window, "destroy",
367 G_CALLBACK (on_window_destroy_event), NULL);
368 g_signal_connect (window, "response",
369 G_CALLBACK (nautilus_bookmarks_window_response_callback), NULL);
371 name_field_changed_signal_id =
372 g_signal_connect (name_field, "changed",
373 G_CALLBACK (on_name_field_changed), NULL);
375 g_signal_connect (name_field, "focus_out_event",
376 G_CALLBACK (on_text_field_focus_out_event), NULL);
377 g_signal_connect (name_field, "activate",
378 G_CALLBACK (name_or_uri_field_activate), NULL);
380 uri_field_changed_signal_id =
381 g_signal_connect (uri_field, "changed",
382 G_CALLBACK (on_uri_field_changed), NULL);
384 g_signal_connect (uri_field, "focus_out_event",
385 G_CALLBACK (on_text_field_focus_out_event), NULL);
386 g_signal_connect (uri_field, "activate",
387 G_CALLBACK (name_or_uri_field_activate), NULL);
388 g_signal_connect (remove_button, "clicked",
389 G_CALLBACK (on_remove_button_clicked), NULL);
390 jump_button_signal_id =
391 g_signal_connect (jump_button, "clicked",
392 G_CALLBACK (on_jump_button_clicked), undo_manager_source);
394 gtk_tree_selection_set_mode (bookmark_selection, GTK_SELECTION_BROWSE);
396 /* Fill in list widget with bookmarks, must be after signals are wired up. */
397 repopulate();
399 g_object_unref (G_OBJECT (gui));
401 return GTK_WINDOW (window);
404 void
405 edit_bookmarks_dialog_set_signals (GObject *undo_manager_source)
408 g_signal_handler_disconnect (GTK_OBJECT (jump_button),
409 jump_button_signal_id);
410 g_signal_handler_disconnect (GTK_OBJECT (bookmark_list_widget),
411 row_activated_signal_id);
413 jump_button_signal_id =
414 g_signal_connect (jump_button, "clicked",
415 G_CALLBACK (on_jump_button_clicked), undo_manager_source);
416 row_activated_signal_id =
417 g_signal_connect (bookmark_list_widget, "row_activated",
418 G_CALLBACK (on_row_activated), undo_manager_source);
420 g_object_weak_ref (G_OBJECT (undo_manager_source), edit_bookmarks_dialog_reset_signals,
421 undo_manager_source);
424 static NautilusBookmark *
425 get_selected_bookmark (void)
427 g_return_val_if_fail(NAUTILUS_IS_BOOKMARK_LIST(bookmarks), NULL);
429 if (!get_selection_exists())
430 return NULL;
432 if (nautilus_bookmark_list_length (bookmarks) < 1)
433 return NULL;
435 return nautilus_bookmark_list_item_at(bookmarks, get_selected_row ());
438 static guint
439 get_selected_row (void)
441 GtkTreeIter iter;
442 GtkTreePath *path;
443 GtkTreeModel *model;
444 gint *indices, row;
446 g_assert (get_selection_exists());
448 model = GTK_TREE_MODEL (bookmark_list_store);
449 gtk_tree_selection_get_selected (bookmark_selection,
450 &model,
451 &iter);
453 path = gtk_tree_model_get_path (model, &iter);
454 indices = gtk_tree_path_get_indices (path);
455 row = indices[0];
456 gtk_tree_path_free (path);
457 return row;
460 static gboolean
461 get_selection_exists (void)
463 return gtk_tree_selection_get_selected (bookmark_selection, NULL, NULL);
466 static void
467 nautilus_bookmarks_window_restore_geometry (GtkWidget *window)
469 const char *window_geometry;
471 g_return_if_fail (GTK_IS_WINDOW (window));
472 g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
474 window_geometry = nautilus_bookmark_list_get_window_geometry (bookmarks);
476 if (window_geometry != NULL) {
477 eel_gtk_window_set_initial_geometry_from_string
478 (GTK_WINDOW (window), window_geometry,
479 BOOKMARKS_WINDOW_MIN_WIDTH, BOOKMARKS_WINDOW_MIN_HEIGHT, FALSE);
481 } else {
482 /* use default since there was no stored geometry */
483 gtk_window_set_default_size (GTK_WINDOW (window),
484 BOOKMARKS_WINDOW_INITIAL_WIDTH,
485 BOOKMARKS_WINDOW_INITIAL_HEIGHT);
487 /* Let window manager handle default position if no position stored */
492 * nautilus_bookmarks_window_save_geometry:
494 * Save window size & position to disk.
495 * @window: The bookmarks window whose geometry should be saved.
497 void
498 nautilus_bookmarks_window_save_geometry (GtkWindow *window)
500 g_return_if_fail (GTK_IS_WINDOW (window));
501 g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
503 /* Don't bother if window is already closed */
504 if (GTK_WIDGET_VISIBLE (window)) {
505 char *geometry_string;
507 geometry_string = eel_gtk_window_get_geometry_string (window);
509 nautilus_bookmark_list_set_window_geometry (bookmarks, geometry_string);
510 g_free (geometry_string);
514 static void
515 on_bookmark_list_changed (NautilusBookmarkList *bookmarks, gpointer data)
517 g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
519 /* maybe add logic here or in repopulate to save/restore selection */
520 repopulate ();
523 static void
524 on_name_field_changed (GtkEditable *editable,
525 gpointer user_data)
527 GtkTreeIter iter;
528 g_return_if_fail(GTK_IS_TREE_VIEW(bookmark_list_widget));
529 g_return_if_fail(GTK_IS_ENTRY(name_field));
531 if (!get_selection_exists())
532 return;
534 /* Update text displayed in list instantly. Also remember that
535 * user has changed text so we update real bookmark later.
537 gtk_tree_selection_get_selected (bookmark_selection,
538 NULL,
539 &iter);
541 gtk_list_store_set (bookmark_list_store,
542 &iter, BOOKMARK_LIST_COLUMN_NAME,
543 gtk_entry_get_text (GTK_ENTRY (name_field)),
544 -1);
545 text_changed = TRUE;
546 name_text_changed = TRUE;
549 static void
550 open_selected_bookmark (gpointer user_data, GdkScreen *screen)
552 NautilusBookmark *selected;
553 NautilusWindow *window;
554 GFile *location;
556 selected = get_selected_bookmark ();
558 if (!selected) {
559 return;
562 location = nautilus_bookmark_get_location (selected);
563 if (location == NULL) {
564 return;
567 if (NAUTILUS_IS_NAVIGATION_WINDOW (user_data)) {
568 nautilus_window_go_to (NAUTILUS_WINDOW (user_data), location);
569 } else if (NAUTILUS_IS_SPATIAL_WINDOW (user_data)) {
570 window = nautilus_application_present_spatial_window (application,
571 NULL,
572 NULL,
573 location,
574 screen);
575 } else { /* window that opened bookmarks window has been closed */
576 if (parent_is_browser_window || eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_BROWSER)) {
577 window = nautilus_application_create_navigation_window (application,
578 NULL,
579 screen);
580 nautilus_window_go_to (window, location);
581 } else {
582 window = nautilus_application_present_spatial_window (application,
583 NULL,
584 NULL,
585 location,
586 screen);
590 g_object_unref (location);
593 static void
594 on_jump_button_clicked (GtkButton *button,
595 gpointer user_data)
597 GdkScreen *screen;
599 screen = gtk_widget_get_screen (GTK_WIDGET (button));
600 open_selected_bookmark (user_data, screen);
603 static void
604 bookmarks_delete_bookmark (void)
606 GtkTreeIter iter;
607 GtkTreePath *path;
608 gint *indices, row, rows;
610 g_assert (GTK_IS_TREE_VIEW (bookmark_list_widget));
612 if (!gtk_tree_selection_get_selected (bookmark_selection, NULL, &iter))
613 return;
615 /* Remove the selected item from the list store. on_row_deleted() will
616 remove it from the bookmark list. */
617 path = gtk_tree_model_get_path (GTK_TREE_MODEL (bookmark_list_store),
618 &iter);
619 indices = gtk_tree_path_get_indices (path);
620 row = indices[0];
621 gtk_tree_path_free (path);
623 gtk_list_store_remove (bookmark_list_store, &iter);
625 /* Try to select the same row, or the last one in the list. */
626 rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (bookmark_list_store), NULL);
627 if (row >= rows)
628 row = rows - 1;
630 if (row < 0) {
631 bookmarks_set_empty (TRUE);
632 } else {
633 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (bookmark_list_store),
634 &iter, NULL, row);
635 gtk_tree_selection_select_iter (bookmark_selection, &iter);
639 static void
640 on_remove_button_clicked (GtkButton *button,
641 gpointer user_data)
643 bookmarks_delete_bookmark ();
647 /* This is a bit of a kludge to get DnD to work. We check if the row in the
648 GtkListStore matches the one in the bookmark list. If it doesn't, we assume
649 the bookmark has just been dragged here and we insert it into the bookmark
650 list. */
651 static void
652 on_row_changed (GtkListStore *store,
653 GtkTreePath *path,
654 GtkTreeIter *iter,
655 gpointer user_data)
657 NautilusBookmark *bookmark = NULL, *bookmark_in_list;
658 gint *indices, row;
659 gboolean insert_bookmark = TRUE;
661 store = bookmark_list_store;
663 indices = gtk_tree_path_get_indices (path);
664 row = indices[0];
665 gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
666 BOOKMARK_LIST_COLUMN_BOOKMARK, &bookmark,
667 -1);
669 /* If the bookmark in the list doesn't match the changed one, it must
670 have been dragged here, so we insert it into the list. */
671 if (row < (gint) nautilus_bookmark_list_length (bookmarks)) {
672 bookmark_in_list = nautilus_bookmark_list_item_at (bookmarks,
673 row);
674 if (bookmark_in_list == bookmark)
675 insert_bookmark = FALSE;
678 if (insert_bookmark) {
679 g_signal_handler_block (bookmarks,
680 bookmark_list_changed_signal_id);
681 nautilus_bookmark_list_insert_item (bookmarks, bookmark, row);
682 g_signal_handler_unblock (bookmarks,
683 bookmark_list_changed_signal_id);
685 /* The bookmark will be copied when inserted into the list, so
686 we have to update the pointer in the list store. */
687 bookmark = nautilus_bookmark_list_item_at (bookmarks, row);
688 g_signal_handler_block (store, row_changed_signal_id);
689 gtk_list_store_set (store, iter,
690 BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark,
691 -1);
692 g_signal_handler_unblock (store, row_changed_signal_id);
696 /* The update_bookmark_from_text() calls in the
697 * on_button_pressed() and on_key_pressed() handlers
698 * of the tree view are a hack.
700 * The purpose is to track selection changes to the view
701 * and write the text fields back before the selection
702 * actually changed.
704 * Note that the focus-out event of the text entries is emitted
705 * after the selection changed, else this would not not be neccessary.
708 static gboolean
709 on_button_pressed (GtkTreeView *view,
710 GdkEventButton *event,
711 gpointer user_data)
713 update_bookmark_from_text ();
715 return FALSE;
718 static gboolean
719 on_key_pressed (GtkTreeView *view,
720 GdkEventKey *event,
721 gpointer user_data)
723 if (event->keyval == GDK_Delete || event->keyval == GDK_KP_Delete) {
724 bookmarks_delete_bookmark ();
725 return TRUE;
728 update_bookmark_from_text ();
730 return FALSE;
733 static void
734 on_row_activated (GtkTreeView *view,
735 GtkTreePath *path,
736 GtkTreeViewColumn *column,
737 gpointer user_data)
739 GdkScreen *screen;
741 screen = gtk_widget_get_screen (GTK_WIDGET (view));
742 open_selected_bookmark (user_data, screen);
745 static void
746 on_row_deleted (GtkListStore *store,
747 GtkTreePath *path,
748 gpointer user_data)
750 gint *indices, row;
752 indices = gtk_tree_path_get_indices (path);
753 row = indices[0];
755 g_signal_handler_block (bookmarks, bookmark_list_changed_signal_id);
756 nautilus_bookmark_list_delete_item_at (bookmarks, row);
757 g_signal_handler_unblock (bookmarks, bookmark_list_changed_signal_id);
760 static void
761 on_selection_changed (GtkTreeSelection *treeselection,
762 gpointer user_data)
764 NautilusBookmark *selected;
765 char *name = NULL, *uri = NULL;
767 g_assert (GTK_IS_ENTRY (name_field));
768 g_assert (GTK_IS_ENTRY (uri_field));
770 selected = get_selected_bookmark ();
772 if (selected) {
773 name = nautilus_bookmark_get_name (selected);
774 uri = nautilus_bookmark_get_uri (selected);
777 /* Set the sensitivity of widgets that require a selection */
778 gtk_widget_set_sensitive (remove_button, selected != NULL);
779 gtk_widget_set_sensitive (jump_button, selected != NULL);
780 gtk_widget_set_sensitive (name_field, selected != NULL);
781 gtk_widget_set_sensitive (uri_field, selected != NULL);
783 g_signal_handler_block (name_field, name_field_changed_signal_id);
784 nautilus_entry_set_text (NAUTILUS_ENTRY (name_field),
785 name ? name : "");
786 g_signal_handler_unblock (name_field, name_field_changed_signal_id);
788 g_signal_handler_block (uri_field, uri_field_changed_signal_id);
789 nautilus_entry_set_text (NAUTILUS_ENTRY (uri_field),
790 uri ? uri : "");
791 g_signal_handler_unblock (uri_field, uri_field_changed_signal_id);
793 text_changed = FALSE;
794 name_text_changed = FALSE;
796 g_free (name);
797 g_free (uri);
801 static void
802 update_bookmark_from_text (void)
804 if (text_changed) {
805 NautilusBookmark *bookmark, *bookmark_in_list;
806 char *name;
807 GdkPixbuf *pixbuf;
808 guint selected_row;
809 GtkTreeIter iter;
810 GFile *location;
812 g_assert (GTK_IS_ENTRY (name_field));
813 g_assert (GTK_IS_ENTRY (uri_field));
815 location = g_file_new_for_uri (gtk_entry_get_text (GTK_ENTRY (uri_field)));
817 bookmark = nautilus_bookmark_new_with_icon (location, gtk_entry_get_text (GTK_ENTRY (name_field)),
818 name_text_changed, NULL);
820 g_object_unref (location);
822 selected_row = get_selected_row ();
824 /* turn off list updating 'cuz otherwise the list-reordering code runs
825 * after repopulate(), thus reordering the correctly-ordered list.
827 g_signal_handler_block (bookmarks,
828 bookmark_list_changed_signal_id);
829 nautilus_bookmark_list_delete_item_at (bookmarks, selected_row);
830 nautilus_bookmark_list_insert_item (bookmarks, bookmark, selected_row);
831 g_signal_handler_unblock (bookmarks,
832 bookmark_list_changed_signal_id);
833 g_object_unref (bookmark);
835 /* We also have to update the bookmark pointer in the list
836 store. */
837 gtk_tree_selection_get_selected (bookmark_selection,
838 NULL, &iter);
839 g_signal_handler_block (bookmark_list_store,
840 row_changed_signal_id);
842 bookmark_in_list = nautilus_bookmark_list_item_at (bookmarks,
843 selected_row);
845 name = nautilus_bookmark_get_name (bookmark_in_list);
847 pixbuf = nautilus_bookmark_get_pixbuf (bookmark_in_list, GTK_ICON_SIZE_MENU);
849 gtk_list_store_set (bookmark_list_store, &iter,
850 BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark_in_list,
851 BOOKMARK_LIST_COLUMN_NAME, name,
852 BOOKMARK_LIST_COLUMN_ICON, pixbuf,
853 -1);
854 g_signal_handler_unblock (bookmark_list_store,
855 row_changed_signal_id);
857 gdk_pixbuf_unref (pixbuf);
858 g_free (name);
862 static gboolean
863 on_text_field_focus_out_event (GtkWidget *widget,
864 GdkEventFocus *event,
865 gpointer user_data)
867 g_assert (NAUTILUS_IS_ENTRY (widget));
869 update_bookmark_from_text ();
870 return FALSE;
873 static void
874 name_or_uri_field_activate (NautilusEntry *entry)
876 g_assert (NAUTILUS_IS_ENTRY (entry));
878 update_bookmark_from_text ();
879 nautilus_entry_select_all_at_idle (entry);
882 static void
883 on_uri_field_changed (GtkEditable *editable,
884 gpointer user_data)
886 /* Remember that user has changed text so we
887 * update real bookmark later.
889 text_changed = TRUE;
892 static gboolean
893 on_window_delete_event (GtkWidget *widget,
894 GdkEvent *event,
895 gpointer user_data)
897 gtk_widget_hide (widget);
898 return TRUE;
901 static gboolean
902 restore_geometry (gpointer data)
904 g_assert (GTK_IS_WINDOW (data));
906 nautilus_bookmarks_window_restore_geometry (GTK_WIDGET (data));
908 /* Don't call this again */
909 return FALSE;
912 static void
913 on_window_hide_event (GtkWidget *widget,
914 gpointer user_data)
916 nautilus_bookmarks_window_save_geometry (GTK_WINDOW (widget));
918 /* Disable undo for entry widgets */
919 nautilus_undo_unregister (G_OBJECT (name_field));
920 nautilus_undo_unregister (G_OBJECT (uri_field));
922 /* restore_geometry only works after window is hidden */
923 g_idle_add (restore_geometry, widget);
926 static void
927 on_window_destroy_event (GtkWidget *widget,
928 gpointer user_data)
930 g_object_unref (bookmark_list_store);
931 g_object_unref (bookmark_empty_list_store);
932 g_source_remove_by_user_data (widget);
935 static void
936 repopulate (void)
938 NautilusBookmark *selected;
939 GtkListStore *store;
940 GtkTreePath *path;
941 GtkTreeRowReference *reference;
942 guint index;
944 g_assert (GTK_IS_TREE_VIEW (bookmark_list_widget));
945 g_assert (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
947 store = GTK_LIST_STORE (bookmark_list_store);
949 selected = get_selected_bookmark ();
951 g_signal_handler_block (bookmark_selection,
952 selection_changed_id);
953 g_signal_handler_block (bookmark_list_store,
954 row_deleted_signal_id);
955 g_signal_handler_block (bookmark_list_widget,
956 row_activated_signal_id);
957 g_signal_handler_block (bookmark_list_widget,
958 key_pressed_signal_id);
959 g_signal_handler_block (bookmark_list_widget,
960 button_pressed_signal_id);
962 gtk_list_store_clear (store);
964 g_signal_handler_unblock (bookmark_list_widget,
965 row_activated_signal_id);
966 g_signal_handler_unblock (bookmark_list_widget,
967 key_pressed_signal_id);
968 g_signal_handler_unblock (bookmark_list_widget,
969 button_pressed_signal_id);
970 g_signal_handler_unblock (bookmark_list_store,
971 row_deleted_signal_id);
972 g_signal_handler_unblock (bookmark_selection,
973 selection_changed_id);
975 /* Fill the list in with the bookmark names. */
976 g_signal_handler_block (store, row_changed_signal_id);
978 reference = NULL;
980 for (index = 0; index < nautilus_bookmark_list_length (bookmarks); ++index) {
981 NautilusBookmark *bookmark;
982 char *bookmark_name;
983 GdkPixbuf *bookmark_pixbuf;
984 GtkTreeIter iter;
986 bookmark = nautilus_bookmark_list_item_at (bookmarks, index);
987 bookmark_name = nautilus_bookmark_get_name (bookmark);
988 bookmark_pixbuf = nautilus_bookmark_get_pixbuf (bookmark, GTK_ICON_SIZE_MENU);
990 gtk_list_store_append (store, &iter);
991 gtk_list_store_set (store, &iter,
992 BOOKMARK_LIST_COLUMN_ICON, bookmark_pixbuf,
993 BOOKMARK_LIST_COLUMN_NAME, bookmark_name,
994 BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark,
995 BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_NORMAL,
996 -1);
998 if (bookmark == selected) {
999 /* save old selection */
1000 GtkTreePath *path;
1002 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
1003 reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
1004 gtk_tree_path_free (path);
1007 g_free (bookmark_name);
1008 g_object_unref (bookmark_pixbuf);
1011 g_signal_handler_unblock (store, row_changed_signal_id);
1013 if (reference != NULL) {
1014 /* restore old selection */
1016 /* bookmarks_set_empty() will call the selection change handler,
1017 * so we block it here in case of selection change.
1019 g_signal_handler_block (bookmark_selection, selection_changed_id);
1021 g_assert (index != 0);
1022 g_assert (gtk_tree_row_reference_valid (reference));
1024 path = gtk_tree_row_reference_get_path (reference);
1025 gtk_tree_selection_select_path (bookmark_selection, path);
1026 gtk_tree_row_reference_free (reference);
1027 gtk_tree_path_free (path);
1029 g_signal_handler_unblock (bookmark_selection, selection_changed_id);
1032 bookmarks_set_empty (index == 0);
1035 static int
1036 handle_close_accelerator (GtkWindow *window,
1037 GdkEventKey *event,
1038 gpointer user_data)
1040 g_assert (GTK_IS_WINDOW (window));
1041 g_assert (event != NULL);
1042 g_assert (user_data == NULL);
1044 if (eel_gtk_window_event_is_close_accelerator (window, event)) {
1045 gtk_widget_hide (GTK_WIDGET (window));
1046 return TRUE;
1049 return FALSE;
1052 static void
1053 set_up_close_accelerator (GtkWidget *window)
1055 /* Note that we don't call eel_gtk_window_set_up_close_accelerator
1056 * here because we have to handle saving geometry before hiding the
1057 * window.
1059 g_signal_connect (window, "key_press_event",
1060 G_CALLBACK (handle_close_accelerator), NULL);