/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2006)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2006)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#include "panelBrowser.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <gtk/gtk.h>

#include <visu_object.h>
#include <visu_tools.h>
#include <visu_rendering.h>
#include <visu_basic.h>
#include <support.h>
#include <extraGtkFunctions/gtk_dumpDialogWidget.h>
#include <renderingBackend/visu_windowInterface.h>
#include <gtk_renderingWindowWidget.h>

subPanel *panelBrowser;

GtkListStore *listStoreFiles;
GtkTreeModel *listStoreFilesFilter;
enum
  {
    COLUMN_BOOLEAN, /* Rendered or not. */
    COLUMN_NAME,  /* File name in locale of the file system. */
    COLUMN_NAME_UTF8,  /* File name in UTF8 (to view it it GTK). */
    COLUMN_DATA,  /* File info (size). */
    COLUMN_ACTIVE, /* A boolean to set if this file is active or not. */
    COLUMN_FILE_KIND, /* An integer that correspond to the file type. */
    N_COLUMNS
  };
GtkWidget *fileTree;
gboolean listLoaded;
GtkWidget *progressbar;
GtkWidget *vBoxWaiting;
GtkWidget *labelWaiting;
GtkWidget *scrolledwindow1;
GtkWidget *labelDirectory;
gboolean flagWorkInProgress;
gboolean flagBarIsShown;
gchar *currentBrowseredDirectory;

GtkWidget *entryFilterBrowser;
enum
  {
    PANEL_BROWSER_COLUMN_FILTER_LABEL,
    PANEL_BROWSER_COLUMN_FILTER_ID,
    PANEL_BROWSER_N_COLUMN_FILTER
  };
GtkListStore *panelBrowserListFilter;
GtkWidget *panelBrowserComboFilter;
gint currentComboFilterValue;

GtkWidget *imagePlay;
GtkWidget *imageStop;
GtkWidget *spinDelay;
guint isPlayingCallbackId;

GtkWidget *buttonPrevious;
GtkWidget *buttonNext;
GtkWidget *buttonSelectAll;
GtkWidget *buttonUnselectAll;
GtkWidget *buttonDirectory;
GtkWidget *buttonPlayStop;
GtkWidget *radioGoAround, *radioGoOnce, *radioGoAndBack;
static int currentBrowseDirection;
static GtkTreePath *startBrowsePath;

GtkWidget *buttonDumpAll;
/* GtkProgressBar *progressBarDump; */


GtkWidget *createInteriorBrowser();
void createCallBacksBrowser();
void browseDirectory(gchar* dir);
gboolean checkFilesOnEnter(gpointer data);
gboolean stopPlayOnLeave(gpointer data);
gboolean showProgressBar(gpointer data);
gboolean browserLoad(gchar *filename);

gboolean gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *last, GtkTreePath **path);
void panelBrowserSet_labelCurrentDir();

/* Callbacks */
gboolean treeViewClicked(GtkWidget *widget, GdkEventButton *event,
			 gpointer user_data);
void treeViewActivated(GtkTreeView *treeview, GtkTreePath *path,
		       GtkTreeViewColumn *col, gpointer user_data);
void navigateClicked(GtkButton *button, gpointer data);
void checkFiles(GtkButton *button, gpointer data);
void clearListFiles(GObject *obj, gpointer data);
void directoryClicked(GtkButton *button, gpointer data);
void playStopClicked(GtkButton *button, gpointer data);
void stopPlayStop(gpointer data);
void onSpinDelayChangeValue(GtkSpinButton *spinbutton,
			    GtkScrollType scroll,
			    gpointer user_data);
void onDumpButtonClicked(GtkButton *button, gpointer user_data);
void filterBrowserChanged(GtkEditable *entry, gpointer user_data);
void abortDumpAll(GtkButton *button, gpointer data);
void updateDumpAllProgressBar(gpointer data);
void onRenderingChangedUpdateFilters(GObject *obj, gpointer data);
gboolean panelBrowserIsIterVisible(GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
void onComboFilterChanged(GtkComboBox *combo, gpointer data);
void onFileLoaded(GObject *obj, VisuData *dataObj, gpointer data);
void onRefreshDir(GtkButton *button, gpointer data);

gboolean navigateInFiles(GtkTreePath *path, GtkTreeIter *iterSelected);


subPanel* initPanelBrowser()
{
  char *cl = _("Browser");
  char *tl = _("Browser");
  GtkWidget *child;
  GtkCellRenderer *renderer;
  GtkTreeViewColumn *column;

  /* Create the list that store the filters. */
  panelBrowserListFilter = gtk_list_store_new(PANEL_BROWSER_N_COLUMN_FILTER,
					      G_TYPE_STRING,
					      G_TYPE_INT);


  child = createInteriorBrowser();
  panelBrowser = createSubPanelWithIconFromStock(cl, tl, GTK_STOCK_INDEX,
						 child, checkFilesOnEnter, stopPlayOnLeave);
  if (!panelBrowser)
    return (subPanel*)0;
						 
  /* Create the tree structure. */
  listStoreFiles = gtk_list_store_new (N_COLUMNS,
				       G_TYPE_BOOLEAN,
				       G_TYPE_STRING,
				       G_TYPE_STRING,
				       G_TYPE_STRING,
				       G_TYPE_BOOLEAN,
				       G_TYPE_INT);
  /* Use the COLUMN_ACTIVE as a flag to hide or not the rows that 
     don't match the filter value. */
  listStoreFilesFilter = gtk_tree_model_filter_new(GTK_TREE_MODEL(listStoreFiles), NULL);
  gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(listStoreFilesFilter),
					 panelBrowserIsIterVisible, (gpointer)0,
					 (GtkDestroyNotify)0);
/*   gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(listStoreFilesFilter), COLUMN_ACTIVE); */

  /* Add a new row to the model */
  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(listStoreFiles),
				       COLUMN_NAME_UTF8, GTK_SORT_ASCENDING);

  renderer = gtk_cell_renderer_toggle_new ();
  column = gtk_tree_view_column_new_with_attributes ("Render",
						     renderer,
						     "active", COLUMN_BOOLEAN,
						     NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column);
  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes ("Filename",
						     renderer,
						     "text", COLUMN_NAME_UTF8,
						     NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column);
/*   renderer = gtk_cell_renderer_text_new (); */
/*   column = gtk_tree_view_column_new_with_attributes ("Data", */
/* 						     renderer, */
/* 						     "text", COLUMN_DATA, */
/* 						     NULL); */
/*   gtk_tree_view_append_column (GTK_TREE_VIEW (fileTree), column); */

  gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree)),
			      GTK_SELECTION_BROWSE);

  /* Initialise the values. */
  currentBrowseredDirectory = (gchar*)0;
  listLoaded = FALSE;
  isPlayingCallbackId = 0;
  currentBrowseDirection = BROWSER_NEXT;

  /* Create the callbacks of all the sensitive widgets. */
  createCallBacksBrowser();

  /* call the visu add routine */
  addSubPanel(panelBrowser);

  return panelBrowser;
}

GtkWidget *createInteriorBrowser()
{
  GtkWidget *vbox1;

  /* include from glade */
  GtkWidget *image2;
  GtkWidget *image3;
  GtkWidget *image1;
  GtkWidget *hbox2;
  GtkWidget *label4;
  GtkObject *spinDelay_adj;
  GtkWidget *label1;
  GtkWidget *hbox3;
  GtkWidget *alignment1;
  GtkWidget *hbox4;
  GtkWidget *hbox5;
  GtkWidget *image4;
  GtkWidget *label3;
  GtkWidget *refreshDirButton;
  GtkTooltips *tooltips;

  GtkWidget *label5;
  GtkWidget *label;
  GtkWidget *hbox, *vbox;
  GtkWidget *hrule;

  GtkCellRenderer *renderer;

  GSList *radiobuttonCycle_group;

  vbox1 = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(vbox1);

  tooltips = gtk_tooltips_new ();

  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
  /* This is a label in the browser panel to introduce the
     entry that allows to enter a filter for files shown. */
  label = gtk_label_new(_("Filter: "));
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
  entryFilterBrowser = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(entryFilterBrowser), TRUE);
  gtk_entry_set_text(GTK_ENTRY(entryFilterBrowser), "*");
  gtk_widget_show(entryFilterBrowser);
  gtk_box_pack_start(GTK_BOX(hbox), entryFilterBrowser, TRUE, TRUE, 0);
  panelBrowserComboFilter = gtk_combo_box_new_with_model(GTK_TREE_MODEL(panelBrowserListFilter));
  renderer = gtk_cell_renderer_text_new();
  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(panelBrowserComboFilter), renderer, FALSE);
  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(panelBrowserComboFilter), renderer,
				"text", PANEL_BROWSER_COLUMN_FILTER_LABEL);
  gtk_widget_show(panelBrowserComboFilter);
  gtk_box_pack_start(GTK_BOX(hbox), panelBrowserComboFilter, FALSE, FALSE, 2);

  /*******************/
  /* File lists part */
  /*******************/
  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox1), hbox, TRUE, TRUE, 0);
  
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_widget_show(vbox);
  gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 2);

  buttonDirectory = gtk_button_new ();
  gtk_widget_show (buttonDirectory);
  gtk_box_pack_start (GTK_BOX (vbox), buttonDirectory, FALSE, FALSE, 2);
  gtk_tooltips_set_tip (tooltips, buttonDirectory, _("Choose a different directory."), NULL);

  image3 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image3);
  gtk_container_add (GTK_CONTAINER (buttonDirectory), image3);

  refreshDirButton = gtk_button_new ();
  gtk_tooltips_set_tip (tooltips, refreshDirButton, _("Rescan current directory."), NULL);
  gtk_widget_show (refreshDirButton);
  gtk_box_pack_start(GTK_BOX(vbox), refreshDirButton, FALSE, FALSE, 2);
  image3 = create_pixmap (mainWindow, "stock-refresh-dir_20.png");
  gtk_widget_show(image3);
  gtk_container_add(GTK_CONTAINER(refreshDirButton), image3);
  g_signal_connect(G_OBJECT(refreshDirButton), "clicked",
		   G_CALLBACK(onRefreshDir), (gpointer)0);

#if GTK_MINOR_VERSION > 5
  label = gtk_label_new(_("Directory tools:"));
  gtk_label_set_angle(GTK_LABEL(label), 90.);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
#endif

  scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_show (scrolledwindow1);
  gtk_box_pack_start (GTK_BOX (hbox), scrolledwindow1, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_ETCHED_IN);

  fileTree = gtk_tree_view_new ();
  gtk_tooltips_set_tip (tooltips, fileTree, _("Double clic on a selected file to render it."), NULL);
  gtk_widget_show (fileTree);
  gtk_container_add (GTK_CONTAINER (scrolledwindow1), fileTree);
  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fileTree), FALSE);

  vBoxWaiting = gtk_vbox_new (FALSE, 0);
/*   gtk_widget_show (vBoxWaiting); */
  gtk_box_pack_start (GTK_BOX (vbox1), vBoxWaiting, TRUE, TRUE, 0);

  label5 = gtk_label_new (_("Please wait, parsing the directory ..."));
  gtk_widget_show (label5);
  gtk_box_pack_start (GTK_BOX (vBoxWaiting), label5, TRUE, TRUE, 0);
  gtk_misc_set_alignment (GTK_MISC (label5), 0.5, 1);

  progressbar = gtk_progress_bar_new ();
  gtk_widget_show (progressbar);
  gtk_box_pack_start (GTK_BOX (vBoxWaiting), progressbar, TRUE, FALSE, 0);

  labelWaiting = gtk_label_new (_("0 files"));
  gtk_widget_show (labelWaiting);
  gtk_box_pack_start (GTK_BOX (vBoxWaiting), labelWaiting, TRUE, TRUE, 0);
  gtk_misc_set_alignment (GTK_MISC (labelWaiting), 0.5, 0);

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_widget_show(vbox);
  gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 2);

  buttonSelectAll = gtk_button_new();
  gtk_tooltips_set_tip(tooltips, buttonSelectAll, _("Select all files."), NULL);
  gtk_widget_show (buttonSelectAll);
  gtk_box_pack_start (GTK_BOX (vbox), buttonSelectAll, FALSE, FALSE, 1);
  image2 = create_pixmap (mainWindow, "stock-select-all_20.png");
  gtk_widget_show (image2);
  gtk_container_add (GTK_CONTAINER (buttonSelectAll), image2);

  buttonUnselectAll = gtk_button_new();
  gtk_tooltips_set_tip(tooltips, buttonUnselectAll, _("Unselect all files."), NULL);
  gtk_widget_show (buttonUnselectAll);
  gtk_box_pack_start(GTK_BOX(vbox), buttonUnselectAll, FALSE, FALSE, 1);
  image2 = create_pixmap (mainWindow, "stock-unselect-all_20.png");
  gtk_widget_show (image2);
  gtk_container_add(GTK_CONTAINER(buttonUnselectAll), image2);

  buttonNext = gtk_button_new ();
  gtk_widget_show (buttonNext);
  gtk_box_pack_end (GTK_BOX (vbox), buttonNext, FALSE, FALSE, 1);
  gtk_tooltips_set_tip (tooltips, buttonNext, _("Render the next selected file."), NULL);

  image1 = gtk_image_new_from_stock ("gtk-go-down", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image1);
  gtk_container_add (GTK_CONTAINER (buttonNext), image1);

  buttonPrevious = gtk_button_new ();
  gtk_widget_show (buttonPrevious);
  gtk_box_pack_end (GTK_BOX (vbox), buttonPrevious, FALSE, FALSE, 1);
  gtk_tooltips_set_tip (tooltips, buttonPrevious, _("Render the previous selected file."), NULL);

  image2 = gtk_image_new_from_stock ("gtk-go-up", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image2);
  gtk_container_add (GTK_CONTAINER (buttonPrevious), image2);

  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
  
  label = gtk_label_new(_("<span size=\"smaller\">Current dir.: </span>"));
  gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  
  labelDirectory = gtk_label_new("");
  gtk_label_set_use_markup(GTK_LABEL(labelDirectory), TRUE);
  gtk_misc_set_alignment(GTK_MISC(labelDirectory), 0., 0.5);
#if GTK_MINOR_VERSION > 5
  gtk_label_set_ellipsize(GTK_LABEL(labelDirectory), PANGO_ELLIPSIZE_START);
#endif
  gtk_widget_show(labelDirectory);
  gtk_box_pack_start(GTK_BOX(hbox), labelDirectory, TRUE, TRUE, 0);
  panelBrowserSet_labelCurrentDir();

  /***************/
  /* Action part */
  /***************/
  alignment1 = gtk_alignment_new(0.5, 0.5, 0.3, 0);
  gtk_widget_show(alignment1);
  gtk_box_pack_start(GTK_BOX(vbox1), alignment1, FALSE, FALSE, 2);

  hrule = gtk_hseparator_new();
  gtk_widget_show(hrule);
  gtk_container_add(GTK_CONTAINER(alignment1), hrule);

  hbox2 = gtk_hbox_new (FALSE, 0);
  gtk_widget_show (hbox2);
  gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, TRUE, 1);

  alignment1 = gtk_alignment_new(0.5, 0.5, 1.0, 0.0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(alignment1), 0, 0, 0, 5);
  gtk_widget_show(alignment1);
  gtk_box_pack_start(GTK_BOX(hbox2), alignment1, FALSE, FALSE, 0);

  hbox5 = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox5);
  gtk_container_add(GTK_CONTAINER(alignment1), hbox5);
  
  radioGoAround = gtk_radio_button_new(NULL);
  gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoAround), (GSList*)0);
  radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoAround));
  gtk_widget_show(radioGoAround);
  gtk_box_pack_start(GTK_BOX(hbox5), radioGoAround, FALSE, FALSE, 0);
  image1 = create_pixmap(mainWindow, "stock-go-around.png");
  gtk_widget_show (image1);
  gtk_container_add(GTK_CONTAINER(radioGoAround), image1);

  radioGoOnce = gtk_radio_button_new(NULL);
  gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoOnce), radiobuttonCycle_group);
  radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoOnce));
  gtk_widget_show(radioGoOnce);
  gtk_box_pack_start(GTK_BOX(hbox5), radioGoOnce, FALSE, FALSE, 0);
  image1 = create_pixmap(mainWindow, "stock-go-once.png");
  gtk_widget_show (image1);
  gtk_container_add(GTK_CONTAINER(radioGoOnce), image1);

  radioGoAndBack = gtk_radio_button_new(NULL);
  gtk_radio_button_set_group(GTK_RADIO_BUTTON(radioGoAndBack), radiobuttonCycle_group);
  radiobuttonCycle_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radioGoAndBack));
  gtk_widget_show(radioGoAndBack);
  gtk_box_pack_start(GTK_BOX(hbox5), radioGoAndBack, FALSE, FALSE, 0);
  image1 = create_pixmap(mainWindow, "stock-go-and-back.png");
  gtk_widget_show (image1);
  gtk_container_add(GTK_CONTAINER(radioGoAndBack), image1);

  label4 = gtk_label_new (_("Play at "));
  gtk_widget_show (label4);
  gtk_box_pack_start (GTK_BOX (hbox2), label4, TRUE, TRUE, 0);
  gtk_misc_set_alignment (GTK_MISC (label4), 1, 0.5);

  spinDelay_adj = gtk_adjustment_new (500, 10, 10000, 25, 100, 100);
  spinDelay = gtk_spin_button_new (GTK_ADJUSTMENT (spinDelay_adj), 1, 0);
  gtk_widget_show (spinDelay);
  gtk_box_pack_start (GTK_BOX (hbox2), spinDelay, FALSE, TRUE, 0);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinDelay), TRUE);

  /* Units: milliseconds */
  label1 = gtk_label_new (_(" ms"));
  gtk_widget_show (label1);
  gtk_box_pack_start (GTK_BOX (hbox2), label1, TRUE, TRUE, 0);
  gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5);

  buttonPlayStop = gtk_button_new ();
  gtk_tooltips_set_tip (tooltips, buttonPlayStop, _("Cycle through the selected files at the given rate."), NULL);
  gtk_widget_show (buttonPlayStop);
  gtk_box_pack_start (GTK_BOX (hbox2), buttonPlayStop, FALSE, FALSE, 5);

  hbox5 = gtk_hbox_new (FALSE, 0);
  gtk_widget_show (hbox5);
  gtk_container_add (GTK_CONTAINER (buttonPlayStop), hbox5);

  imagePlay = create_pixmap (mainWindow, "stock_media-play.png");
  gtk_widget_show (imagePlay);
  gtk_box_pack_start (GTK_BOX (hbox5), imagePlay, TRUE, TRUE, 0);

  imageStop = create_pixmap (mainWindow, "stock_media-stop.png");
  gtk_box_pack_start (GTK_BOX (hbox5), imageStop, TRUE, TRUE, 0);

  hbox3 = gtk_hbox_new (FALSE, 0);
  gtk_widget_show (hbox3);
  gtk_box_pack_start (GTK_BOX (vbox1), hbox3, FALSE, TRUE, 1);

  buttonDumpAll = gtk_button_new ();
  gtk_widget_show (buttonDumpAll);
  gtk_box_pack_start (GTK_BOX (hbox3), buttonDumpAll, TRUE, FALSE, 0);
  gtk_tooltips_set_tip (tooltips, buttonDumpAll, _("Export the rendering of all selected files in other formats."), NULL);

  alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_widget_show (alignment1);
  gtk_container_add (GTK_CONTAINER (buttonDumpAll), alignment1);

  hbox4 = gtk_hbox_new (FALSE, 2);
  gtk_widget_show (hbox4);
  gtk_container_add (GTK_CONTAINER (alignment1), hbox4);

  image4 = gtk_image_new_from_stock ("gtk-save-as", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image4);
  gtk_box_pack_start (GTK_BOX (hbox4), image4, FALSE, FALSE, 0);

  label3 = gtk_label_new_with_mnemonic (_("Export all selected files"));
  gtk_widget_show (label3);
  gtk_box_pack_start (GTK_BOX (hbox4), label3, FALSE, FALSE, 0);

  return vbox1;
}

void createCallBacksBrowser()
{
  g_signal_connect(G_OBJECT(fileTree), "button-release-event",
		   G_CALLBACK(treeViewClicked), (gpointer)0);
  g_signal_connect(G_OBJECT(fileTree), "row-activated",
		   G_CALLBACK(treeViewActivated), (gpointer)0);
  g_signal_connect(G_OBJECT(buttonPrevious), "clicked",
		   G_CALLBACK(navigateClicked), (gpointer)BROWSER_PREVIOUS);
  g_signal_connect(G_OBJECT(buttonNext), "clicked",
		   G_CALLBACK(navigateClicked), (gpointer)BROWSER_NEXT);
  g_signal_connect(G_OBJECT(buttonSelectAll), "clicked",
		   G_CALLBACK(checkFiles), (gpointer)1);
  g_signal_connect(G_OBJECT(buttonUnselectAll), "clicked",
		   G_CALLBACK(checkFiles), (gpointer)0);
  g_signal_connect(G_OBJECT(buttonDirectory), "clicked",
		   G_CALLBACK(directoryClicked), (gpointer)0);
  g_signal_connect(G_OBJECT(buttonPlayStop), "clicked",
		   G_CALLBACK(playStopClicked), (gpointer)0);
  g_signal_connect(G_OBJECT(spinDelay), "value-changed",
		   G_CALLBACK(onSpinDelayChangeValue), (gpointer)0);
  g_signal_connect(G_OBJECT(buttonDumpAll), "clicked",
		   G_CALLBACK(onDumpButtonClicked), (gpointer)0);
  g_signal_connect(G_OBJECT(visu), "renderingChanged",
		   G_CALLBACK(clearListFiles), (gpointer)0);
  g_signal_connect(G_OBJECT(visu), "renderingChanged",
		   G_CALLBACK(onRenderingChangedUpdateFilters), (gpointer)0);
  g_signal_connect(G_OBJECT(entryFilterBrowser), "changed",
		   G_CALLBACK(filterBrowserChanged), (gpointer)0);
  g_signal_connect(G_OBJECT(panelBrowserComboFilter), "changed",
		   G_CALLBACK(onComboFilterChanged), (gpointer)0);
  g_signal_connect(G_OBJECT(visu), "dataReadyForRendering",
		   G_CALLBACK(onFileLoaded), (gpointer)0);
}

/*************/
/* Callbacks */
/*************/

void filterBrowserChanged(GtkEditable *entry, gpointer user_data)
{
  GPatternSpec *pattern;
  gboolean valid;
  GtkTreeIter iter;
  gboolean match;
  gchar *fileUTF8;

/*   fprintf(stderr, "'%s'\n", gtk_entry_get_text(GTK_ENTRY(entry))); */

  pattern = g_pattern_spec_new(gtk_entry_get_text(GTK_ENTRY(entry)));

  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoreFiles), &iter);
  while (valid)
    {
      gtk_tree_model_get(GTK_TREE_MODEL(listStoreFiles), &iter,
			 COLUMN_NAME_UTF8, &fileUTF8, -1);
      match = g_pattern_match_string(pattern, fileUTF8);
      gtk_list_store_set(listStoreFiles, &iter,
			 COLUMN_ACTIVE, match, -1);
      valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(listStoreFiles), &iter);
    }
  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(listStoreFilesFilter));
}

gboolean treeViewClicked(GtkWidget *widget, GdkEventButton *event,
			 gpointer user_data)
{
  GtkTreePath *currentPath;
  GtkTreeIter iter, iterList;
  GtkTreeViewColumn *col;
  gboolean res;
  gboolean checked;

  if (event->button == 1)
    {
      res = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW (fileTree),
					  event->x, event->y, &currentPath,
					  &col, NULL, NULL);

      if (!res)
	return FALSE;
      if (col == gtk_tree_view_get_column(GTK_TREE_VIEW(fileTree), COLUMN_BOOLEAN))
	{
	  gtk_tree_model_get_iter(GTK_TREE_MODEL(listStoreFilesFilter), &iter, currentPath);
	  gtk_tree_model_get(GTK_TREE_MODEL(listStoreFilesFilter), &iter,
			     COLUMN_BOOLEAN, &checked, -1);
	  gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(listStoreFilesFilter),
							   &iterList, &iter);
	  gtk_list_store_set(listStoreFiles, &iterList,
			     COLUMN_BOOLEAN, !checked, -1);
	}
      gtk_tree_path_free(currentPath);
    }

  return FALSE;
}

void treeViewActivated(GtkTreeView *treeview, GtkTreePath *path,
		       GtkTreeViewColumn *col, gpointer user_data)
{
  GtkTreeIter iter, childIter;
  gboolean checked;
  gchar* filename, *utf8;

  gtk_tree_model_get_iter(GTK_TREE_MODEL(listStoreFilesFilter), &iter, path);
  gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(listStoreFilesFilter),
						   &childIter, &iter);
  gtk_tree_model_get(GTK_TREE_MODEL(listStoreFiles), &childIter,
		     COLUMN_NAME, &filename,
		     COLUMN_NAME_UTF8, &utf8,
		     COLUMN_BOOLEAN, &checked, -1);
  if (checked)
    {
      DBG_fprintf(stderr, "Panel Browser : double clic asks for loading (%s).\n", filename);
      browserLoad(filename);
    }
  else
    {
      DBG_fprintf(stderr, "Panel Browser : double clic ask for loading"
		  " refused since not checked.\n");
      raiseAlertDialog(_("Check the box to render a file."));
    }
/*   gtk_tree_path_free(path); */
}
void navigateClicked(GtkButton *button, gpointer data)
{
  GtkTreeIter iter;
  GtkTreePath *path;
  gboolean res;

  res = panelBrowserGet_nextSelected(&path, &iter, GPOINTER_TO_INT(data));
  if (!res)
    return;

  res = navigateInFiles(path, &iter);
  gtk_tree_path_free(path);
}
void checkFiles(GtkButton *button, gpointer data)
{
  gtk_tree_model_foreach(GTK_TREE_MODEL(listStoreFilesFilter), checkFile, data);
}
void clearListFiles(GObject *obj, gpointer data)
{
  gtk_list_store_clear(listStoreFiles);
  listLoaded = FALSE;
  if (currentBrowseredDirectory)
    g_free(currentBrowseredDirectory);
  currentBrowseredDirectory = (gchar*)0;
}
void onRenderingChangedUpdateFilters(GObject *obj, gpointer data)
{
  int nb, i;
  GtkTreeIter iter;
  RenderingMethod *method;

  DBG_fprintf(stderr, "Panel Browser : catch the 'renderingChanged' signal,"
	      " recreating filters...\n");
  gtk_list_store_clear(panelBrowserListFilter);
  method = getRenderingMethodInUse();
  if (!method)
    return;
  nb = renderingMethodGet_nbFileType(method);
  if (nb == 1)
    gtk_widget_set_sensitive(panelBrowserComboFilter, FALSE);
  else
    gtk_widget_set_sensitive(panelBrowserComboFilter, TRUE);
  for (i = 0; i < nb; i++)
    {
      gtk_list_store_append(panelBrowserListFilter, &iter);
      gtk_list_store_set(panelBrowserListFilter, &iter,
			 PANEL_BROWSER_COLUMN_FILTER_LABEL,
			 renderingMethodGet_fileTypeName(method, i),
			 PANEL_BROWSER_COLUMN_FILTER_ID, i,
			 -1);
    }
  gtk_combo_box_set_active(GTK_COMBO_BOX(panelBrowserComboFilter), 0);
  currentComboFilterValue = 0;
}
void onFileLoaded(GObject *obj, VisuData *dataObj, gpointer data)
{
  checkFilesOnEnter(data);
}
void onRefreshDir(GtkButton *button, gpointer data)
{
  if (currentBrowseredDirectory)
    browseDirectory(currentBrowseredDirectory);
}
gboolean playSelectedFiles(gpointer data)
{
  GtkTreeIter iter;
  gboolean res;
  GtkTreePath *path;

  g_return_val_if_fail(startBrowsePath, FALSE);

  res = panelBrowserGet_nextSelected(&path, &iter, currentBrowseDirection);
  if (!res)
    return FALSE;

  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoAround)))
    {
      res = navigateInFiles(path, &iter);
      gtk_tree_path_free(path);
      return res;
    }

  res = TRUE;
  if (!gtk_tree_path_compare(path, startBrowsePath))
    {
      DBG_fprintf(stderr, "Panel Browser : On round is done, applyng policy.\n");
      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoAndBack)))
	{
	  if (currentBrowseDirection == BROWSER_PREVIOUS)
	    {
	      res = navigateInFiles(path, &iter);
	      gtk_tree_path_free(path);
	      currentBrowseDirection = BROWSER_NEXT;
	    }
	  else
	    {
	      gtk_tree_path_free(path);
	      currentBrowseDirection = BROWSER_PREVIOUS;
	      res = panelBrowserGet_nextSelected(&path, &iter, currentBrowseDirection);
	      if (res)
		{
		  res = navigateInFiles(path, &iter);
		  gtk_tree_path_free(path);
		}
	    }
	}
      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioGoOnce)))
	{
	  res = FALSE;
	  navigateInFiles(path, &iter);
	  gtk_tree_path_free(path);
	}
    }
  else
    {
      res = navigateInFiles(path, &iter);
      gtk_tree_path_free(path);
    }

  return res;
}

void playStopClicked(GtkButton *button, gpointer data)
{
  GtkTreeIter startIter;
  gboolean res;

  if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(panelBrowserListFilter), &startIter))
    return;
  if (!isPlayingCallbackId)
    {
      res = panelBrowserGet_currentSelected(&startBrowsePath, &startIter);
      if (!res)
	{
	  res = panelBrowserGet_nextSelected(&startBrowsePath, &startIter, BROWSER_NEXT);
	  if (!res)
	    return;
	  else
	    navigateInFiles(startBrowsePath, &startIter);
	}

      /* Launch play */
      gtk_widget_hide(imagePlay);
      gtk_widget_show(imageStop);

      currentBrowseDirection = BROWSER_NEXT;
      isPlayingCallbackId =
	g_timeout_add_full(G_PRIORITY_DEFAULT + 30,
			   (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spinDelay)),
			   playSelectedFiles, (gpointer)0,
			   stopPlayStop);
    }
  else
    {
      /* Stop play */
      g_source_remove(isPlayingCallbackId);
    }
}
void stopPlayStop(gpointer data)
{
  isPlayingCallbackId = 0;
  gtk_widget_hide(imageStop);
  gtk_widget_show(imagePlay);
  g_return_if_fail(startBrowsePath);
  gtk_tree_path_free(startBrowsePath);
}
void onSpinDelayChangeValue(GtkSpinButton *spinbutton,
			    GtkScrollType scroll,
			    gpointer user_data)
{
  GtkTreeIter startIter;
  gboolean res;
  GtkTreePath *startPath;

  if (isPlayingCallbackId != 0)
    {
      startPath = gtk_tree_path_copy(startBrowsePath);
      /* Stop playing at this rate */
      g_source_remove(isPlayingCallbackId);
      startBrowsePath = startPath;
      /* Flush the remove callback */
      visuWaitFunction();
      /* Relaunch playing */
      gtk_widget_hide(imagePlay);
      gtk_widget_show(imageStop);
      isPlayingCallbackId =
	g_timeout_add_full(G_PRIORITY_DEFAULT + 30,
			   (guint)gtk_spin_button_get_value(spinbutton),
			   playSelectedFiles, (gpointer)0,
			   stopPlayStop);
    }
}
void onDumpButtonClicked(GtkButton *button, gpointer user_data)
{
  GtkWidget *dump;
  GtkProgressBar *progressBarDump;
  char *filename;
  DumpType *format;
  int res;
  GString *buffer;
  GtkButton *abort;
  char *chr, *chr2;
  int goodPattern;
  int flagAbort;
  int i;
  GString *fileNumbered;
  GtkTreeIter iter;
  gboolean valid, checked, errors;
  GtkTreePath *currentPath;
  gchar *file;
  RenderingWindow *window;

  window = RENDERING_WINDOW(visuRenderingWindowGet_current());
  g_return_if_fail(window);

  dump = dumpDialog_new(renderingWindowGet_visuData(window));
  if (gtk_dialog_run(GTK_DIALOG(dump)) != GTK_RESPONSE_ACCEPT)
    {
      gtk_widget_destroy(dump);
      return;
    }

  filename = dumpDialogGet_fileName(DUMP_DIALOG(dump));
  format = dumpDialogGet_dumpType(DUMP_DIALOG(dump));
  if (!format || !filename)
    {
      fprintf(stderr, "INTERNAL ERROR! The dump dialog doesn't"
	      " return the desired format nor the chosen name.\n");
      exit(1);
    }

  DBG_fprintf(stderr, "Panel Browser : dump all returns this filename"
	      " pattern '%s' (format : %s)\n", filename, format->fileType->description);
  if (format->writeFunc)
    {
      res = 0;
      buffer = g_string_new(_("Dumping all selected files to images,"));
      g_string_append_printf(buffer, _(" format '%s'.\n\n"), format->fileType->description);
      /* Verify the name is regular */
      if (g_pattern_match_simple("*%0?d*", filename))
	{
	  chr = strchr(filename, '%');
	  if ((int)*(chr + 2) <= '0' || (int)*(chr + 2) > '9')
	    {
	      goodPattern = 0;
	      g_string_append_printf(buffer, _("Error! The numbering pattern is"
					       " wrong.\n"));
	    }
	  else
	    {
	      chr2 = strchr(chr + 1, '%');
	      if (chr2)
		{
		  goodPattern = 0;
		  g_string_append_printf(buffer, _("Error! Only one '%%' character"
						   " is allowed in the file name.\n"));
		}
	      else
		goodPattern = 1;
	    }
	}
      else
	{
	  goodPattern = 0;
	  g_string_append_printf(buffer, _("Error! Missing pattern in the filename.\n"));
	}
      if (!goodPattern)
	{
	  g_string_append_printf(buffer, _("\nHelp : you must specify '%%0xd' in"
					   " the filename, with 'x' is a number [|1;9|]."
					   " This allows V_Sim to number the dumped"
					   " files.\n\n For example, with a pattern like this"
					   " : 'toto%%02d.pdf', dumped files will be named"
					   " : toto00.pdf, toto01.pdf..."));
	}
      if (goodPattern)
	{
	  abort = dumpDialogGet_cancelButton(DUMP_DIALOG(dump));
	  progressBarDump = dumpDialogGet_progressBar(DUMP_DIALOG(dump));

	  g_signal_connect (G_OBJECT(abort), "clicked",
			    G_CALLBACK(abortDump), (gpointer)&flagAbort);
	  g_signal_connect (G_OBJECT(abort), "clicked",
			    G_CALLBACK(abortDumpAll), (gpointer)progressBarDump);

	  gtk_progress_bar_set_fraction(progressBarDump, 0.);
	  fileNumbered = g_string_new("");
	  i = 0;
	  flagAbort = 0;

	  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoreFilesFilter), &iter);
	  errors = FALSE;
	  while (valid && !errors && !flagAbort)
	    {
	      checked = FALSE;
	      gtk_tree_model_get(GTK_TREE_MODEL(listStoreFilesFilter), &iter,
				 COLUMN_BOOLEAN, &checked, -1);
	      if (checked)
		{
		  g_string_append_printf(buffer, _("Write to file %d ..."), i);

		  currentPath = gtk_tree_model_get_path(GTK_TREE_MODEL(listStoreFilesFilter), &iter);
		  res = navigateInFiles(currentPath, &iter);
		  gtk_tree_path_free(currentPath);
      
		  if (!res)
		    {
		      g_string_append_printf(buffer, _(" error\n"));
		      errors = TRUE;
		    }
		  else
		    {
		      g_string_printf(fileNumbered, filename, i);
		      DBG_fprintf(stderr, "Panel browser : write '%s'\n",
				  fileNumbered->str);

		      gtk_progress_bar_set_text(progressBarDump,
						_("Waiting for generating image in memory..."));
		      visuWaitFunction();

		      res = format->writeFunc(format->fileType, buffer, fileNumbered->str,
					      dumpDialogGet_widthValue(DUMP_DIALOG(dump)),
					      dumpDialogGet_heightValue(DUMP_DIALOG(dump)),
					      renderingWindowGet_visuData(window),
					      updateDumpAllProgressBar,
					      (gpointer)progressBarDump);

		      if (res)
			{
			  g_string_append_printf(buffer, _(" error\n"));
			  errors = TRUE;
			}
		      else
			g_string_append_printf(buffer, _(" OK\n"));
		    }
		  i++;
		}
	      valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(listStoreFilesFilter), &iter);
	    }
	  g_string_free(fileNumbered, TRUE);
	}
      if (!goodPattern || res)
	raiseAlertDialog(buffer->str);
      g_string_free(buffer, TRUE);
    }
  gtk_widget_destroy(dump);
}
void updateDumpAllProgressBar(gpointer data)
{
  gdouble val;
  gdouble percentage;
  gdouble nEle;

  g_return_if_fail(GTK_PROGRESS_BAR(data));

  nEle = (gdouble)gtk_tree_model_iter_n_children(GTK_TREE_MODEL(listStoreFilesFilter), NULL);
  val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(data));
  if (((int)(val * nEle)) % 100 == 0)
    gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data), "");

  percentage = val + 0.01 / nEle;
  if (percentage > 1.0)
    percentage = 1.0;
  if (percentage < 0.)
    percentage = 0.;
  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data), percentage);
  visuWaitFunction();
}
void abortDumpAll(GtkButton *button, gpointer data)
{
  gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data),
			    _("Abortion request, please wait..."));
}





/******************/
/* Public methods */
/******************/

gboolean panelBrowserGet_currentSelected(GtkTreePath **path, GtkTreeIter *iterSelected)
{
  GtkTreeSelection *selection;
  gboolean res;
  GtkTreeModel *model;

  g_return_val_if_fail(path && iterSelected, FALSE);

  if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoreFilesFilter), iterSelected))
    return FALSE;

  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree));
  res = gtk_tree_selection_get_selected(selection, &model, iterSelected);

  if (res)
    *path = gtk_tree_model_get_path(model, iterSelected);
  return res;
}

gboolean panelBrowserGet_nextSelected(GtkTreePath **path, GtkTreeIter *iterSelected, int direction)
{
  GtkTreeSelection *selection;
  GtkTreePath *currentPath, *firstPath;
  GtkTreeIter iter;
  gboolean res, checked;
  GtkTreeModel *model;
  int loopComplete;

  g_return_val_if_fail(path && iterSelected &&
		       (direction == BROWSER_NEXT || direction == BROWSER_PREVIOUS), FALSE);

  *path = (GtkTreePath*)0;

  if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoreFilesFilter), &iter))
    return FALSE;

  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree));
  res = gtk_tree_selection_get_selected(selection, &model, &iter);

  /* Cas où rien n'est sélectionné */
  if (!res)
    {
      if (direction == BROWSER_NEXT)
	res = gtk_tree_model_get_iter_last(GTK_TREE_MODEL(listStoreFilesFilter),
					   &iter, (GtkTreePath**)0);
      else if (GPOINTER_TO_INT(direction) == BROWSER_PREVIOUS)
	res = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoreFilesFilter), &iter);
    }
  g_return_val_if_fail(res, FALSE);

  currentPath = gtk_tree_model_get_path(GTK_TREE_MODEL(listStoreFilesFilter), &iter);
  firstPath = gtk_tree_path_copy(currentPath);
  do
    {
      if (direction == BROWSER_NEXT)
	{
	  /* Avance d'un pas dans la liste */
	  gtk_tree_path_next(currentPath);
	  /* Recupère l'itération avancée d'un pas */
	  res = gtk_tree_model_get_iter(GTK_TREE_MODEL(listStoreFilesFilter),
					&iter, currentPath);
	  /* Si cette iteration n'existe pas on revient au début. */
	  if (!res)
	    {
	      gtk_tree_model_get_iter_first(GTK_TREE_MODEL(listStoreFilesFilter),
					    &iter);
	      gtk_tree_path_free(currentPath);
	      currentPath =
		gtk_tree_model_get_path(GTK_TREE_MODEL(listStoreFilesFilter), &iter);
	    }
	}
      else if (direction == BROWSER_PREVIOUS)
	{
	  /* Recule d'un pas dans la liste */
	  res = gtk_tree_path_prev(currentPath);
	  /* Recupère l'itération reculée d'un pas */
	  res = res && gtk_tree_model_get_iter(GTK_TREE_MODEL(listStoreFilesFilter),
					&iter, currentPath);
	  /* Si ce path n'existe pas ou 
	     si cette iteration n'existe pas on va à la fin. */
	  if (!res)
	    {
	      gtk_tree_path_free(currentPath);
	      res = gtk_tree_model_get_iter_last(GTK_TREE_MODEL(listStoreFilesFilter),
						 &iter, &currentPath);
	      if (!res)
		{
		  g_warning("Panel browser : impossible to find"
			    " the end of the list.\n");
		  gtk_tree_path_free(currentPath);
		  gtk_tree_path_free(firstPath);
		  return FALSE;
		}
	    }
	}

      /* Récupère les données pour l'itération avancée d'un pas. */
      checked = FALSE;
      gtk_tree_model_get(GTK_TREE_MODEL(listStoreFilesFilter), &iter,
			 COLUMN_BOOLEAN, &checked, -1);
/*       fprintf(stderr, "%d '%s'\n", nbSteps, filename); */
      loopComplete = !gtk_tree_path_compare(firstPath, currentPath);
    }
  while ( !checked && !loopComplete);
  gtk_tree_path_free(firstPath);
  if (!loopComplete)
    {
      *path = currentPath;
      *iterSelected = iter;
      return TRUE;
    }
  else
    {
      gtk_tree_path_free(currentPath);
      return FALSE;
    }
}

gboolean navigateInFiles(GtkTreePath *path, GtkTreeIter *iterSelected)
{
  GtkTreeSelection *selection;
  gboolean res;
  gchar *filename;

  g_return_val_if_fail(path && iterSelected, FALSE);

  /* Rend l'iter sélectionné */
  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(fileTree));
  gtk_tree_selection_select_iter(selection, iterSelected);
  gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fileTree), path, NULL, FALSE, 0., 0.);
      
  /* Load the new selected file */
  gtk_tree_model_get(GTK_TREE_MODEL(listStoreFilesFilter), iterSelected,
		     COLUMN_NAME, &filename, -1);
  res = browserLoad(filename);
  return res;
}

gboolean browserLoad(gchar *filename)
{
  gchar *pathToFile;
  GString *buffer;
  VisuData *data, *prevData;
  RenderingMethod *method;
  int res;
  int kind, nbKind;
  gboolean changeElement;
  RenderingWindow *window;
  VisuData *dataObj;

  window = RENDERING_WINDOW(visuRenderingWindowGet_current());
  if(!window)
    return FALSE;

  dataObj = renderingWindowGet_visuData(window);
  if (dataObj)
    data = visuDataNew_withOpenGLView(visuDataGet_openGLView(dataObj));
  else
    data = visuDataNew();
  if (!data)
    exit(1);

  method = getRenderingMethodInUse();
  if (!method)
    {
      fprintf(stderr, "INTERNAL ERROR! Can't load file '%s' since no"
	      " rendering method is specififed.\n", filename);
      return FALSE;
    }
  pathToFile = g_build_filename(currentBrowseredDirectory, filename, NULL);
  visuDataAdd_file(data, pathToFile, currentComboFilterValue);
  g_free(pathToFile);
  nbKind = renderingMethodGet_nbFileType(method);
  dataObj = renderingWindowGet_visuData(window);
  if (nbKind > 1 && !dataObj)
    {
      raiseAlertDialog(_("Can't load this file through the browser because it"
			 " requires to read several files. You should use the 'Open'"
			 " button on the main panel and then use the browser to vary"
			 " one kind of file at a time."));
      g_object_unref(data);
      return FALSE;

    }
  for (kind = 0; kind < nbKind; kind++)
    if (kind != currentComboFilterValue)
      visuDataAdd_file(data, visuDataGet_file(dataObj, kind), kind);

  prevData = dataObj;

  res = loadDataFromFile(data, &buffer);

  if (!res)
    {
      raiseAlertDialog(buffer->str);
      dataObj = (VisuData*)0;
    }
  else
    dataObj = data;

  if (prevData && dataObj)
    {
      changeElement = visuData_compareElements(prevData, dataObj);
      visuDataSet_changeElementFlag(dataObj, changeElement);
      /* Useless unref since, attaching dataObj to the window on
	 next line will unref the previous VisuData object attached. */
/*       g_object_unref(G_OBJECT(prevData)); */
    }
  renderingWindowSet_visuData(window, dataObj);
  if (dataObj)
    {
      visuData_createAllNodes(dataObj);
      g_signal_emit (visu, VISU_GET_CLASS (visu)->OpenGLAskForReDraw_signal_id,
		     0 , NULL);
    }

  if (buffer)
    g_string_free(buffer, TRUE);

  if (dataObj)
    return TRUE;
  else
    return FALSE;
}

gboolean checkFile(GtkTreeModel *model, GtkTreePath *path,
		   GtkTreeIter *iter, gpointer data)
{
  gboolean filterOk;
  GtkTreeIter iterList;
  GtkListStore *list;

  /* If we check the row, the checkbutton is on only
     if the name is in accordance with the filter. */
  gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(listStoreFilesFilter),
						   &iterList, iter);
  list = GTK_LIST_STORE(gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(listStoreFilesFilter)));
  if (GPOINTER_TO_INT(data))
    {
      gtk_tree_model_get(GTK_TREE_MODEL(model), iter, COLUMN_ACTIVE,
			 &filterOk, -1);
      
      if (filterOk)
	gtk_list_store_set(list, &iterList, COLUMN_BOOLEAN,
			   TRUE, -1);
      else
	gtk_list_store_set(list, &iterList, COLUMN_BOOLEAN,
			   FALSE, -1);
    }
  else
    {
      gtk_list_store_set(list, &iterList, COLUMN_BOOLEAN,
			 FALSE, -1);
    }
  return FALSE;
}

void browseDirectory(gchar* dir)
{
  GDir *gdir;
  const gchar *fileFromDir;
  gchar *fileUTF8, *file;
  GtkTreeIter iter;
  gsize lu, ecrit;
  GPatternSpec ***pattern;
  int *nbPattern, i;
  RenderingMethod* method;
  gboolean passed;
  char nbFilesLabel[36];
  GList *tmpLst, *tmpLst2;
  int nbFiles;
  gint nbKind, kind;

  DBG_fprintf(stderr, "Panel browser : scanning directory '%s'.\n", dir);
  gdir = g_dir_open(dir, 0, NULL);
  if (!gdir)
    {
      raiseAlertDialog(_("The specified directory is unreadable."));
      return;
    }
  gtk_list_store_clear(listStoreFiles);
  listLoaded = FALSE;
  
  method = getRenderingMethodInUse();
  if (!method)
    return;

  nbKind = renderingMethodGet_nbFileType(method);
  pattern = malloc(sizeof(GPatternSpec**) * nbKind);
  nbPattern = malloc(sizeof(int) * nbKind);
  if (!pattern || !nbPattern)
    {
      allocationProblems();
      exit(1);
    }
  for( kind = 0; kind < nbKind; kind++)
    {
      nbPattern[kind] = 0;
      tmpLst = renderingMethodGet_fileType(method, kind);
      while (tmpLst)
	{
	  nbPattern[kind] += g_list_length(((FileFormat*)tmpLst->data)->fileType);
	  tmpLst = g_list_next(tmpLst);
	}
      if (nbPattern[kind])
	{
	  pattern[kind] = malloc(sizeof(GPatternSpec*) * nbPattern[kind]);
	  if (!pattern[kind])
	    {
	      allocationProblems();
	      exit(1);
	    }
	  i = 0;
	  tmpLst = renderingMethodGet_fileType(method, kind);
	  while (tmpLst)
	    {
	      tmpLst2 = ((FileFormat*)tmpLst->data)->fileType;
	      while (tmpLst2)
		{
		  pattern[kind][i] = g_pattern_spec_new((char*)tmpLst2->data);
		  tmpLst2 = g_list_next(tmpLst2);
		  i++;
		}
	      tmpLst = g_list_next(tmpLst);
	    }
	}
      else
	{
	  g_warning("WARNING! The present rendering method has no"
		    " pattern for prefered file of kind %d, assuming '*'.\n", kind);
	  pattern[kind] = malloc(sizeof(GPatternSpec*));
	  if (!pattern[kind])
	    {
	      allocationProblems();
	      exit(1);
	    }
	  nbPattern[kind] = 1;
	  pattern[kind][0] = g_pattern_spec_new((char*)"*");
	}
    }

  /* Add a timeout to show the progress bar if the scan is too long. */
  flagWorkInProgress = TRUE;
  flagBarIsShown = FALSE;
  g_timeout_add(150, showProgressBar, (gpointer)0);
    
  gtk_tree_view_set_model(GTK_TREE_VIEW(fileTree),
			  (GtkTreeModel*)0);
  nbFiles = 0;
  fileFromDir = g_dir_read_name(gdir);
  while (fileFromDir)
    {
      passed = FALSE;
      file = g_strdup(fileFromDir);
      if (!getFileSystemInUTF8())
	{
	  fileUTF8 = g_filename_to_utf8(fileFromDir, -1, &lu, &ecrit, NULL);
	  if (!fileUTF8)
	    g_warning("INTERNAL ERROR! Impossible to convert this file"
		      " name (%s) to UTF8.\n", fileFromDir);
	}
      else
	fileUTF8 = g_strdup(file);

      if(fileUTF8)
	{
	  for (kind = 0; kind < nbKind && !passed; kind++)
	    {
	      for (i = 0; i < nbPattern[kind] && !passed; i++)
		passed = passed || g_pattern_match_string(pattern[kind][i], fileUTF8);
	      if (passed)
		{
		  gtk_list_store_append(listStoreFiles, &iter);
		  gtk_list_store_set(listStoreFiles, &iter,
				     COLUMN_BOOLEAN, FALSE,
				     COLUMN_NAME, file,
				     COLUMN_NAME_UTF8, fileUTF8,
				     COLUMN_DATA, "??",
				     COLUMN_ACTIVE, TRUE,
				     COLUMN_FILE_KIND, kind,
				      -1);
		  nbFiles ++;
		}
	    }
	}
      if (flagBarIsShown && nbFiles%10 == 0)
	{
	  gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progressbar));
	  sprintf(nbFilesLabel, _("%d files."), nbFiles);
	  gtk_label_set_text(GTK_LABEL(labelWaiting), nbFilesLabel);
	}
      visuWaitFunction();
      fileFromDir = g_dir_read_name(gdir);
    }
  flagWorkInProgress = FALSE;
  g_dir_close(gdir);
  panelBrowserSet_labelCurrentDir();
  listLoaded = TRUE;
  for (kind = 0; kind < nbKind; kind++)
    {
      for (i = 0; i < nbPattern[kind]; i++)
	g_pattern_spec_free(pattern[kind][i]);
      free(pattern[kind]);
    }
  free(pattern);
  free(nbPattern);
  gtk_tree_view_set_model(GTK_TREE_VIEW(fileTree),
			  GTK_TREE_MODEL(listStoreFilesFilter));
  if (flagBarIsShown)
    {
      gtk_widget_show(scrolledwindow1);
      gtk_widget_hide(vBoxWaiting);
      flagBarIsShown = FALSE;
    }
  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(listStoreFilesFilter));
}

gboolean checkFilesOnEnter(gpointer data)
{
  if (currentBrowseredDirectory && !strcmp(currentBrowseredDirectory, getLastOpenDirectory()))
    return FALSE;

  DBG_fprintf(stderr, "Panel Browser : Entering panel Brwoser, checking for files...\n");

  if (currentBrowseredDirectory)
    g_free(currentBrowseredDirectory);
  currentBrowseredDirectory = g_strdup(getLastOpenDirectory());

  browseDirectory(currentBrowseredDirectory);

  return FALSE;
}
gboolean stopPlayOnLeave(gpointer data)
{
  if (isPlayingCallbackId != 0)
    {
      /* Stop play */
      g_source_remove(isPlayingCallbackId);
    }
  return FALSE;
}

void directoryClicked(GtkButton *button, gpointer data)
{
  char *filename;

  filename = getSelectedDirectory();

  if (!filename)
    return;

  browseDirectory(filename);
  
  if (currentBrowseredDirectory)
    g_free(currentBrowseredDirectory);
  currentBrowseredDirectory = filename;
}

gboolean showProgressBar(gpointer data)
{
  if (flagWorkInProgress)
    {
      gtk_widget_hide(scrolledwindow1);
      gtk_widget_show(vBoxWaiting);
      DBG_fprintf(stderr, "Panel Browser : scanning is too slow, showing progress bar.\n");
      flagBarIsShown = TRUE;
    }
  return FALSE;
}


/***************************/
/* Miscellaneous functions */
/***************************/

gboolean gtk_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *last, GtkTreePath **path)
{
  gboolean valid;
  GtkTreeIter iter;

  if (!model || !last)
    {
      fprintf(stderr, "WARNING! 'gtk_tree_model_get_iter_last' has been called with a"
	      " null model or a null last argument.\n");
      return FALSE;
    }

  valid = gtk_tree_model_get_iter_first(model, &iter);
  if (valid)
    *last = iter;
  else
    return FALSE;
  while (valid)
    {
      *last = iter;
      valid = gtk_tree_model_iter_next(model, &iter);
    }

  if (path)
    {
      if (last)
	*path = gtk_tree_model_get_path(model, last);
      else
	*path = (GtkTreePath*)0;
    }
  
  return TRUE;
}

gboolean panelBrowserIsIterVisible(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
  gboolean passUserFilter;
  gint kind;
  
  gtk_tree_model_get(model, iter,
		     COLUMN_FILE_KIND, &kind,
		     COLUMN_ACTIVE, &passUserFilter,
		     -1);
  return (passUserFilter && (kind == currentComboFilterValue));
}

void onComboFilterChanged(GtkComboBox *combo, gpointer data)
{
  GtkTreeIter comboIter;
  gboolean validIter;

  validIter = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(panelBrowserComboFilter), &comboIter);
  if (!validIter)
    return;

  gtk_tree_model_get(GTK_TREE_MODEL(panelBrowserListFilter), &comboIter,
		     PANEL_BROWSER_COLUMN_FILTER_ID, &currentComboFilterValue,
		     -1);
  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(listStoreFilesFilter));
}

void panelBrowserSet_labelCurrentDir()
{
  gchar *directoryUTF8, *directory, *markup;

  directory = getLastOpenDirectory();
  directoryUTF8 = getStringInUTF8(directory);
  markup = g_markup_printf_escaped(_("<span style=\"italic\" size=\"smaller\">%s</span>"),
				   directoryUTF8);
  g_free(directoryUTF8);
  gtk_label_set_markup(GTK_LABEL(labelDirectory), markup);
  g_free(markup);
}
