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) 2000 Helix Code, Inc.
5  *  Copyright (C) 2001, 2002 Ximian, Inc.
6  *  Authors: Radek Doulik
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public License
19  *  along with this library; see the file COPYING.LIB.  If not, write to
20  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301, USA.
22 */
23 
24 #include <config.h>
25 #include "htmlcluealigned.h"
26 #include "htmlclueflow.h"
27 #include "htmlcursor.h"
28 #include "htmlimage.h"
29 #include "htmlengine.h"
30 #include "htmlengine-edit.h"
31 #include "htmlengine-edit-cut-and-paste.h"
32 #include "htmlengine-edit-table.h"
33 #include "htmlengine-edit-tablecell.h"
34 #include "htmlinterval.h"
35 #include "htmltable.h"
36 #include "htmltablecell.h"
37 #include "htmltablepriv.h"
38 #include "htmlselection.h"
39 #include "htmlundo.h"
40 
41 HTMLTable *
html_engine_get_table(HTMLEngine * e)42 html_engine_get_table (HTMLEngine *e)
43 {
44 	if (!e->cursor->object->parent
45 	    || !e->cursor->object->parent->parent
46 	    || !e->cursor->object->parent->parent->parent
47 	    || !HTML_IS_TABLE (e->cursor->object->parent->parent->parent))
48 		return NULL;
49 	else
50 		return HTML_TABLE (e->cursor->object->parent->parent->parent);
51 }
52 
53 HTMLTableCell *
html_engine_new_cell(HTMLEngine * e,HTMLTable * table)54 html_engine_new_cell (HTMLEngine *e,
55                       HTMLTable *table)
56 {
57 	HTMLObject    *cell;
58 	HTMLObject    *text;
59 	HTMLObject    *flow;
60 
61 	cell  = html_table_cell_new (1, 1, table->padding);
62 	flow  = html_clueflow_new (HTML_CLUEFLOW_STYLE_NORMAL, g_byte_array_new (),
63 				   HTML_LIST_TYPE_UNORDERED, 0, HTML_CLEAR_NONE);
64 	text  = html_engine_new_text_empty (e);
65 
66 	html_clue_append (HTML_CLUE (flow), text);
67 	html_clue_append (HTML_CLUE (cell), flow);
68 
69 	return HTML_TABLE_CELL (cell);
70 }
71 
72 /*
73  * Table insertion
74  */
75 
76 /**
77  * html_engine_insert_table_1_1:
78  * @e: An html engine
79  *
80  * Inserts new table with one cell containing an empty flow with an empty text. Inserted table has 1 row and 1 column.
81  **/
82 
83 void
html_engine_insert_table_1_1(HTMLEngine * e)84 html_engine_insert_table_1_1 (HTMLEngine *e)
85 {
86 	HTMLObject    *table;
87 
88 	table = html_table_new (0, 100, 1, 2, 1);
89 
90 	html_table_add_cell (HTML_TABLE (table), html_engine_new_cell (e, HTML_TABLE (table)));
91 
92 	html_engine_append_object (e, table, 2);
93 	html_cursor_backward (e->cursor, e);
94 	html_engine_table_set_align (e, (HTMLTable *) table, HTML_HALIGN_CENTER);
95 }
96 
97 /**
98  * html_engine_insert_table_1_1:
99  * @e: An html engine
100  *
101  * Inserts new table with @cols columns and @rows rows. Cells contain an empty flow with an empty text.
102  **/
103 
104 void
html_engine_insert_table(HTMLEngine * e,gint cols,gint rows,gint width,gint percent,gint padding,gint spacing,gint border)105 html_engine_insert_table (HTMLEngine *e,
106                           gint cols,
107                           gint rows,
108                           gint width,
109                           gint percent,
110                           gint padding,
111                           gint spacing,
112                           gint border)
113 {
114 	HTMLObject *table;
115 	gint r, c;
116 
117 	g_return_if_fail (cols >= 0);
118 	g_return_if_fail (rows >= 0);
119 
120 	table = html_table_new (width, percent, padding, spacing, border);
121 
122 	for (r = 0; r < rows; r++) {
123 		html_table_start_row (HTML_TABLE (table));
124 		for (c = 0; c < cols; c++)
125 			html_table_add_cell (HTML_TABLE (table), html_engine_new_cell (e, HTML_TABLE (table)));
126 		html_table_end_row (HTML_TABLE (table));
127 	}
128 
129 	html_engine_append_object (e, table, 1 + rows * cols);
130 	html_cursor_backward_n (e->cursor, e, rows * cols);
131 }
132 
133 /*
134  *  Insert Column
135  */
136 
137 struct _InsertCellsUndo {
138 	HTMLUndoData data;
139 
140 	gint pos;
141 };
142 typedef struct _InsertCellsUndo InsertCellsUndo;
143 #define INSERT_UNDO(x) ((InsertCellsUndo *) x)
144 
145 static HTMLUndoData *
insert_undo_data_new(gint pos)146 insert_undo_data_new (gint pos)
147 {
148 	InsertCellsUndo *ud = g_new0 (InsertCellsUndo, 1);
149 
150 	html_undo_data_init (HTML_UNDO_DATA (ud));
151 	ud->pos = pos;
152 
153 	return HTML_UNDO_DATA (ud);
154 }
155 
156 static void
insert_column_undo_action(HTMLEngine * e,HTMLUndoData * data,HTMLUndoDirection dir,guint position_after)157 insert_column_undo_action (HTMLEngine *e,
158                            HTMLUndoData *data,
159                            HTMLUndoDirection dir,
160                            guint position_after)
161 {
162 	html_table_delete_column (html_engine_get_table (e), e, INSERT_UNDO (data)->pos, html_undo_direction_reverse (dir));
163 }
164 
165 static void
insert_column_setup_undo(HTMLEngine * e,gint col,guint position_before,HTMLUndoDirection dir)166 insert_column_setup_undo (HTMLEngine *e,
167                           gint col,
168                           guint position_before,
169                           HTMLUndoDirection dir)
170 {
171 	html_undo_add_action (e->undo, e,
172 			      html_undo_action_new ("Insert table column", insert_column_undo_action,
173 						    insert_undo_data_new (col), html_cursor_get_position (e->cursor),
174 						    position_before),
175 			      dir);
176 }
177 
178 gboolean
html_engine_goto_table_0(HTMLEngine * e,HTMLTable * table)179 html_engine_goto_table_0 (HTMLEngine *e,
180                           HTMLTable *table)
181 {
182 	return html_cursor_jump_to (e->cursor, e, HTML_OBJECT (table), 0);
183 }
184 
185 gboolean
html_engine_goto_table(HTMLEngine * e,HTMLTable * table,gint row,gint col)186 html_engine_goto_table (HTMLEngine *e,
187                         HTMLTable *table,
188                         gint row,
189                         gint col)
190 {
191 	HTMLTableCell *cell;
192 
193 	html_engine_goto_table_0 (e, table);
194 	do {
195 		cell = html_engine_get_table_cell (e);
196 		if (cell && HTML_OBJECT (cell)->parent && HTML_OBJECT (cell)->parent == HTML_OBJECT (table)
197 		    && cell->col == col && cell->row == row)
198 			return TRUE;
199 	} while (cell && html_cursor_forward (e->cursor, e));
200 
201 	return FALSE;
202 }
203 
204 gboolean
html_engine_table_goto_col(HTMLEngine * e,HTMLTable * table,gint col)205 html_engine_table_goto_col (HTMLEngine *e,
206                             HTMLTable *table,
207                             gint col)
208 {
209 	HTMLTableCell *cell;
210 
211 	if (html_engine_goto_table_0 (e, table)) {
212 		html_cursor_forward (e->cursor, e);
213 		cell = html_engine_get_table_cell (e);
214 		while (cell && cell->col != col && HTML_OBJECT (cell)->parent == HTML_OBJECT (table)) {
215 			html_engine_next_cell (e, FALSE);
216 			cell = html_engine_get_table_cell (e);
217 		}
218 
219 		return cell != NULL && HTML_OBJECT (cell)->parent == HTML_OBJECT (table);
220 	}
221 
222 	return FALSE;
223 }
224 
225 gboolean
html_engine_table_goto_row(HTMLEngine * e,HTMLTable * table,gint row)226 html_engine_table_goto_row (HTMLEngine *e,
227                             HTMLTable *table,
228                             gint row)
229 {
230 	HTMLTableCell *cell;
231 
232 	if (html_engine_goto_table_0 (e, table)) {
233 		html_cursor_forward (e->cursor, e);
234 		cell = html_engine_get_table_cell (e);
235 		while (cell && cell->row != row && HTML_OBJECT (cell)->parent == HTML_OBJECT (table)) {
236 			html_engine_next_cell (e, FALSE);
237 			cell = html_engine_get_table_cell (e);
238 		}
239 
240 		return cell != NULL && HTML_OBJECT (cell)->parent == HTML_OBJECT (table);
241 	}
242 
243 	return FALSE;
244 }
245 
246 void
html_table_insert_column(HTMLTable * t,HTMLEngine * e,gint col,HTMLTableCell ** column,HTMLUndoDirection dir)247 html_table_insert_column (HTMLTable *t,
248                           HTMLEngine *e,
249                           gint col,
250                           HTMLTableCell **column,
251                           HTMLUndoDirection dir)
252 {
253 	HTMLTableCell *cell;
254 	HTMLPoint pos;
255 	gint c, r;
256 	guint position_before;
257 
258 	html_engine_freeze (e);
259 
260 	position_before = e->cursor->position;
261 	pos.object = e->cursor->object;
262 	pos.offset = e->cursor->offset;
263 
264 	html_engine_goto_table_0 (e, t);
265 
266 	html_table_alloc_cell (t, 0, t->totalCols);
267 	for (c = t->totalCols - 1; c > col; c--) {
268 		for (r = 0; r < t->totalRows; r++) {
269 			HTMLTableCell *cell = t->cells[r][c - 1];
270 
271 			if (cell) {
272 				if (cell->col == c - 1) {
273 					html_table_cell_set_position (cell, cell->row, c);
274 					t->cells[r][c - 1] = NULL;
275 				} else if (c == col + 1 && cell->row == r)
276 					cell->cspan++;
277 				if (cell->col > c - 1)
278 					t->cells[r][c - 1] = NULL;
279 				t->cells[r][c] = cell;
280 			}
281 		}
282 	}
283 	for (r = 0; r < t->totalRows; r++) {
284 		if (!t->cells[r][col]) {
285 			guint len;
286 
287 			cell = column
288 				? HTML_TABLE_CELL (html_object_op_copy (HTML_OBJECT (column[r]), HTML_OBJECT (t),
289 									e, NULL, NULL, &len))
290 				: html_engine_new_cell (e, t);
291 			html_table_set_cell (t, r, col, cell);
292 			html_table_cell_set_position (t->cells[r][col], r, col);
293 		}
294 	}
295 
296 	html_cursor_jump_to (e->cursor, e, pos.object, pos.offset);
297 	insert_column_setup_undo (e, col, position_before, dir);
298 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
299 	html_engine_queue_draw (e, HTML_OBJECT (t));
300 	html_engine_thaw (e);
301 }
302 
303 /**
304  * html_engine_insert_table_column:
305  * @e: An HTML engine.
306  * @after: If TRUE then inserts new column after current one, defined by current cursor position.
307  *         If FALSE then inserts before current one.
308  *
309  * Inserts new column into table after/before current column.
310  **/
311 
312 void
html_engine_insert_table_column(HTMLEngine * e,gboolean after)313 html_engine_insert_table_column (HTMLEngine *e,
314                                  gboolean after)
315 {
316 	HTMLTable *table;
317 	HTMLTableCell *cell;
318 
319 	table = html_engine_get_table (e);
320 	cell = html_engine_get_table_cell (e);
321 	if (table && cell)
322 		html_table_insert_column (table, e, cell->col + (after ? cell->cspan : 0), NULL, HTML_UNDO_UNDO);
323 }
324 
325 /*
326  * Delete column
327  */
328 
329 struct _DeleteCellsUndo {
330 	HTMLUndoData data;
331 
332 	HTMLTableCell **cells;
333 	gint size;
334 	gint pos;
335 };
336 typedef struct _DeleteCellsUndo DeleteCellsUndo;
337 
338 static void
delete_cells_undo_destroy(HTMLUndoData * undo_data)339 delete_cells_undo_destroy (HTMLUndoData *undo_data)
340 {
341 	DeleteCellsUndo *data = (DeleteCellsUndo *) undo_data;
342 	gint i;
343 
344 	for (i = 0; i < data->size; i++)
345 		if (data->cells[i])
346 			html_object_destroy (HTML_OBJECT (data->cells[i]));
347 	g_free (data->cells);
348 }
349 
350 static DeleteCellsUndo *
delete_cells_undo_new(HTMLTableCell ** cells,gint size,gint pos)351 delete_cells_undo_new (HTMLTableCell **cells,
352                        gint size,
353                        gint pos)
354 {
355 	DeleteCellsUndo *data;
356 
357 	data = g_new0 (DeleteCellsUndo, 1);
358 
359 	html_undo_data_init (HTML_UNDO_DATA (data));
360 
361 	data->data.destroy = delete_cells_undo_destroy;
362 	data->cells        = cells;
363 	data->pos          = pos;
364 	data->size         = size;
365 
366 	return data;
367 }
368 
369 static void
delete_column_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)370 delete_column_undo_action (HTMLEngine *e,
371                            HTMLUndoData *undo_data,
372                            HTMLUndoDirection dir,
373                            guint position_after)
374 {
375 	DeleteCellsUndo *data = (DeleteCellsUndo *) undo_data;
376 	HTMLTable *table;
377 
378 	table = html_engine_get_table (e);
379 	if (!table) {
380 		html_cursor_jump_to_position (e->cursor, e, position_after + 1);
381 		table = html_engine_get_table (e);
382 	}
383 	g_assert (table);
384 	g_assert (data->size == table->totalRows);
385 	html_table_insert_column (table, e, data->pos, data->cells, html_undo_direction_reverse (dir));
386 }
387 
388 static void
delete_column_setup_undo(HTMLEngine * e,HTMLTableCell ** column,gint size,guint position_after,gint col,HTMLUndoDirection dir)389 delete_column_setup_undo (HTMLEngine *e,
390                           HTMLTableCell **column,
391                           gint size,
392                           guint position_after,
393                           gint col,
394                           HTMLUndoDirection dir)
395 {
396 	html_undo_add_action (e->undo, e,
397 			      html_undo_action_new ("Delete table column", delete_column_undo_action,
398 						    HTML_UNDO_DATA (delete_cells_undo_new (column, size, col)),
399 						    html_cursor_get_position (e->cursor),
400 						    position_after), dir);
401 }
402 
403 static void
backward_before_col(HTMLEngine * e,HTMLTable * table,gint col)404 backward_before_col (HTMLEngine *e,
405                      HTMLTable *table,
406                      gint col)
407 {
408 	HTMLObject *cell;
409 
410 	do {
411 		if (!html_cursor_backward (e->cursor, e))
412 			return;
413 		cell = html_cursor_child_of (e->cursor, HTML_OBJECT (table));
414 	} while (cell && HTML_IS_TABLE_CELL (cell) && HTML_TABLE_CELL (cell)->col >= col);
415 }
416 
417 void
html_table_delete_column(HTMLTable * t,HTMLEngine * e,gint col,HTMLUndoDirection dir)418 html_table_delete_column (HTMLTable *t,
419                           HTMLEngine *e,
420                           gint col,
421                           HTMLUndoDirection dir)
422 {
423 	HTMLTableCell **column;
424 	HTMLTableCell *cell;
425 	HTMLPoint pos;
426 	gint r, c;
427 	guint position_after;
428 
429 	/* this command is valid only in table and when this table has > 1 column */
430 	if (!t || t->totalCols < 2)
431 		return;
432 
433 	html_engine_freeze (e);
434 
435 	column = g_new0 (HTMLTableCell *, t->totalRows);
436 
437 	backward_before_col (e, t, col);
438 	pos.object = e->cursor->object;
439 	pos.offset = e->cursor->offset;
440 
441 	html_engine_goto_table_0 (e, t);
442 	for (r = 0; r < t->totalRows; r++) {
443 		cell = t->cells[r][col];
444 
445 		/* remove & keep old one */
446 		if (cell && cell->col == col) {
447 			HTML_OBJECT (cell)->parent = NULL;
448 			column[r] = cell;
449 			t->cells[r][col] = NULL;
450 		}
451 
452 		for (c = col + 1; c < t->totalCols; c++) {
453 			cell = t->cells[r][c];
454 			if (cell && cell->col != col) {
455 				if (cell->row == r && cell->col == c)
456 					html_table_cell_set_position (cell, r, c - 1);
457 				t->cells[r][c - 1] = cell;
458 				t->cells[r][c]     = NULL;
459 			}
460 		}
461 	}
462 
463 	html_cursor_jump_to (e->cursor, e, pos.object, pos.offset);
464 	position_after = e->cursor->position;
465 	delete_column_setup_undo (e, column, t->totalRows, position_after, col, dir);
466 	t->totalCols--;
467 
468 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
469 	html_engine_queue_draw (e, HTML_OBJECT (t));
470 	html_engine_thaw (e);
471 }
472 
473 static gboolean
html_engine_get_table_start_end_cells(HTMLEngine * e,HTMLTableCell ** start_cell,HTMLTableCell ** end_cell)474 html_engine_get_table_start_end_cells (HTMLEngine *e,
475                                        HTMLTableCell **start_cell,
476                                        HTMLTableCell **end_cell)
477 {
478 	if (!e->cursor->object->parent ||
479 	    !e->cursor->object->parent->parent ||
480 	    !HTML_IS_TABLE_CELL (e->cursor->object->parent->parent))
481 		return FALSE;
482 	if (html_engine_is_selection_active (e))        {
483 		if (!e->mark->object->parent ||
484 		    !e->mark->object->parent->parent ||
485 		    !HTML_IS_TABLE_CELL (e->mark->object->parent->parent) ||
486 		    HTML_TABLE (e->mark->object->parent->parent->parent) != html_engine_get_table (e))
487 			return FALSE;
488 		if (html_cursor_precedes (e->cursor, e->mark)) {
489 			*start_cell = HTML_TABLE_CELL (e->cursor->object->parent->parent);
490 			*end_cell = HTML_TABLE_CELL (e->mark->object->parent->parent);
491 		} else {
492 			*start_cell = HTML_TABLE_CELL (e->mark->object->parent->parent);
493 			*end_cell = HTML_TABLE_CELL (e->cursor->object->parent->parent);
494 		}
495 	} else {
496 		*start_cell = *end_cell = html_engine_get_table_cell (e);
497 	}
498 
499 	return TRUE;
500 }
501 
502 /**
503  * html_engine_delete_table_column:
504  * @e: An HTML engine.
505  *
506  * Deletes current table column.
507  **/
508 
509 void
html_engine_delete_table_column(HTMLEngine * e)510 html_engine_delete_table_column (HTMLEngine *e)
511 {
512 	HTMLTableCell *start_cell, *end_cell;
513 	gint start_col, end_col;
514 	HTMLTable *table;
515 
516 	table = html_engine_get_table (e);
517 	if (!table || !HTML_IS_TABLE (table) ||
518 		!html_engine_get_table_start_end_cells (e, &start_cell, &end_cell))       {
519 		g_warning ("Invalid table object! Row deletion failed!");
520 		return;
521 	}
522 
523 	start_col = start_cell->col;
524 	end_col = end_cell->col;
525 	html_engine_disable_selection (e);
526 	if (start_cell->row == end_cell->row)
527 		while (start_col <= end_col--)
528 			html_table_delete_column (table, e, start_col, HTML_UNDO_UNDO);
529 	else
530 		if ((start_cell->row == end_cell->row - 1) &&
531 		   (start_col > end_col + 1)) {
532 			while (start_col < table->totalCols)
533 				html_table_delete_column (table, e, start_col, HTML_UNDO_UNDO);
534 			while (0 <= end_col--)
535 				html_table_delete_column (table, e, 0, HTML_UNDO_UNDO);
536 		}
537 		else
538 			html_engine_delete_table (e);
539 }
540 
541 /*
542  *  Insert Row
543  */
544 
545 static void
insert_row_undo_action(HTMLEngine * e,HTMLUndoData * data,HTMLUndoDirection dir,guint position_after)546 insert_row_undo_action (HTMLEngine *e,
547                         HTMLUndoData *data,
548                         HTMLUndoDirection dir,
549                         guint position_after)
550 {
551 	html_table_delete_row (html_engine_get_table (e), e, INSERT_UNDO (data)->pos, html_undo_direction_reverse (dir));
552 }
553 
554 static void
insert_row_setup_undo(HTMLEngine * e,gint row,guint position_before,HTMLUndoDirection dir)555 insert_row_setup_undo (HTMLEngine *e,
556                        gint row,
557                        guint position_before,
558                        HTMLUndoDirection dir)
559 {
560 	html_undo_add_action (e->undo, e,
561 			      html_undo_action_new ("Insert table row", insert_row_undo_action,
562 						    insert_undo_data_new (row),
563 						    html_cursor_get_position (e->cursor),
564 						    html_cursor_get_position (e->cursor)),
565 			      dir);
566 }
567 
568 void
html_table_insert_row(HTMLTable * t,HTMLEngine * e,gint row,HTMLTableCell ** row_cells,HTMLUndoDirection dir)569 html_table_insert_row (HTMLTable *t,
570                        HTMLEngine *e,
571                        gint row,
572                        HTMLTableCell **row_cells,
573                        HTMLUndoDirection dir)
574 {
575 	HTMLTableCell *cell;
576 	HTMLPoint pos;
577 	gint r, c;
578 	guint position_before;
579 
580 	html_engine_freeze (e);
581 	position_before = e->cursor->position;
582 	pos.object = e->cursor->object;
583 	pos.offset = e->cursor->offset;
584 	html_engine_goto_table_0 (e, t);
585 
586 	html_table_alloc_cell (t, t->totalRows, 0);
587 	for (r = t->totalRows; r > row; r--) {
588 		for (c = 0; c < t->totalCols; c++) {
589 			HTMLTableCell *cell = t->cells[r - 1][c];
590 
591 			if (cell) {
592 				if (cell->row == r - 1) {
593 					html_table_cell_set_position (cell, r, cell->col);
594 					t->cells[r - 1][c] = NULL;
595 				} else if (r == row + 1 && cell->col == c)
596 					cell->rspan++;
597 				if (cell->row > r - 1)
598 					t->cells[r - 1][c] = NULL;
599 				t->cells[r][c] = cell;
600 			}
601 		}
602 	}
603 	for (c = 0; c < t->totalCols; c++) {
604 		if (!t->cells[row][c]) {
605 			guint len;
606 
607 			cell = row_cells
608 				? HTML_TABLE_CELL (html_object_op_copy (HTML_OBJECT (row_cells[c]), HTML_OBJECT (t),
609 									e, NULL, NULL, &len))
610 				:  html_engine_new_cell (e, t);
611 			html_table_set_cell (t, row, c, cell);
612 			html_table_cell_set_position (t->cells[row][c], row, c);
613 		}
614 	}
615 
616 	html_cursor_jump_to (e->cursor, e, pos.object, pos.offset);
617 	insert_row_setup_undo (e, row, position_before, dir);
618 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
619 	html_engine_queue_draw (e, HTML_OBJECT (t));
620 	html_engine_thaw (e);
621 }
622 
623 /**
624  * html_engine_insert_table_row:
625  * @e: An HTML engine.
626  * @after: If TRUE then inserts new row after current one, defined by current cursor position.
627  *         If FALSE then inserts before current one.
628  *
629  * Inserts new row into table after/before current row.
630  **/
631 
632 void
html_engine_insert_table_row(HTMLEngine * e,gboolean after)633 html_engine_insert_table_row (HTMLEngine *e,
634                               gboolean after)
635 {
636 	HTMLTable *table;
637 	HTMLTableCell *cell;
638 
639 	table = html_engine_get_table (e);
640 	cell = html_engine_get_table_cell (e);
641 	if (table && cell)
642 		html_table_insert_row (table, e, cell->row + (after ? cell->rspan : 0), NULL, HTML_UNDO_UNDO);
643 }
644 
645 /*
646  * Delete row
647  */
648 
649 static void
delete_row_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)650 delete_row_undo_action (HTMLEngine *e,
651                         HTMLUndoData *undo_data,
652                         HTMLUndoDirection dir,
653                         guint position_after)
654 {
655 	DeleteCellsUndo *data = (DeleteCellsUndo *) undo_data;
656 	HTMLTable *table;
657 
658 	table = html_engine_get_table (e);
659 	if (!table) {
660 		html_cursor_jump_to_position (e->cursor, e, position_after + 1);
661 		table = html_engine_get_table (e);
662 	}
663 	g_assert (table);
664 	g_assert (data->size == table->totalCols);
665 	html_table_insert_row (table, e, data->pos, data->cells, html_undo_direction_reverse (dir));
666 }
667 
668 static void
delete_row_setup_undo(HTMLEngine * e,HTMLTableCell ** row_cells,gint size,guint position_after,gint row,HTMLUndoDirection dir)669 delete_row_setup_undo (HTMLEngine *e,
670                        HTMLTableCell **row_cells,
671                        gint size,
672                        guint position_after,
673                        gint row,
674                        HTMLUndoDirection dir)
675 {
676 	html_undo_add_action (e->undo, e,
677 			      html_undo_action_new ("Delete table row", delete_row_undo_action,
678 						    HTML_UNDO_DATA (delete_cells_undo_new (row_cells, size, row)),
679 						    html_cursor_get_position (e->cursor),
680 						    position_after), dir);
681 }
682 
683 static void
backward_before_row(HTMLEngine * e,HTMLTable * table,gint row)684 backward_before_row (HTMLEngine *e,
685                      HTMLTable *table,
686                      gint row)
687 {
688 	HTMLObject *cell;
689 
690 	do {
691 		if (!html_cursor_backward (e->cursor, e))
692 			return;
693 		cell = html_cursor_child_of (e->cursor, HTML_OBJECT (table));
694 	} while (cell && HTML_IS_TABLE_CELL (cell) && HTML_TABLE_CELL (cell)->row >= row);
695 }
696 
697 void
html_table_delete_row(HTMLTable * t,HTMLEngine * e,gint row,HTMLUndoDirection dir)698 html_table_delete_row (HTMLTable *t,
699                        HTMLEngine *e,
700                        gint row,
701                        HTMLUndoDirection dir)
702 {
703 	HTMLTableCell **row_cells;
704 	HTMLTableCell *cell;
705 	HTMLPoint pos;
706 	gint r, c;
707 	guint position_after;
708 
709 	/* this command is valid only in table and when this table has > 1 row */
710 	if (!t || t->totalRows < 2)
711 		return;
712 
713 	html_engine_freeze (e);
714 
715 	row_cells = g_new0 (HTMLTableCell *, t->totalCols);
716 
717 	backward_before_row (e, t, row);
718 	pos.object = e->cursor->object;
719 	pos.offset = e->cursor->offset;
720 
721 	html_engine_goto_table_0 (e, t);
722 	for (c = 0; c < t->totalCols; c++) {
723 		cell = t->cells[row][c];
724 
725 		/* remove & keep old one */
726 		if (cell && cell->row == row) {
727 			HTML_OBJECT (cell)->parent = NULL;
728 			row_cells[c] = cell;
729 			t->cells[row][c] = NULL;
730 		}
731 
732 		for (r = row + 1; r < t->totalRows; r++) {
733 			cell = t->cells[r][c];
734 			if (cell && cell->row != row) {
735 				if (cell->row == r && cell->col == c)
736 					html_table_cell_set_position (cell, r - 1, c);
737 				t->cells[r - 1][c] = cell;
738 				t->cells[r][c]     = NULL;
739 			}
740 		}
741 	}
742 
743 	html_cursor_jump_to (e->cursor, e, pos.object, pos.offset);
744 	t->totalRows--;
745 	position_after = e->cursor->position;
746 	delete_row_setup_undo (e, row_cells, t->totalCols, position_after, row, dir);
747 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
748 	html_engine_queue_draw (e, HTML_OBJECT (t));
749 	html_engine_thaw (e);
750 }
751 
752 /**
753  * html_engine_delete_table_row:
754  * @e: An HTML engine.
755  *
756  * Deletes current table row.
757  **/
758 
759 void
html_engine_delete_table_row(HTMLEngine * e)760 html_engine_delete_table_row (HTMLEngine *e)
761 {
762 	HTMLTableCell *start_cell, *end_cell;
763 	gint start_row, end_row;
764 	HTMLTable *table;
765 
766 	table = html_engine_get_table (e);
767 	if (!table || !HTML_IS_TABLE (table) ||
768 		!html_engine_get_table_start_end_cells (e, &start_cell, &end_cell))	{
769 		g_warning ("Invalid table object! Row deletion failed!");
770 		return;
771 	}
772 
773 	start_row = start_cell->row;
774 	end_row = end_cell->row;
775 	html_engine_disable_selection (e);
776 	if (end_row - start_row == table->totalRows - 1)
777 		html_engine_delete_table (e);
778 	else
779 		while (start_row <= end_row--)
780 			html_table_delete_row (table, e, start_row, HTML_UNDO_UNDO);
781 }
782 
783 typedef enum {
784 	HTML_TABLE_BORDER,
785 	HTML_TABLE_PADDING,
786 	HTML_TABLE_SPACING,
787 	HTML_TABLE_WIDTH,
788 	HTML_TABLE_BGCOLOR,
789 	HTML_TABLE_BGPIXMAP,
790 	HTML_TABLE_ALIGN
791 } HTMLTableAttrType;
792 
793 union _HTMLTableUndoAttr {
794 	gint border;
795 	gint spacing;
796 	gint padding;
797 
798 	gchar *pixmap;
799 
800 	struct {
801 		gint width;
802 		gboolean percent;
803 	} width;
804 
805 	struct {
806 		GdkColor color;
807 		gboolean has_bg_color;
808 	} color;
809 
810 	HTMLHAlignType align;
811 };
812 typedef union _HTMLTableUndoAttr HTMLTableUndoAttr;
813 
814 struct _HTMLTableSetAttrUndo {
815 	HTMLUndoData data;
816 
817 	HTMLTableUndoAttr attr;
818 	HTMLTableAttrType type;
819 };
820 typedef struct _HTMLTableSetAttrUndo HTMLTableSetAttrUndo;
821 
822 static void
attr_destroy(HTMLUndoData * undo_data)823 attr_destroy (HTMLUndoData *undo_data)
824 {
825 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
826 
827 	switch (data->type) {
828 	case HTML_TABLE_BGPIXMAP:
829 		g_free (data->attr.pixmap);
830 		break;
831 	default:
832 		;
833 	}
834 }
835 
836 static HTMLTableSetAttrUndo *
attr_undo_new(HTMLTableAttrType type)837 attr_undo_new (HTMLTableAttrType type)
838 {
839 	HTMLTableSetAttrUndo *undo = g_new (HTMLTableSetAttrUndo, 1);
840 
841 	html_undo_data_init (HTML_UNDO_DATA (undo));
842 	undo->data.destroy = attr_destroy;
843 	undo->type         = type;
844 
845 	return undo;
846 }
847 
848 /*
849  * Border width
850  */
851 
852 static void table_set_border_width (HTMLEngine *e, HTMLTable *t, gint border_width, gboolean relative, HTMLUndoDirection dir);
853 
854 static void
table_set_border_width_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)855 table_set_border_width_undo_action (HTMLEngine *e,
856                                     HTMLUndoData *undo_data,
857                                     HTMLUndoDirection dir,
858                                     guint position_after)
859 {
860 	table_set_border_width (e, html_engine_get_table (e), ((HTMLTableSetAttrUndo *) undo_data)->attr.border, FALSE,
861 				html_undo_direction_reverse (dir));
862 }
863 
864 static void
table_set_border_width(HTMLEngine * e,HTMLTable * t,gint border_width,gboolean relative,HTMLUndoDirection dir)865 table_set_border_width (HTMLEngine *e,
866                         HTMLTable *t,
867                         gint border_width,
868                         gboolean relative,
869                         HTMLUndoDirection dir)
870 {
871 	HTMLTableSetAttrUndo *undo;
872 	gint new_border;
873 
874 	if (!t || !HTML_IS_TABLE (t))
875 		return;
876 
877 	if (relative)
878 		new_border = t->border + border_width;
879 	else
880 		new_border = border_width;
881 	if (new_border < 0)
882 		new_border = 0;
883 	if (new_border == t->border)
884 		return;
885 
886 	undo = attr_undo_new (HTML_TABLE_BORDER);
887 	undo->attr.border = t->border;
888 
889 	html_engine_freeze (e);
890 	t->border = new_border;
891 
892 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
893 	html_engine_thaw (e);
894 
895 	html_undo_add_action (e->undo, e,
896 			      html_undo_action_new ("Set table border width", table_set_border_width_undo_action,
897 						    HTML_UNDO_DATA (undo), html_cursor_get_position (e->cursor),
898 						    html_cursor_get_position (e->cursor)), dir);
899 }
900 
901 void
html_engine_table_set_border_width(HTMLEngine * e,HTMLTable * t,gint border_width,gboolean relative)902 html_engine_table_set_border_width (HTMLEngine *e,
903                                     HTMLTable *t,
904                                     gint border_width,
905                                     gboolean relative)
906 {
907 	table_set_border_width (e, t, border_width, relative, HTML_UNDO_UNDO);
908 }
909 
910 /*
911  * bg color
912  *
913  */
914 
915 static void table_set_bg_color (HTMLEngine *e, HTMLTable *t, GdkColor *c, HTMLUndoDirection dir);
916 
917 static void
table_set_bg_color_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)918 table_set_bg_color_undo_action (HTMLEngine *e,
919                                 HTMLUndoData *undo_data,
920                                 HTMLUndoDirection dir,
921                                 guint position_after)
922 {
923 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
924 	HTMLTable *table = html_engine_get_table (e);
925 
926 	if (!table)
927 		return;
928 
929 	table_set_bg_color (e, table, data->attr.color.has_bg_color
930 			    ? &data->attr.color.color : NULL, html_undo_direction_reverse (dir));
931 }
932 
933 static void
table_set_bg_color(HTMLEngine * e,HTMLTable * t,GdkColor * c,HTMLUndoDirection dir)934 table_set_bg_color (HTMLEngine *e,
935                     HTMLTable *t,
936                     GdkColor *c,
937                     HTMLUndoDirection dir)
938 {
939 	HTMLTableSetAttrUndo *undo;
940 
941 	undo = attr_undo_new (HTML_TABLE_BGCOLOR);
942 	if (t->bgColor) {
943 		undo->attr.color.color        = *t->bgColor;
944 		undo->attr.color.has_bg_color = TRUE;
945 	} else
946 		undo->attr.color.has_bg_color = FALSE;
947 	html_undo_add_action (e->undo, e,
948 			      html_undo_action_new ("Set table background color", table_set_bg_color_undo_action,
949 						    HTML_UNDO_DATA (undo),
950 						    html_cursor_get_position (e->cursor),
951 						    html_cursor_get_position (e->cursor)), dir);
952 	if (c) {
953 		if (!t->bgColor)
954 			t->bgColor = gdk_color_copy (c);
955 		*t->bgColor = *c;
956 	} else {
957 		if (t->bgColor)
958 			gdk_color_free (t->bgColor);
959 		t->bgColor = NULL;
960 	}
961 	html_engine_queue_draw (e, HTML_OBJECT (t));
962 }
963 
964 void
html_engine_table_set_bg_color(HTMLEngine * e,HTMLTable * t,GdkColor * c)965 html_engine_table_set_bg_color (HTMLEngine *e,
966                                 HTMLTable *t,
967                                 GdkColor *c)
968 {
969 	table_set_bg_color (e, t, c, HTML_UNDO_UNDO);
970 }
971 
972 /*
973  * bg pixmap
974  *
975  */
976 
977 static void table_set_bg_pixmap (HTMLEngine *e, HTMLTable *t, gchar *url, HTMLUndoDirection dir);
978 
979 static void
table_set_bg_pixmap_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)980 table_set_bg_pixmap_undo_action (HTMLEngine *e,
981                                  HTMLUndoData *undo_data,
982                                  HTMLUndoDirection dir,
983                                  guint position_after)
984 {
985 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
986 
987 	table_set_bg_pixmap (e, html_engine_get_table (e), data->attr.pixmap, html_undo_direction_reverse (dir));
988 }
989 
990 static void
table_set_bg_pixmap(HTMLEngine * e,HTMLTable * t,gchar * url,HTMLUndoDirection dir)991 table_set_bg_pixmap (HTMLEngine *e,
992                      HTMLTable *t,
993                      gchar *url,
994                      HTMLUndoDirection dir)
995 {
996 	HTMLImagePointer *iptr;
997 	HTMLTableSetAttrUndo *undo;
998 
999 	undo = attr_undo_new (HTML_TABLE_BGPIXMAP);
1000 	undo->attr.pixmap = t->bgPixmap ? g_strdup (t->bgPixmap->url) : NULL;
1001 	html_undo_add_action (e->undo, e,
1002 			      html_undo_action_new ("Set table background pixmap", table_set_bg_pixmap_undo_action,
1003 						    HTML_UNDO_DATA (undo),
1004 						    html_cursor_get_position (e->cursor),
1005 						    html_cursor_get_position (e->cursor)), dir);
1006 
1007 	iptr = t->bgPixmap;
1008 	t->bgPixmap = url ? html_image_factory_register (e->image_factory, NULL, url, TRUE) : NULL;
1009 	if (iptr)
1010 		html_image_factory_unregister (e->image_factory, iptr, NULL);
1011 	html_engine_queue_draw (e, HTML_OBJECT (t));
1012 }
1013 
1014 void
html_engine_table_set_bg_pixmap(HTMLEngine * e,HTMLTable * t,gchar * url)1015 html_engine_table_set_bg_pixmap (HTMLEngine *e,
1016                                  HTMLTable *t,
1017                                  gchar *url)
1018 {
1019 	table_set_bg_pixmap (e, t, url, HTML_UNDO_UNDO);
1020 }
1021 
1022 /*
1023  * spacing
1024  *
1025  */
1026 
1027 static void table_set_spacing (HTMLEngine *e, HTMLTable *t, gint spacing, gboolean relative, HTMLUndoDirection dir);
1028 
1029 static void
table_set_spacing_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)1030 table_set_spacing_undo_action (HTMLEngine *e,
1031                                HTMLUndoData *undo_data,
1032                                HTMLUndoDirection dir,
1033                                guint position_after)
1034 {
1035 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
1036 
1037 	table_set_spacing (e, html_engine_get_table (e), data->attr.spacing, FALSE, html_undo_direction_reverse (dir));
1038 }
1039 
1040 static void
table_set_spacing(HTMLEngine * e,HTMLTable * t,gint spacing,gboolean relative,HTMLUndoDirection dir)1041 table_set_spacing (HTMLEngine *e,
1042                    HTMLTable *t,
1043                    gint spacing,
1044                    gboolean relative,
1045                    HTMLUndoDirection dir)
1046 {
1047 	HTMLTableSetAttrUndo *undo;
1048 	gint new_spacing;
1049 
1050 	if (!t || !HTML_IS_TABLE (t))
1051 		return;
1052 
1053 	if (relative)
1054 		new_spacing = t->spacing + spacing;
1055 	else
1056 		new_spacing = spacing;
1057 	if (new_spacing < 0)
1058 		new_spacing = 0;
1059 	if (new_spacing == t->spacing)
1060 		return;
1061 
1062 	undo = attr_undo_new (HTML_TABLE_SPACING);
1063 	undo->attr.spacing = t->spacing;
1064 	html_undo_add_action (e->undo, e,
1065 			      html_undo_action_new ("Set table spacing", table_set_spacing_undo_action,
1066 						    HTML_UNDO_DATA (undo),
1067 						    html_cursor_get_position (e->cursor),
1068 						    html_cursor_get_position (e->cursor)), dir);
1069 	t->spacing = new_spacing;
1070 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
1071 	html_engine_schedule_update (e);
1072 }
1073 
1074 void
html_engine_table_set_spacing(HTMLEngine * e,HTMLTable * t,gint spacing,gboolean relative)1075 html_engine_table_set_spacing (HTMLEngine *e,
1076                                HTMLTable *t,
1077                                gint spacing,
1078                                gboolean relative)
1079 {
1080 	table_set_spacing (e, t, spacing, relative, HTML_UNDO_UNDO);
1081 }
1082 
1083 /*
1084  * padding
1085  *
1086  */
1087 
1088 static void table_set_padding (HTMLEngine *e, HTMLTable *t, gint padding, gboolean relative, HTMLUndoDirection dir);
1089 
1090 static void
table_set_padding_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)1091 table_set_padding_undo_action (HTMLEngine *e,
1092                                HTMLUndoData *undo_data,
1093                                HTMLUndoDirection dir,
1094                                guint position_after)
1095 {
1096 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
1097 
1098 	table_set_padding (e, html_engine_get_table (e), data->attr.padding, FALSE, html_undo_direction_reverse (dir));
1099 }
1100 
1101 static void
table_set_padding(HTMLEngine * e,HTMLTable * t,gint padding,gboolean relative,HTMLUndoDirection dir)1102 table_set_padding (HTMLEngine *e,
1103                    HTMLTable *t,
1104                    gint padding,
1105                    gboolean relative,
1106                    HTMLUndoDirection dir)
1107 {
1108 	HTMLTableSetAttrUndo *undo;
1109 	gint r, c;
1110 	gint new_padding;
1111 
1112 	if (!t || !HTML_IS_TABLE (t))
1113 		return;
1114 
1115 	if (relative)
1116 		new_padding = t->padding + padding;
1117 	else
1118 		new_padding = padding;
1119 	if (new_padding < 0)
1120 		new_padding = 0;
1121 	if (new_padding == t->padding)
1122 		return;
1123 
1124 	undo = attr_undo_new (HTML_TABLE_PADDING);
1125 	undo->attr.padding = t->padding;
1126 	html_undo_add_action (e->undo, e,
1127 			      html_undo_action_new ("Set table padding", table_set_padding_undo_action,
1128 						    HTML_UNDO_DATA (undo),
1129 						    html_cursor_get_position (e->cursor),
1130 						    html_cursor_get_position (e->cursor)), dir);
1131 
1132 	t->padding = new_padding;
1133 	for (r = 0; r < t->totalRows; r++)
1134 		for (c = 0; c < t->totalCols; c++)
1135 			if (t->cells[r][c]->col == c && t->cells[r][c]->row == r) {
1136 				HTML_CLUEV (t->cells[r][c])->padding = new_padding;
1137 				HTML_OBJECT (t->cells[r][c])->change |= HTML_CHANGE_ALL_CALC;
1138 			}
1139 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
1140 	html_engine_schedule_update (e);
1141 }
1142 
1143 void
html_engine_table_set_padding(HTMLEngine * e,HTMLTable * t,gint padding,gboolean relative)1144 html_engine_table_set_padding (HTMLEngine *e,
1145                                HTMLTable *t,
1146                                gint padding,
1147                                gboolean relative)
1148 {
1149 	table_set_padding (e, t, padding, relative, HTML_UNDO_UNDO);
1150 }
1151 
1152 /*
1153  * align
1154  *
1155  */
1156 
1157 static void table_set_align (HTMLEngine *e, HTMLTable *t, HTMLHAlignType align, HTMLUndoDirection dir);
1158 
1159 static void
table_set_align_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)1160 table_set_align_undo_action (HTMLEngine *e,
1161                              HTMLUndoData *undo_data,
1162                              HTMLUndoDirection dir,
1163                              guint position_after)
1164 {
1165 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
1166 
1167 	table_set_align (e, html_engine_get_table (e), data->attr.align, html_undo_direction_reverse (dir));
1168 }
1169 
1170 static void
table_set_align(HTMLEngine * e,HTMLTable * t,HTMLHAlignType align,HTMLUndoDirection dir)1171 table_set_align (HTMLEngine *e,
1172                  HTMLTable *t,
1173                  HTMLHAlignType align,
1174                  HTMLUndoDirection dir)
1175 {
1176 	HTMLTableSetAttrUndo *undo;
1177 
1178 	/* table gone */
1179 	if (!t)
1180 		return;
1181 
1182 	g_return_if_fail (HTML_OBJECT (t)->parent);
1183 
1184 	undo = attr_undo_new (HTML_TABLE_ALIGN);
1185 	undo->attr.align = HTML_CLUE (HTML_OBJECT (t)->parent)->halign;
1186 
1187 	if (align == HTML_HALIGN_NONE || align == HTML_HALIGN_CENTER) {
1188 		if (HTML_IS_CLUEALIGNED (HTML_OBJECT (t)->parent)) {
1189 			HTMLObject *aclue = HTML_OBJECT (t)->parent;
1190 
1191 			html_clue_remove (HTML_CLUE (aclue), HTML_OBJECT (t));
1192 			html_clue_append_after (HTML_CLUE (aclue->parent), HTML_OBJECT (t), aclue);
1193 			html_clue_remove (HTML_CLUE (aclue->parent), aclue);
1194 			html_object_destroy (aclue);
1195 		}
1196 	} else if (align == HTML_HALIGN_LEFT || align == HTML_HALIGN_RIGHT) {
1197 		if (HTML_IS_CLUEFLOW (HTML_OBJECT (t)->parent)) {
1198 			HTMLObject *aclue, *flow = HTML_OBJECT (t)->parent;
1199 
1200 			html_clue_remove (HTML_CLUE (flow), HTML_OBJECT (t));
1201 			aclue = html_cluealigned_new (NULL, 0, 0, flow->max_width, 100);
1202 			html_clue_append (HTML_CLUE (flow), aclue);
1203 			html_clue_append (HTML_CLUE (aclue), HTML_OBJECT (t));
1204 		}
1205 	} else
1206 		g_assert_not_reached ();
1207 
1208 	html_undo_add_action (e->undo, e,
1209 			      html_undo_action_new ("Set table align", table_set_align_undo_action,
1210 						    HTML_UNDO_DATA (undo),
1211 						    html_cursor_get_position (e->cursor),
1212 						    html_cursor_get_position (e->cursor)), dir);
1213 
1214 	HTML_CLUE (HTML_OBJECT (t)->parent)->halign = align;
1215 	html_object_change_set (HTML_OBJECT (t)->parent, HTML_CHANGE_ALL_CALC);
1216 	html_engine_schedule_update (e);
1217 }
1218 
1219 void
html_engine_table_set_align(HTMLEngine * e,HTMLTable * t,HTMLHAlignType align)1220 html_engine_table_set_align (HTMLEngine *e,
1221                              HTMLTable *t,
1222                              HTMLHAlignType align)
1223 {
1224 	table_set_align (e, t, align, HTML_UNDO_UNDO);
1225 }
1226 
1227 /*
1228  * width
1229  *
1230  */
1231 
1232 static void table_set_width (HTMLEngine *e, HTMLTable *t, gint width, gboolean percent, HTMLUndoDirection dir);
1233 
1234 static void
table_set_width_undo_action(HTMLEngine * e,HTMLUndoData * undo_data,HTMLUndoDirection dir,guint position_after)1235 table_set_width_undo_action (HTMLEngine *e,
1236                              HTMLUndoData *undo_data,
1237                              HTMLUndoDirection dir,
1238                              guint position_after)
1239 {
1240 	HTMLTableSetAttrUndo *data = (HTMLTableSetAttrUndo *) undo_data;
1241 
1242 	table_set_width (e, html_engine_get_table (e), data->attr.width.width, data->attr.width.percent,
1243 			 html_undo_direction_reverse (dir));
1244 }
1245 
1246 static void
table_set_width(HTMLEngine * e,HTMLTable * t,gint width,gboolean percent,HTMLUndoDirection dir)1247 table_set_width (HTMLEngine *e,
1248                  HTMLTable *t,
1249                  gint width,
1250                  gboolean percent,
1251                  HTMLUndoDirection dir)
1252 {
1253 	HTMLTableSetAttrUndo *undo;
1254 
1255 	undo = attr_undo_new (HTML_TABLE_WIDTH);
1256 	undo->attr.width.width = HTML_OBJECT (t)->percent
1257 		? HTML_OBJECT (t)->percent
1258 		: (HTML_OBJECT (t)->flags & HTML_OBJECT_FLAG_FIXEDWIDTH
1259 		   ? t->specified_width : 0);
1260 	undo->attr.width.percent = HTML_OBJECT (t)->percent != 0;
1261 	html_undo_add_action (e->undo, e,
1262 			      html_undo_action_new ("Set table width", table_set_width_undo_action,
1263 						    HTML_UNDO_DATA (undo),
1264 						    html_cursor_get_position (e->cursor),
1265 						    html_cursor_get_position (e->cursor)), dir);
1266 
1267 	if (percent) {
1268 		HTML_OBJECT (t)->percent = width;
1269 		HTML_OBJECT (t)->flags  &= ~ HTML_OBJECT_FLAG_FIXEDWIDTH;
1270 		t->specified_width       = 0;
1271 	} else {
1272 		HTML_OBJECT (t)->percent = 0;
1273 		t->specified_width       = width;
1274 		if (width)
1275 			HTML_OBJECT (t)->flags |= HTML_OBJECT_FLAG_FIXEDWIDTH;
1276 		else
1277 			HTML_OBJECT (t)->flags &= ~ HTML_OBJECT_FLAG_FIXEDWIDTH;
1278 	}
1279 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
1280 	html_engine_schedule_update (e);
1281 }
1282 
1283 void
html_engine_table_set_width(HTMLEngine * e,HTMLTable * t,gint width,gboolean percent)1284 html_engine_table_set_width (HTMLEngine *e,
1285                              HTMLTable *t,
1286                              gint width,
1287                              gboolean percent)
1288 {
1289 	table_set_width (e, t, width, percent, HTML_UNDO_UNDO);
1290 }
1291 
1292 /*
1293  * set number of columns in current table
1294  */
1295 
1296 void
html_engine_table_set_cols(HTMLEngine * e,gint cols)1297 html_engine_table_set_cols (HTMLEngine *e,
1298                             gint cols)
1299 {
1300 	HTMLTable *table = html_engine_get_table (e);
1301 
1302 	if (!table)
1303 		return;
1304 
1305 	if (table->totalCols == cols)
1306 		return;
1307 
1308 	if (table->totalCols < cols) {
1309 		gint n = cols - table->totalCols;
1310 
1311 		for (; n > 0; n--)
1312 			html_table_insert_column (table, e, table->totalCols, NULL, HTML_UNDO_UNDO);
1313 	} else {
1314 		gint n = table->totalCols - cols;
1315 
1316 		for (; n > 0; n--)
1317 			html_table_delete_column (table, e, table->totalCols - 1, HTML_UNDO_UNDO);
1318 	}
1319 }
1320 
1321 /*
1322  * set number of rows in current table
1323  */
1324 
1325 void
html_engine_table_set_rows(HTMLEngine * e,gint rows)1326 html_engine_table_set_rows (HTMLEngine *e,
1327                             gint rows)
1328 {
1329 	HTMLTable *table = html_engine_get_table (e);
1330 
1331 	if (!table)
1332 		return;
1333 
1334 	if (table->totalRows == rows)
1335 		return;
1336 
1337 	if (table->totalRows < rows) {
1338 		gint n = rows - table->totalRows;
1339 
1340 		for (; n > 0; n--)
1341 			html_table_insert_row (table, e, table->totalRows, NULL, HTML_UNDO_UNDO);
1342 	} else {
1343 		gint n = table->totalRows - rows;
1344 
1345 		for (; n > 0; n--)
1346 			html_table_delete_row (table, e, table->totalRows - 1, HTML_UNDO_UNDO);
1347 	}
1348 }
1349 
1350 void
html_engine_delete_table(HTMLEngine * e)1351 html_engine_delete_table (HTMLEngine *e)
1352 {
1353 	HTMLTable *table;
1354 
1355 	html_engine_disable_selection (e);
1356 
1357 	table = html_engine_get_table (e);
1358 
1359 	if (!table)
1360 		return;
1361 	while (e->cursor->object != HTML_OBJECT (table) || e->cursor->offset)
1362 		html_cursor_backward (e->cursor, e);
1363 	html_engine_set_mark (e);
1364 	html_cursor_end_of_line (e->cursor, e);
1365 	html_engine_delete (e);
1366 }
1367