Fixed typo in string
[nautilus-actions.git] / src / core / na-importer.c
blob6e39cb162f86259ae5990749249ae3363de1f134
1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011, 2012 Pierre Wieser and others (see AUTHORS)
9 * This Program 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.
14 * This Program 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
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <glib/gi18n.h>
36 #include <string.h>
38 #include <api/na-core-utils.h>
39 #include <api/na-iimporter.h>
40 #include <api/na-object-api.h>
42 #include "na-import-mode.h"
43 #include "na-importer.h"
44 #include "na-importer-ask.h"
46 typedef struct {
47 guint id; /* the import mode used in switch statement in the code */
48 const gchar *mode; /* the import mode saved in user's preferences */
49 const gchar *label; /* short label */
50 const gchar *description; /* full description */
51 gchar *image; /* associated image */
53 NAImportModeStr;
55 static NAImportModeStr st_import_modes[] = {
57 { IMPORTER_MODE_NO_IMPORT,
58 "NoImport",
59 N_( "Do _not import the item" ),
60 N_( "This used to be the historical behavior.\n" \
61 "The selected file will be marked as \"NOT OK\" in the Summary page.\n" \
62 "The existing item will not be modified." ),
63 "import-mode-no-import.png" },
65 { IMPORTER_MODE_RENUMBER,
66 "Renumber",
67 N_( "Import the item, _allocating it a new identifier" ),
68 N_( "The selected file will be imported with a slightly modified label " \
69 "indicating the renumbering.\n" \
70 "The existing item will not be modified." ),
71 "import-mode-renumber.png" },
73 { IMPORTER_MODE_OVERRIDE,
74 "Override",
75 N_( "_Override the existing item" ),
76 N_( "The item found in the selected file will silently override the " \
77 "current one which has the same identifier.\n" \
78 "Be warned: this mode may be dangerous. You will not be prompted another time." ),
79 "import-mode-override.png" },
81 { 0 }
84 static NAImportModeStr st_import_ask_mode = {
86 IMPORTER_MODE_ASK,
87 "Ask",
88 N_( "_Ask me" ),
89 N_( "You will be asked each time an imported ID already exists." ),
90 "import-mode-ask.png"
93 static NAImporterResult *import_from_uri( const NAPivot *pivot, GList *modules, const gchar *uri );
94 static void manage_import_mode( NAImporterParms *parms, GList *results, NAImporterAskUserParms *ask_parms, NAImporterResult *result );
95 static NAObjectItem *is_importing_already_exists( NAImporterParms *parms, GList *results, NAImporterResult *result );
96 static void renumber_label_item( NAObjectItem *item );
97 static guint ask_user_for_mode( const NAObjectItem *importing, const NAObjectItem *existing, NAImporterAskUserParms *parms );
98 static guint get_id_from_string( const gchar *str );
99 static NAIOption *get_mode_from_struct( const NAImportModeStr *str );
101 /* i18n: '%s' stands for the file URI */
102 #define ERR_NOT_LOADABLE _( "%s is not loadable (empty or too big or not a regular file)" )
105 * na_importer_import_from_uris:
106 * @pivot: the #NAPivot pivot for this application.
107 * @parms: a #NAImporterParms structure.
109 * Imports a list of URIs.
111 * For each URI to import, we search through the available #NAIImporter
112 * providers until the first which returns with something different from
113 * "not_willing_to" code.
115 * #parms.uris contains a list of URIs to import.
117 * Each import operation will have its corresponding newly allocated
118 * #NAImporterResult structure which will contain:
119 * - the imported URI
120 * - the #NAIImporter provider if one has been found, or %NULL
121 * - a #NAObjectItem item if import was successful, or %NULL
122 * - a list of error messages, or %NULL.
124 * Returns: a #GList of #NAImporterResult structures
125 * (was the last import operation code up to 3.2).
127 * Since: 2.30
129 GList *
130 na_importer_import_from_uris( const NAPivot *pivot, NAImporterParms *parms )
132 static const gchar *thisfn = "na_importer_import_from_uris";
133 GList *results, *ires;
134 GList *modules;
135 GSList *uri;
136 NAImporterResult *import_result;
137 NAImporterAskUserParms ask_parms;
138 gchar *mode_str;
140 g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
141 g_return_val_if_fail( parms != NULL, NULL );
143 results = NULL;
145 g_debug( "%s: pivot=%p, parms=%p", thisfn, ( void * ) pivot, ( void * ) parms );
147 /* first phase: just try to import the uris into memory
149 modules = na_pivot_get_providers( pivot, NA_TYPE_IIMPORTER );
151 for( uri = parms->uris ; uri ; uri = uri->next ){
152 import_result = import_from_uri( pivot, modules, ( const gchar * ) uri->data );
153 results = g_list_prepend( results, import_result );
156 na_pivot_free_providers( modules );
158 results = g_list_reverse( results );
160 memset( &ask_parms, '\0', sizeof( NAImporterAskUserParms ));
161 ask_parms.parent = parms->parent_toplevel;
162 ask_parms.count = 0;
163 ask_parms.keep_choice = FALSE;
164 ask_parms.pivot = pivot;
166 /* set the default import mode
168 if( !parms->preferred_mode ){
169 mode_str = na_settings_get_string( NA_IPREFS_IMPORT_PREFERRED_MODE, NULL, NULL );
170 parms->preferred_mode = get_id_from_string( mode_str );
171 g_free( mode_str );
174 /* second phase: check for their pre-existence
176 for( ires = results ; ires ; ires = ires->next ){
177 import_result = ( NAImporterResult * ) ires->data;
179 if( import_result->imported ){
180 g_return_val_if_fail( NA_IS_OBJECT_ITEM( import_result->imported ), NULL );
181 g_return_val_if_fail( NA_IS_IIMPORTER( import_result->importer ), NULL );
183 ask_parms.uri = import_result->uri;
184 manage_import_mode( parms, results, &ask_parms, import_result );
188 return( results );
192 * na_importer_free_result:
193 * @result: the #NAImporterResult structure to be released.
195 * Release the structure.
197 void
198 na_importer_free_result( NAImporterResult *result )
200 g_free( result->uri );
201 na_core_utils_slist_free( result->messages );
203 g_free( result );
207 * Each NAIImporter interface may return some messages, specially if it
208 * recognized but is not able to import the provided URI. But as long
209 * we do not have yet asked to all available interfaces, we are not sure
210 * of whether this URI is eventually importable or not.
212 * We so let each interface push its messages in the list, but be ready to
213 * only keep the messages provided by the interface which has successfully
214 * imported the item.
216 static NAImporterResult *
217 import_from_uri( const NAPivot *pivot, GList *modules, const gchar *uri )
219 NAImporterResult *result;
220 NAIImporterImportFromUriParmsv2 provider_parms;
221 GList *im;
222 guint code;
223 GSList *all_messages;
224 NAIImporter *provider;
226 result = NULL;
227 all_messages = NULL;
228 provider = NULL;
229 code = IMPORTER_CODE_NOT_WILLING_TO;
231 memset( &provider_parms, '\0', sizeof( NAIImporterImportFromUriParmsv2 ));
232 provider_parms.version = 2;
233 provider_parms.content = 1;
234 provider_parms.uri = uri;
236 for( im = modules ;
237 im && ( code == IMPORTER_CODE_NOT_WILLING_TO || code == IMPORTER_CODE_NOT_LOADABLE ) ;
238 im = im->next ){
240 code = na_iimporter_import_from_uri( NA_IIMPORTER( im->data ), &provider_parms );
242 if( code == IMPORTER_CODE_NOT_WILLING_TO ){
243 all_messages = g_slist_concat( all_messages, provider_parms.messages );
244 provider_parms.messages = NULL;
246 } else if( code == IMPORTER_CODE_NOT_LOADABLE ){
247 na_core_utils_slist_free( all_messages );
248 all_messages = NULL;
249 na_core_utils_slist_free( provider_parms.messages );
250 provider_parms.messages = NULL;
251 na_core_utils_slist_add_message( &all_messages, ERR_NOT_LOADABLE, ( const gchar * ) uri );
253 } else {
254 na_core_utils_slist_free( all_messages );
255 all_messages = provider_parms.messages;
256 provider = NA_IIMPORTER( im->data );
260 result = g_new0( NAImporterResult, 1 );
261 result->uri = g_strdup( uri );
262 result->imported = provider_parms.imported;
263 result->importer = provider;
264 result->messages = all_messages;
266 return( result );
270 * check for existence of the imported item
271 * ask for the user if needed
273 static void
274 manage_import_mode( NAImporterParms *parms, GList *results, NAImporterAskUserParms *ask_parms, NAImporterResult *result )
276 static const gchar *thisfn = "na_importer_manage_import_mode";
277 NAObjectItem *exists;
278 guint mode;
279 gchar *id;
281 exists = NULL;
282 result->exist = FALSE;
283 result->mode = parms->preferred_mode;
284 mode = 0;
286 /* if no check function is provided, then we systematically allocate
287 * a new identifier to the imported item
289 if( !parms->check_fn ){
290 renumber_label_item( result->imported );
291 na_core_utils_slist_add_message(
292 &result->messages,
293 "%s",
294 _( "Item was renumbered because the caller did not provide any check function." ));
295 result->mode = IMPORTER_MODE_RENUMBER;
297 } else {
298 exists = is_importing_already_exists( parms, results, result );
301 g_debug( "%s: exists=%p", thisfn, exists );
303 if( exists ){
304 result->exist = TRUE;
306 if( parms->preferred_mode == IMPORTER_MODE_ASK ){
307 mode = ask_user_for_mode( result->imported, exists, ask_parms );
309 } else {
310 mode = parms->preferred_mode;
314 /* mode is only set if asked mode was "ask me" and an ask function was provided
315 * or if asked mode was not "ask me"
317 if( mode ){
318 result->mode = mode;
320 switch( mode ){
321 case IMPORTER_MODE_RENUMBER:
322 renumber_label_item( result->imported );
323 if( parms->preferred_mode == IMPORTER_MODE_ASK ){
324 na_core_utils_slist_add_message(
325 &result->messages,
326 "%s",
327 _( "Item was renumbered due to user request." ));
329 break;
331 case IMPORTER_MODE_OVERRIDE:
332 if( parms->preferred_mode == IMPORTER_MODE_ASK ){
333 na_core_utils_slist_add_message(
334 &result->messages,
335 "%s",
336 _( "Existing item was overriden due to user request." ));
338 break;
340 case IMPORTER_MODE_NO_IMPORT:
341 default:
342 id = na_object_get_id( result->imported );
343 na_core_utils_slist_add_message(
344 &result->messages,
345 _( "Item %s already exists." ),
346 id );
347 if( parms->preferred_mode == IMPORTER_MODE_ASK ){
348 na_core_utils_slist_add_message(
349 &result->messages,
350 "%s",
351 _( "Import was canceled due to user request." ));
353 g_free( id );
354 g_object_unref( result->imported );
355 result->imported = NULL;
361 * First check here for duplicates inside of imported population,
362 * then delegates to the caller-provided check function the rest of work...
364 static NAObjectItem *
365 is_importing_already_exists( NAImporterParms *parms, GList *results, NAImporterResult *result )
367 static const gchar *thisfn = "na_importer_is_importing_already_exists";
368 NAObjectItem *exists;
369 GList *ip;
371 exists = NULL;
373 gchar *importing_id = na_object_get_id( result->imported );
374 g_debug( "%s: importing=%p, id=%s", thisfn, ( void * ) result->imported, importing_id );
376 /* is the importing item already in the current importation list ?
377 * (only tries previous items of the list)
379 for( ip = results ; ip && !exists && ip->data != result ; ip = ip->next ){
380 NAImporterResult *try_result = ( NAImporterResult * ) ip->data;
382 if( try_result->imported ){
383 g_return_val_if_fail( NA_IS_OBJECT_ITEM( try_result->imported ), NULL );
385 gchar *id = na_object_get_id( try_result->imported );
386 if( !strcmp( importing_id, id )){
387 exists = NA_OBJECT_ITEM( try_result->imported );
389 g_free( id );
393 g_free( importing_id );
395 /* if not found in our current importation list,
396 * then check the existence via provided function and data
398 if( !exists ){
399 exists = parms->check_fn( result->imported, parms->check_fn_data );
402 return( exists );
406 * renumber the item, and set a new label
408 static void
409 renumber_label_item( NAObjectItem *item )
411 gchar *label, *tmp;
413 na_object_set_new_id( item, NULL );
415 label = na_object_get_label( item );
417 /* i18n: the action has been renumbered during import operation */
418 tmp = g_strdup_printf( "%s %s", label, _( "(renumbered)" ));
420 na_object_set_label( item, tmp );
422 g_free( tmp );
423 g_free( label );
426 static guint
427 ask_user_for_mode( const NAObjectItem *importing, const NAObjectItem *existing, NAImporterAskUserParms *parms )
429 guint mode;
430 gchar *mode_str;
432 if( parms->count == 0 || !parms->keep_choice ){
433 mode = na_importer_ask_user( importing, existing, parms );
435 } else {
436 mode_str = na_settings_get_string( NA_IPREFS_IMPORT_ASK_USER_LAST_MODE, NULL, NULL );
437 mode = get_id_from_string( mode_str );
438 g_free( mode_str );
441 return( mode );
444 static guint
445 get_id_from_string( const gchar *str )
447 int i;
449 /* search in standard import modes
451 for( i = 0 ; st_import_modes[i].id ; ++i ){
452 if( !strcmp( st_import_modes[i].mode, str )){
453 return( st_import_modes[i].id );
457 /* else, is it ask option ?
459 if( !strcmp( st_import_ask_mode.mode, str )){
460 return( st_import_ask_mode.id );
463 return( 0 );
467 * na_importer_get_modes:
469 * Returns: the list of available import modes.
470 * This list should later be released by calling na_importer_free_modes();
472 GList *
473 na_importer_get_modes( void )
475 static const gchar *thisfn = "na_importer_get_modes";
476 GList *modes;
477 NAIOption *mode;
478 guint i;
480 g_debug( "%s", thisfn );
482 modes = NULL;
484 for( i = 0 ; st_import_modes[i].id ; ++i ){
485 mode = get_mode_from_struct( st_import_modes+i );
486 modes = g_list_prepend( modes, mode );
489 return( modes );
492 static NAIOption *
493 get_mode_from_struct( const NAImportModeStr *str )
495 NAImportMode *mode;
496 gint width, height;
497 gchar *fname;
498 GdkPixbuf *pixbuf;
500 if( !gtk_icon_size_lookup( GTK_ICON_SIZE_DIALOG, &width, &height )){
501 width = height = 48;
504 mode = na_import_mode_new( str->id );
505 pixbuf = NULL;
507 if( str->image && g_utf8_strlen( str->image, -1 )){
508 fname = g_strdup_printf( "%s/%s", PKGDATADIR, str->image );
509 pixbuf = gdk_pixbuf_new_from_file_at_size( fname, width, height, NULL );
510 g_free( fname );
512 g_object_set( G_OBJECT( mode ),
513 NA_IMPORT_PROP_MODE, str->mode,
514 NA_IMPORT_PROP_LABEL, gettext( str->label ),
515 NA_IMPORT_PROP_DESCRIPTION, gettext( str->description ),
516 NA_IMPORT_PROP_IMAGE, pixbuf,
517 NULL );
519 return( NA_IOPTION( mode ));
523 * na_importer_free_modes:
524 * @modes: a #GList of #NAImportMode items, as returned by na_importer_get_modes().
526 * Releases the resources allocated to the @modes list.
528 void
529 na_importer_free_modes( GList *modes )
531 static const gchar *thisfn = "na_importer_free_modes";
533 g_debug( "%s: modes=%p", thisfn, ( void * ) modes );
535 g_list_foreach( modes, ( GFunc ) g_object_unref, NULL );
536 g_list_free( modes );
540 * na_importer_get_ask_mode:
542 * Returns: a #NAImportMode object which describes the 'Ask me' option.
544 NAIOption *
545 na_importer_get_ask_mode( void )
547 static const gchar *thisfn = "na_importer_get_ask_mode";
549 g_debug( "%s", thisfn );
551 return( get_mode_from_struct( &st_import_ask_mode ));