clipboard.c 6.7 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
#include "render-ascii.h"

16 17 18 19 20
/*
 * x_selection_clear:
 *
 * Callback for the "we lost the X selection" signal
 */
21 22 23 24 25 26 27 28
static gint
x_selection_clear (GtkWidget *widget, GdkEventSelection *event, Workbook *wb)
{
	wb->have_x_selection = FALSE;

	return TRUE;
}

29 30 31 32 33
/*
 * x_selection_handler:
 *
 * Callback invoked when another application requests we render the selection.
 */
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
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));
}

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
/*
 * x_selection_received
 *
 * Invoked when the selection has been received by our application.
 * This is triggered by a call we do to gtk_selection_convert.
 */
static void
x_selection_received (GtkWidget *widget, GtkSelectionData *sel, gpointer data)
{
	Workbook *wb = data;

	/* Did X provide any selection? */
	if (sel->length < 0){
		
	} 
}

/*
 * x_clipboard_bind_workbook
 *
 * Binds the signals related to the X selection to the Workbook
 */
71 72 73 74 75 76 77 78 79 80 81 82 83
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);
84 85 86
	gtk_signal_connect (
		GTK_OBJECT (wb->toplevel), "selection_received",
		GTK_SIGNAL_FUNC(x_selection_received), wb);
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
}

/*
 * 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
102 103 104 105 106 107

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

108
static int
Arturo Espinosa's avatar
Arturo Espinosa committed
109 110 111 112 113 114 115 116 117
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;
118
	copy->row_offset  = row - c->base_row;
Arturo Espinosa's avatar
Arturo Espinosa committed
119 120 121 122 123 124 125 126 127 128 129
	
	/* 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;
}

130 131 132 133 134
/*
 * clipboard_copy_cell_range:
 *
 * Entry point to the clipboard copy code
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
135 136 137 138
CellRegion *
clipboard_copy_cell_range (Sheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
	append_cell_closure_t c;
139
	
140 141 142 143
	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);
144

145
	c.r = g_new0 (CellRegion, 1);
Arturo Espinosa's avatar
Arturo Espinosa committed
146 147 148

	c.base_col = start_col;
	c.base_row = start_row;
149 150
	c.r->cols = end_col - start_col + 1;
	c.r->rows = end_row - start_row + 1;
Arturo Espinosa's avatar
Arturo Espinosa committed
151 152 153
	
	sheet_cell_foreach_range (
		sheet, 1, start_col, start_row, end_col, end_row,
154 155
		clipboard_append_cell, &c);

156 157
	clipboard_export_cell_region (sheet->workbook, c.r);
	
158
	return c.r;
Arturo Espinosa's avatar
Arturo Espinosa committed
159 160
}

Arturo Espinosa's avatar
Arturo Espinosa committed
161 162 163 164
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
165
	
Arturo Espinosa's avatar
Arturo Espinosa committed
166 167 168 169 170 171 172 173
	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
174 175 176 177
		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
178
	}
Miguel de Icaza's avatar
Miguel de Icaza committed
179 180

	cell_render_value (new_cell);
Arturo Espinosa's avatar
Arturo Espinosa committed
181 182 183
	
	if (!(paste_flags & PASTE_FORMULAS)){
		string_unref (new_cell->entered_text);
Miguel de Icaza's avatar
Miguel de Icaza committed
184
		new_cell->entered_text = string_ref (new_cell->text);
Arturo Espinosa's avatar
Arturo Espinosa committed
185
	}
Miguel de Icaza's avatar
Miguel de Icaza committed
186

Arturo Espinosa's avatar
Arturo Espinosa committed
187 188 189 190 191 192 193
	sheet_redraw_cell_region (dest_sheet,
				  target_col, target_row,
				  target_col, target_row);

	return new_cell->parsed_node != 0;
}

194 195 196
/*
 * Main entry point for the paste code
 */
Arturo Espinosa's avatar
Arturo Espinosa committed
197
void
Arturo Espinosa's avatar
Arturo Espinosa committed
198
clipboard_paste_region (CellRegion *region, Sheet *dest_sheet,
199 200 201
			int dest_col,       int dest_row,
			int paste_width,    int paste_height,
			int paste_flags,    guint32 time)
Arturo Espinosa's avatar
Arturo Espinosa committed
202
{
203
	CellCopyList *l;
Arturo Espinosa's avatar
Arturo Espinosa committed
204
	GList *deps;
Arturo Espinosa's avatar
Arturo Espinosa committed
205
	int formulas = 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
206
	int col, row;
207
	
208 209 210 211 212
	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 */
213 214 215 216 217
	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);
218

Arturo Espinosa's avatar
Arturo Espinosa committed
219 220 221 222
	/* 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
223 224
					  dest_col + paste_width - 1,
					  dest_row + paste_height - 1);
225
	
226
	/* Paste each element */
Arturo Espinosa's avatar
Arturo Espinosa committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	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;

243 244 245 246 247 248 249 250 251 252
				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
253
				
254 255 256 257
					formulas |= paste_cell (
						dest_sheet, new_cell,
						target_col, target_row, paste_flags);
				}
Arturo Espinosa's avatar
Arturo Espinosa committed
258 259 260 261 262 263 264 265 266 267 268 269 270
			}
		}
	}
	
	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;
271
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
272

Arturo Espinosa's avatar
Arturo Espinosa committed
273
	/* Trigger a recompute if required */
Arturo Espinosa's avatar
Arturo Espinosa committed
274 275
	if (formulas)
		workbook_recalc (dest_sheet->workbook);
276 277
}

278 279 280
/*
 * Destroys the contents of a CellRegion
 */
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
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
298
}
299

300