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