No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2008 Red Hat, Inc.
4 * Copyright (C) 2006 Paolo Borelli <pborelli@katamail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Authors: David Zeuthen <davidz@redhat.com>
21 * Paolo Borelli <pborelli@katamail.com>
22 *
23 */
24
25 #include "config.h"
26
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <string.h>
30
31 #include "nautilus-x-content-bar.h"
32 #include <libnautilus-private/nautilus-icon-info.h>
33 #include <libnautilus-private/nautilus-program-choosing.h>
34
35 #define NAUTILUS_X_CONTENT_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NAUTILUS_TYPE_X_CONTENT_BAR, NautilusXContentBarPrivate))
36
37 struct NautilusXContentBarPrivate
38 {
39 GtkWidget *label;
40
41 char **x_content_types;
42 GMount *mount;
43 };
44
45 enum {
46 PROP_0,
47 PROP_MOUNT,
48 PROP_X_CONTENT_TYPES,
49 };
50
51 enum {
52 CONTENT_BAR_RESPONSE_APP = 1
53 };
54
55 G_DEFINE_TYPE (NautilusXContentBar, nautilus_x_content_bar, GTK_TYPE_INFO_BAR)
56
57 static void
58 content_bar_response_cb (GtkInfoBar *infobar,
59 gint response_id,
60 gpointer user_data)
61 {
62 GAppInfo *default_app;
63 NautilusXContentBar *bar = user_data;
64
65 if (response_id < 0) {
66 return;
67 }
68
69 if (bar->priv->x_content_types == NULL ||
70 bar->priv->mount == NULL)
71 return;
72
73 /* FIXME */
74 default_app = g_app_info_get_default_for_type (bar->priv->x_content_types[response_id], FALSE);
75 if (default_app != NULL) {
76 nautilus_launch_application_for_mount (default_app, bar->priv->mount,
77 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (bar))));
78 g_object_unref (default_app);
79 }
80 }
81
82 static char *
83 get_message_for_x_content_type (const char *x_content_type)
84 {
85 char *message;
86 char *description;
87
88 description = g_content_type_get_description (x_content_type);
89
90 /* Customize greeting for well-known x-content types */
91 /* translators: these describe the contents of removable media */
92 if (strcmp (x_content_type, "x-content/audio-cdda") == 0) {
93 message = g_strdup (_("Audio CD"));
94 } else if (strcmp (x_content_type, "x-content/audio-dvd") == 0) {
95 message = g_strdup (_("Audio DVD"));
96 } else if (strcmp (x_content_type, "x-content/video-dvd") == 0) {
97 message = g_strdup (_("Video DVD"));
98 } else if (strcmp (x_content_type, "x-content/video-vcd") == 0) {
99 message = g_strdup (_("Video CD"));
100 } else if (strcmp (x_content_type, "x-content/video-svcd") == 0) {
101 message = g_strdup (_("Super Video CD"));
102 } else if (strcmp (x_content_type, "x-content/image-photocd") == 0) {
103 message = g_strdup (_("Photo CD"));
104 } else if (strcmp (x_content_type, "x-content/image-picturecd") == 0) {
105 message = g_strdup (_("Picture CD"));
106 } else if (strcmp (x_content_type, "x-content/image-dcf") == 0) {
107 message = g_strdup (_("Contains digital photos"));
108 } else if (strcmp (x_content_type, "x-content/audio-player") == 0) {
109 message = g_strdup (_("Contains music"));
110 } else if (strcmp (x_content_type, "x-content/unix-software") == 0) {
111 message = g_strdup (_("Contains software"));
112 } else {
113 /* fallback to generic greeting */
114 message = g_strdup_printf (_("Detected as â%sâ"), description);
115 }
116
117 g_free (description);
118
119 return message;
120 }
121
122 static char *
123 get_message_for_two_x_content_types (char **x_content_types)
124 {
125 char *message;
126
127 g_assert (x_content_types[0] != NULL);
128 g_assert (x_content_types[1] != NULL);
129
130 /* few combinations make sense */
131 if (strcmp (x_content_types[0], "x-content/image-dcf") == 0
132 || strcmp (x_content_types[1], "x-content/image-dcf") == 0) {
133
134 /* translators: these describe the contents of removable media */
135 if (strcmp (x_content_types[0], "x-content/audio-player") == 0) {
136 message = g_strdup (_("Contains music and photos"));
137 } else if (strcmp (x_content_types[1], "x-content/audio-player") == 0) {
138 message = g_strdup (_("Contains photos and music"));
139 } else {
140 message = g_strdup (_("Contains digital photos"));
141 }
142 } else {
143 message = get_message_for_x_content_type (x_content_types[0]);
144 }
145
146 return message;
147 }
148
149 static void
150 nautilus_x_content_bar_set_x_content_types (NautilusXContentBar *bar, const char **x_content_types)
151 {
152 char *message = NULL;
153 guint num_types;
154 guint n;
155 GPtrArray *types;
156 GPtrArray *apps;
157 GAppInfo *default_app;
158
159 g_strfreev (bar->priv->x_content_types);
160
161 types = g_ptr_array_new ();
162 apps = g_ptr_array_new ();
163 g_ptr_array_set_free_func (apps, g_object_unref);
164 for (n = 0; x_content_types[n] != NULL; n++) {
165 if (g_str_has_prefix (x_content_types[n], "x-content/blank-"))
166 continue;
167
168 if (g_content_type_is_a (x_content_types[n], "x-content/win32-software"))
169 continue;
170
171 default_app = g_app_info_get_default_for_type (x_content_types[n], FALSE);
172 if (default_app == NULL)
173 continue;
174
175 g_ptr_array_add (types, g_strdup (x_content_types[n]));
176 g_ptr_array_add (apps, default_app);
177 }
178
179 num_types = types->len;
180 g_ptr_array_add (types, NULL);
181
182 bar->priv->x_content_types = (char **) g_ptr_array_free (types, FALSE);
183
184 switch (num_types) {
185 case 0:
186 message = NULL;
187 break;
188 case 1:
189 message = get_message_for_x_content_type (bar->priv->x_content_types[0]);
190 break;
191 case 2:
192 message = get_message_for_two_x_content_types (bar->priv->x_content_types);
193 break;
194 default:
195 message = g_strdup (_("Open with:"));
196 break;
197 }
198
199 if (message == NULL) {
200 g_ptr_array_free (apps, TRUE);
201 gtk_widget_destroy (GTK_WIDGET (bar));
202 return;
203 }
204
205 gtk_label_set_text (GTK_LABEL (bar->priv->label), message);
206 g_free (message);
207
208 gtk_widget_show (bar->priv->label);
209
210 for (n = 0; bar->priv->x_content_types[n] != NULL; n++) {
211 const char *name;
212 GIcon *icon;
213 GtkWidget *image;
214 GtkWidget *button;
215
216 /* TODO: We really need a GtkBrowserBackButton-ish widget here.. until then, we only
217 * show the default application. */
218
219 default_app = g_ptr_array_index (apps, n);
220 icon = g_app_info_get_icon (default_app);
221 if (icon != NULL) {
222 image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
223 } else {
224 image = NULL;
225 }
226
227 name = g_app_info_get_name (default_app);
228 button = gtk_info_bar_add_button (GTK_INFO_BAR (bar),
229 name,
230 n);
231
232 gtk_button_set_image (GTK_BUTTON (button), image);
233 gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE);
234 gtk_button_set_label (GTK_BUTTON (button), name);
235 gtk_widget_show (button);
236 }
237
238 g_ptr_array_free (apps, TRUE);
239 }
240
241 static void
242 nautilus_x_content_bar_set_mount (NautilusXContentBar *bar, GMount *mount)
243 {
244 if (bar->priv->mount != NULL) {
245 g_object_unref (bar->priv->mount);
246 }
247 bar->priv->mount = mount != NULL ? g_object_ref (mount) : NULL;
248 }
249
250
251 static void
252 nautilus_x_content_bar_set_property (GObject *object,
253 guint prop_id,
254 const GValue *value,
255 GParamSpec *pspec)
256 {
257 NautilusXContentBar *bar;
258
259 bar = NAUTILUS_X_CONTENT_BAR (object);
260
261 switch (prop_id) {
262 case PROP_MOUNT:
263 nautilus_x_content_bar_set_mount (bar, G_MOUNT (g_value_get_object (value)));
264 break;
265 case PROP_X_CONTENT_TYPES:
266 nautilus_x_content_bar_set_x_content_types (bar, g_value_get_boxed (value));
267 break;
268 default:
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270 break;
271 }
272 }
273
274 static void
275 nautilus_x_content_bar_get_property (GObject *object,
276 guint prop_id,
277 GValue *value,
278 GParamSpec *pspec)
279 {
280 NautilusXContentBar *bar;
281
282 bar = NAUTILUS_X_CONTENT_BAR (object);
283
284 switch (prop_id) {
285 case PROP_MOUNT:
286 g_value_set_object (value, bar->priv->mount);
287 break;
288 case PROP_X_CONTENT_TYPES:
289 g_value_set_boxed (value, &bar->priv->x_content_types);
290 break;
291 default:
292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293 break;
294 }
295 }
296
297 static void
298 nautilus_x_content_bar_finalize (GObject *object)
299 {
300 NautilusXContentBar *bar = NAUTILUS_X_CONTENT_BAR (object);
301
302 g_strfreev (bar->priv->x_content_types);
303 if (bar->priv->mount != NULL)
304 g_object_unref (bar->priv->mount);
305
306 G_OBJECT_CLASS (nautilus_x_content_bar_parent_class)->finalize (object);
307 }
308
309 static void
310 nautilus_x_content_bar_class_init (NautilusXContentBarClass *klass)
311 {
312 GObjectClass *object_class;
313
314 object_class = G_OBJECT_CLASS (klass);
315 object_class->get_property = nautilus_x_content_bar_get_property;
316 object_class->set_property = nautilus_x_content_bar_set_property;
317 object_class->finalize = nautilus_x_content_bar_finalize;
318
319 g_type_class_add_private (klass, sizeof (NautilusXContentBarPrivate));
320
321 g_object_class_install_property (object_class,
322 PROP_MOUNT,
323 g_param_spec_object (
324 "mount",
325 "The GMount to run programs for",
326 "The GMount to run programs for",
327 G_TYPE_MOUNT,
328 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
329
330 g_object_class_install_property (object_class,
331 PROP_X_CONTENT_TYPES,
332 g_param_spec_boxed ("x-content-types",
333 "The x-content types for the cluebar",
334 "The x-content types for the cluebar",
335 G_TYPE_STRV,
336 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
337 }
338
339 static void
340 nautilus_x_content_bar_init (NautilusXContentBar *bar)
341 {
342 GtkWidget *content_area;
343 GtkWidget *action_area;
344 PangoAttrList *attrs;
345
346 bar->priv = NAUTILUS_X_CONTENT_BAR_GET_PRIVATE (bar);
347 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (bar));
348 action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (bar));
349
350 gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), GTK_ORIENTATION_HORIZONTAL);
351
352 attrs = pango_attr_list_new ();
353 pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
354 bar->priv->label = gtk_label_new (NULL);
355 gtk_label_set_attributes (GTK_LABEL (bar->priv->label), attrs);
356 pango_attr_list_unref (attrs);
357
358 gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_END);
359 gtk_container_add (GTK_CONTAINER (content_area), bar->priv->label);
360
361 g_signal_connect (bar, "response",
362 G_CALLBACK (content_bar_response_cb),
363 bar);
364 }
365
366 GtkWidget *
367 nautilus_x_content_bar_new (GMount *mount,
368 const char **x_content_types)
369 {
370 return g_object_new (NAUTILUS_TYPE_X_CONTENT_BAR,
371 "message-type", GTK_MESSAGE_QUESTION,
372 "mount", mount,
373 "x-content-types", x_content_types,
374 NULL);
375 }