/* SciGraphica - Scientific graphics and data manipulation * Copyright (C) 2001 Adrian E. Feiguin * * 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 #include #include #include #include #include #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); }