1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
4 *
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8 *
9 * Nautilus-Actions is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * Nautilus-Actions is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Nautilus-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 * Authors:
24 * Frederic Ruaudel <grumz@grumz.net>
25 * Rodrigo Moya <rodrigo@gnome-db.org>
26 * Pierre Wieser <pwieser@trychlos.org>
27 * ... and many others (see AUTHORS)
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
36 #include <string.h>
37
38 #include "na-exporter.h"
39 #include "na-export-format.h"
40 #include "na-settings.h"
41
42 typedef struct {
43 const gchar *format; /* export format saved in user's preferences */
44 const gchar *label; /* short label */
45 const gchar *description; /* full description */
46 const gchar *image; /* associated image */
47 }
48 NAExporterFormatStr;
49
50 static NAExporterFormatStr st_format_ask = {
51
52 EXPORTER_FORMAT_ASK,
53 N_( "_Ask me" ),
54 N_( "You will be asked for the format to choose each time an item " \
55 "is about to be exported." ),
56 "export-format-ask.png"
57 };
58
59 /* i18n: NAIExporter is an interface name, do not even try to translate */
60 #define NO_IMPLEMENTATION_MSG N_( "No NAIExporter implementation found for '%s' format." )
61
62 static GList *exporter_get_formats( const NAIExporter *exporter );
63 static void exporter_free_formats( const NAIExporter *exporter, GList * str_list );
64 static gchar *exporter_get_name( const NAIExporter *exporter );
65 static void on_pixbuf_finalized( gpointer user_data, GObject *pixbuf );
66
67 /*
68 * na_exporter_get_formats:
69 * @pivot: the #NAPivot instance.
70 *
71 * Returns: a list of #NAExportFormat objects, each of them addressing an
72 * available export format, i.e. a format provided by a module which
73 * implement the #NAIExporter interface.
74 *
75 * The returned list should later be na_exporter_free_formats() by the caller.
76 */
77 GList *
na_exporter_get_formats(const NAPivot * pivot)78 na_exporter_get_formats( const NAPivot *pivot )
79 {
80 GList *iexporters, *imod;
81 GList *formats;
82 GList *str_list, *is;
83 NAExportFormat *format;
84
85 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
86
87 formats = NULL;
88 iexporters = na_pivot_get_providers( pivot, NA_TYPE_IEXPORTER );
89
90 for( imod = iexporters ; imod ; imod = imod->next ){
91 str_list = exporter_get_formats( NA_IEXPORTER( imod->data ));
92
93 for( is = str_list ; is ; is = is->next ){
94 format = na_export_format_new(( NAIExporterFormatv2 * ) is->data );
95 formats = g_list_prepend( formats, format );
96 }
97
98 exporter_free_formats( NA_IEXPORTER( imod->data ), str_list );
99 }
100
101 na_pivot_free_providers( iexporters );
102
103 return( formats );
104 }
105
106 /*
107 * Returns a GList of NAIExporterFormatv2 structures which describes
108 * the export formats provided by the exporter
109 * If the provider only implements the v1 interface, we dynamically
110 * allocate a new structure and convert the v1 to the v2.
111 */
112 static GList *
exporter_get_formats(const NAIExporter * exporter)113 exporter_get_formats( const NAIExporter *exporter )
114 {
115 GList *str_list;
116 guint version;
117
118 str_list = NULL;
119
120 version = 1;
121 if( NA_IEXPORTER_GET_INTERFACE( exporter )->get_version ){
122 version = NA_IEXPORTER_GET_INTERFACE( exporter )->get_version( exporter );
123 }
124
125 if( NA_IEXPORTER_GET_INTERFACE( exporter )->get_formats ){
126 if( version == 1 ){
127 #ifdef NA_ENABLE_DEPRECATED
128 const NAIExporterFormat *strv1;
129 strv1 = NA_IEXPORTER_GET_INTERFACE( exporter )->get_formats( exporter );
130 while( strv1->format ){
131 NAIExporterFormatv2 *strv2 = g_new0( NAIExporterFormatv2, 1 );
132 strv2->version = 2;
133 strv2->provider = ( NAIExporter * ) exporter;
134 strv2->format = strv1->format;
135 strv2->label = strv1->label;
136 strv2->description = strv1->description;
137 strv2->pixbuf = NULL;
138 str_list = g_list_prepend( str_list, strv2 );
139 strv1++;
140 }
141 #else
142 ;
143 #endif
144 } else {
145 str_list = NA_IEXPORTER_GET_INTERFACE( exporter )->get_formats( exporter );
146 }
147 }
148
149 return( str_list );
150 }
151
152 /*
153 * Free the list returned by exporter_get_formats() for this provider
154 */
155 static void
exporter_free_formats(const NAIExporter * exporter,GList * str_list)156 exporter_free_formats( const NAIExporter *exporter, GList *str_list )
157 {
158 guint version;
159
160 version = 1;
161 if( NA_IEXPORTER_GET_INTERFACE( exporter )->get_version ){
162 version = NA_IEXPORTER_GET_INTERFACE( exporter )->get_version( exporter );
163 }
164
165 if( version == 1 ){
166 g_list_foreach( str_list, ( GFunc ) g_free, NULL );
167 g_list_free( str_list );
168
169 } else {
170 g_return_if_fail( NA_IEXPORTER_GET_INTERFACE( exporter )->free_formats );
171 NA_IEXPORTER_GET_INTERFACE( exporter )->free_formats( exporter, str_list );
172 }
173 }
174
175 /*
176 * na_exporter_free_formats:
177 * @formats: a list of available export formats, as returned by
178 * na_exporter_get_formats().
179 *
180 * Release the @formats #GList.
181 */
182 void
na_exporter_free_formats(GList * formats)183 na_exporter_free_formats( GList *formats )
184 {
185 static const gchar *thisfn = "na_exporter_free_formats";
186
187 g_debug( "%s: formats=%p (count=%d)", thisfn, ( void * ) formats, g_list_length( formats ));
188
189 g_list_foreach( formats, ( GFunc ) g_object_unref, NULL );
190 g_list_free( formats );
191 }
192
193 /*
194 * na_exporter_get_ask_option:
195 *
196 * Returns the 'Ask me' option.
197 *
198 * Since: 3.2
199 */
200 NAIOption *
na_exporter_get_ask_option(void)201 na_exporter_get_ask_option( void )
202 {
203 static const gchar *thisfn = "na_exporter_get_ask_option";
204 NAIExporterFormatv2 *str;
205 gint width, height;
206 gchar *fname;
207 NAExportFormat *format;
208
209 if( !gtk_icon_size_lookup( GTK_ICON_SIZE_DIALOG, &width, &height )){
210 width = height = 48;
211 }
212
213 str = g_new0( NAIExporterFormatv2, 1 );
214 str->version = 2;
215 str->provider = NULL;
216 str->format = g_strdup( st_format_ask.format );
217 str->label = g_strdup( gettext( st_format_ask.label ));
218 str->description = g_strdup( gettext( st_format_ask.description ));
219 if( st_format_ask.image ){
220 fname = g_strdup_printf( "%s/%s", PKGEXPORTFORMATDIR, st_format_ask.image );
221 str->pixbuf = gdk_pixbuf_new_from_file_at_size( fname, width, height, NULL );
222 g_free( fname );
223 if( str->pixbuf ){
224 g_debug( "%s: allocating pixbuf at %p", thisfn, str->pixbuf );
225 g_object_weak_ref( G_OBJECT( str->pixbuf ), ( GWeakNotify ) on_pixbuf_finalized, NULL );
226 }
227 }
228
229 format = na_export_format_new( str );
230
231 if( str->pixbuf ){
232 g_object_unref( str->pixbuf );
233 }
234 g_free( str->description );
235 g_free( str->label );
236 g_free( str->format );
237 g_free( str );
238
239 return( NA_IOPTION( format ));
240 }
241
242 static void
on_pixbuf_finalized(gpointer user_data,GObject * pixbuf)243 on_pixbuf_finalized( gpointer user_data /* ==NULL */, GObject *pixbuf )
244 {
245 g_debug( "na_exporter_on_pixbuf_finalized: pixbuf=%p", ( void * ) pixbuf );
246 }
247
248 /*
249 * na_exporter_to_buffer:
250 * @pivot: the #NAPivot pivot for the running application.
251 * @item: a #NAObjectItem-derived object.
252 * @format: the target format identifier.
253 * @messages: a pointer to a #GSList list of strings; the provider
254 * may append messages to this list, but shouldn't reinitialize it.
255 *
256 * Exports the specified @item in the required @format.
257 *
258 * Returns: the output buffer, as a newly allocated string which should
259 * be g_free() by the caller, or %NULL if an error has been detected.
260 */
261 gchar *
na_exporter_to_buffer(const NAPivot * pivot,const NAObjectItem * item,const gchar * format,GSList ** messages)262 na_exporter_to_buffer( const NAPivot *pivot,
263 const NAObjectItem *item, const gchar *format, GSList **messages )
264 {
265 static const gchar *thisfn = "na_exporter_to_buffer";
266 gchar *buffer;
267 NAIExporterBufferParmsv2 parms;
268 NAIExporter *exporter;
269 gchar *name;
270 gchar *msg;
271
272 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
273 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
274
275 buffer = NULL;
276
277 g_debug( "%s: pivot=%p, item=%p (%s), format=%s, messages=%p",
278 thisfn,
279 ( void * ) pivot,
280 ( void * ) item, G_OBJECT_TYPE_NAME( item ),
281 format,
282 ( void * ) messages );
283
284 exporter = na_exporter_find_for_format( pivot, format );
285 g_debug( "%s: exporter=%p (%s)", thisfn, ( void * ) exporter, G_OBJECT_TYPE_NAME( exporter ));
286
287 if( exporter ){
288 parms.version = 2;
289 parms.exported = ( NAObjectItem * ) item;
290 parms.format = g_strdup( format );
291 parms.buffer = NULL;
292 parms.messages = messages ? *messages : NULL;
293
294 if( NA_IEXPORTER_GET_INTERFACE( exporter )->to_buffer ){
295 NA_IEXPORTER_GET_INTERFACE( exporter )->to_buffer( exporter, &parms );
296
297 if( parms.buffer ){
298 buffer = parms.buffer;
299 }
300
301 } else {
302 name = exporter_get_name( exporter );
303 /* i18n: NAIExporter is an interface name, do not even try to translate */
304 msg = g_strdup_printf( _( "%s NAIExporter doesn't implement 'to_buffer' interface." ), name );
305 *messages = g_slist_append( *messages, msg );
306 g_free( name );
307 }
308
309 g_free( parms.format );
310
311 } else {
312 msg = g_strdup_printf( NO_IMPLEMENTATION_MSG, format );
313 *messages = g_slist_append( *messages, msg );
314 }
315
316 return( buffer );
317 }
318
319 /*
320 * na_exporter_to_file:
321 * @pivot: the #NAPivot pivot for the running application.
322 * @item: a #NAObjectItem-derived object.
323 * @folder_uri: the URI of the target folder.
324 * @format: the target format identifier.
325 * @messages: a pointer to a #GSList list of strings; the provider
326 * may append messages to this list, but shouldn't reinitialize it.
327 *
328 * Exports the specified @item to the target @uri in the required @format.
329 *
330 * Returns: the URI of the exported file, as a newly allocated string which
331 * should be g_free() by the caller, or %NULL if an error has been detected.
332 */
333 gchar *
na_exporter_to_file(const NAPivot * pivot,const NAObjectItem * item,const gchar * folder_uri,const gchar * format,GSList ** messages)334 na_exporter_to_file( const NAPivot *pivot,
335 const NAObjectItem *item, const gchar *folder_uri, const gchar *format, GSList **messages )
336 {
337 static const gchar *thisfn = "na_exporter_to_file";
338 gchar *export_uri;
339 NAIExporterFileParmsv2 parms;
340 NAIExporter *exporter;
341 gchar *msg;
342 gchar *name;
343
344 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
345 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
346
347 export_uri = NULL;
348
349 g_debug( "%s: pivot=%p, item=%p (%s), folder_uri=%s, format=%s, messages=%p",
350 thisfn,
351 ( void * ) pivot,
352 ( void * ) item, G_OBJECT_TYPE_NAME( item ),
353 folder_uri,
354 format,
355 ( void * ) messages );
356
357 exporter = na_exporter_find_for_format( pivot, format );
358
359 if( exporter ){
360 parms.version = 2;
361 parms.exported = ( NAObjectItem * ) item;
362 parms.folder = ( gchar * ) folder_uri;
363 parms.format = g_strdup( format );
364 parms.basename = NULL;
365 parms.messages = messages ? *messages : NULL;
366
367 if( NA_IEXPORTER_GET_INTERFACE( exporter )->to_file ){
368 NA_IEXPORTER_GET_INTERFACE( exporter )->to_file( exporter, &parms );
369
370 if( parms.basename ){
371 export_uri = g_strdup_printf( "%s%s%s", folder_uri, G_DIR_SEPARATOR_S, parms.basename );
372 }
373
374 } else {
375 name = exporter_get_name( exporter );
376 /* i18n: NAIExporter is an interface name, do not even try to translate */
377 msg = g_strdup_printf( _( "%s NAIExporter doesn't implement 'to_file' interface." ), name );
378 *messages = g_slist_append( *messages, msg );
379 g_free( name );
380 }
381
382 g_free( parms.format );
383
384 } else {
385 msg = g_strdup_printf( NO_IMPLEMENTATION_MSG, format );
386 *messages = g_slist_append( *messages, msg );
387 }
388
389 return( export_uri );
390 }
391
392 static gchar *
exporter_get_name(const NAIExporter * exporter)393 exporter_get_name( const NAIExporter *exporter )
394 {
395 gchar *name;
396
397 name = NULL;
398
399 if( NA_IEXPORTER_GET_INTERFACE( exporter )->get_name ){
400 name = NA_IEXPORTER_GET_INTERFACE( exporter )->get_name( exporter );
401 }
402
403 return( name );
404 }
405
406 /**
407 * na_exporter_find_for_format:
408 * @pivot: the #NAPivot instance.
409 * @format: the string identifier of the searched format.
410 *
411 * Returns: the #NAIExporter instance which provides the @format export
412 * format. The returned instance is owned by @pivot, and should not be
413 * released by the caller.
414 */
415 NAIExporter *
na_exporter_find_for_format(const NAPivot * pivot,const gchar * format)416 na_exporter_find_for_format( const NAPivot *pivot, const gchar *format )
417 {
418 NAIExporter *exporter;
419 GList *formats, *ifmt;
420 gchar *id;
421 NAExportFormat *export_format;
422
423 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
424
425 exporter = NULL;
426 formats = na_exporter_get_formats( pivot );
427
428 for( ifmt = formats ; ifmt && !exporter ; ifmt = ifmt->next ){
429
430 export_format = NA_EXPORT_FORMAT( ifmt->data );
431 id = na_ioption_get_id( NA_IOPTION( export_format ));
432 if( !strcmp( id, format )){
433 exporter = na_export_format_get_provider( NA_EXPORT_FORMAT( ifmt->data ));
434 }
435 g_free( id );
436 }
437
438 na_exporter_free_formats( formats );
439
440 return( exporter );
441 }
442