Logo Search packages:      
Sourcecode: gaby version File versions  Download package

gtk_menu.c

/*  Gaby
 *  Copyright (C) 1998-2001 Frederic Peters
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "gaby.h"
#include "files.h"
#include "tables.h"
#include "records.h"
#include "actions.h"
#include "gtk_main.h"
#include "gtk_menu.h"
#include "gtk_dialogs.h"
#include "print_plg.h"
#include "gtk_print_dlg.h"

#ifdef USE_SQL
#  include <postgres.h>
#  include <libpq-fe.h>
extern PGconn *sqlconn;
#endif

static void new_view_create_callback(GtkWidget *t, view *fl);
static void print_callback(GtkWidget *t, PrintPluginData *ppd);
static void import_callback(GtkWidget *t, gpointer data);
static void export_callback(GtkWidget *t, gpointer data);
static void database_callback(GtkWidget *t, gpointer data);
static void otherdb_callback(GtkWidget *t, gpointer data);
static void launchbuilder_callback(GtkWidget *t, gpointer data);
#if 0
static void management_callback(GtkWidget *t, GList *tables);
#endif
static void do_action(GtkWidget *t, action *act);
static void launch_homebrewed_script (GtkWidget *t, gabywindow *win);
static void save_editable_windows(void);

/*
 * it's the old, well-rounded way. It should (will?) be replaced by 
 * gtkitemfactory when I'll have time to look how it works.
 *
 * this will also make easier to move to/support Gnome menus.
 *
 * update : there is not a 'gpointer data' part in the gtkmenuitem structure.
 *            how do you want I send data today ?
 *          (it exists in gnome apphelper)
 * 
 * update (10/3/99) : now that gaby can use gnome I no longer believe that
 *                    moving to the gtkitemfactory will be done.
 */

struct database {
      char *name;
      char *cmd;
};

/* TODO (post-2.0): databases are hard-coded (baaaad)
 *  I should at least provide an easy way for the user to add its databases to
 *  the menu (on-the-fly reading of ~/.gaby/desc.* would sure be better but a
 *  dedicated file (a la formats/infos) is enough (it could be generated from
 *  the descfiles in ../data/ so I won't have to maintain it)
 *  Note that 'on-the-fly reading' is not simply getting file names but also
 *  opening them and looking for a description. I think I'l go for the infos
 *  file...
 */
struct database dbs[] = {
      { gettext_noop("Address Book"), "gaby" },
      { gettext_noop("CDs"), "gcd" },
#ifdef USE_DEBIAN
      { gettext_noop("Debian packages"), "apt" },
#endif
      { gettext_noop("Books"), "gbc" },
      { gettext_noop("Videos"), "videobase" },
      { NULL, NULL }
};

static void menu_tables_save(GtkWidget *w, GList *tables)
{
      statusbar_message(_("Writing files ..."), NULL);
      save_editable_windows();
      tables_save();
      statusbar_message(_("Done."), NULL);
}

static void preferences_clicked(GtkWidget *w, gpointer data)
{
      GtkWidget *a;
      
      a = configure_dialog (NULL);
      if ( a != NULL ) gtk_widget_show(a);
}

static void windows_binding_callback (GtkWidget *t, gpointer data)
{
      gtk_widget_show(windows_binding_dialog());
}

#ifdef DEBUG_GABY
#ifdef USE_GNOME

static void show_windows_list (GtkWidget *t, gpointer data)
{
      GtkWidget *dialog;
      GtkWidget *parent;
      GtkWidget *list;
      GList *a = g_list_first(list_windows);
      gabywindow *win;
      gchar *a_line[3];
      ViewPluginData *vpd;
      view *vi;
      char *titles[] = { "plug-in", "subtable", "focus" };
      
      list = gtk_clist_new_with_titles(2, titles);
      gtk_widget_set_usize(list, 200, 200 );
      gtk_widget_show(list);
      while ( a != NULL ) {
            win = a->data;
            vpd = win->view->type;
            a_line[0] = vpd->i18n_name;
            vi = win->view;
            a_line[1] = vi->subtable->i18n_name;
            parent = win->parent;
            if ( parent != NULL && 
                        GTK_WIDGET_HAS_FOCUS(GTK_WIDGET(parent))) {
                  debug_print("%s has the focus\n", a_line[0]);
            }
            gtk_clist_append(GTK_CLIST(list), a_line);
            a = g_list_next(a);
      }
      
      dialog = gnome_dialog_new("Windows list", GNOME_STOCK_BUTTON_OK, NULL);
      gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), list, TRUE, TRUE, 0);
      gnome_dialog_set_close(GNOME_DIALOG(dialog), TRUE);
      gtk_widget_show(dialog);
}

static void show_memory_profile (GtkWidget *t, gpointer data)
{
      g_mem_profile();
}

#endif /* USE_GNOME */
#endif /* DEBUG_GABY */
      
/**
 * actions_menu_for_table
 * @table: the table you want actions for
 * @window: the window of the view
 *
 * Description:
 * This functions creates a menu (GtkMenu) filled with the actions available
 * for the given table, @win is used to get the current view and id (it may be
 * NULL if _no_ actions need them)
 *
 * Returns: GtkWidget* menu (NULL if there were no actions)
 **/
GtkWidget* actions_menu_for_table(table *table, gabywindow *window)
{
      GtkWidget *t;
      GtkWidget *m = NULL;
      action *a;
      GList *actions = list_actions;
      
      while (actions != NULL && actions->data != NULL ) {
            a = actions->data;
            actions = g_list_next(actions);
            if ( ! (a->event & EVENT_MENU ) ) continue;
            /* we don't want actions about other tables */
            if ( a->nb_params == 0 || a->params[0].table == table ) {
                  if ( m == NULL ) m = gtk_menu_new();
                  t = gtk_menu_item_new_with_label(a->i18n_name);
                  gtk_object_set_data(GTK_OBJECT(t), "win", window);
                  gtk_signal_connect(GTK_OBJECT(t), "activate", 
                                    GTK_SIGNAL_FUNC(do_action), a);
                  gtk_menu_append(GTK_MENU(m), t);
                  gtk_widget_show(t);
            }
      }
      
      return m;
}

#ifdef USE_GNOME

static GnomeUIInfo empty_menu[] = {
      GNOMEUIINFO_END
};

static GnomeUIInfo print_menu[] = {
      GNOMEUIINFO_END
};

static GnomeUIInfo databases_menu[] = {
/*0*/ GNOMEUIINFO_SEPARATOR,
/*1*/ { GNOME_APP_UI_ITEM,
      N_("_Other..."), N_("Select an other database to open"),
      otherdb_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
/*2*/ GNOMEUIINFO_SEPARATOR,
/*3*/ { GNOME_APP_UI_ITEM,
      N_("_Create a new one..."), N_("Launch the Gaby database builder"),
      launchbuilder_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
      GNOMEUIINFO_END
};

static GnomeUIInfo file_menu[] = {
/*0*/ GNOMEUIINFO_MENU_SAVE_ITEM(menu_tables_save, NULL),
#if 0
/*1*/ { GNOME_APP_UI_ITEM,    /* this needs a decent description */
      N_("_Management..."), N_("Manage different aspects of tables"),
      management_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
#endif
/*1*/ { GNOME_APP_UI_ITEM,
      N_("_Import..."), N_("Import datas from a file in a foreign format"),
      import_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
/*2*/ { GNOME_APP_UI_ITEM,
      N_("_Export..."), N_("Export datas to a file in a foreign format"),
      export_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
      
/*3*/ GNOMEUIINFO_SEPARATOR,
/*4*/ { GNOME_APP_UI_SUBTREE,
      N_("_Print"), N_("Output a subtable in a nice format"),
      print_menu, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
      GNOME_STOCK_PIXMAP_PRINT, 0, 0, NULL },
/*5*/ GNOMEUIINFO_SEPARATOR,
/*6*/ { GNOME_APP_UI_SUBTREE,
      N_("_Databases"), N_("Select a database to work on"),
      databases_menu, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
/*7*/ GNOMEUIINFO_SEPARATOR,
/*8*/ GNOMEUIINFO_MENU_EXIT_ITEM(gaby_quit_callback, NULL),
/*9*/ GNOMEUIINFO_END
};

#define FILE_SAVE 0
#define FILE_IMPORT     1
#define FILE_EXPORT     2
#define FILE_PRINT      4
#define FILE_DATABASES  6
#define FILE_EXIT 8

static GnomeUIInfo actions_menu[] = {
      GNOMEUIINFO_END
};

static GnomeUIInfo views_menu[] = {
      GNOMEUIINFO_END
};

static GnomeUIInfo settings_menu[] = {
/*0*/ { GNOME_APP_UI_ITEM,
      N_("_Windows binding..."), N_("Define how windows are related"),
      windows_binding_callback, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
/*1*/ GNOMEUIINFO_MENU_PREFERENCES_ITEM(preferences_clicked, NULL),
      GNOMEUIINFO_END
};

static GnomeUIInfo help_menu[] = {
      GNOMEUIINFO_HELP ("gaby"),
      GNOMEUIINFO_SEPARATOR,
      GNOMEUIINFO_MENU_ABOUT_ITEM(about_gaby_cb, NULL),
      GNOMEUIINFO_END
};

#ifdef DEBUG_GABY
static GnomeUIInfo debug_menu[] = {
      { GNOME_APP_UI_ITEM,
      "_Windows...", NULL,
      show_windows_list, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
      { GNOME_APP_UI_ITEM,
      "_Memory profile", "(glib must be compiled with it)",
      show_memory_profile, NULL, NULL, GNOME_APP_PIXMAP_NONE,
      NULL, 0, 0, NULL },
      GNOMEUIINFO_END
};
#endif
      
static GnomeUIInfo main_menu[] = {
      GNOMEUIINFO_MENU_FILE_TREE(file_menu),
      GNOMEUIINFO_SUBTREE (N_("A_ctions"), actions_menu),
      GNOMEUIINFO_SUBTREE (N_("_Views"), views_menu),
      GNOMEUIINFO_MENU_SETTINGS_TREE(settings_menu),
/*#ifdef DEBUG_GABY*/
#if 0
      GNOMEUIINFO_SUBTREE (N_("_Debugging"), debug_menu),
#endif
      GNOMEUIINFO_MENU_HELP_TREE(help_menu),
      GNOMEUIINFO_END
};

#if 0
static void create_homebrewed_submenu()
{
      char insert_pnt[100];
      GnomeUIInfo entry[2];
      DIR *dir;
      FILE *f;
      struct dirent *ent;
      char dirname[PATH_MAX];
      char st[100];
      char *s;
      
      sprintf(insert_pnt, "%s/%s/", _("A_ctions"), _("Home-brewed scripts"));
      
      entry[1].type = GNOME_APP_UI_ENDOFINFO;
      entry[0].hint = NULL;
      entry[0].unused_data = NULL;
      entry[0].pixmap_type = GNOME_APP_PIXMAP_NONE;
      entry[0].pixmap_info = NULL;
      entry[0].accelerator_key = 0;
      entry[0].type = GNOME_APP_UI_ITEM;

      sprintf(dirname, "%s/.gaby/scripts", g_get_home_dir());
      dir = opendir(dirname);
      if ( dir == NULL ) {
            entry[0].type = GNOME_APP_UI_ENDOFINFO;
            gnome_app_insert_menus(app, insert_pnt, entry);
            return;
      }
      
      while ( 1 ) {
            ent = readdir(dir);
            if ( ent == NULL ) break;
#ifdef DEBUG_GABY
            debug_print("[create_homebrewed_submenu] %s\n", 
                        ent->d_name );
#endif
            if ( strncmp(ent->d_name, "autoexec", 8) == 0 ) continue;
            f = fopen(ent->d_name, "r");
            if ( f == NULL ) continue;
            do {
                  fgets(st, 99, f);
            } while ( strncmp(st, "# Works with", 12) != 0 && ! feof(f));
            if ( feof(f) ) {
                  fclose(f);
                  continue;
            }
            if ( strcmp(st, "# Works with any descfile\n") != 0 ) {
                  s = strstr(st, appname);
                  if ( s == NULL ) {
                        fclose(f);
                        continue;
                  }
                  if ( strchr("\t ,;:", *(s-1) ) == NULL ) {
                        fclose(f);
                        continue;
                  }
                  if ( strchr("\t ,;.\n", *(s+strlen(s))) == NULL ) {
                        fclose(f);
                        continue;
                  }
            }

            fclose(f);
      }
            
      entry[0].type = GNOME_APP_UI_ENDOFINFO;
      gnome_app_insert_menus(app, insert_pnt, entry);
}
#endif

static gboolean create_actions_menu( gabywindow *window )
{
      GnomeUIInfo entry[2];
      action *a;
      view *v = window->view;
      table *table = v->subtable->table;
      gboolean one = FALSE;
      char insert_pnt[50];
      GList *actions;

      sprintf(insert_pnt, "%s/", _("A_ctions") );

      entry[1].type = GNOME_APP_UI_ENDOFINFO;
      
      entry[0].hint = NULL;
      entry[0].unused_data = NULL;
      entry[0].pixmap_type = GNOME_APP_PIXMAP_NONE;
      entry[0].pixmap_info = NULL;
      entry[0].accelerator_key = 0;

#if defined USE_PYTHON || defined USE_PERL || defined USE_GUILE
      if ( get_config_bool("common", "misc", "expert_mode", FALSE) == TRUE ) {
            entry[0].type = GNOME_APP_UI_ITEM;
            entry[0].label = g_strdup(_("Home-brewed scripts..."));
            entry[0].moreinfo = launch_homebrewed_script;
            entry[0].user_data = window;
            gnome_app_insert_menus(app, insert_pnt, entry);
            one = TRUE;
      }
#endif

      if ( one == TRUE ) {
            entry[0].type = GNOME_APP_UI_SEPARATOR;
            gnome_app_insert_menus(app, insert_pnt, entry);
      }
      entry[0].type = GNOME_APP_UI_ITEM;

      actions = g_list_last(list_actions);

      while ( actions != NULL ) {
            a = actions->data;
            actions = g_list_previous(actions);
            if ( a == NULL ) continue;
            if ( ! (a->event & EVENT_MENU ) ) continue;
            if ( a->nb_params == 0 || a->params[0].table == table ) {
                  entry[0].label = a->i18n_name;
                  entry[0].moreinfo = do_action;
                  entry[0].user_data = a;

#ifdef DEBUG_GABY
                  debug_print("[create_actions_menu] insert at %s\n", insert_pnt);
#endif
                  gnome_app_insert_menus(app, insert_pnt, entry);
                  gtk_object_set_data(GTK_OBJECT(entry[0].widget),
                              "win", window);
                  one = TRUE;
            }
      }

      return one;
}

static gboolean create_print_menu (gchar *insert)
{
      PrintPluginData *ppd;
      GList *list = list_print_plugins;
      GnomeUIInfo entry[2];
      char insert_pnt[50];
      
      sprintf(insert_pnt, "%s/", insert );
      
      entry[1].type = GNOME_APP_UI_ENDOFINFO;

      entry[0].type = GNOME_APP_UI_ITEM;
      entry[0].hint = NULL;
      entry[0].unused_data = NULL;
      entry[0].pixmap_type = GNOME_APP_PIXMAP_NONE;
      entry[0].pixmap_info = NULL;
      entry[0].accelerator_key = 0;
      
      if ( list == NULL ) return FALSE;
      list = g_list_last(list);
      
#ifdef DEBUG_GABY
      debug_print("[create_print_menu] insert at %s\n", insert_pnt);
#endif
      
      while ( list != NULL ) {
            ppd = list->data;
            list = g_list_previous(list);
            entry[0].label = ppd->i18n_name;
            entry[0].moreinfo = print_callback;
            entry[0].user_data = ppd;

            gnome_app_insert_menus(app, insert_pnt, entry); 
            
            if ( entry[0].widget == NULL ) {
#ifdef DEBUG_GABY
                  debug_print("[create_print_menu] unable to insert at %s \n", insert_pnt);
#endif
                  continue;
            }
      }
      
      return TRUE;
}

static gboolean create_databases_menu (gchar *insert)
{
      GnomeUIInfo entry[2];
      char insert_pnt[50];
      int i;
      DIR* directory;
      struct dirent *direntry;
      char str[PATH_MAX];
      
      sprintf(insert_pnt, "%s/", insert );
      
      entry[1].type = GNOME_APP_UI_ENDOFINFO;

      entry[0].type = GNOME_APP_UI_ITEM;
      entry[0].hint = NULL;
      entry[0].unused_data = NULL;
      entry[0].pixmap_type = GNOME_APP_PIXMAP_NONE;
      entry[0].pixmap_info = NULL;
      entry[0].accelerator_key = 0;
      
      /* contribution by Emmanueal Jeandel */
      sprintf(str, "%s/.gaby", g_get_home_dir());
      directory = opendir(str);
      while ( directory && (direntry = readdir(directory)) != NULL){
            if ((!strncmp("desc.", direntry->d_name,5)) &&
                  (direntry->d_name[strlen(direntry->d_name)-1] != '~' ) )
            {
                  debug_print("[create_databases_menu] adding %s\n", direntry->d_name);
                  entry[0].label = strdup(direntry->d_name+5);
                  entry[0].moreinfo = database_callback;
                  entry[0].user_data = entry[0].label;
                  gnome_app_insert_menus(app, insert_pnt, entry);
            }
      }
      closedir(directory);
      /* end of contrib*/
      
      i=0;
      while ( dbs[i++].name != NULL ) ;
      i--;
      
      debug_print("[create_dabases_menu] number of items to add: %d\n", i);

      while ( --i >= 0 ) {
            if ( strcmp(dbs[i].cmd, appname) == 0 ) continue;
            debug_print("[create_databases_menu] adding %s\n", dbs[i].name);
            entry[0].label = dbs[i].name;
            entry[0].moreinfo = database_callback;
            entry[0].user_data = dbs[i].cmd;

            gnome_app_insert_menus(app, insert_pnt, entry); 
      }

      return TRUE;
}

static gboolean create_views_submenu (ViewPluginData *type)
{
      GnomeUIInfo entry[2];
      view *f;
      GList *a=g_list_last(list_views);
      char insert_pnt[50];
      int i;
      
      sprintf(insert_pnt, "%s/%s/", _("_Views"), type->i18n_name);

      entry[1].type = GNOME_APP_UI_ENDOFINFO;

      entry[0].type = GNOME_APP_UI_ITEM;
      entry[0].hint = NULL;
      entry[0].moreinfo = new_view_create_callback;
      entry[0].unused_data = NULL;
      entry[0].pixmap_type = GNOME_APP_PIXMAP_NONE;
      entry[0].pixmap_info = NULL;
      entry[0].accelerator_key = 0;

      i = 0;
      while ( a != NULL ) {
            f = a->data;
            a = g_list_previous(a);
            if ( f->type != type )
                  continue;
            i++;
            entry[0].label = f->name;
            entry[0].user_data = f;
            
#ifdef DEBUG_GABY
            debug_print("[create_views_submenu] insert at %s\n", insert_pnt);
#endif
            gnome_app_insert_menus(app, insert_pnt, entry);
      }

      return ( i > 0 );
}

static void create_views_menu (GList *view_plugins)
{
      GnomeUIInfo entry[2];
      ViewPluginData *vpd, *vpdfilter = NULL;
      char insert_pnt[50];
      GList *tmp;
      GList *filters = NULL;
      gboolean direct_access;

      sprintf(insert_pnt, "%s/", _("_Views") );
      
      entry[1].type = GNOME_APP_UI_ENDOFINFO;

      if ( g_list_length(list_subtables) == 1 ) {
            direct_access = TRUE;
            entry[0].type = GNOME_APP_UI_ITEM;
            entry[0].moreinfo = new_view_create_callback;
      } else {
            direct_access = FALSE;
            entry[0].type = GNOME_APP_UI_SUBTREE;
            entry[0].moreinfo = empty_menu;
      }
      entry[0].hint = NULL;
      entry[0].user_data = NULL;
      entry[0].unused_data = NULL;
      entry[0].pixmap_type = GNOME_APP_PIXMAP_NONE;
      entry[0].pixmap_info = NULL;
      entry[0].accelerator_key = 0;

      tmp = g_list_first(view_plugins);
      while ( tmp != NULL ) {
            vpd = tmp->data;
            if ( vpd->type == FILTER ) {
                  filters = g_list_append(filters, vpd);
            }
            tmp = g_list_next(tmp);
      }
      
      if ( filters != NULL ) {
            tmp = g_list_last(filters);
            while ( tmp != NULL ) {
                  vpdfilter = tmp->data;
                  entry[0].label = vpdfilter->i18n_name;
                  if ( direct_access ) {
                        GList *l = g_list_first(list_views);
                        while ( l ) {
                              view *v = l->data;
                              if ( v->type == vpdfilter ) {
                                    entry[0].user_data = v;
                                    gnome_app_insert_menus(app, insert_pnt, entry);
                                    break;
                              }
                              l = g_list_next(l);
                        }
                  } else {
                        gnome_app_insert_menus(app, insert_pnt, entry);
                        create_views_submenu( vpdfilter );
                  }
                  tmp = g_list_previous(tmp);
            }
            entry[0].type = GNOME_APP_UI_SEPARATOR;
            gnome_app_insert_menus(app, insert_pnt, entry);
            if ( direct_access ) {
                  entry[0].type = GNOME_APP_UI_ITEM;
            } else {
                  entry[0].type = GNOME_APP_UI_SUBTREE;
            }
            filters = g_list_first(filters);
      }
      
      tmp = g_list_last(view_plugins);
      while ( tmp != NULL) {
            vpd = tmp->data;
            tmp = g_list_previous(tmp);
            if ( g_list_find(filters, vpd) != NULL ) continue;
            
            entry[0].label = vpd->i18n_name;
#ifdef DEBUG_GABY
            debug_print("[create_views_menu] insert at %s\n", insert_pnt);
#endif
            if ( direct_access ) {
                  GList *l = g_list_first(list_views);
                  while ( l ) {
                        view *v = l->data;
                        if ( v->type == vpd ) {
                              entry[0].user_data = v;
                              gnome_app_insert_menus(app, insert_pnt, entry);
                              break;
                        }
                        l = g_list_next(l);
                  }
            } else {
                  gnome_app_insert_menus(app, insert_pnt, entry);
                  if ( ! create_views_submenu(vpd) ) {
                        gnome_app_remove_menus(app, insert_pnt, 1);
                  }
            }
      }

}

GtkWidget* menubar_create (GList *view_plugins)
{
      GtkWidget *wid;
      gchar foo[80];
      gchar *insert;
      
      gnome_app_create_menus(app, main_menu);
      
      /* you want an explanation ? ok :
       *  we insert menu entries using gnome_app_insert_menus which has the
       *  insert point as third arg -> "File/Print/".
       *  But gnome l10n renames the menus to "Fichier" and "Imprimer" (for
       *  french) using its locale messages. The problem is that when I'll
       *  insert menus to _("File/Print/"), I'll use _my_ locale messages
       *  and if I don't have in my translations the french translation for
       *  "File/Print/" (and the same translation that from gnome) the result
       *  is simple : segfault most of the time.
       *  The answer to this problem is to get the gnome translation which is
       *  located somewhere in file_menu[3].widget once
       *  gnome_app_create_menus has been called. The widget has a field
       *  "name" which will have "<gaby>/Fichier/Imprimer"; it's now easy as
       *  removing the "<gaby>/" and adding a '/' at the end (done in
       *  create_print_menu).
       *  
       *  cool.
       * 
       *
       * update: that doesn't work with gtk 1.2.3 :( (I'll look the
       * differences later but this really piss me off)
       *
       * re-update: my fix is 3-lines long (and looks ugly)
       */

      /* creating print submenu */
      wid = file_menu[FILE_PRINT].widget;
#ifndef HAVE_LIBXML
      gtk_widget_set_sensitive(wid, FALSE);
#else
#  ifndef USE_PYTHON
      gtk_widget_set_sensitive(wid, FALSE);
#  endif
#endif
      
      if ( wid->name == NULL ) {
            debug_print("[menubar_create] looks like a problem. gtk+ 1.2.3 ?\n");
            sprintf(foo, "%s/%s", 
                  GTK_LABEL(GTK_BIN(main_menu[0].widget)->child)->label,
                  GTK_LABEL(GTK_BIN(wid)->child)->label);
            insert = foo;
      } else {
            insert = strchr(wid->name, '/')+1;
      }
      
#ifdef DEBUG_GABY
      debug_print("%s\n", GTK_LABEL(GTK_BIN(wid)->child)->label);
      debug_print("[menubar_create] main_menu[0].widget : %p\n", wid);
      debug_print("[menubar_create] name : %s\n", insert);
#endif
      if ( ! create_print_menu(insert) ) {
            gtk_widget_hide(file_menu[FILE_PRINT].widget);
            gtk_widget_hide(file_menu[FILE_PRINT+1].widget);
      }

      /* creating databases submenu */
      wid = file_menu[FILE_DATABASES].widget;
      if ( wid->name == NULL ) {
            sprintf(foo, "%s/%s", 
                  GTK_LABEL(GTK_BIN(main_menu[0].widget)->child)->label,
                  GTK_LABEL(GTK_BIN(wid)->child)->label);
            insert = foo;
      } else {
            insert = strchr(wid->name, '/')+1;
      }
      if ( ! create_databases_menu(insert) ) {
            gtk_widget_hide(file_menu[FILE_DATABASES].widget);
            gtk_widget_hide(file_menu[FILE_DATABASES+1].widget);
      }

      /* creating actions menu */
      if (! create_actions_menu((gabywindow*)(list_windows->data))){
            gtk_widget_hide(main_menu[1].widget);
      }

      /* creating views menu */
      create_views_menu(view_plugins);

      /* preferences */
      
      gnome_app_install_menu_hints(GNOME_APP(app), main_menu);
      
      return NULL;
}

#else /* ! USE_GNOME */


#if 0 /* not used anymore, still there if needed elsewhere ... */

static GtkWidget* create_subtables_menu(GList *subtables, GString *str)
{
      GtkWidget *t;
      GtkWidget *m=gtk_menu_new();
      subtable *st;
      gpointer *foo;
      
      subtables = g_list_first(subtables);
      while ( subtables != NULL ) {
            st = subtables->data;
            t = gtk_menu_item_new_with_label(st->i18n_name);
            gtk_object_set_data(GTK_OBJECT(t), "subtable", st);
            foo = g_new0(gpointer,2);
            foo[0] = (gpointer)str;
            gtk_signal_connect(GTK_OBJECT(t), "activate", 
                        NULL, foo );
/*                      GTK_SIGNAL_FUNC(print_callback), foo);    */
            gtk_menu_append(GTK_MENU(m), t);
            gtk_widget_show(t);
            
            subtables = g_list_next(subtables);
      }
      
      return m;
}

#endif

static GtkWidget* create_print_submenu()
{
      GtkWidget *t;
      GtkWidget *m=gtk_menu_new();
      GList *list;
      PrintPluginData *ppd;
      GList *print_plugins = list_print_plugins;

      if ( print_plugins == NULL ) return m;
      list = g_list_first(print_plugins);

      while ( list != NULL ) {
            ppd = list->data;
            
            t = gtk_menu_item_new_with_label(ppd->i18n_name);
            gtk_signal_connect(GTK_OBJECT(t), "activate", 
                        GTK_SIGNAL_FUNC(print_callback), list->data);
            gtk_menu_append(GTK_MENU(m), t);
            gtk_widget_show(t);
            
            list = g_list_next(list);
      }

      gtk_widget_show(m);
      
      return m;
}

static GtkWidget* create_databases_submenu()
{
      GtkWidget *t;
      GtkWidget *m = gtk_menu_new();
      int i;
      DIR* directory;
      struct dirent *direntry;
      char str[PATH_MAX];
      
      i=0;
      while ( dbs[i++].name != NULL ) ;
      i--;
      
      debug_print("[create_dabases_menu] number of items to add: %d\n", i);

      while ( --i >= 0 ) {
            if ( strcmp(dbs[i].cmd, appname) == 0 ) continue;
            debug_print("[create_databases_menu] adding %s\n", dbs[i].name);

            t = gtk_menu_item_new_with_label(dbs[i].name);
            gtk_signal_connect(GTK_OBJECT(t), "activate", 
                        GTK_SIGNAL_FUNC(database_callback), dbs[i].cmd);
            gtk_menu_append(GTK_MENU(m), t);
            gtk_widget_show(t);
      }
      
      /* contribution by Emmanueal Jeandel */
      sprintf(str, "%s/.gaby", g_get_home_dir());
      directory = opendir(str);
      while ( directory && (direntry = readdir(directory)) != NULL){
            if ((!strncmp("desc.", direntry->d_name,5)) &&
                  (direntry->d_name[strlen(direntry->d_name)-1] != '~' ) )
            {
                  debug_print("[create_databases_submenu] adding %s\n", direntry->d_name);
            }
      }
      closedir(directory);
      /* end of contrib */
      
      t = gtk_menu_item_new();
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
      
#if 1
      t = gtk_menu_item_new_with_label(_("Other..."));
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(otherdb_callback), NULL);
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);

      t = gtk_menu_item_new();
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
#endif
      
      t = gtk_menu_item_new_with_label(_("Create a new one..."));
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(launchbuilder_callback), NULL);
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);

      gtk_widget_show(m);
      
      return m;
}

static GtkWidget* create_file_menu(GList *view_plugins)
{
/*
 * (File)
 *    Write
 *    Import ...
 *    -----
 *    Print -> [..]
 *    -----
 *    Databases -> [..]
 *    -----
 *    Exit
 */
      GtkWidget *t;
      GtkTooltips *tips;
      GtkWidget *m = gtk_menu_new();

      tips = gtk_tooltips_new();
      

      t = gtk_menu_item_new_with_label(_("Write"));
      gtk_tooltips_set_tip(tips, t, _("Write data on disk"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(menu_tables_save), list_tables);
      gtk_widget_show(t);

#if 0
      t = gtk_menu_item_new_with_label(_("Management..."));
      gtk_tooltips_set_tip(tips, t, _("Manage different aspects of tables"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(management_callback), tables);
      gtk_widget_show(t);
#endif
      t = gtk_menu_item_new_with_label(_("Import..."));
      gtk_tooltips_set_tip(tips, t, 
                  _("Import datas from a file in a foreign format"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                        GTK_SIGNAL_FUNC(import_callback), NULL);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Export..."));
      gtk_tooltips_set_tip(tips, t, 
                  _("Export datas to a file in a foreign format"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                        GTK_SIGNAL_FUNC(export_callback), NULL);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new();
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Print"));
#ifndef HAVE_LIBXML
      gtk_widget_set_sensitive(t, FALSE);
#else
#  ifndef USE_PYTHON
      gtk_widget_set_sensitive(t, FALSE);
#  endif
#endif
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), create_print_submenu());
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
            
      t = gtk_menu_item_new();
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Databases"));
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), create_databases_submenu());
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
            
      t = gtk_menu_item_new();
      gtk_menu_append(GTK_MENU(m), t);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Exit"));
      gtk_tooltips_set_tip(tips, t, _("Exit Gaby"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(gaby_quit_callback), list_tables);
      gtk_widget_show(t);

      return m;
}

static GtkWidget* create_settings_menu ()
{
/*
 * (Settings)
 *    Windows binding ...
 *    Preferences ...
 */
      GtkWidget *t;
      GtkTooltips *tips;
      GtkWidget *m = gtk_menu_new();

      tips = gtk_tooltips_new();
      
      t = gtk_menu_item_new_with_label(_("Windows binding..."));
      gtk_tooltips_set_tip(tips, t,  _("Define how windows are related"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(windows_binding_callback), NULL);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Preferences..."));
      gtk_menu_append(GTK_MENU(m), t);
#if 0
      gtk_object_set_data(GTK_OBJECT(t), "actions", actions);
      gtk_object_set_data(GTK_OBJECT(t), "view_plugins", view_plugins);
      gtk_object_set_data(GTK_OBJECT(t), "print_plugins", print_plugins);
      gtk_object_set_data(GTK_OBJECT(t), "tables", tables);
#endif
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(preferences_clicked), NULL);
      gtk_widget_show(t);
      
      return m;
}

static GtkWidget* create_help_menu()
{
      GtkWidget *t;
      GtkTooltips *tips;
      GtkWidget *m = gtk_menu_new();

      tips = gtk_tooltips_new();

      t = gtk_menu_item_new_with_label(_("Help ..."));
      gtk_widget_set_sensitive(t, FALSE);
      gtk_tooltips_set_tip(tips, t, _("Brings information to you"),"");
      gtk_menu_append(GTK_MENU(m), t);
/*    gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(gtk_main_quit), NULL);*/
      gtk_widget_show(t);

      t = gtk_menu_item_new_with_label(_("About ..."));
      gtk_tooltips_set_tip(tips, t, _("Shows various info about Gaby"),"");
      gtk_menu_append(GTK_MENU(m), t);
      gtk_signal_connect(GTK_OBJECT(t), "activate", 
                  GTK_SIGNAL_FUNC(about_gaby_cb), NULL);
      gtk_widget_show(t);
      

      return m;
}

static GtkWidget* create_views_submenu(ViewPluginData *type)
{
      GtkWidget *t;
      GtkTooltips *tips;
      view *f;
      GtkWidget *m=gtk_menu_new();
      GList *a=g_list_first(list_views);
      int i = 0;

      tips = gtk_tooltips_new();

      while ( a != NULL ) {
            f = a->data;
            a = g_list_next(a);
            if ( f->type != type )
                  continue;
            i++;
            t = gtk_menu_item_new_with_label(f->name);
            
            gtk_signal_connect(GTK_OBJECT(t), "activate", 
                        GTK_SIGNAL_FUNC(new_view_create_callback),f);
            
            gtk_menu_append(GTK_MENU(m), t);
            gtk_widget_show(t);
      }

      if ( i == 0 ) {
            gtk_widget_destroy(m);
            return NULL;
      }
      
      return m;
}

static GtkWidget* create_views_menu( GList *view_plugins )
{
      GtkWidget *m=gtk_menu_new();
      ViewPluginData *vpd;
      GList *plugins;
      
      plugins = g_list_first(view_plugins);

      while (plugins) {
            GtkWidget *t, *subm;

            vpd = plugins->data;
            subm = create_views_submenu(vpd);

            if ( subm ) {
                  t = gtk_menu_item_new_with_label(vpd->i18n_name);
                  gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), subm);
                  gtk_menu_append(GTK_MENU(m), t);
                  gtk_widget_show(t);
            }

            plugins = g_list_next(plugins);
      }
      
      return m;
}

static GtkWidget* create_actions_menu( gabywindow *window )
{
      GtkWidget *m;
      table *table = window->view->subtable->table;
      
      m = actions_menu_for_table(table, window);

      return m;
}

GtkWidget* menubar_create (GList *view_plugins)
{
      GtkWidget *mb = gtk_menu_bar_new();
      GtkWidget *t;
      GtkWidget *sub;
      
      t = gtk_menu_item_new_with_label(_("File"));
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), 
                              create_file_menu (view_plugins));
      gtk_menu_bar_append(GTK_MENU_BAR(mb), t);
      gtk_widget_show(t);
      
      sub = create_actions_menu( (gabywindow*)(list_windows->data) );
      if ( sub != NULL ) {
            t = gtk_menu_item_new_with_label(_("Actions"));
            gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), sub );
            gtk_menu_bar_append(GTK_MENU_BAR(mb), t);
            gtk_widget_show(t);
      }
      
      t = gtk_menu_item_new_with_label(_("Views"));
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), 
                              create_views_menu(view_plugins));
      gtk_menu_bar_append(GTK_MENU_BAR(mb), t);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Settings"));
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), create_settings_menu());
      gtk_menu_bar_append(GTK_MENU_BAR(mb), t);
      gtk_widget_show(t);
      
      t = gtk_menu_item_new_with_label(_("Help"));
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(t), create_help_menu());
      gtk_menu_bar_append(GTK_MENU_BAR(mb), t);
      gtk_menu_item_right_justify(GTK_MENU_ITEM(t));
      gtk_widget_show(t);
      
      gtk_widget_show(mb);
      return mb;
}

#endif /* ! USE_GNOME */

gboolean delete_view(GtkWidget *win, gpointer data)
{
      GList *tmp;
      gabywindow *window;
      gabywindow *other;
#ifdef DEBUG_GABY
      debug_print("[delete_view] win : %p - data : %p\n", win, data);
      debug_print("[delete_view] actually list_windows is : %p\n", list_windows);
#endif
      if ( GTK_IS_OBJECT(win) ) {
            window = gtk_object_get_data(GTK_OBJECT(win), "window");
#ifdef DEBUG_GABY
            debug_print("[delete_view] removing %p\n", window);
#endif
            list_windows = g_list_remove(list_windows, window);

            tmp = g_list_first(list_windows);
            while ( tmp != NULL ) {
                  if ( tmp->data == NULL ) {
                        tmp = g_list_next(tmp);
                        continue;
                  }
                  other = tmp->data;
                  other->bound_windows = g_list_remove( 
                              other->bound_windows, window);
                  tmp = g_list_next(tmp);
            }
            g_free(window);
      }

#ifdef DEBUG_GABY
      debug_print("[delete_view] ok to delete this window\n");
#endif
      return FALSE;
}

static void new_view_create_callback(GtkWidget *t, view *v)
{
      GList *tables;
      GList *views;
      struct window_info wi;
      gabywindow *win;
      
      tables = list_tables;
      views = list_views;

      wi.view = v;
      wi.x = -1; wi.y = -1; wi.height = -1; wi.width = -1;
      win = new_view_create(&wi);
      if ( win != NULL && win->widget != NULL && win->parent != NULL) {
            gtk_widget_show(win->parent);
      }

#ifdef DEBUG_GABY
      debug_print("[new_view_create_callback] the end\n");
#endif
}

static void do_action(GtkWidget *t, action *act)
{
#if 1
      gabywindow *win = gtk_object_get_data(GTK_OBJECT(t), "win");
/*    GList *tables = list_tables;
      GList *subtables = list_subtables;
      GList *views = list_views;
*/    int *id = NULL;
      view *v = NULL;
      int i;
      record *r = NULL;

      if ( win != NULL ) {
            id = &(win->id);
            v = win->view;
      }

      for ( i=0; i < act->nb_params; i++ ) {
            if ( act->params[i].type == P_FIELD  ) {
                  if ( r == NULL && v->type->view_save != NULL ) {
                        /*  we could perhaps do this for the
                         *  user. this will need a way to access
                         *  view_save_record (that is
                         *  form_record_save in the form
                         *  plug-in) or require that view_fill
                         *  first saves the record.
                         *
                         *  Update: I decided to go the
                         *  view_save way. The documentation
                         *  isn't updated yet.
                         */
                        v->type->view_save(win);
                  }
                  r = get_record_no(act->params[i].table, *id);
                  if ( r == NULL ) {
                        gaby_errno = CUSTOM_WARNING;
                        gaby_message = g_strdup(_("You need to be on a saved record before doing any action on it.\n"));
                        gaby_perror_in_a_box();
                        return;
                  }
            }
      }
      
      for ( i=0; i<act->nb_params; i++ ) {
            if ( act->params[i].type == P_FIELD ) {
                  memcpy(&act->params[i].val, 
                        &r->cont[act->params[i].field_no], 
                        sizeof(union data));
            }
      }

      switch ( act->type ) {
            case PLUG_IN:
            {
                  do_action_plugin(act);
            } break;
            case SCRIPT:
            {
                  do_action_script(act);
            } break;
            case SCRIPT_FU:
            {
                  do_action_script_fu(act);
            } break;
      }
      
#else
      gaby_message = g_strdup( _(
            "Actions have been removed from this release waiting\n"
            "that I write something really better for them.") );
      gaby_errno = CUSTOM_MESSAGE;
      gaby_perror_in_a_box();
#endif
}

void gaby_quit_callback(GtkWidget *t, GList *tables)
{
      gaby_quit(tables);
}

#ifndef USE_GNOME
static void quit_button_clicked(GtkWidget *but, GtkWidget *dialog)
{
      int nb = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(but), "nb"));

      gtk_object_set_data(GTK_OBJECT(dialog), "nb", GINT_TO_POINTER(nb));
      gtk_widget_hide(dialog);

      gtk_main_quit();
}
#endif

static void save_editable_windows()
{
      GList *l = list_windows;
      gabywindow *w;
      view *v;
      
      while ( l != NULL ) {
            w = l->data;
            l = g_list_next(l);
#if 0
            if ( ! GTK_IS_WIDGET(w->widget) ) {
#ifdef DEBUG_GABY
                  debug_print("aie aie, a window has been destroyed\n");
#endif
                  continue;
            }
#endif
            v = w->view;
            if ( ! (v->type->capabilities & EDITABLE) )
                  continue;
#ifdef DEBUG_GABY
            debug_print("%p (%s) is editable and ", w, v->name);
            if ( w->updated ) {
                  debug_print("has been updated\n");
            } else {
                  debug_print("hasn't been updated\n");
            }
#endif
            if ( v->type->view_save == NULL ) {
#ifdef DEBUG_GABY
                  debug_print("eh you, plug-in writer! you should implement view_save !\n");
#endif
                  continue;
            }
            if ( w->updated ) v->type->view_save(w);
      }
}

gboolean gaby_quit(GList *tables)
{
      GtkWidget *d, *l;
      GtkWidget *vbox;
#ifndef USE_GNOME
      GtkWidget *but;
#endif
      int button;

      tables = list_tables;

#ifdef DEBUG_GABY
      if ( tables == NULL ) {
            debug_print("gaby_quit has been called without tables\n");
      }
#endif

      /* this ask views if the current record is modified
       * updated == TRUE can't work when editing a record (ie no
       * calls to record_{add,modify,delete}.
       * This asks every views (that are editable) to know if they
       * have something changed (what a pain)
       */
      save_editable_windows();

#ifdef USE_SQL
      PQfinish(sqlconn);
#else /* ! USE_SQL */
      if ( tables_modified() == TRUE ) {
            debug_print("[gq] there are unsaved changes.\n");

#  ifdef USE_GNOME
            /* this part is from gnumeric (but the gtk part is mine) */
            d = gnome_dialog_new(_("Warning"), 
                        GNOME_STOCK_BUTTON_YES,
                        GNOME_STOCK_BUTTON_NO,
                        GNOME_STOCK_BUTTON_CANCEL,
                        NULL);
            vbox = GNOME_DIALOG(d)->vbox;
#  else /* ! USE_GNOME */
            d = gtk_dialog_new();

            but = gtk_button_new_with_label(_("Yes"));
            gtk_object_set_data(GTK_OBJECT(but), "nb", GINT_TO_POINTER(0));
            gtk_signal_connect(GTK_OBJECT(but), "clicked", 
                        GTK_SIGNAL_FUNC(quit_button_clicked), d);
            gtk_widget_show(but);
            gtk_box_pack_start(GTK_BOX(GTK_DIALOG(d)->action_area), 
                        but, TRUE, TRUE, 0 );
            
            but = gtk_button_new_with_label(_("No"));
            gtk_object_set_data(GTK_OBJECT(but), "nb", GINT_TO_POINTER(1));
            gtk_signal_connect(GTK_OBJECT(but), "clicked", 
                        GTK_SIGNAL_FUNC(quit_button_clicked), d );
            gtk_widget_show(but);
            gtk_box_pack_start(GTK_BOX(GTK_DIALOG(d)->action_area), 
                        but, TRUE, TRUE, 0 );
            
            but = gtk_button_new_with_label(_("Cancel"));
            gtk_object_set_data(GTK_OBJECT(but), "nb", GINT_TO_POINTER(2));
            gtk_signal_connect(GTK_OBJECT(but), "clicked", 
                        GTK_SIGNAL_FUNC(quit_button_clicked), d );
            gtk_widget_show(but);
            
            gtk_box_pack_start(GTK_BOX(GTK_DIALOG(d)->action_area), 
                        but, TRUE, TRUE, 0 );
            gtk_window_set_modal(GTK_WINDOW(d), TRUE);

            vbox = GTK_DIALOG(d)->vbox;
#  endif /* ! USE_GNOME */
            
            l = gtk_label_new(_("There are unsaved changes, save them ?"));
            gtk_widget_show(l);
            gtk_box_pack_start (GTK_BOX (vbox), l, TRUE, TRUE, 0);

            gtk_window_set_position (GTK_WINDOW (d), GTK_WIN_POS_MOUSE);

#  ifdef USE_GNOME
            button = gnome_dialog_run (GNOME_DIALOG (d));
#  else /* ! USE_GNOME */
            gtk_widget_show(d);
            gtk_main();
            button=GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(d),"nb"));
#  endif /* ! USE_GNOME */
            
            switch ( button ) {
                  case 0: /* Yes */
                  {
                        debug_print("[gq] I'll save %p\n", tables);
                        tables_save();
                  } break;
                  case 1: /* No */
                        break;
                  case 2: /* Cancel */
                  case -1:
                  {
                        gtk_widget_destroy(d);
                        return TRUE;
                  } break;
            }
      }
#endif /* ! USE_SQL */
      
      debug_print("woow, no segfault this time ! :)\n");

      gtk_main_quit();

#ifdef DEBUG_GABY
      g_mem_profile();
#endif
      exit(0);

      return FALSE;     /* we'll never reach this point :( */
}

#ifndef USE_GNOME
      /* gtk+ is a pain once you try gnome :) */
static void close_dialog(GtkWidget *w, GtkWidget *dlg)
{
      gtk_widget_destroy(dlg);
}

#endif

#ifdef USE_GNOME
static void show_licence(GtkWidget *wid, gpointer data)
{
      GtkWidget *win;
      GtkWidget *gless;
      /* I don't want to enlarge gaby by 17k */
      char *common_locations[] = {
            "/usr/doc/copyright/GPL",           /* Debian (old) */
            "/usr/share/common-licenses/GPL",   /* Debian (new) */
            NULL,                         /* $(prefix)/doc/gaby */
            NULL,                         /* /usr/src/linux */
            NULL
      };
      char docgaby[PATH_MAX];
      char *filename;
      int i=0, j;
      FILE *f;

#ifdef DEBUG_GABY
      debug_print("[show_licence] ...\n");
#endif
      sprintf(docgaby, "%s/COPYING", DOCDIR);
      common_locations[2] = docgaby;
      
      win = gnome_dialog_new(_("The GNU General Public Licence"), 
                  GNOME_STOCK_BUTTON_OK, NULL );
      gnome_dialog_set_close(GNOME_DIALOG(win), TRUE);
      gless = gnome_less_new();
      gtk_widget_set_usize(gless, 480, 400);
      gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(win)->vbox),gless,TRUE,TRUE,0);
      
      i=0;
      do {
            filename = common_locations[i];
            i++;
#ifdef DEBUG_GABY
            debug_print("[show_licence] trying %s\n", filename);
#endif
            if ( i == 4 ) { /* /usr/src/linux */
                  f = fopen("/usr/src/linux/COPYING", "r");
                  if ( f == NULL ) continue;
                  for ( j = 0; j < 12; j++ ) {
                        fgets(docgaby, 90, f);
                  }
                  gnome_less_show_filestream(GNOME_LESS(gless), f);
                  fclose(f);
                  break;
            } else {
                  if ( filename == NULL ) {
                        gtk_widget_destroy(gless);
                        gnome_app_message(GNOME_APP(app), 
_("Gaby is copyrighted under the term of the GPL licence\n"
  "but was unable to find a copy of it on your system.\n"
  "If you know where your distribution put this file,\n"
  "please send a mail to <fpeters@tiscalinet.be>, thanks."));
                        return;
                  }
            }
      } while ( ! gnome_less_show_file(GNOME_LESS(gless), filename) );

#ifdef DEBUG_GABY
      debug_print("[show_licence] let's show it\n");
#endif
      gtk_widget_show(gless);
      gtk_widget_show(win);
      
}
#endif /* USE_GNOME */

/*static*/
void about_gaby_cb(GtkWidget *t, gpointer data)
{
      static GtkWidget *about = NULL;
      const gchar *main_authors[] = {
            "Ron Bessems <R.E.M.W.Bessems@stud.tue.nl>",
            "Frederic Peters <fpeters@tiscalinet.be>",
            NULL
      };
      gchar *authors[10];
      gchar str[255];
      gint i;
#ifndef USE_GNOME
      GtkWidget *vbox;
      GtkWidget *button;
      GtkWidget *label;
#endif
      
      /* Gnome (gnome-libs/devel-docs/suggestions (still accurate ?)) says to
       * do that but I saw _no_ gnomeapps doing that :) (there is basically
       * two ways : allowing lots of about windows or making the dialog modal
       * they definitely should read this file :) )
       */
      if ( GTK_IS_OBJECT(about) && GTK_IS_WINDOW(about) ) {
            gtk_widget_show(about);
            gdk_window_raise((GdkWindow*)about->window);
            /* and do you think it works ? no ! and nobody cares ! :) */
            return;
      }

      /* Create author list. */
      for (i=0; main_authors[i] != NULL; i++)
            authors[i] = (char*)main_authors[i];
      if (data != NULL) authors[i++] = data;
      authors[i] = NULL;
      
#ifdef CODENAME
      sprintf(str, "%s (%s)", VERSION, CODENAME);
#else
      strcpy(str, VERSION);
#endif

#ifdef USE_GNOME
      
      about = gnome_about_new( "Gaby", str,
                        _("(C) 1998-2001 Frederic Peters"), 
                        (const gchar**)authors, 
                        _("Personal databases manager"), NULL);
      gnome_dialog_set_parent(GNOME_DIALOG(about), GTK_WINDOW(app));
      gnome_dialog_close_hides(GNOME_DIALOG(about), TRUE );
      gnome_dialog_append_button(GNOME_DIALOG(about), _("Show the licence"));
      gnome_dialog_button_connect(GNOME_DIALOG(about), 1, 
                              GTK_SIGNAL_FUNC(show_licence), NULL );
      gtk_widget_show(about);
                        
#else
      about = gtk_dialog_new();
      
      gtk_window_set_title(GTK_WINDOW(about), _("About"));
      button = gtk_button_new_with_label(_("OK"));
      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about)->action_area), 
                                    button, TRUE, TRUE, 5 );
      gtk_widget_show(button);
      gtk_signal_connect(GTK_OBJECT(button), "clicked", close_dialog, about);
      
      vbox = GTK_DIALOG(about)->vbox;
      gtk_container_set_border_width(GTK_CONTAINER(vbox), 5 );
      
      label = gtk_label_new(str);
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 5 );
      label = gtk_label_new(_("(C) 1998-2001 Frederic Peters"));
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 2 );
      label = gtk_label_new(_("Personal databases manager"));
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 2 );
#if 0
      /* the update is not automatic but it is at least easy :) */
      sprintf(str, "%s :\n%s,\n%s", _("Authors"), authors[0], authors[1]);
#endif
      /* Now its a bit harder */
      sprintf(str, "%s :\n%s", _("Authors"), authors[0]);
      for (i=1; authors[i] != NULL; i++)
            sprintf(str, "%s,\n %s", str, authors[i]);
                  
      label = gtk_label_new(str);
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0 );
      
      gtk_widget_show(about);
#endif
}

#if 0
static void management_callback(GtkWidget *wid, GList *tables)
{
      gtk_widget_show(management_dialog(tables));
}
#endif 

static void import_callback(GtkWidget *wid, gpointer data)
{
      GList *subtables = list_subtables;
      subtable *st;
      
      if ( g_list_length(subtables) == 1 ) {
            st = subtables->data;
            import_export_dialog(st, 0);
      } else {
            gboolean *blabla;
            blabla = select_subtable_dialog(
                        _("Select the subtable you want to import "
                          "new records in."),
                        import_real_callback, NULL);
            /*g_free(blabla);*/
      }
}

static void export_callback(GtkWidget *wid, gpointer data)
{
      GList *subtables = list_subtables;
      subtable *st;

      if ( g_list_length(subtables) == 1 ) {
            st = subtables->data;
            import_export_dialog(st, 1);
      } else {
            gboolean *blabla;
            blabla = select_subtable_dialog(
                        _("Select the subtable you want to export."),
                        export_real_callback, NULL);
            /*g_free(blabla);*/
      }
}

static void print_callback(GtkWidget *t, PrintPluginData *ppd)
{
#ifdef HAVE_LIBXML
      GList *subtables = list_subtables;

      if ( g_list_length(subtables) == 1 ) {
            subtable *st = subtables->data;

            /* only one subtable -> we don't show the 'select a subtable'
             * dialog */

            print_plugin_open(ppd, st);
            
#if 0
            /* warning: code duplicated from gtk_print_dlg.c (print_real) */
            sprintf(filename, PLUGINS_DIR "/print/%s.xml", ppd->name);
#ifdef HAVE_LIBXML
            if ( print_load_xml(filename, &pages, &names) != 0)
                  return;
#endif
            dlg = build_gtk_print_dialog(st, pages, names);
            gtk_object_set_data(GTK_OBJECT(dlg), "pp_name", ppd->name);
            gtk_object_set_data(GTK_OBJECT(dlg), "pages", pages);
            gtk_object_set_data(GTK_OBJECT(dlg), "names", names);
            gtk_object_set_data(GTK_OBJECT(dlg), "subtable", st);

            gtk_widget_show(dlg);
#endif

      } else {
            gtk_widget_show(print_dialog(ppd));
      }
#else /* ! HAVE_LIBXML */
      gaby_message = g_strdup(_("Printing requires Gaby to be compiled with libxml"));
      gaby_errno = CUSTOM_WARNING;
      gaby_perror_in_a_box();
#endif /* ! HAVE_LIBXML */
}

static void database_callback(GtkWidget *t, gpointer data)
{
      gchar *cmd = data;
      gchar real_cmd[200];

      debug_print("[database_clicked] launching %s\n", cmd);
      sprintf(real_cmd, "gaby --as %s --disable-other-windows --skip-startup-actions", cmd);

      if (fork()) return;
      
      setsid();
      if(execlp("gaby","gaby","--as", cmd, "--disable-other-windows",
                  "--skip-startup-actions", NULL)==-1)
      {
            exit(100);
      }
      exit(0);

}

#ifdef USE_GNOME
static void otherdb_reply_cb(gchar* string, gpointer data)
{
#ifdef DEBUG_GABY
      debug_print("[otherdb_reply_cb] data: %s\n", string);
#endif
      if ( string == NULL ) return;
      
      database_callback(NULL, string);
}
#else /* ! USE_GNOME */
static void otherdb_reply_cb(GtkWidget *but, GtkWidget *entry)
{
      gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
      if ( strlen(text) == 0 ) return;
      database_callback(NULL, text);
}
#endif /* ! USE_GNOME */

#ifndef USE_GNOME
static void request_string_dlg(char *title, char *msg, GtkCallback cb)
{
      GtkWidget *dlg;
      GtkWidget *vbox, *vbox2;
      GtkWidget *entry;
      GtkWidget *hbb, *button;

      dlg = gtk_dialog_new();
      gtk_window_set_title(GTK_WINDOW(dlg), title);
      vbox = GTK_DIALOG(dlg)->vbox;

      vbox2 = gtk_vbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
      gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
      
      gtk_box_pack_start(GTK_BOX(vbox2), gtk_label_new(msg), TRUE, TRUE, 0);
      entry = gtk_entry_new();
      gtk_box_pack_start(GTK_BOX(vbox2), entry, TRUE, TRUE, 0);
      
      hbb = gtk_hbutton_box_new();
      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), hbb,
                        TRUE, TRUE, 5);
      
      button = gtk_button_new_with_label(_("OK"));
      gtk_signal_connect(GTK_OBJECT(button), "clicked", cb, entry);
      gtk_signal_connect(GTK_OBJECT(button), "clicked", close_dialog, dlg);
      gtk_container_add(GTK_CONTAINER(hbb), button);
      
      button = gtk_button_new_with_label(_("Cancel"));
      gtk_signal_connect(GTK_OBJECT(button), "clicked", close_dialog, dlg);
      gtk_container_add(GTK_CONTAINER(hbb), button);
      
      gtk_widget_show_all(dlg);
}
#endif /* ! USE_GNOME */

static void otherdb_callback(GtkWidget *t, gpointer data)
{
#ifdef USE_GNOME
      gnome_app_request_string(GNOME_APP(app),
                        _("Please enter the database name"),
                        otherdb_reply_cb, NULL);
#else
      request_string_dlg( _("Database name"),
                      _("Please enter the database name"),
                      (GtkCallback)otherdb_reply_cb);
#endif
}

static void launchbuilder_callback(GtkWidget *t, gpointer data)
{
      if (fork()) return;
      
      setsid();
      if(execlp("gabybuilder","gabybuilder", NULL)==-1) {
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(_("Unable to start the builder"));
            gaby_perror_in_a_box();
            exit(100);
      }
      exit(0);
}

/* launch_homebrewed_script */

struct lhs_dlg { /* short for launch_homebrewed_script_dialog */
      GtkWidget *fileselection;
      GtkWidget *filename_entry;
      GtkWidget *interpreter_entry;
      GtkWidget *description_text;
};

static void launch_homebrewed_script_cancel_cb (GtkWidget *but, struct lhs_dlg *lhs)
{
      GtkWidget *fs = lhs->fileselection;
      g_free(lhs);
      gtk_widget_destroy(fs);
}

static void launch_homebrewed_script_ok_cb (GtkWidget *but, struct lhs_dlg *lhs )
{
      GtkFileSelection *fs = GTK_FILE_SELECTION(lhs->fileselection);
      char filename[PATH_MAX];
      action act;
      char scriptline[PATH_MAX+50];
      char interpreter[50];

      strcpy(filename, gtk_file_selection_get_filename(fs));
      strcpy(interpreter, gtk_entry_get_text(GTK_ENTRY(lhs->interpreter_entry)));
      launch_homebrewed_script_cancel_cb(but, lhs);

#ifdef DEBUG_GABY
      debug_print("[lhs_ok_cb] running %s\n", filename);
#endif
      sprintf(scriptline, "%s:%s", interpreter, filename);
      act.what.script = scriptline;
      act.nb_params = 0;
            /* TODO (post-2.0): scripts args
             *  have a field that the user could use to give args to the
             *  launched script */
            /* Actually redesigning this dialog box is needed */
      
      do_action_script_fu(&act);
      
}

static void homebrewedsel_changed (GtkWidget *entry, struct lhs_dlg *lhs)
{
      char line[201], *s;
      GtkFileSelection *fs = GTK_FILE_SELECTION(lhs->fileselection);
      GtkWidget *ok_button = fs->ok_button;
      char *filename;
      struct stat buf;
      FILE *f;
      enum { UNKNOWN, PYTHON, PERL, GUILE } type_int = UNKNOWN;
      int done = 0;
      
      filename = gtk_file_selection_get_filename(fs);
#ifdef DEBUG_GABY
      debug_print("[homebrewedlist_changed] filename: %s\n", filename);
#endif

      gtk_widget_set_sensitive(ok_button, FALSE);

      gtk_text_set_point ( GTK_TEXT(lhs->description_text), 0 );
      gtk_text_forward_delete ( GTK_TEXT(lhs->description_text), 
                  gtk_text_get_length(GTK_TEXT(lhs->description_text)));

      if ( strlen(filename) == 0 || stat(filename, &buf) < 0 || 
                                          ! S_ISREG(buf.st_mode) ) {
            gtk_entry_set_text(GTK_ENTRY(lhs->filename_entry), _("None"));
            gtk_entry_set_text(GTK_ENTRY(lhs->interpreter_entry), _("Unknown"));
            return;
      }

      gtk_entry_set_text(GTK_ENTRY(lhs->filename_entry), 
            strchr(filename, '/') ? strrchr(filename, '/')+1 : filename );
      f = fopen(filename, "r");
      if ( f == NULL ) {
            gtk_entry_set_text(GTK_ENTRY(lhs->interpreter_entry), "");
            return;
      }

      fgets(line, 200, f);
      if ( line[0] == '#' && line[1] == '!' ) {
            s = strstr(line, " -i ");
            if ( s == NULL ) s = strstr(line, " --interpreter ");
            if ( s != NULL ) {
                  s++;
                  while ( ! isspace((int)*s) ) s++;
                  s++;
                  strchr(s, ' ')[0] = 0;
#ifdef DEBUG_GABY
                  debug_print("[hbl_c] int : %s\n", s);
#endif
                  if      ( g_strcasecmp(s, "python") == 0 )
                                          type_int = PYTHON;
                  else if ( g_strcasecmp(s, "perl")   == 0 )
                                          type_int = PERL;
                  else if ( g_strcasecmp(s, "guile")  == 0 )
                                          type_int = GUILE;
            }
      }
      do {
            s = line;
            if ( g_strncasecmp(s, "# Interpreter: ", 15) == 0 ) {
                  s[strlen(s)-1] = 0;
#ifdef DEBUG_GABY
                  debug_print("[hbs_changed] int: %s", s+15);
#endif
                  if      ( g_strcasecmp(s+15, "Python") == 0 )
                                          type_int = PYTHON;
                  else if ( g_strcasecmp(s+15, "Perl"  ) == 0 )
                                          type_int = PERL;
                  else if ( g_strcasecmp(s+15, "Guile" ) == 0 )
                                          type_int = GUILE;
#ifdef DEBUG_GABY
                  debug_print(" (-> %d)\n", type_int );
#endif
            }
            if ( g_strncasecmp(s, "# Description: ", 15) == 0 ) {
                  gtk_text_insert( GTK_TEXT(lhs->description_text), 
                              NULL, NULL, NULL, s+15, -1);
                  done++;
            }
            if ( g_strncasecmp(s, "# Descfiles: ", 13) == 0 ) {
#if 0
                  gaby_message = g_strdup(_("The script you chose is not suitable\nfor the current descfile."));
                  gaby_errno = CUSTOM_WARNING;
                  gaby_perror_in_a_box();
#endif
                  /* TODO (post-2.0, perhaps): tell the user that this
                   * script isn't suitable for the current descfile
                   */
                  /* 20001123: I don't know why I disabled it; probably
                   * a good reason... (investigation needed)
                   * (in case of startup scripts ?)
                   */

                  done++;
            }
            if ( done == 2 && type_int != UNKNOWN ) break;
            fgets(line, 200, f);
      } while ( ! feof(f) );

      if ( type_int != UNKNOWN ) gtk_widget_set_sensitive(ok_button, TRUE);
            
      switch ( type_int ) {
            case PYTHON:
            {
                  gtk_entry_set_text(
                        GTK_ENTRY(lhs->interpreter_entry), "Python");
#ifndef USE_PYTHON
                  gtk_entry_append_text( 
                              GTK_ENTRY(lhs->interpreter_entry), 
                              _(" (unavailable)"));
                  gtk_widget_set_sensitive(ok_button, FALSE);
#endif
            } break;
            case PERL:
            {
                  gtk_entry_set_text( 
                        GTK_ENTRY(lhs->interpreter_entry), "Perl");
#ifndef USE_PERL
                  gtk_entry_append_text( 
                              GTK_ENTRY(lhs->interpreter_entry), 
                              _(" (unavailable)"));
                  gtk_widget_set_sensitive(ok_button, FALSE);
#endif
            } break;
            case GUILE:
            {
                  gtk_entry_set_text( 
                        GTK_ENTRY(lhs->interpreter_entry), 
                        "Guile");
#ifndef USE_GUILE
                  gtk_entry_append_text( 
                              GTK_ENTRY(lhs->interpreter_entry), 
                              _(" (unavailable)"));
                  gtk_widget_set_sensitive(ok_button, FALSE);
#endif
            } break;
            case UNKNOWN:
            default:
            {
                  gtk_entry_set_text(GTK_ENTRY(lhs->interpreter_entry), 
                              _("Unknown"));
            } break;
      }
      fclose(f);
}

static void launch_homebrewed_script (GtkWidget *t, gabywindow *win)
{
      GtkWidget *dialog;
      GtkWidget *selection_entry;
      GtkWidget *infoframe, *table, *label, *entry;
      struct lhs_dlg *lhs = NULL;

      dialog = gtk_file_selection_new(_("Home-brewed scripts"));

      infoframe = gtk_frame_new(_("Informations"));
      gtk_widget_show(infoframe);
      gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(dialog)->main_vbox), 
                  infoframe, TRUE, TRUE, 3 );
      table = gtk_table_new(3, 2, FALSE);
      gtk_widget_show(table);
      gtk_container_add(GTK_CONTAINER(infoframe), table);
      
      lhs = g_new0(struct lhs_dlg, 1);
      lhs->fileselection = dialog;
      
      label = gtk_label_new(_("Filename:"));
      gtk_widget_show(label);
      gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
      
      entry = gtk_entry_new();
      gtk_entry_set_editable(GTK_ENTRY(entry), FALSE);
      gtk_widget_show(entry);
      gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 0, 1);
      lhs->filename_entry = entry;
            
      label = gtk_label_new(_("Interpreter:"));
      gtk_widget_show(label);
      gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
      
      entry = gtk_entry_new();
      gtk_entry_set_editable(GTK_ENTRY(entry), FALSE);
      gtk_widget_show(entry);
      gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2);
      lhs->interpreter_entry = entry;

      label = gtk_label_new(_("Description:"));
      gtk_widget_show(label);
      gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
      
      entry = gtk_text_new(NULL, NULL);
      gtk_widget_set_usize(entry, -2, 70); /* _bad_, should be previous_size/2 */
      gtk_text_set_editable(GTK_TEXT(entry), FALSE);
      gtk_widget_show(entry);
      gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 2, 3);
      lhs->description_text = entry;
      
      selection_entry = GTK_FILE_SELECTION(dialog)->selection_entry;
      gtk_signal_connect(GTK_OBJECT(selection_entry), "changed", 
                                    homebrewedsel_changed, lhs );
      
      gtk_widget_set_sensitive(GTK_FILE_SELECTION(dialog)->ok_button, FALSE);
      gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(dialog)->ok_button), 
                  "clicked", launch_homebrewed_script_ok_cb, lhs );
      gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(dialog)->cancel_button), 
                  "clicked", launch_homebrewed_script_cancel_cb, lhs );
      
      gtk_widget_show(dialog);

}


Generated by  Doxygen 1.6.0   Back to index