src/mn-file-chooser-button.gob (7313B) - raw
1 /*
2 * MNFileChooserButton - a non-broken partial reimplementation of
3 * GtkFileChooserButton (GtkFileChooserButton is unusable, see
4 * http://bugzilla.gnome.org/show_bug.cgi?id=327243)
5 *
6 * Based on GtkFileChooserButton,
7 * Copyright (c) 2004 James M. Cape <jcape@ignore-your.tv>
8 *
9 * Mail Notification
10 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 %headertop{
28 #include <gtk/gtk.h>
29 %}
30
31 %h{
32 typedef GtkFileChooserDialog *(*MNFileChooserButtonCreateDialogFunction) (gpointer data);
33 %}
34
35 %privateheader{
36 #include <libgnomevfs/gnome-vfs.h>
37 %}
38
39 %{
40 #include <glib/gi18n.h>
41 #include <gnome.h>
42 #include "mn-util.h"
43 %}
44
45 class MN:File:Chooser:Button from Gtk:HBox
46 {
47 private char *filename destroywith g_free;
48 property STRING filename (export)
49 get
50 {
51 g_value_set_string(VAL, selfp->filename);
52 }
53 set
54 {
55 g_free(selfp->filename);
56 selfp->filename = g_value_dup_string(VAL);
57
58 self_update(self);
59
60 if (selfp->dialog)
61 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(selfp->dialog), selfp->filename);
62 };
63
64 private MNFileChooserButtonCreateDialogFunction create_dialog;
65 private gpointer create_dialog_data;
66
67 private GtkWidget *image;
68 private GtkWidget *label;
69 private GtkWidget *dialog unrefwith gtk_widget_destroy;
70
71 private GnomeVFSAsyncHandle *async_handle unrefwith gnome_vfs_async_cancel;
72
73 init (self)
74 {
75 GtkWidget *button;
76 GtkWidget *box;
77 GtkWidget *separator;
78 GtkWidget *image;
79
80 button = gtk_button_new();
81 gtk_container_add(GTK_CONTAINER(self), button);
82 gtk_widget_show(button);
83
84 box = gtk_hbox_new(FALSE, 4);
85 gtk_container_add(GTK_CONTAINER(button), box);
86 gtk_widget_show(box);
87
88 selfp->image = gtk_image_new();
89 gtk_box_pack_start(GTK_BOX(box), selfp->image, FALSE, FALSE, 0);
90 gtk_widget_show(selfp->image);
91
92 selfp->label = gtk_label_new(NULL);
93 gtk_label_set_ellipsize(GTK_LABEL(selfp->label), PANGO_ELLIPSIZE_END);
94 gtk_misc_set_alignment(GTK_MISC(selfp->label), 0.0, 0.5);
95 gtk_container_add(GTK_CONTAINER(box), selfp->label);
96 gtk_widget_show(selfp->label);
97
98 separator = gtk_vseparator_new();
99 gtk_box_pack_start(GTK_BOX(box), separator, FALSE, FALSE, 0);
100 gtk_widget_show(separator);
101
102 image = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
103 gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
104 gtk_widget_show(image);
105
106 g_signal_connect(button, "clicked", G_CALLBACK(self_clicked_h), self);
107
108 self_update(self);
109 }
110
111 private void
112 clicked_h (GtkButton *button, gpointer data)
113 {
114 Self *self = data;
115
116 if (! selfp->dialog)
117 {
118 /* translators: header capitalization */
119 selfp->dialog = GTK_WIDGET(selfp->create_dialog(selfp->create_dialog_data));
120 g_assert(GTK_IS_FILE_CHOOSER_DIALOG(selfp->dialog));
121
122 mn_add_weak_pointer(&selfp->dialog);
123
124 if (selfp->filename)
125 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(selfp->dialog), selfp->filename);
126
127 g_signal_connect(selfp->dialog, "response", G_CALLBACK(self_response_h), self);
128 }
129
130 if (! GTK_WIDGET_VISIBLE(selfp->dialog))
131 {
132 GtkWindow *parent;
133
134 parent = mn_widget_get_parent_window(GTK_WIDGET(self));
135 if (parent)
136 {
137 if (parent != gtk_window_get_transient_for(GTK_WINDOW(selfp->dialog)))
138 gtk_window_set_transient_for(GTK_WINDOW(selfp->dialog), parent);
139
140 gtk_window_set_modal(GTK_WINDOW(selfp->dialog), gtk_window_get_modal(parent));
141 }
142 }
143
144 mn_window_present_from_event(GTK_WINDOW(selfp->dialog));
145 }
146
147 private void
148 update (self)
149 {
150 GnomeVFSURI *uri = NULL;
151
152 if (selfp->async_handle)
153 {
154 gnome_vfs_async_cancel(selfp->async_handle);
155 selfp->async_handle = NULL;
156 }
157
158 if (selfp->filename && *selfp->filename)
159 {
160 char *text_uri;
161 char *base;
162
163 base = g_path_get_basename(selfp->filename);
164 gtk_label_set_text(GTK_LABEL(selfp->label), base);
165 g_free(base);
166
167 text_uri = gnome_vfs_get_uri_from_local_path(selfp->filename);
168 if (text_uri)
169 {
170 uri = gnome_vfs_uri_new(text_uri);
171 g_free(text_uri);
172 }
173 }
174 else
175 /*
176 * translators: GTK+ has the same message used in the same
177 * context; please use the GTK+ translation for consistency
178 */
179 gtk_label_set_text(GTK_LABEL(selfp->label), _("(None)"));
180
181 /*
182 * Do not use MN_STOCK_UNKNOWN: we want to appear exactly as a
183 * GtkFileChooserButton.
184 */
185 gtk_image_set_from_icon_name(GTK_IMAGE(selfp->image), "stock_unknown", GTK_ICON_SIZE_MENU);
186
187 if (uri)
188 {
189 GList *uri_list = NULL;
190
191 uri_list = g_list_append(uri_list, uri);
192
193 g_object_ref(self);
194 gnome_vfs_async_get_file_info(&selfp->async_handle,
195 uri_list,
196 GNOME_VFS_FILE_INFO_GET_MIME_TYPE
197 | GNOME_VFS_FILE_INFO_FOLLOW_LINKS,
198 GNOME_VFS_PRIORITY_DEFAULT,
199 self_get_file_info_cb,
200 self);
201
202 gnome_vfs_uri_unref(uri);
203 g_list_free(uri_list);
204 }
205 }
206
207 private void
208 get_file_info_cb (GnomeVFSAsyncHandle *handle, GList *results, gpointer data)
209 {
210 Self *self = data;
211
212 GDK_THREADS_ENTER();
213
214 if (results)
215 {
216 GnomeVFSGetFileInfoResult *result = results->data;
217
218 if (result->result == GNOME_VFS_OK
219 && (result->file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0)
220 {
221 char *uri;
222 char *icon_name;
223
224 uri = gnome_vfs_get_uri_from_local_path(selfp->filename);
225 g_assert(uri != NULL);
226
227 icon_name = gnome_icon_lookup(gtk_icon_theme_get_default(),
228 NULL,
229 uri,
230 NULL,
231 result->file_info,
232 result->file_info->mime_type,
233 GNOME_ICON_LOOKUP_FLAGS_NONE,
234 NULL);
235
236 g_free(uri);
237
238 if (icon_name)
239 {
240 gtk_image_set_from_icon_name(GTK_IMAGE(selfp->image), icon_name, GTK_ICON_SIZE_MENU);
241 g_free(icon_name);
242 }
243 }
244 }
245
246 selfp->async_handle = NULL;
247 g_object_unref(self);
248
249 /* do not call gdk_flush(), we're normally in the main thread */
250 GDK_THREADS_LEAVE();
251 }
252
253 private void
254 response_h (GtkDialog *dialog, int response, gpointer user_data)
255 {
256 Self *self = user_data;
257
258 if (response == GTK_RESPONSE_ACCEPT)
259 {
260 char *filename;
261
262 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
263 self_set_filename(self, filename);
264 g_free(filename);
265 }
266
267 gtk_widget_destroy(GTK_WIDGET(dialog));
268 }
269
270 public GtkWidget *
271 new (MNFileChooserButtonCreateDialogFunction create_dialog (check null),
272 gpointer data)
273 {
274 Self *self = GET_NEW;
275
276 selfp->create_dialog = create_dialog;
277 selfp->create_dialog_data = data;
278
279 return GTK_WIDGET(self);
280 }
281 }