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 }