clipboard.c 5.95 KB
Newer Older
Arturo Espinosa's avatar
Arturo Espinosa committed
1 2 3 4 5 6 7 8 9 10
/*
 * Clipboard.c: Implements the copy/paste operations
 *
 * Author:
 *  MIguel de Icaza (miguel@gnu.org)
 *
 */
#include <config.h>
#include <gnome.h>
#include "gnumeric.h"
11
#include "gnumeric-util.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
12
#include "clipboard.h"
13
#include "eval.h"
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
#include "render-ascii.h"

static gint
x_selection_clear (GtkWidget *widget, GdkEventSelection *event, Workbook *wb)
{
	wb->have_x_selection = FALSE;

	return TRUE;
}

static void
x_selection_handler (GtkWidget *widget, GtkSelectionData *selection_data, gpointer data)
{
	Workbook *wb = data;
	char *rendered_selection;
	
	g_assert (wb->clipboard_contents);

	rendered_selection = cell_region_render_ascii (wb->clipboard_contents);
	
	gtk_selection_data_set (
		selection_data, GDK_SELECTION_TYPE_STRING, 8,
		rendered_selection, strlen (rendered_selection));
}

void
x_clipboard_bind_workbook (Workbook *wb)
{
	wb->have_x_selection = FALSE;
	
	gtk_signal_connect (
		GTK_OBJECT (wb->toplevel), "selection_clear_event",
		GTK_SIGNAL_FUNC(x_selection_clear), wb);

	gtk_selection_add_handler (
		wb->toplevel,
		GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING,
		x_selection_handler, wb);
}

/*
 * clipboard_export_cell_region:
 *
 * This routine exports a CellRegion to the X selection
 */
static void
clipboard_export_cell_region (Workbook *wb, CellRegion *region)
{
	wb->have_x_selection = gtk_selection_owner_set (
		current_workbook->toplevel,
		GDK_SELECTION_PRIMARY,
		GDK_CURRENT_TIME);
}
Arturo Espinosa's avatar
Arturo Espinosa committed
67 68 69 70 71 72

typedef struct {
	int        base_col, base_row;
	CellRegion *r;
} append_cell_closure_t;

73
static int
Arturo Espinosa's avatar
Arturo Espinosa committed
74 75 76 77 78 79 80 81 82
clipboard_append_cell (Sheet *sheet, int col, int row, Cell *cell, void *user_data)
{
	append_cell_closure_t *c = user_data;
	CellCopy *copy;

	copy = g_new (CellCopy, 1);

	copy->cell = cell_copy (cell);
	copy->col_offset  = col - c->base_col;
83
	copy->row_offset  = row - c->base_row;
Arturo Espinosa's avatar
Arturo Espinosa committed
84 85 86 87 88 89 90 91 92 93 94
	
	/* Now clear the traces and dependencies on the copied Cell */
	copy->cell->col   = NULL;
	copy->cell->row   = NULL;
	copy->cell->sheet = NULL;
	
	c->r->list = g_list_prepend (c->r->list, copy);

	return TRUE;
}

95 96 97 98 99
/*
 * clipboard_copy_cell_range:
 *
 * Entry point to the clipboard copy code
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
100 101 102 103
CellRegion *
clipboard_copy_cell_range (Sheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
	append_cell_closure_t c;
104 105
	GtkEditable *editable;
	
106 107 108 109
	g_return_val_if_fail (sheet != NULL, NULL);
	g_return_val_if_fail (IS_SHEET (sheet), NULL);
	g_return_val_if_fail (start_col <= end_col, NULL);
	g_return_val_if_fail (start_row <= end_row, NULL);
110 111 112 113

	if (!editable){
		editable = GTK_EDITABLE (gtk_type_new (gtk_editable_get_type ()));
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
114
	
115
	c.r = g_new0 (CellRegion, 1);
Arturo Espinosa's avatar
Arturo Espinosa committed
116 117 118

	c.base_col = start_col;
	c.base_row = start_row;
119 120
	c.r->cols = end_col - start_col + 1;
	c.r->rows = end_row - start_row + 1;
Arturo Espinosa's avatar
Arturo Espinosa committed
121 122 123
	
	sheet_cell_foreach_range (
		sheet, 1, start_col, start_row, end_col, end_row,
124 125
		clipboard_append_cell, &c);

126 127
	clipboard_export_cell_region (sheet->workbook, c.r);
	
128
	return c.r;
Arturo Espinosa's avatar
Arturo Espinosa committed
129 130
}

Arturo Espinosa's avatar
Arturo Espinosa committed
131 132 133 134
static int
paste_cell (Sheet *dest_sheet, Cell *new_cell, int target_col, int target_row, int paste_flags)
{
	sheet_cell_add (dest_sheet, new_cell, target_col, target_row);
Miguel de Icaza's avatar
Miguel de Icaza committed
135
	
Arturo Espinosa's avatar
Arturo Espinosa committed
136 137 138 139 140 141 142 143
	if (!(paste_flags & PASTE_FORMULAS)){
		if (new_cell->parsed_node){
			expr_tree_unref (new_cell->parsed_node);
			new_cell->parsed_node = NULL;
		}
	}
	
	if (new_cell->parsed_node){
Arturo Espinosa's avatar
Arturo Espinosa committed
144 145 146 147
		if (paste_flags & PASTE_FORMULAS)
			cell_formula_relocate (new_cell, target_col, target_row);
		else 
			cell_make_value (new_cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
148
	}
Miguel de Icaza's avatar
Miguel de Icaza committed
149 150

	cell_render_value (new_cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
151 152 153
	
	if (!(paste_flags & PASTE_FORMULAS)){
		string_unref (new_cell->entered_text);
Miguel de Icaza's avatar
Miguel de Icaza committed
154
		new_cell->entered_text = string_ref (new_cell->text);
Arturo Espinosa's avatar
Arturo Espinosa committed
155
	}
Miguel de Icaza's avatar
Miguel de Icaza committed
156

Arturo Espinosa's avatar
Arturo Espinosa committed
157 158 159 160 161 162 163
	sheet_redraw_cell_region (dest_sheet,
				  target_col, target_row,
				  target_col, target_row);

	return new_cell->parsed_node != 0;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
164
void
Arturo Espinosa's avatar
Arturo Espinosa committed
165 166 167 168
clipboard_paste_region (CellRegion *region, Sheet *dest_sheet,
			int dest_col,    int dest_row,
			int paste_width, int paste_height,
			int paste_flags)
Arturo Espinosa's avatar
Arturo Espinosa committed
169
{
170
	CellCopyList *l;
Arturo Espinosa's avatar
Arturo Espinosa committed
171
	GList *deps;
Arturo Espinosa's avatar
Arturo Espinosa committed
172
	int formulas = 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
173
	int col, row;
174
	
175 176 177 178 179
	g_return_if_fail (region != NULL);
	g_return_if_fail (dest_sheet != NULL);
	g_return_if_fail (IS_SHEET (dest_sheet));

	/* Clear the region where we will paste */
180 181 182 183 184
	if (paste_flags & (PASTE_VALUES | PASTE_FORMULAS))
		sheet_clear_region (dest_sheet,
				    dest_col, dest_row,
				    dest_col + paste_width - 1,
				    dest_row + paste_height - 1);
185

Arturo Espinosa's avatar
Arturo Espinosa committed
186 187 188 189
	/* If no operations are defined, we clear the area */
	if (!(paste_flags & PASTE_OP_MASK))
		sheet_redraw_cell_region (dest_sheet,
					  dest_col, dest_row,
Arturo Espinosa's avatar
Arturo Espinosa committed
190 191
					  dest_col + paste_width - 1,
					  dest_row + paste_height - 1);
192
	
193
	/* Paste each element */
Arturo Espinosa's avatar
Arturo Espinosa committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	for (col = 0; col < paste_width; col += region->cols){
		for (row = 0; row < paste_height; row += region->rows){
			for (l = region->list; l; l = l->next){
				CellCopy *c_copy = l->data;
				Cell *new_cell;
				int target_col, target_row;
				
				target_col = col + dest_col + c_copy->col_offset;
				target_row = row + dest_row + c_copy->row_offset;

				if (target_col > dest_col + paste_width - 1)
					continue;

				if (target_row > dest_row + paste_height - 1)
					continue;

210 211 212 213 214 215 216 217 218 219
				if (!(paste_flags & (PASTE_FORMULAS | PASTE_VALUES))){
					Cell *cell;
					
					cell = sheet_cell_get (dest_sheet,
							       target_col,
							       target_row);
					if (cell && c_copy->cell)
						cell_set_style (cell, c_copy->cell->style);
				} else {
					new_cell = cell_copy (c_copy->cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
220
				
221 222 223 224
					formulas |= paste_cell (
						dest_sheet, new_cell,
						target_col, target_row, paste_flags);
				}
Arturo Espinosa's avatar
Arturo Espinosa committed
225 226 227 228 229 230 231 232 233 234 235 236 237
			}
		}
	}
	
	deps = region_get_dependencies (
		dest_sheet,
		dest_col, dest_row,
		dest_col + paste_width - 1,
		dest_row + paste_height -1);

	if (deps){
		cell_queue_recalc_list (deps);
		formulas = 1;
238
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
239

Arturo Espinosa's avatar
Arturo Espinosa committed
240
	/* Trigger a recompute if required */
Arturo Espinosa's avatar
Arturo Espinosa committed
241 242
	if (formulas)
		workbook_recalc (dest_sheet->workbook);
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
}

void
clipboard_release (CellRegion *region)
{
	CellCopyList *l;

	g_return_if_fail (region != NULL);
	
	l = region->list;

	for (; l; l = l->next){
		CellCopy *this_cell = l->data;

		cell_destroy (this_cell->cell);
		g_free (this_cell);
	}
	g_list_free (region->list);
	g_free (region);
Arturo Espinosa's avatar
Arturo Espinosa committed
262
}
263

264