Commit ef0634ee authored by Arturo Espinosa's avatar Arturo Espinosa
Browse files

Autofill lists work:



Autofill lists work:

	Integers, Floats, Formulas and constant strings works.

Todo:

	Lists of known strings and strings with numbers embedded

Miguel.
parent ca8fa0ac
1998-09-16 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_item_new): We now have a working
implementation of the Autofill feature.
1998-09-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_range_new): New routine, used to
create a fill_item
* src/item-grid.c (item_grid_event): Use the proper cursor
depending on the sheet mode.
* src/sheet-object.c (object_event): Set the cursor to the arrow.
(object_handle_event): Same.
* src/cursors.h (cursor_set_widget, cursor_set): New macros to
access easily the gnumeric cursors.
1998-09-14 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/cursors.c: Define the Gnumeric cursors here.
......
1998-09-16 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_item_new): We now have a working
implementation of the Autofill feature.
1998-09-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_range_new): New routine, used to
create a fill_item
* src/item-grid.c (item_grid_event): Use the proper cursor
depending on the sheet mode.
* src/sheet-object.c (object_event): Set the cursor to the arrow.
(object_handle_event): Same.
* src/cursors.h (cursor_set_widget, cursor_set): New macros to
access easily the gnumeric cursors.
1998-09-14 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/cursors.c: Define the Gnumeric cursors here.
......
1998-09-16 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_item_new): We now have a working
implementation of the Autofill feature.
1998-09-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_range_new): New routine, used to
create a fill_item
* src/item-grid.c (item_grid_event): Use the proper cursor
depending on the sheet mode.
* src/sheet-object.c (object_event): Set the cursor to the arrow.
(object_handle_event): Same.
* src/cursors.h (cursor_set_widget, cursor_set): New macros to
access easily the gnumeric cursors.
1998-09-14 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/cursors.c: Define the Gnumeric cursors here.
......
1998-09-16 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_item_new): We now have a working
implementation of the Autofill feature.
1998-09-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/sheet-autofill.c (fill_range_new): New routine, used to
create a fill_item
* src/item-grid.c (item_grid_event): Use the proper cursor
depending on the sheet mode.
* src/sheet-object.c (object_event): Set the cursor to the arrow.
(object_handle_event): Same.
* src/cursors.h (cursor_set_widget, cursor_set): New macros to
access easily the gnumeric cursors.
1998-09-14 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/cursors.c: Define the Gnumeric cursors here.
......
......@@ -97,8 +97,6 @@ cell_set_halign (Cell *cell, StyleHAlignFlags halign)
void
cell_set_font_from_style (Cell *cell, StyleFont *style_font)
{
GdkFont *font;
g_return_if_fail (cell != NULL);
g_return_if_fail (style_font != NULL);
......@@ -109,8 +107,6 @@ cell_set_font_from_style (Cell *cell, StyleFont *style_font)
cell->style->font = style_font;
font = style_font->font;
cell_calc_dimensions (cell);
cell_queue_redraw (cell);
......@@ -874,6 +870,7 @@ cell_draw (Cell *cell, void *sv, GdkGC *gc, GdkDrawable *drawable, int x1, int y
rect.height = cell->height;
rect.width = cell->width;
gdk_gc_set_clip_rectangle (gc, &rect);
printf ("Cliping to: %d %d %d %d\n", x1, y1, cell->height, cell->width);
switch (style->valign){
case VALIGN_TOP:
......
......@@ -86,3 +86,4 @@ cursors_shutdown (void)
for (i = 0; gnumeric_cursors [i].hot_x; i++)
gdk_cursor_destroy (gnumeric_cursors [0].cursor);
}
......@@ -13,6 +13,13 @@ typedef struct {
extern GnumericCursorDef gnumeric_cursors [];
void cursors_init (void);
void cursors_shutdown (void);
void cursors_init (void);
void cursors_shutdown (void);
#define cursor_set(win,c) \
gdk_window_set_cursor (win, gnumeric_cursors [c].cursor)
#define cursor_set_widget(w,c) \
gdk_window_set_cursor (GTK_WIDGET (w)->window, gnumeric_cursors [c].cursor)
#endif
......@@ -436,7 +436,7 @@ workbook_recalc (Workbook *wb)
workbook_next_generation (wb);
generation = wb->generation;
while ((cell = pick_next_cell_from_queue (wb))){
cell->generation = generation;
cell_eval (cell);
......
......@@ -436,7 +436,7 @@ workbook_recalc (Workbook *wb)
workbook_next_generation (wb);
generation = wb->generation;
while ((cell = pick_next_cell_from_queue (wb))){
cell->generation = generation;
cell_eval (cell);
......
......@@ -739,7 +739,7 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
cell = sheet_cell_get (sheet, col, row);
if (cell && cell->value){
if (cell){
if (cell->parsed_node && cell->generation != sheet->workbook->generation){
cell->generation = sheet->workbook->generation;
cell_eval (cell);
......
......@@ -24,8 +24,7 @@ typedef enum {
} Operation;
typedef enum {
VALUE_UNKNOWN = -1,
VALUE_STRING = 0,
VALUE_STRING,
VALUE_INTEGER,
VALUE_FLOAT,
VALUE_CELLRANGE,
......
......@@ -815,7 +815,7 @@ gnumeric_sheet_realize (GtkWidget *widget)
gsheet->patterns [i] = gdk_bitmap_create_from_data (
window, gnumeric_sheet_patterns [i].pattern, 8, 8);
gdk_window_set_cursor (window, gnumeric_cursors [GNUMERIC_CURSOR_FAT_CROSS].cursor);
cursor_set (window, GNUMERIC_CURSOR_FAT_CROSS);
}
void
......
......@@ -815,7 +815,7 @@ gnumeric_sheet_realize (GtkWidget *widget)
gsheet->patterns [i] = gdk_bitmap_create_from_data (
window, gnumeric_sheet_patterns [i].pattern, 8, 8);
gdk_window_set_cursor (window, gnumeric_cursors [GNUMERIC_CURSOR_FAT_CROSS].cursor);
cursor_set (window, GNUMERIC_CURSOR_FAT_CROSS);
}
void
......
......@@ -17,6 +17,7 @@
#include "gnumeric-util.h"
#include "color.h"
#include "cursors.h"
#include "sheet-autofill.h"
static GnomeCanvasItem *item_cursor_parent_class;
......@@ -382,7 +383,7 @@ item_cursor_setup_auto_fill (ItemCursor *item_cursor, ItemCursor *parent, int x,
}
static void
item_cursor_set_cursor (GdkWindow *window, GnomeCanvasItem *item, int x, int y)
item_cursor_set_cursor (GnomeCanvas *canvas, GnomeCanvasItem *item, int x, int y)
{
int cursor;
......@@ -390,8 +391,8 @@ item_cursor_set_cursor (GdkWindow *window, GnomeCanvasItem *item, int x, int y)
cursor = GNUMERIC_CURSOR_THIN_CROSS;
else
cursor = GNUMERIC_CURSOR_ARROW;
gdk_window_set_cursor (window, gnumeric_cursors [cursor].cursor);
cursor_set_widget (canvas, cursor);
}
static gint
......@@ -407,14 +408,14 @@ item_cursor_selection_event (GnomeCanvasItem *item, GdkEvent *event)
gnome_canvas_w2c (
canvas, event->crossing.x, event->crossing.y, &x, &y);
item_cursor_set_cursor (GTK_WIDGET (canvas)->window, item, x, y);
item_cursor_set_cursor (canvas, item, x, y);
return TRUE;
case GDK_MOTION_NOTIFY:
gnome_canvas_w2c (
canvas, event->motion.x, event->motion.y, &x, &y);
item_cursor_set_cursor (GTK_WIDGET (canvas)->window, item, x, y);
item_cursor_set_cursor (canvas, item, x, y);
return TRUE;
case GDK_BUTTON_PRESS: {
......@@ -646,15 +647,28 @@ item_cursor_autofill_event (GnomeCanvasItem *item, GdkEvent *event)
switch (event->type){
case GDK_BUTTON_RELEASE: {
Sheet *sheet = item_cursor->sheet;
gnome_canvas_item_ungrab (item, event->button.time);
g_warning ("Temporary flush after ungrap here\n");
gnome_canvas_update_now (canvas);
gdk_flush ();
if (!((item_cursor->end_col == item_cursor->base_col + item_cursor->base_cols) &&
(item_cursor->end_row == item_cursor->base_row + item_cursor->base_rows)))
sheet_autofill (sheet,
item_cursor->base_col, item_cursor->base_row,
item_cursor->base_cols+1, item_cursor->base_rows+1,
item_cursor->end_col, item_cursor->end_row);
sheet_cursor_set (sheet,
item_cursor->base_col, item_cursor->base_row,
item_cursor->end_col, item_cursor->end_row);
sheet_selection_reset_only (sheet);
sheet_selection_append (sheet, item_cursor->base_col, item_cursor->base_row);
sheet_selection_extend_to (sheet, item_cursor->end_col, item_cursor->end_row);
gtk_object_destroy (GTK_OBJECT (item));
return TRUE;
......
......@@ -560,11 +560,17 @@ item_grid_event (GnomeCanvasItem *item, GdkEvent *event)
int scroll_x, scroll_y;
switch (event->type){
case GDK_ENTER_NOTIFY:
gdk_window_set_cursor (
GTK_WIDGET (canvas)->window,
gnumeric_cursors [GNUMERIC_CURSOR_FAT_CROSS].cursor);
case GDK_ENTER_NOTIFY: {
int cursor;
if (sheet->mode == SHEET_MODE_SHEET)
cursor = GNUMERIC_CURSOR_FAT_CROSS;
else
cursor = GNUMERIC_CURSOR_ARROW;
cursor_set_widget (canvas, cursor);
return TRUE;
}
case GDK_BUTTON_RELEASE:
if (event->button.button == 1){
......
......@@ -49,7 +49,6 @@ main (int argc, char *argv [])
symbol_init ();
constants_init ();
functions_init ();
autofill_init ();
plugins_init ();
if (startup_file)
......
......@@ -49,7 +49,6 @@ main (int argc, char *argv [])
symbol_init ();
constants_init ();
functions_init ();
autofill_init ();
plugins_init ();
if (startup_file)
......
......@@ -3,6 +3,14 @@
*
* Author:
* Miguel de Icaza (miguel@kernel.org), 1998
*
* This is more complex than it would look at first sight,
* as we have to support autofilling of mixed data and
* we have to do the filling accordingly.
*
* The idea is that the autofill routines first classify
* the source cells into different types and the deltas
* are computed on a per-group basis.
*/
#include <config.h>
......@@ -10,85 +18,486 @@
#include "gnumeric.h"
#include "sheet-autofill.h"
static void
sheet_autofill_dir (Sheet *sheet,
int base_col, int base_row,
int region_count,
int start_pos, int end_pos,
int col_inc, int row_inc)
{
ValueType last_value_type = VALUE_UNKNOWN;
int x = base_col;
int y = base_row;
int i, pos, fill_start;
int region_types = 0;
Value **values;
typedef enum {
values = g_new (Value *, region_count);
/*
* FILL_INVALID: Should never happen, used only as a flag
*/
FILL_INVALID,
printf ("region_count=%d\n", region_count);
fill_start = start_pos;
/*
* FILL_EMPTY: Cell is empty
*/
FILL_EMPTY,
/*
* FILL_STRING_CONSTANT: We could not figure any
* method of autoincrement, just duplicate this constant
*/
FILL_STRING_CONSTANT,
/*
* FILL_STRING_WITH_NUMBER: The string contains a number
* that is in a position where we can auto-increment.
*/
FILL_STRING_WITH_NUMBER,
/*
* FILL_STRING_LIST: The string matches a component in
* one of the autofill string lists.
*/
FILL_STRING_LIST,
/*
* FILL_NUMBER: We are dealing with a number
*/
FILL_NUMBER,
/*
* Count the number of different region types we have
*
* We need this to deal with regions that have numbers and strings
* and apply an autofill function depending on it.
* FILL_FORMULA: This is a formula
*/
FILL_FORMULA
} FillType;
struct FillItem {
FillType type;
union {
ExprTree *formula;
Value *value;
String *str;
struct {
GList *list;
int num;
} list;
struct {
String *str;
int pos, num;
} numstr;
} v;
int delta_is_float;
union {
double d_float;
int d_int;
} delta;
struct FillItem *group_last;
};
typedef struct FillItem FillItem;
typedef struct {
int count;
char **items;
} AutoFillList;
static GList *autofill_lists;
void
autofill_register_list (char **list)
{
AutoFillList *afl;
char **p = list;
while (*p)
p++;
afl = g_new (AutoFillList, 1);
afl->count = p - list;
afl->items = list;
autofill_lists = g_list_prepend (autofill_lists, afl);
}
static GList *
matches_list (String *str, int *n)
{
return NULL;
}
static int
string_has_number (String *str, int *num, int *pos)
{
return FALSE;
}
static void
fill_item_destroy (FillItem *fi)
{
switch (fi->type){
case FILL_STRING_LIST:
case FILL_STRING_CONSTANT:
string_unref (fi->v.str);
break;
case FILL_STRING_WITH_NUMBER:
string_unref (fi->v.numstr.str);
break;
default:
}
g_free (fi);
}
static FillItem *
fill_item_new (Cell *cell)
{
Value *value = cell->value;
ValueType value_type = value->type;
FillItem *fi;
fi = g_new (FillItem, 1);
fi->type = FILL_EMPTY;
if (!cell)
return fi;
if (CELL_IS_FORMULA (cell)){
fi->type = FILL_FORMULA;
fi->v.formula = cell->parsed_node;
return fi;
}
if (value_type == VALUE_INTEGER || value_type == VALUE_FLOAT){
fi->type = FILL_NUMBER;
fi->v.value = value;
return fi;
}
if (value_type == VALUE_STRING){
void *list;
int num, pos;
fi->type = FILL_STRING_CONSTANT;
fi->v.str = string_ref (value->v.str);
list = matches_list (value->v.str, &num);
if (list){
fi->type = FILL_STRING_LIST;
fi->v.list.list = list;
fi->v.list.num = num;
return fi;
}
if (string_has_number (value->v.str, &num, &pos)){
fi->type = FILL_STRING_WITH_NUMBER;
fi->v.numstr.str = value->v.str;
fi->v.numstr.num = num;
fi->v.numstr.pos = pos;
}
}
return fi;
}
/*
* Computes the delta for the items of the same type in fill_item_list
* and stores the delta result in the last element (we get this as
* the parameter last
*/
static void
autofill_compute_delta (GList *list_last, GList *fill_item_list)
{
FillItem *fi = list_last->data;
FillItem *lfi;
switch (fi->type){
case FILL_NUMBER: {
double a, b;
if (!list_last->prev){
if (fi->v.value->type == VALUE_INTEGER){
fi->delta_is_float = FALSE;
fi->delta.d_int = 1;
} else {
fi->delta_is_float = TRUE;
fi->delta.d_float = 1.0;
}
return;
}
lfi = list_last->prev->data;
if (fi->v.value->type == VALUE_INTEGER && lfi->v.value->type == VALUE_INTEGER){
fi->delta_is_float = FALSE;
fi->delta.d_int = fi->v.value->v.v_int - lfi->v.value->v.v_int;
return;
}
a = value_get_as_double (lfi->v.value);
b = value_get_as_double (fi->v.value);
fi->delta_is_float = TRUE;
fi->delta.d_float = b - a;
return;
}
case FILL_STRING_WITH_NUMBER:
fi->delta_is_float = FALSE;
fi->delta.d_int = 1;
if (list_last->prev){
lfi = list_last->prev->data;
fi->delta.d_int = lfi->v.numstr.num - fi->v.numstr.num;
}
return;
case FILL_EMPTY:
case FILL_STRING_CONSTANT:
case FILL_FORMULA:
case FILL_INVALID:
case FILL_STRING_LIST:
return;
}
}
static GList *
autofill_create_fill_items (Sheet *sheet, int x, int y, int region_count, int col_inc, int row_inc)
{
FillType last_type;
GList *item_list, *all_items, *l;
int i;
last_type = FILL_INVALID;
item_list = all_items = NULL;
for (i = 0; i < region_count; i++){
FillItem *fi;
Cell *cell;
fill_start++;
cell = sheet_cell_get (sheet, x, y);
if (cell)
values [i] = cell->value;
else
values [i] = NULL;
fi = fill_item_new (cell);
if (fi->type != last_type){
if (last_type != FILL_INVALID){
all_items = g_list_append (all_items, item_list);
item_list = NULL;
}