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

python.c

/*  Gaby
 *  Copyright (C) 1998-2000 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 <tables.h>
#include <records.h>
#include <files.h>
#include <windows.h>    /* for update_bound_windows */
#include <print_plg.h>

#ifdef NO_GUI
#  include <nogui_main.h>
#else
#  include <gtk_print_dlg.h>
#  include <gtk_main.h> /* for new_view_create */
#  include <gtk_menu.h> /* for gaby_quit */
#endif

#include <Python.h>

#ifdef HAVE_PYGTK
#include <pygtk/pygtk.h>
#endif

#ifdef HAVE_LIBGLADE
#include <glade/glade.h>
#endif

static PyObject *gaby_module;

typedef struct {
      PyObject_HEAD
      gabywindow *win;
} PyGabyWindow_Object;
staticforward PyTypeObject PyGabyWindow_Type;

typedef struct {
      PyObject_HEAD
      subtable *st;
} PyGabySubTable_Object;
staticforward PyTypeObject PyGabySubTable_Type;

static PyObject* PyGabyWindow_New(gabywindow *win);
static PyObject* PyGabySubTable_New(subtable *st);

/* GabyWindow Object */

static PyObject* PyGabyWindow_New(gabywindow *win)
{
      PyGabyWindow_Object *self;

      self = (PyGabyWindow_Object*)PyObject_NEW(PyGabyWindow_Object, &PyGabyWindow_Type);
      debug_print("[PyGabyWindow_New] self : %p\n", self);
      if ( self == NULL )
            return NULL;
      self->win = win;
      return (PyObject*)self;
}

static void PyGabyWindow_dealloc(PyGabyWindow_Object *self)
{
      PyMem_DEL(self);
}

static int PyGabyWindow_print(PyGabyWindow_Object *self, FILE *f, int flags)
{
      gabywindow *win;
      view *v;
      
      win = self->win;
      v = win->view;
                  
      fprintf(f,"<GabyWindow, showing the subtable '%s' using the view '%s'>",
                  v->subtable->name, v->type->name );
      return 0;
}

      /* Methods */

static PyObject* py_win_move(PyObject *self, PyObject *args);
static PyObject* py_win_resize(PyObject *self, PyObject *args);
static PyObject* py_win_destroy(PyObject *self, PyObject *args);
static PyObject* py_win_add_bound_window(PyObject *self, PyObject *args);
static PyObject* py_win_remove_bound_window(PyObject *self, PyObject *args);
static PyObject* py_win_set_records_list(PyObject *self, PyObject *args);
static PyObject* py_win_get_widget(PyObject *self, PyObject *args);

static PyMethodDef window_methods[] = {
      { "move",         (PyCFunction)py_win_move, 1 },
      { "resize",       (PyCFunction)py_win_resize, 1 },
      { "destroy",            (PyCFunction)py_win_destroy, 1 },
      { "add_bound_window",   (PyCFunction)py_win_add_bound_window, 1 },
      { "remove_bound_window",(PyCFunction)py_win_remove_bound_window, 1 },
      { "set_records_list",   (PyCFunction)py_win_set_records_list, 1 },
      { "get_widget",         (PyCFunction)py_win_get_widget, 1 },
      { NULL,                 NULL }
};

/**
 * <window>.move(i, i)
 *
 * Description:
 * This method moves the window to (i, i) (respectively x and y)
 * OBSOLETE!: use gtk methods on window.gtkwindow
 **/
static PyObject* py_win_move(PyObject *self, PyObject *args)
{
#ifdef NO_GUI
      puts("No support for windows compiled!");
#else
      gabywindow *win;
      GtkWidget *parent;
      int x, y;

      if ( ! PyArg_ParseTuple(args, "ii", &x, &y)) return NULL;
      
      win = ((PyGabyWindow_Object*)self)->win;
      parent = win->parent;
      gdk_window_move(parent->window, x, y);
#endif

      return Py_None;
}

/**
 * <window>.resize(i, i)
 *
 * Description:
 * This method resizes the window to (i, i) (respectively width and height)
 * OBSOLETE!: use gtk methods on window.gtkwindow
 **/
static PyObject* py_win_resize(PyObject *self, PyObject *args)
{
#ifdef NO_GUI
      puts("No support for windows compiled!");
#else
      gabywindow *win;
      GtkWidget *parent;
      int w, h;

      if ( ! PyArg_ParseTuple(args, "ii", &w, &h)) return NULL;
      
      win = ((PyGabyWindow_Object*)self)->win;
      parent = win->parent;
      gdk_window_resize(parent->window, w, h);
#endif
      return Py_None;
}

/**
 * <window>.destroy()
 *
 * Description:
 * This method destroy the window
 **/
static PyObject* py_win_destroy(PyObject *self, PyObject *args)
{
#ifdef NO_GUI
      puts("No support for windows compiled!");
#else
      gabywindow *win;
      GtkWidget *parent;

      if ( ! PyArg_ParseTuple(args, "")) return NULL;
      
      win = ((PyGabyWindow_Object*)self)->win;
      parent = win->parent;
      gtk_widget_destroy(parent);
#endif
      return Py_None;
}

/**
 * <window>.add_bound_window(w)
 *
 * Description:
 * This method binds the window given as arg to the window
 **/
static PyObject* py_win_add_bound_window(PyObject *self, PyObject *args)
{
      PyObject *objwin;
      gabywindow *win1, *win2;
      GList *bound_windows;

      if ( ! PyArg_ParseTuple(args, "O", &objwin)) return NULL;
      
      win1 = ((PyGabyWindow_Object*)self)->win;
      win2 = ((PyGabyWindow_Object*)objwin)->win;
      
      bound_windows = win1->bound_windows;
      if ( g_list_find(bound_windows, win2) == NULL ) {
            win1->bound_windows = g_list_append ( 
                        win1->bound_windows, win2 );
      }

      return Py_None;
}

/**
 * <window>.remove_bound_window(w)
 *
 * Description:
 * This method unbinds the window given as arg from the window
 **/
static PyObject* py_win_remove_bound_window(PyObject *self, PyObject *args)
{
      PyObject *objwin;
      gabywindow *win1, *win2;
      GList *bound_windows;

      if ( ! PyArg_ParseTuple(args, "O", &objwin)) return NULL;
      
      win1 = ((PyGabyWindow_Object*)self)->win;
      win2 = ((PyGabyWindow_Object*)objwin)->win;
      
      bound_windows = win1->bound_windows;
      if ( g_list_find(bound_windows, win2) != NULL ) {
            win1->bound_windows = g_list_remove( 
                                    win1->bound_windows, win2);
      }

      return Py_None;
}

/**
 * <window>.set_records_list( (i,i,i,...) )
 *
 * Description:
 * This method reduces the amount of viewable records to the records with ids
 * (normal or fast) from the list. This is especially useful for things like
 * advanced filters. Note that using fast id will really be faster.
 **/
static PyObject* py_win_set_records_list(PyObject *self, PyObject *args)
{
      PyObject *py_list;
      int i, j, t;
      GList *rlist = NULL;
      gabywindow *win;
      view *v;
      ViewPluginData *vpd;
      
      if ( ! PyArg_ParseTuple(args, "O", &py_list)) return NULL;
      
      win = ((PyGabyWindow_Object*)self)->win;
      vpd = win->view->type;
      if ( ! v->type->capabilities & FILTERABLE ) {
            g_print("This window doesn't support this function.\n");
            return Py_None;
      }
      
      v = win->view;
      
      for ( i=0; i<PyList_Size(py_list); i++ ) {
            t = PyInt_AsLong(PyList_GetItem(py_list, i));
            if ( t < 0 ) {
                  t = -t-1;
            } else {
                  /* I don't recommend this functions with usual ids */
                  for ( j=0; j<v->subtable->table->max_records; j++) {
                        if ( v->subtable->table->records[j]->id == t ) {
                              t = j;
                              break;
                        }
                  }
            }
            rlist = g_list_append(rlist, GINT_TO_POINTER(t));
      }
      
      if ( win->what != NULL ) {
            g_list_free(win->what);
      }
      win->what = rlist;
      
      vpd->view_fill(win);

      return Py_None;
}

/**
 * <window>.get_widget(s)
 *
 * Description:
 * This method returns the GUI widget (actually a GtkObject) matching the
 * given string. The strings you can give depends upon the used view.
 **/
static PyObject* py_win_get_widget(PyObject *self, PyObject *args)
{
#ifndef HAVE_PYGTK
      return Py_None;
#else /* HAVE_PYGTK */
      char *str;
      GtkWidget *wid;
      gabywindow *win;
      ViewPluginData *vpd;
      PyObject *ob;
      
      if ( ! PyArg_ParseTuple(args, "s", &str)) {
            PyErr_SetString(PyExc_TypeError, 
                  "get_widget() requires 1 argument (string)");
            return NULL;
      }
      
      win = ((PyGabyWindow_Object*)self)->win;
      vpd = win->view->type;
      if ( vpd->view_get_widget == NULL ) {
            puts("get_widget not implemented for this view");
            return Py_None;
      }
      wid = vpd->view_get_widget(win, str);
      
      if ( wid == NULL ) return Py_None;
      
      ob = PyGtk_New(GTK_OBJECT(wid));
      return ob;
#endif
}

      /* Items */
static PyObject *PyGabyWindow_getattr(PyGabyWindow_Object *self, char *name)
{
      gabywindow *win;
      view *v;
      
      win = self->win;
      v = win->view;
      
      /**
       * <window>.type
       * Description:
       * this item holds the type of the view
       **/
      if ( strcmp(name, "type") == 0 ) {
            return PyString_FromString(v->type->name );
      }

      /**
       * <window>.i18n_type
       * Description:
       * this item holds the type of the view translated in the user's
       * favortie language
       **/
      if ( strcmp(name, "i18n_type") == 0 ) {
            return PyString_FromString(v->type->i18n_name );
      }

      /**
       * <window>.subtable
       * Description:
       * this item holds the subtable used by the window
       **/
      if ( strcmp(name, "subtable") == 0 ) {
            return PyGabySubTable_New(v->subtable);
      }

      /**
       * <window>.id
       * Description:
       * this item holds the id of the record currently shown. Unlike other
       * attributes this one is not read-only.
       **/
      if ( strcmp(name, "id") == 0 ) {
            return PyInt_FromLong((long)win->id);
      }

      /**
       * <window>.name
       * Description:
       * this item holds the name of the window, as shown in its title bar
       **/
      if ( strcmp(name, "name") == 0 ) {
            return PyString_FromString( win->name ? win->name : "?" );
      }

      /**
       * <window>.can_restrict_list
       * Description:
       * this item holds a boolean value that is set if the window has the
       * 'what' attribute available.
       **/
      if ( strcmp(name, "can_restrict_list") == 0 ) {
            /* this would need a specific attribute (FIXED) (optimally?) */
            return PyInt_FromLong ( v->type->capabilities & FILTERABLE );
      }

#ifdef HAVE_PYGTK
      /**
       * <window>.gtkwindow
       * Description:
       * this item holds a GtkWindow reprensenting the physical window itself
       **/

      /*  this allows to use gtk functions on gaby windows (useful for move,
       *  resize, ...). move and resize are currently handled with {move,
       *  resize}_window but they are simple wrappers around gdk_window_{move,
       *  resize} but they are marked as obsolete
       */
      if ( strcmp(name, "gtkwindow") == 0 ) {
            PyObject *ob;
            ob = PyGtk_New(GTK_OBJECT(win->parent));
            return ob;
      }
#endif
      
      return Py_FindMethod(window_methods, (PyObject*)self, name);
}

static int PyGabyWindow_setattr (PyGabyWindow_Object *self, char *name,
                         PyObject *val)
{
      gabywindow *window;
      ViewPluginData *vpd;
      
      window = ((PyGabyWindow_Object*)self)->win;
      vpd = window->view->type;

      if ( strcmp(name, "id") == 0 ) {
            int id;
            
            id = PyInt_AsLong(val);
            
            if ( id == -1 && PyErr_Occurred())
                  return -1;
            
            window->id = id;

            vpd->view_fill(window);
            update_bound_windows(window);

            return 0;
      }

      /**
       * <window>.restricted_list
       *
       * Description:
       * This item is the place to set a 'restricted list' of records
       * to show in a window (this is a duplicated set_records_list)
       **/
      if ( strcmp(name, "restricted_list") == 0 ) {
            int i;
            int id;
            GList *l = NULL, *t;
            view *v;

            v = window->view;
            
            if ( ! PyList_Check(val) && PyErr_Occurred())
                  return -1;

            for  (i=0; i < PyList_GET_SIZE(val); i++ ) {
                  id = PyInt_AsLong(PyList_GET_ITEM(val, i));
                  if ( id < 0 ) {
                        id = - id - 1;
                  } else {
                        int j;
                        table *t = v->subtable->table;
                        for ( j=0; j < t->max_records; j++ ) {
                              if ( t->records[j] && 
                                    t->records[j]->id == id )
                              {
                                    id = j;
                                    break;
                              }
                        }
                  }
                  
                  l = g_list_append(l, GINT_TO_POINTER(id));
            }
            if ( l == NULL && PyList_GET_SIZE(val) != 0 ) {
                  l = g_list_append(l, GINT_TO_POINTER(-1));
            }
            t = window->what;
            if ( t ) g_list_free(t);
            window->what = l;

            vpd->view_fill(window);

            return 0;
      }

      PyErr_SetString(PyExc_AttributeError, name);
      return -1;
}

static char PyGabyWindow_Type__doc__[] = "This is the type of Gaby Windows";
static PyTypeObject PyGabyWindow_Type = {
      PyObject_HEAD_INIT(&PyType_Type)
      0,                            /*ob_size*/
      "GabyWindow",                       /*tp_name*/
      sizeof(PyGabyWindow_Object),        /*tp_basicsize*/
      0,                            /*tp_itemsize*/
      (destructor)PyGabyWindow_dealloc,   /*tp_dealloc*/
      (printfunc)PyGabyWindow_print,            /*tp_print*/
      (getattrfunc)PyGabyWindow_getattr,  /*tp_getattr*/
      (setattrfunc)PyGabyWindow_setattr,  /*tp_setattr*/
      (cmpfunc)0,                   /*tp_compare*/
      (reprfunc)0,                        /*tp_repr*/
      0,                            /*tp_as_number*/
      0,                            /*tp_as_sequence*/
      0,                            /*tp_as_mapping*/
      (hashfunc)0,                        /*tp_hash*/
      (ternaryfunc)0,                     /*tp_call*/
      (reprfunc)0,                        /*tp_str*/
      0L,0L,0L,0L,
      PyGabyWindow_Type__doc__
};

/* GabySubTable Object */

static PyObject* PyGabySubTable_New(subtable *st)
{
      PyGabySubTable_Object *self;

      self = (PyGabySubTable_Object*)PyObject_NEW( 
                        PyGabySubTable_Object, &PyGabySubTable_Type);
      debug_print("[PyGabySubTable_New] self : %p\n", self);
      if ( self == NULL )
            return NULL;
      self->st = st;
      return (PyObject*)self;
}

static void PyGabySubTable_dealloc(PyGabySubTable_Object *self)
{
      PyMem_DEL(self);
}

static int PyGabySubTable_print(PyGabySubTable_Object *self, FILE *f, int flags)
{
      subtable *st;
      st = self->st;
      fprintf(f, "<GabySubTable, name : %s, derived from table %s>",
                                    st->name, st->table->name );
      return 0;
}

      /* Methods */
static PyObject* py_st_get_record_no(PyObject *self, PyObject *args);
static PyObject* py_st_add_record(PyObject *self, PyObject *args);
static PyObject* py_st_delete_record(PyObject *self, PyObject *args);
static PyObject* py_st_set_record_no(PyObject *self, PyObject *args);
static PyObject* py_st_fast_records_list(PyObject *self, PyObject *args);
static PyObject* py_st_records_list(PyObject *self, PyObject *args);
static PyObject* py_st_get_first_record(PyObject *self, PyObject *args);
static PyObject* py_st_get_previous_record(PyObject *self, PyObject *args);
static PyObject* py_st_get_next_record(PyObject *self, PyObject *args);
static PyObject* py_st_get_last_record(PyObject *self, PyObject *args);
static PyObject* py_st_create_new_window(PyObject *self, PyObject *args);
static PyObject* py_st_save(PyObject *self, PyObject *args);

static PyMethodDef subtable_methods[] = {
      { "get_record_no",      (PyCFunction)py_st_get_record_no, 1 },
      { "add_record",         (PyCFunction)py_st_add_record, 1 },
      { "delete_record",      (PyCFunction)py_st_delete_record, 1 },
      { "set_record_no",      (PyCFunction)py_st_set_record_no, 1 },
      { "get_first_record",   (PyCFunction)py_st_get_first_record, 1 },
      { "get_previous_record",(PyCFunction)py_st_get_previous_record, 1 },
      { "get_next_record",    (PyCFunction)py_st_get_next_record, 1 },
      { "get_last_record",    (PyCFunction)py_st_get_last_record, 1 },
      { "records_list", (PyCFunction)py_st_records_list, 1 },
      { "fast_records_list",  (PyCFunction)py_st_fast_records_list, 1 },
      { "create_new_window",  (PyCFunction)py_st_create_new_window, 1 },
      { "save",         (PyCFunction)py_st_save, 1 },
      { NULL,                 NULL }
};

/**
 * <subtable>.get_record_no(i [, b] )
 * 
 * Description:
 * This methods returns the record (list of strings) whose id (or 'fast id') is
 * i from the subtable. If b is set to TRUE the list is filled using Python
 * types matching in the best possible way the record type.
 **/
static PyObject* py_st_get_record_no(PyObject *self, PyObject *args)
{
      subtable *st;
      int id;
      PyObject *rec;
      PyObject *py_ob;
      GString *str;
      int i;
      gboolean pytypes = FALSE;
      record *r;
      
      if ( PyTuple_Check(args) ) {
            if ( ! PyArg_ParseTuple(args, "i|i", &id, &pytypes))
                  return NULL;
      } else {
            if ( ! PyArg_Parse(args, "i", &id))
                  return NULL;
      }
      
      st = ((PyGabySubTable_Object*)self)->st;

      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }
      
      if ( id < 0 ) {
            r = st->table->records[-id-1];
      } else {
            r = get_record_no(st->table, id);
      }
      
      if ( r == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid record id");
            return NULL;
      }

      rec = PyList_New(st->nb_fields);
      
      for ( i=0; i < st->nb_fields; i++ ) {
            if ( pytypes == TRUE ) {
                  switch ( st->fields[i].type ) {
                        case T_INTEGER:
                        case T_BOOLEAN:
                              py_ob = PyInt_FromLong( (long)
                                    r->cont[st->fields[i].no].i );
                              break;
                        case T_REAL:
                              py_ob = PyFloat_FromDouble( (double)
                                    r->cont[st->fields[i].no].d );
                              break;
                        case T_DECIMAL:
                              py_ob = PyFloat_FromDouble( (double)
                                    r->cont[st->fields[i].no].i / 100.0 );
                              break;
                        default: py_ob = NULL; /* this never happens */
                  }
                  if ( py_ob != NULL ) {
                        PyList_SetItem(rec, i, py_ob);
                        continue;
                  }
            }

            if ( st->fields[i].type == T_RECORDS ) {
                  /* we create a list of records */
                  GList *l_recs, *s_lr;
                  PyObject *sub_st = PyGabySubTable_New (
                                    st->fields[i].v->subtable);

                  py_ob = PyList_New(0);
                  l_recs = get_related_records( &(st->fields[i]), r->id);
                  s_lr = l_recs;
                  while ( s_lr != NULL && 
                              GPOINTER_TO_INT(s_lr->data) != -1 ) {

                        int val = GPOINTER_TO_INT(s_lr->data);
                        val = -(val+1);   /* in Python, we start at -1 */
                        
                        PyList_Append(py_ob, 
                              py_st_get_record_no(sub_st, 
                                    PyInt_FromLong(val)) );
                        
                        s_lr = g_list_next(s_lr);
                  }
                  g_list_free(l_recs);
                  
                  PyList_SetItem(rec, i, py_ob);

                  continue;
            }
            
            str = get_subtable_stringed_field(st, r, i);
            py_ob = PyString_FromString(str->str);
            g_string_free(str, 1);
            PyList_SetItem(rec, i, py_ob);
      }
      
      return rec;
}

/**
 * <subtable>.add_record(r)
 *
 * Description:
 * This method adds the given record @r to the subtable. It returns the new
 * record's id.
 **/
static PyObject* py_st_add_record(PyObject *self, PyObject *args)
{
      /* I miss good old Python way:
       *    def add_record(r): return self.set_record_no(0,r)
       * sooo easier...
       */
      PyObject *rec, *py_tuple;
      
      if ( ! PyArg_ParseTuple(args, "O", &rec)) return NULL;
      
      py_tuple = PyTuple_New(2);
      PyTuple_SetItem(py_tuple, 0, PyInt_FromLong(0));
      PyTuple_SetItem(py_tuple, 1, rec);
      
      return py_st_set_record_no(self, py_tuple);
}

/**
 * <subtable>.delete_record(id)
 *
 * Description:
 * This method removes the record whose id is @id from the subtable.
 **/
static PyObject* py_st_delete_record(PyObject *self, PyObject *args)
{
      /* I miss good old Python way:
       *    def delete_record(id): return self.set_record_no(id, None)
       * sooo easier...
       */
      /* note that I could tell to set_record_no that the second arg has a
       * default value == None but this would be cheating :) 
       * (I need correct type checking)
       */
      PyObject *py_tuple;
      int id;
      
      if ( ! PyArg_ParseTuple(args, "i", &id)) return NULL;
      
      py_tuple = PyTuple_New(2);
      PyTuple_SetItem(py_tuple, 0, PyInt_FromLong(id));
      PyTuple_SetItem(py_tuple, 1, Py_None);
      
      return py_st_set_record_no(self, py_tuple);
}

/**
 * <subtable>.set_record_no(i, r)
 * 
 * Description:
 * This method sets the record whose id (or 'fast id') is i from the subtable
 * to the record (list of strings) r. If id is 0 then the record is added to
 * the table. This method returns the _real_ id.
 *
 * Comment: it doesn't touch to 'Record' and 'Records' fields
 **/
static PyObject* py_st_set_record_no(PyObject *self, PyObject *args)
{
      subtable *st;
      int id;
      PyObject *rec;
      PyObject *py_ob;
      int i;
      record *r;
      
      if ( ! PyArg_ParseTuple(args, "iO", &id, &rec)) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }

      if ( rec == Py_None ) { /* remove record */
            debug_print("[st_set_record_no] removing record\n");
            if ( id < 0 ) {
                  r = st->table->records[-id-1];
                  id = r->id;
            }
            record_remove_id(st->table, id);
            
            return Py_None;
      }

      if ( id == 0 ) { /* new record */
            r = record_defaults(st->table);
      } else {
            if ( id < 0 ) {
                  r = st->table->records[-id-1];
            } else {
                  r = get_record_no(st->table, id);
            }
            if ( r == NULL ) {
                  PyErr_SetString(PyExc_ValueError, "Invalid record id");
                  return NULL;
            }
      }

      for ( i=0; i < st->nb_fields; i++ ) {
            if ( st->fields[i].type == T_RECORDS )
                  continue;

            py_ob = PyList_GetItem(rec, i);
            
            if ( PyString_Check(py_ob) ) {
                  set_subtable_stringed_field(st, r, i, 
                              PyString_AsString(py_ob));
            } else {
                  switch ( st->fields[i].type ) {
                        case T_INTEGER:
                        case T_RECORD:
                        {
                              if ( PyInt_Check(py_ob) || 
                                          PyLong_Check(py_ob)) {
                                    r->cont[st->fields[i].no].i = 
                                          PyInt_AsLong(py_ob);
                              }
                        } break;
                        case T_DECIMAL:
                        {
                              if ( PyFloat_Check(py_ob) ) {
                                    r->cont[i].i = 100.0 * 
                                          PyFloat_AsDouble(py_ob);
                              }
                        }
                        case T_REAL:
                        {
                              if ( PyFloat_Check(py_ob) ) {
                                    r->cont[i].d = 
                                          PyFloat_AsDouble(py_ob);
                              }
                        } break;
                        default: break;
                  }
            }
      }

      if ( id == 0 ) {
            if ( record_add(st->table, r, TRUE, TRUE ) == -1 ) {
                  record_free(st->table, r);
                  return NULL;
            }
      }
      return PyInt_FromLong( r->id );
}

/**
 * <subtable>.get_next_record(i)
 * 
 * Description:
 * This methods returns the id of the record directly following the record
 * whose id (_not_ fast id) is i in the subtable
 **/
static PyObject* py_st_get_next_record(PyObject *self, PyObject *args)
{
      int id;
      subtable *st;
      record *r;
      
      if ( ! PyArg_ParseTuple(args, "i", &id)) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }
      
      if ( id < 1 ) {
            PyErr_SetString(PyExc_ValueError, 
                  "this function does not work with fast ids");
            return NULL;
      }
      
      r = get_record_no(st->table, id);
      if ( r == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid record id");
            return NULL;
      }

      r = table_next(st->table, r, -1);
      
      return PyInt_FromLong((long)r->id);
}

/**
 * <subtable>.get_previous_record(i)
 * 
 * Description:
 * This methods returns the id of the record directly preceding the record
 * whose id (_not_ fast id) is i in the subtable
 **/
static PyObject* py_st_get_previous_record(PyObject *self, PyObject *args)
{
      int id;
      subtable *st;
      record *r;
      
      if ( ! PyArg_ParseTuple(args, "i", &id)) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }

      if ( id < 1 ) {
            PyErr_SetString(PyExc_ValueError, 
                  "this function does not work with fast ids");
            return NULL;
      }
      
      r = get_record_no(st->table, id);
      if ( r == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid record id");
            return NULL;
      }

      r = table_prev(st->table, r, -1);
      
      return PyInt_FromLong((long)r->id);
}

/**
 * <subtable>.get_first_record()
 * 
 * Description:
 * This methods returns the id of the first record in the subtable.
 **/
static PyObject* py_st_get_first_record(PyObject *self, PyObject *args)
{
      subtable *st;
      record *r;
      
      if ( ! PyArg_ParseTuple(args, "")) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }

      r = table_first(st->table, -1);
      
      return PyInt_FromLong((long)r->id);
}

/**
 * <subtable>.get_last_record()
 * 
 * Description:
 * This methods returns the id of the last record in the subtable.
 **/
static PyObject* py_st_get_last_record(PyObject *self, PyObject *args)
{
      subtable *st;
      record *r;
      
      if ( ! PyArg_ParseTuple(args, "")) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }

      r = table_last(st->table, -1);
      
      return PyInt_FromLong((long)r->id);
}

/**
 * <subtable>.records_list()
 * 
 * Description:
 * This methods returns the list (PyList) of the id of the records in the
 * subtable.
 **/
static PyObject* py_st_records_list(PyObject *self, PyObject *args)
{
      subtable *st;
      PyObject *py_list;
      int i;
      
      if ( ! PyArg_ParseTuple(args, "")) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }
      
      py_list = PyList_New(0);
      for ( i=0; i<st->table->max_records; i++) {
            if ( st->table->records[i] != NULL && 
                        st->table->records[i]->id != 0 ) {
                  PyList_Append(py_list, 
                        PyInt_FromLong(st->table->records[i]->id));
            }
      }

      return py_list;
}

/**
 * <subtable>.fast_records_list()
 * 
 * Description:
 * This methods returns the list (PyList) of the 'fast id' of the records in
 * the subtable.
 *
 * Comments on 'fast id': they are slightly faster than 'normal' ids but there
 * are drawbacks : you can't record_{add,delete} a record and then reuse a list
 * you got previously. (example: on a table with around 2600 records it was
 * twice faster (simply listing))
 **/
static PyObject* py_st_fast_records_list(PyObject *self, PyObject *args)
{
#ifndef USE_CURSOR
//#  define USE_CURSOR
#endif
      subtable *st;
      PyObject *py_list;
      int i;
#ifdef USE_CURSOR
      gabycursor *cs;
      record *r;
#endif
      
      if ( args != NULL ) { /* NULL happens when called from C for printing */
            if ( ! PyArg_ParseTuple(args, "")) return NULL;
      }
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }
      
      py_list = PyList_New(0);

#ifndef USE_CURSOR /* old way; doesn't work with gabyqsl */
      for ( i=0; i<st->table->max_records; i++) {
            if ( st->table->records[i] != NULL && 
                        st->table->records[i]->id != 0 ) {
                  PyList_Append(py_list,  PyInt_FromLong(-i-1));
            }
      }
#else /* new way; using a cursor */
      cs = cursor_declare(st->table);
      r = cursor_get_first(cs);
      while ( r ) {
            PyList_Append(py_list, PyInt_FromLong(r->id));
            r = cursor_get_next(cs);
      }
      cursor_free(cs);
#endif /* USE_CURSOR */ 

      return py_list;
}

/**
 * <subtable>.create_new_window(s)
 * 
 * Description:
 * This methods creates (then shows) a new window of the type given by s
 * ('form', 'xlist', ...) and fill it with the data from the subtable.
 **/
static PyObject* py_st_create_new_window(PyObject *self, PyObject *args)
{
      gchar *view_name;
      GList *vi;
      view *v;
      subtable *st;
      gabywindow *win;
      struct window_info wi = { NULL, -1, -1, -1, -1, TRUE};
      
      debug_print("[py_st_create_new_window] -->\n");
      if ( ! PyArg_ParseTuple(args, "s", &view_name)) return NULL;
      debug_print("[py_st_create_new_window] <--\n");
      
      st = ((PyGabySubTable_Object*)self)->st;
      
      if ( st == NULL ) {
            PyErr_SetString(PyExc_ValueError, "Invalid subtable name");
            return NULL;
      }
      
      vi = g_list_first(list_views);
      while ( vi != NULL ) {
            v = vi->data;
            vi = g_list_next(vi);
            if ( v->type == NULL ) continue;
            if ( v->subtable == st && 
                        strcmp(view_name, v->type->name) == 0 ) {
                  wi.view = v;
                  win = new_view_create(&wi);
#ifndef NO_GUI
                  gtk_widget_show(win->parent);
#endif
                  return PyGabyWindow_New(win);
            }
      }

      return Py_None;
}

/**
 * <subtable>.save()
 * 
 * Description:
 * This methods saves the subtable on disk.
 **/
static PyObject* py_st_save(PyObject *self, PyObject *args)
{
      subtable *st;
      
      if ( ! PyArg_ParseTuple(args, "")) return NULL;
      
      st = ((PyGabySubTable_Object*)self)->st;

      if ( ! table_save_file(st->table) )
            return NULL;

      return Py_None;
}

      /* Items */
static PyObject *PyGabySubTable_getattr(PyGabySubTable_Object *self, char *name)
{
      subtable *st = self->st;
      
      /**
       * <subtable>.name
       * Description:
       * this item holds the name of the subtable
       **/
      if ( strcmp(name, "name") == 0 ) {
            return PyString_FromString(st->name);
      }

      /**
       * <subtable>.i18n_name
       * Description:
       * this item holds the name of the subtable translated in the user's
       * favorite language
       **/
      if ( strcmp(name, "i18n_name") == 0 ) {
            return PyString_FromString(st->i18n_name);
      }

      /**
       * <subtable>.fields
       * Description:
       * this item holds a tuple (_not_ list !) with the names of the
       * subtable's fields.
       **/
      if ( strcmp(name, "fields") == 0 ) {
            PyObject *py_tuple;
            PyObject *py_string;
            int i;
      
            py_tuple = PyTuple_New(st->nb_fields);
            for (i=0; i < st->nb_fields; i++) {
                  py_string = PyString_FromString(st->fields[i].name);
                  PyTuple_SetItem(py_tuple, i, py_string);
            }
            return py_tuple;
      }

      /**
       * <subtable>.dict_fields
       * Description:
       * this item holds a dict with the fields numbers referenced by
       * the fields names.
       **/
      if ( strcmp(name, "dict_fields") == 0 ) {
            PyObject *py_dict;
            PyObject *py_string;
            int i;
            py_dict = PyDict_New();
            for (i=0; i < st->nb_fields; i++) {
                  py_string = PyString_FromString(st->fields[i].name);
                  PyDict_SetItem(py_dict, py_string, PyInt_FromLong(i));
            }
            return py_dict;
      }

      /**
       * <subtable>.i18n_fields
       * Description:
       * this item holds a tuple (_not_ list !) with the names translated
       * in the user's favorite language of the subtable's fields.
       **/
      if ( strcmp(name, "i18n_fields") == 0 ) {
            PyObject *py_tuple;
            PyObject *py_string;
            int i;
      
            py_tuple = PyTuple_New(st->nb_fields);
            for (i=0; i < st->nb_fields; i++) {
                  py_string = PyString_FromString(st->fields[i].i18n_name);
                  PyTuple_SetItem(py_tuple, i, py_string);
            }
            return py_tuple;
      }

      /**
       * <subtable>.dict_i18n_fields
       * Description:
       * this item holds a dict with the fields numbers referenced by
       * the fields names translated in the user's favorite language.
       **/
      if ( strcmp(name, "dict_i18n_fields") == 0 ) {
            PyObject *py_dict;
            PyObject *py_string;
            int i;
            py_dict = PyDict_New();
            for (i=0; i < st->nb_fields; i++) {
                  py_string = PyString_FromString(st->fields[i].i18n_name);
                  PyDict_SetItem(py_dict, py_string, PyLong_FromLong(i));
            }
            return py_dict;
      }

      /**
       * <subtable>.table
       * Description:
       * this item holds the name of the table hidden behind the subtable
       **/
      if ( strcmp(name, "table") == 0 ) {
            return PyString_FromString(st->table->name);
      }

      return Py_FindMethod(subtable_methods, (PyObject*)self, name);
}

static char PyGabySubTable_Type__doc__[] = "This is the type of Gaby SubTables";
static PyTypeObject PyGabySubTable_Type = {
      PyObject_HEAD_INIT(&PyType_Type)
      0,                            /*ob_size*/
      "GabySubTable",                     /*tp_name*/
      sizeof(PyGabySubTable_Object),            /*tp_basicsize*/
      0,                            /*tp_itemsize*/
      (destructor)PyGabySubTable_dealloc, /*tp_dealloc*/
      (printfunc)PyGabySubTable_print,    /*tp_print*/
      (getattrfunc)PyGabySubTable_getattr,      /*tp_getattr*/
      (setattrfunc)0,                     /*tp_setattr*/
      (cmpfunc)0,                   /*tp_compare*/
      (reprfunc)0,                        /*tp_repr*/
      0,                            /*tp_as_number*/
      0,                            /*tp_as_sequence*/
      0,                            /*tp_as_mapping*/
      (hashfunc)0,                        /*tp_hash*/
      (ternaryfunc)0,                     /*tp_call*/
      (reprfunc)0,                        /*tp_str*/
      0L,0L,0L,0L,
      PyGabySubTable_Type__doc__
};


/* the GabyOutput type is used to catch the output from the Python script
 * (it must be affected to sys.stdout and sys.stderr)
 * (method described in doc/python/FAQ) */
typedef struct {
      PyObject_HEAD
      FILE *file;
} PyGabyOutput_Object;
staticforward PyTypeObject PyGabyOutput_Type;

static PyObject* PyGabyOutput_New(char *filename)
{
      PyGabyOutput_Object *self;
      FILE *f;

      self = (PyGabyOutput_Object*)PyObject_NEW(PyGabyOutput_Object, &PyGabyOutput_Type);
      if ( self == NULL )
            return NULL;

      f = fopen(filename, "w");
      self->file = f;
      return (PyObject*)self;
}

static void PyGabyOutput_dealloc(PyGabyOutput_Object *self)
{
      debug_print("[PyGabyOutput_dealloc] called\n");
      PyMem_DEL(self);
}

static int PyGabyOutput_print(PyGabyWindow_Object *self, FILE *f, int flags)
{
      return 0;
}

      /* Methods */

static PyObject* py_output_write(PyObject *self, PyObject *args);
static PyObject* py_output_close(PyObject *self, PyObject *args);

static PyMethodDef output_methods[] = {
      { "write",        (PyCFunction)py_output_write, 1 },
      { "close",        (PyCFunction)py_output_close, 1 },
      { NULL,                 NULL }
};

static PyObject* py_output_write(PyObject *self, PyObject *args)
{
      FILE *f = ((PyGabyOutput_Object*)self)->file;
      char *string;
      
      debug_print("[python] it printed something ! (but I catched it)\n");

#if 1
      PyArg_ParseTuple(args, "s", &string);
#else
      PyArg_Parse(args, "s", &string);
#endif

      debug_print("it was : %s\n", string);
      if ( f == NULL ) {
            puts(string);
            return Py_None;
      } else {
            fputs(string, f);
            return Py_None;
      }
}

static PyObject* py_output_close(PyObject *self, PyObject *args)
{
      FILE *f = ((PyGabyOutput_Object*)self)->file;
      fclose(f);
      return Py_None;
}

static PyObject *PyGabyOutput_getattr(PyGabyOutput_Object *self, char *name)
{
      return Py_FindMethod(output_methods, (PyObject*)self, name);
}

static char PyGabyOutput_Type__doc__[] = "[internal] type used for Gaby Output";
static PyTypeObject PyGabyOutput_Type = {
      PyObject_HEAD_INIT(&PyType_Type)
      0,                            /*ob_size*/
      "GabyOutput",                       /*tp_name*/
      sizeof(PyGabyOutput_Object),        /*tp_basicsize*/
      0,                            /*tp_itemsize*/
      (destructor)PyGabyOutput_dealloc,   /*tp_dealloc*/
      (printfunc)PyGabyOutput_print,            /*tp_print*/
      (getattrfunc)PyGabyOutput_getattr,  /*tp_getattr*/
      (setattrfunc)0,                     /*tp_setattr*/
      (cmpfunc)0,                   /*tp_compare*/
      (reprfunc)0,                        /*tp_repr*/
      0,                            /*tp_as_number*/
      0,                            /*tp_as_sequence*/
      0,                            /*tp_as_mapping*/
      (hashfunc)0,                        /*tp_hash*/
      (ternaryfunc)0,                     /*tp_call*/
      (reprfunc)0,                        /*tp_str*/
      0L,0L,0L,0L,
      PyGabyOutput_Type__doc__
};


/* misc functions */

/**
 * hello_world()
 * 
 * Description:
 * Prints 'Hello, World !'
 **/
static PyObject* py_hello_world(PyObject *self, PyObject *args)
{
      debug_print("[gaby.hello_world()] --\n");
      if (!PyArg_ParseTuple(args, ""))
            return NULL;
            
      puts("Hello, World !");

      return Py_None;
}

/**
 * load_database(s)
 *
 * Description:
 * This function loads the database 's' (ie both descfile and datas). It will
 * fail if a database is already loaded.
 **/
static PyObject* py_load_database(PyObject *self, PyObject *args)
{
      char *name;

      if ( ! PyArg_ParseTuple(args, "s", &name)) {
            PyErr_SetString(PyExc_TypeError, 
                  "load_database() requires 1 argument (string)");
            return NULL;
      }

      if ( appname != NULL ) {
#if 1
            free_everything();
#else
            PyErr_SetString(PyExc_SystemError, "a database is already there");
            return NULL;
#endif
      }

      list_tables = NULL;
      list_subtables = NULL;
      
      appname = g_strdup(name);
      if ( ! tables_load_struct(name) ) {
            PyErr_SetString(PyExc_SystemError, "error in tables_load_struct");
            appname = NULL;
            return NULL;
      }
      if ( ! st_load_struct(NULL, name ) ) {
            PyErr_SetString(PyExc_SystemError, "error in st_load_struct");
            appname = NULL;
            return NULL;
      }
      
      tables_load();
      
      return Py_None;
}

/**
 * get_subtable_by_name(s)
 *
 * Description:
 * This functions returns the subtable with the given name
 **/
static PyObject* py_get_subtable_by_name(PyObject *self, PyObject *args)
{
      char *subtable_name;
      subtable *st;
      
      if ( ! PyArg_ParseTuple(args, "s", &subtable_name)) {
            PyErr_SetString(PyExc_TypeError, 
                  "get_subtable_by_name() requires 1 argument (string)");
            return NULL;
      }
      
      st = get_subtable_by_name(subtable_name);
      if ( st == NULL ) return Py_None;
      return PyGabySubTable_New(st);
}

/**
 * get_main_window()
 *
 * Description:
 * This function returns the main window (== the first created window)
 **/
static PyObject* py_get_main_window (PyObject *self, PyObject *args)
{
      GList *aw = g_list_first(list_windows);

      debug_print("py_get_main_window\n");

      if (!PyArg_ParseTuple(args, "")) {
            PyErr_SetString(PyExc_TypeError, 
                  "get_main_window() doesn't accept arguments");
            return NULL;
      }
      
/*    res = PyCObject_FromVoidPtr(aw->data, NULL);
      return res;*/
      return PyGabyWindow_New((gabywindow*)aw->data);
}

/**
 * get_current_window()
 *
 * Description:
 * This functions returns the focused window (if none has the focus, it is
 * equivalent to get_main_window)
 **/
static PyObject* py_get_current_window(PyObject *self, PyObject *args)
{
      /*
       * the way I use to know if a given window has the focus is not right
       * but since I don't know what is the right thing ...
       */
#ifdef NO_GUI
      puts("No support for windows compiled!");
      return Py_None;
#else
      GList *aw = g_list_first(list_windows);
      gabywindow *win;
      GtkWidget *parent;

      if (!PyArg_ParseTuple(args, "")) {
            PyErr_SetString(PyExc_TypeError, 
                  "get_current_window() doesn't accept arguments");
            return NULL;
      }
            
      while ( aw != NULL ) {
            win = aw->data;
            aw = g_list_next(aw);
            parent = win->parent;
            if ( parent == NULL ) {
                  aw = g_list_next(aw);
                  continue;
            }
            if ( ! win->focused ) continue;
            
            debug_print("current window : %p\n", aw->data);
            /*res = PyCObject_FromVoidPtr(aw->data, NULL);
            return res;*/
            return PyGabyWindow_New(win);
      }

      debug_print("No window has the focus right now\n");

      return py_get_main_window(self, args);
#endif /* ! NO_GUI */
}

/**
 * exit_gaby()
 *
 * Description:
 * This function exits Gaby cleanly (asking confirmation if there were unsaved
 * record(s))
 **/
static PyObject* py_exit_gaby(PyObject *self, PyObject *args)
{
      
      if (!PyArg_ParseTuple(args, "")) {
            PyErr_SetString(PyExc_TypeError, 
                  "exit_gaby() doesn't accept arguments");
            return NULL;
      }

      gaby_quit(g_list_first(list_tables));
      return Py_None;
}

/**
 * get_subtables_list()
 *
 * Description:
 * This functions returns a list filled with the name of the subtables
 **/
static PyObject* py_get_subtables_list(PyObject *self, PyObject *args)
{
      subtable *st;
      PyObject *py_list;
      GList *tmp = list_subtables;
      
      if (!PyArg_ParseTuple(args, "")) {
            PyErr_SetString(PyExc_TypeError, 
                  "get_subtables_list() doesn't accept arguments");
            return NULL;
      }
      
      py_list = PyList_New(0);
      while ( tmp != NULL ) {
            st = tmp->data;
            PyList_Append(py_list, PyString_FromString(st->name));
            tmp = g_list_next(tmp);
      }

      return py_list;
}

/**
 * get_windows_list()
 *
 * Description:
 * This functions returns a list of GabyWindow objects
 **/
static PyObject* py_get_windows_list(PyObject *self, PyObject *args)
{
      gabywindow *win;
      PyObject *py_list;
      GList *tmp = g_list_first(list_windows);
      
      if (!PyArg_ParseTuple(args, "")) {
            PyErr_SetString(PyExc_TypeError, 
                  "get_windows_list() doesn't accept arguments");
            return NULL;
      }

      debug_print("[python:get_windows_list] -> adding... ");

      py_list = PyList_New(0);
      while ( tmp != NULL ) {
            win = tmp->data;
            debug_print("%s ", win->name);
            PyList_Append(py_list, PyGabyWindow_New(win));
            tmp = g_list_next(tmp);
      }
      debug_print("... <-\n");

      return py_list;
}

/**
 * message_dialog(i, s)
 *
 * Description:
 * This functions pops up a message box with the given message, the first arg
 * is an integer representing the message type while the second is a string
 * whose purpose is determined by the value of the integer
 **/
static PyObject* py_message_dialog(PyObject *self, PyObject *args)
{
      int type;
      char *message;
      
      if ( ! PyArg_ParseTuple(args, "is", &type, &message)) {
            PyErr_SetString(PyExc_TypeError, 
                  "message_dialog() requires 2 arguments (int,string)");
            return NULL;
      }

      gaby_errno = type;
      gaby_message = g_strdup(message);
      gaby_perror_in_a_box();

      return Py_None;
}

static PyObject* py_new_output(PyObject *self, PyObject *args)
{
      char *filename;
      
      if ( ! PyArg_ParseTuple(args, "s", &filename)) {
            PyErr_SetString(PyExc_TypeError, 
                  "new_output() requires 1 argument (string)");
            return NULL;
      }

      return PyGabyOutput_New(filename);
}

#if 0

#undef USE_GNOME

static void py_stdlg_row_changed( GtkCList *clist, gint row, gint column,
                          GdkEventButton *event, GtkWidget *wid)
{
#ifdef USE_GNOME
      gnome_dialog_set_sensitive(GNOME_DIALOG(wid), 0, 
                              ( clist->selection != NULL ) );
#else /* ! USE_GNOME */
      gtk_widget_set_sensitive(wid, ( clist->selection != NULL ) );
#endif /* ! USE_GNOME */
}

void py_stdlg_ok_cb (GtkWidget *but, GtkWidget *dialog)
{
#ifndef NO_GUI
      subtable **st = gtk_object_get_data(GTK_OBJECT(dialog), "subtable");
      gchar *text;
      GtkWidget *clist = gtk_object_get_data(GTK_OBJECT(dialog), "clist");
            
      gtk_clist_get_text(GTK_CLIST(clist), 
                  GPOINTER_TO_INT(GTK_CLIST(clist)->selection->data), 
                  0, &text );
      
      *st = get_subtable_by_name(text);
            
      gtk_widget_hide(dialog);
#endif
}

/* ODOT: move subtable_dialog to src/ dir
 *       why ? to keep this plugin free of any GTK+ or Gnome reference
 */
static GtkWidget* py_subtable_dialog (gchar *text, subtable **st)
{
      GtkWidget *dialog;
      GtkWidget *vbox, *clist;
      GtkWidget *label;
#ifndef USE_GNOME
      GtkWidget *button, *buttonok;
#endif
      GList *subtables = list_subtables;

#ifdef USE_GNOME
      dialog = gnome_dialog_new(_("Select a subtable"), 
                        GNOME_STOCK_BUTTON_OK, 
                        GNOME_STOCK_BUTTON_CANCEL, 
                        NULL );
      gnome_dialog_set_close(GNOME_DIALOG(dialog), TRUE );
      vbox = GNOME_DIALOG(dialog)->vbox;

      gnome_dialog_button_connect(GNOME_DIALOG(dialog), 0, 
                                    py_stdlg_ok_cb, dialog);
#else
      dialog = gtk_dialog_new();
      vbox = GTK_DIALOG(dialog)->vbox;
      gtk_box_set_spacing(GTK_BOX(vbox), 5 );
      
      button = gtk_button_new_with_label(_("OK"));
      gtk_widget_show(button);
      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, 
                        FALSE, FALSE, 5 );
      gtk_signal_connect(GTK_OBJECT(button), "clicked", py_stdlg_ok_cb, dialog );
      buttonok = button;

      button = gtk_button_new_with_label(_("Cancel"));
      gtk_widget_show(button);
      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, 
                        FALSE, FALSE, 5 );
/*    gtk_signal_connect(GTK_OBJECT(button), "clicked", close_dialog, dialog);
*/
#endif
      gtk_object_set_data(GTK_OBJECT(dialog), "subtable", st);

      label = gtk_label_new(text);
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0 );
      
      clist = gtk_clist_new(1);
      gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0 );
      
      subtables = g_list_first(subtables);
      while ( subtables != NULL ) {
            gtk_clist_append(GTK_CLIST(clist), 
                        &((subtable*)subtables->data)->i18n_name );
            subtables = g_list_next(subtables);
      }

#ifdef USE_GNOME
      gtk_signal_connect(GTK_OBJECT(clist), "select_row", 
                              py_stdlg_row_changed, dialog );
      gtk_signal_connect(GTK_OBJECT(clist), "unselect_row", 
                              py_stdlg_row_changed, dialog );
      py_stdlg_row_changed(GTK_CLIST(clist), 0, 0, NULL, dialog);
#else
      gtk_signal_connect(GTK_OBJECT(clist), "select_row", 
                              py_stdlg_row_changed, buttonok );
      gtk_signal_connect(GTK_OBJECT(clist), "unselect_row", 
                              py_stdlg_row_changed, buttonok );
      py_stdlg_row_changed(GTK_CLIST(clist), 0, 0, NULL, buttonok);
#endif
      
      gtk_widget_show(clist);
      gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist );

      return dialog;
}
#endif /* 0 */

/**
 * select_subtable()
 *
 * Description:
 * This function lets the user select a subtable in a clean manner. It returns
 * the subtable or 'None' if the user selected canceled the operation.
 **/
static PyObject* py_select_subtable(PyObject *self, PyObject *args)
{
      subtable *st = NULL;
      gboolean *visible;
      
      if (!PyArg_ParseTuple(args, "")) {
            PyErr_SetString(PyExc_TypeError, 
                  "select_subtable() doesn't accept arguments");
            return NULL;
      }

      if ( app == NULL || getenv("DISPLAY") == NULL ) {
            GList *subtables = list_subtables;
            subtable *tmpst;
            int i = 1;
            char buf[15];

            puts(_("Please select a subtable: "));
            while ( subtables != NULL ) {
                  tmpst = subtables->data;
                  g_print("  [%d] : %s\n", i++, tmpst->i18n_name);
                  subtables = g_list_next(subtables);
            }
            i = atoi(fgets(buf, 14, stdin));
            st = (subtable*) (g_list_nth(list_subtables, i-1))->data;
      } else {
            visible = select_subtable_dialog(
                        _("Please select a subtable: "), NULL, &st);
            wait_dialog_to_finish(visible);
            debug_print("[py_select_subtable] window closed!\n");
      }

      if ( st == NULL )
            return Py_None;
      else
            return PyGabySubTable_New(st);
}

/**
 * gettext(s)
 *
 * Description:
 * This functions returns a translation of the given string
 **/
static PyObject* py_gettext(PyObject *self, PyObject *args)
{
      char *str;
      
      if ( ! PyArg_ParseTuple(args, "s", &str)) {
            PyErr_SetString(PyExc_TypeError, 
                  "gettext() requires 1 argument (string)");
            return NULL;
      }
      
      return PyString_FromString( gettext(str) );
}

static PyMethodDef gaby_funcs[] = {
      { "hello_world",              py_hello_world, 1 },
      { "load_database",            py_load_database, 1 },
      { "get_subtable_by_name",     py_get_subtable_by_name, 1 },
      { "get_current_window",       py_get_current_window, 1 },
      { "get_main_window",          py_get_main_window, 1 },
      { "exit_gaby",                py_exit_gaby, 1 },
      { "get_subtables_list",       py_get_subtables_list, 1 },
      { "get_windows_list",         py_get_windows_list, 1 },
      { "message_dialog",           py_message_dialog, 1 },
      { "select_subtable",          py_select_subtable, 1 },

#if 0 /* disabled since they are now methods of GabySubTable */
      { "get_first_record",         py_get_first_record, 1 },
      { "get_next_record",          py_get_next_record, 1 },
      { "get_previous_record",      py_get_previous_record, 1 },
      { "get_last_record",          py_get_last_record, 1 },
      { "subtable_get_record_no",   py_subtable_get_record_no, 1 },
      { "subtable_set_record_no",   py_subtable_set_record_no, 1 },
      { "subtable_records_list",    py_subtable_records_list, 1 },
      { "subtable_fast_records_list", py_subtable_fast_records_list, 1 },
      { "create_new_window",        py_create_new_window, 1 },
#endif

#if 0 /* disabled since they are now methods of GabyWindow */
      { "get_window_current_id",    py_get_window_current_id, 1 },
      { "set_window_current_id",    py_set_window_current_id, 1 },
      { "move_window",              py_move_window, 1 },
      { "resize_window",            py_resize_window, 1 },
      { "destroy_window",           py_destroy_window, 1 },
      { "add_bound_window",         py_add_bound_window, 1 },
      { "remove_bound_window",      py_remove_bound_window, 1 },
#endif
      { "new_output",               py_new_output, 1},
      { "gettext",                  py_gettext, 1},
      { NULL, NULL, 0 }
};

void initgaby()
{
      PyObject *d, *m, *private;
      m = Py_InitModule("gaby", gaby_funcs);
      gaby_module = m;
      d = PyModule_GetDict(m);
      
      PyDict_SetItemString(d, "GabyWindowType", (PyObject *)&PyGabyWindow_Type);
      PyDict_SetItemString(d, "GabySubTableType", (PyObject *)&PyGabySubTable_Type);
      if ( app != NULL ) {
            PyDict_SetItemString(d, "GabyOutputType", 
                        (PyObject *)&PyGabyOutput_Type);
      }
      
      private = PyDict_New();
      PyDict_SetItemString(d, "_private", private); Py_DECREF(private);
      PyDict_SetItemString(private, "PyGabyWindow_New",
                  d=PyCObject_FromVoidPtr(PyGabyWindow_New,NULL));
      Py_DECREF(d);
      PyDict_SetItemString(private, "PyGabySubTable_New",
                  d=PyCObject_FromVoidPtr(PyGabySubTable_New,NULL));
      Py_DECREF(d);
      if ( app != NULL ) {
            PyDict_SetItemString(private, "PyGabyOutput_New",
                  d=PyCObject_FromVoidPtr(PyGabyOutput_New,NULL));
            Py_DECREF(d);
      }

      if ( language[0] == 0 ) {
            strcpy(language, "en");
            if ( getenv("LANGUAGE") || getenv("LANG") ) {
                  char *t = g_strdup_printf("%s", getenv("LANGUAGE") ?
                                          getenv("LANGUAGE")
                                          : getenv("LANG")   );
                  t[2] = 0;
                  strcpy(language, t);
                  g_free(t);
            }
      }

      debug_print("Python module initialized\n");
}

int python_init_interpreter ( gchar *argv[] )
{
      char path_gaby_py[PATH_MAX];
      char *our_argv = "gaby"; 
      char *real_argv[20];
      int argc = 1;

      real_argv[0] = our_argv;
      real_argv[1] = NULL;

      if ( argv != NULL ) {
            while ( argv[argc-1] != NULL ) {
                  real_argv[argc] = argv[argc-1];
                  argc++;
            }
            argv[argc] = NULL;
      }

      if ( ! Py_IsInitialized() ) {
            debug_print("[python:init_interpreter] initializing Python\n");
            Py_SetProgramName ("gaby");
            Py_Initialize ();
            initgaby();
      
            if ( PyErr_Occurred ()) {
                  PyErr_Print ();
                  return -1;
            }

            /* to make gtk.py happy */
            PySys_SetArgv(argc, real_argv);
            
            PyRun_SimpleString("import sys\n");
            sprintf(path_gaby_py, 
                  "sys.path.append('%s/interpreter')\n", SCRIPTS_DIR);
            PyRun_SimpleString(path_gaby_py);
#ifdef DEBUG_GABY
            /*PyRun_SimpleString("print sys.path\n");*/
#endif
/*          PyRun_SimpleString("from gaby import *\n");*/
            PyRun_SimpleString("import gaby\n");
#ifdef HAVE_PYGTK
            /* freaky macro contains return statements... */
            init_pygtk();
#endif
      } else {
            debug_print("[python:init_interpreter] already initialized\n");
      }

      return 0;
}

void python_close_interpreter ()
{
      debug_print("[python:close_interpreter] <--\n");
/*    Py_Finalize();    */
      debug_print("[python:close_interpreter] -->\n");
}

void python_run_script(gchar *filename, action *act)
{
      FILE *f;
      int i;
      char string[500], *s;
      char filenam[PATH_MAX], *sfn;
      gboolean textmode = ( app == NULL ); /*getenv("DISPLAY") == NULL;*/
      
      debug_print("[python:run_script] %s\n", filename);

#ifdef DEBUG_GABY
#if 0
      PyRun_SimpleString("print sys.builtin_module_names\n");
      PyRun_SimpleString("print sys.modules.keys()\n");
      PyRun_SimpleString("print sys.executable\n");
#endif
#endif

      f = fopen(filename, "r");
      
      if ( f != NULL ) {
            debug_print("[python:run_script] the file is present\n");
            /* this should be used to pop-up a dialog with errors (if
             * errors) or with the result 
             * But I don't know how to handle this for scripts that aren't
             * finished after PyRun_SimpleFile()
             */

#if 0 /* while I don't have a way to show errors, I don't catch them */
            PyRun_SimpleString("sys.stderr = new_output()\n");
#endif

            if ( ! textmode ) {
#ifdef HAVE_TMPNAM
                  sfn = tmpnam(filenam);
#else
                  sprintf(filenam, "%s/gabypy_XXXXXX", g_get_tmp_dir());
                  sfn = mktemp(filenam);
#endif
                  g_snprintf(string, 499, "sys.stdout = gaby.new_output('%s')\n", sfn);
                  PyRun_SimpleString(string);
            }
            
            sprintf(string, "params = ( ");
            s = string+strlen(string);
            for ( i=0; i < act->nb_params; i++ ) {
                  switch ( act->params[i].type ) {
                        case P_FIELD:
                        case P_FIELD_NO:
                        {
                              sprintf(s, "%d, ", 
                                    act->params[i].field_no);
                        } break;
                        case P_TABLE:
                        {
                              sprintf(s, "'%s', ", 
                                    act->params[i].table->name );
                        } break;
                        case P_DIRECT:
                        {
                              sprintf(s, "'%s', ", 
                                    act->params[i].val.str->str );
                        } break;
                  }
                  s+=strlen(s);
            }
            s[-1] = ')';
            s[0] = '\n';
            s[1] = 0;
            debug_print("[python:run_script] params : %s", string);
            PyRun_SimpleString(string);   /* sets the args */
            
            PyRun_SimpleFile(f, filename);      /* runs the script */
            fclose(f);

            if ( ! textmode ) {
                  PyRun_SimpleString("sys.stdout.close()\n");
            
                  f =  fopen(filenam, "r");
                  string[fread(string, 1, 500, f)] = 0;
                  fclose(f);
                  unlink(filenam);
                  while ( string[strlen(string)-1] == '\n' )
                        string[strlen(string)-1] = 0;
                  debug_print("and we now show : %s\n", string);
                  if ( strlen(string) > 0 ) {
                        gaby_message = g_strdup(string);
                        gaby_errno = CUSTOM_MESSAGE;
                        gaby_perror_in_a_box();
                  }
            }
            
      } else {
            perror("oops");
      }
      
      debug_print("[python_run_script] done\n");

}


int print_plugin_fct (char *pp_name, subtable *st, GList *names, gboolean fast)
{
      PyObject *d, *s, *py_dict, *obj, *ost;
      FILE *f;
      char filename[PATH_MAX];
      int res;
      
      py_dict = PyDict_New();

      obj = PyGabySubTable_New(st);
      ost = obj;
      PyDict_SetItemString(py_dict, "subtable", obj);
      while ( names ) {
            struct ref *r = names->data;
            if ( ! fast ) {
#ifndef NO_GUI
                  switch ( r->type ) {
                  case PAGE_FIELDS:
                  {
                        GabyPage *w = r->pointer;
                        GtkWidget *page = w->real_widget;
                        int i;
                        gboolean active;
                        int selected[st->nb_fields+1]; /* portable ? */
                        page_select_fields_get_info(st, page,
                                          &active, selected);
                        i=0;
                        obj = PyList_New(0);
                        while ( selected[i] != -1 ) {
                              PyList_Append(obj,
                                    PyInt_FromLong(selected[i]));
                              i++;
                        }
                        debug_print("selected: %d\n", i);
                        PyDict_SetItemString(py_dict, r->key, obj);
                  } break;
                  case PAGE_RECORDS:
                  {
                        GabyPage *w = r->pointer;
                        GtkWidget *page = w->real_widget;
                        GList *recs = NULL, *trecs;
                        gboolean all;

                        page_select_records_get_info(st, page,
                                                &all, &recs);
                        if ( all ) {
                              PyDict_SetItemString(py_dict, r->key,
                                    py_st_fast_records_list(ost, NULL));
                              break;
                        }
                        
                        trecs = recs;
                        obj = PyList_New(0);
                        while ( trecs ) {
                              int id = GPOINTER_TO_INT(trecs->data);
                              /* those are not ids, not even the
                               * 'fast ids' as we know them: they
                               * are records pos in t->records (fast
                               * records for different people...)
                               * How coherent...
                               */
                              PyList_Append(obj,
                                    PyInt_FromLong( -id-1 ));
                              trecs = g_list_next(trecs);
                        }
                        PyDict_SetItemString(py_dict, r->key, obj);
                        g_list_free(recs);

                  } break;
                  case PAGE_ORDER:
                  {
                        GabyPage *w = r->pointer;
                        GtkWidget *page = w->real_widget;
                        int field;
                        page_select_order_get_info(st, page, &field);
                        PyDict_SetItemString(py_dict, r->key,
                                    PyInt_FromLong(field) );
                  } break;
                  case WIDGET_FILESEL:
                  case WIDGET_ENTRY:
                  {
                        GabyWidget *w = r->pointer;
                        GtkEntry *e = w->real_widget;
                        gchar *s = gtk_entry_get_text(e);
                        debug_print("value of the entry: %s\n", s);
                        PyDict_SetItemString(py_dict, r->key,
                                          PyString_FromString(s));
                  } break;
                  case WIDGET_CHECKBOX:
                  {
                        GabyWidget *w = r->pointer;
                        GtkToggleButton *tb = w->real_widget;
                        debug_print("value of toggle button: %d\n",
                                    tb->active );
                        PyDict_SetItemString(py_dict, r->key,
                                    PyInt_FromLong(tb->active));
                  } break;
                  default: break;
                  }
#endif /* ! NO_GUI */
            } else {
                  switch ( r->type ) {
                  case PAGE_FIELDS:
                  {
                        GabyPageFields *w = r->pointer;
                        int sel = w->selection;
                        int i;
                        if ( sel == G_MAXINT ) {
                              sel = st->nb_fields;
                        }
                        obj = PyList_New(0);
                        if ( sel > 0 ) {
                              for ( i=0; i<sel; i++) {
                                    PyList_Append(obj,
                                          PyInt_FromLong(i));
                              }
                        } else {
                              for ( i=-sel; i>=0; i--) {
                                    PyList_Append(obj,
                                          PyInt_FromLong(i));
                              }
                        }
                        PyDict_SetItemString(py_dict, r->key, obj);
                  } break;
                  case PAGE_RECORDS: 
                  {
                        PyDict_SetItemString(py_dict, r->key,
                              py_st_fast_records_list(ost, NULL));
                  } break;
                  case PAGE_ORDER:
                  {
                        PyDict_SetItemString(py_dict, r->key,
                                          PyInt_FromLong(0) );
                  } break;
                  case WIDGET_FILESEL:
                  case WIDGET_ENTRY:
                  {
                        PyDict_SetItemString(py_dict, r->key,
                                    PyString_FromString("-"));
                  } break;
                  case WIDGET_CHECKBOX:
                  {
                        PyDict_SetItemString(py_dict, r->key,
                                    PyInt_FromLong(0));
                  } break;
                  default: break;
                  }
            }
            names = g_list_next(names);
      }
      
/*    for (i=0; i < st->nb_fields; i++) {
            py_string = PyString_FromString(st->fields[i].name);
            PyDict_SetItem(py_dict, py_string, PyInt_FromLong(i));
      }*/

      d = PyModule_GetDict(gaby_module);
            
      s = PyInt_FromLong(5);
      PyDict_SetItemString(d, "PrintDict", (PyObject *)py_dict);

#if 1
      sprintf(filename, PLUGINS_DIR "/print/%s.py", pp_name);
      f = fopen(filename, "r");
      res = PyRun_SimpleFile(f, filename);      /* runs the script */
      fclose(f);
#else
      PyRun_SimpleString("print gaby.PrintDict\n");
#endif
      
      return res;
}

#ifndef FOLLOW_MIGUEL
char* get_interpreter_name()
{
      return "python";
}
#endif


Generated by  Doxygen 1.6.0   Back to index