1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
---|
2 | /* This file is part of the GtkHTML library. |
---|
3 | |
---|
4 | Copyright (C) 2001 Ximian, Inc. |
---|
5 | Authors: Radek Doulik |
---|
6 | |
---|
7 | This library is free software; you can redistribute it and/or |
---|
8 | modify it under the terms of the GNU Library General Public |
---|
9 | License as published by the Free Software Foundation; either |
---|
10 | version 2 of the License, or (at your option) any later version. |
---|
11 | |
---|
12 | This library is distributed in the hope that it will be useful, |
---|
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
15 | Library General Public License for more details. |
---|
16 | |
---|
17 | You should have received a copy of the GNU Library General Public License |
---|
18 | along with this library; see the file COPYING.LIB. If not, write to |
---|
19 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
20 | Boston, MA 02111-1307, USA. |
---|
21 | */ |
---|
22 | |
---|
23 | #include <config.h> |
---|
24 | #include "htmlcursor.h" |
---|
25 | #include "htmlengine.h" |
---|
26 | #include "htmlengine-edit.h" |
---|
27 | #include "htmlengine-edit-cut-and-paste.h" |
---|
28 | #include "htmlengine-edit-table.h" |
---|
29 | #include "htmlengine-edit-tablecell.h" |
---|
30 | #include "htmlobject.h" |
---|
31 | #include "htmltable.h" |
---|
32 | #include "htmltablecell.h" |
---|
33 | #include "htmlundo.h" |
---|
34 | |
---|
35 | HTMLTableCell * |
---|
36 | html_engine_get_table_cell (HTMLEngine *e) |
---|
37 | { |
---|
38 | g_assert (HTML_IS_ENGINE (e)); |
---|
39 | |
---|
40 | if (!e->cursor->object->parent || !e->cursor->object->parent->parent |
---|
41 | || !HTML_IS_TABLE_CELL (e->cursor->object->parent->parent)) |
---|
42 | return NULL; |
---|
43 | |
---|
44 | return HTML_TABLE_CELL (e->cursor->object->parent->parent); |
---|
45 | } |
---|
46 | |
---|
47 | typedef enum { |
---|
48 | HTML_TABLE_CELL_BGCOLOR, |
---|
49 | HTML_TABLE_CELL_BGPIXMAP, |
---|
50 | HTML_TABLE_CELL_NOWRAP, |
---|
51 | HTML_TABLE_CELL_HEADING, |
---|
52 | HTML_TABLE_CELL_HALIGN, |
---|
53 | HTML_TABLE_CELL_VALIGN, |
---|
54 | HTML_TABLE_CELL_WIDTH, |
---|
55 | } HTMLTableCellAttrType; |
---|
56 | |
---|
57 | union _HTMLTableCellUndoAttr { |
---|
58 | gboolean no_wrap; |
---|
59 | gboolean heading; |
---|
60 | |
---|
61 | gchar *pixmap; |
---|
62 | |
---|
63 | struct { |
---|
64 | gint width; |
---|
65 | gboolean percent; |
---|
66 | } width; |
---|
67 | |
---|
68 | struct { |
---|
69 | GdkColor color; |
---|
70 | gboolean has_bg_color; |
---|
71 | } color; |
---|
72 | |
---|
73 | HTMLHAlignType halign; |
---|
74 | HTMLHAlignType valign; |
---|
75 | }; |
---|
76 | typedef union _HTMLTableCellUndoAttr HTMLTableCellUndoAttr; |
---|
77 | |
---|
78 | struct _HTMLTableCellSetAttrUndo { |
---|
79 | HTMLUndoData data; |
---|
80 | |
---|
81 | HTMLTableCellUndoAttr attr; |
---|
82 | HTMLTableCellAttrType type; |
---|
83 | }; |
---|
84 | typedef struct _HTMLTableCellSetAttrUndo HTMLTableCellSetAttrUndo; |
---|
85 | |
---|
86 | static void |
---|
87 | attr_destroy (HTMLUndoData *undo_data) |
---|
88 | { |
---|
89 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
90 | |
---|
91 | switch (data->type) { |
---|
92 | case HTML_TABLE_CELL_BGPIXMAP: |
---|
93 | g_free (data->attr.pixmap); |
---|
94 | break; |
---|
95 | default: |
---|
96 | ; |
---|
97 | } |
---|
98 | } |
---|
99 | |
---|
100 | static HTMLTableCellSetAttrUndo * |
---|
101 | attr_undo_new (HTMLTableCellAttrType type) |
---|
102 | { |
---|
103 | HTMLTableCellSetAttrUndo *undo = g_new (HTMLTableCellSetAttrUndo, 1); |
---|
104 | |
---|
105 | html_undo_data_init (HTML_UNDO_DATA (undo)); |
---|
106 | undo->data.destroy = attr_destroy; |
---|
107 | undo->type = type; |
---|
108 | |
---|
109 | return undo; |
---|
110 | } |
---|
111 | |
---|
112 | /* |
---|
113 | * bg color |
---|
114 | * |
---|
115 | */ |
---|
116 | |
---|
117 | static void table_cell_set_bg_color (HTMLEngine *e, HTMLTableCell *cell, GdkColor *c, HTMLUndoDirection dir); |
---|
118 | |
---|
119 | static void |
---|
120 | table_cell_set_bg_color_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
121 | { |
---|
122 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
123 | |
---|
124 | table_cell_set_bg_color (e, html_engine_get_table_cell (e), data->attr.color.has_bg_color |
---|
125 | ? &data->attr.color.color : NULL, html_undo_direction_reverse (dir)); |
---|
126 | } |
---|
127 | |
---|
128 | static void |
---|
129 | table_cell_set_bg_color (HTMLEngine *e, HTMLTableCell *cell, GdkColor *c, HTMLUndoDirection dir) |
---|
130 | { |
---|
131 | HTMLTableCellSetAttrUndo *undo; |
---|
132 | |
---|
133 | undo = attr_undo_new (HTML_TABLE_CELL_BGCOLOR); |
---|
134 | undo->attr.color.color = cell->bg; |
---|
135 | undo->attr.color.has_bg_color = cell->have_bg; |
---|
136 | html_undo_add_action (e->undo, |
---|
137 | html_undo_action_new ("Set cell background color", table_cell_set_bg_color_undo_action, |
---|
138 | HTML_UNDO_DATA (undo), |
---|
139 | html_cursor_get_position (e->cursor), |
---|
140 | html_cursor_get_position (e->cursor)), dir); |
---|
141 | |
---|
142 | html_object_set_bg_color (HTML_OBJECT (cell), c); |
---|
143 | html_engine_queue_draw (e, HTML_OBJECT (cell)); |
---|
144 | } |
---|
145 | |
---|
146 | void |
---|
147 | html_engine_table_cell_set_bg_color (HTMLEngine *e, HTMLTableCell *cell, GdkColor *c) |
---|
148 | { |
---|
149 | table_cell_set_bg_color (e, cell, c, HTML_UNDO_UNDO); |
---|
150 | } |
---|
151 | |
---|
152 | /* |
---|
153 | * bg pixmap |
---|
154 | * |
---|
155 | */ |
---|
156 | |
---|
157 | static void table_cell_set_bg_pixmap (HTMLEngine *e, HTMLTableCell *cell, gchar *url, HTMLUndoDirection dir); |
---|
158 | |
---|
159 | static void |
---|
160 | table_cell_set_bg_pixmap_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
161 | { |
---|
162 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
163 | |
---|
164 | table_cell_set_bg_pixmap (e, html_engine_get_table_cell (e), data->attr.pixmap, html_undo_direction_reverse (dir)); |
---|
165 | } |
---|
166 | |
---|
167 | static void |
---|
168 | table_cell_set_bg_pixmap (HTMLEngine *e, HTMLTableCell *cell, gchar *url, HTMLUndoDirection dir) |
---|
169 | { |
---|
170 | HTMLImagePointer *iptr; |
---|
171 | HTMLTableCellSetAttrUndo *undo; |
---|
172 | |
---|
173 | undo = attr_undo_new (HTML_TABLE_CELL_BGPIXMAP); |
---|
174 | undo->attr.pixmap = cell->have_bgPixmap ? g_strdup (cell->bgPixmap->url) : NULL; |
---|
175 | html_undo_add_action (e->undo, |
---|
176 | html_undo_action_new ("Set cell background pixmap", table_cell_set_bg_pixmap_undo_action, |
---|
177 | HTML_UNDO_DATA (undo), |
---|
178 | html_cursor_get_position (e->cursor), |
---|
179 | html_cursor_get_position (e->cursor)), dir); |
---|
180 | |
---|
181 | iptr = cell->bgPixmap; |
---|
182 | cell->bgPixmap = url ? html_image_factory_register (e->image_factory, NULL, url, TRUE) : NULL; |
---|
183 | if (cell->have_bgPixmap && iptr) |
---|
184 | html_image_factory_unregister (e->image_factory, iptr, NULL); |
---|
185 | cell->have_bgPixmap = url ? TRUE : FALSE; |
---|
186 | html_engine_queue_draw (e, HTML_OBJECT (cell)); |
---|
187 | } |
---|
188 | |
---|
189 | void |
---|
190 | html_engine_table_cell_set_bg_pixmap (HTMLEngine *e, HTMLTableCell *cell, gchar *url) |
---|
191 | { |
---|
192 | table_cell_set_bg_pixmap (e, cell, url, HTML_UNDO_UNDO); |
---|
193 | } |
---|
194 | |
---|
195 | /* |
---|
196 | * halign |
---|
197 | * |
---|
198 | */ |
---|
199 | |
---|
200 | static void table_cell_set_halign (HTMLEngine *e, HTMLTableCell *cell, HTMLHAlignType halign, HTMLUndoDirection dir); |
---|
201 | |
---|
202 | static void |
---|
203 | table_cell_set_halign_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
204 | { |
---|
205 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
206 | |
---|
207 | table_cell_set_halign (e, html_engine_get_table_cell (e), data->attr.halign, html_undo_direction_reverse (dir)); |
---|
208 | } |
---|
209 | |
---|
210 | static void |
---|
211 | table_cell_set_halign (HTMLEngine *e, HTMLTableCell *cell, HTMLHAlignType halign, HTMLUndoDirection dir) |
---|
212 | { |
---|
213 | HTMLTableCellSetAttrUndo *undo; |
---|
214 | |
---|
215 | undo = attr_undo_new (HTML_TABLE_CELL_HALIGN); |
---|
216 | undo->attr.halign = HTML_CLUE (cell)->halign; |
---|
217 | html_undo_add_action (e->undo, |
---|
218 | html_undo_action_new ("Set cell horizontal align", table_cell_set_halign_undo_action, |
---|
219 | HTML_UNDO_DATA (undo), |
---|
220 | html_cursor_get_position (e->cursor), |
---|
221 | html_cursor_get_position (e->cursor)), dir); |
---|
222 | |
---|
223 | HTML_CLUE (cell)->halign = halign; |
---|
224 | html_engine_schedule_update (e); |
---|
225 | } |
---|
226 | |
---|
227 | void |
---|
228 | html_engine_table_cell_set_halign (HTMLEngine *e, HTMLTableCell *cell, HTMLHAlignType halign) |
---|
229 | { |
---|
230 | table_cell_set_halign (e, cell, halign, HTML_UNDO_UNDO); |
---|
231 | } |
---|
232 | |
---|
233 | /* |
---|
234 | * valign |
---|
235 | * |
---|
236 | */ |
---|
237 | |
---|
238 | static void table_cell_set_valign (HTMLEngine *e, HTMLTableCell *cell, HTMLVAlignType valign, HTMLUndoDirection dir); |
---|
239 | |
---|
240 | static void |
---|
241 | table_cell_set_valign_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
242 | { |
---|
243 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
244 | |
---|
245 | table_cell_set_valign (e, html_engine_get_table_cell (e), data->attr.valign, html_undo_direction_reverse (dir)); |
---|
246 | } |
---|
247 | |
---|
248 | static void |
---|
249 | table_cell_set_valign (HTMLEngine *e, HTMLTableCell *cell, HTMLVAlignType valign, HTMLUndoDirection dir) |
---|
250 | { |
---|
251 | HTMLTableCellSetAttrUndo *undo; |
---|
252 | |
---|
253 | undo = attr_undo_new (HTML_TABLE_CELL_VALIGN); |
---|
254 | undo->attr.valign = HTML_CLUE (cell)->valign; |
---|
255 | html_undo_add_action (e->undo, |
---|
256 | html_undo_action_new ("Set cell vertical align", table_cell_set_valign_undo_action, |
---|
257 | HTML_UNDO_DATA (undo), |
---|
258 | html_cursor_get_position (e->cursor), |
---|
259 | html_cursor_get_position (e->cursor)), dir); |
---|
260 | |
---|
261 | HTML_CLUE (cell)->valign = valign; |
---|
262 | html_engine_schedule_update (e); |
---|
263 | } |
---|
264 | |
---|
265 | void |
---|
266 | html_engine_table_cell_set_valign (HTMLEngine *e, HTMLTableCell *cell, HTMLVAlignType valign) |
---|
267 | { |
---|
268 | table_cell_set_valign (e, cell, valign, HTML_UNDO_UNDO); |
---|
269 | } |
---|
270 | |
---|
271 | /* |
---|
272 | * nowrap |
---|
273 | * |
---|
274 | */ |
---|
275 | |
---|
276 | static void table_cell_set_no_wrap (HTMLEngine *e, HTMLTableCell *cell, gboolean no_wrap, HTMLUndoDirection dir); |
---|
277 | |
---|
278 | static void |
---|
279 | table_cell_set_no_wrap_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
280 | { |
---|
281 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
282 | |
---|
283 | table_cell_set_no_wrap (e, html_engine_get_table_cell (e), data->attr.no_wrap, html_undo_direction_reverse (dir)); |
---|
284 | } |
---|
285 | |
---|
286 | static void |
---|
287 | table_cell_set_no_wrap (HTMLEngine *e, HTMLTableCell *cell, gboolean no_wrap, HTMLUndoDirection dir) |
---|
288 | { |
---|
289 | if (cell->no_wrap != no_wrap) { |
---|
290 | HTMLTableCellSetAttrUndo *undo; |
---|
291 | |
---|
292 | undo = attr_undo_new (HTML_TABLE_CELL_NOWRAP); |
---|
293 | undo->attr.no_wrap = cell->no_wrap; |
---|
294 | html_undo_add_action (e->undo, |
---|
295 | html_undo_action_new ("Set cell wrapping", table_cell_set_no_wrap_undo_action, |
---|
296 | HTML_UNDO_DATA (undo), |
---|
297 | html_cursor_get_position (e->cursor), |
---|
298 | html_cursor_get_position (e->cursor)), dir); |
---|
299 | cell->no_wrap = no_wrap; |
---|
300 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL_CALC); |
---|
301 | html_engine_schedule_update (e); |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | void |
---|
306 | html_engine_table_cell_set_no_wrap (HTMLEngine *e, HTMLTableCell *cell, gboolean no_wrap) |
---|
307 | { |
---|
308 | table_cell_set_no_wrap (e, cell, no_wrap, HTML_UNDO_UNDO); |
---|
309 | } |
---|
310 | |
---|
311 | /* |
---|
312 | * heading |
---|
313 | * |
---|
314 | */ |
---|
315 | |
---|
316 | static void table_cell_set_heading (HTMLEngine *e, HTMLTableCell *cell, gboolean heading, HTMLUndoDirection dir); |
---|
317 | |
---|
318 | static void |
---|
319 | table_cell_set_heading_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
320 | { |
---|
321 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
322 | |
---|
323 | table_cell_set_heading (e, html_engine_get_table_cell (e), data->attr.heading, html_undo_direction_reverse (dir)); |
---|
324 | } |
---|
325 | |
---|
326 | static void |
---|
327 | table_cell_set_heading (HTMLEngine *e, HTMLTableCell *cell, gboolean heading, HTMLUndoDirection dir) |
---|
328 | { |
---|
329 | if (cell->heading != heading) { |
---|
330 | HTMLTableCellSetAttrUndo *undo; |
---|
331 | |
---|
332 | undo = attr_undo_new (HTML_TABLE_CELL_HEADING); |
---|
333 | undo->attr.heading = cell->heading; |
---|
334 | html_undo_add_action (e->undo, |
---|
335 | html_undo_action_new ("Set cell style", table_cell_set_heading_undo_action, |
---|
336 | HTML_UNDO_DATA (undo), |
---|
337 | html_cursor_get_position (e->cursor), |
---|
338 | html_cursor_get_position (e->cursor)), dir); |
---|
339 | |
---|
340 | cell->heading = heading; |
---|
341 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL_CALC); |
---|
342 | html_object_change_set_down (HTML_OBJECT (cell), HTML_CHANGE_ALL); |
---|
343 | html_engine_schedule_update (e); |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | void |
---|
348 | html_engine_table_cell_set_heading (HTMLEngine *e, HTMLTableCell *cell, gboolean heading) |
---|
349 | { |
---|
350 | table_cell_set_heading (e, cell, heading, HTML_UNDO_UNDO); |
---|
351 | } |
---|
352 | |
---|
353 | /* |
---|
354 | * width |
---|
355 | * |
---|
356 | */ |
---|
357 | |
---|
358 | static void table_cell_set_width (HTMLEngine *e, HTMLTableCell *cell, gint width, gboolean percent, HTMLUndoDirection dir); |
---|
359 | static void |
---|
360 | table_cell_set_width_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirection dir, guint position_after) |
---|
361 | { |
---|
362 | HTMLTableCellSetAttrUndo *data = (HTMLTableCellSetAttrUndo *) undo_data; |
---|
363 | |
---|
364 | table_cell_set_width (e, html_engine_get_table_cell (e), |
---|
365 | data->attr.width.width, data->attr.width.percent, html_undo_direction_reverse (dir)); |
---|
366 | } |
---|
367 | |
---|
368 | static void |
---|
369 | table_cell_set_width (HTMLEngine *e, HTMLTableCell *cell, gint width, gboolean percent, HTMLUndoDirection dir) |
---|
370 | { |
---|
371 | if (cell->percent_width != percent || cell->fixed_width != width) { |
---|
372 | HTMLTableCellSetAttrUndo *undo; |
---|
373 | |
---|
374 | undo = attr_undo_new (HTML_TABLE_CELL_WIDTH); |
---|
375 | undo->attr.width.width = cell->fixed_width; |
---|
376 | undo->attr.width.percent = cell->percent_width; |
---|
377 | html_undo_add_action (e->undo, |
---|
378 | html_undo_action_new ("Set cell style", table_cell_set_width_undo_action, |
---|
379 | HTML_UNDO_DATA (undo), |
---|
380 | html_cursor_get_position (e->cursor), |
---|
381 | html_cursor_get_position (e->cursor)), dir); |
---|
382 | |
---|
383 | cell->percent_width = percent; |
---|
384 | cell->fixed_width = width; |
---|
385 | if (width && !percent) |
---|
386 | HTML_OBJECT (cell)->flags |= HTML_OBJECT_FLAG_FIXEDWIDTH; |
---|
387 | else |
---|
388 | HTML_OBJECT (cell)->flags &= ~ HTML_OBJECT_FLAG_FIXEDWIDTH; |
---|
389 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL_CALC); |
---|
390 | html_engine_schedule_update (e); |
---|
391 | } |
---|
392 | } |
---|
393 | |
---|
394 | void |
---|
395 | html_engine_table_cell_set_width (HTMLEngine *e, HTMLTableCell *cell, gint width, gboolean percent) |
---|
396 | { |
---|
397 | table_cell_set_width (e, cell, width, percent, HTML_UNDO_UNDO); |
---|
398 | } |
---|
399 | |
---|
400 | void |
---|
401 | html_engine_delete_table_cell_contents (HTMLEngine *e) |
---|
402 | { |
---|
403 | HTMLTableCell *cell; |
---|
404 | |
---|
405 | cell = html_engine_get_table_cell (e); |
---|
406 | if (!cell) |
---|
407 | return; |
---|
408 | |
---|
409 | html_engine_prev_cell (e); |
---|
410 | html_cursor_forward (e->cursor, e); |
---|
411 | html_engine_set_mark (e); |
---|
412 | html_engine_next_cell (e, FALSE); |
---|
413 | html_cursor_backward (e->cursor, e); |
---|
414 | html_engine_delete (e); |
---|
415 | } |
---|
416 | |
---|
417 | static void collapse_cspan (HTMLEngine *e, HTMLTableCell *cell, gint cspan, HTMLUndoDirection dir); |
---|
418 | static void collapse_rspan (HTMLEngine *e, HTMLTableCell *cell, gint rspan, HTMLUndoDirection dir); |
---|
419 | |
---|
420 | struct Move { |
---|
421 | gboolean move; |
---|
422 | gint rs, cs, rt, ct; |
---|
423 | }; |
---|
424 | struct MoveCellRDUndo { |
---|
425 | gint rspan, cspan; |
---|
426 | |
---|
427 | struct Move *moved; |
---|
428 | HTMLTableCell **removed; |
---|
429 | |
---|
430 | struct Move move; |
---|
431 | }; |
---|
432 | |
---|
433 | static struct MoveCellRDUndo * |
---|
434 | move_cell_rd_undo_new (gint rspan, gint cspan) |
---|
435 | { |
---|
436 | struct MoveCellRDUndo *undo; |
---|
437 | |
---|
438 | undo = g_new (struct MoveCellRDUndo, 1); |
---|
439 | undo->rspan = rspan; |
---|
440 | undo->cspan = cspan; |
---|
441 | undo->moved = g_new0 (struct Move, rspan*cspan); |
---|
442 | undo->removed = g_new0 (HTMLTableCell *, rspan*cspan); |
---|
443 | |
---|
444 | return undo; |
---|
445 | } |
---|
446 | |
---|
447 | static void |
---|
448 | move_cell_rd_undo_free (struct MoveCellRDUndo *undo) |
---|
449 | { |
---|
450 | gint i; |
---|
451 | |
---|
452 | for (i = 0; i < undo->rspan*undo->cspan; i ++) |
---|
453 | if (undo->removed [i]) |
---|
454 | html_object_destroy (HTML_OBJECT (undo->removed [i])); |
---|
455 | g_free (undo->removed); |
---|
456 | g_free (undo->moved); |
---|
457 | } |
---|
458 | |
---|
459 | static struct MoveCellRDUndo * |
---|
460 | move_cell_rd (HTMLTable *t, HTMLTableCell *cell, gint rs, gint cs) |
---|
461 | { |
---|
462 | struct MoveCellRDUndo *undo; |
---|
463 | gint r, c; |
---|
464 | |
---|
465 | g_assert ((rs == 0 && cs > 0) || (cs == 0 && rs > 0)); |
---|
466 | |
---|
467 | undo = move_cell_rd_undo_new (cell->rspan, cell->cspan); |
---|
468 | /* printf ("move %dx%d --> %dx%d\n", cell->row, cell->col, cell->row + rs, cell->col + cs); */ |
---|
469 | for (r = cell->row + cell->rspan - 1; r >= cell->row; r --) |
---|
470 | for (c = cell->col + cell->cspan - 1; c >= cell->col; c --) { |
---|
471 | if (r > cell->row + cell->rspan - 1 - rs || c > cell->col + cell->cspan - 1 - cs) { |
---|
472 | gint nr = rs + r - (rs ? cell->rspan : 0), nc = cs + c - (cs ? cell->cspan : 0); |
---|
473 | |
---|
474 | /* printf ("exchange: %dx%d <--> %dx%d (%p)\n", rs + r, cs + c, nr, nc, t->cells [rs][nc]); */ |
---|
475 | t->cells [nr][nc] = t->cells [rs + r][cs + c]; |
---|
476 | if (t->cells [nr][nc]) { |
---|
477 | struct Move *move = &undo->moved [(r - cell->row)*cell->cspan + c - cell->col]; |
---|
478 | |
---|
479 | html_table_cell_set_position (t->cells [nr][nc], nr, nc); |
---|
480 | move->rs = rs + r; |
---|
481 | move->cs = cs + c; |
---|
482 | move->rt = nr; |
---|
483 | move->ct = nc; |
---|
484 | move->move = TRUE; |
---|
485 | /* printf ("moved: %dx%d --> %dx%d (%d, %d) %p\n", rs + r, cs + c, nr, nc, r - cell->row, c - cell->col, t->cells [nr][nc]); */ |
---|
486 | } |
---|
487 | } else { |
---|
488 | if (r >= cell->row + rs && c >= cell->col + cs) { |
---|
489 | if (t->cells [rs + r][cs + c] && t->cells [rs + r][cs + c]->col == cs + c && t->cells [rs + r][cs + c]->row == rs + r) { |
---|
490 | /* printf ("move destroy: %dx%d\n", rs + r, cs + c); */ |
---|
491 | /* html_object_destroy (HTML_OBJECT (t->cells [rs + r][cs + c])); */ |
---|
492 | /* printf ("removed: %dx%d (%d, %d)\n", rs + r, cs + c, r - cell->row, c - cell->col); */ |
---|
493 | undo->removed [(r - cell->row)*cell->cspan + c - cell->col] = t->cells [r][c]; |
---|
494 | } |
---|
495 | t->cells [r][c] = NULL; |
---|
496 | } |
---|
497 | } |
---|
498 | t->cells [rs + r][cs + c] = cell; |
---|
499 | /* printf ("cell %dx%d <--\n", rs + r, cs + c); */ |
---|
500 | } |
---|
501 | /* printf ("set %dx%d --> %dx%d\n", cell->row, cell->col, cell->row + rs, cell->col + cs); */ |
---|
502 | undo->move.rs = cell->row; |
---|
503 | undo->move.cs = cell->col; |
---|
504 | undo->move.rt = cell->row + rs; |
---|
505 | undo->move.ct = cell->col + cs; |
---|
506 | |
---|
507 | html_table_cell_set_position (cell, cell->row + rs, cell->col + cs); |
---|
508 | |
---|
509 | return undo; |
---|
510 | } |
---|
511 | |
---|
512 | struct _ExpandSpanUndo { |
---|
513 | HTMLUndoData data; |
---|
514 | |
---|
515 | gint span; |
---|
516 | GSList *move_undo; |
---|
517 | }; |
---|
518 | typedef struct _ExpandSpanUndo ExpandSpanUndo; |
---|
519 | #define EXPAND_UNDO(x) ((ExpandSpanUndo *) x) |
---|
520 | |
---|
521 | static void |
---|
522 | expand_undo_destroy (HTMLUndoData *undo_data) |
---|
523 | { |
---|
524 | ExpandSpanUndo *data = EXPAND_UNDO (undo_data); |
---|
525 | GSList *slist; |
---|
526 | |
---|
527 | for (slist = data->move_undo; slist; slist = slist->next) |
---|
528 | move_cell_rd_undo_free ((struct MoveCellRDUndo *) slist->data); |
---|
529 | g_slist_free (data->move_undo); |
---|
530 | } |
---|
531 | |
---|
532 | static HTMLUndoData * |
---|
533 | expand_undo_data_new (gint span, GSList *slist) |
---|
534 | { |
---|
535 | ExpandSpanUndo *ud = g_new0 (ExpandSpanUndo, 1); |
---|
536 | |
---|
537 | html_undo_data_init (HTML_UNDO_DATA (ud)); |
---|
538 | ud->data.destroy = expand_undo_destroy; |
---|
539 | ud->span = span; |
---|
540 | ud->move_undo = slist; |
---|
541 | |
---|
542 | return HTML_UNDO_DATA (ud); |
---|
543 | } |
---|
544 | |
---|
545 | static void |
---|
546 | move_cell_rd_undo (HTMLTable *table, struct MoveCellRDUndo *undo) |
---|
547 | { |
---|
548 | HTMLTableCell *cell = table->cells [undo->move.rt][undo->move.ct]; |
---|
549 | gint r, c; |
---|
550 | |
---|
551 | for (r = 0; r < undo->rspan; r ++) |
---|
552 | for (c = 0; c < undo->cspan; c ++) |
---|
553 | if (undo->moved [r*undo->cspan + c].move) { |
---|
554 | struct Move *move = &undo->moved [r*undo->cspan + c]; |
---|
555 | |
---|
556 | /* printf ("move back: %dx%d --> %dx%d (%d, %d) %p\n", move->rt, move->ct, move->rs, move->cs, r, c, table->cells [move->rt][move->ct]); */ |
---|
557 | table->cells [move->rs][move->cs] = table->cells [move->rt][move->ct]; |
---|
558 | html_table_cell_set_position (table->cells [move->rs][move->cs], move->rs, move->cs); |
---|
559 | table->cells [move->rt][move->ct] = NULL; |
---|
560 | } |
---|
561 | |
---|
562 | for (r = 0; r < cell->rspan; r ++) |
---|
563 | for (c = 0; c < cell->cspan; c ++) |
---|
564 | table->cells [undo->move.rt + r][undo->move.ct + c] = NULL; |
---|
565 | for (r = 0; r < cell->rspan; r ++) |
---|
566 | for (c = 0; c < cell->cspan; c ++) |
---|
567 | table->cells [undo->move.rs + r][undo->move.cs + c] = cell; |
---|
568 | |
---|
569 | html_table_cell_set_position (cell, undo->move.rs, undo->move.cs); |
---|
570 | } |
---|
571 | |
---|
572 | static void |
---|
573 | expand_cspan_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection dir, guint position_after) |
---|
574 | { |
---|
575 | GSList *slist; |
---|
576 | |
---|
577 | html_engine_freeze (e); |
---|
578 | collapse_cspan (e, html_engine_get_table_cell (e), EXPAND_UNDO (data)->span, html_undo_direction_reverse (dir)); |
---|
579 | for (slist = EXPAND_UNDO (data)->move_undo; slist; slist = slist->next) |
---|
580 | move_cell_rd_undo (html_engine_get_table (e), (struct MoveCellRDUndo *) slist->data); |
---|
581 | html_engine_thaw (e); |
---|
582 | } |
---|
583 | |
---|
584 | static void |
---|
585 | expand_cspan_setup_undo (HTMLEngine *e, GSList *slist, gint cspan, guint position_before, HTMLUndoDirection dir) |
---|
586 | { |
---|
587 | html_undo_add_action (e->undo, |
---|
588 | html_undo_action_new ("Expand Column Span", expand_cspan_undo_action, |
---|
589 | expand_undo_data_new (cspan, slist), html_cursor_get_position (e->cursor), |
---|
590 | position_before), |
---|
591 | dir); |
---|
592 | } |
---|
593 | |
---|
594 | static void |
---|
595 | expand_cspan (HTMLEngine *e, HTMLTableCell *cell, gint cspan, HTMLUndoDirection dir) |
---|
596 | { |
---|
597 | HTMLTable *table = HTML_TABLE (HTML_OBJECT (cell)->parent); |
---|
598 | GSList *slist = NULL; |
---|
599 | guint position_before = e->cursor->position; |
---|
600 | gint r, c, *move_rows, max_move, add_cols; |
---|
601 | |
---|
602 | move_rows = g_new0 (gint, cell->rspan); |
---|
603 | for (r = cell->row; r < cell->row + cell->rspan; r ++) |
---|
604 | for (c = cell->col + cell->cspan; c < MIN (cell->col + cspan, table->totalCols); c ++) |
---|
605 | if (table->cells [r][c] && !html_clue_is_empty (HTML_CLUE (table->cells [r][c])) && move_rows [r - cell->row] == 0) |
---|
606 | move_rows [r - cell->row] = cspan - (c - cell->col); |
---|
607 | |
---|
608 | max_move = 0; |
---|
609 | for (r = 0; r < cell->rspan; r ++) |
---|
610 | if (move_rows [r] > max_move) |
---|
611 | max_move = move_rows [r]; |
---|
612 | |
---|
613 | add_cols = MAX (max_move, cspan - (table->totalCols - cell->col)); |
---|
614 | /* printf ("max move: %d add: %d\n", max_move, add_cols); */ |
---|
615 | for (c = 0; c < add_cols; c ++) |
---|
616 | html_table_insert_column (table, e, table->totalCols, NULL, dir); |
---|
617 | |
---|
618 | if (max_move > 0) { |
---|
619 | for (c = table->totalCols - max_move - 1; c >= cell->col + cspan - max_move; c --) |
---|
620 | for (r = cell->row; r < cell->row + cell->rspan; r ++) { |
---|
621 | HTMLTableCell *ccell = table->cells [r][c]; |
---|
622 | |
---|
623 | if (ccell && ccell->col == c) { |
---|
624 | slist = g_slist_prepend (slist, move_cell_rd (table, ccell, 0, max_move)); |
---|
625 | r += ccell->rspan - 1; |
---|
626 | } |
---|
627 | } |
---|
628 | } |
---|
629 | |
---|
630 | expand_cspan_setup_undo (e, slist, cell->cspan, position_before, dir); |
---|
631 | cell->cspan = cspan; |
---|
632 | for (r = cell->row; r < cell->row + cell->rspan; r ++) |
---|
633 | for (c = cell->col; c < cell->col + cell->cspan; c ++) |
---|
634 | table->cells [r][c] = cell; |
---|
635 | |
---|
636 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL); |
---|
637 | } |
---|
638 | |
---|
639 | struct _CollapseSpanUndo { |
---|
640 | HTMLUndoData data; |
---|
641 | |
---|
642 | gint span; |
---|
643 | }; |
---|
644 | typedef struct _CollapseSpanUndo CollapseSpanUndo; |
---|
645 | #define COLLAPSE_UNDO(x) ((CollapseSpanUndo *) x) |
---|
646 | |
---|
647 | static HTMLUndoData * |
---|
648 | collapse_undo_data_new (gint span) |
---|
649 | { |
---|
650 | CollapseSpanUndo *ud = g_new0 (CollapseSpanUndo, 1); |
---|
651 | |
---|
652 | html_undo_data_init (HTML_UNDO_DATA (ud)); |
---|
653 | ud->span = span; |
---|
654 | |
---|
655 | return HTML_UNDO_DATA (ud); |
---|
656 | } |
---|
657 | |
---|
658 | static void |
---|
659 | collapse_cspan_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection dir, guint position_after) |
---|
660 | { |
---|
661 | html_engine_freeze (e); |
---|
662 | expand_cspan (e, html_engine_get_table_cell (e), COLLAPSE_UNDO (data)->span, html_undo_direction_reverse (dir)); |
---|
663 | html_engine_thaw (e); |
---|
664 | } |
---|
665 | |
---|
666 | static void |
---|
667 | collapse_cspan_setup_undo (HTMLEngine *e, gint cspan, guint position_before, HTMLUndoDirection dir) |
---|
668 | { |
---|
669 | html_undo_add_action (e->undo, |
---|
670 | html_undo_action_new ("Collapse Column Span", collapse_cspan_undo_action, |
---|
671 | collapse_undo_data_new (cspan), html_cursor_get_position (e->cursor), |
---|
672 | position_before), |
---|
673 | dir); |
---|
674 | } |
---|
675 | |
---|
676 | static void |
---|
677 | collapse_cspan (HTMLEngine *e, HTMLTableCell *cell, gint cspan, HTMLUndoDirection dir) |
---|
678 | { |
---|
679 | HTMLTable *table; |
---|
680 | guint position_before = e->cursor->position; |
---|
681 | gint r, c; |
---|
682 | |
---|
683 | table = HTML_TABLE (HTML_OBJECT (cell)->parent); |
---|
684 | for (c = cell->col + cspan; c < cell->col + cell->cspan; c ++) |
---|
685 | for (r = cell->row; r < cell->row + cell->rspan; r ++) { |
---|
686 | table->cells [r][c] = NULL; |
---|
687 | html_table_set_cell (table, r, c, html_engine_new_cell (e, table)); |
---|
688 | html_table_cell_set_position (table->cells [r][c], r, c); |
---|
689 | } |
---|
690 | |
---|
691 | collapse_cspan_setup_undo (e, cell->cspan, position_before, dir); |
---|
692 | cell->cspan = cspan; |
---|
693 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL); |
---|
694 | } |
---|
695 | |
---|
696 | void |
---|
697 | html_engine_set_cspan (HTMLEngine *e, gint cspan) |
---|
698 | { |
---|
699 | HTMLTableCell *cell = html_engine_get_table_cell (e); |
---|
700 | |
---|
701 | g_return_if_fail (cspan > 0); |
---|
702 | g_return_if_fail (cell != NULL); |
---|
703 | |
---|
704 | if (cell->cspan == cspan) |
---|
705 | return; |
---|
706 | |
---|
707 | html_engine_freeze (e); |
---|
708 | if (cspan > cell->cspan) |
---|
709 | expand_cspan (e, cell, cspan, HTML_UNDO_UNDO); |
---|
710 | else |
---|
711 | collapse_cspan (e, cell, cspan, HTML_UNDO_UNDO); |
---|
712 | html_engine_thaw (e); |
---|
713 | } |
---|
714 | |
---|
715 | static gint |
---|
716 | calc_rspan_max_move (HTMLTableCell *cell, gint rspan) |
---|
717 | { |
---|
718 | HTMLTable *table = HTML_TABLE (HTML_OBJECT (cell)->parent); |
---|
719 | gint r, c, *move_cols, max_move; |
---|
720 | |
---|
721 | move_cols = g_new0 (gint, cell->cspan); |
---|
722 | for (c = cell->col; c < cell->col + cell->cspan; c ++) |
---|
723 | for (r = cell->row + cell->rspan; r < MIN (cell->row + rspan, table->totalRows); r ++) |
---|
724 | if (table->cells [r][c] && !html_clue_is_empty (HTML_CLUE (table->cells [r][c])) && move_cols [c - cell->col] == 0) |
---|
725 | move_cols [c - cell->col] = rspan - (r - cell->row); |
---|
726 | |
---|
727 | max_move = 0; |
---|
728 | for (c = 0; c < cell->cspan; c ++) |
---|
729 | if (move_cols [c] > max_move) |
---|
730 | max_move = move_cols [c]; |
---|
731 | g_free (move_cols); |
---|
732 | |
---|
733 | return max_move; |
---|
734 | } |
---|
735 | |
---|
736 | static void |
---|
737 | expand_rspan (HTMLEngine *e, HTMLTableCell *cell, gint rspan, HTMLUndoDirection dir) |
---|
738 | { |
---|
739 | HTMLTable *table = HTML_TABLE (HTML_OBJECT (cell)->parent); |
---|
740 | GSList *slist = NULL; |
---|
741 | gint r, c, max_move, add_rows; |
---|
742 | |
---|
743 | max_move = calc_rspan_max_move (cell, rspan); |
---|
744 | add_rows = MAX (max_move, rspan - (table->totalRows - cell->row)); |
---|
745 | /* printf ("max move: %d add: %d\n", max_move, add_rows); */ |
---|
746 | for (r = 0; r < add_rows; r ++) |
---|
747 | html_table_insert_row (table, e, table->totalRows, NULL, dir); |
---|
748 | |
---|
749 | if (max_move > 0) { |
---|
750 | for (r = table->totalRows - max_move - 1; r >= cell->row + rspan - max_move; r --) |
---|
751 | for (c = cell->col; c < cell->col + cell->cspan; c ++) { |
---|
752 | HTMLTableCell *ccell = table->cells [r][c]; |
---|
753 | |
---|
754 | if (ccell && ccell->row == r) { |
---|
755 | slist = g_slist_prepend (slist, move_cell_rd (table, ccell, max_move, 0)); |
---|
756 | c += ccell->cspan - 1; |
---|
757 | } |
---|
758 | } |
---|
759 | } |
---|
760 | |
---|
761 | cell->rspan = rspan; |
---|
762 | for (r = cell->row; r < cell->row + cell->rspan; r ++) |
---|
763 | for (c = cell->col; c < cell->col + cell->cspan; c ++) |
---|
764 | table->cells [r][c] = cell; |
---|
765 | |
---|
766 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL); |
---|
767 | } |
---|
768 | |
---|
769 | static void |
---|
770 | collapse_rspan_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection dir, guint position_after) |
---|
771 | { |
---|
772 | html_engine_freeze (e); |
---|
773 | expand_rspan (e, html_engine_get_table_cell (e), COLLAPSE_UNDO (data)->span, html_undo_direction_reverse (dir)); |
---|
774 | html_engine_thaw (e); |
---|
775 | } |
---|
776 | |
---|
777 | static void |
---|
778 | collapse_rspan_setup_undo (HTMLEngine *e, gint rspan, guint position_before, HTMLUndoDirection dir) |
---|
779 | { |
---|
780 | html_undo_add_action (e->undo, |
---|
781 | html_undo_action_new ("Collapse Row Span", collapse_rspan_undo_action, |
---|
782 | collapse_undo_data_new (rspan), html_cursor_get_position (e->cursor), |
---|
783 | position_before), |
---|
784 | dir); |
---|
785 | } |
---|
786 | |
---|
787 | static void |
---|
788 | collapse_rspan (HTMLEngine *e, HTMLTableCell *cell, gint rspan, HTMLUndoDirection dir) |
---|
789 | { |
---|
790 | HTMLTable *table; |
---|
791 | guint position_before = e->cursor->position; |
---|
792 | gint r, c; |
---|
793 | |
---|
794 | table = HTML_TABLE (HTML_OBJECT (cell)->parent); |
---|
795 | for (r = cell->row + rspan; r < cell->row + cell->rspan; r ++) |
---|
796 | for (c = cell->col; c < cell->col + cell->cspan; c ++) { |
---|
797 | table->cells [r][c] = NULL; |
---|
798 | html_table_set_cell (table, r, c, html_engine_new_cell (e, table)); |
---|
799 | html_table_cell_set_position (table->cells [r][c], r, c); |
---|
800 | } |
---|
801 | |
---|
802 | collapse_rspan_setup_undo (e, cell->rspan, position_before, dir); |
---|
803 | cell->rspan = rspan; |
---|
804 | html_object_change_set (HTML_OBJECT (cell), HTML_CHANGE_ALL); |
---|
805 | } |
---|
806 | |
---|
807 | void |
---|
808 | html_engine_set_rspan (HTMLEngine *e, gint rspan) |
---|
809 | { |
---|
810 | HTMLTableCell *cell = html_engine_get_table_cell (e); |
---|
811 | |
---|
812 | g_return_if_fail (rspan > 0); |
---|
813 | g_return_if_fail (cell != NULL); |
---|
814 | |
---|
815 | if (cell->rspan == rspan) |
---|
816 | return; |
---|
817 | |
---|
818 | html_engine_freeze (e); |
---|
819 | if (rspan > cell->rspan) |
---|
820 | expand_rspan (e, cell, rspan, HTML_UNDO_UNDO); |
---|
821 | else |
---|
822 | collapse_rspan (e, cell, rspan, HTML_UNDO_UNDO); |
---|
823 | html_engine_thaw (e); |
---|
824 | } |
---|
825 | |
---|
826 | gboolean |
---|
827 | html_engine_cspan_delta (HTMLEngine *e, gint delta) |
---|
828 | { |
---|
829 | HTMLTableCell *cell; |
---|
830 | |
---|
831 | cell = html_engine_get_table_cell (e); |
---|
832 | if (cell) { |
---|
833 | if (cell->cspan + delta > 0) { |
---|
834 | html_engine_set_cspan (e, cell->cspan + delta); |
---|
835 | return TRUE; |
---|
836 | } |
---|
837 | } |
---|
838 | |
---|
839 | return FALSE; |
---|
840 | } |
---|
841 | |
---|
842 | gboolean |
---|
843 | html_engine_rspan_delta (HTMLEngine *e, gint delta) |
---|
844 | { |
---|
845 | HTMLTableCell *cell; |
---|
846 | |
---|
847 | cell = html_engine_get_table_cell (e); |
---|
848 | if (cell) { |
---|
849 | if (cell->rspan + delta > 0) { |
---|
850 | html_engine_set_rspan (e, cell->rspan + delta); |
---|
851 | return TRUE; |
---|
852 | } |
---|
853 | } |
---|
854 | |
---|
855 | return FALSE; |
---|
856 | } |
---|