source: trunk/third/gtkhtml3/src/htmlengine-edit-tablecell.c @ 21116

Revision 21116, 25.6 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21115, which included commits to RCS files with non-trunk default branches.
Line 
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
35HTMLTableCell *
36html_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
47typedef 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
57union _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};
76typedef union _HTMLTableCellUndoAttr HTMLTableCellUndoAttr;
77
78struct _HTMLTableCellSetAttrUndo {
79        HTMLUndoData data;
80
81        HTMLTableCellUndoAttr attr;
82        HTMLTableCellAttrType type;
83};
84typedef struct _HTMLTableCellSetAttrUndo HTMLTableCellSetAttrUndo;
85
86static void
87attr_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
100static HTMLTableCellSetAttrUndo *
101attr_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
117static void table_cell_set_bg_color (HTMLEngine *e, HTMLTableCell *cell, GdkColor *c, HTMLUndoDirection dir);
118
119static void
120table_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
128static void
129table_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
146void
147html_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
157static void table_cell_set_bg_pixmap (HTMLEngine *e, HTMLTableCell *cell, gchar *url, HTMLUndoDirection dir);
158
159static void
160table_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
167static void
168table_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
189void
190html_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
200static void table_cell_set_halign (HTMLEngine *e, HTMLTableCell *cell, HTMLHAlignType halign, HTMLUndoDirection dir);
201
202static void
203table_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
210static void
211table_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
227void
228html_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
238static void table_cell_set_valign (HTMLEngine *e, HTMLTableCell *cell, HTMLVAlignType valign, HTMLUndoDirection dir);
239
240static void
241table_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
248static void
249table_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
265void
266html_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
276static void table_cell_set_no_wrap (HTMLEngine *e, HTMLTableCell *cell, gboolean no_wrap, HTMLUndoDirection dir);
277
278static void
279table_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
286static void
287table_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
305void
306html_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
316static void table_cell_set_heading (HTMLEngine *e, HTMLTableCell *cell, gboolean heading, HTMLUndoDirection dir);
317
318static void
319table_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
326static void
327table_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
347void
348html_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
358static void table_cell_set_width (HTMLEngine *e, HTMLTableCell *cell, gint width, gboolean percent, HTMLUndoDirection dir);
359static void
360table_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
368static void
369table_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
394void
395html_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
400void
401html_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
417static void collapse_cspan (HTMLEngine *e, HTMLTableCell *cell, gint cspan, HTMLUndoDirection dir);
418static void collapse_rspan (HTMLEngine *e, HTMLTableCell *cell, gint rspan, HTMLUndoDirection dir);
419
420struct Move {
421        gboolean move;
422        gint rs, cs, rt, ct;
423};
424struct MoveCellRDUndo {
425        gint rspan, cspan;
426
427        struct Move *moved;
428        HTMLTableCell **removed;
429
430        struct Move move;
431};
432
433static struct MoveCellRDUndo *
434move_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
447static void
448move_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
459static struct MoveCellRDUndo *
460move_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
512struct _ExpandSpanUndo {
513        HTMLUndoData data;
514
515        gint span;
516        GSList *move_undo;
517};
518typedef struct _ExpandSpanUndo ExpandSpanUndo;
519#define EXPAND_UNDO(x) ((ExpandSpanUndo *) x)
520
521static void
522expand_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
532static HTMLUndoData *
533expand_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
545static void
546move_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
572static void
573expand_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
584static void
585expand_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
594static void
595expand_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
639struct _CollapseSpanUndo {
640        HTMLUndoData data;
641
642        gint span;
643};
644typedef struct _CollapseSpanUndo CollapseSpanUndo;
645#define COLLAPSE_UNDO(x) ((CollapseSpanUndo *) x)
646
647static HTMLUndoData *
648collapse_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
658static void
659collapse_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
666static void
667collapse_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
676static void
677collapse_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
696void
697html_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
715static gint
716calc_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
736static void
737expand_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
769static void
770collapse_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
777static void
778collapse_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
787static void
788collapse_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
807void
808html_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
826gboolean
827html_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
842gboolean
843html_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}
Note: See TracBrowser for help on using the repository browser.