1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD et Damien
3 	CALISTE, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 
9 	Ce logiciel est un programme informatique servant à visualiser des
10 	structures atomiques dans un rendu pseudo-3D.
11 
12 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 	respectant les principes de diffusion des logiciels libres. Vous pouvez
14 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 	sur le site "http://www.cecill.info".
17 
18 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24 	Copyright CEA, contributors : Luc BILLARD et Damien
25 	CALISTE, laboratoire L_Sim, (2001-2005)
26 
27 	E-mail address:
28 	BILLARD, not reachable any more ;
29 	CALISTE, damien P caliste AT cea P fr.
30 
31 	This software is a computer program whose purpose is to visualize atomic
32 	configurations in 3D.
33 
34 	This software is governed by the CeCILL  license under French law and
35 	abiding by the rules of distribution of free software.  You can  use,
36 	modify and/ or redistribute the software under the terms of the CeCILL
37 	license as circulated by CEA, CNRS and INRIA at the following URL
38 	"http://www.cecill.info".
39 
40 	The fact that you are presently reading this means that you have had
41 	knowledge of the CeCILL license and that you accept its terms. You can
42 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 #include "panelBrowser.h"
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <math.h>
50 #include <time.h>
51 
52 #include <glib/gstdio.h>
53 #include <gtk/gtk.h>
54 
55 #include <visu_gtk.h>
56 #include <visu_tools.h>
57 #include <visu_basic.h>
58 #include <visu_configFile.h>
59 #include <visu_dataatomic.h>
60 #include <visu_dataspin.h>
61 
62 #include <support.h>
63 #include <gtk_main.h>
64 #include <extraGtkFunctions/gtk_dumpDialogWidget.h>
65 #include <gtk_openGLWidget.h>
66 #include <gtk_renderingWindowWidget.h>
67 
68 /**
69  * SECTION: panelBrowser
70  * @short_description: A tab to view a list of files and quickly
71  * change from one to another.
72  *
73  * <para>One can display a message about the file list by calling
74  * visu_ui_panel_browser_setMessage(). It is possible also to change
75  * the browser directory or directories with
76  * visu_ui_panel_browser_setCurrentDirectory().</para>
77  */
78 
79 static GtkWidget *panelBrowser, *vbox1;
80 static GtkTreeStore *treeStoreFiles;
81 static GtkTreeModel *treeStoreFilesFilter;
82 enum
83   {
84     COLUMN_BOOLEAN,       /* Rendered or not. */
85     COLUMN_NAME,          /* File name in locale of the file system. */
86     COLUMN_NAME_UTF8,     /* File name in UTF8 (to view it in GTK). */
87     COLUMN_DATE,          /* The modified time for the file. */
88     COLUMN_DATA,          /* File info (size / date). */
89     COLUMN_ACTIVE,        /* A boolean to set if this file is filtered or not. */
90     COLUMN_FILE_KIND,     /* An integer that correspond to the file type. */
91     COLUMN_FILE_VALID,    /* TRUE if the file is parsable. */
92     COLUMN_FILE_ERROR_ID, /* a stock icon id. */
93     N_COLUMNS
94   };
95 static gboolean dirDirty;
_toSpherical(void)96 static GtkWidget *fileTree;
97 static GtkWidget *scrolledwindow1, *infoBar, *labelInfo;
98 static GtkWidget *labelDirectory;
99 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17
100 static GtkWidget *infoImg;
101 #endif
102 /* A list of array of directory names and the current position in the list. */
103 static GList *historyBrowseredDirectory, *currentHistory;
104 /* A NULL terminated array of directories names, currently printed. */
105 static gchar **currentBrowseredDirectory;
106 /* The string common to all paths in currentBrowseredDirectory. */
107 static gchar *commonBrowseredDirectory;
108 #define HISTORY_TOOLTIP_PREV "Go to previously visited directories in history."
_fromSpherical(void)109 #define HISTORY_TOOLTIP_NEXT "Go to next visited directories in history."
110 
111 static GtkWidget *entryFilterBrowser;
112 enum
113   {
114     PANEL_BROWSER_COLUMN_FILTER_LABEL,
115     PANEL_BROWSER_COLUMN_FILTER_ID,
116     PANEL_BROWSER_N_COLUMN_FILTER
117   };
118 static GtkWidget *comboFilter;
119 struct TimerInfo_
120 {
121   GtkWidget *bt;
122   guint timer, label, nbFiles;
123   gboolean abort;
124 };
125 
126 static GtkWidget *imagePlay;
127 static GtkWidget *imageStop;
128 static GtkWidget *buttonPlayStop;
129 static GtkWidget *spinDelay;
130 
gtk_spin_create_direction()131 static GtkWidget *buttonPrevious;
132 static GtkWidget *buttonNext;
133 static GtkWidget *buttonDirPrev;
134 static GtkWidget *buttonDirNext;
135 static GtkWidget *buttonSelectAll;
136 static GtkWidget *buttonUnselectAll;
137 static GtkWidget *buttonDirectory;
138 static GtkWidget *buttonRecurse;
139 static GtkWidget *radioGoAround, *radioGoOnce, *radioGoAndBack;
140 static int currentBrowseDirection;
141 static GtkTreePath *startBrowsePath;
142 static GtkWidget *buttonDumpAll;
143 /* GtkProgressBar *progressBarDump; */
144 
145 static GtkWidget *createInteriorBrowser();
146 static void browseDirectory();
147 static void addParsedDirectory(int commonPathLen, const gchar *root,
148 			       GDir *gdir, gboolean recurse,
149                                GList *atFmt, gint atKind, GList *spFmt, gint spKind,
150 			       struct TimerInfo_ *timer);
151 static gboolean showProgressBar(gpointer data);
152 static void hideProgressBar(struct TimerInfo_ *timer);
153 /* Load and render the given file. The iter is given in the filter
154    model. */
155 static gboolean browserLoad(gchar *filename, gchar* fileUTF8,
156                             GtkTreeIter *iter, int nSet);
157 /* For the given iter load it. The iter must be given
158    in the filter model. */
159 static gboolean navigateInFiles(GtkTreePath *path, GtkTreeIter *iterSelected);
160 static void selectFile(GtkTreePath *path, GtkTreeIter *iter);
161 
162 gboolean gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *last, GtkTreePath **path);
163 void panelBrowserSet_labelCurrentDir();
164 
165 /* Callbacks */
166 static void onCheckFile(GtkCellRendererToggle *cell_renderer, gchar *path,
167 			gpointer user_data);
168 static void onTreeviewActivated(GtkTreeView *treeview, GtkTreePath *path,
169                                 GtkTreeViewColumn *col, gpointer user_data);
170 static void navigateClicked(GtkButton *button, gpointer data);
171 static void checkFiles(GtkButton *button, gpointer data);
172 static void onDirectoryClicked(GtkButton *button, gpointer data);
173 static void onPlayStopClicked(GtkToggleButton *button _U_, gpointer data _U_);
174 static void stopPlayStop(gpointer data);
175 static void onSpinDelayChangeValue(GtkSpinButton *spinbutton, gpointer user_data);
176 void onDumpButtonClicked(GtkButton *button, gpointer user_data);
177 static void onFilterChanged(GtkEditable *entry, gpointer user_data);
178 void abortDumpAll(GtkButton *button, gpointer data);
179 void updateDumpAllProgressBar(gpointer data);
180 static gboolean panelBrowserIsIterVisible(GtkTreeModel *model,
181 					  GtkTreeIter *iter, gpointer data);
182 static void onRefreshDir(GtkButton *button, gpointer data);
183 static void onEnter(VisuUiPanel *visu_ui_panel, gpointer data);
184 static gboolean checkFile(GtkTreeModel *model, GtkTreePath *path,
185 			  GtkTreeIter *iter, gpointer data);
186 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17
187 static void onParseAbortClicked(GtkButton *button, gpointer data);
188 #else
189 static void onParseAbortClicked(GtkInfoBar *infoBar, gint response, gpointer data);
190 #endif
191 static void onRecurseToggled(GtkToggleButton *toggle, gpointer data);
192 static void onNewDir(GObject *obj, VisuUiDirectoryType type, gpointer userData);
193 static void onPrevClicked(GtkButton *button, gpointer data);
194 static void onNextClicked(GtkButton *button, gpointer data);
195 static gint onSortNames(GtkTreeModel *model, GtkTreeIter *a,
196 			GtkTreeIter *b, gpointer user_data);
197 static void onNextPrevFile(VisuUiRenderingWindow *window, gpointer data);
198 
199 static void updateHistory();
200 static void updateDirectionalTooltips();
201 
202 /* Parameters customising the dialog. */
203 #define FLAG_PARAMETER_BROWSER_HEADERS    "browser_headersVisibility"
204 #define DESC_PARAMETER_BROWSER_HEADERS    "Show or hide the headers in the treeview ; boolean 0 or 1"
205 static gboolean showHeaders;
206 #define FLAG_PARAMETER_BROWSER_DATE    "browser_dateVisibility"
207 #define DESC_PARAMETER_BROWSER_DATE    "Show or hide the date column in the treeview ; boolean 0 or 1"
208 static gboolean showDate;
209 static void exportParameters(GString *data, VisuData *dataObj);
210 
gtk_spin_create_color_wheel()211 VisuUiPanel* visu_ui_panel_browser_init(VisuUiMain *ui)
212 {
213   char *cl = _("Browser");
214   char *tl = _("Browser");
215   VisuConfigFileEntry *entry;
216 
217   panelBrowser = visu_ui_panel_newWithIconFromPath("Panel_browser", cl, tl,
218                                                    "stock-browser_20.png");
219   if (!panelBrowser)
220     return (VisuUiPanel*)0;
221   vbox1 = gtk_vbox_new(FALSE, 0);
222   fileTree = (GtkWidget*)0;
223   buttonDirPrev = (GtkWidget*)0;
224   buttonDirNext = (GtkWidget*)0;
225   gtk_container_add(GTK_CONTAINER(panelBrowser), vbox1);
226   gtk_container_set_border_width(GTK_CONTAINER(panelBrowser), 5);
227   visu_ui_panel_setDockable(VISU_UI_PANEL(panelBrowser), TRUE);
228 
229   /* Create the configuration file entries. */
230   entry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER,
231                                            FLAG_PARAMETER_BROWSER_HEADERS,
232                                            DESC_PARAMETER_BROWSER_HEADERS,
233                                            &showHeaders, FALSE);
234   visu_config_file_entry_setVersion(entry, 3.5f);
235   entry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER,
236                                            FLAG_PARAMETER_BROWSER_DATE,
237                                            DESC_PARAMETER_BROWSER_DATE,
238                                            &showDate, FALSE);
239   visu_config_file_entry_setVersion(entry, 3.5f);
240   visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER,
241 				   exportParameters);
242 
243   /* Create the tree structure. */
244   treeStoreFiles = gtk_tree_store_new(N_COLUMNS,
245 				      G_TYPE_BOOLEAN,
246 				      G_TYPE_STRING,
247 				      G_TYPE_STRING,
248 				      G_TYPE_UINT,
249 				      G_TYPE_STRING,
250 				      G_TYPE_BOOLEAN,
251 				      G_TYPE_INT,
252 				      G_TYPE_BOOLEAN,
253 				      G_TYPE_STRING);
254   /* Use the COLUMN_ACTIVE as a flag to hide or not the rows that
255      don't match the filter value. */
256   treeStoreFilesFilter = gtk_tree_model_filter_new(GTK_TREE_MODEL(treeStoreFiles), NULL);
257   gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter),
258 					 panelBrowserIsIterVisible, (gpointer)0,
259 					 (GDestroyNotify)0);
260 /*   gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), COLUMN_ACTIVE); */
261 
262   gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(treeStoreFiles),
263 				  COLUMN_NAME_UTF8, onSortNames,
264 				  (gpointer)0, (GDestroyNotify)0);
265 
266   /* Add a new row to the model */
267   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(treeStoreFiles),
268 				       COLUMN_NAME_UTF8, GTK_SORT_ASCENDING);
269 
270   /* Initialise the values. */
271   currentBrowseredDirectory = (gchar**)0;
272   commonBrowseredDirectory  = (gchar*)0;
273   historyBrowseredDirectory = (GList*)0;
274   currentHistory            = (GList*)0;
275   currentBrowseDirection    = VISU_UI_PANEL_BROWSER_NEXT;
276   showHeaders               = FALSE;
277   showDate                  = FALSE;
278   dirDirty                  = FALSE;
279 
280   /* Create the callbacks of all the sensitive widgets. */
281   g_signal_connect(G_OBJECT(panelBrowser), "page-entered",
282 		   G_CALLBACK(onEnter), (gpointer)0);
283   g_signal_connect(ui, "DirectoryChanged",
284 		   G_CALLBACK(onNewDir), (gpointer)0);
285   g_signal_connect(G_OBJECT(visu_ui_main_class_getDefaultRendering()), "load-next-file",
286                    G_CALLBACK(onNextPrevFile), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_NEXT));
287   g_signal_connect(G_OBJECT(visu_ui_main_class_getDefaultRendering()), "load-prev-file",
288                    G_CALLBACK(onNextPrevFile), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_PREVIOUS));
289 
290   return VISU_UI_PANEL(panelBrowser);
291 }
292 
293 static GtkWidget *createInteriorBrowser()
294 {
295   /* include from glade */
296   GtkWidget *image2;
_setModel(VisuMethodSpin * spin)297   GtkWidget *image3;
298   GtkWidget *image1;
299   GtkWidget *hbox2;
300   GtkWidget *label4;
301   GtkWidget *label1;
302   GtkWidget *hbox5;
303   GtkWidget *image4;
304   GtkWidget *refreshDirButton;
305   GtkCellRenderer *renderer;
306   GtkTreeViewColumn *column;
307 
308   GtkWidget *label;
309   GtkWidget *hbox, *vbox;
310 
311 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12
312   GtkTooltips *tooltips;
313 
314   tooltips = gtk_tooltips_new ();
315 #endif
316 
317   GSList *radiobuttonCycle_group;
318 
319   hbox = gtk_hbox_new(FALSE, 0);
320   gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
321   /* This is a label in the browser panel to introduce the
322      entry that allows to enter a filter for files shown. */
323   label = gtk_label_new(_("Filter: "));
324   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
325   entryFilterBrowser = gtk_entry_new();
326   gtk_editable_set_editable(GTK_EDITABLE(entryFilterBrowser), TRUE);
327   gtk_entry_set_text(GTK_ENTRY(entryFilterBrowser), "*");
328   gtk_box_pack_start(GTK_BOX(hbox), entryFilterBrowser, TRUE, TRUE, 0);
329   comboFilter = gtk_combo_box_text_new();
330   gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter),
331                             "atomic", _("atomic rendering"));
332   gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter),
333                             "spin", _("spin rendering"));
334   gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter),
335                             "spin_at", _("atomic part"));
336   gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(comboFilter),
337                             "spin_sp", _("spin part"));
338   gtk_box_pack_start(GTK_BOX(hbox), comboFilter, FALSE, FALSE, 2);
339   gtk_combo_box_set_active(GTK_COMBO_BOX(comboFilter), 0);
340 
341   /*******************/
342   /* File lists part */
343   /*******************/
344   hbox = gtk_hbox_new(FALSE, 0);
345   gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
346 
347   vbox = gtk_vbox_new (FALSE, 0);
348   gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 2);
349 
350   buttonDirectory = gtk_button_new ();
351   gtk_box_pack_start (GTK_BOX (vbox), buttonDirectory, FALSE, FALSE, 1);
352   gtk_widget_set_tooltip_text(buttonDirectory,
353 			_("Choose a different directory."));
354 
355   image3 = gtk_image_new_from_icon_name("document-open", GTK_ICON_SIZE_BUTTON);
356   gtk_container_add (GTK_CONTAINER (buttonDirectory), image3);
357 
358   refreshDirButton = gtk_button_new ();
359   gtk_widget_set_tooltip_text(refreshDirButton,
360 			_("Rescan current directory."));
361   gtk_box_pack_start(GTK_BOX(vbox), refreshDirButton, FALSE, FALSE, 1);
362   image3 = gtk_image_new_from_icon_name("view-refresh", GTK_ICON_SIZE_BUTTON);
363   gtk_container_add(GTK_CONTAINER(refreshDirButton), image3);
364   g_signal_connect(G_OBJECT(refreshDirButton), "clicked",
365 		   G_CALLBACK(onRefreshDir), (gpointer)entryFilterBrowser);
366 
367   buttonRecurse = gtk_toggle_button_new();
368   gtk_widget_set_tooltip_text(buttonRecurse,
visu_ui_panel_method_spin_create(VisuGlNodeScene * scene _U_)369 			_("Read directories recursively."));
370   gtk_box_pack_start(GTK_BOX(vbox), buttonRecurse, FALSE, FALSE, 1);
371   image3 = gtk_image_new_from_icon_name("zoom-in", GTK_ICON_SIZE_BUTTON);
372   gtk_container_add(GTK_CONTAINER(buttonRecurse), image3);
373   g_signal_connect(G_OBJECT(buttonRecurse), "toggled",
374 		   G_CALLBACK(onRecurseToggled), (gpointer)entryFilterBrowser);
375 
376   buttonDirPrev = gtk_button_new();
377   gtk_widget_set_sensitive(buttonDirPrev, FALSE);
378   gtk_widget_set_tooltip_text(buttonDirPrev, _(HISTORY_TOOLTIP_PREV));
379   gtk_box_pack_start(GTK_BOX(vbox), buttonDirPrev, FALSE, FALSE, 1);
380   image3 = gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_BUTTON);
381   gtk_container_add(GTK_CONTAINER(buttonDirPrev), image3);
382   g_signal_connect(G_OBJECT(buttonDirPrev), "clicked",
383 		   G_CALLBACK(onPrevClicked), (gpointer)0);
384 
385   buttonDirNext = gtk_button_new();
386   gtk_widget_set_sensitive(buttonDirNext, FALSE);
387   gtk_widget_set_tooltip_text(buttonDirNext, _(HISTORY_TOOLTIP_NEXT));
388   gtk_box_pack_start(GTK_BOX(vbox), buttonDirNext, FALSE, FALSE, 1);
389   image3 = gtk_image_new_from_icon_name("go-next", GTK_ICON_SIZE_BUTTON);
390   gtk_container_add(GTK_CONTAINER(buttonDirNext), image3);
391   g_signal_connect(G_OBJECT(buttonDirNext), "clicked",
392 		   G_CALLBACK(onNextClicked), (gpointer)0);
393 
394 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5
395   label = gtk_label_new(_("Dir.:"));
396   gtk_label_set_angle(GTK_LABEL(label), 90.);
397   gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0);
398 #endif
399 
400   /* The infobar for cancel if to long and other messages. */
401   vbox = gtk_vbox_new(FALSE, 3);
402   gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
403   labelInfo = gtk_label_new("");
404   gtk_label_set_xalign(GTK_LABEL(labelInfo), 0.);
405 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17
406   infoBar = gtk_info_bar_new();
407   gtk_container_add(GTK_CONTAINER(gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar))),
408 		    labelInfo);
409 #else
410   infoBar = gtk_hbox_new(FALSE, 5);
411   infoImg = gtk_image_new_from_stock(GTK_STOCK_INFO, GTK_ICON_SIZE_MENU);
412   gtk_box_pack_start(GTK_BOX(infoBar), infoImg, FALSE, FALSE, 0);
413   gtk_box_pack_start(GTK_BOX(infoBar), labelInfo, TRUE, TRUE, 0);
414 #endif
415   gtk_widget_set_no_show_all(infoBar, TRUE);
416   gtk_box_pack_start(GTK_BOX(vbox), infoBar, FALSE, FALSE, 0);
417 
418   scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
419   gtk_box_pack_start(GTK_BOX(vbox), scrolledwindow1, TRUE, TRUE, 0);
420   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1),
421 				 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
422   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow1),
423 				      GTK_SHADOW_ETCHED_IN);
424 
425   fileTree = gtk_tree_view_new ();
426   gtk_widget_set_tooltip_text(fileTree,
427 			_("Double click on a file to render it."));
428   gtk_container_add (GTK_CONTAINER (scrolledwindow1), fileTree);
429   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fileTree), showHeaders);
430 
431   renderer = gtk_cell_renderer_toggle_new ();
432   g_signal_connect(G_OBJECT(renderer), "toggled",
433 		   G_CALLBACK(onCheckFile), (gpointer)0);
434   column = gtk_tree_view_column_new_with_attributes ("",
435 						     renderer,
436 						     "active", COLUMN_BOOLEAN,
437 						     "sensitive", COLUMN_FILE_VALID,
438 						     "activatable", COLUMN_FILE_VALID,
439 						     NULL);
440   gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column);
441   column = gtk_tree_view_column_new();
442   gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(column), _("File"));
443   renderer = gtk_cell_renderer_text_new ();
444   gtk_tree_view_column_pack_end(GTK_TREE_VIEW_COLUMN(column), renderer, TRUE);
445   gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer,
446                                       "markup", COLUMN_NAME_UTF8,
447                                       "sensitive", COLUMN_FILE_VALID,
448                                       NULL);
set_view(GtkWidget * button _U_,gpointer data _U_)449   renderer = gtk_cell_renderer_pixbuf_new();
450   gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
451   gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer,
452                                       "icon-name", COLUMN_FILE_ERROR_ID,
453                                       NULL);
454   gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME_UTF8);
455   gtk_tree_view_column_set_expand(column, TRUE);
456   gtk_tree_view_append_column(GTK_TREE_VIEW (fileTree), column);
457   if (showDate)
458     {
459       renderer = gtk_cell_renderer_text_new ();
460       column = gtk_tree_view_column_new_with_attributes (_("Date"),
461 							 renderer,
462 							 "text", COLUMN_DATA,
463 							 "sensitive", COLUMN_FILE_VALID,
464 							 NULL);
465       gtk_tree_view_column_set_sort_column_id(column, COLUMN_DATE);
466       gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column);
467     }
468 
469   gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)),
470 			      GTK_SELECTION_SINGLE);
471 
472   vbox = gtk_vbox_new (FALSE, 0);
473   gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 2);
474 
475   buttonUnselectAll = gtk_button_new();
476   gtk_widget_set_tooltip_text(buttonUnselectAll, _("Unselect all files."));
477   gtk_box_pack_start(GTK_BOX(vbox), buttonUnselectAll, FALSE, FALSE, 1);
478   image2 = create_pixmap ((GtkWidget*)0, "stock-unselect-all_20.png");
479   gtk_container_add(GTK_CONTAINER(buttonUnselectAll), image2);
480 
481   buttonSelectAll = gtk_button_new();
482   gtk_widget_set_tooltip_text(buttonSelectAll, _("Select all files."));
483   gtk_box_pack_start(GTK_BOX (vbox), buttonSelectAll, FALSE, FALSE, 1);
484   image2 = create_pixmap ((GtkWidget*)0, "stock-select-all_20.png");
485   gtk_container_add (GTK_CONTAINER (buttonSelectAll), image2);
486 
487   buttonDumpAll = gtk_button_new();
488   gtk_box_pack_start(GTK_BOX(vbox), buttonDumpAll, TRUE, FALSE, 0);
489   image4 = gtk_image_new_from_icon_name("document-save-as", GTK_ICON_SIZE_BUTTON);
490   gtk_container_add(GTK_CONTAINER(buttonDumpAll), image4);
491   gtk_widget_set_tooltip_text(buttonDumpAll,
492 		       _("Export the rendering of all selected files"
493 			 " in other formats."));
494 
495   buttonNext = gtk_button_new ();
496   gtk_box_pack_end(GTK_BOX (vbox), buttonNext, FALSE, FALSE, 1);
497   gtk_widget_set_tooltip_text(buttonNext,
498 		       _("Render the next selected file."));
499   image1 = gtk_image_new_from_icon_name("go-down", GTK_ICON_SIZE_BUTTON);
500   gtk_container_add (GTK_CONTAINER (buttonNext), image1);
501 
502   buttonPrevious = gtk_button_new ();
503   gtk_box_pack_end(GTK_BOX (vbox), buttonPrevious, FALSE, FALSE, 1);
504   gtk_widget_set_tooltip_text(buttonPrevious,
505 		       _("Render the previous selected file."));
506   image2 = gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_BUTTON);
507   gtk_container_add (GTK_CONTAINER (buttonPrevious), image2);
508 
509   hbox = gtk_hbox_new(FALSE, 0);
510   gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
511 
512   label = gtk_label_new(_("<span size=\"smaller\">Current dir.: </span>"));
513   gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
514   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
515 
516   labelDirectory = gtk_label_new("");
517   gtk_label_set_use_markup(GTK_LABEL(labelDirectory), TRUE);
518   gtk_label_set_xalign(GTK_LABEL(labelDirectory), 0.);
519 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5
520   gtk_label_set_ellipsize(GTK_LABEL(labelDirectory), PANGO_ELLIPSIZE_START);
521 #endif
522   gtk_box_pack_start(GTK_BOX(hbox), labelDirectory, TRUE, TRUE, 0);
523   panelBrowserSet_labelCurrentDir();
524 
525   /***************/
526   /* Action part */
527   /***************/
528   hbox2 = gtk_hbox_new (FALSE, 0);
529   gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, TRUE, 1);
530 
531   hbox5 = gtk_hbox_new(FALSE, 0);
532   gtk_widget_set_margin_end(hbox5, 5);
533   gtk_box_pack_start(GTK_BOX(hbox2), hbox5, FALSE, FALSE, 0);
534 
535   radioGoAround = gtk_radio_button_new(NULL);
536   gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoAround), (GSList*)0);
537   radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoAround));
538   gtk_box_pack_start(GTK_BOX(hbox5), radioGoAround, FALSE, FALSE, 0);
539   image1 = create_pixmap((GtkWidget*)0, "stock-go-around.png");
540   gtk_container_add(GTK_CONTAINER(radioGoAround), image1);
541 
542   radioGoOnce = gtk_radio_button_new(NULL);
543   gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoOnce), radiobuttonCycle_group);
544   radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoOnce));
545   gtk_box_pack_start(GTK_BOX(hbox5), radioGoOnce, FALSE, FALSE, 0);
546   image1 = create_pixmap((GtkWidget*)0, "stock-go-once.png");
547   gtk_container_add(GTK_CONTAINER(radioGoOnce), image1);
548 
549   radioGoAndBack = gtk_radio_button_new(NULL);
550   gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoAndBack), radiobuttonCycle_group);
551   radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoAndBack));
552   gtk_box_pack_start(GTK_BOX(hbox5), radioGoAndBack, FALSE, FALSE, 0);
553   image1 = create_pixmap((GtkWidget*)0, "stock-go-and-back.png");
554   gtk_container_add(GTK_CONTAINER(radioGoAndBack), image1);
555 
556   label4 = gtk_label_new (_("Play at "));
557   gtk_box_pack_start (GTK_BOX (hbox2), label4, TRUE, TRUE, 0);
558   gtk_label_set_xalign(GTK_LABEL(label4), 1.);
559 
560   spinDelay = gtk_spin_button_new_with_range(10, 10000, 25);
561   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinDelay), 500);
562   gtk_box_pack_start (GTK_BOX (hbox2), spinDelay, FALSE, TRUE, 0);
563   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinDelay), TRUE);
564 
565   /* Units: milliseconds */
566   label1 = gtk_label_new (_(" ms"));
567   gtk_box_pack_start (GTK_BOX (hbox2), label1, TRUE, TRUE, 0);
568   gtk_label_set_xalign(GTK_LABEL(label1), 0.);
569 
570   buttonPlayStop = gtk_toggle_button_new();
571   gtk_widget_set_tooltip_text(buttonPlayStop, _("Cycle through the selected files at the given rate."));
572   gtk_box_pack_start (GTK_BOX (hbox2), buttonPlayStop, FALSE, FALSE, 5);
573 
574   hbox5 = gtk_hbox_new (FALSE, 0);
575   gtk_container_add (GTK_CONTAINER (buttonPlayStop), hbox5);
576 
577 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 5
578   imagePlay = create_pixmap ((GtkWidget*)0, "stock_media-play.png");
579   imageStop = create_pixmap ((GtkWidget*)0, "stock_media-stop.png");
580 #else
581   imagePlay = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_MENU);
582   imageStop = gtk_image_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_MENU);
583 #endif
584   gtk_widget_set_no_show_all(imageStop, TRUE);
585   gtk_box_pack_start (GTK_BOX (hbox5), imagePlay, TRUE, TRUE, 0);
586   gtk_box_pack_start (GTK_BOX (hbox5), imageStop, TRUE, TRUE, 0);
587 
588   g_signal_connect(G_OBJECT(fileTree), "row-activated",
589 		   G_CALLBACK(onTreeviewActivated), (gpointer)0);
590   g_signal_connect(G_OBJECT(buttonPrevious), "clicked",
591 		   G_CALLBACK(navigateClicked), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_PREVIOUS));
592   g_signal_connect(G_OBJECT(buttonNext), "clicked",
593 		   G_CALLBACK(navigateClicked), GINT_TO_POINTER(VISU_UI_PANEL_BROWSER_NEXT));
594   g_signal_connect(G_OBJECT(buttonSelectAll), "clicked",
595 		   G_CALLBACK(checkFiles), GINT_TO_POINTER(TRUE));
596   g_signal_connect(G_OBJECT(buttonUnselectAll), "clicked",
597 		   G_CALLBACK(checkFiles), GINT_TO_POINTER(FALSE));
598   g_signal_connect(G_OBJECT(buttonDirectory), "clicked",
599 		   G_CALLBACK(onDirectoryClicked), (gpointer)entryFilterBrowser);
600   g_signal_connect(G_OBJECT(buttonPlayStop), "toggled",
601 		   G_CALLBACK(onPlayStopClicked), (gpointer)0);
602   g_signal_connect(G_OBJECT(spinDelay), "value-changed",
603 		   G_CALLBACK(onSpinDelayChangeValue), (gpointer)buttonPlayStop);
604   g_signal_connect(G_OBJECT(buttonDumpAll), "clicked",
605 		   G_CALLBACK(onDumpButtonClicked), (gpointer)0);
606   g_signal_connect(G_OBJECT(entryFilterBrowser), "changed",
607 		   G_CALLBACK(onFilterChanged), (gpointer)0);
608   g_signal_connect_swapped(G_OBJECT(comboFilter), "changed",
609                            G_CALLBACK(gtk_tree_model_filter_refilter),
610                            treeStoreFilesFilter);
611 
612   gtk_widget_show_all(vbox1);
613 
614   return vbox1;
615 }
616 
617 /*************/
618 /* Callbacks */
619 /*************/
620 
621 static void onFilterChanged(GtkEditable *entry, gpointer user_data _U_)
622 {
623   GPatternSpec *pattern;
624   gboolean valid;
625   GtkTreeIter iter;
626   gboolean match;
627   gchar *fileUTF8;
628 
629 /*   fprintf(stderr, "'%s'\n", gtk_entry_get_text(GTK_ENTRY(entry))); */
630 
631   pattern = g_pattern_spec_new(gtk_entry_get_text(GTK_ENTRY(entry)));
632 
633   for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFiles), &iter);
634        valid;
635        valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStoreFiles), &iter))
636     {
637       gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter,
638 			 COLUMN_NAME_UTF8, &fileUTF8, -1);
639       match = g_pattern_match_string(pattern, fileUTF8);
640       gtk_tree_store_set(treeStoreFiles, &iter,
641 			 COLUMN_ACTIVE, match, -1);
642       g_free(fileUTF8);
643     }
644   gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter));
645 
646   g_pattern_spec_free(pattern);
647 }
648 
649 static void onCheckFile(GtkCellRendererToggle *cell_renderer _U_, gchar *path,
650 			gpointer user_data _U_)
651 {
652   GtkTreeIter iter, childIter;
653   gboolean checked;
654   GtkTreePath *currentPath;
655 
656   currentPath = gtk_tree_path_new_from_string(path);
657   gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, currentPath);
658   gtk_tree_path_free(currentPath);
659 
660   gtk_tree_model_filter_convert_iter_to_child_iter
661     (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &childIter, &iter);
662 
663   gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &childIter,
664 		     COLUMN_BOOLEAN, &checked, -1);
665   gtk_tree_store_set(treeStoreFiles, &childIter,
666 		     COLUMN_BOOLEAN, !checked, -1);
667 
668 }
669 
670 static void onTreeviewActivated(GtkTreeView *treeview _U_, GtkTreePath *path,
671 				GtkTreeViewColumn *col _U_, gpointer user_data _U_)
672 {
673   GtkTreeIter iter, childIter, parentIter;
674   gboolean checked;
675   gchar* filename, *utf8;
676   int nSet;
677 
678   DBG_fprintf(stderr, "Panel Browser: double click detected.\n");
679   gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, path);
680   gtk_tree_model_filter_convert_iter_to_child_iter
681     (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &childIter, &iter);
682   gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &childIter,
683 		     COLUMN_NAME, &filename,
684 		     COLUMN_NAME_UTF8, &utf8,
685 		     COLUMN_BOOLEAN, &checked, -1);
686   if (!checked)
687     gtk_tree_store_set(GTK_TREE_STORE(treeStoreFiles), &childIter,
688 		       COLUMN_BOOLEAN, TRUE, -1);
689   if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFiles),
690 				 &parentIter, &childIter))
691     gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &childIter,
692 		       COLUMN_DATE, &nSet, -1);
693   else
694     nSet = 0;
695 
696   DBG_fprintf(stderr, "Panel Browser: double click asks for loading (%s).\n",
697 	      filename);
698   browserLoad(filename, utf8, &childIter, nSet);
699   g_free(filename);
700   g_free(utf8);
701 }
702 static void navigateClicked(GtkButton *button _U_, gpointer data)
703 {
704   GtkTreeIter iter;
705   GtkTreePath *path;
706   gboolean res;
707 
708   res = visu_ui_panel_browser_getNextSelected(&path, &iter, GPOINTER_TO_INT(data));
709   if (!res)
710     return;
711 
712   res = navigateInFiles(path, &iter);
713   gtk_tree_path_free(path);
714 }
715 static void onNextPrevFile(VisuUiRenderingWindow *window _U_, gpointer data)
716 {
717   GtkTreeIter iter;
718   GtkTreePath *path;
719   gboolean res;
720 
721   res = visu_ui_panel_browser_getNextSelected(&path, &iter, GPOINTER_TO_INT(data));
722   if (!res)
723     return;
724 
725   res = navigateInFiles(path, &iter);
726   gtk_tree_path_free(path);
727 }
728 static void checkFiles(GtkButton *button _U_, gpointer data)
729 {
730   gtk_tree_model_foreach(GTK_TREE_MODEL(treeStoreFilesFilter), checkFile, data);
731 }
732 static void onRefreshDir(GtkButton *button _U_, gpointer data _U_)
733 {
734   browseDirectory((gchar*)0);
735 }
736 gboolean playSelectedFiles(gpointer data _U_)
737 {
738   GtkTreeIter iter;
739   gboolean res, load;
740   GtkTreePath *path;
741 
742   g_return_val_if_fail(startBrowsePath, FALSE);
743 
744   /* We try to get the next iter. */
745   res = visu_ui_panel_browser_getNextSelected(&path, &iter, currentBrowseDirection);
746   if (!res)
747     return FALSE;
748 
749   /* We follow the cycle policy to select the file. */
750   load = TRUE;
751   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoAndBack)))
752     {
753       if (!gtk_tree_path_compare(path, startBrowsePath))
754 	{
755 	  DBG_fprintf(stderr, "Panel browser: One round is done, applyng policy.\n");
756 	  if (currentBrowseDirection == VISU_UI_PANEL_BROWSER_PREVIOUS)
757 	    currentBrowseDirection = VISU_UI_PANEL_BROWSER_NEXT;
758 	  else
759 	    {
760 	      currentBrowseDirection = VISU_UI_PANEL_BROWSER_PREVIOUS;
761 	      gtk_tree_path_free(path);
762 	      res = visu_ui_panel_browser_getNextSelected(&path, &iter,
763 						 currentBrowseDirection);
764 	      g_return_val_if_fail(res, FALSE);
765 	    }
766 	}
767     }
768   else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoOnce)))
769     {
770       if (!gtk_tree_path_compare(path, startBrowsePath))
771 	{
772 	  DBG_fprintf(stderr, "Panel browser: One round is done, applyng policy.\n");
773 	  res = FALSE;
774 	  load = FALSE;
775 	}
776     }
777 
778   if (load)
779     {
780       /* We advance the select one. */
781       selectFile(path, &iter);
782       /* We render it. */
783       res = navigateInFiles(path, &iter);
784     }
785 
786   gtk_tree_path_free(path);
787 
788   return res;
789 }
790 
791 static void onPlayStopClicked(GtkToggleButton *button, gpointer data _U_)
792 {
793   GtkTreeIter startIter;
794   gboolean res, checked, hasChild;
795   gulong *playCallbackId;
796 
797   DBG_fprintf(stderr, "Panel Browser: toggle on play button.\n");
798 /*   if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(panelBrowserListFilter), &startIter)) */
799 /*     return; */
800 
801   if (gtk_toggle_button_get_active(button))
802     {
803       /* Button has been pushed. */
804       checked = FALSE;
805       res = visu_ui_panel_browser_getCurrentSelected(&startBrowsePath, &startIter);
806       if (res)
807         {
808           gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFilesFilter), &startIter,
809                              COLUMN_BOOLEAN, &checked, -1);
810           hasChild = gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter),
811                                                    &startIter);
812         }
813       if (!res || !checked || hasChild)
814 	{
815 	  res = visu_ui_panel_browser_getNextSelected(&startBrowsePath, &startIter,
816 					     VISU_UI_PANEL_BROWSER_NEXT);
817 	  if (!res)
818 	    {
819 	      startBrowsePath = gtk_tree_path_new();
820 	      /* No file selected. */
821 	      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonPlayStop), FALSE);
822 	      return;
823 	    }
824 	}
825       navigateInFiles(startBrowsePath, &startIter);
826 
827       /* Launch play */
828       gtk_widget_hide(imagePlay);
829       gtk_widget_show(imageStop);
830 
831       currentBrowseDirection = VISU_UI_PANEL_BROWSER_NEXT;
832       playCallbackId = g_malloc(sizeof(gulong));
833       *playCallbackId =
834 	g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,
835 			   (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinDelay)),
836 			   playSelectedFiles, (gpointer)0,
837 			   stopPlayStop);
838       g_object_set_data(G_OBJECT(button), "playCallbackId",
839 			(gpointer)playCallbackId);
840       DBG_fprintf(stderr, " | start play\n");
841     }
842   else
843     {
844       /* Stop play */
845       playCallbackId = (gulong*)g_object_get_data(G_OBJECT(button), "playCallbackId");
846       if (playCallbackId)
847 	g_source_remove(*playCallbackId);
848       DBG_fprintf(stderr, " | stop play\n");
849     }
850 }
851 void stopPlayStop(gpointer data _U_)
852 {
853   gtk_widget_hide(imageStop);
854   gtk_widget_show(imagePlay);
855   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonPlayStop), FALSE);
856   g_return_if_fail(startBrowsePath);
857   gtk_tree_path_free(startBrowsePath);
858 }
859 static void onSpinDelayChangeValue(GtkSpinButton *spinbutton _U_, gpointer user_data)
860 {
861   GtkTreePath *startPath;
862   GtkToggleButton *button;
863   gulong *playCallbackId;
864 
865   g_return_if_fail(GTK_IS_TOGGLE_BUTTON(user_data));
866   button = GTK_TOGGLE_BUTTON(user_data);
867 
868   if (gtk_toggle_button_get_active(button))
869     {
870       playCallbackId = (gulong*)g_object_get_data(G_OBJECT(button), "playCallbackId");
871       g_return_if_fail(playCallbackId);
872 
873       startPath = gtk_tree_path_copy(startBrowsePath);
874       /* Stop playing at this rate */
875       g_source_remove(*playCallbackId);
876       startBrowsePath = startPath;
877       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttonPlayStop), TRUE);
878     }
879 }
880 void onDumpButtonClicked(GtkButton *button _U_, gpointer user_data _U_)
881 {
882   GtkWidget *dump;
883   GtkProgressBar *progressBarDump;
884   char *filename;
885   VisuDump *format;
886   GError *error;
887   GString *buffer;
888   GtkButton *abort;
889   char *chr, *chr2;
890   int goodPattern, flagAbort, i;
891   gint response;
892   GString *fileNumbered;
893   GtkTreeIter iter;
894   gboolean valid, errors;
895   GtkTreePath *currentPath, *startPath;
896   VisuGlView *view;
897 
898   view = visu_ui_panel_getView(VISU_UI_PANEL(panelBrowser));
899   dump = visu_ui_dump_dialog_new
900     (visu_ui_panel_getData(VISU_UI_PANEL(panelBrowser)),
901      visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelBrowser)),
902      _("foo%02d.png"), view->window.width, view->window.height);
903 
904   do
905     {
906       response = gtk_dialog_run(GTK_DIALOG(dump));
907 
908       if (response != GTK_RESPONSE_ACCEPT)
909 	{
910 	  gtk_widget_destroy(dump);
911 	  return;
912 	}
913 
914       filename = visu_ui_dump_dialog_getFilename(VISU_UI_DUMP_DIALOG(dump));
915       format = visu_ui_dump_dialog_getType(VISU_UI_DUMP_DIALOG(dump));
916       g_return_if_fail(filename && format);
917 
918       DBG_fprintf(stderr, "Panel browser: dump all returns this filename"
919 		  " pattern '%s' (format : %s)\n", filename,
920                   tool_file_format_getName(TOOL_FILE_FORMAT(format)));
921 
922       buffer = g_string_new(_("Dumping all selected files to images,"));
923       g_string_append_printf(buffer, _(" format '%s'.\n\n"),
924                              tool_file_format_getName(TOOL_FILE_FORMAT(format)));
925       /* Verify the name is regular */
926       if (g_pattern_match_simple("*%0?d*", filename))
927 	{
928 	  chr = strchr(filename, '%');
929 	  if ((int)*(chr + 2) <= '0' || (int)*(chr + 2) > '9')
930 	    {
931 	      goodPattern = 0;
932 	      g_string_append_printf(buffer, _("Error! The numbering pattern is"
933 					       " wrong.\n"));
934 	    }
935 	  else
936 	    {
937 	      chr2 = strchr(chr + 1, '%');
938 	      if (chr2)
939 		{
940 		  goodPattern = 0;
941 		  g_string_append_printf(buffer,
942 					 _("Error! Only one '%s' character"
943 					   " is allowed in the file name.\n"), "%");
944 		}
945 	      else
946 		goodPattern = 1;
947 	    }
948 	}
949       else
950 	{
951 	  goodPattern = 0;
952 	  g_string_append_printf(buffer, _("Error! Missing pattern in the filename.\n"));
953 	}
954       if (!goodPattern)
955 	{
956 	  g_string_append_printf(buffer,
957 				 _("\nHelp : you must specify '%s' in"
958 				   " the filename, where 'x' is a number [|1;9|]."
959 				   " This allows V_Sim to number the dumped"
960 				   " files.\n\n For example, with a pattern like this"
961 				   " : 'foo%s.pdf', dumped files will be named"
962 				   " : foo00.pdf, foo01.pdf..."),
963 				 "%0xd", "%02d");
964 	  visu_ui_raiseWarning(_("Exporting files"), buffer->str, (GtkWindow*)0);
965 	  g_string_free(buffer, TRUE);
966 	}
967     }
968   while (!goodPattern);
969 
970   error = (GError*)0;
971   abort = visu_ui_dump_dialog_getCancelButton(VISU_UI_DUMP_DIALOG(dump));
972   progressBarDump = visu_ui_dump_dialog_getProgressBar(VISU_UI_DUMP_DIALOG(dump));
973   visu_ui_dump_dialog_start(VISU_UI_DUMP_DIALOG(dump));
974 
975   g_signal_connect (G_OBJECT(abort), "clicked",
976 		    G_CALLBACK(visu_dump_abort), (gpointer)&flagAbort);
977   g_signal_connect (G_OBJECT(abort), "clicked",
978 		    G_CALLBACK(abortDumpAll), (gpointer)progressBarDump);
979 
980   gtk_progress_bar_set_fraction(progressBarDump, 0.);
981   fileNumbered = g_string_new("");
982   i = 0;
983   flagAbort = 0;
984 
985   /* We write it only once to avoid blinking effects. */
986   gtk_progress_bar_set_text(progressBarDump,
987 			    _("Waiting for generating image in memory..."));
988   visu_ui_wait();
989 
990   gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)));
991 
992   errors = FALSE;
993   valid = visu_ui_panel_browser_getNextSelected(&startPath, &iter, VISU_UI_PANEL_BROWSER_NEXT);
994   if (valid)
995     valid = navigateInFiles(startPath, &iter);
996   while (valid && !errors && !flagAbort)
997     {
998       g_string_append_printf(buffer, _("Write to file %d ..."), i);
999       g_string_printf(fileNumbered, filename, i);
1000       DBG_fprintf(stderr, "Panel browser: write '%s'\n", fileNumbered->str);
1001 
1002       errors = !visu_gl_node_scene_dump(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()),
1003                                         format, fileNumbered->str,
1004                                         visu_ui_dump_dialog_getWidth(VISU_UI_DUMP_DIALOG(dump)),
1005                                         visu_ui_dump_dialog_getHeight(VISU_UI_DUMP_DIALOG(dump)),
1006                                         updateDumpAllProgressBar, (gpointer)progressBarDump,
1007                                         &error);
1008       if (errors)
1009         g_string_append_printf(buffer, _(" error\n"));
1010       else
1011         g_string_append_printf(buffer, _(" OK\n"));
1012       i += 1;
1013 
1014       valid = visu_ui_panel_browser_getNextSelected(&currentPath, &iter, VISU_UI_PANEL_BROWSER_NEXT);
1015       if (!gtk_tree_path_compare(currentPath, startPath))
1016         valid = FALSE;
1017       if (valid)
1018         valid = navigateInFiles(currentPath, &iter);
1019       gtk_tree_path_free(currentPath);
1020     }
1021   gtk_tree_path_free(startPath);
1022   if (error)
1023     {
1024       visu_ui_raiseWarning(_("Exporting files"), error->message, (GtkWindow*)0);
1025       g_error_free(error);
1026     }
1027   g_string_free(fileNumbered, TRUE);
1028 
1029   gtk_widget_destroy(dump);
1030 }
1031 void updateDumpAllProgressBar(gpointer data)
1032 {
1033   gdouble val;
1034   gdouble percentage;
1035   gdouble nEle;
1036 
1037   g_return_if_fail(GTK_PROGRESS_BAR(data));
1038 
1039   nEle = (gdouble)gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStoreFilesFilter), NULL);
1040   val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(data));
1041 /*   if (((int)(val * nEle)) % 100 == 1) */
1042     gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data), "");
1043 
1044   percentage = val + 0.01 / nEle;
1045   if (percentage > 1.0)
1046     percentage = 1.0;
1047   if (percentage < 0.)
1048     percentage = 0.;
1049   gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data), percentage);
1050   visu_ui_wait();
1051 }
1052 void abortDumpAll(GtkButton *button _U_, gpointer data)
1053 {
1054   gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data),
1055 			    _("Abortion request, please wait..."));
1056 }
1057 
1058 
1059 
1060 
1061 
1062 /******************/
1063 /* Public methods */
1064 /******************/
1065 
1066 gboolean visu_ui_panel_browser_getCurrentSelected(GtkTreePath **path, GtkTreeIter *iterSelected)
1067 {
1068   GtkTreeSelection *selection;
1069   gboolean res;
1070   GtkTreeModel *model;
1071 
1072   g_return_val_if_fail(path && iterSelected, FALSE);
1073 
1074   if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFilesFilter), iterSelected))
1075     return FALSE;
1076 
1077   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree));
1078   res = gtk_tree_selection_get_selected(selection, &model, iterSelected);
1079 
1080   if (res)
1081     *path = gtk_tree_model_get_path(model, iterSelected);
1082   return res;
1083 }
1084 
1085 gboolean visu_ui_panel_browser_getNextSelected(GtkTreePath **path, GtkTreeIter *iterSelected,
1086 				      int direction)
1087 {
1088   GtkTreeSelection *selection;
1089   GtkTreePath *currentPath, *firstPath;
1090   GtkTreeIter iter, child, parent;
1091   gboolean res, checked;
1092   GtkTreeModel *model;
1093   int loopComplete;
1094 
1095   g_return_val_if_fail(path && iterSelected &&
1096 		       (direction == VISU_UI_PANEL_BROWSER_NEXT ||
1097 			direction == VISU_UI_PANEL_BROWSER_PREVIOUS), FALSE);
1098 
1099   *path = (GtkTreePath*)0;
1100 
1101   if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFilesFilter), &iter))
1102     return FALSE;
1103 
1104   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree));
1105   res = gtk_tree_selection_get_selected(selection, &model, &iter);
1106 
1107   /* Nothing is selected. */
1108   if (!res)
1109     {
1110       if (direction == VISU_UI_PANEL_BROWSER_NEXT)
1111 	res = gtk_tree_model_get_iter_last(GTK_TREE_MODEL(treeStoreFilesFilter),
1112 					   &iter, (GtkTreePath**)0);
1113       else if (GPOINTER_TO_INT(direction) == VISU_UI_PANEL_BROWSER_PREVIOUS)
1114 	res = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFilesFilter),
1115 					    &iter);
1116     }
1117   g_return_val_if_fail(res, FALSE);
1118 
1119   currentPath = gtk_tree_model_get_path(GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1120   firstPath = gtk_tree_path_copy(currentPath);
1121   do
1122     {
1123       if (direction == VISU_UI_PANEL_BROWSER_NEXT)
1124 	{
1125 	  /* If the current iter has child, we select the first. */
1126 	  if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter),
1127 					    &iter))
1128 	    {
1129 	      gtk_tree_model_iter_children(GTK_TREE_MODEL(treeStoreFilesFilter),
1130 					   &child, &iter);
1131 	      iter = child;
1132 	      gtk_tree_path_free(currentPath);
1133 	      currentPath =
1134 		gtk_tree_model_get_path(GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1135 	    }
1136 	  /* If the current iter has no child, we go next. */
1137 	  else
1138 	    {
1139 	      /* Avance d'un pas dans la liste */
1140 	      gtk_tree_path_next(currentPath);
1141 	      child = iter;
1142 	      res = gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter),
1143 					    &iter, currentPath);
1144 	      /* In case, there's no next iter. */
1145 	      if (!res)
1146 		{
1147 		  /* If the iter has no parent we go top. */
1148 		  if (!gtk_tree_model_iter_parent
1149 		      (GTK_TREE_MODEL(treeStoreFilesFilter), &parent, &child))
1150 		    {
1151 		      gtk_tree_model_get_iter_first
1152 			(GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1153 		      gtk_tree_path_free(currentPath);
1154 		      currentPath =
1155 			gtk_tree_model_get_path
1156 			(GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1157 		    }
1158 		  /* If the iter has parent, we go next parent. */
1159 		  else
1160 		    {
1161 		      iter = parent;
1162 		      gtk_tree_path_free(currentPath);
1163 		      currentPath = gtk_tree_model_get_path
1164 			(GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1165 		      gtk_tree_path_next(currentPath);
1166 		      res = gtk_tree_model_get_iter
1167 			(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, currentPath);
1168 		      if (!res)
1169 			{
1170 			  gtk_tree_model_get_iter_first
1171 			    (GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1172 			  gtk_tree_path_free(currentPath);
1173 			  currentPath = gtk_tree_model_get_path
1174 			    (GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1175 			}
1176 		    }
1177 		}
1178 	    }
1179 	}
1180       else if (direction == VISU_UI_PANEL_BROWSER_PREVIOUS)
1181 	{
1182 	  /* Recule d'un pas dans la liste */
1183 	  res = gtk_tree_path_prev(currentPath);
1184 	  /* Recup�re l'it�ration recul�e d'un pas */
1185 	  child = iter;
1186 	  res = res && gtk_tree_model_get_iter(GTK_TREE_MODEL(treeStoreFilesFilter),
1187 					       &iter, currentPath);
1188 	  /* If this prev iter does not exist. */
1189 	  if (!res)
1190 	    {
1191 	      /* In the case the current iter has a parent, we select it. */
1192 	      if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFilesFilter),
1193 					     &parent, &child))
1194 		{
1195 		  iter = parent;
1196 		  gtk_tree_path_free(currentPath);
1197 		  currentPath = gtk_tree_model_get_path
1198 		    (GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1199 		}
1200 	      /* Si ce path n'existe pas ou
1201 		 si cette iteration n'existe pas on va � la fin. */
1202 	      else
1203 		{
1204 		  gtk_tree_path_free(currentPath);
1205 		  res = gtk_tree_model_get_iter_last
1206 		    (GTK_TREE_MODEL(treeStoreFilesFilter), &iter, &currentPath);
1207 		  if (!res)
1208 		    {
1209 		      g_warning("Panel browser: impossible to find"
1210 				" the end of the list.\n");
1211 		      gtk_tree_path_free(currentPath);
1212 		      gtk_tree_path_free(firstPath);
1213 		      return FALSE;
1214 		    }
1215 		}
1216 	    }
1217 	  /* If the previous iter has children, we select last. */
1218 	  else if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter),
1219 						 &iter))
1220 	    {
1221 	      parent = iter;
1222 	      res = gtk_tree_model_iter_nth_child
1223 		(GTK_TREE_MODEL(treeStoreFilesFilter), &iter, &parent,
1224 		 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStoreFilesFilter),
1225 						&parent) - 1);
1226 	      if (!res)
1227 		{
1228 		  g_warning("Panel browser: impossible to find"
1229 			    " the last child of this iter.\n");
1230 		  gtk_tree_path_free(currentPath);
1231 		  gtk_tree_path_free(firstPath);
1232 		  return FALSE;
1233 		}
1234 	      gtk_tree_path_free(currentPath);
1235 	      currentPath = gtk_tree_model_get_path
1236 		(GTK_TREE_MODEL(treeStoreFilesFilter), &iter);
1237 	    }
1238 	}
1239 
1240       checked = FALSE;
1241       gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFilesFilter), &iter,
1242 			 COLUMN_BOOLEAN, &checked, -1);
1243       checked = checked && !gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treeStoreFilesFilter),
1244                                                           &iter);
1245 /*       fprintf(stderr, "%d '%s'\n", nbSteps, filename); */
1246       loopComplete = !gtk_tree_path_compare(firstPath, currentPath);
1247     }
1248   while ( !checked && !loopComplete);
1249   gtk_tree_path_free(firstPath);
1250   if (!loopComplete)
1251     {
1252       *path = currentPath;
1253       *iterSelected = iter;
1254       return TRUE;
1255     }
1256   else
1257     {
1258       gtk_tree_path_free(currentPath);
1259       return FALSE;
1260     }
1261 }
1262 
1263 static void selectFile(GtkTreePath *path, GtkTreeIter *iter)
1264 {
1265   GtkTreeSelection *selection;
1266 
1267   g_return_if_fail(path && iter);
1268 
1269   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree));
1270   gtk_tree_selection_select_iter(selection, iter);
1271   gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fileTree), path, NULL, FALSE, 0., 0.);
1272 }
1273 static gboolean navigateInFiles(GtkTreePath *path, GtkTreeIter *iterSelected)
1274 {
1275   gboolean res;
1276   gchar *filename, *utf8;
1277   int nSet;
1278   GtkTreeIter parentIter, iter;
1279 
1280   g_return_val_if_fail(path && iterSelected, FALSE);
1281 
1282   /* We select the given iter. */
1283   selectFile(path, iterSelected);
1284 
1285   /* Load the new selected file */
1286   gtk_tree_model_filter_convert_iter_to_child_iter
1287     (GTK_TREE_MODEL_FILTER(treeStoreFilesFilter), &iter, iterSelected);
1288   if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFiles),
1289 				 &parentIter, &iter))
1290     gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter,
1291 		       COLUMN_DATE, &nSet, -1);
1292   else
1293     nSet = 0;
1294   gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter,
1295 		     COLUMN_NAME, &filename,
1296 		     COLUMN_NAME_UTF8, &utf8, -1);
1297   res = browserLoad(filename, utf8, &iter, nSet);
1298   g_free(filename);
1299   g_free(utf8);
1300   return res;
1301 }
1302 
1303 static VisuDataLoadable* setFiles(const gchar *filename, const gchar *utf8,
1304                                   VisuData *oldData)
1305 {
1306   gchar *pt, **tokens, *name, *name2;
1307   VisuDataAtomic *atomic;
1308   VisuDataSpin *spin;
1309 
1310   switch (gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter)))
1311     {
1312     case 0:
1313       atomic = visu_data_atomic_new(filename, (VisuDataLoader*)0);
1314       return VISU_DATA_LOADABLE(atomic);
1315     case 1:
1316       /* The case where the name is used for all files. */
1317       pt = strrchr(utf8, ']');
1318       *pt = '\0';
1319       pt = strrchr(utf8, '[');
1320       tokens = g_strsplit(pt + 1, ",", 2);
1321       name = g_strdup_printf("%s.%s", filename, tokens[0]);
1322       name2 = g_strdup_printf("%s.%s", filename, tokens[1]);
1323       g_strfreev(tokens);
1324       spin = visu_data_spin_new(name, name2, (VisuDataLoader*)0, (VisuDataLoader*)0);
1325       g_free(name);
1326       g_free(name2);
1327       return VISU_DATA_LOADABLE(spin);
1328     case 2:
1329       g_return_val_if_fail(VISU_IS_DATA_LOADABLE(oldData), (VisuDataLoadable*)0);
1330       spin = visu_data_spin_new(filename, visu_data_loadable_getFilename(VISU_DATA_LOADABLE(oldData), 1), (VisuDataLoader*)0, (VisuDataLoader*)0);
1331       return VISU_DATA_LOADABLE(spin);
1332     case 3:
1333       g_return_val_if_fail(VISU_IS_DATA_LOADABLE(oldData), (VisuDataLoadable*)0);
1334       spin = visu_data_spin_new(visu_data_loadable_getFilename(VISU_DATA_LOADABLE(oldData), 0), filename, (VisuDataLoader*)0, (VisuDataLoader*)0);
1335       return VISU_DATA_LOADABLE(spin);
1336     default:
1337       return (VisuDataLoadable*)0;
1338     }
1339 }
1340 
1341 static gboolean browserLoad(gchar *filename, gchar *utf8, GtkTreeIter *iter, int nSet)
1342 {
1343   GError *error;
1344   VisuDataLoadable *data;
1345   VisuData *prevData;
1346   gboolean valid;
1347   GtkTreeIter parentIter, childIter;
1348   int iSet, nSets;
1349   GtkTreePath *path;
1350   const gchar *comment;
1351   gchar *buf, *commentFormat;
1352 
1353   g_return_val_if_fail(iter, FALSE);
1354 
1355   prevData = visu_ui_panel_getData(VISU_UI_PANEL(panelBrowser));
1356   data = setFiles(filename, utf8, prevData);
1357   if (!data)
1358     {
1359       visu_ui_raiseWarning(_("Loading a file"),
1360 			   _("Can't load this file through the browser because it"
1361 			     " requires to read several files. You should use the 'Open'"
1362 			     " button on the main panel and then use the browser to vary"
1363 			     " one kind of file at a time."), (GtkWindow*)0);
1364       g_object_unref(data);
1365 
1366       gtk_tree_store_set(treeStoreFiles, iter,
1367 			 COLUMN_FILE_VALID, FALSE,
1368 			 COLUMN_BOOLEAN, FALSE,
1369 			 -1);
1370       return FALSE;
1371     }
1372 
1373   gtk_widget_set_sensitive(buttonPrevious, FALSE);
1374   gtk_widget_set_sensitive(buttonNext, FALSE);
1375   error = (GError*)0;
1376   if (!visu_gl_node_scene_loadData(visu_ui_rendering_window_getGlScene(visu_ui_main_class_getDefaultRendering()), data, nSet, (GCancellable*)0, &error))
1377     {
1378       if (error)
1379         {
1380           visu_ui_raiseWarning(_("Loading a file"), error->message, (GtkWindow*)0);
1381           g_error_free(error);
1382         }
1383       g_object_unref(data);
1384       data = (VisuDataLoadable*)0;
1385     }
1386   gtk_widget_set_sensitive(buttonPrevious, TRUE);
1387   gtk_widget_set_sensitive(buttonNext, TRUE);
1388 
1389   if (!data)
1390     gtk_tree_store_set(treeStoreFiles, iter,
1391 		       COLUMN_FILE_ERROR_ID, "dialog-error",
1392 		       COLUMN_FILE_VALID, FALSE,
1393 		       COLUMN_BOOLEAN, FALSE,
1394 		       -1);
1395   else
1396     gtk_tree_store_set(treeStoreFiles, iter,
1397 		       COLUMN_FILE_ERROR_ID, (gchar*)0,
1398 		       COLUMN_FILE_VALID, TRUE,
1399 		       -1);
1400 
1401   if (data)
1402     {
1403       /* If the file has more than one node set, we create the child
1404 	 entries in the tree view. */
1405       nSets = visu_data_loadable_getNSets(data);
1406       if (nSets > 1)
1407 	{
1408 	  /* We get the parent iter. */
1409 	  if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(treeStoreFiles),
1410 					  &parentIter, iter))
1411 	    {
1412 	      /* We clear its children. */
1413 	      valid = gtk_tree_model_iter_children
1414 		(GTK_TREE_MODEL(treeStoreFiles), &childIter, iter);
1415 	      while (valid)
1416 		{
1417 		  gtk_tree_store_remove(treeStoreFiles, &childIter);
1418 		  valid = gtk_tree_model_iter_children
1419 		    (GTK_TREE_MODEL(treeStoreFiles), &childIter, iter);
1420 		}
1421 	      /* We create the new ones. */
1422 	      commentFormat = g_strdup_printf(_("data set %s0%dd"), "%",
1423 					      (int)log10(nSets) + 1);
1424 	      for (iSet = 0; iSet < nSets; iSet++)
1425 		{
1426 		  comment = visu_data_loadable_getSetLabel(data, iSet);
1427 		  if (!comment || !comment[0])
1428 		    {
1429 		      buf = g_strdup_printf(commentFormat, iSet + 1);
1430 		      comment = buf;
1431 		    }
1432 		  else
1433 		    buf = (gchar*)0;
1434 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9
1435 		  gtk_tree_store_insert_with_values(treeStoreFiles,
1436 						    &childIter, iter, iSet,
1437 						    COLUMN_BOOLEAN, TRUE,
1438 						    COLUMN_NAME, filename,
1439 						    COLUMN_NAME_UTF8, comment,
1440 						    COLUMN_ACTIVE, TRUE,
1441 						    COLUMN_DATE, iSet,
1442 						    COLUMN_FILE_VALID, TRUE,
1443 						    -1);
1444 #else
1445 		  gtk_tree_store_insert(treeStoreFiles, &childIter,
1446 					iter, iSet);
1447 		  gtk_tree_store_set(treeStoreFiles, &childIter,
1448 				     COLUMN_BOOLEAN, TRUE,
1449 				     COLUMN_NAME, filename,
1450 				     COLUMN_NAME_UTF8, comment,
1451 				     COLUMN_ACTIVE, TRUE,
1452 				     COLUMN_DATE, iSet,
1453 				     COLUMN_FILE_VALID, TRUE,
1454 				     -1);
1455 #endif
1456 		  if (buf)
1457 		    g_free(buf);
1458 		}
1459 	      g_free(commentFormat);
1460 	      /* We expand the row. */
1461 	      gtk_tree_model_filter_convert_child_iter_to_iter
1462 		(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter),
1463 		 &parentIter, iter);
1464 	      path = gtk_tree_model_get_path(GTK_TREE_MODEL(treeStoreFilesFilter),
1465 					     &parentIter);
1466 	      gtk_tree_view_expand_row(GTK_TREE_VIEW(fileTree), path, TRUE);
1467               /* We select the first. */
1468               /* selectFile(path, iterSelected); */
1469 	      gtk_tree_path_free(path);
1470 	    }
1471 	}
1472       g_object_unref(data);
1473     }
1474 
1475   if (data)
1476     return TRUE;
1477   else
1478     return FALSE;
1479 }
1480 
1481 static gboolean checkFile(GtkTreeModel *model, GtkTreePath *path _U_,
1482 			  GtkTreeIter *iter, gpointer data)
1483 {
1484   gboolean filterOk, valid;
1485   GtkTreeIter iterList;
1486   GtkTreeStore *tree;
1487 
1488   /* If we check the row, the checkbutton is on only
1489      if the name is in accordance with the filter. */
1490   gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter),
1491 						   &iterList, iter);
1492   tree = GTK_TREE_STORE(gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(treeStoreFilesFilter)));
1493   if (GPOINTER_TO_INT(data))
1494     {
1495       gtk_tree_model_get(GTK_TREE_MODEL(model), iter,
1496 			 COLUMN_ACTIVE, &filterOk, COLUMN_FILE_VALID, &valid, -1);
1497 
1498       if (filterOk && valid)
1499 	gtk_tree_store_set(tree, &iterList, COLUMN_BOOLEAN,
1500 			   TRUE, -1);
1501 /*       else */
1502 /* 	gtk_tree_store_set(tree, &iterList, COLUMN_BOOLEAN, */
1503 /* 			   FALSE, -1); */
1504     }
1505   else
1506     {
1507       gtk_tree_store_set(tree, &iterList, COLUMN_BOOLEAN,
1508 			 FALSE, -1);
1509     }
1510   return FALSE;
1511 }
1512 
1513 void visu_ui_panel_browser_setCurrentDirectory(const gchar *dir)
1514 {
1515   g_return_if_fail(dir && dir[0]);
1516 
1517   if (currentBrowseredDirectory)
1518     DBG_fprintf(stderr, "Panel Browser: compare dirs '%s' and '%s'.\n",
1519 		currentBrowseredDirectory[0], dir);
1520 
1521   /* Test if the new directory is not already the current one. */
1522   if (currentBrowseredDirectory && currentBrowseredDirectory[0] &&
1523       !strcmp(currentBrowseredDirectory[0], dir) && !currentBrowseredDirectory[1])
1524     return;
1525 
1526   /* Set the new directory current. */
1527   currentBrowseredDirectory = g_malloc(sizeof(gchar*) * 2);
1528   currentBrowseredDirectory[0] = g_strdup(dir);
1529   currentBrowseredDirectory[1] = (gchar*)0;
1530   DBG_fprintf(stderr, "Panel Browser: set currentBrowseredDirectory to '%s'.\n",
1531 	      currentBrowseredDirectory[0]);
1532   if (commonBrowseredDirectory)
1533     g_free(commonBrowseredDirectory);
1534   commonBrowseredDirectory = tool_path_normalize(dir);
1535   DBG_fprintf(stderr, "Panel Browser: set common path to '%s'.\n",
1536 	      commonBrowseredDirectory);
1537 
1538   /* Save the new list of current directories. */
1539   updateHistory();
1540 
1541   /* Refresh the list if visible, else let the page-enter
1542      signal do it. */
1543   DBG_fprintf(stderr, "Panel Browser: ask for refresh.\n");
1544   if (visu_ui_panel_getVisible(VISU_UI_PANEL(panelBrowser)))
1545     browseDirectory();
1546   else
1547     dirDirty = TRUE;
1548 
1549   visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(),
1550                                     commonBrowseredDirectory, VISU_UI_DIR_BROWSER);
1551 }
1552 static void setCurrentDirectories(gchar **dirs)
1553 {
1554   int i, j;
1555   gchar *tmp;
1556 
1557   /* Set the new directory current. */
1558   currentBrowseredDirectory = dirs;
1559 
1560   DBG_fprintf(stderr, "Panel Browser: set currentBrowseredDirectory to the list:\n");
1561   /* Try to find a common path for all directories. */
1562   if (commonBrowseredDirectory)
1563     g_free(commonBrowseredDirectory);
1564   commonBrowseredDirectory = g_strdup(dirs[0]);
1565   for (i = 0; dirs[i]; i++)
1566     {
1567       DBG_fprintf(stderr, " | '%s'\n", dirs[i]);
1568       for (j = 0; dirs[i][j] && commonBrowseredDirectory[j]; j++)
1569 	if (dirs[i][j] != commonBrowseredDirectory[j])
1570 	  commonBrowseredDirectory[j] = '\0';
1571     }
1572   tmp = commonBrowseredDirectory;
1573   commonBrowseredDirectory = tool_path_normalize(tmp);
1574   g_free(tmp);
1575   DBG_fprintf(stderr, "Panel Browser: set common path to '%s'.\n",
1576 	      commonBrowseredDirectory);
1577 
1578   /* Refresh the list if visible, else let the page-enter
1579      signal do it. */
1580   if (visu_ui_panel_getVisible(VISU_UI_PANEL(panelBrowser)))
1581     browseDirectory();
1582   else
1583     dirDirty = TRUE;
1584 
1585   visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(),
1586                                     commonBrowseredDirectory, VISU_UI_DIR_BROWSER);
1587 }
1588 static void updateHistory()
1589 {
1590   GList *tmpLst, *del;
1591 
1592   g_return_if_fail(currentBrowseredDirectory);
1593 
1594   DBG_fprintf(stderr, "Panel Browser: update the history.\n");
1595 
1596   /* We kill the history between historyBrowseredDirectory and
1597      currentHistory. */
1598   tmpLst = historyBrowseredDirectory;
1599   while (tmpLst != currentHistory)
1600     {
1601       DBG_fprintf(stderr, "Panel Browser: removing a group of"
1602 		  " directories from history.\n");
1603       g_strfreev((gchar**)tmpLst->data);
1604       del = tmpLst;
1605       tmpLst = g_list_next(tmpLst);
1606       g_list_free_1(del);
1607     }
1608   if (currentHistory)
1609     currentHistory->prev = (GList*)0;
1610   historyBrowseredDirectory = currentHistory;
1611   DBG_fprintf(stderr, "Panel Browser: adding a group of"
1612 	      " directories to history.\n");
1613   historyBrowseredDirectory = g_list_prepend(historyBrowseredDirectory,
1614 					     currentBrowseredDirectory);
1615   currentHistory = historyBrowseredDirectory;
1616   DBG_fprintf(stderr, "Panel Browser: set current history to %p (%d).\n",
1617 	      (gpointer)currentHistory, g_list_length(currentHistory));
1618 
1619   if (buttonDirPrev) gtk_widget_set_sensitive(buttonDirPrev, TRUE);
1620   if (buttonDirNext) gtk_widget_set_sensitive(buttonDirNext, FALSE);
1621 
1622   DBG_fprintf(stderr, "Panel Browser: history updated OK.\n");
1623 
1624   updateDirectionalTooltips();
1625 }
1626 void visu_ui_panel_browser_setCurrentDirectories(gchar **dirs)
1627 {
1628   g_return_if_fail(dirs && dirs[0]);
1629 
1630   /* Change the current directories. */
1631   setCurrentDirectories(dirs);
1632 
1633   /* Save the new list of current directories. */
1634   updateHistory();
1635   DBG_fprintf(stderr, "Panel Browser: directories updated OK.\n");
1636 }
1637 static void updateDirectionalTooltips()
1638 {
1639   GString *lbl;
1640   int i;
1641   gchar **history;
1642 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12
1643   GtkTooltips *tooltips;
1644 
1645   tooltips = gtk_tooltips_new ();
1646 #endif
1647 
1648   DBG_fprintf(stderr, "Panel Browser: update directional tooltips.\n");
1649 
1650   if (currentHistory && currentHistory->prev && buttonDirNext)
1651     {
1652       history = (gchar**)(currentHistory->prev->data);
1653 
1654       lbl = g_string_new(_(HISTORY_TOOLTIP_NEXT));
1655       if (history)
1656 	{
1657 	  g_string_append_printf(lbl, "\n\n(%s", history[0]);
1658 	  for (i = 1; history[i]; i++)
1659 	    g_string_append_printf(lbl, ", %s", history[i]);
1660 	  g_string_append_printf(lbl, ")");
1661 	}
1662       gtk_widget_set_tooltip_text(buttonDirNext, lbl->str);
1663       g_string_free(lbl, TRUE);
1664     }
1665   if (currentHistory && currentHistory->next && buttonDirPrev)
1666     {
1667       history = (gchar**)(currentHistory->next->data);
1668 
1669       lbl = g_string_new(_(HISTORY_TOOLTIP_PREV));
1670       if (history)
1671 	{
1672 	  g_string_append_printf(lbl, "\n\n(%s", history[0]);
1673 	  for (i = 1; history[i]; i++)
1674 	    g_string_append_printf(lbl, ", %s", history[i]);
1675 	  g_string_append_printf(lbl, ")");
1676 	}
1677       gtk_widget_set_tooltip_text(buttonDirPrev, lbl->str);
1678       g_string_free(lbl, TRUE);
1679     }
1680 }
1681 gboolean panelBrowserSet_previousHistoryDirectories()
1682 {
1683   if (!currentHistory || !g_list_next(currentHistory))
1684     return FALSE;
1685 
1686   currentHistory = g_list_next(currentHistory);
1687   DBG_fprintf(stderr, "Panel Browser: set current history to %p (%d).\n",
1688 	      (gpointer)currentHistory, g_list_length(currentHistory));
1689 
1690   setCurrentDirectories((gchar**)(currentHistory->data));
1691   updateDirectionalTooltips();
1692 
1693   gtk_widget_set_sensitive(buttonDirPrev, g_list_next(currentHistory) != (gpointer)0);
1694   gtk_widget_set_sensitive(buttonDirNext, TRUE);
1695 
1696   return TRUE;
1697 }
1698 gboolean panelBrowserSet_nextHistoryDirectories()
1699 {
1700   if (!currentHistory || !g_list_previous(currentHistory))
1701     return FALSE;
1702 
1703   currentHistory = g_list_previous(currentHistory);
1704   DBG_fprintf(stderr, "Panel Browser: set current history to %p (%d).\n",
1705 	      (gpointer)currentHistory, g_list_length(currentHistory));
1706 
1707   setCurrentDirectories((gchar**)(currentHistory->data));
1708   updateDirectionalTooltips();
1709 
1710   gtk_widget_set_sensitive(buttonDirPrev, TRUE);
1711   gtk_widget_set_sensitive(buttonDirNext, g_list_previous(currentHistory) != (gpointer)0);
1712 
1713   return TRUE;
1714 }
1715 
1716 static void associateFiles(int nbKind, int commonPathLen)
1717 {
1718   gboolean valid;
1719   GtkTreeIter iter;
1720   int kind, searchKind, i;
1721   gchar *filename, *searchName, *pt, *fileUTF8;
1722   GList *tmpLst, *storeLst;
1723   gsize lu, ecrit;
1724   gchar **ext;
1725 
1726   /* Read all the stored files and try to associate them on their names.
1727      When the name matches the previous one without the extension, then the kind
1728      is stored. If a full set of names can be retrieved, then it is stored. The
1729      extensions are stored in the ext array. */
1730   searchName = g_strdup(".");
1731   searchKind = 0;
1732   storeLst = (GList*)0;
1733   ext = g_malloc(sizeof(gchar*) * (nbKind + 1));
1734   memset(ext, 0, sizeof(gchar*) * (nbKind + 1));
1735   for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treeStoreFiles), &iter);
1736        valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(treeStoreFiles), &iter))
1737     {
1738       gtk_tree_model_get(GTK_TREE_MODEL(treeStoreFiles), &iter,
1739 			 COLUMN_FILE_KIND, &kind, COLUMN_NAME, &filename, -1);
1740       pt = strrchr(filename, '.');
1741       if (pt)
1742 	*pt = '\0';
1743       if (kind >= 0 && kind < nbKind)
1744 	ext[kind] = g_strdup(pt + 1);
1745 /*       fprintf(stderr, "'%s' %d %d\n", filename, kind, searchKind); */
1746       if (kind >= 0 && kind < nbKind && !strcmp(searchName, filename))
1747 	{
1748 	  /* Ok, match, we continue. */
1749 	  searchKind += kind;
1750 	  g_free(filename);
1751 	  if (searchKind == nbKind * (nbKind - 1) / 2)
1752 	    {
1753 	      pt = g_strjoinv(",", ext);
1754 	      /* We found a complete set. */
1755 	      storeLst =
1756 		g_list_prepend(storeLst, g_markup_printf_escaped("%s<span size=\"smaller\" foreground=\"grey\">.[%s]</span>", searchName, pt));
1757 	      g_free(pt);
1758 	      for (i = 0; i < nbKind; i++)
1759 		g_free(ext[i]);
1760 	      memset(ext, 0, sizeof(gchar*) * (nbKind + 1));
1761 	    }
1762 	}
1763       else
1764 	{
1765 	  /* Doesn't match, try for new. */
1766 	  g_free(searchName);
1767 	  for (i = 0; i < nbKind; i++)
1768 	    if (ext[i])
1769 	      g_free(ext[i]);
1770 	  memset(ext, 0, sizeof(gchar*) * (nbKind + 1));
1771 	  searchName = filename;
1772 	  searchKind = kind;
1773 	  if (kind >= 0 && kind < nbKind)
1774 	    ext[kind] = g_strdup(pt + 1);
1775 	}
1776     }
1777   g_free(searchName);
1778   /* Store now the associated list. */
1779   for (tmpLst = storeLst; tmpLst; tmpLst = g_list_next(tmpLst))
1780     {
1781       fileUTF8 = g_filename_to_utf8((gchar*)tmpLst->data + commonPathLen + 1,
1782 				    -1, &lu, &ecrit, NULL);
1783       pt = g_strrstr((gchar*)tmpLst->data, "<span ");
1784       *pt = '\0';
1785 /*       fprintf(stderr, "Panel Browser: found association for '%s'.\n", fileUTF8); */
1786 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9
1787       gtk_tree_store_insert_with_values(treeStoreFiles, &iter, (GtkTreeIter*)0, 0,
1788 					COLUMN_BOOLEAN, FALSE,
1789 					COLUMN_NAME, tmpLst->data,
1790 					COLUMN_NAME_UTF8, fileUTF8,
1791 					COLUMN_ACTIVE, TRUE,
1792 					COLUMN_FILE_KIND, nbKind,
1793 					COLUMN_FILE_VALID, TRUE,
1794 					-1);
1795 #else
1796       gtk_tree_store_prepend(treeStoreFiles, &iter, (GtkTreeIter*)0);
1797       gtk_tree_store_set(treeStoreFiles, &iter,
1798 			 COLUMN_BOOLEAN, FALSE,
1799 			 COLUMN_NAME, tmpLst->data,
1800 			 COLUMN_NAME_UTF8, fileUTF8,
1801 			 COLUMN_ACTIVE, TRUE,
1802 			 COLUMN_FILE_KIND, nbKind,
1803 			 COLUMN_FILE_VALID, TRUE,
1804 			 -1);
1805 #endif
1806       g_free(tmpLst->data);
1807       if (fileUTF8)
1808 	g_free(fileUTF8);
1809     }
1810   g_list_free(storeLst);
1811 }
1812 
1813 static void browseDirectory()
1814 {
1815   GDir *gdir;
1816   gint len;
1817   int i;
1818   GList *atFmt, *spFmt;
1819   gint atKind, spKind;
1820   gboolean success;
1821   struct TimerInfo_ info;
1822 
1823   if (!currentBrowseredDirectory)
1824     return;
1825 
1826   dirDirty = FALSE;
1827 
1828   atFmt = spFmt = (GList*)0;
1829   atKind = spKind = -1;
1830   switch (gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter)))
1831     {
1832     case 0:
1833       atKind = 0;
1834       atFmt = visu_data_atomic_class_getLoaders();
1835       break;
1836     case 1:
1837       atFmt = visu_data_atomic_class_getLoaders();
1838       spFmt = visu_data_spin_class_getLoaders();
1839       atKind = 2;
1840       spKind = 3;
1841       break;
1842     case 2:
1843       atFmt = visu_data_atomic_class_getLoaders();
1844       atKind = 2;
1845       break;
1846     case 3:
1847       spFmt = visu_data_spin_class_getLoaders();
1848       spKind = 3;
1849       break;
1850     default:
1851       break;
1852     }
1853   if (!atFmt && !spFmt)
1854     return;
1855 
1856   DBG_fprintf(stderr, "Panel browser: cleaning of the list.\n");
1857   gtk_tree_store_clear(treeStoreFiles);
1858 
1859   /* Remove temporary the model. */
1860   gtk_tree_view_set_model(GTK_TREE_VIEW(fileTree),
1861 			  (GtkTreeModel*)0);
1862   gtk_widget_set_sensitive(scrolledwindow1, FALSE);
1863 
1864   /* Add a timeout to show the progress bar if the scan is too long. */
1865   info.abort   = FALSE;
1866   info.nbFiles = 0;
1867   info.bt      = (GtkWidget*)0;
1868 #if GLIB_MINOR_VERSION < 13
1869   info.timer   = g_timeout_add(1000, showProgressBar, (gpointer)(&info));
1870 #else
1871   info.timer   = g_timeout_add_seconds(1, showProgressBar, (gpointer)(&info));
1872 #endif
1873   info.label   = 0;
1874 
1875   success = TRUE;
1876   len = strlen(commonBrowseredDirectory);
1877   for (i = 0; success && currentBrowseredDirectory[i] && !info.abort; i++)
1878     {
1879       DBG_fprintf(stderr, "Panel browser: scanning directory '%s'.\n",
1880 		  currentBrowseredDirectory[i]);
1881       gdir = g_dir_open(currentBrowseredDirectory[i], 0, NULL);
1882       if (gdir)
1883 	{
1884 	  addParsedDirectory(len, currentBrowseredDirectory[i], gdir,
1885 			     gtk_toggle_button_get_active
1886 			     (GTK_TOGGLE_BUTTON(buttonRecurse)),
1887 			     atFmt, atKind, spFmt, spKind, &info);
1888 	  g_dir_close(gdir);
1889 	}
1890       else
1891 	success = FALSE;
1892     }
1893   hideProgressBar(&info);
1894 
1895   panelBrowserSet_labelCurrentDir();
1896 
1897   if (gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter)) == 1)
1898     associateFiles(2, len);
1899 
1900   onFilterChanged(GTK_EDITABLE(entryFilterBrowser), (gpointer)0);
1901 
1902   /* Reattach the model. */
1903   gtk_tree_view_set_model(GTK_TREE_VIEW(fileTree), GTK_TREE_MODEL(treeStoreFilesFilter));
1904   gtk_widget_set_sensitive(scrolledwindow1, TRUE);
1905 
1906   if (!success)
1907     visu_ui_raiseWarning(_("Browsing a directory"),
1908 			 _("The specified directory is unreadable."),
1909 			 (GtkWindow*)0);
1910 }
1911 
1912 static void addParsedDirectory(int commonPathLen, const gchar *root,
1913 			       GDir *gdir, gboolean recurse,
1914                                GList *atFmt, gint atKind, GList *spFmt, gint spKind,
1915 			       struct TimerInfo_ *timer)
1916 {
1917   const gchar *fileFromDir;
1918   gchar *fileUTF8, *file;
1919   gint kind;
1920   gsize lu, ecrit;
1921   GDir *recursedDir;
1922   GtkTreeIter iter;
1923   GList *lst;
1924 #if GLIB_MINOR_VERSION > 5
1925   struct stat buf;
1926   struct tm *tm;
1927   gchar data[256];
1928 #endif
1929 
1930   g_return_if_fail(root && root[0]);
1931   DBG_fprintf(stderr, "Panel Browser: read dir '%s' %d.\n", root, (int)recurse);
1932   fileFromDir = g_dir_read_name(gdir);
1933   while(fileFromDir && !timer->abort)
1934     {
1935       file = g_build_filename(root, fileFromDir, NULL);
1936       fileUTF8 = g_filename_to_utf8(file + commonPathLen + 1,
1937 				    -1, &lu, &ecrit, NULL);
1938 
1939       if(fileUTF8)
1940 	{
1941 	  if (g_file_test(file, G_FILE_TEST_IS_DIR))
1942 	    {
1943 	      DBG_fprintf(stderr, "Panel Browser: read dir '%s'\n", file);
1944 	      if (recurse)
1945 		{
1946 		  recursedDir = g_dir_open(file, 0, NULL);
1947 		  if (recursedDir)
1948 		    {
1949 		      addParsedDirectory(commonPathLen, file, recursedDir, TRUE,
1950 					 atFmt, atKind, spFmt, spKind, timer);
1951 		      g_dir_close(recursedDir);
1952 		    }
1953 		}
1954 	    }
1955 	  else
1956 	    {
1957 	      kind = -1;
1958 	      for (lst = atFmt; lst && kind < 0; lst = g_list_next(lst))
1959                 if (tool_file_format_validate(TOOL_FILE_FORMAT(lst->data), fileUTF8))
1960                   kind = atKind;
1961 	      for (lst = spFmt; lst && kind < 0; lst = g_list_next(lst))
1962                 if (tool_file_format_validate(TOOL_FILE_FORMAT(lst->data), fileUTF8))
1963                   kind = spKind;
1964 #if GLIB_MINOR_VERSION > 5
1965 	      if (showDate)
1966 		{
1967 		  if (g_stat(file, &buf))
1968 		    buf.st_mtime = 0;
1969 		  DBG_fprintf(stderr, "Panel Browser: mtime %d.\n", (int)buf.st_mtime);
1970 		  tm = localtime(&buf.st_mtime);
1971 		  strftime(data, 256, _("%Y-%m-%d %H:%M"), tm);
1972 		}
1973 	      else
1974 		{
1975 		  buf.st_mtime = 0;
1976 		  data[0] = '\0';
1977 		}
1978 #endif
1979 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 9
1980 	      gtk_tree_store_insert_with_values(treeStoreFiles, &iter,
1981 						(GtkTreeIter*)0, 0,
1982 						COLUMN_BOOLEAN, FALSE,
1983 						COLUMN_NAME, file,
1984 						COLUMN_NAME_UTF8, fileUTF8,
1985 						COLUMN_ACTIVE, TRUE,
1986                                                 COLUMN_FILE_KIND, kind,
1987 						COLUMN_FILE_VALID, (kind >= 0),
1988 #if GLIB_MINOR_VERSION > 5
1989 						COLUMN_DATE, buf.st_mtime,
1990 						COLUMN_DATA, data,
1991 #endif
1992 						-1);
1993 #else
1994 	      gtk_tree_store_append(treeStoreFiles, &iter, (GtkTreeIter*)0);
1995 	      gtk_tree_store_set(treeStoreFiles, &iter,
1996 				 COLUMN_BOOLEAN, FALSE,
1997 				 COLUMN_NAME, file,
1998 				 COLUMN_NAME_UTF8, fileUTF8,
1999                                  COLUMN_FILE_KIND, kind,
2000 				 COLUMN_ACTIVE, TRUE,
2001 				 COLUMN_FILE_VALID, (kind >= 0),
2002 #if GLIB_MINOR_VERSION > 5
2003 				 COLUMN_DATE, buf.st_mtime,
2004 				 COLUMN_DATA, data,
2005 #endif
2006 				 -1);
2007 #endif
2008 	      timer->nbFiles += 1;
2009 	    }
2010 	  g_free(fileUTF8);
2011 	}
2012       g_free(file);
2013       visu_ui_wait();
2014       fileFromDir = g_dir_read_name(gdir);
2015     }
2016 }
2017 
2018 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17
2019 static void onParseAbortClicked(GtkButton *button _U_, gpointer data)
2020 {
2021   (*(gboolean*)data) = TRUE;
2022 }
2023 #else
2024 static void onParseAbortClicked(GtkInfoBar *infoBar _U_, gint response,
2025 				gpointer data)
2026 {
2027   (*(gboolean*)data) = (response == GTK_RESPONSE_CANCEL);
2028 }
2029 #endif
2030 
2031 static void onEnter(VisuUiPanel *visu_ui_panel _U_, gpointer data _U_)
2032 {
2033   DBG_fprintf(stderr, "Panel Browser: enter, parse directory (%d).\n",
2034 	      !fileTree);
2035   if (!fileTree)
2036     createInteriorBrowser();
2037   if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(treeStoreFiles), (GtkTreeIter*)0) == 0 || dirDirty)
2038     browseDirectory();
2039 }
2040 
2041 static void onDirectoryClicked(GtkButton *button _U_, gpointer data _U_)
2042 {
2043   gchar **filenames;
2044 
2045   filenames = visu_ui_main_getSelectedDirectory
2046     (visu_ui_main_class_getCurrentPanel(),
2047      visu_ui_panel_getContainerWindow(VISU_UI_PANEL(panelBrowser)),
2048      TRUE, commonBrowseredDirectory);
2049 
2050   if (!filenames)
2051     return;
2052 
2053   visu_ui_panel_browser_setCurrentDirectories(filenames);
2054 }
2055 
2056 static void onRecurseToggled(GtkToggleButton *toggle _U_, gpointer data _U_)
2057 {
2058   browseDirectory();
2059 }
2060 
2061 static void onPrevClicked(GtkButton *button _U_, gpointer data _U_)
2062 {
2063   panelBrowserSet_previousHistoryDirectories();
2064 }
2065 static void onNextClicked(GtkButton *button _U_, gpointer data _U_)
2066 {
2067   panelBrowserSet_nextHistoryDirectories();
2068 }
2069 
2070 static gboolean pulseProgressBar(gpointer data)
2071 {
2072   struct TimerInfo_ *timer;
2073   gchar nbFilesLabel[36];
2074 
2075   timer = (struct TimerInfo_*)data;
2076   sprintf(nbFilesLabel, _("%4d files found."), timer->nbFiles);
2077   gtk_label_set_text(GTK_LABEL(labelInfo), nbFilesLabel);
2078   DBG_fprintf(stderr, "Panel browser: update label to '%s'.\n", nbFilesLabel);
2079 
2080   return TRUE;
2081 }
2082 static gboolean showProgressBar(gpointer data)
2083 {
2084   gchar nbFilesLabel[36];
2085   struct TimerInfo_ *timer;
2086 
2087   DBG_fprintf(stderr, "Panel browser: scanning is too slow, showing progress bar.\n");
2088 
2089   timer = (struct TimerInfo_*)data;
2090 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 17
2091   timer->bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
2092   gtk_box_pack_end(GTK_BOX(infoBar), timer->bt, FALSE, FALSE, 0);
2093   g_signal_connect(G_OBJECT(timer->bt), "clicked",
2094 		   G_CALLBACK(onParseAbortClicked), (gpointer)&timer->abort);
2095 #else
2096   timer->bt = gtk_info_bar_add_button(GTK_INFO_BAR(infoBar),
2097 				      TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL);
2098   g_signal_connect(G_OBJECT(infoBar), "response",
2099 		   G_CALLBACK(onParseAbortClicked), (gpointer)&timer->abort);
2100 #endif
2101 
2102   sprintf(nbFilesLabel, _("%4d files found."), timer->nbFiles);
2103   visu_ui_panel_browser_setMessage(nbFilesLabel, GTK_MESSAGE_INFO);
2104 
2105   timer->label = g_timeout_add(250, pulseProgressBar, data);
2106 
2107   return FALSE;
2108 }
2109 static void hideProgressBar(struct TimerInfo_ *timer)
2110 {
2111   DBG_fprintf(stderr, "Panel browser: scanning is finished, hiding progress bar.\n");
2112 
2113   g_source_remove(timer->timer);
2114   if (timer->label)
2115     {
2116       g_source_remove(timer->label);
2117       visu_ui_panel_browser_setMessage((const gchar*)0, GTK_MESSAGE_INFO);
2118     }
2119   if (timer->bt)
2120     gtk_widget_destroy(timer->bt);
2121 }
2122 
2123 
2124 /***************************/
2125 /* Miscellaneous functions */
2126 /***************************/
2127 
2128 gboolean gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *last, GtkTreePath **path)
2129 {
2130   gboolean valid;
2131   gint n;
2132 
2133   g_return_val_if_fail(model && last, FALSE);
2134 
2135   n = gtk_tree_model_iter_n_children(model, (GtkTreeIter*)0);
2136   if (n == 0)
2137     return FALSE;
2138 
2139   valid = gtk_tree_model_iter_nth_child(model, last, (GtkTreeIter*)0, n - 1);
2140   g_return_val_if_fail(valid, FALSE);
2141 
2142   if (path)
2143     *path = gtk_tree_model_get_path(model, last);
2144 
2145   return TRUE;
2146 }
2147 
2148 static gboolean panelBrowserIsIterVisible(GtkTreeModel *model, GtkTreeIter *iter,
2149 					  gpointer data _U_)
2150 {
2151   gboolean passUserFilter;
2152   gint kind;
2153 
2154   gtk_tree_model_get(model, iter,
2155 		     COLUMN_FILE_KIND, &kind,
2156 		     COLUMN_ACTIVE, &passUserFilter,
2157 		     -1);
2158   return (passUserFilter && (kind == gtk_combo_box_get_active(GTK_COMBO_BOX(comboFilter)) || kind < 0));
2159 }
2160 
2161 static gint onSortNames(GtkTreeModel *model, GtkTreeIter *a,
2162 			GtkTreeIter *b, gpointer user_data _U_)
2163 {
2164   gint kindA, kindB;
2165   gchar *lblA, *lblB;
2166   gint diff, iSetA, iSetB;
2167   GtkTreeIter parentA, parentB;
2168 
2169   /* We always sort the kind first. */
2170   gtk_tree_model_get(model, a, COLUMN_FILE_KIND, &kindA, -1);
2171   gtk_tree_model_get(model, b, COLUMN_FILE_KIND, &kindB, -1);
2172 
2173   if ((kindA < 0 && kindB >= 0) || (kindA >= 0 && kindB < 0))
2174     return (kindB - kindA);
2175   else
2176     {
2177       if (gtk_tree_model_iter_parent(model, &parentA, a) &&
2178 	  gtk_tree_model_iter_parent(model, &parentB, b))
2179 	{
2180 	  gtk_tree_model_get(model, a, COLUMN_DATE, &iSetA, -1);
2181 	  gtk_tree_model_get(model, b, COLUMN_DATE, &iSetB, -1);
2182 
2183 	  diff = iSetA - iSetB;
2184 	}
2185       else
2186 	{
2187 	  gtk_tree_model_get(model, a, COLUMN_NAME_UTF8, &lblA, -1);
2188 	  gtk_tree_model_get(model, b, COLUMN_NAME_UTF8, &lblB, -1);
2189 
2190 	  diff = g_utf8_collate(lblA, lblB);
2191 
2192 	  g_free(lblA);
2193 	  g_free(lblB);
2194 	}
2195 
2196       return diff;
2197     }
2198 }
2199 
2200 void panelBrowserSet_labelCurrentDir()
2201 {
2202   gchar *directoryUTF8, *markup;
2203 
2204   if (!commonBrowseredDirectory)
2205     return;
2206 
2207   directoryUTF8 = g_filename_to_utf8(commonBrowseredDirectory, -1, NULL, NULL, NULL);
2208   g_return_if_fail(directoryUTF8);
2209 
2210   markup = g_markup_printf_escaped(_("<span style=\"italic\" size=\"smaller\">%s</span>"),
2211 				   directoryUTF8);
2212   g_free(directoryUTF8);
2213   gtk_label_set_markup(GTK_LABEL(labelDirectory), markup);
2214   g_free(markup);
2215 }
2216 
2217 static void onNewDir(GObject *obj _U_, VisuUiDirectoryType type, gpointer user _U_)
2218 {
2219   DBG_fprintf(stderr, "Panel Browser: caught 'DirectoryChanged'"
2220 	      " signal for type %d.\n", type);
2221   if (type == VISU_UI_DIR_FILE)
2222     visu_ui_panel_browser_setCurrentDirectory(visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel()));
2223 }
2224 
2225 static void exportParameters(GString *data, VisuData *dataObj _U_)
2226 {
2227   g_string_append_printf(data, "# %s\n", DESC_PARAMETER_BROWSER_HEADERS);
2228   g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_BROWSER_HEADERS,
2229 			 (int)showHeaders);
2230   g_string_append_printf(data, "# %s\n", DESC_PARAMETER_BROWSER_DATE);
2231   g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_BROWSER_DATE,
2232 			 (int)showDate);
2233 }
2234 /**
2235  * visu_ui_panel_browser_setMessage:
2236  * @message: a string to be displaied.
2237  * @message_type: the kind of message.
2238  *
2239  * This routine is used to give the user a message. This message can
2240  * be mere information or a warning or an error.
2241  *
2242  * Since: 3.6
2243  */
2244 void visu_ui_panel_browser_setMessage(const gchar* message, GtkMessageType message_type)
2245 {
2246   if (!fileTree)
2247     createInteriorBrowser();
2248 
2249   if (message)
2250     {
2251       gtk_label_set_text(GTK_LABEL(labelInfo), message);
2252 #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 17
2253       gtk_info_bar_set_message_type(GTK_INFO_BAR(infoBar), message_type);
2254 #else
2255       switch (message_type)
2256 	{
2257 	case GTK_MESSAGE_INFO:
2258 	  gtk_image_set_from_stock(GTK_IMAGE(infoImg),
2259 				   GTK_STOCK_INFO, GTK_ICON_SIZE_BUTTON);
2260 	  break;
2261 	default:
2262 	  gtk_image_clear(GTK_IMAGE(infoImg));
2263 	  break;
2264 	}
2265 #endif
2266       gtk_widget_set_no_show_all(infoBar, FALSE);
2267       gtk_widget_show_all(infoBar);
2268     }
2269   else
2270     {
2271       gtk_widget_hide(infoBar);
2272     }
2273 }
2274