Commit 6a895d14 authored by Arturo Espinosa's avatar Arturo Espinosa

Paste special dialog box. Expression tree decoder (required for copy



Paste special dialog box.
Expression tree decoder (required for copy paste).
Selection walking works properly just like in Excel.
parent 7e63f4fc
......@@ -3,22 +3,6 @@
#include "gnumeric.h"
#include "eval.h"
static void
cell_formula_link (Cell *cell)
{
Sheet *sheet = cell->sheet;
sheet->formula_cell_list = g_list_prepend (sheet->formula_cell_list, cell);
}
static void
cell_formula_unlink (Cell *cell)
{
Sheet *sheet = cell->sheet;
sheet->formula_cell_list = g_list_remove (sheet->formula_cell_list, cell);
}
void
cell_set_formula (Cell *cell, char *text)
{
......@@ -38,7 +22,7 @@ cell_set_formula (Cell *cell, char *text)
return;
}
cell_formula_link (cell);
sheet_cell_formula_link (cell);
cell_add_dependencies (cell);
cell_queue_recalc (cell);
}
......@@ -76,7 +60,7 @@ cell_set_text (Cell *cell, char *text)
if (cell->parsed_node){
cell_drop_dependencies (cell);
cell_formula_unlink (cell);
sheet_cell_formula_unlink (cell);
expr_tree_unref (cell->parsed_node);
cell->parsed_node = NULL;
......@@ -172,7 +156,6 @@ cell_destroy (Cell *cell)
g_return_if_fail (cell != NULL);
if (cell->parsed_node){
cell_formula_unlink (cell);
expr_tree_unref (cell->parsed_node);
}
......
......@@ -100,9 +100,27 @@ clipboard_paste_region (CellRegion *region, Sheet *dest_sheet, int dest_col, int
new_cell = cell_copy (c_copy->cell);
sheet_cell_add (dest_sheet, new_cell, target_col, target_row);
if (new_cell->parsed_node)
if (new_cell->parsed_node){
char *new_text, *formula;
string_unref (new_cell->entered_text);
new_text = expr_decode_tree (
new_cell->parsed_node,
target_col, target_row);
formula = g_copy_strings ("=", new_text, NULL);
new_cell->entered_text = string_get (formula);
g_free (formula);
g_free (new_text);
cell_queue_recalc (new_cell);
}
}
sheet_redraw_cell_region (dest_sheet,
dest_col, dest_row,
dest_col + region->cols - 1,
dest_row + region->rows - 1);
}
void
......@@ -123,3 +141,96 @@ clipboard_release (CellRegion *region)
g_list_free (region->list);
g_free (region);
}
static struct {
char *name;
int disables_second_group;
} paste_types [] = {
{ N_("All"), 0 },
{ N_("Formulas"), 0 },
{ N_("Values"), 0 },
{ N_("Formats"), 1 },
{ NULL, 0 }
};
static char *paste_ops [] = {
N_("None"),
N_("Add"),
N_("Substract"),
N_("Multiply"),
N_("Divide"),
NULL
};
static void
disable_op_group (GtkWidget *widget, GtkWidget *group)
{
gtk_widget_set_sensitive (group, FALSE);
}
static void
enable_op_group (GtkWidget *widget, GtkWidget *group)
{
gtk_widget_set_sensitive (group, TRUE);
}
int
dialog_paste_special (void)
{
GtkWidget *dialog, *hbox;
GtkWidget *f1, *f1v, *f2, *f2v;
GSList *group;
int i;
dialog = gnome_dialog_new (_("Paste special"),
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL,
NULL);
f1 = gtk_frame_new (_("Paste type"));
f1v = gtk_vbox_new (TRUE, 0);
gtk_container_add (GTK_CONTAINER (f1), f1v);
f2 = gtk_frame_new (_("Operation"));
f2v = gtk_vbox_new (TRUE, 0);
gtk_container_add (GTK_CONTAINER (f2), f2v);
group = NULL;
for (i = 0; paste_types [i].name; i++){
GtkSignalFunc func;
GtkWidget *r;
if (paste_types [i].disables_second_group)
func = GTK_SIGNAL_FUNC (disable_op_group);
else
func = GTK_SIGNAL_FUNC (enable_op_group);
r = gtk_radio_button_new_with_label (group, _(paste_types [i].name));
group = GTK_RADIO_BUTTON (r)->group;
gtk_signal_connect (GTK_OBJECT (r), "toggled", func, f2);
gtk_box_pack_start_defaults (GTK_BOX (f1v), r);
}
group = NULL;
for (i = 0; paste_ops [i]; i++){
GtkWidget *r;
r = gtk_radio_button_new_with_label (group, _(paste_ops [i]));
group = GTK_RADIO_BUTTON (r)->group;
gtk_box_pack_start_defaults (GTK_BOX (f2v), r);
}
hbox = gtk_hbox_new (TRUE, 0);
gtk_box_pack_start_defaults (GTK_BOX (hbox), f1);
gtk_box_pack_start_defaults (GTK_BOX (hbox), f2);
gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show_all (hbox);
gnome_dialog_run_modal (GNOME_DIALOG (dialog));
gtk_object_destroy (GTK_OBJECT (dialog));
return 0;
}
......@@ -27,4 +27,7 @@ void clipboard_paste_region (CellRegion *region,
int paste_flags);
void clipboard_release (CellRegion *region);
int dialog_paste_special (void);
#endif
......@@ -731,3 +731,129 @@ cell_get_abs_col_row (CellRef *cell_ref, int eval_col, int eval_row, int *col, i
*row = cell_ref->row;
}
/*
* Converts a parsed tree into its string representation
* assuming that we are evaluating at col, row (This is
* only used during copying to "render" a new text
* representation for a copied cell.
*
* This routine is pretty simple: it walks the ExprTree and
* create a string representation.
*/
char *
expr_decode_tree (ExprTree *tree, int col, int row)
{
static const char *binary_operation_names [] = {
"=", ">", "<", ">=", "<=", "<>",
"+", "-", "*", "/", "^", "&"
};
g_return_val_if_fail (tree != NULL, NULL);
switch (tree->oper){
/* The binary operations */
case OP_EQUAL:
case OP_NOT_EQUAL:
case OP_GT:
case OP_GTE:
case OP_LT:
case OP_LTE:
case OP_ADD:
case OP_SUB:
case OP_MULT:
case OP_DIV:
case OP_EXP:
case OP_CONCAT: {
char *a, *b, *res;
char const *op;
a = expr_decode_tree (tree->u.binary.value_a, col, row);
b = expr_decode_tree (tree->u.binary.value_b, col, row);
op = binary_operation_names [tree->oper];
res = g_copy_strings ("(", a, op, b, ")", NULL);
g_free (a);
g_free (b);
return res;
}
case OP_NEG: {
char *res, *a;
a = expr_decode_tree (tree->u.value, col, row);
res = g_copy_strings ("-", a);
g_free (a);
return res;
}
case OP_FUNCALL: {
FunctionDefinition *fd;
GList *arg_list, *l;
char *res, *sum;
char **args;
int argc;
fd = tree->u.function.symbol->data;
arg_list = tree->u.function.arg_list;
argc = g_list_length (arg_list);
if (argc){
int i, len = 0;
args = g_malloc (sizeof (char *) * argc);
i = 0;
for (l = arg_list; l; l = l->next){
ExprTree *t = l->data;
args [i] = expr_decode_tree (t, col, row);
len += strlen (args [i]) + 1;
}
len++;
sum = g_malloc (len + 1);
i = 0;
sum [0] = 0;
for (l = arg_list; l; l = l->next)
strcat (sum, args [i]);
res = g_copy_strings (
fd->name, "(", sum, ")", NULL);
for (i = 0; i < argc; i++)
g_free (args [i]);
g_free (args);
return res;
} else
return g_copy_strings (fd->name, "()", NULL);
}
case OP_CONSTANT: {
Value *v = tree->u.constant;
if (v->type == VALUE_CELLRANGE){
char buffer_a [20], buffer_b [20], *a;
a = cellref_name (&v->v.cell_range.cell_a, col, row);
strcpy (buffer_a, a);
a = cellref_name (&v->v.cell_range.cell_b, col, row);
strcpy (buffer_b, a);
return g_copy_strings (buffer_a, ":", buffer_b, NULL);
} else
return value_string (v);
}
case OP_VAR: {
CellRef *cell_ref;
cell_ref = &tree->u.constant->v.cell;
return g_strdup (cellref_name (cell_ref, col, row));
}
}
g_warning ("ExprTree: This should not happen\n");
return g_strdup ("0");
}
......@@ -138,6 +138,8 @@ extern int parser_col, parser_row;
void cell_get_abs_col_row (CellRef *cell_ref, int eval_col, int eval_row, int *col, int *row);
ExprTree *expr_parse_string (char *expr, int col, int row, char **error_msg);
char *expr_decode_tree (ExprTree *tree, int col, int row);
void expr_tree_ref (ExprTree *tree);
void expr_tree_unref (ExprTree *tree);
......@@ -147,7 +149,7 @@ void eval_expr_release (ExprTree *tree);
Value *eval_expr (void *asheet, ExprTree *tree,
int col, int row,
char **error_string);
void value_release (Value *value);
Value *value_cast_to_float (Value *v);
int value_get_bool (Value *v, int *err);
......
......@@ -82,3 +82,38 @@ cell_name (int col, int row)
return buffer;
}
char *
cellref_name (CellRef *cell_ref, int eval_col, int eval_row)
{
static char buffer [20];
char *p = buffer;
int col, row;
if (cell_ref->col_relative)
col = eval_col + cell_ref->col;
else {
*p++ = '$';
col = cell_ref->col;
}
if (col < 'Z'-'A'){
*p++ = col + 'A';
} else {
int a = col / ('Z'-'A');
int b = col % ('Z'-'A');
*p++ = a + 'A';
*p++ = b + 'A';
}
if (cell_ref->row_relative)
row = eval_row + cell_ref->row;
else {
*p++ = '$';
row = cell_ref->row;
}
sprintf (p, "%d", row+1);
return buffer;
}
......@@ -2,8 +2,9 @@
#define G_UTILS_H
/* Gets an integer in the buffer in start to end */
void int_get_from_range (char *start, char *end, int_t *t);
void int_get_from_range (char *start, char *end, int_t *t);
void float_get_from_range (char *start, char *end, float_t *t);
char *cell_name (int col, int row);
char *cell_name (int col, int row);
char *cellref_name (CellRef *cell_ref, int eval_col, int eval_row);
#endif
......@@ -629,7 +629,6 @@ value_string (Value *value)
break;
case VALUE_CELLRANGE:
g_warning ("Cellrange on a value!");
return g_strdup ("Internal problem");
}
return g_strdup (buffer);
......
......@@ -1118,11 +1118,10 @@ walk_boundaries (int lower_col, int lower_row,
int upper_col, int upper_row,
int inc_x, int inc_y,
int current_col, int current_row,
int *new_col, int *new_row,
int wrap)
int *new_col, int *new_row)
{
if (current_row + inc_y == upper_row ||
current_col + inc_x == upper_col){
if (current_row + inc_y > upper_row ||
current_col + inc_x > upper_col){
*new_row = current_row;
*new_col = current_col;
return TRUE;
......@@ -1140,13 +1139,72 @@ walk_boundaries (int lower_col, int lower_row,
return FALSE;
}
/*
* walk_boundaries: implements the decitions for walking a region
* returns TRUE if the cursor left the boundary region. This
* version implements wrapping on the regions.
*/
static int
walk_boundaries_wrapped (int lower_col, int lower_row,
int upper_col, int upper_row,
int inc_x, int inc_y,
int current_col, int current_row,
int *new_col, int *new_row)
{
if (current_row + inc_y > upper_row){
if (current_col + 1 > upper_col)
goto overflow;
*new_row = lower_row;
*new_col = current_col + 1;
return FALSE;
}
if (current_row + inc_y < lower_row){
if (current_col - 1 < lower_col)
goto overflow;
*new_row = upper_row;
*new_col = current_col - 1;
return FALSE;
}
if (current_col + inc_x > upper_col){
if (current_row + 1 > upper_row)
goto overflow;
*new_row = current_row + 1;
*new_col = lower_col;
return FALSE;
}
if (current_col + inc_x < lower_col){
if (current_row - 1 < lower_row)
goto overflow;
*new_row = current_row - 1;
*new_col = upper_col;
return FALSE;
}
*new_row = current_row + inc_y;
*new_col = current_col + inc_x;
return FALSE;
overflow:
*new_row = current_row;
*new_col = current_col;
return TRUE;
}
int
sheet_selection_walk_step (Sheet *sheet, int forward, int horizontal,
int current_col, int current_row,
int *new_col, int *new_row)
{
int inc_x = 0, inc_y = 0, diff, overflow;
SheetSelection *ss;
int inc_x = 0, inc_y = 0;
int selections_count, diff, overflow;;
diff = forward ? 1 : -1;
if (horizontal)
......@@ -1154,14 +1212,16 @@ sheet_selection_walk_step (Sheet *sheet, int forward, int horizontal,
else
inc_y = diff;
if (g_list_length (sheet->selections) == 1){
SheetSelection *ss = sheet->selections->data;
selections_count = g_list_length (sheet->selections);
if (selections_count == 1){
ss = sheet->selections->data;
/* If there is no selection besides the cursor, plain movement */
if (ss->start_col == ss->end_col && ss->start_row == ss->end_row){
walk_boundaries (0, 0, SHEET_MAX_COLS, SHEET_MAX_ROWS,
inc_x, inc_y, current_col, current_row,
new_col, new_row, FALSE);
new_col, new_row);
return FALSE;
}
}
......@@ -1169,30 +1229,35 @@ sheet_selection_walk_step (Sheet *sheet, int forward, int horizontal,
if (!sheet->walk_info.current)
sheet->walk_info.current = sheet->selections->data;
do {
SheetSelection *ss = sheet->walk_info.current;
overflow = walk_boundaries (ss->start_col, ss->start_row,
ss->end_col, ss->end_row,
inc_x, inc_y, current_col, current_row,
new_col, new_row, TRUE);
if (overflow){
GList *l = sheet->selections;
for (; l; l = l->next){
if (l->data != sheet->walk_info.current)
continue;
l = l->next;
sheet->walk_info.current =
l ? l->data : sheet->selections->data;
*new_col = ss->start_col;
*new_row = ss->start_row;
return TRUE;
}
ss = sheet->walk_info.current;
overflow = walk_boundaries_wrapped (
ss->start_col, ss->start_row,
ss->end_col, ss->end_row,
inc_x, inc_y, current_col, current_row,
new_col, new_row);
if (overflow){
int p;
p = g_list_index (sheet->selections, ss);
p += diff;
if (p < 0)
p = selections_count - 1;
else if (p == selections_count)
p = 0;
ss = g_list_nth (sheet->selections, p)->data;
sheet->walk_info.current = ss;
if (forward){
*new_col = ss->start_col;
*new_row = ss->start_row;
} else {
*new_col = ss->end_col;
*new_row = ss->end_row;
}
} while (overflow);
}
return TRUE;
}
......@@ -1442,7 +1507,10 @@ sheet_cell_remove (Sheet *sheet, Cell *cell)
cellref.col = cell->col->pos;
cellref.row = cell->row->pos;
if (cell->parsed_node)
sheet_cell_formula_unlink (cell);
g_hash_table_remove (sheet->cell_hash, &cellref);
cell->col->data = g_list_remove (cell->col->data, cell);
......@@ -1451,6 +1519,22 @@ sheet_cell_remove (Sheet *sheet, Cell *cell)
cellref.col, cellref.row);
}
void
sheet_cell_formula_link (Cell *cell)
{
Sheet *sheet = cell->sheet;
sheet->formula_cell_list = g_list_prepend (sheet->formula_cell_list, cell);
}
void
sheet_cell_formula_unlink (Cell *cell)
{
Sheet *sheet = cell->sheet;
sheet->formula_cell_list = g_list_remove (sheet->formula_cell_list, cell);
}
static int
assemble_cell (Sheet *sheet, int col, int row, Cell *cell, void *user_data)
{
......
......@@ -144,6 +144,8 @@ int sheet_cell_foreach_range (Sheet *sheet, int only_existing,
sheet_cell_foreach_callback callback,
void *closure);
Cell *sheet_cell_get (Sheet *sheet, int col, int row);
void sheet_cell_formula_link (Cell *cell);
void sheet_cell_formula_unlink (Cell *cell);
/* Create new ColRowInfos from the default sheet style */
ColRowInfo *sheet_col_new (Sheet *sheet);
......
......@@ -82,3 +82,38 @@ cell_name (int col, int row)
return buffer;
}
char *
cellref_name (CellRef *cell_ref, int eval_col, int eval_row)
{
static char buffer [20];
char *p = buffer;
int col, row;
if (cell_ref->col_relative)
col = eval_col + cell_ref->col;
else {
*p++ = '$';
col = cell_ref->col;
}
if (col < 'Z'-'A'){
*p++ = col + 'A';
} else {
int a = col / ('Z'-'A');
int b = col % ('Z'-'A');
*p++ = a + 'A';
*p++ = b + 'A';
}
if (cell_ref->row_relative)
row = eval_row + cell_ref->row;
else {
*p++ = '$';
row = cell_ref->row;
}
sprintf (p, "%d", row+1);
return buffer;
}
......@@ -2,8 +2,9 @@
#define G_UTILS_H
/* Gets an integer in the buffer in start to end */
void int_get_from_range (char *start, char *end, int_t *t);
void int_get_from_range (char *start, char *end, int_t *t);
void float_get_from_range (char *start, char *end, float_t *t);
char *cell_name (int col, int row);
char *cell_name (int col, int row);
char *cellref_name (CellRef *cell_ref, int eval_col, int eval_row);
#endif
......@@ -58,6 +58,7 @@ cut_cmd (GtkWidget *widget, Workbook *wb)
static void
paste_special_cmd (GtkWidget *widget, Workbook *wb)
{
dialog_paste_special ();
}
static GnomeUIInfo workbook_menu_file [] = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment