1 /* nautilus-places-view.c
2 *
3 * Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "nautilus-mime-actions.h"
20 #include "nautilus-places-view.h"
21
22 #include "gtk/nautilusgtkplacesviewprivate.h"
23
24 #include "nautilus-application.h"
25 #include "nautilus-file.h"
26 #include "nautilus-toolbar-menu-sections.h"
27 #include "nautilus-view.h"
28 #include "nautilus-window-slot.h"
29
30 typedef struct
31 {
32 GFile *location;
33 NautilusQuery *search_query;
34 NautilusToolbarMenuSections *toolbar_menu_sections;
35
36 GtkWidget *places_view;
37 } NautilusPlacesViewPrivate;
38
39 struct _NautilusPlacesView
40 {
41 GtkFrameClass parent;
42 };
43
44 static void nautilus_places_view_iface_init (NautilusViewInterface *iface);
45
46 G_DEFINE_TYPE_WITH_CODE (NautilusPlacesView, nautilus_places_view, GTK_TYPE_BOX,
47 G_ADD_PRIVATE (NautilusPlacesView)
48 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_VIEW, nautilus_places_view_iface_init));
49
50 enum
51 {
52 PROP_0,
53 PROP_LOCATION,
54 PROP_SEARCH_QUERY,
55 PROP_LOADING,
56 PROP_SEARCHING,
57 PROP_SELECTION,
58 PROP_EXTENSIONS_BACKGROUND_MENU,
59 PROP_TEMPLATES_MENU,
60 LAST_PROP
61 };
62
63 static void
open_location_cb(NautilusPlacesView * view,GFile * location,GtkPlacesOpenFlags open_flags)64 open_location_cb (NautilusPlacesView *view,
65 GFile *location,
66 GtkPlacesOpenFlags open_flags)
67 {
68 NautilusWindowOpenFlags flags;
69 GtkWidget *slot;
70
71 slot = gtk_widget_get_ancestor (GTK_WIDGET (view), NAUTILUS_TYPE_WINDOW_SLOT);
72
73 switch (open_flags)
74 {
75 case GTK_PLACES_OPEN_NEW_TAB:
76 {
77 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB |
78 NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE;
79 }
80 break;
81
82 case GTK_PLACES_OPEN_NEW_WINDOW:
83 {
84 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
85 }
86 break;
87
88 case GTK_PLACES_OPEN_NORMAL: /* fall-through */
89 default:
90 {
91 flags = 0;
92 }
93 break;
94 }
95
96 if (slot)
97 {
98 NautilusFile *file;
99 GtkWidget *window;
100 char *path;
101
102 path = "other-locations:///";
103 file = nautilus_file_get (location);
104 window = gtk_widget_get_toplevel (GTK_WIDGET (view));
105
106 nautilus_mime_activate_file (GTK_WINDOW (window),
107 NAUTILUS_WINDOW_SLOT (slot),
108 file,
109 path,
110 flags);
111 nautilus_file_unref (file);
112 }
113 }
114
115 static void
loading_cb(NautilusView * view)116 loading_cb (NautilusView *view)
117 {
118 g_object_notify (G_OBJECT (view), "loading");
119 }
120
121 static void
show_error_message_cb(NautilusGtkPlacesView * view,const gchar * primary,const gchar * secondary)122 show_error_message_cb (NautilusGtkPlacesView *view,
123 const gchar *primary,
124 const gchar *secondary)
125 {
126 GtkWidget *dialog;
127 GtkWidget *window;
128
129 window = gtk_widget_get_toplevel (GTK_WIDGET (view));
130
131 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
132 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
133 GTK_MESSAGE_ERROR,
134 GTK_BUTTONS_CLOSE,
135 "%s", primary);
136 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
137 "%s", secondary);
138
139 gtk_dialog_run (GTK_DIALOG (dialog));
140
141 gtk_widget_destroy (dialog);
142 }
143
144 static void
nautilus_places_view_finalize(GObject * object)145 nautilus_places_view_finalize (GObject *object)
146 {
147 NautilusPlacesView *self = (NautilusPlacesView *) object;
148 NautilusPlacesViewPrivate *priv = nautilus_places_view_get_instance_private (self);
149
150 g_clear_object (&priv->location);
151 g_clear_object (&priv->search_query);
152
153 g_free (priv->toolbar_menu_sections);
154
155 G_OBJECT_CLASS (nautilus_places_view_parent_class)->finalize (object);
156 }
157
158 static void
nautilus_places_view_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)159 nautilus_places_view_get_property (GObject *object,
160 guint prop_id,
161 GValue *value,
162 GParamSpec *pspec)
163 {
164 NautilusView *view = NAUTILUS_VIEW (object);
165
166 switch (prop_id)
167 {
168 case PROP_LOCATION:
169 {
170 g_value_set_object (value, nautilus_view_get_location (view));
171 }
172 break;
173
174 case PROP_SEARCH_QUERY:
175 {
176 g_value_set_object (value, nautilus_view_get_search_query (view));
177 }
178 break;
179
180 /* Collect all unused properties and do nothing. Ideally, this wouldn’t
181 * have to be done in the first place.
182 */
183 case PROP_SEARCHING:
184 case PROP_SELECTION:
185 case PROP_EXTENSIONS_BACKGROUND_MENU:
186 case PROP_TEMPLATES_MENU:
187 {
188 }
189 break;
190
191 default:
192 {
193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
194 }
195 }
196 }
197
198 static void
nautilus_places_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)199 nautilus_places_view_set_property (GObject *object,
200 guint prop_id,
201 const GValue *value,
202 GParamSpec *pspec)
203 {
204 NautilusView *view = NAUTILUS_VIEW (object);
205
206 switch (prop_id)
207 {
208 case PROP_LOCATION:
209 {
210 nautilus_view_set_location (view, g_value_get_object (value));
211 }
212 break;
213
214 case PROP_SEARCH_QUERY:
215 {
216 nautilus_view_set_search_query (view, g_value_get_object (value));
217 }
218 break;
219
220 default:
221 {
222 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223 }
224 }
225 }
226
227 static GFile *
nautilus_places_view_get_location(NautilusView * view)228 nautilus_places_view_get_location (NautilusView *view)
229 {
230 NautilusPlacesViewPrivate *priv;
231
232 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
233
234 return priv->location;
235 }
236
237 static void
nautilus_places_view_set_location(NautilusView * view,GFile * location)238 nautilus_places_view_set_location (NautilusView *view,
239 GFile *location)
240 {
241 if (location)
242 {
243 NautilusPlacesViewPrivate *priv;
244 gchar *uri;
245
246 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
247 uri = g_file_get_uri (location);
248
249 /*
250 * If it's not trying to open the places view itself, simply
251 * delegates the location to application, which takes care of
252 * selecting the appropriate view.
253 */
254 if (g_strcmp0 (uri, "other-locations:///") != 0)
255 {
256 nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
257 location, 0, NULL, NULL, NULL);
258 }
259 else
260 {
261 g_set_object (&priv->location, location);
262 }
263
264 g_free (uri);
265 }
266 }
267
268 static GList *
nautilus_places_view_get_selection(NautilusView * view)269 nautilus_places_view_get_selection (NautilusView *view)
270 {
271 /* STUB */
272 return NULL;
273 }
274
275 static void
nautilus_places_view_set_selection(NautilusView * view,GList * selection)276 nautilus_places_view_set_selection (NautilusView *view,
277 GList *selection)
278 {
279 /* STUB */
280 }
281
282 static NautilusQuery *
nautilus_places_view_get_search_query(NautilusView * view)283 nautilus_places_view_get_search_query (NautilusView *view)
284 {
285 NautilusPlacesViewPrivate *priv;
286
287 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
288
289 return priv->search_query;
290 }
291
292 static void
nautilus_places_view_set_search_query(NautilusView * view,NautilusQuery * query)293 nautilus_places_view_set_search_query (NautilusView *view,
294 NautilusQuery *query)
295 {
296 NautilusPlacesViewPrivate *priv;
297 gchar *text;
298
299 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
300
301 g_set_object (&priv->search_query, query);
302
303 text = query ? nautilus_query_get_text (query) : NULL;
304
305 nautilus_gtk_places_view_set_search_query (NAUTILUS_GTK_PLACES_VIEW (priv->places_view), text);
306
307 g_free (text);
308 }
309
310 static NautilusToolbarMenuSections *
nautilus_places_view_get_toolbar_menu_sections(NautilusView * view)311 nautilus_places_view_get_toolbar_menu_sections (NautilusView *view)
312 {
313 NautilusPlacesViewPrivate *priv;
314
315 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
316
317 return priv->toolbar_menu_sections;
318 }
319
320 static gboolean
nautilus_places_view_is_loading(NautilusView * view)321 nautilus_places_view_is_loading (NautilusView *view)
322 {
323 NautilusPlacesViewPrivate *priv;
324
325 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
326
327 return nautilus_gtk_places_view_get_loading (NAUTILUS_GTK_PLACES_VIEW (priv->places_view));
328 }
329
330 static gboolean
nautilus_places_view_is_searching(NautilusView * view)331 nautilus_places_view_is_searching (NautilusView *view)
332 {
333 NautilusPlacesViewPrivate *priv;
334
335 priv = nautilus_places_view_get_instance_private (NAUTILUS_PLACES_VIEW (view));
336
337 return priv->search_query != NULL;
338 }
339
340 static guint
nautilus_places_view_get_view_id(NautilusView * view)341 nautilus_places_view_get_view_id (NautilusView *view)
342 {
343 return NAUTILUS_VIEW_OTHER_LOCATIONS_ID;
344 }
345
346 static void
nautilus_places_view_iface_init(NautilusViewInterface * iface)347 nautilus_places_view_iface_init (NautilusViewInterface *iface)
348 {
349 iface->get_location = nautilus_places_view_get_location;
350 iface->set_location = nautilus_places_view_set_location;
351 iface->get_selection = nautilus_places_view_get_selection;
352 iface->set_selection = nautilus_places_view_set_selection;
353 iface->get_search_query = nautilus_places_view_get_search_query;
354 iface->set_search_query = nautilus_places_view_set_search_query;
355 iface->get_toolbar_menu_sections = nautilus_places_view_get_toolbar_menu_sections;
356 iface->is_loading = nautilus_places_view_is_loading;
357 iface->is_searching = nautilus_places_view_is_searching;
358 iface->get_view_id = nautilus_places_view_get_view_id;
359 }
360
361 static void
nautilus_places_view_class_init(NautilusPlacesViewClass * klass)362 nautilus_places_view_class_init (NautilusPlacesViewClass *klass)
363 {
364 GObjectClass *object_class = G_OBJECT_CLASS (klass);
365
366 object_class->finalize = nautilus_places_view_finalize;
367 object_class->get_property = nautilus_places_view_get_property;
368 object_class->set_property = nautilus_places_view_set_property;
369
370 g_object_class_override_property (object_class, PROP_LOADING, "loading");
371 g_object_class_override_property (object_class, PROP_SEARCHING, "searching");
372 g_object_class_override_property (object_class, PROP_LOCATION, "location");
373 g_object_class_override_property (object_class, PROP_SELECTION, "selection");
374 g_object_class_override_property (object_class, PROP_SEARCH_QUERY, "search-query");
375 g_object_class_override_property (object_class,
376 PROP_EXTENSIONS_BACKGROUND_MENU,
377 "extensions-background-menu");
378 g_object_class_override_property (object_class,
379 PROP_TEMPLATES_MENU,
380 "templates-menu");
381 }
382
383 static void
nautilus_places_view_init(NautilusPlacesView * self)384 nautilus_places_view_init (NautilusPlacesView *self)
385 {
386 NautilusPlacesViewPrivate *priv;
387
388 priv = nautilus_places_view_get_instance_private (self);
389
390 /* Location */
391 priv->location = g_file_new_for_uri ("other-locations:///");
392
393 /* Places view */
394 priv->places_view = nautilus_gtk_places_view_new ();
395 nautilus_gtk_places_view_set_open_flags (NAUTILUS_GTK_PLACES_VIEW (priv->places_view),
396 GTK_PLACES_OPEN_NEW_TAB | GTK_PLACES_OPEN_NEW_WINDOW | GTK_PLACES_OPEN_NORMAL);
397 gtk_widget_set_hexpand (priv->places_view, TRUE);
398 gtk_widget_set_vexpand (priv->places_view, TRUE);
399 gtk_widget_show (priv->places_view);
400 gtk_container_add (GTK_CONTAINER (self), priv->places_view);
401
402 g_signal_connect_swapped (priv->places_view,
403 "notify::loading",
404 G_CALLBACK (loading_cb),
405 self);
406
407 g_signal_connect_swapped (priv->places_view,
408 "open-location",
409 G_CALLBACK (open_location_cb),
410 self);
411
412 g_signal_connect_swapped (priv->places_view,
413 "show-error-message",
414 G_CALLBACK (show_error_message_cb),
415 self);
416
417 /* Toolbar menu */
418 priv->toolbar_menu_sections = g_new0 (NautilusToolbarMenuSections, 1);
419 priv->toolbar_menu_sections->supports_undo_redo = FALSE;
420 }
421
422 NautilusPlacesView *
nautilus_places_view_new(void)423 nautilus_places_view_new (void)
424 {
425 NautilusPlacesView *view;
426
427 view = g_object_new (NAUTILUS_TYPE_PLACES_VIEW, NULL);
428 if (g_object_is_floating (view))
429 {
430 g_object_ref_sink (view);
431 }
432
433 return view;
434 }
435