No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 * Nautilus
5 *
6 * Copyright (C) 1999, 2000 Eazel, Inc.
7 *
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.
12 *
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.
17 *
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.
21 *
22 * Authors: John Sullivan <sullivan@eazel.com>
23 */
24
25 /* nautilus-bookmarks-window.c - implementation of bookmark-editing window.
26 */
27
28 #include <config.h>
29
30 #include "nautilus-application.h"
31 #include "nautilus-bookmarks-window.h"
32 #include "nautilus-window.h"
33
34 #include <libnautilus-private/nautilus-entry.h>
35 #include <libnautilus-private/nautilus-global-preferences.h>
36
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 #include <gdk/gdkkeysyms.h>
40
41 /* We store a pointer to the bookmark in a column so when an item is moved
42 with DnD we know which item it is. However we have to be careful to keep
43 this in sync with the actual bookmark. Note that
44 nautilus_bookmark_list_insert_item() makes a copy of the bookmark, so we
45 have to fetch the new copy and update our pointer. */
46
47 enum {
48 BOOKMARK_LIST_COLUMN_ICON,
49 BOOKMARK_LIST_COLUMN_NAME,
50 BOOKMARK_LIST_COLUMN_BOOKMARK,
51 BOOKMARK_LIST_COLUMN_STYLE,
52 BOOKMARK_LIST_NUM_COLUMNS
53 };
54
55 /* Larger size initially; user can stretch or shrink (but not shrink below min) */
56 #define BOOKMARKS_WINDOW_INITIAL_WIDTH 500
57 #define BOOKMARKS_WINDOW_INITIAL_HEIGHT 400
58
59 G_DEFINE_TYPE (NautilusBookmarksWindow, nautilus_bookmarks_window, GTK_TYPE_WINDOW)
60
61 enum {
62 PROP_PARENT_WINDOW = 1,
63 NUM_PROPERTIES
64 };
65
66 static GParamSpec* properties[NUM_PROPERTIES] = { NULL, };
67
68 struct NautilusBookmarksWindowPrivate {
69 NautilusWindow *parent_window;
70
71 NautilusBookmarkList *bookmarks;
72 gulong bookmarks_changed_id;
73
74 GtkTreeView *tree_view;
75 GtkTreeSelection *selection;
76 gulong row_activated_id;
77 gulong button_press_id;
78 gulong key_press_id;
79 gulong selection_changed_id;
80
81 GtkListStore *model;
82 gulong row_changed_id;
83 gulong row_deleted_id;
84
85 GtkWidget *name_field;
86 GtkWidget *uri_field;
87 gulong name_changed_id;
88 gulong uri_changed_id;
89 gboolean text_changed;
90 gboolean name_text_changed;
91
92 GtkWidget *remove_button;
93 GtkWidget *up_button;
94 GtkWidget *down_button;
95 };
96
97 static gboolean
98 get_selection_exists (NautilusBookmarksWindow *self)
99 {
100 return gtk_tree_selection_get_selected (self->priv->selection, NULL, NULL);
101 }
102
103 static guint
104 get_selected_row (NautilusBookmarksWindow *self)
105 {
106 GtkTreeIter iter;
107 GtkTreePath *path;
108 GtkTreeModel *model;
109 gint *indices, row;
110
111 if (!gtk_tree_selection_get_selected (self->priv->selection, &model, &iter)) {
112 g_assert_not_reached ();
113 }
114
115 path = gtk_tree_model_get_path (model, &iter);
116 indices = gtk_tree_path_get_indices (path);
117 row = indices[0];
118 gtk_tree_path_free (path);
119 return row;
120 }
121
122 static NautilusBookmark *
123 get_selected_bookmark (NautilusBookmarksWindow *self)
124 {
125 if (!get_selection_exists (self)) {
126 return NULL;
127 }
128
129 if (nautilus_bookmark_list_length (self->priv->bookmarks) < 1) {
130 return NULL;
131 }
132
133 return nautilus_bookmark_list_item_at (self->priv->bookmarks,
134 get_selected_row (self));
135 }
136
137 static int
138 nautilus_bookmarks_window_key_press_event_cb (GtkWindow *window,
139 GdkEventKey *event,
140 gpointer user_data)
141 {
142 if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_w) {
143 gtk_widget_destroy (GTK_WIDGET (window));
144 return TRUE;
145 }
146
147 return FALSE;
148 }
149
150 static GtkListStore *
151 create_bookmark_store (void)
152 {
153 return gtk_list_store_new (BOOKMARK_LIST_NUM_COLUMNS,
154 G_TYPE_ICON,
155 G_TYPE_STRING,
156 G_TYPE_OBJECT,
157 PANGO_TYPE_STYLE);
158 }
159
160 static void
161 setup_empty_list (NautilusBookmarksWindow *self)
162 {
163 GtkListStore *empty_model;
164 GtkTreeIter iter;
165
166 empty_model = create_bookmark_store ();
167 gtk_list_store_append (empty_model, &iter);
168
169 gtk_list_store_set (empty_model, &iter,
170 BOOKMARK_LIST_COLUMN_NAME, _("No bookmarks defined"),
171 BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_ITALIC,
172 -1);
173 gtk_tree_view_set_model (self->priv->tree_view,
174 GTK_TREE_MODEL (empty_model));
175
176 g_object_unref (empty_model);
177 }
178
179 static void
180 update_widgets_sensitivity (NautilusBookmarksWindow *self)
181 {
182 NautilusBookmark *selected;
183 int n_active;
184 int index = -1;
185
186 selected = get_selected_bookmark (self);
187 n_active = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->priv->model), NULL);
188 if (selected != NULL) {
189 index = get_selected_row (self);
190 }
191
192 /* Set the sensitivity of widgets that require a selection */
193 gtk_widget_set_sensitive (self->priv->remove_button, index >= 0 && n_active > 1);
194 gtk_widget_set_sensitive (self->priv->up_button, index > 0);
195 gtk_widget_set_sensitive (self->priv->down_button, index >= 0 && index < n_active - 1);
196 gtk_widget_set_sensitive (self->priv->name_field, selected != NULL);
197 gtk_widget_set_sensitive (self->priv->uri_field, selected != NULL);
198 }
199
200 static void
201 on_selection_changed (GtkTreeSelection *treeselection,
202 gpointer user_data)
203 {
204 NautilusBookmarksWindow *self = user_data;
205 NautilusBookmark *selected;
206 const char *name = NULL;
207 char *entry_text = NULL;
208 GFile *location;
209
210 selected = get_selected_bookmark (self);
211
212 if (selected) {
213 name = nautilus_bookmark_get_name (selected);
214 location = nautilus_bookmark_get_location (selected);
215 entry_text = g_file_get_parse_name (location);
216
217 g_object_unref (location);
218 }
219
220 update_widgets_sensitivity (self);
221
222 g_signal_handler_block (self->priv->name_field, self->priv->name_changed_id);
223 nautilus_entry_set_text (NAUTILUS_ENTRY (self->priv->name_field),
224 name ? name : "");
225 g_signal_handler_unblock (self->priv->name_field, self->priv->name_changed_id);
226
227 g_signal_handler_block (self->priv->uri_field, self->priv->uri_changed_id);
228 nautilus_entry_set_text (NAUTILUS_ENTRY (self->priv->uri_field),
229 entry_text ? entry_text : "");
230 g_signal_handler_unblock (self->priv->uri_field, self->priv->uri_changed_id);
231
232 self->priv->text_changed = FALSE;
233 self->priv->name_text_changed = FALSE;
234
235 g_free (entry_text);
236 }
237
238 static void
239 bookmarks_set_empty (NautilusBookmarksWindow *self,
240 gboolean empty)
241 {
242 GtkTreeIter iter;
243
244 if (empty) {
245 setup_empty_list (self);
246 gtk_widget_set_sensitive (GTK_WIDGET (self->priv->tree_view), FALSE);
247 } else {
248 gtk_tree_view_set_model (self->priv->tree_view, GTK_TREE_MODEL (self->priv->model));
249 gtk_widget_set_sensitive (GTK_WIDGET (self->priv->tree_view), TRUE);
250
251 if (nautilus_bookmark_list_length (self->priv->bookmarks) > 0 &&
252 !get_selection_exists (self)) {
253 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->priv->model),
254 &iter, NULL, 0);
255 gtk_tree_selection_select_iter (self->priv->selection, &iter);
256 }
257 }
258
259 on_selection_changed (self->priv->selection, self);
260 }
261
262 static void
263 repopulate (NautilusBookmarksWindow *self)
264 {
265 NautilusBookmark *selected;
266 GtkListStore *store;
267 GtkTreePath *path;
268 GtkTreeRowReference *reference;
269 guint index;
270
271 selected = get_selected_bookmark (self);
272
273 g_signal_handler_block (self->priv->selection, self->priv->selection_changed_id);
274 g_signal_handler_block (self->priv->model, self->priv->row_deleted_id);
275 g_signal_handler_block (self->priv->tree_view, self->priv->row_activated_id);
276 g_signal_handler_block (self->priv->tree_view, self->priv->key_press_id);
277 g_signal_handler_block (self->priv->tree_view, self->priv->button_press_id);
278
279 gtk_list_store_clear (self->priv->model);
280
281 g_signal_handler_unblock (self->priv->selection, self->priv->selection_changed_id);
282 g_signal_handler_unblock (self->priv->model, self->priv->row_deleted_id);
283 g_signal_handler_unblock (self->priv->tree_view, self->priv->row_activated_id);
284 g_signal_handler_unblock (self->priv->tree_view, self->priv->key_press_id);
285 g_signal_handler_unblock (self->priv->tree_view, self->priv->button_press_id);
286
287 /* Fill the list in with the bookmark names. */
288 g_signal_handler_block (self->priv->model, self->priv->row_changed_id);
289
290 reference = NULL;
291 store = self->priv->model;
292
293 for (index = 0; index < nautilus_bookmark_list_length (self->priv->bookmarks); ++index) {
294 NautilusBookmark *bookmark;
295 const char *bookmark_name;
296 GIcon *bookmark_icon;
297 GtkTreeIter iter;
298
299 bookmark = nautilus_bookmark_list_item_at (self->priv->bookmarks, index);
300 bookmark_name = nautilus_bookmark_get_name (bookmark);
301 bookmark_icon = nautilus_bookmark_get_symbolic_icon (bookmark);
302
303 gtk_list_store_append (store, &iter);
304 gtk_list_store_set (store, &iter,
305 BOOKMARK_LIST_COLUMN_ICON, bookmark_icon,
306 BOOKMARK_LIST_COLUMN_NAME, bookmark_name,
307 BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark,
308 BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_NORMAL,
309 -1);
310
311 if (bookmark == selected) {
312 /* save old selection */
313 GtkTreePath *path;
314
315 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
316 reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
317 gtk_tree_path_free (path);
318 }
319
320 g_object_unref (bookmark_icon);
321 }
322
323 g_signal_handler_unblock (self->priv->model, self->priv->row_changed_id);
324
325 if (reference != NULL) {
326 /* restore old selection */
327
328 /* bookmarks_set_empty() will call the selection change handler,
329 * so we block it here in case of selection change.
330 */
331 g_signal_handler_block (self->priv->selection, self->priv->selection_changed_id);
332
333 g_assert (index != 0);
334 g_assert (gtk_tree_row_reference_valid (reference));
335
336 path = gtk_tree_row_reference_get_path (reference);
337 gtk_tree_selection_select_path (self->priv->selection, path);
338 gtk_tree_row_reference_free (reference);
339 gtk_tree_path_free (path);
340
341 g_signal_handler_unblock (self->priv->selection, self->priv->selection_changed_id);
342 }
343
344 bookmarks_set_empty (self, (index == 0));
345 }
346
347 static void
348 on_bookmark_list_changed (NautilusBookmarkList *bookmarks,
349 gpointer user_data)
350 {
351 NautilusBookmarksWindow *self = user_data;
352
353 /* maybe add logic here or in repopulate to save/restore selection */
354 repopulate (self);
355 }
356
357 static void
358 on_name_field_changed (GtkEditable *editable,
359 gpointer user_data)
360 {
361 NautilusBookmarksWindow *self = user_data;
362 GtkTreeIter iter;
363
364 if (!get_selection_exists(self)) {
365 return;
366 }
367
368 /* Update text displayed in list instantly. Also remember that
369 * user has changed text so we update real bookmark later.
370 */
371 gtk_tree_selection_get_selected (self->priv->selection, NULL, &iter);
372 gtk_list_store_set (self->priv->model,
373 &iter, BOOKMARK_LIST_COLUMN_NAME,
374 gtk_entry_get_text (GTK_ENTRY (self->priv->name_field)),
375 -1);
376
377 self->priv->text_changed = TRUE;
378 self->priv->name_text_changed = TRUE;
379 }
380
381 static void
382 bookmarks_delete_bookmark (NautilusBookmarksWindow *self)
383 {
384 GtkTreeIter iter;
385 GtkTreePath *path;
386 gint *indices, row, rows;
387
388 if (!gtk_tree_selection_get_selected (self->priv->selection, NULL, &iter)) {
389 return;
390 }
391
392 /* Remove the selected item from the list store. on_row_deleted() will
393 remove it from the bookmark list. */
394 path = gtk_tree_model_get_path (GTK_TREE_MODEL (self->priv->model), &iter);
395 indices = gtk_tree_path_get_indices (path);
396 row = indices[0];
397 gtk_tree_path_free (path);
398
399 gtk_list_store_remove (self->priv->model, &iter);
400
401 /* Try to select the same row, or the last one in the list. */
402 rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->priv->model), NULL);
403 if (row >= rows) {
404 row = rows - 1;
405 }
406
407 if (row < 0) {
408 bookmarks_set_empty (self, TRUE);
409 } else {
410 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->priv->model),
411 &iter, NULL, row);
412 gtk_tree_selection_select_iter (self->priv->selection, &iter);
413 }
414 }
415
416 static void
417 on_remove_button_clicked (GtkButton *button,
418 gpointer user_data)
419 {
420 NautilusBookmarksWindow *self = user_data;
421 bookmarks_delete_bookmark (self);
422 }
423
424 static void
425 on_up_button_clicked (GtkButton *button,
426 gpointer user_data)
427 {
428 NautilusBookmarksWindow *self = user_data;
429 guint row;
430 GtkTreeIter iter;
431
432 row = get_selected_row (self);
433 nautilus_bookmark_list_move_item (self->priv->bookmarks, row, row - 1);
434 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->priv->model),
435 &iter, NULL, row - 1);
436 gtk_tree_selection_select_iter (self->priv->selection, &iter);
437 }
438
439 static void
440 on_down_button_clicked (GtkButton *button,
441 gpointer user_data)
442 {
443 NautilusBookmarksWindow *self = user_data;
444 guint row;
445 GtkTreeIter iter;
446
447 row = get_selected_row (self);
448 nautilus_bookmark_list_move_item (self->priv->bookmarks, row, row + 1);
449 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->priv->model),
450 &iter, NULL, row + 1);
451 gtk_tree_selection_select_iter (self->priv->selection, &iter);
452 }
453
454 /* This is a bit of a kludge to get DnD to work. We check if the row in the
455 GtkListStore matches the one in the bookmark list. If it doesn't, we assume
456 the bookmark has just been dragged here and we insert it into the bookmark
457 list. */
458 static void
459 on_row_changed (GtkListStore *store,
460 GtkTreePath *path,
461 GtkTreeIter *iter,
462 gpointer user_data)
463 {
464 NautilusBookmarksWindow *self = user_data;
465 NautilusBookmark *bookmark = NULL, *bookmark_in_list;
466 gint *indices, row;
467 gboolean insert_bookmark = TRUE;
468
469 indices = gtk_tree_path_get_indices (path);
470 row = indices[0];
471 gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
472 BOOKMARK_LIST_COLUMN_BOOKMARK, &bookmark,
473 -1);
474
475 /* If the bookmark in the list doesn't match the changed one, it must
476 have been dragged here, so we insert it into the list. */
477 if (row < (gint) nautilus_bookmark_list_length (self->priv->bookmarks)) {
478 bookmark_in_list = nautilus_bookmark_list_item_at (self->priv->bookmarks, row);
479 if (bookmark_in_list == bookmark)
480 insert_bookmark = FALSE;
481 }
482
483 if (insert_bookmark) {
484 g_signal_handler_block (self->priv->bookmarks,
485 self->priv->bookmarks_changed_id);
486 nautilus_bookmark_list_insert_item (self->priv->bookmarks,
487 bookmark, row);
488 g_signal_handler_unblock (self->priv->bookmarks,
489 self->priv->bookmarks_changed_id);
490
491 /* The bookmark will be copied when inserted into the list, so
492 we have to update the pointer in the list store. */
493 bookmark = nautilus_bookmark_list_item_at (self->priv->bookmarks, row);
494 g_signal_handler_block (store, self->priv->row_changed_id);
495 gtk_list_store_set (store, iter,
496 BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark,
497 -1);
498 g_signal_handler_unblock (store, self->priv->row_changed_id);
499 }
500 }
501
502 static void
503 update_bookmark_from_text (NautilusBookmarksWindow *self)
504 {
505 NautilusBookmark *bookmark, *bookmark_in_list;
506 const char *name;
507 GIcon *icon;
508 guint selected_row;
509 GtkTreeIter iter;
510 GFile *location;
511
512 if (!self->priv->text_changed ||
513 gtk_entry_get_text_length (GTK_ENTRY (self->priv->uri_field)) == 0) {
514 return;
515 }
516
517 location = g_file_parse_name
518 (gtk_entry_get_text (GTK_ENTRY (self->priv->uri_field)));
519
520 bookmark = nautilus_bookmark_new (location,
521 self->priv->name_text_changed ?
522 gtk_entry_get_text (GTK_ENTRY (self->priv->name_field)) : NULL);
523 g_object_unref (location);
524
525 selected_row = get_selected_row (self);
526
527 /* turn off list updating 'cuz otherwise the list-reordering code runs
528 * after repopulate(), thus reordering the correctly-ordered list.
529 */
530 g_signal_handler_block (self->priv->bookmarks, self->priv->bookmarks_changed_id);
531 nautilus_bookmark_list_delete_item_at (self->priv->bookmarks, selected_row);
532 nautilus_bookmark_list_insert_item (self->priv->bookmarks, bookmark, selected_row);
533 g_signal_handler_unblock (self->priv->bookmarks, self->priv->bookmarks_changed_id);
534 g_object_unref (bookmark);
535
536 /* We also have to update the bookmark pointer in the list
537 store. */
538 gtk_tree_selection_get_selected (self->priv->selection, NULL, &iter);
539 g_signal_handler_block (self->priv->model, self->priv->row_changed_id);
540
541 bookmark_in_list = nautilus_bookmark_list_item_at (self->priv->bookmarks, selected_row);
542 name = nautilus_bookmark_get_name (bookmark_in_list);
543 icon = nautilus_bookmark_get_symbolic_icon (bookmark_in_list);
544
545 gtk_list_store_set (self->priv->model, &iter,
546 BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark_in_list,
547 BOOKMARK_LIST_COLUMN_NAME, name,
548 BOOKMARK_LIST_COLUMN_ICON, icon,
549 -1);
550
551 g_signal_handler_unblock (self->priv->model, self->priv->row_changed_id);
552 g_object_unref (icon);
553 }
554
555 /* The update_bookmark_from_text() calls in the
556 * on_button_pressed() and on_key_pressed() handlers
557 * of the tree view are a hack.
558 *
559 * The purpose is to track selection changes to the view
560 * and write the text fields back before the selection
561 * actually changed.
562 *
563 * Note that the focus-out event of the text entries is emitted
564 * after the selection changed, else this would not not be neccessary.
565 */
566
567 static gboolean
568 on_button_pressed (GtkTreeView *view,
569 GdkEventButton *event,
570 gpointer user_data)
571 {
572 NautilusBookmarksWindow *self = user_data;
573 update_bookmark_from_text (self);
574
575 return FALSE;
576 }
577
578 static gboolean
579 on_key_pressed (GtkTreeView *view,
580 GdkEventKey *event,
581 gpointer user_data)
582 {
583 NautilusBookmarksWindow *self = user_data;
584
585 if (event->keyval == GDK_KEY_Delete || event->keyval == GDK_KEY_KP_Delete) {
586 bookmarks_delete_bookmark (self);
587 return TRUE;
588 }
589
590 update_bookmark_from_text (self);
591
592 return FALSE;
593 }
594
595 static void
596 on_row_activated (GtkTreeView *view,
597 GtkTreePath *path,
598 GtkTreeViewColumn *column,
599 gpointer user_data)
600 {
601 NautilusBookmarksWindow *self = user_data;
602 NautilusBookmark *selected;
603 GFile *location;
604
605 selected = get_selected_bookmark (self);
606
607 if (!selected) {
608 return;
609 }
610
611 location = nautilus_bookmark_get_location (selected);
612 if (location == NULL) {
613 return;
614 }
615
616 nautilus_window_go_to (self->priv->parent_window, location);
617 g_object_unref (location);
618 }
619
620 static void
621 on_row_deleted (GtkListStore *store,
622 GtkTreePath *path,
623 gpointer user_data)
624 {
625 NautilusBookmarksWindow *self = user_data;
626 gint *indices, row;
627
628 indices = gtk_tree_path_get_indices (path);
629 row = indices[0];
630
631 g_signal_handler_block (self->priv->bookmarks, self->priv->bookmarks_changed_id);
632 nautilus_bookmark_list_delete_item_at (self->priv->bookmarks, row);
633 g_signal_handler_unblock (self->priv->bookmarks, self->priv->bookmarks_changed_id);
634 }
635
636 static gboolean
637 on_text_field_focus_out_event (GtkWidget *widget,
638 GdkEventFocus *event,
639 gpointer user_data)
640 {
641 NautilusBookmarksWindow *self = user_data;
642 update_bookmark_from_text (self);
643
644 return FALSE;
645 }
646
647 static void
648 name_or_uri_field_activate (NautilusEntry *entry,
649 gpointer user_data)
650 {
651 NautilusBookmarksWindow *self = user_data;
652
653 update_bookmark_from_text (self);
654 nautilus_entry_select_all_at_idle (entry);
655 }
656
657 static void
658 on_uri_field_changed (GtkEditable *editable,
659 gpointer user_data)
660 {
661 NautilusBookmarksWindow *self = user_data;
662
663 /* Remember that user has changed text so we
664 * update real bookmark later.
665 */
666 self->priv->text_changed = TRUE;
667 }
668
669 static void
670 nautilus_bookmarks_window_dispose (GObject *object)
671 {
672 NautilusBookmarksWindow *self = NAUTILUS_BOOKMARKS_WINDOW (object);
673
674 if (self->priv->bookmarks_changed_id != 0) {
675 g_signal_handler_disconnect (self->priv->bookmarks,
676 self->priv->bookmarks_changed_id);
677 self->priv->bookmarks_changed_id = 0;
678 }
679
680 g_clear_object (&self->priv->model);
681
682 G_OBJECT_CLASS (nautilus_bookmarks_window_parent_class)->dispose (object);
683 }
684
685 static void
686 nautilus_bookmarks_window_constructed (GObject *object)
687 {
688 NautilusBookmarksWindow *self = NAUTILUS_BOOKMARKS_WINDOW (object);
689 GtkBuilder *builder;
690 GError *error = NULL;
691 GtkWindow *window;
692 GtkWidget *content;
693 GtkTreeViewColumn *col;
694 GtkCellRenderer *rend;
695
696 G_OBJECT_CLASS (nautilus_bookmarks_window_parent_class)->constructed (object);
697
698 builder = gtk_builder_new ();
699 if (!gtk_builder_add_from_resource (builder,
700 "/org/gnome/nautilus/nautilus-bookmarks-window.ui",
701 &error)) {
702 g_object_unref (builder);
703
704 g_critical ("Can't load UI description for the bookmarks editor: %s", error->message);
705 g_error_free (error);
706 return;
707 }
708
709 window = GTK_WINDOW (object);
710 gtk_window_set_title (window, _("Bookmarks"));
711 gtk_window_set_default_size (window,
712 BOOKMARKS_WINDOW_INITIAL_WIDTH,
713 BOOKMARKS_WINDOW_INITIAL_HEIGHT);
714 gtk_window_set_application (window,
715 gtk_window_get_application (GTK_WINDOW (self->priv->parent_window)));
716
717 gtk_window_set_destroy_with_parent (window, TRUE);
718 gtk_window_set_transient_for (window, GTK_WINDOW (self->priv->parent_window));
719 gtk_window_set_position (window, GTK_WIN_POS_CENTER_ON_PARENT);
720 gtk_container_set_border_width (GTK_CONTAINER (window), 6);
721
722 g_signal_connect (window, "key-press-event",
723 G_CALLBACK (nautilus_bookmarks_window_key_press_event_cb), NULL);
724
725 content = GTK_WIDGET (gtk_builder_get_object (builder, "bookmarks_window_content"));
726 gtk_container_add (GTK_CONTAINER (window), content);
727
728 /* tree view */
729 self->priv->tree_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "bookmark_tree_view"));
730 self->priv->selection = gtk_tree_view_get_selection (self->priv->tree_view);
731 gtk_tree_selection_set_mode (self->priv->selection, GTK_SELECTION_BROWSE);
732
733 rend = gtk_cell_renderer_pixbuf_new ();
734 g_object_set (rend, "follow-state", TRUE, NULL);
735 col = gtk_tree_view_column_new_with_attributes ("Icon",
736 rend,
737 "gicon",
738 BOOKMARK_LIST_COLUMN_ICON,
739 NULL);
740 gtk_tree_view_append_column (self->priv->tree_view,
741 GTK_TREE_VIEW_COLUMN (col));
742 gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (col),
743 NAUTILUS_ICON_SIZE_SMALLER);
744
745 rend = gtk_cell_renderer_text_new ();
746 g_object_set (rend,
747 "ellipsize", PANGO_ELLIPSIZE_END,
748 "ellipsize-set", TRUE,
749 NULL);
750
751 col = gtk_tree_view_column_new_with_attributes ("Icon",
752 rend,
753 "text",
754 BOOKMARK_LIST_COLUMN_NAME,
755 "style",
756 BOOKMARK_LIST_COLUMN_STYLE,
757 NULL);
758 gtk_tree_view_append_column (self->priv->tree_view,
759 GTK_TREE_VIEW_COLUMN (col));
760
761 self->priv->model = create_bookmark_store ();
762 setup_empty_list (self);
763
764 /* name entry */
765 self->priv->name_field = nautilus_entry_new ();
766 gtk_widget_show (self->priv->name_field);
767 gtk_box_pack_start (GTK_BOX (gtk_builder_get_object (builder, "bookmark_name_placeholder")),
768 self->priv->name_field, TRUE, TRUE, 0);
769
770 gtk_label_set_mnemonic_widget (
771 GTK_LABEL (gtk_builder_get_object (builder, "bookmark_name_label")),
772 self->priv->name_field);
773
774 /* URI entry */
775 self->priv->uri_field = nautilus_entry_new ();
776 gtk_widget_show (self->priv->uri_field);
777 gtk_box_pack_start (GTK_BOX (gtk_builder_get_object (builder, "bookmark_location_placeholder")),
778 self->priv->uri_field, TRUE, TRUE, 0);
779
780 gtk_label_set_mnemonic_widget (
781 GTK_LABEL (gtk_builder_get_object (builder, "bookmark_location_label")),
782 self->priv->uri_field);
783
784 /* buttons */
785 self->priv->remove_button = GTK_WIDGET (gtk_builder_get_object (builder, "bookmark_remove_button"));
786 self->priv->up_button = GTK_WIDGET (gtk_builder_get_object (builder, "bookmark_up_button"));
787 self->priv->down_button = GTK_WIDGET (gtk_builder_get_object (builder, "bookmark_down_button"));
788
789 g_object_unref (builder);
790
791 /* setup bookmarks list and signals */
792 self->priv->bookmarks = nautilus_application_get_bookmarks
793 (NAUTILUS_APPLICATION (g_application_get_default ()));
794 self->priv->bookmarks_changed_id =
795 g_signal_connect (self->priv->bookmarks, "changed",
796 G_CALLBACK (on_bookmark_list_changed), self);
797
798 self->priv->row_changed_id =
799 g_signal_connect (self->priv->model, "row-changed",
800 G_CALLBACK (on_row_changed), self);
801 self->priv->row_deleted_id =
802 g_signal_connect (self->priv->model, "row-deleted",
803 G_CALLBACK (on_row_deleted), self);
804
805 self->priv->row_activated_id =
806 g_signal_connect (self->priv->tree_view, "row-activated",
807 G_CALLBACK (on_row_activated), self);
808 self->priv->button_press_id =
809 g_signal_connect (self->priv->tree_view, "button-press-event",
810 G_CALLBACK (on_button_pressed), self);
811 self->priv->key_press_id =
812 g_signal_connect (self->priv->tree_view, "key-press-event",
813 G_CALLBACK (on_key_pressed), self);
814 self->priv->selection_changed_id =
815 g_signal_connect (self->priv->selection, "changed",
816 G_CALLBACK (on_selection_changed), self);
817
818 self->priv->name_changed_id =
819 g_signal_connect (self->priv->name_field, "changed",
820 G_CALLBACK (on_name_field_changed), self);
821 g_signal_connect (self->priv->name_field, "focus_out_event",
822 G_CALLBACK (on_text_field_focus_out_event), self);
823 g_signal_connect (self->priv->name_field, "activate",
824 G_CALLBACK (name_or_uri_field_activate), self);
825
826 self->priv->uri_changed_id =
827 g_signal_connect (self->priv->uri_field, "changed",
828 G_CALLBACK (on_uri_field_changed), self);
829 g_signal_connect (self->priv->uri_field, "focus_out_event",
830 G_CALLBACK (on_text_field_focus_out_event), self);
831 g_signal_connect (self->priv->uri_field, "activate",
832 G_CALLBACK (name_or_uri_field_activate), self);
833
834 g_signal_connect (self->priv->remove_button, "clicked",
835 G_CALLBACK (on_remove_button_clicked), self);
836 g_signal_connect (self->priv->up_button, "clicked",
837 G_CALLBACK (on_up_button_clicked), self);
838 g_signal_connect (self->priv->down_button, "clicked",
839 G_CALLBACK (on_down_button_clicked), self);
840
841 /* Fill in list widget with bookmarks, must be after signals are wired up. */
842 repopulate (self);
843 }
844
845 static void
846 nautilus_bookmarks_window_set_property (GObject *object,
847 guint arg_id,
848 const GValue *value,
849 GParamSpec *pspec)
850 {
851 NautilusBookmarksWindow *self = NAUTILUS_BOOKMARKS_WINDOW (object);
852
853 switch (arg_id) {
854 case PROP_PARENT_WINDOW:
855 self->priv->parent_window = g_value_get_object (value);
856 break;
857 default:
858 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec);
859 break;
860 }
861 }
862
863 static void
864 nautilus_bookmarks_window_init (NautilusBookmarksWindow *self)
865 {
866 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_BOOKMARKS_WINDOW,
867 NautilusBookmarksWindowPrivate);
868 }
869
870 static void
871 nautilus_bookmarks_window_class_init (NautilusBookmarksWindowClass *klass)
872 {
873 GObjectClass *oclass = G_OBJECT_CLASS (klass);
874
875 oclass->set_property = nautilus_bookmarks_window_set_property;
876 oclass->dispose = nautilus_bookmarks_window_dispose;
877 oclass->constructed = nautilus_bookmarks_window_constructed;
878
879 properties[PROP_PARENT_WINDOW] =
880 g_param_spec_object ("parent-window",
881 "The NautilusWindow",
882 "The parent NautilusWindow",
883 NAUTILUS_TYPE_WINDOW,
884 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
885
886 g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
887 g_type_class_add_private (klass, sizeof (NautilusBookmarksWindowPrivate));
888 }
889
890 /**
891 * nautilus_bookmarks_window_new:
892 *
893 * Create a new bookmark-editing window.
894 * @parent_window: The parent NautilusWindow.
895 *
896 * Return value: A pointer to the new window.
897 **/
898 GtkWindow *
899 nautilus_bookmarks_window_new (NautilusWindow *parent_window)
900 {
901 return g_object_new (NAUTILUS_TYPE_BOOKMARKS_WINDOW,
902 "parent-window", parent_window,
903 NULL);
904 }