1 /* ************************************************************************** */
2 /* */
3 /* copyright (c) 2000-2008 Cédric Auger (cedric@grisbi.org) */
4 /* 2004-2009 Benjamin Drieu (bdrieu@april.org) */
5 /* 2008-2009 Pierre Biava (grisbi@pierre.biava.name) */
6 /* https://www.grisbi.org/ */
7 /* */
8 /* This program is free software; you can redistribute it and/or modify */
9 /* it under the terms of the GNU General Public License as published by */
10 /* the Free Software Foundation; either version 2 of the License, or */
11 /* (at your option) any later version. */
12 /* */
13 /* This program is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16 /* GNU General Public License for more details. */
17 /* */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with this program; if not, write to the Free Software */
20 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
21 /* */
22 /* ************************************************************************** */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "include.h"
29 #include <gdk-pixbuf/gdk-pixdata.h>
30 #include <glib/gi18n.h>
31
32 /*START_INCLUDE*/
33 #include "gsb_select_icon.h"
34 #include "dialog.h"
35 #include "grisbi_app.h"
36 #include "utils_str.h"
37 #include "structures.h"
38 #include "utils.h"
39 #include "erreur.h"
40 #include "gsb_dirs.h"
41 /*END_INCLUDE*/
42
43 /*START_STATIC*/
44 /*END_STATIC*/
45
46 /*START_EXTERN*/
47 /*END_EXTERN*/
48
49 static GtkWidget *dialog;
50 static GtkWidget *bouton_OK;
51 static GtkWidget *entry_text;
52 static GtkWidget *icon_view;
53 static GdkPixbuf *pixbuf_logo = NULL;
54
55 static GtkListStore *store = NULL;
56
57 static gchar *path_icon;
58 static gchar *new_icon;
59
60 enum {
61 PIXBUF_COLUMN,
62 TEXT_COLUMN,
63 FILENAME_COLUMN /* On conserve le nom du fichier de l'icône */
64 };
65
66 /******************************************************************************/
67 /* Private functions */
68 /******************************************************************************/
69 /**
70 * callback pour traiter les changements de sélection dans le GtkIconView
71 *
72 * \param le GtkIconView appellant
73 * \param
74 *
75 * \return
76 *
77 **/
gsb_select_icon_selection_changed(GtkIconView * view,gpointer user_data)78 static void gsb_select_icon_selection_changed (GtkIconView *view,
79 gpointer user_data)
80 {
81 GList *liste;
82 GtkTreePath *path;
83 GtkTreeModel *model;
84 GtkTreeIter iter;
85 gchar *name_icon = NULL;
86
87 liste = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (view));
88
89 /* Could happen if selection is unset, exiting then. */
90 if (! liste)
91 return;
92
93 path = liste->data;
94
95 model = gtk_icon_view_get_model (GTK_ICON_VIEW (view));
96 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
97 gtk_tree_model_get (model, &iter, FILENAME_COLUMN, &name_icon, -1);
98 devel_debug (name_icon);
99 if (name_icon && strlen (name_icon) > 0)
100 {
101 new_icon = g_strdup (name_icon);
102 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (entry_text))), new_icon);
103 gtk_widget_set_sensitive (bouton_OK, TRUE);
104 g_free (name_icon);
105 }
106 g_list_free_full (liste, (GDestroyNotify) gtk_tree_path_free);
107 }
108
109 /**
110 * coupe le nom des fichiers pour garder un même nombre de colonnes
111 * dans le GtkIconView quelque soit la longueur du nom
112 *
113 * \param nom de l'icône et la longueur maxi de la ligne
114 * \param
115 *
116 * \return le nom de l'icône sur une ou plusieurs lignes
117 **/
gsb_select_icon_troncate_name_icon(gchar * name_icon,gint trunc)118 static gchar *gsb_select_icon_troncate_name_icon (gchar *name_icon,
119 gint trunc)
120 {
121 glong size = g_utf8_strlen (name_icon, -1);
122
123 if (size > 10)
124 {
125 gchar *tmpstr, *tmpstr2;
126 gchar *end;
127 gchar *ptr = NULL;
128 gint i = 1;
129 glong n = 0;
130
131 n = size / trunc;
132 if ((size % trunc) == 0)
133 n--;
134
135 tmpstr = g_malloc (size + n + 1);
136 /* devel_debug_int (n);
137 devel_debug (name_icon); */
138 tmpstr = g_utf8_strncpy (tmpstr, name_icon, trunc);
139 do
140 {
141 end = g_utf8_offset_to_pointer (name_icon, i *trunc);
142 /* devel_debug (end); */
143 if (i < n)
144 ptr = g_utf8_offset_to_pointer (name_icon, (i + 1) *10);
145 if (ptr)
146 tmpstr2 = g_strconcat (tmpstr, "\n",
147 g_strndup (end, ptr - end), NULL);
148 else
149 tmpstr2 = g_strconcat (tmpstr, "\n", end, NULL);
150 ptr = NULL;
151 i++;
152 } while (i <= n);
153
154 g_free (tmpstr);
155 return tmpstr2;
156 }
157 else
158 return g_strdup (name_icon);
159 }
160
161 /**
162 * remplit le modèle qu'il crée et attache au GtkIconView
163 *
164 * \param nom de l'icône initiale ou NULL
165 *
166 * \return un GtkTreePath qui donne la position de l'icône passée
167 * en paramètre
168 **/
gsb_select_icon_fill_icon_view(gchar * name_icon)169 static GtkTreePath *gsb_select_icon_fill_icon_view (gchar *name_icon)
170
171 {
172 GDir *dir;
173 GError *error = NULL;
174 GtkTreePath *tree_path = NULL;
175
176 devel_debug (path_icon);
177
178 dir = g_dir_open (path_icon, 0, &error);
179 if (dir)
180 {
181 GtkListStore *list_store;
182 GtkTreeIter iter;
183 GdkPixbuf *pixbuf;
184 GSList *liste = NULL;
185 gint i = 0;
186 const gchar *name = NULL;
187
188 while ((name = g_dir_read_name (dir)))
189 {
190 liste = g_slist_append (liste, g_strdup (name));
191 }
192 printf ("nbre elements = %u\n", g_slist_length (liste));
193 liste = g_slist_sort (liste, (GCompareFunc) my_strcasecmp);
194
195 list_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
196 while (liste)
197 {
198 gchar *tmp_filename;
199
200 tmp_filename = g_strconcat (path_icon, G_DIR_SEPARATOR_S, liste->data, NULL);
201 if (g_strcmp0 (tmp_filename, name_icon) == 0)
202 {
203 gchar *tmp_str;
204
205 tmp_str = utils_str_itoa (i);
206 tree_path = gtk_tree_path_new_from_string (tmp_str);
207 g_free (tmp_str);
208 }
209
210 pixbuf = gdk_pixbuf_new_from_file_at_size (tmp_filename, 32, 32, NULL);
211 if (pixbuf)
212 {
213 gchar *tmp_str;
214
215 gtk_list_store_append (list_store, &iter);
216 tmp_str = gsb_select_icon_troncate_name_icon (liste->data, 10);
217 gtk_list_store_set (list_store, &iter, PIXBUF_COLUMN, pixbuf, TEXT_COLUMN, tmp_str, -1);
218 gtk_list_store_set (list_store, &iter,
219 PIXBUF_COLUMN, pixbuf,
220 TEXT_COLUMN, tmp_str,
221 FILENAME_COLUMN, tmp_filename,
222 -1);
223 g_free (tmp_str);
224 g_object_unref (pixbuf);
225 }
226
227 liste = liste->next;
228 if (!g_file_test (tmp_filename, G_FILE_TEST_IS_DIR))
229 i++;
230 g_free (tmp_filename);
231 }
232 gtk_icon_view_set_model (GTK_ICON_VIEW (icon_view), GTK_TREE_MODEL (list_store));
233 g_object_unref (G_OBJECT (list_store));
234 g_dir_close (dir);
235 }
236 else
237 {
238 dialogue_error (error->message);
239 g_error_free (error);
240 }
241
242 if (tree_path == NULL)
243 tree_path = gtk_tree_path_new_from_string ("0");
244
245
246 return tree_path;
247 }
248
249 /**
250 * ajoute le nouveau path. S'il existe déjà dans la liste on le supprime
251 * de telle façon qu'il n'existe qu'une fois et apparaisse en premier dans
252 * la liste
253 *
254 * \param néant
255 *
256 * \return TRUE
257 **/
gsb_select_icon_add_path(void)258 static gboolean gsb_select_icon_add_path (void)
259 {
260 GtkTreeIter iter;
261 gboolean result = FALSE;
262
263 result = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store),
264 &iter);
265
266 while (result)
267 {
268 gchar *rep;
269
270 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &rep, -1);
271 if (strcmp (path_icon, rep) == 0)
272 {
273 gtk_list_store_remove (store, &iter);
274 break;
275 }
276 result = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
277 }
278 gtk_list_store_prepend (store, &iter);
279 gtk_list_store_set (store, &iter, 0, path_icon, -1);
280 devel_debug (g_strconcat ("path ajouté ", path_icon, NULL));
281
282 return TRUE;
283 }
284
285 /**
286 * Crée le dialogue pour le choix du nouveau répertoire et entre le choix
287 * dans le GtkComboBoxEntry
288 *
289 * \param bouton appelant
290 * \param
291 *
292 * \return void
293 *
294 **/
gsb_select_icon_create_file_chooser(GtkWidget * button,gpointer user_data)295 static void gsb_select_icon_create_file_chooser (GtkWidget *button,
296 gpointer user_data)
297 {
298 GtkWidget *chooser;
299
300 devel_debug (NULL);
301 chooser = gtk_file_chooser_dialog_new (_("Select icon directory"),
302 GTK_WINDOW (dialog),
303 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
304 "gtk-cancel", GTK_RESPONSE_CANCEL,
305 "gtk-open", GTK_RESPONSE_ACCEPT,
306 NULL);
307
308 gtk_window_set_position (GTK_WINDOW (chooser), GTK_WIN_POS_CENTER_ON_PARENT);
309 gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (dialog));
310 gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE);
311 gtk_widget_set_size_request (chooser, 600, 750);
312 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), path_icon);
313 if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
314 {
315 GtkTreePath *path;
316
317 path_icon = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
318 //~ devel_debug (path_icon);
319 path = gsb_select_icon_fill_icon_view (NULL);
320 gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (icon_view),
321 path, TRUE, 0.5, 0);
322 gsb_select_icon_add_path ();
323 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (entry_text))), path_icon);
324 gtk_widget_set_sensitive (bouton_OK, FALSE);
325 }
326
327 gtk_widget_destroy (chooser);
328 }
329
330 /**
331 * callback pour traiter les changements dans le GtkComboBoxEntry
332 *
333 * \param le GtkComboBoxEntry appellant
334 *
335 * \return void
336 *
337 **/
gsb_select_icon_entry_text_changed(GtkComboBox * entry,gpointer user_data)338 static void gsb_select_icon_entry_text_changed (GtkComboBox *entry,
339 gpointer user_data)
340 {
341 GtkTreePath *path;
342 const gchar *tmp_str;
343 gchar *ptr;
344
345 tmp_str = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (entry))));
346 devel_debug (tmp_str);
347
348 ptr = g_strstr_len (tmp_str, -1, path_icon);
349 if (ptr == NULL)
350 {
351 if (g_file_test (tmp_str, G_FILE_TEST_IS_DIR))
352 {
353 path_icon = g_strdup (tmp_str);
354 path = gsb_select_icon_fill_icon_view (NULL);
355 gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (icon_view), path, TRUE, 0.5, 0);
356
357 gtk_widget_set_sensitive (bouton_OK, FALSE);
358 }
359 }
360 }
361
362 /**
363 * crée le GtkComboBox pour l'entrée d'un nom de fichier ou de répertoire
364 * mémorise la liste des répertoires utilisés
365 *
366 * \param nom de l'icône
367 *
368 * \return le GtkComboBox
369 **/
gsb_select_icon_create_entry_text(gchar * name_icon)370 static GtkWidget *gsb_select_icon_create_entry_text (gchar *name_icon)
371 {
372 GtkWidget *combo;
373 GtkTreeIter iter;
374
375 if (!store)
376 {
377 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
378 gtk_list_store_append (store, &iter);
379 if (g_strcmp0 (gsb_dirs_get_pixmaps_dir (), path_icon) != 0)
380 {
381 gtk_list_store_set (store, &iter, 0, gsb_dirs_get_pixmaps_dir (), -1);
382 gtk_list_store_prepend (store, &iter);
383 }
384 gtk_list_store_set (store, &iter, 0, path_icon, -1);
385 }
386
387 combo = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (store));
388 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (combo), 0);
389
390 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo))), name_icon);
391
392 return combo;
393 }
394
395 /**
396 * Crée le GtkIconView
397 *
398 * \param nom de l'icône
399 *
400 * \return le GtkIconView rempli avec l'icône sélectionnée au premier plan
401 *
402 **/
gsb_select_icon_create_icon_view(gchar * name_icon)403 static GtkWidget *gsb_select_icon_create_icon_view (gchar *name_icon)
404 {
405 GtkTreePath *tree_path;
406
407 /* construct the GtkIconView */
408 icon_view = gtk_icon_view_new ();
409 gtk_icon_view_set_margin (GTK_ICON_VIEW (icon_view), 0);
410 gtk_icon_view_set_spacing (GTK_ICON_VIEW (icon_view), 0);
411 gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view), GTK_SELECTION_SINGLE);
412 gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), PIXBUF_COLUMN);
413 gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view), TEXT_COLUMN);
414
415 /* remplissage et positionnement initial du curseur dans le GtkIconView */
416 tree_path = gsb_select_icon_fill_icon_view (name_icon);
417
418 gtk_icon_view_select_path (GTK_ICON_VIEW (icon_view), tree_path);
419 gtk_icon_view_set_cursor (GTK_ICON_VIEW (icon_view), tree_path,
420 NULL, FALSE);
421 gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (icon_view),
422 tree_path, TRUE, 0.5, 0);
423
424 return icon_view;
425 }
426
427 /**
428 * redimmensionne le logo
429 *
430 * \param pixbuf à redimmensionner
431 *
432 * return a new pixbuf
433 **/
gsb_select_icon_resize_logo_pixbuf(GdkPixbuf * pixbuf)434 static GdkPixbuf *gsb_select_icon_resize_logo_pixbuf (GdkPixbuf *pixbuf)
435 {
436 GdkPixbuf *tmp;
437
438 if (!pixbuf)
439 return NULL;
440
441 tmp = gdk_pixbuf_scale_simple (pixbuf, LOGO_WIDTH, LOGO_HEIGHT, GDK_INTERP_HYPER);
442
443 return tmp;
444 }
445
446 /******************************************************************************/
447 /* Public functions */
448 /******************************************************************************/
449 /**
450 * crée la boite de dialogue initiale avec le GtkIconView
451 *
452 * \param nom de l'icône
453 *
454 * \return le nouveau nom de l'icône ou NULL
455 **/
gsb_select_icon_create_window(gchar * name_icon)456 gchar *gsb_select_icon_create_window (gchar *name_icon)
457 {
458 GtkWidget *content_area;
459 GtkWidget *hbox;
460 GtkWidget *chooser_button;
461 GtkWidget *scroll;
462 GtkWidget *view;
463 gint result;
464
465 devel_debug (name_icon);
466
467 if (new_icon && strlen (new_icon) > 0)
468 g_free (new_icon);
469
470 new_icon = g_strdup (name_icon);
471
472 if (path_icon && strlen (path_icon) > 0)
473 g_free (path_icon);
474
475 path_icon = g_path_get_dirname (name_icon);
476 dialog = gtk_dialog_new_with_buttons (_("Browse icons"),
477 GTK_WINDOW (grisbi_app_get_active_window (NULL)),
478 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
479 "gtk-cancel",
480 GTK_RESPONSE_REJECT,
481 NULL);
482
483 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
484 gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
485
486 bouton_OK = gtk_dialog_add_button (GTK_DIALOG (dialog),
487 "gtk-ok",
488 GTK_RESPONSE_ACCEPT);
489
490 content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
491
492 /* création hbox pour GtkEntry répertoire et bouton sélection des répertoires */
493 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, MARGIN_BOX);
494 gtk_container_set_border_width (GTK_CONTAINER(hbox), 6);
495 gtk_box_pack_start (GTK_BOX (content_area), hbox, FALSE, FALSE, 5);
496
497 /* création du GtkComboBoxEntry pour la saisie du répertoire */
498 entry_text = gsb_select_icon_create_entry_text (name_icon);
499 gtk_box_pack_start (GTK_BOX (hbox), entry_text, TRUE, TRUE, 0);
500
501 /* création du bouton de sélection des répertoires */
502 chooser_button = gtk_button_new_with_label (_("Browse"));
503 gtk_box_pack_start (GTK_BOX (hbox), chooser_button, FALSE, FALSE, 0);
504
505 /* création de la vue pour les icônes */
506 scroll = gtk_scrolled_window_new (NULL, NULL);
507 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
508 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
509 gtk_box_pack_start (GTK_BOX (content_area), scroll, TRUE, TRUE, 0);
510 view = gsb_select_icon_create_icon_view (name_icon);
511 gtk_container_set_border_width (GTK_CONTAINER(scroll), 6);
512 gtk_container_add (GTK_CONTAINER (scroll), view);
513
514 /* limitation de la fenêtre */
515 gtk_window_set_default_size (GTK_WINDOW (dialog), 480, 550);
516
517 /* gestion des signaux */
518 g_signal_connect (G_OBJECT (view),
519 "selection-changed",
520 G_CALLBACK(gsb_select_icon_selection_changed),
521 NULL);
522
523 g_signal_connect (G_OBJECT (chooser_button),
524 "clicked",
525 G_CALLBACK(gsb_select_icon_create_file_chooser),
526 NULL);
527
528 g_signal_connect (G_OBJECT(entry_text),
529 "changed",
530 G_CALLBACK(gsb_select_icon_entry_text_changed),
531 NULL);
532
533 gtk_widget_show_all (dialog);
534
535 result = gtk_dialog_run (GTK_DIALOG (dialog));
536 switch (result)
537 {
538 case GTK_RESPONSE_ACCEPT:
539 devel_debug ("réponse OK");
540 break;
541 default:
542 devel_debug ("réponse Non OK");
543 if (new_icon && strlen (new_icon) > 0)
544 g_free (new_icon);
545 new_icon = NULL;
546 break;
547 }
548 gtk_widget_destroy (dialog);
549
550 return new_icon;
551 }
552
553 /**
554 * retourne le logo par défaut de grisbi
555 *
556 * \param
557 *
558 * return a new pixbuf
559 **/
gsb_select_icon_get_default_logo_pixbuf(void)560 GdkPixbuf *gsb_select_icon_get_default_logo_pixbuf (void)
561 {
562 GdkPixbuf *pixbuf = NULL;
563 GError *error = NULL;
564 gchar *filename;
565
566 filename = g_build_filename (gsb_dirs_get_pixmaps_dir (), "grisbi.svg", NULL);
567 pixbuf = gdk_pixbuf_new_from_file_at_scale (filename, LOGO_WIDTH, LOGO_HEIGHT, FALSE, &error);
568 g_free (filename);
569
570 if (!pixbuf)
571 {
572 g_error_free (error);
573 return NULL;
574 }
575 else
576 return pixbuf;
577 }
578
579 /**
580 *
581 *
582 * \param
583 *
584 * \return
585 **/
gsb_select_icon_get_logo_pixbuf(void)586 GdkPixbuf *gsb_select_icon_get_logo_pixbuf (void)
587 {
588 return pixbuf_logo;
589 }
590
591 /**
592 *
593 *
594 * \param
595 *
596 * \return
597 **/
gsb_select_icon_init_logo_variables(void)598 gboolean gsb_select_icon_init_logo_variables (void)
599 {
600 if (pixbuf_logo)
601 g_object_unref (pixbuf_logo);
602 pixbuf_logo = NULL;
603
604 return FALSE;
605 }
606
607 /**
608 *
609 *
610 * \param
611 * \param
612 *
613 * \return
614 **/
gsb_select_icon_new_account_pixbuf_from_file(const gchar * filename)615 GdkPixbuf *gsb_select_icon_new_account_pixbuf_from_file (const gchar *filename)
616 {
617 GdkPixbuf *pixbuf;
618
619 pixbuf = gdk_pixbuf_new_from_file_at_size (filename , 32, 32, NULL);
620 if (pixbuf)
621 {
622 return pixbuf;
623 }
624 else
625 {
626 return NULL;
627 }
628 }
629
630 /**
631 *
632 *
633 * \param
634 *
635 * \return
636 **/
gsb_select_icon_set_gtk_icon_theme_path(void)637 void gsb_select_icon_set_gtk_icon_theme_path (void)
638 {
639 GtkIconTheme *icon_theme;
640
641 icon_theme = gtk_icon_theme_get_default ();
642 gtk_icon_theme_append_search_path (icon_theme, gsb_dirs_get_pixmaps_dir ());
643 }
644
645 /**
646 *
647 *
648 * \param
649 *
650 * \return
651 **/
gsb_select_icon_set_logo_pixbuf(GdkPixbuf * pixbuf)652 void gsb_select_icon_set_logo_pixbuf (GdkPixbuf *pixbuf)
653 {
654 if (pixbuf_logo != NULL)
655 g_object_unref (G_OBJECT (pixbuf_logo));
656
657 if (gdk_pixbuf_get_width (pixbuf) > LOGO_WIDTH ||
658 gdk_pixbuf_get_height (pixbuf) > LOGO_HEIGHT)
659 {
660 pixbuf_logo = gsb_select_icon_resize_logo_pixbuf (pixbuf);
661 }
662 else
663 {
664 pixbuf_logo = pixbuf ;
665 g_object_ref (G_OBJECT (pixbuf_logo));
666 }
667 }
668
669 /**
670 *
671 *
672 * \param
673 *
674 * \return
675 **/
676 /* Local Variables: */
677 /* c-basic-offset: 4 */
678 /* End: */
679