/**  file ge.c
 *   Explorer widget Inspired by grace-5.99
 * Copyright (c) P. Vincent.    See GNU GPL ../LICENCE
 */

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

#include <gtk/gtk.h>


#include "globals.h"
#include "utils.h"
#include "noxprotos.h"

#include "gw_list.h"
#include "gw_choice.h"
#include "ge_tree.h"

#include "gg_gutil.h"
#include "gg_gtkinc.h"
#include "gg_protos.h"
#include "gg_events.h"

#include "ge_protos.h"
#include "ng_objects.h"
#include "nn_tree.h"

extern void nn_cmd_label_edited (char *old_text ,char *new_text);  // provisoire

static gint popup_width = 520 ,popup_height = 590; // ,tree_width = 250;

extern GdkColor  bleuciel ,wheat;
extern GdkCursor *wait_cursor;

extern int set_graph_title (int gno ,char *s);
extern int set_axis_label (int gno ,int axisno ,char *s);

enum ex_responses {
  EX_STORE_TEMPLATE,
  EX_MOVE
};

/* two times let place for defaults */
#define NB_RMENUS 2*Q_Last

static GtkWidget    *explorer = NULL;
static void ge_explorer_AAC_CB (GtkWidget *w ,gint reponse);
/* rpane state */
static int rpane_iu  = 0;           /* 0:template 1: current object */
static Qtype rpane_typ = Q_Project; /* rpane_typ > Q_Last if it is a template */

static GtkWidget    *bt_apply           ,*bt_close;
static GtkWidget    *exvbox = NULL;
static GtkWidget    *exhbox;
static GtkWidget    *tree;
static Ge_tree      *getree;
static GtkTreeIter  *projet ,*graphe ,*set ,*node ,*iter;
static GtkWidget    *tscroll;

static GraphMenu3Struct     *graph_menu3     = NULL;
static AxisMenu3Struct      *axis_menu3      = NULL;
static SetsMenu3Struct      *sets_menu3      = NULL;
static ObjMenu3Struct       *obj_menu3       = NULL;
static ColorbarMenu3Struct  *colorbar_menu3  = NULL;
static LegendBoxMenu3Struct *legendbox_menu3 = NULL;

static GtkWidget *rightpane[NB_RMENUS];

static void ge_pages_block (gboolean sw);

void ppp (char *s)
{
  printf ("\n%s  \t cur_obj typ: typ=%d \t id=%d  father_typ=%d \t father_id=%d \t num=%d\n"
	  ,s       ,cur_obj_typ ,cur_obj_id  ,cur_parent_typ  ,cur_parent_id ,cur_obj_num);
  if (cur_obj_typ >= 0)    printf ("\t    typ: %s" ,Qtype_name[cur_obj_typ]);
  if (cur_parent_typ >= 0) printf ("\t parent: %s" ,Qtype_name[cur_parent_typ]);
  printf ("\n");
}

Ge_tree *get_getree (void)
{
  if (explorer != NULL) {
    return getree;
  } else {
    return NULL;
  }
}


static gulong idtreeCB;

void ge_block_tree_CB (gboolean sw)
{
  if (explorer != NULL) {
    if (sw) {
      g_signal_handler_block (tree, idtreeCB);
    } else {
      g_signal_handler_unblock (tree, idtreeCB);
    }
  }
}

static char *current_label = NULL;   /* ISO-8859-1 */
char *get_current_label (void)
{
  return current_label;
}

void ge_wait_cursor (int sw)
{
  if (explorer != NULL) {
    GdkWindow *ww = GTK_WIDGET (explorer)->window;
    if (ww != NULL) {
      if (sw) {
	gdk_window_set_cursor (ww ,wait_cursor);
      } else {
	gdk_window_set_cursor (ww ,NULL);
      }
    }
  }
}

/**
 *  ge_label_edited_CB is called when the label column is edited
 */
void  ge_label_edited_CB (GtkCellRendererText *cell,
			  gchar               *path_string,
			  gchar               *new_text,      /* UTF-8 */
			  gpointer             p)
{
  char *old_text = NULL;
  switch (cur_obj_typ) {
  case Q_LegendBox:
  case Q_TimeStamp:
  case Q_Colorbar:  //16
    break;
  default:
    if (objs[cur_obj_num].id >= 0 || cur_obj_typ == Q_Project) {
      GtkTreePath  *path  = gtk_tree_path_new_from_string (path_string);
      GtkTreeIter l2iter;
      gtk_tree_model_get_iter (getree->model ,&l2iter ,path);
      gtk_tree_store_set (getree->store ,&l2iter ,GE_TREE_LABEL ,new_text ,-1);
      xfree (current_label);
      current_label = g_convert (new_text ,-1 ,"ISO-8859-1" ,"UTF-8" ,NULL, NULL, NULL);
      switch (cur_obj_typ) {
      case  Q_Arc:
      case  Q_Box:
      case  Q_Compound:
      case  Q_Line:
      case  Q_Polyline:
      case  Q_String:
	old_text            = copy_string (old_text            ,objs[cur_obj_num].s);
	objs[cur_obj_num].s = copy_string (objs[cur_obj_num].s ,current_label);
	set_dirtystate ();
	gg_drawgraph   ();
	break;
      case Q_Graph:
	get_graph_title (cur_obj_id ,&old_text);
	set_graph_title (cur_obj_id ,current_label);
	ge_graph_update (cur_obj_id);
	set_dirtystate 	();
	gg_drawgraph   	();
	break;
      case Q_Axis:
	get_axis_label (cur_parent_id ,cur_obj_id ,&old_text);
	if (set_axis_label (cur_parent_id ,cur_obj_id ,current_label) == RETURN_SUCCESS) {
	  set_dirtystate ();
	  gg_drawgraph   ();
	}
	break;
      case Q_Set:
	old_text = copy_string (old_text ,get_legend_string (cur_parent_id ,cur_obj_id));
	set_legend_string  (cur_parent_id ,cur_obj_id ,current_label);
	ge_set_update      (cur_parent_id ,cur_obj_id);
	set_dirtystate ();
	gg_drawgraph   ();
	break;
      default:
	XCFREE (old_text);
	break;
      }
      nn_cmd_label_edited (old_text ,current_label);
      xfree (old_text);
    }
  }
}

void ge_label_update_current (gchar *label)
{
  gchar *utf8_label;
  if (explorer != NULL && cur_parent_typ != Q_Undef) {
    GtkTreeIter l2iter;
    if (ge_tree_get_iter (getree ,cur_parent_typ ,cur_parent_id ,cur_obj_typ ,cur_obj_id ,&l2iter)) {
      ge_expand_current ();
      ge_select_current ();
      if (label == NULL) label = "";
      utf8_label = g_convert (label, -1, "UTF-8", "ISO-8859-1" ,NULL, NULL, NULL);
      gtk_tree_store_set (getree->store ,&l2iter ,GE_TREE_LABEL ,utf8_label ,-1);
      current_label = copy_string (current_label ,label);
    }
  }
}

/**
 *  ge_hidden_update sets the style to show if the object is hidden or not
 */
void ge_hidden_update (Qtype typ ,int id ,Qtype ptyp, int pid ,gboolean hidden)
{
  if (explorer != NULL && ptyp != Q_Undef) {
    GtkTreeIter l2iter;
    if (ge_tree_get_iter (getree ,ptyp ,pid ,typ ,id ,&l2iter)) {
      if (hidden) {
	gtk_tree_store_set (getree->store ,&l2iter ,GE_TREE_STYLE_COLUMN  ,PANGO_STYLE_ITALIC ,-1);
	gtk_tree_store_set (getree->store ,&l2iter ,GE_TREE_WEIGHT_COLUMN ,PANGO_WEIGHT_ULTRALIGHT ,-1);
      } else {
	gtk_tree_store_set (getree->store ,&l2iter ,GE_TREE_STYLE_COLUMN  ,PANGO_STYLE_NORMAL ,-1);
	gtk_tree_store_set (getree->store ,&l2iter ,GE_TREE_WEIGHT_COLUMN ,PANGO_WEIGHT_BOLD ,-1);
      }
    }
  }
}


/* tree needs update */
static int need_tree_update = FALSE;
void ge_tree_need_update (int sw)
{
  need_tree_update = sw;
}

/**
 *  ge_explorer_show : change contextual menu in the right pane
 */
static void ge_explorer_show (void)
{
  int i;

  ge_pages_block (TRUE);
  ge_set_reset_rect     ();
  gtk_widget_show_all (GTK_DIALOG (explorer)->action_area);
  gtk_widget_show_all (tree);
  gtk_widget_show_all (tscroll);
  for (i = 0; i < NB_RMENUS; i++) {
    if (rightpane[i] != NULL) gtk_widget_hide_all (rightpane[i]);
  }
  if (rightpane[rpane_typ] != NULL) {
    gtk_widget_show_all (rightpane[rpane_typ]);
  }
  gtk_widget_show (exvbox);
  gtk_widget_show (explorer);
  if (rpane_typ == Q_Project) ge_project_set_page ();
  if (rpane_typ == Q_Graph)   ge_graph_set_page   ();
  if (rpane_typ == Q_Axis)    ge_axis_set_page    ();
  if (rpane_typ == Q_Set) {
    ge_set_set_page ();
    ge_set_warn_linsym_null ();
  }
  ge_pages_block (FALSE);
}


/**
 * ge_tree_CB is called when selection is changed in TreeView
 *            and updates the rpane
 */
void ge_tree_CB (GtkWidget *tree ,GdkEvent *event ,gpointer p)
{
  Qtype typ ,father_typ;
  gint id ,father_id ,n ,button;
  gboolean hidden;
  gchar *b1 ,*b2;
  QDobject *po;

  gg_set_action (DO_NOTHING);
  if (event == NULL) {
    button = Button1;
  } else {
    button = event->button.button;
  }
  ge_pages_block (TRUE);
  switch (button) {

    /*************** Button1 ************/
  case Button1:
    /* Actions when only one item is selected */
    if (ge_tree_get_selected (getree
			      ,&typ        ,&id
			      ,&father_typ ,&father_id
			      ,&b1 ,&b2 ,&hidden)
	) {
      ge_set_reset_rect ();
      gtk_widget_hide_all (rightpane[rpane_typ]);
      clear_all_handles ();
      rpane_typ = typ;
      obj_tid_make_current (typ ,id ,father_typ ,father_id);
      current_label = copy_string (current_label ,b2);
      switch (typ) {
      case Q_Graph:
	gg_switch_current_graph (id);
	ge_graph_update (id);
  	break;
      case Q_Set:
	gg_switch_current_set (father_id ,id);
	ge_set_update (father_id ,id);
	ge_set_set_page ();
  	break;
      case Q_Axis:
   	gg_switch_current_graph (father_id);
	ge_axis_update (father_id ,id);
  	break;
      case Q_LegendBox:
        gg_switch_current_graph (father_id);
        ge_legendbox_update (father_id);
        obj_tid_make_current (Q_LegendBox ,-1 ,Q_Graph ,father_id);
        draw_curobj_handles ();
        break;
      case Q_Arc:
      case Q_Box:
      case Q_Colorbar:  //16
      case Q_Compound:
      case Q_Line:
      case Q_Polyline:
      case Q_String:
      case Q_TimeStamp:
        /* geometric types only */
        ge_objs_u_update (typ);
        po = obj_tid_get_pointer (typ ,id ,father_id);
        if (po != NULL) {
          if (id < 0) {
            /* It is a template */
            rpane_iu = 0;
            rpane_typ = typ + Q_Last;
            ge_obj_update (po ,rpane_iu);
          } else {
            /* It is a normal object */
            if (typ != Q_TimeStamp) {
              int gno = obj_get_typed_ancestor_id (cur_obj_num ,Q_Graph);
              gg_switch_current_graph (gno);
            }
            rpane_iu = 1;
            rpane_typ = typ;
            ge_obj_update (po ,rpane_iu);
            draw_curobj_handles ();
          }
          // ge_hidden_update_current (po->hidden);
        }
        break;
      case Q_Project:
        ge_project_update (tdevice);
        break;
      default:
        break;
      }
    }
    break;

    /*************** Button3 ************/
  case Button3:
    n = ge_selection_is_homogeneous (&typ);
    /* Actions when the selected item(s) have all the same type */
    if (ge_tree_get_selected (GE_TREE (tree)
                              ,&typ        ,&id
                              ,&father_typ ,&father_id
                              ,&b1 ,&b2 ,&hidden)
	) {
      obj_tid_make_current (typ ,id ,father_typ ,father_id);
    }
    if (n > 0) {
      switch (typ) {
      case Q_Graph:
	gg_graph_popup_menu3 (graph_menu3 ,n);
	break;
      case Q_Set:
	gg_sets_popup_menu3 (sets_menu3 ,n ,FALSE);
	break;
      case Q_Axis:
	ge_axis_popup_menu3 (axis_menu3);
	break;
      case Q_Arc:
      case Q_Box:
      case Q_Compound:
      case Q_Line:
      case Q_Polyline:
      case Q_String:
      case Q_TimeStamp:
	ge_obj_popup_menu3 (obj_menu3 ,n ,typ ,id);
  	break;
      case Q_Colorbar:
	ge_colorbar_popup_menu3 (colorbar_menu3);
  	break;
      case Q_LegendBox:
	ge_legendbox_popup_menu3 (legendbox_menu3);
  	break;
      default:
	printf ("ge_tree_CB: Button3  Pas de popup pour %s\n" ,Qtype_name[typ]);
	break;
      }
    } else {
      ge_obj_popup_menu3_mixed (obj_menu3);
    }
    break;
  }
  ge_rpane_update ();
  ge_pages_block (FALSE);
}

/* To avoid to write (NULL) */
static gchar *ge_strdup (const gchar *s)
{
  if (s == NULL) {
    return g_strdup (" ");
  } else {
    return g_strdup (s);
  }
}

/**
 *  ge_append : is used by _ge_traverse to append objects in the (ge)tree
 */
static void ge_append (int i ,GtkTreeIter *p ,GtkTreeIter **c)
{
  gchar *bufn ,*buf1 ,*buf2 ,*buf1_utf8 ,*buf2_utf8;
  gboolean hidden;
  labels labs;
  tickmarks *t;
  if (i < 0) return;

  Qtype typ = objs[i].typ;
  int    id = objs[i].id;
  Qtype father_typ = objs[i].father_typ;
  int   father_id  = objs[i].father_id;

  buf1 = buf2 = NULL;
  hidden = FALSE;
  if (id < 0) {
    bufn = NULL;
  } else {
    bufn = g_strdup_printf (" %d" ,id);
  }
  switch (typ) {
  case Q_Graph:
    if (get_graph_labels (id ,&labs) == RETURN_FAILURE) return;
    buf1 = g_strconcat (Qtype_name[typ] ,bufn ,NULL);
    buf2 = ge_strdup   (labs.title.s);
    p = projet;
    hidden = is_graph_hidden (id);
    break;
  case Q_Set:
    buf1 = g_strconcat (Qtype_name[typ] ,bufn ,NULL);
    buf2 = ge_strdup   (get_legend_string (father_id ,id));
    hidden = is_set_hidden (father_id, id);
    break;
  case Q_Colorbar:  //16
    if (id < 0) return;    /* no template for this type */
    buf1 = g_strconcat (Qtype_name[typ] ,bufn ,NULL);
    buf2 = ge_strdup (objs[i].s);
    hidden = objs[i].hidden;
    break;
  case Q_Axis:
    t = get_graph_tickmarks (father_id ,id);
    if (t == NULL) {
      *c = NULL;
      return;
    }
    if (t->active == FALSE && id > 1) {
      *c = p;
      return;
    }
    switch (get_graph_type (father_id)) {
    case GRAPH_POLAR:
      switch (id) {
      case  X_AXIS: buf1 = g_strdup ("Axis phi");   break;
      case  Y_AXIS: buf1 = g_strdup ("Axis rho");   break;
      case ZX_AXIS: buf1 = g_strdup ("Axis X bis"); break;
      case ZY_AXIS: buf1 = g_strdup ("Axis Y bis"); break;
      }
      break;
    default:
      switch (id) {
      case  X_AXIS: buf1 = g_strdup ("Axis X");     break;
      case  Y_AXIS: buf1 = g_strdup ("Axis Y");     break;
      case ZX_AXIS: buf1 = g_strdup ("Axis X bis"); break;
      case ZY_AXIS: buf1 = g_strdup ("Axis Y bis"); break;
      }
      break;
    }
    buf2 = ge_strdup (t->label.s);
    hidden = !is_axis_active (father_id, id);
    break;
  case Q_LegendBox:
    buf1 = g_strdup  (Qtype_name[typ]);
    buf2 = ge_strdup (objs[i].s);
    hidden = !is_graph_legend_active (father_id);
    break;
  case Q_Arc:
  case Q_Box:
  case Q_Compound:
  case Q_Line:
  case Q_Polyline:
  case Q_String:
  case Q_TimeStamp:
    buf1 = g_strconcat (Qtype_name[typ] ,bufn ,NULL);
    if (id < 0) {
      p = projet;
      buf2 = g_strdup  ("Template");
    } else {
      buf2 = ge_strdup (objs[i].s);
    }
    hidden = objs[i].hidden;
    break;
  case Q_Project:
    buf1 = g_strdup  (Qtype_name[typ]);
    buf2 = ge_strdup (objs[i].s);
    break;
  default:
    break;
  }
  *c = g_malloc (sizeof (GtkTreeIter));
  /* Problem  with grace-5 motif.agr : TM must be \#{d4} */
  buf1_utf8  = g_convert (buf1 ,-1 ,"UTF-8" ,"ISO-8859-1" ,NULL ,NULL ,NULL);
  buf2_utf8  = g_convert (buf2 ,-1 ,"UTF-8" ,"ISO-8859-1" ,NULL ,NULL ,NULL);
  ge_tree_append (getree ,p ,c ,typ ,id ,father_typ ,father_id ,buf1_utf8 ,buf2_utf8 ,hidden);
  g_free (bufn);
  g_free (buf1);
  g_free (buf2);
  if (i == 0) projet = *c;      // A REVOIR
}
/* Internal */
static void _ge_traverse (int i ,GtkTreeIter *p ,GtkTreeIter **c)
{
  int next;
  if (i < 0) return;
  ge_append (i ,p ,c);
  next = objs[i].child;
  if (next > 0) {
    p = *c;
    _ge_traverse (next ,p ,c);
    gtk_tree_model_iter_parent (getree->model ,*c ,p);
    p = *c;
  }
  next = objs[i].brother;
  if (next > 0) _ge_traverse (next ,p ,c);
}

/**
 *  ge_traverse : traverse the objs[] tree to build the (ge)tree
 */
static void ge_traverse (void)
{
  static GtkTreeIter *p = NULL;
  static GtkTreeIter *c = NULL;
  _ge_traverse (0 ,p ,&c);
}

/**
 * ge_update_explorer : in fact, update the (ge)tree
 */
void ge_update_explorer (void)
{
  GtkTreePath *path;
  if (explorer != NULL) {
    /* update tree in lpane */
    ge_tree_clear (getree);
    ge_traverse ();

    path = gtk_tree_path_new_from_string ("0");
    gtk_tree_view_expand_to_path (GTK_TREE_VIEW(getree->view) ,path);
    /* rpane is updated through ge_tree_CB
    * or explicitely by ge_reset_explorer */
    clear_all_handles ();
    if (cur_obj_typ == Q_Graph) ge_select_current ();
  }
}


void ge_update_explorer_CB  (GtkWidget *w ,gpointer p)
{
  ge_update_explorer ();
}

/**
 * Reset right pane to project
 * */
void ge_reset_explorer (void)
{
  if (explorer != NULL) {
    ge_pages_block (TRUE);

    gtk_widget_hide_all (rightpane[rpane_typ]);
    rpane_typ = Q_Project;
    rpane_iu  = 0;
    ge_update_explorer ();
    ge_project_update (tdevice);
    ge_explorer_show ();
    ge_tree_need_update (FALSE);
    ge_pages_block (FALSE);
  }
}


void ge_expand_graph (int gno)
{
  if (explorer != NULL) {
    ge_tree_expand (getree ,Q_Project ,-1 ,Q_Graph ,gno);
  }
}


void ge_expand_graph_or_obj (Qtype typ ,int gno)
{
  if (explorer != NULL) {
    if (gno == -1) {
      ge_tree_expand (getree ,typ ,-1 ,typ ,0);
    } else {
      ge_legendbox_update (gno);
      ge_tree_expand (getree ,Q_Graph ,gno ,typ ,0);
    }
  }
}

void ge_explorer_hide (void)
{
  if (explorer != NULL) {
    ge_pages_block (TRUE);
    gtk_widget_hide_all (explorer);
    ge_pages_block (FALSE);
  }
}

void ge_explorer_popup (void)
{
  int i ,typ;
  if (explorer == NULL) {
    explorer = gtk_dialog_new ();
    ge_obj_block_instant_update (TRUE);
    bt_apply        = gtk_dialog_add_button (GTK_DIALOG (explorer) ,GTK_STOCK_APPLY       ,GTK_RESPONSE_APPLY);
    bt_close        = gtk_dialog_add_button (GTK_DIALOG (explorer) ,GTK_STOCK_CLOSE       ,GTK_RESPONSE_CLOSE);

    exvbox = GTK_DIALOG (explorer)->vbox;
    gtk_widget_set_size_request (GTK_WIDGET(exvbox) ,popup_width ,popup_height);

    tscroll = gtk_scrolled_window_new (NULL ,NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tscroll)
				    ,GTK_POLICY_NEVER
				    ,GTK_POLICY_AUTOMATIC);

    exhbox = gtk_hbox_new (FALSE ,1);
    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (tscroll) ,exhbox);
    gtk_box_pack_start (GTK_BOX (exvbox) ,tscroll ,TRUE ,TRUE , 0);

    /********* Left pane: treeview ***********/
    tree = ge_tree_new ("Explorer" ,"Objects" ,"label" ,ge_label_edited_CB);
    getree = GE_TREE (tree);
    gtk_box_pack_start_defaults (GTK_BOX (exhbox) ,tree);
    projet = g_malloc (sizeof (GtkTreeIter));
    graphe = g_malloc (sizeof (GtkTreeIter));
    set    = g_malloc (sizeof (GtkTreeIter));
    node   = g_malloc (sizeof (GtkTreeIter));
    iter   = g_malloc (sizeof (GtkTreeIter));

    /*********** Right pane: contextual menus *********/
    for (i = 0; i < NB_RMENUS; i++) rightpane[i] = NULL;
    rightpane[Q_Project]   = ge_project_create_menu   (exhbox);
    for (typ = Q_Line; typ < Q_Colorbar; typ++) {
      rightpane[typ       ] = ge_obj_create_menu (exhbox ,typ ,1); /* current */
      rightpane[typ+Q_Last] = ge_obj_create_menu (exhbox ,typ ,0); /* template */
    }
    /* types without template */
    rightpane[Q_Colorbar]  = ge_colorbar_create_menu  (exhbox);
    rightpane[Q_TimeStamp] = ge_obj_create_menu       (exhbox ,Q_TimeStamp ,1);
    rightpane[Q_LegendBox] = ge_legendbox_create_menu (exhbox);
    rightpane[Q_Graph]     = ge_graph_create_menu     (exhbox);
    rightpane[Q_Axis]      = ge_axis_create_menu      (exhbox);
    rightpane[Q_Set]       = ge_set_create_menu       (exhbox);
    rightpane[Q_Function]  = ge_function_create_menu  (exhbox ,1); /* current */
    rightpane[Q_Compound]  = ge_obj_create_menu       (exhbox ,Q_Compound ,1); /* no template */

    ge_pages_block (TRUE);

    graph_menu3      = gg_CreateGraphPopupEntries     (graph_menu3    ,NULL ,ge_graph_menu3_CB);
    axis_menu3       = ge_CreateAxisPopupEntries      (axis_menu3     ,NULL ,ge_axis_menu3_CB);
    sets_menu3       = gg_CreateSetPopupEntries       (sets_menu3     ,NULL ,ge_sets_menu3_CB);
    obj_menu3        = ge_CreateObjPopupEntries       (obj_menu3      ,NULL ,ge_obj_menu3_CB);
    colorbar_menu3   = ge_CreateColorbarPopupEntries  (colorbar_menu3 ,NULL ,ge_colorbar_menu3_CB);
    legendbox_menu3  = ge_CreateLegendboxPopupEntries (legendbox_menu3 ,NULL ,ge_legendbox_menu3_CB);

    ge_update_explorer ();
    gtk_widget_show_all (explorer);
    ge_project_update (tdevice);
    ge_pages_block (FALSE);


    idtreeCB = g_signal_connect_after (tree ,"ge_tree_event" ,G_CALLBACK (ge_tree_CB) ,NULL);

    g_signal_connect (explorer 	 ,"delete-event"  ,G_CALLBACK (gtk_widget_hide)    ,NULL);
    g_signal_connect (explorer 	 ,"response"      ,G_CALLBACK (ge_explorer_AAC_CB) ,NULL);
    ge_obj_block_instant_update (FALSE);
  }
  ge_explorer_show ();
  gg_set_action (DO_NOTHING);
}

void ge_explorer_popup_CB (GtkWidget *w ,gpointer p)
{
  ge_explorer_popup ();
}


void ge_kill_graph (int gno)
{
  if (explorer != NULL) {
    ge_tree_remove (getree ,Q_Project ,-1 ,Q_Graph ,gno);
  }
}

void ge_kill_set (int gno ,int setno)
{
  if (is_valid_setno (gno, setno)) {
    killset (gno, setno);
    obj_tid_make_current (Q_Graph ,gno ,Q_Project ,-1);
    if (explorer != NULL) {
      ge_tree_remove 	 (getree ,Q_Graph ,gno ,Q_Set ,setno);
      ge_reset_explorer  ();
      ge_update_explorer ();
      ge_select_current  ();
    }
  }
}

void ge_rpane_set_type (Qtype typ)
{
  rpane_typ = typ;
}

Qtype ge_rpane_get_type (void)
{
  return rpane_typ;
}

gint ge_get_rpane_iu (void)
{
  return rpane_iu;
}

/**
 * ge_rpane_update : updates the visible menu in rpane
 */
void ge_rpane_update (void)
{
  int i;
  if (explorer != NULL) {
    ge_pages_block (TRUE);
    for (i = 0; i < NB_RMENUS; i++) {
      if (rightpane[i] != NULL) gtk_widget_hide_all (rightpane[i]);
    }
    if (rightpane[rpane_typ] != NULL) {
      gtk_widget_show_all (rightpane[rpane_typ]);
      switch (rpane_typ) {
      case Q_Graph:
	ge_graph_set_page ();
	ge_graph_update (-2);
  	break;
      case Q_Set:
	ge_set_set_page ();
	ge_set_update (get_cg () ,-2);
	break;
      case Q_Axis:
	ge_axis_set_page ();
  	break;
      case Q_LegendBox:
	ge_legendbox_update (-2);
	break;
      case Q_Arc:
      case Q_Box:
      case Q_Line:
      case Q_Polyline:
      case Q_String:
      case Q_TimeStamp:
      case Q_Compound:
	ge_obj_update_rpane ();
	break;
      case Q_Colorbar:
	ge_colorbar_update (-2);
	break;
      case Q_Project:
	ge_project_set_page ();
	break;
      default:
	if (rpane_typ < Q_Last) {
	  printf ("ge_rpane_update: not yet programmed for typ %d\n" ,rpane_typ);
	}
	break;
      }
    }
    ge_pages_block (FALSE);
  }
}

static void ge_rpane_apply (int father_id ,Qtype typ ,int id)
{
  int iu;

  if (explorer != NULL) {
    gg_set_wait_cursor ();
    switch (cur_obj_typ) {
    case Q_Undef:
      break;
    case Q_LegendBox:
      ge_legendbox_apply (father_id);
      break;
    case Q_Arc:
    case Q_Box:
    case Q_Compound:
    case Q_Line:
    case Q_Polyline:
    case Q_String:
    case Q_TimeStamp:
      iu = (cur_obj_id == -1) ? 0 : 1;       /* Is it a template ? */
      if (iu > 0) cur_obj_num = obj_geom_get_num (typ ,id);
      ge_obj_apply (cur_obj_num ,iu);
      break;
    case Q_Colorbar:
      ge_colorbar_apply (0 ,cur_obj_num);
      break;
    case Q_Graph:
      ge_graph_apply     (id);
      break;
    case Q_Axis:
      ge_axis_apply (father_id ,id); /* the axis changed are sets in axis_applyto combo */
      break;
    case Q_Set:
      ge_set_apply (father_id ,id);
      break;
    case Q_Project:
      ge_project_apply ();
      break;
    default:
      printf ("ge_rpane_apply: apply to be done for typ %d\n" ,cur_obj_typ);
      break;
    }
    gg_unset_wait_cursor ();
  }
}

static void ge_explorer_AAC_CB (GtkWidget *w ,gint reponse)
{
  Qtype typ ,father_typ;
  gint  id  ,father_id;
  gboolean hidden;
  gchar *b1_utf8 ,*b2_utf8;
  QDobject *po;

  if (reponse == GTK_RESPONSE_CLOSE) {
    ge_pages_block (TRUE);
    gtk_widget_hide_all (explorer);
    ge_pages_block (FALSE);
    return;
  }
  if (ge_tree_get_selected (GE_TREE (tree)
			    ,&typ ,&id
			    ,&father_typ ,&father_id
			    ,&b1_utf8 ,&b2_utf8 ,&hidden)
      ) {
    ge_hidden_update (typ ,id ,father_typ ,father_id ,hidden);
    obj_tid_make_current (typ ,id ,father_typ ,father_id);
    xfree (current_label);
    current_label = g_convert (b2_utf8 ,-1 ,"ISO-8859-1" ,"UTF-8" ,NULL ,NULL ,NULL);
    switch (reponse) {
    case GTK_RESPONSE_APPLY:
      ge_rpane_apply (father_id ,typ ,id);
      if (need_tree_update) ge_update_explorer ();
      break;
    case EX_STORE_TEMPLATE:
      ge_rpane_apply (father_id ,typ ,id);
      po = obj_tid_get_pointer (typ ,id ,father_id);
      obj_set_template (po ,typ);
      break;
    }
  } else {
    errmsg ("Please, select ONE item in TreeView");
  }
}

gboolean ge_select (int father_typ ,int father_id  ,int typ ,int id)
{
  if (explorer != NULL) {
    if (ge_tree_select (getree ,father_typ ,father_id ,typ ,id))
      return TRUE;
  }
  return FALSE;
}

gboolean ge_select_root (void)
{
  return ge_tree_select_root (getree);
}

void ge_unselect_all (void)
{
  if (explorer != NULL) {
    ge_block_tree_CB (TRUE);
    ge_tree_unselect_all (getree);
    ge_block_tree_CB (FALSE);
  }
}

/**
 *  Select in the left pane tree, the current object
 *  returns TRUE if found, FALSE if not.
 */
gboolean ge_select_current (void)
{
  if (explorer != NULL) {
    gboolean retval =  ge_tree_select (getree
				       ,cur_parent_typ ,cur_parent_id
				       ,cur_obj_typ    ,cur_obj_id);
    if (retval) rpane_typ = cur_obj_typ;
    return retval;
  } else {
    return FALSE;
  }
}

void ge_expand_current (void)
{
  if (explorer != NULL && cur_parent_typ != Q_Undef) {
    ge_tree_expand (getree ,cur_parent_typ ,cur_parent_id ,cur_obj_typ ,cur_obj_id);
  }
}

/**
 *  returns TRUE if one selected element and one only
 *          FALSE if not
 *  args return typ and id of selected
 */
gboolean ge_get_selected (Qtype *typ ,gint *id)
{
  Qtype father_typ;
  gint father_id;
  gboolean hidden;
  gchar *b1 ,*b2;
  if (ge_tree_get_selected (getree ,typ ,id
			    ,&father_typ ,&father_id
			    ,&b1 ,&b2 ,&hidden)) {
    return TRUE;
  } else {
    return FALSE;
  }
}

/**
 *  Block/unblock notebook pages handler in rpane menus
 */
static void ge_pages_block (gboolean sw)
{
  if (sw) {
    ge_project_page_block ();
    ge_graph_page_block   ();
    ge_set_page_block     ();
    ge_axis_page_block    ();
  } else {
    ge_project_page_unblock ();
    ge_graph_page_unblock   ();
    ge_set_page_unblock     ();
    ge_axis_page_unblock    ();
  }
}

/**
 * Used for selections multiples. Calls for each selected row
 *  a function defined as void f1(int action ,int num)
 *  where num is the index in array objs[].
 */
gboolean ge_selection_for_each (int action ,void (*f1) (int action ,int num))
{
  int j ,id ,father_id;
  Qtype typ ,father_typ;
  GtkTreeIter      iter;
  GtkTreeSelection *select;
  GList 	   *lpath = NULL;
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (getree->view));
  lpath  = gtk_tree_selection_get_selected_rows (select ,&(getree->model));
  /* the list is traversed un reverse order */
  lpath = g_list_last (lpath);
  j = 0;
  while (lpath != NULL) {
    if (gtk_tree_model_get_iter (getree->model ,&iter ,lpath->data)) {
      gtk_tree_model_get (getree->model ,&iter
			  ,GE_TREE_TYP        ,&typ
			  ,GE_TREE_ID         ,&id
			  ,GE_TREE_PARENT_TYP ,&father_typ
			  ,GE_TREE_PARENT_ID  ,&father_id
			  ,-1);
      int num  = obj_tid_get_num (typ ,id ,father_typ ,father_id);
      if (num >= 0) {
	f1 (action ,num);
      }
      lpath = g_list_previous (lpath);
      j++;
    }
  }
  return (j > 0);
}

/**
 * Returns n > 0  if all the n selected rows have the same GE_TREE_TYP
 * If not or if no row selected, returns 0
 */
int ge_selection_is_homogeneous (Qtype *typ)
{
  return ge_tree_sel_is_homogeneous (getree ,typ);
}

int ge_selection_count (void)
{
  GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (getree->view));
  return gtk_tree_selection_count_selected_rows (select);
}

/**
 * return index in objs[] if one and only one rows is selected
 * else return -1
 */
int ge_selection_get_num (void)
{
  Qtype typ ,father_typ;
  gint  id ,father_id;
  gboolean hidden;
  gchar *b1 ,*b2;

  if (ge_tree_get_selected (getree
			    ,&typ        ,&id
			    ,&father_typ ,&father_id
			    ,&b1 ,&b2 ,&hidden)
      ) {
    return obj_tid_get_num (typ ,id ,father_typ ,father_id);
  } else {
    return -1;
  }
}
