/* SciGraphica - Scientific graphics and data manipulation
* Copyright (C) 2001 Adrian E. Feiguin <feiguin@ifir.edu.ar>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <string.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <gtkextra/gtkextra.h>
#include <gdk/gdkkeysyms.h>
#include "sg_worksheet.h"
#include "sg.h"
#include "sg_worksheet_tools.h"
#include "sg_formula_dialog.h"
#include "../pixmaps/sheet_icon2.xpm"
#include "python/python_main.h"
#define DEFAULT_PRECISION 3
#define DEFAULT_ROWS 20
#define DEFAULT_COLUMNS 5
static void sg_worksheet_class_init (SGworksheetClass *klass);
static void sg_worksheet_init (SGworksheet *worksheet);
static void sg_worksheet_init_gui (SGworksheet *worksheet);
static void sg_worksheet_destroy (GtkObject *object);
static void sg_worksheet_realize (GtkWidget *widget);
static gboolean activate_cell (GtkSheet *sheet,
gint row, gint col,
gpointer data);
static gboolean deactivate_cell (GtkSheet *sheet,
gint row, gint col,
gpointer data);
static gboolean click_on_column (GtkWidget *widget,
GdkEventButton *event,
gpointer data);
static void clear_cell (GtkSheet *sheet,
gint row, gint col,
gpointer data);
static void sheet_changed (GtkSheet *sheet,
gpointer data);
#ifdef WITH_GNOME
static GnomeAppClass *parent_class = NULL;
#else
static GtkWindowClass *parent_class = NULL;
#endif
GtkType
sg_worksheet_get_type (void)
{
static GtkType sg_worksheet_type = 0;
if (!sg_worksheet_type)
{
GtkTypeInfo sg_worksheet_info =
{
"SGworksheet",
sizeof (SGworksheet),
sizeof (SGworksheetClass),
(GtkClassInitFunc) sg_worksheet_class_init,
(GtkObjectInitFunc) sg_worksheet_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
#ifdef WITH_GNOME
sg_worksheet_type = gtk_type_unique (gnome_app_get_type(), &sg_worksheet_info);
#else
sg_worksheet_type = gtk_type_unique (gtk_window_get_type(), &sg_worksheet_info);
#endif
}
return sg_worksheet_type;
}
static void
sg_worksheet_class_init (SGworksheetClass *klass)
{
GtkWidgetClass *widget_class;
GtkObjectClass *object_class;
widget_class = (GtkWidgetClass*) klass;
object_class = (GtkObjectClass*) klass;
#ifdef WITH_GNOME
parent_class = (GnomeAppClass *)gtk_type_class (gnome_app_get_type ());
#else
parent_class = (GtkWindowClass *)gtk_type_class (gtk_window_get_type ());
#endif
widget_class->realize = sg_worksheet_realize;
object_class->destroy = sg_worksheet_destroy;
}
static void
sg_worksheet_init (SGworksheet *worksheet)
{
GtkSheet *sheet;
gint c;
gint nrows, ncols;
worksheet->mode = SG_MODE_WORKSHEET;
worksheet->cell_save=NULL;
worksheet->is_frozen = FALSE;
worksheet->sheet = gtk_sheet_new(DEFAULT_ROWS, DEFAULT_COLUMNS, "Data");
nrows = 20;
ncols = 5;
worksheet->last_column = ncols-1;
sheet = GTK_SHEET(worksheet->sheet);
gtk_sheet_set_row_titles_width(sheet, 60);
GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_JUSTIFY_ENTRY);
GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_ROW_FROZEN);
worksheet->column = g_new(SGcolumn, ncols);
for(c = 0; c < ncols; c++){
gchar label[4];
gint max = 'Z'-'A'+1;
gint n;
n = 0;
if(c >= max*max){
label[0] = c/(max*max)+'A'-1;
label[1] = '\0';
n = 1;
c -= (c/(max*max))*max*max;
}
if(c >= max){
label[n] = c/max+'A'-1;
label[n+1] = '\0';
n++ ;
c -= (c/max)*max;
}
if(c < max){
label[n] = c+'A';
label[n+1] = '\0';
}
gtk_sheet_column_button_add_label(sheet, c, label);
gtk_sheet_set_column_title(sheet, c, label);
sg_worksheet_column_set_format(worksheet, c,
SG_TYPE_NUMBER,
SG_FORMAT_DECIMAL,
SG_INTERNAL_DOUBLE,
DEFAULT_PRECISION);
worksheet->column[c].exp = NULL;
}
sg_worksheet_matrix_set_format(worksheet,
SG_TYPE_NUMBER,
SG_FORMAT_DECIMAL,
SG_INTERNAL_DOUBLE,
DEFAULT_PRECISION);
worksheet->matrix.exp = NULL;
worksheet->sw = NULL;
worksheet->x = 0;
worksheet->y = 0;
worksheet->width = 500;
worksheet->height = 350;
worksheet->begin = -1;
worksheet->end = -1;
worksheet->xmin = 0.;
worksheet->xmax = 10.;
worksheet->ymin = 0.;
worksheet->ymax = 10.;
gtk_signal_connect(GTK_OBJECT(worksheet->sheet), "activate",
GTK_SIGNAL_FUNC(activate_cell), worksheet);
gtk_signal_connect(GTK_OBJECT(worksheet->sheet), "deactivate",
GTK_SIGNAL_FUNC(deactivate_cell), worksheet);
gtk_signal_connect(GTK_OBJECT(worksheet->sheet), "clear_cell",
GTK_SIGNAL_FUNC(clear_cell), worksheet);
gtk_signal_connect(GTK_OBJECT(worksheet->sheet), "changed",
GTK_SIGNAL_FUNC(sheet_changed), NULL);
gtk_signal_connect(GTK_OBJECT(worksheet->sheet), "button_press_event",
GTK_SIGNAL_FUNC(click_on_column), worksheet);
sg_worksheet_init_gui(worksheet);
}
SGworksheet *
sg_worksheet_new(gchar *name, gint nrows, gint ncols)
{
SGworksheet *worksheet;
worksheet = SG_WORKSHEET(gtk_widget_new(sg_worksheet_get_type(), NULL));
worksheet->name = g_strdup(name);
gtk_sheet_set_title(GTK_SHEET(worksheet->sheet), (const gchar *)name);
gtk_window_set_title(GTK_WINDOW(worksheet),name);
sg_worksheet_add_rows(worksheet, nrows - DEFAULT_ROWS);
sg_worksheet_add_columns(worksheet, ncols - DEFAULT_COLUMNS);
return worksheet;
}
gint
sg_worksheet_get_column(SGworksheet *worksheet, gchar *col_name)
{
GtkSheet *sheet;
gint i;
sheet = GTK_SHEET(worksheet->sheet);
for(i = 0; i <= sheet->maxcol; i++)
if(strcmp(sheet->column[i].name, col_name) == 0) return i;
return -1;
}
void
sg_worksheet_column_set_format(SGworksheet *worksheet,
gint column,
SGcolumntype type,
SGcolumnformat format,
SGcolumninternal internal,
gint precision)
{
GtkSheet *sheet;
gint row;
sheet = GTK_SHEET(worksheet->sheet);
worksheet->column[column].type = type;
worksheet->column[column].format = format;
worksheet->column[column].internal = internal;
worksheet->column[column].precision = precision;
switch(worksheet->column[column].type){
case SG_TYPE_NUMBER:
gtk_sheet_column_set_justification(sheet, column, GTK_JUSTIFY_RIGHT);
break;
case SG_TYPE_DATE:
case SG_TYPE_TIME:
gtk_sheet_column_set_justification(sheet, column, GTK_JUSTIFY_CENTER);
break;
case SG_TYPE_TEXT:
default:
gtk_sheet_column_set_justification(sheet, column, GTK_JUSTIFY_LEFT);
}
gtk_sheet_freeze(sheet);
for(row = 0; row <= sheet->maxallocrow; row++)
sg_worksheet_cell_update_format(worksheet, row, column);
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_matrix_set_format(SGworksheet *worksheet,
SGcolumntype type,
SGcolumnformat format,
SGcolumninternal internal,
gint precision)
{
GtkSheet *sheet;
gint row,col;
sheet = GTK_SHEET(worksheet->sheet);
worksheet->matrix.type = type;
worksheet->matrix.format = format;
worksheet->matrix.internal = internal;
worksheet->matrix.precision = precision;
switch(worksheet->matrix.type){
case SG_TYPE_NUMBER:
for(col = 0; col <= sheet->maxalloccol; col++)
gtk_sheet_column_set_justification(sheet, col, GTK_JUSTIFY_RIGHT);
break;
case SG_TYPE_DATE:
case SG_TYPE_TIME:
for(col = 0; col <= sheet->maxalloccol; col++)
gtk_sheet_column_set_justification(sheet, col, GTK_JUSTIFY_CENTER);
break;
case SG_TYPE_TEXT:
default:
for(col = 0; col <= sheet->maxalloccol; col++)
gtk_sheet_column_set_justification(sheet, col, GTK_JUSTIFY_LEFT);
}
gtk_sheet_freeze(sheet);
for(col = 0; col <= sheet->maxalloccol; col++)
for(row = 0; row <= sheet->maxallocrow; row++)
sg_worksheet_cell_update_format(worksheet, row, col);
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_hidden_cell_clear(SGworksheet *sheet, gint row, gint col)
{
SGhiddencell *hidden;
hidden = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(sheet->sheet), row, col);
if(hidden)
{
if (hidden->formula){
g_free(hidden->formula);
hidden->formula = NULL;
}
switch(hidden->type){
case SG_TYPE_DATE:
case SG_TYPE_TIME:
case SG_TYPE_TEXT:
if (hidden->value.val_char){
g_free(hidden->value.val_char);
hidden->value.val_char = NULL;
}
break;
default:
break;
}
g_free(hidden);
gtk_sheet_link_cell(GTK_SHEET(sheet->sheet), row, col, NULL);
}
}
void
sg_worksheet_cell_clear(SGworksheet *sheet, gint row, gint col)
{
sg_worksheet_hidden_cell_clear(sheet, row, col);
gtk_sheet_cell_clear(GTK_SHEET(sheet->sheet), row, col);
}
static gboolean
click_on_column(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
SGworksheet *worksheet;
GtkSheet *sheet;
GdkModifierType mods;
gint x, y;
gint r, c;
worksheet = SG_WORKSHEET(data);
sheet = GTK_SHEET(worksheet->sheet);
if(event->window != sheet->column_title_window) return FALSE;
gdk_window_get_pointer(widget->window, &x, &y, &mods);
if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
if(event->type != GDK_2BUTTON_PRESS) return FALSE;
GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION|GTK_SHEET_IN_XDRAG|GTK_SHEET_IN_YDRAG);
gdk_pointer_ungrab(event->time);
gtk_grab_remove(widget);
gtk_sheet_get_pixel_info(sheet, x, y, &r, &c);
if(c >= 0)
sg_formula_dialog(worksheet, c);
return FALSE;
}
static void
clear_cell(GtkSheet *sheet, gint row, gint col, gpointer data)
{
SGhiddencell *hidden;
hidden = (SGhiddencell *)gtk_sheet_get_link(sheet, row, col);
if(hidden)
{
if (hidden->formula){
g_free(hidden->formula);
hidden->formula = NULL;
}
switch(hidden->type){
case SG_TYPE_DATE:
case SG_TYPE_TIME:
case SG_TYPE_TEXT:
if (hidden->value.val_char){
g_free(hidden->value.val_char);
hidden->value.val_char = NULL;
}
break;
default: break;
}
g_free(hidden);
gtk_sheet_link_cell(sheet, row, col, NULL);
}
}
static gboolean
activate_cell(GtkSheet *sheet, gint row, gint col, gpointer data)
{
SGworksheet *worksheet;
GtkEntry *entry;
gchar *text=NULL,fpnum[40];
gchar label[100];
SGhiddencell *link = NULL;
PyObject *floato;
entry = GTK_ENTRY(sheet->sheet_entry);
worksheet = (SGworksheet *)data;
worksheet->cell_save = g_strdup(gtk_entry_get_text(entry));
if(worksheet->column[col].type == SG_TYPE_TEXT) return TRUE;
link=(SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet),row,col);
fpnum[0]='\0';
if (link)
{
if (link->formula){
text = link->formula;
}
else if(link->type == SG_TYPE_NUMBER){
if(link->internal == SG_INTERNAL_INTEGER){
switch(link->format){
case SG_FORMAT_DECIMAL:
g_snprintf(fpnum,40,"%l",link->value.val_long);
text=fpnum;
break;
case SG_FORMAT_SCIENTIFIC:
floato=PyObject_Repr(PyFloat_FromDouble((double)link->value.val_long));
text=PyString_AsString(floato);
break;
}
} else {
switch(link->format){
case SG_FORMAT_DECIMAL:
floato=PyObject_Repr(PyFloat_FromDouble(link->value.val_double));
text=PyString_AsString(floato);
break;
case SG_FORMAT_SCIENTIFIC:
g_snprintf(fpnum,40,"%2.20e",link->value.val_double);
text=fpnum;
break;
}
}
} else {
text=link->value.val_char;
}
if(!worksheet->is_frozen) gtk_entry_set_text(entry,text);
}
else
{
text = NULL;
gtk_entry_set_text(entry,"");
}
if(text && strlen(text)){
gtk_entry_select_region(entry, 0, strlen(text));
gtk_entry_set_position(entry, 0);
}
sprintf(label, " %s:%d", sheet->column[col].name, row);
gtk_label_set(GTK_LABEL(worksheet->label), label);
return TRUE;
}
static gboolean
deactivate_cell(GtkSheet *sheet, gint row, gint col, gpointer data)
{
SGworksheet *worksheet;
gchar *text;
gint arow,acol;
worksheet = (SGworksheet *)data;
text = gtk_sheet_cell_get_text(sheet, row, col);
if(text && strlen(text) > 0)
sg_worksheet_cell_set(worksheet, row, col, text, TRUE, TRUE);
return TRUE;
}
void sg_worksheet_cell_set_text(SGworksheet *worksheet, gint row, gint col, gchar *text)
{
gint arow,acol;
gtk_sheet_set_cell_text(GTK_SHEET(worksheet->sheet), row, col, text);
gtk_sheet_get_active_cell(GTK_SHEET(worksheet->sheet), &arow, &acol);
if (arow==row && acol==col)
{
gtk_entry_set_text(GTK_ENTRY(GTK_SHEET(worksheet->sheet)->sheet_entry),text);
}
}
void
sg_worksheet_cell_set(SGworksheet *worksheet, gint row, gint col,
gchar *text, gboolean formula, gboolean eval)
{
gchar *save;
SGhiddencell *link = NULL;
GtkSheet *sheet;
gboolean myformula=formula, myeval=eval;
sheet = GTK_SHEET(worksheet->sheet);
link = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet), row, col);
if (text && strlen(text))
{ if (!link)
{
myformula=formula;
myeval=eval;
link = (SGhiddencell *)g_new0(SGhiddencell, 1);
link->formula = NULL;
link->updated = FALSE;
link->format = worksheet->column[col].format;
link->type = worksheet->column[col].type;
link->internal = worksheet->column[col].internal;
link->precision = worksheet->column[col].precision;
gtk_sheet_link_cell(GTK_SHEET(worksheet->sheet), row, col, link);
}
save = g_strdup(text);
if (!myformula)
{
sg_worksheet_cell_set_text(worksheet,row, col, save);
}
else
{
link->updated=FALSE;
switch(link->type){
case SG_TYPE_DATE:
case SG_TYPE_TIME:
case SG_TYPE_TEXT:
if (link->value.val_char){
g_free(link->value.val_char);
link->value.val_char = NULL;
}
myeval = FALSE;
break;
}
if (myeval){
worksheet->is_frozen = TRUE;
if (python_sheet(worksheet, row, col, save, GTK_ORIENTATION_VERTICAL)){
link->updated=TRUE;
link->formula=g_strdup(save);
}
worksheet->is_frozen = FALSE;
}
else /* currently used for dates, text, and time */
{
sg_worksheet_cell_set_text(worksheet, row, col, (save?save:text));
}
if (link->formula)
g_free(link->formula);
link->formula = save;
}
}
else /* We were passed an empty cell */
{
if (link) sg_worksheet_cell_clear(worksheet, row, col);
else
{
if (worksheet->cell_save && strlen(worksheet->cell_save))
sg_worksheet_cell_set_text(worksheet,
row, col, g_strdup(worksheet->cell_save));
else
gtk_sheet_cell_clear(GTK_SHEET(worksheet->sheet), row, col);
}
}
if(worksheet->cell_save) g_free(worksheet->cell_save);
worksheet->cell_save = NULL;
}
gboolean
sg_worksheet_cell_update_format(SGworksheet *worksheet, gint row, gint col)
{
GtkSheet *sheet;
gchar *string,fpnum[40],pspec[20];
gint freemem=FALSE;
SGhiddencell *hidden;
sheet = GTK_SHEET(worksheet->sheet);
hidden = (SGhiddencell *)gtk_sheet_get_link(sheet, row, col);
if (!hidden) return FALSE;
fpnum[0]='\0';
pspec[0]='\0';
hidden->type = worksheet->column[col].type;
hidden->format = worksheet->column[col].format;
hidden->internal = worksheet->column[col].internal;
hidden->precision = worksheet->column[col].precision;
if(hidden->type == SG_TYPE_NUMBER){
if(hidden->internal == SG_INTERNAL_INTEGER){
switch(hidden->format){
case SG_FORMAT_DECIMAL:
g_snprintf(pspec,20,"%%ld");
g_snprintf(fpnum,40,pspec,hidden->value.val_long);
string=fpnum;
break;
case SG_FORMAT_SCIENTIFIC:
g_snprintf(pspec,20,"%%1.%de",hidden->precision);
g_snprintf(fpnum,40,pspec,(double)hidden->value.val_long);
string=fpnum;
break;
}
} else {
switch(hidden->format){
case SG_FORMAT_DECIMAL:
g_snprintf(pspec,20,"%%1.%df",hidden->precision);
g_snprintf(fpnum,40,pspec,hidden->value.val_double);
string=fpnum;
break;
case SG_FORMAT_SCIENTIFIC:
g_snprintf(pspec,20,"%%1.%de",hidden->precision);
g_snprintf(fpnum,40,pspec,hidden->value.val_double);
string=fpnum;
break;
}
}
} else {
string=hidden->value.val_char;
}
sg_worksheet_cell_set_text(worksheet,row, col, string);
return TRUE;
}
gchar *
sg_worksheet_cell_get_text(SGworksheet *worksheet, gint row, gint col)
{ gint arow,acol;
gchar *text;
gtk_sheet_get_active_cell(GTK_SHEET(worksheet->sheet), &arow, &acol);
if (GTK_SHEET(worksheet->sheet)->state == GTK_STATE_NORMAL &&
arow==row && acol==col && worksheet->cell_save){
text=worksheet->cell_save;
}else{
text = gtk_sheet_cell_get_text(GTK_SHEET(worksheet->sheet), row, col);
}
return text;
}
gchar *
sg_worksheet_cell_get_formula(SGworksheet *worksheet, gint row, gint col)
{
gchar *text=NULL;
SGhiddencell *link;
link = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet),
row, col);
if(link) text = link->formula;
return text;
}
gdouble
sg_worksheet_cell_get_double(SGworksheet *worksheet, gint row, gint col, gboolean *error)
{
gchar *text=NULL;
SGhiddencell *link;
*error = FALSE;
if(!worksheet) {
*error=TRUE;
return 0.0;
}
link = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet),
row, col);
if(!link) {
*error=TRUE;
return 0.0;
}
switch(link->type){
case SG_TYPE_NUMBER:
switch (link->internal){
case SG_INTERNAL_INTEGER: return (gdouble)link->value.val_long;
case SG_INTERNAL_DOUBLE: return (gdouble)link->value.val_double;
default: return 0.0;
}
case SG_TYPE_TEXT:
case SG_TYPE_TIME:
case SG_TYPE_DATE:
default:
return 0.0;
}
}
gint
sg_worksheet_cell_get_int(SGworksheet *worksheet, gint row, gint col, gboolean *error)
{
gchar *text=NULL;
SGhiddencell *link;
*error = FALSE;
if(!worksheet) {
*error=TRUE;
return 0;
}
link = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet),
row, col);
if(!link) {
*error=TRUE;
return 0;
}
switch(link->type){
case SG_TYPE_NUMBER:
switch (link->internal){
case SG_INTERNAL_INTEGER: return (gint)link->value.val_long;
case SG_INTERNAL_DOUBLE: return (gint)link->value.val_double;
default: return 0;
}
case SG_TYPE_TEXT:
case SG_TYPE_TIME:
case SG_TYPE_DATE:
default:
return 0;
}
}
static void
sg_worksheet_init_gui(SGworksheet *worksheet)
{
gchar msg[80];
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *toolbar;
gtk_window_set_title(GTK_WINDOW(worksheet), worksheet->name);
gtk_window_set_policy(GTK_WINDOW(worksheet), TRUE, TRUE, FALSE);
vbox = gtk_vbox_new(FALSE, 5);
#ifdef WITH_GNOME
gnome_app_construct(GNOME_APP(worksheet), PACKAGE, worksheet->name);
gnome_app_set_contents(GNOME_APP(worksheet),vbox);
#else
gtk_container_add(GTK_CONTAINER(worksheet),vbox);
#endif
toolbar = sg_worksheet_build_toolbar(worksheet);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
worksheet->label = gtk_label_new(" ");
gtk_misc_set_alignment(GTK_MISC(worksheet->label), 0., .5);
gtk_container_add(GTK_CONTAINER(frame), worksheet->label);
worksheet->sw = gtk_scrolled_window_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER(worksheet->sw), worksheet->sheet);
gtk_box_pack_start(GTK_BOX(vbox), worksheet->sw, TRUE, TRUE, 0);
gtk_box_pack_end(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
gtk_widget_ensure_style(worksheet->sheet);
gtk_widget_show(worksheet->sw);
gtk_widget_show(worksheet->sheet);
gtk_widget_show(worksheet->label);
gtk_widget_show(frame);
gtk_widget_show(vbox);
if(worksheet->x > 0 && worksheet->y > 0){
gtk_widget_set_uposition(GTK_WIDGET(worksheet),
worksheet->x, worksheet->y);
gtk_widget_set_usize(GTK_WIDGET(worksheet),
worksheet->width,
worksheet->height);
}else{
gtk_widget_set_usize(GTK_WIDGET(worksheet),
500,
350);
}
}
static void
sg_worksheet_realize(GtkWidget *widget)
{
GdkPixmap *sheet_icon_pixmap;
GdkBitmap *sheet_icon_mask;
SGworksheet *worksheet;
worksheet = SG_WORKSHEET(widget);
GTK_WIDGET_CLASS(parent_class)->realize(widget);
sheet_icon_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL,
gdk_colormap_get_system(),
&sheet_icon_mask, NULL, sheet_icon2_xpm);
gdk_window_set_icon(GTK_WIDGET(worksheet)->window, NULL,
sheet_icon_pixmap, sheet_icon_mask);
}
gint
sg_worksheet_rename(SGworksheet *worksheet, gchar *name)
{
if(strcmp(worksheet->name, name) == 0) return FALSE;
if(worksheet->name){
g_free(worksheet->name);
worksheet->name = NULL;
}
worksheet->name = g_strdup(name);
gtk_window_set_title(GTK_WINDOW(worksheet),name);
if(gui_iconlist){
if(worksheet->icon->entry_label){
g_free(worksheet->icon->entry_label);
worksheet->icon->entry_label = NULL;
}
worksheet->icon->entry_label = g_strdup(name);
if(worksheet->icon->entry_label){
g_free(worksheet->icon->label);
worksheet->icon->label = NULL;
}
worksheet->icon->label = g_strdup(name);
gtk_entry_set_text(GTK_ENTRY(worksheet->icon->entry), name);
}
return TRUE;
}
void
sg_worksheet_set_begin(SGworksheet *worksheet, gint row)
{
GtkSheet *sheet;
GdkColor bg;
GtkSheetRange range;
gchar label[100];
sheet = GTK_SHEET(worksheet->sheet);
if(row > worksheet->end &&
worksheet->end != -1) return;
gtk_sheet_freeze(sheet);
if(worksheet->begin != -1){
range.col0 = 0;
range.coli = sheet->maxcol;
range.row0 = worksheet->begin;
range.rowi = worksheet->begin;
gdk_color_white(gdk_colormap_get_system(), &bg);
gtk_sheet_row_button_add_label(sheet, worksheet->begin, NULL);
gtk_sheet_range_set_background(sheet, &range, &bg);
}
gdk_color_parse("light blue", &bg);
gdk_color_alloc(gdk_colormap_get_system(), &bg);
worksheet->begin = row;
range.col0 = 0;
range.coli = sheet->maxcol;
range.row0 = row;
range.rowi = row;
sprintf(label, "(Begin)");
if(row > -1){
gtk_sheet_row_button_add_label(sheet, row, label);
gtk_sheet_range_set_background(sheet, &range, &bg);
}
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_set_end(SGworksheet *worksheet, gint row)
{
GtkSheet *sheet;
GdkColor bg;
GtkSheetRange range;
gchar label[100];
sheet = GTK_SHEET(worksheet->sheet);
if(row != -1 && row < worksheet->begin) return;
gtk_sheet_freeze(sheet);
if(worksheet->end != -1){
range.col0 = 0;
range.coli = sheet->maxcol;
range.row0 = worksheet->end;
range.rowi = worksheet->end;
gdk_color_white(gdk_colormap_get_system(), &bg);
gtk_sheet_row_button_add_label(sheet, worksheet->end, NULL);
gtk_sheet_range_set_background(sheet, &range, &bg);
}
gdk_color_parse("light blue", &bg);
gdk_color_alloc(gdk_colormap_get_system(), &bg);
worksheet->end = row;
range.col0 = 0;
range.coli = sheet->maxcol;
range.row0 = row;
range.rowi = row;
sprintf(label, "(End)");
if(row > -1){
gtk_sheet_row_button_add_label(sheet, row, label);
gtk_sheet_range_set_background(sheet, &range, &bg);
}
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_reset(SGworksheet *worksheet)
{
sg_worksheet_set_begin(worksheet, -1);
sg_worksheet_set_end(worksheet, -1);
}
void
sg_worksheet_destroy(GtkObject *object)
{
SGworksheet *worksheet;
worksheet = SG_WORKSHEET(object);
g_free(worksheet->name);
g_free(worksheet->column);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
void
sg_worksheet_add_rows(SGworksheet *worksheet, gint nrows)
{
GtkSheet *sheet;
sheet = GTK_SHEET(worksheet->sheet);
if(nrows < 0){
sg_worksheet_delete_rows(worksheet, sheet->maxrow+nrows+1, -nrows);
return;
}
gtk_sheet_freeze(sheet);
gtk_sheet_add_row(sheet, nrows);
sg_worksheet_set_begin(worksheet, worksheet->begin);
sg_worksheet_set_end(worksheet, worksheet->end);
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_add_columns(SGworksheet *worksheet, gint ncols)
{
GtkSheet *sheet;
gint i, c, n = 0, max;
gchar label[4];
sheet = GTK_SHEET(worksheet->sheet);
if(ncols < 0){
sg_worksheet_delete_columns(worksheet, sheet->maxcol+ncols+1, -ncols);
return;
}
gtk_sheet_freeze(sheet);
max = 'Z'-'A'+1;
gtk_sheet_add_column(sheet, ncols);
worksheet->column = g_renew(SGcolumn, worksheet->column, (sheet->maxcol + 1));
for(i = sheet->maxcol - ncols + 1; i <= sheet->maxcol ; i++){
worksheet->last_column++;
c = worksheet->last_column;
n = 0;
if(c >= max*max){
label[0] = c/(max*max)+'A'-1;
label[1] = '\0';
n = 1;
c -= (c/(max*max))*max*max;
}
if(c >= max){
label[n] = c/max+'A'-1;
label[n+1] = '\0';
n++ ;
c -= (c/max)*max;
}
if(c < max){
label[n] = c+'A';
label[n+1] = '\0';
}
gtk_sheet_column_button_add_label(sheet, i, label);
gtk_sheet_set_column_title(sheet, i, label);
gtk_sheet_column_set_justification(sheet, i, GTK_JUSTIFY_RIGHT);
sg_worksheet_column_set_format(worksheet, i,
SG_TYPE_NUMBER,
SG_FORMAT_DECIMAL,
SG_INTERNAL_DOUBLE,
DEFAULT_PRECISION);
worksheet->column[i].exp = NULL;
}
sg_worksheet_set_begin(worksheet, worksheet->begin);
sg_worksheet_set_end(worksheet, worksheet->end);
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_set_column_name(SGworksheet *worksheet, gint col, gchar *name)
{
GtkSheet *sheet;
sheet = GTK_SHEET(worksheet->sheet);
gtk_sheet_column_button_add_label(sheet, col, name);
gtk_sheet_set_column_title(sheet, col, name);
}
void
sg_worksheet_insert_rows(SGworksheet *worksheet,
gint row,
gint nrows)
{
GtkSheet *sheet;
sheet = GTK_SHEET(worksheet->sheet);
gtk_sheet_insert_rows(sheet, row, nrows);
if(worksheet->end >= row)
sg_worksheet_set_end(worksheet, worksheet->end + nrows);
if(worksheet->begin >= row)
sg_worksheet_set_begin(worksheet, worksheet->begin + nrows);
}
void
sg_worksheet_insert_columns(SGworksheet *worksheet,
gint col,
gint ncols)
{
GtkSheet *sheet;
gint i, c, n, max;
gchar label[4];
SGcolumn auxcol;
sheet = GTK_SHEET(worksheet->sheet);
gtk_sheet_freeze(sheet);
gtk_sheet_insert_columns(sheet, col, ncols);
worksheet->column = g_renew(SGcolumn, worksheet->column, (sheet->maxcol + 1));
for(i=sheet->maxcol; i>=col+ncols; i--){
auxcol = worksheet->column[i];
worksheet->column[i]=worksheet->column[i-ncols];
worksheet->column[i-ncols]=auxcol;
}
max = 'Z'-'A'+1;
for(i = col; i < col+ncols; i++){
worksheet->last_column++;
c = worksheet->last_column;
n = 0;
if(c >= max*max){
label[0] = c/(max*max)+'A'-1;
label[1] = '\0';
n = 1;
c -= (c/(max*max))*max*max;
}
if(c >= max){
label[n] = c/max+'A'-1;
label[n+1] = '\0';
n++ ;
c -= (c/max)*max;
}
if(c < max){
label[n] = c+'A';
label[n+1] = '\0';
}
gtk_sheet_column_button_add_label(sheet, i, label);
gtk_sheet_set_column_title(sheet, i, label);
gtk_sheet_column_set_justification(sheet, i, GTK_JUSTIFY_RIGHT);
sg_worksheet_column_set_format(worksheet, i,
SG_TYPE_NUMBER,
SG_FORMAT_DECIMAL,
SG_INTERNAL_DOUBLE,
DEFAULT_PRECISION);
worksheet->column[i].exp = NULL;
}
gtk_sheet_thaw(sheet);
}
void
sg_worksheet_delete_rows(SGworksheet *worksheet, gint row, gint nrows)
{
GtkSheet *sheet;
sheet = GTK_SHEET(worksheet->sheet);
gtk_sheet_delete_rows(sheet, row,
nrows);
if(worksheet->begin >= row &&
worksheet->begin <= row+nrows)
sg_worksheet_set_begin(worksheet, -1);
if(worksheet->begin > row+nrows)
sg_worksheet_set_begin(worksheet,
worksheet->begin - nrows);
if(worksheet->end >= row &&
worksheet->end <= row+nrows)
sg_worksheet_set_end(worksheet, -1);
if(worksheet->end > row+nrows)
sg_worksheet_set_end(worksheet,
worksheet->end - nrows);
}
void
sg_worksheet_delete_columns(SGworksheet *worksheet, gint col, gint ncols)
{
GtkSheet *sheet;
gint i;
sheet = GTK_SHEET(worksheet->sheet);
gtk_sheet_delete_columns(sheet,
col,
ncols);
for(i = col; i <= sheet->maxcol-ncols; i++){
sg_worksheet_column_set_exp(worksheet, i, NULL);
worksheet->column[i]=worksheet->column[i+ncols];
}
}
void
sg_worksheet_column_set_exp(SGworksheet *worksheet, gint col, gchar *exp)
{ gchar *new_exp;
if (exp && strlen(exp)>0)
new_exp=g_strdup(exp);
if(worksheet->column[col].exp)
g_free(worksheet->column[col].exp);
worksheet->column[col].exp = NULL;
if(exp && strlen(exp) > 0)
worksheet->column[col].exp = new_exp;;
}
void
sg_worksheet_update_column_exp (SGworksheet *worksheet,
gchar *exp, gint column,
gint from, gint to)
{
PyObject *object;
gint i;
object = (PyObject *)python_eval_expr(exp);
if (object)
{
if (PyArray_Check(object))
{ gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
python_array(worksheet,0,column,(PyArrayObject *)object,
GTK_ORIENTATION_VERTICAL,TRUE);
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
}
else if (PySequence_Check(object))
{ gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
python_sequence(worksheet,0,column,object,
GTK_ORIENTATION_VERTICAL,TRUE,FALSE);
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
}
else if (object!=Py_None)
{ gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
for (i=from;i<=to;i++) /* inclusive */
python_singleton(worksheet,i,column,object,TRUE,TRUE);
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
}
else
{ gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
for (i=from;i<=to;i++) /* inclusive */
sg_worksheet_cell_set(worksheet, i, column, exp, TRUE, TRUE);
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
}
Py_XDECREF(object);
}
}
void
sg_worksheet_matrix_set_exp(SGworksheet *worksheet, gchar *exp)
{
if(worksheet->matrix.exp)
g_free(worksheet->matrix.exp);
worksheet->matrix.exp = NULL;
if(exp && strlen(exp) > 0)
worksheet->matrix.exp = g_strdup(exp);
}
void
sg_worksheet_update_matrix_exp (SGworksheet *worksheet, gchar *exp,
gint from_col, gint to_col,
gint from_row, gint to_row)
{
PyObject *object;
gint i,j;
gdouble x, y, dx, dy, z;
gboolean TwoD=FALSE, OneD=FALSE;
if (exp!=worksheet->matrix.exp)
sg_worksheet_matrix_set_exp(worksheet, exp);
if (!worksheet->matrix.exp) return;
dx=(worksheet->xmax-worksheet->xmin)/gtk_sheet_get_columns_count(GTK_SHEET(worksheet->sheet));
dy=(worksheet->ymax-worksheet->ymin)/gtk_sheet_get_rows_count(GTK_SHEET(worksheet->sheet));
gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
for (j=from_col;j<=to_col;j++) /* inclusive */
{ x=(gdouble)j*dx + worksheet->xmin;
OneD=FALSE;
for (i=from_row;i<=to_row;i++) /* inclusive */
{ y= worksheet->ymin+i*dy;
object = sg_eval_func_xy(exp, x, y, &z);
if (object)
{ if (PyArray_Check(object))
{ PyArrayObject *array;
array=(PyArrayObject *)object;
if (array->nd>2) /*No more than 2 dimensions */
{
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
return;
}
if (array->nd==2) TwoD=TRUE;
if (array->nd==1) OneD=TRUE;
python_array(worksheet,i,j,(PyArrayObject *)array,
GTK_ORIENTATION_VERTICAL,TRUE);
}
else if (PySequence_Check(object))
{
python_sequence(worksheet,0,0,object,
GTK_ORIENTATION_VERTICAL,TRUE,FALSE);
OneD=TRUE;
}
else if (object!=Py_None)
python_singleton(worksheet,i,j,object,FALSE,TRUE);
else
sg_worksheet_cell_set(worksheet, i, j, exp, TRUE, TRUE);
Py_XDECREF(object);
}
if (OneD || TwoD) break;
}
if (TwoD) break;
}
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
}
/* Mark all formulas in a range as not updated */
gint sg_worksheet_unupdate_exp_range(SGworksheet *worksheet,
gint row0, gint rowi,
gint col0, gint coli)
{ SGcolumn *column;
gint col,row;
gchar *exp;
SGhiddencell *link = NULL;
link = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet),
row, col);
for(row=row0;row<=rowi;row++)
for (col=col0;col<=coli;col++)
{
exp=sg_worksheet_cell_get_formula(worksheet, row, col);
if (!exp) continue;
link = (SGhiddencell *)gtk_sheet_get_link(GTK_SHEET(worksheet->sheet), row, col);
if (link) link->updated=FALSE;
}
return TRUE;
}
/* Mark all formulas in cells as not updated */
gint sg_worksheet_unupdate_exp_all(SGworksheet *worksheet)
{
return sg_worksheet_unupdate_exp_range(worksheet,
0, GTK_SHEET(worksheet->sheet)->maxallocrow,
0, GTK_SHEET(worksheet->sheet)->maxalloccol);
}
gint sg_worksheet_update_matrix(SGworksheet *worksheet)
{ SGworksheet *active_sheet_temp;
active_sheet_temp=active_worksheet;
if (!worksheet->mode==SG_MODE_MATRIX) return FALSE;
gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
sg_worksheet_update_matrix_exp(worksheet,worksheet->matrix.exp,0,
gtk_sheet_get_columns_count(GTK_SHEET(worksheet->sheet)) - 1,
0,gtk_sheet_get_rows_count(GTK_SHEET(worksheet->sheet)) - 1);
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
active_worksheet=active_sheet_temp;
return TRUE;
}
gint sg_worksheet_update_column(SGworksheet *worksheet, gint col)
{ SGworksheet *active_sheet_temp;
active_sheet_temp=active_worksheet;
gtk_sheet_freeze(GTK_SHEET(worksheet->sheet));
if (worksheet->column[col].exp)
{ sg_worksheet_update_column_exp(worksheet,worksheet->column[col].exp,col,0,
gtk_sheet_get_rows_count(GTK_SHEET(worksheet->sheet)) - 1);
}
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
active_worksheet=active_sheet_temp;
return TRUE;
}
gint sg_worksheet_update_exp_range(SGworksheet *worksheet,
gint row0, gint rowi,
gint col0, gint coli)
{
SGcolumn *column;
gint col,row,uneval1=-1,uneval2=0,error;
gchar *exp, *exp2;
SGhiddencell *link = NULL;
gint srow,scol,num_selected=0;
GtkSheet *sheet;
SGworksheet *active_sheet_temp;
active_sheet_temp=active_worksheet;
active_worksheet=worksheet;
sheet=GTK_SHEET(worksheet->sheet);
gtk_sheet_freeze(sheet);
gtk_sheet_get_active_cell(GTK_SHEET(worksheet->sheet),&srow,&scol);
num_selected=((sheet->range.rowi-sheet->range.row0)+1)*
((sheet->range.coli-GTK_SHEET(worksheet->sheet)->range.col0)+1);
sg_report_python_error=FALSE;
while (uneval1!=uneval2)
{ /* Report problems from the second pass */
if (uneval1>=0) sg_report_python_error=TRUE;
uneval1=uneval2;
for (col=col0;col<=coli;col++)
{ sg_worksheet_update_column(worksheet,col);
for(row=row0,uneval2=0;row<=rowi;row++)
{ exp=g_strdup(sg_worksheet_cell_get_formula(worksheet, row, col));
link = (SGhiddencell *)gtk_sheet_get_link(sheet, row, col);
if (!link || !exp)
continue;
sg_worksheet_cell_set(worksheet, row, col, exp, TRUE, TRUE);
if (row==srow && col==scol && num_selected==1){
gtk_entry_set_text(GTK_ENTRY(sheet->sheet_entry), g_strdup(exp));
g_free(exp);
}
if (!link->updated) uneval2++;
}
}
if (uneval2==0) break;
}
gtk_sheet_thaw(GTK_SHEET(worksheet->sheet));
active_worksheet=active_sheet_temp;
return uneval2;
}
gint sg_worksheet_update_exp_all(SGworksheet *worksheet)
{ if (worksheet->mode==SG_MODE_MATRIX)
sg_worksheet_update_matrix(worksheet);
return sg_worksheet_update_exp_range(worksheet,
0, gtk_sheet_get_rows_count(GTK_SHEET(worksheet->sheet))-1,
0, gtk_sheet_get_columns_count(GTK_SHEET(worksheet->sheet))-1);
}
static void
sheet_changed (GtkSheet *sheet, gpointer data)
{
sg_project_changed(TRUE);
}
syntax highlighted by Code2HTML, v. 0.9.1