source: trunk/third/gtkhtml3/src/htmlengine-edit-clueflowstyle.c @ 19539

Revision 19539, 11.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19538, 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) 2000 Helix Code, Inc.
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20*/
21
22#include <config.h>
23#include "htmlengine-edit-clueflowstyle.h"
24#include "htmlundo.h"
25#include "htmltype.h"
26#include "htmlcursor.h"
27#include "htmlselection.h"
28
29
30/* Properties of a paragraph.  */
31struct _ClueFlowProps {
32        HTMLClueFlowStyle style;
33        HTMLListType item_type;
34        HTMLHAlignType alignment;
35        GByteArray *levels;
36};
37typedef struct _ClueFlowProps ClueFlowProps;
38
39/* Data for the redo/undo operation.  */
40struct _ClueFlowStyleOperation {
41        HTMLUndoData data;
42       
43        /* Whether we should go backward or forward when re-setting
44           the style.  */
45        gboolean forward;
46
47        /* List of properties for the paragraphs (ClueFlowProps).  */
48        GList *prop_list;
49};
50typedef struct _ClueFlowStyleOperation ClueFlowStyleOperation;
51
52static void
53free_prop (ClueFlowProps *props)
54{
55        g_byte_array_free (props->levels, TRUE);
56        g_free (props);
57}
58
59static void
60free_prop_list (GList *list)
61{
62        GList *p;
63
64        for (p = list; p != NULL; p = p->next) {
65                ClueFlowProps *props;
66
67                props = (ClueFlowProps *) p->data;
68                free_prop (props);
69        }
70
71        g_list_free (list);
72}
73
74static void
75style_operation_destroy (HTMLUndoData *data)
76{
77        free_prop_list (((ClueFlowStyleOperation *) data)->prop_list);
78}
79
80static ClueFlowStyleOperation *
81style_operation_new (GList *prop_list, gboolean forward)
82{
83        ClueFlowStyleOperation *op;
84
85        op = g_new (ClueFlowStyleOperation, 1);
86
87        html_undo_data_init (HTML_UNDO_DATA (op));
88
89        op->data.destroy = style_operation_destroy;
90        op->prop_list    = prop_list;
91        op->forward      = forward;
92
93        return op;
94}
95
96static ClueFlowProps *
97get_props (HTMLClueFlow *clueflow)
98{
99        ClueFlowProps *props;
100
101        props = g_new (ClueFlowProps, 1);
102
103        props->levels      = html_clueflow_dup_levels (clueflow);
104        props->alignment   = html_clueflow_get_halignment (clueflow);
105        props->style       = html_clueflow_get_style (clueflow);
106        props->item_type   = html_clueflow_get_item_type (clueflow);
107
108        return props;
109}
110
111
112static void
113set_props (HTMLEngine *engine,
114           HTMLClueFlow *clueflow,
115           HTMLClueFlowStyle style,
116           HTMLListType item_type,
117           HTMLHAlignType alignment,
118           gint indentation_delta,
119           guint8 *indentation_levels,
120           HTMLEngineSetClueFlowStyleMask mask)
121{
122        if (mask & HTML_ENGINE_SET_CLUEFLOW_INDENTATION)
123                html_clueflow_set_indentation (clueflow, engine, indentation_delta, indentation_levels);
124       
125        if (mask & HTML_ENGINE_SET_CLUEFLOW_INDENTATION_DELTA)
126                html_clueflow_modify_indentation_by_delta (clueflow, engine, indentation_delta, indentation_levels);
127       
128        /* FIXME levels mostly work now */
129        if (mask & HTML_ENGINE_SET_CLUEFLOW_STYLE) {
130                if (style == HTML_CLUEFLOW_STYLE_LIST_ITEM && clueflow->style != HTML_CLUEFLOW_STYLE_LIST_ITEM
131                    && clueflow->levels->len == 0
132                    && !(mask & (HTML_ENGINE_SET_CLUEFLOW_INDENTATION | HTML_ENGINE_SET_CLUEFLOW_INDENTATION_DELTA))) {
133                        guint8 tmp = item_type;
134                        html_clueflow_set_indentation (clueflow, engine, 1, &tmp);
135                } else if (clueflow->style == HTML_CLUEFLOW_STYLE_LIST_ITEM && style != HTML_CLUEFLOW_STYLE_LIST_ITEM
136                           && clueflow->levels->len == 1
137                           && !(mask & (HTML_ENGINE_SET_CLUEFLOW_INDENTATION | HTML_ENGINE_SET_CLUEFLOW_INDENTATION_DELTA))) {
138                        html_clueflow_set_indentation (clueflow, engine, 0, NULL);
139                }
140                html_clueflow_set_style (clueflow, engine, style);
141                html_clueflow_set_item_type (clueflow, engine, item_type);
142                html_object_change_set_down (HTML_OBJECT (clueflow), HTML_CHANGE_ALL);
143        }
144        if (mask & HTML_ENGINE_SET_CLUEFLOW_ALIGNMENT)
145                html_clueflow_set_halignment (clueflow, engine, alignment);
146       
147}
148
149
150/* Undo/redo operations.  */
151
152static void add_undo (HTMLEngine *engine, ClueFlowStyleOperation *op, HTMLUndoDirection dir);
153
154static void
155undo_or_redo (HTMLEngine *engine, HTMLUndoData *data, HTMLUndoDirection dir, guint position_after)
156{
157        ClueFlowStyleOperation *op, *new_op;
158        ClueFlowProps *props, *orig_props;
159        HTMLObject *obj;
160        HTMLClueFlow *clueflow;
161        GList *prop_list;
162        GList *p;
163
164        op = (ClueFlowStyleOperation *) data;
165        g_assert (op != NULL);
166        g_assert (op->prop_list != NULL);
167
168        obj = engine->cursor->object;
169        g_assert (obj != NULL);
170
171        prop_list = NULL;
172
173        p = op->prop_list;
174
175        while (p != NULL) {
176                if (HTML_OBJECT_TYPE (obj->parent) != HTML_TYPE_CLUEFLOW) {
177                        g_warning ("(%s:%s)  Eeeek!  Unknown parent type `%s'.",
178                                   __FILE__, G_GNUC_FUNCTION,
179                                   html_type_name (HTML_OBJECT_TYPE (obj->parent)));
180                        break;
181                }
182
183                clueflow = HTML_CLUEFLOW (obj->parent);
184
185                orig_props = get_props (clueflow);
186                prop_list = g_list_prepend (prop_list, orig_props);
187
188                props = (ClueFlowProps *) p->data;
189
190                html_clueflow_set_levels (clueflow, engine, props->levels);
191                html_clueflow_set_style (clueflow, engine, props->style);
192                html_clueflow_set_item_type (clueflow, engine, props->item_type);
193                html_clueflow_set_levels (clueflow, engine, props->levels);
194                html_clueflow_set_halignment (clueflow, engine, props->alignment);
195
196                p = p->next;
197                if (p == NULL)
198                        break;
199
200                /* Go forward object by object, until we find one
201                   whose parent (i.e. paragraph) is different.  */
202                do {
203                        if (op->forward)
204                                obj = html_object_next_leaf (obj);
205                        else
206                                obj = html_object_prev_leaf (obj);
207
208                        if (obj == NULL) {
209                                /* This should not happen.  */
210                                g_warning ("(%s:%s)  There were not enough paragraphs for "
211                                           "setting the paragraph style.",
212                                           __FILE__, G_GNUC_FUNCTION);
213                                break;
214                        }
215                } while (obj != NULL && HTML_CLUEFLOW (obj->parent) == clueflow);
216        }
217
218        if (prop_list == NULL) {
219                /* This should not happen.  */
220                g_warning ("%s:%s Eeek!  Nothing done?", __FILE__, G_GNUC_FUNCTION);
221                return;
222        }
223
224        prop_list = g_list_reverse (prop_list);
225
226        new_op = style_operation_new (prop_list, op->forward);
227
228        add_undo (engine, new_op, html_undo_direction_reverse (dir));
229}
230
231static HTMLUndoAction *
232undo_action_from_op (HTMLEngine *engine,
233                     ClueFlowStyleOperation *op)
234{
235        return html_undo_action_new ("Paragraph style change",
236                                     undo_or_redo, HTML_UNDO_DATA (op),
237                                     html_cursor_get_position (engine->cursor),
238                                     html_cursor_get_position (engine->cursor));
239}
240
241static void
242add_undo (HTMLEngine *engine,
243          ClueFlowStyleOperation *op, HTMLUndoDirection dir)
244{
245        html_undo_add_action (engine->undo, undo_action_from_op (engine, op), dir);
246}
247
248
249/* "Do" operations.  */
250
251static void
252set_clueflow_style_in_region (HTMLEngine *engine,
253                              HTMLClueFlowStyle style,
254                              HTMLListType item_type,
255                              HTMLHAlignType alignment,
256                              gint indentation_delta,
257                              guint8 *indentation_levels,
258                              HTMLEngineSetClueFlowStyleMask mask,
259                              HTMLUndoDirection dir,
260                              gboolean do_undo)
261{
262        HTMLClueFlow *clueflow;
263        HTMLObject *start, *end, *p;
264        GList *prop_list;
265        gboolean undo_forward;
266
267        if (html_cursor_precedes (engine->cursor, engine->mark)) {
268                start = engine->cursor->object;
269                end = engine->mark->object;
270                undo_forward = TRUE;
271        } else {
272                start = engine->mark->object;
273                end = engine->cursor->object;
274                undo_forward = FALSE;
275        }
276
277        prop_list = NULL;
278
279        p = start;
280        while (p != NULL) {
281                if (HTML_OBJECT_TYPE (p->parent) != HTML_TYPE_CLUEFLOW) {
282                        g_warning ("(%s:%s)  Eeeek!  Unknown parent type `%s'.",
283                                   __FILE__, G_GNUC_FUNCTION,
284                                   html_type_name (HTML_OBJECT_TYPE (p->parent)));
285                        break;
286                }
287
288                clueflow = HTML_CLUEFLOW (p->parent);
289
290                if (do_undo)
291                        prop_list = g_list_prepend (prop_list, get_props (clueflow));
292
293                set_props (engine, clueflow,
294                           style, item_type, alignment, indentation_delta, indentation_levels,
295                           mask);
296               
297                if (p == end)
298                        break;
299
300                do {
301                        p = html_object_next_leaf (p);
302                } while (p != NULL && p != end && HTML_CLUEFLOW (p->parent) == clueflow);
303
304                if (p == end && HTML_CLUEFLOW (p->parent) == clueflow)
305                        break;
306        }
307
308        if (! do_undo)
309                return;
310
311        add_undo (engine, style_operation_new (undo_forward ? g_list_reverse (prop_list) : prop_list, undo_forward), dir);
312}
313
314static void
315set_clueflow_style_at_cursor (HTMLEngine *engine,
316                              HTMLClueFlowStyle style,
317                              HTMLListType item_type,
318                              HTMLHAlignType alignment,
319                              gint indentation_delta,
320                              guint8 *indentation_levels,
321                              HTMLEngineSetClueFlowStyleMask mask,
322                              HTMLUndoDirection dir, gboolean do_undo)
323{
324        HTMLClueFlow *clueflow;
325        HTMLObject *curr;
326
327        curr = engine->cursor->object;
328
329        g_return_if_fail (curr != NULL);
330        g_return_if_fail (curr->parent != NULL);
331        g_return_if_fail (HTML_OBJECT_TYPE (curr->parent) == HTML_TYPE_CLUEFLOW);
332
333        clueflow = HTML_CLUEFLOW (curr->parent);
334
335        if (do_undo)
336                add_undo (engine, style_operation_new (g_list_append (NULL, get_props (clueflow)), TRUE), dir);
337
338        set_props (engine, clueflow,
339                   style, item_type, alignment,
340                   indentation_delta,
341                   indentation_levels,
342                   mask);
343
344}
345
346
347gboolean
348html_engine_set_clueflow_style (HTMLEngine *engine,
349                                HTMLClueFlowStyle style,
350                                HTMLListType item_type,
351                                HTMLHAlignType alignment,
352                                gint indentation_delta,
353                                guint8 *indentation_levels,
354                                HTMLEngineSetClueFlowStyleMask mask,
355                                HTMLUndoDirection dir, gboolean do_undo)
356{
357        g_return_val_if_fail (engine != NULL, FALSE);
358        g_return_val_if_fail (HTML_IS_ENGINE (engine), FALSE);
359
360        html_engine_freeze (engine);
361        if (html_engine_is_selection_active (engine))
362                set_clueflow_style_in_region (engine,
363                                              style, item_type, alignment,
364                                              indentation_delta, indentation_levels,
365                                              mask,
366                                              dir, do_undo);
367        else
368                set_clueflow_style_at_cursor (engine,
369                                              style, item_type, alignment,
370                                              indentation_delta, indentation_levels,
371                                              mask,
372                                              dir, do_undo);
373        html_engine_thaw (engine);
374
375        /* This operation can never fail.  */
376        return TRUE;
377}
378
379
380/* The following functions are used to report the current indentation
381   as it should be shown e.g in a toolbar.  */
382
383static HTMLClueFlow *
384get_current_para (HTMLEngine *engine)
385{
386        HTMLObject *current;
387        HTMLObject *parent;
388
389        current = engine->cursor->object;
390        if (current == NULL)
391                return NULL;
392
393        parent = current->parent;
394        if (parent == NULL)
395                return NULL;
396
397        if (HTML_OBJECT_TYPE (parent) != HTML_TYPE_CLUEFLOW)
398                return NULL;
399
400        return HTML_CLUEFLOW (parent);
401}
402
403void
404html_engine_get_current_clueflow_style (HTMLEngine *engine, HTMLClueFlowStyle *style, HTMLListType *item_type)
405{
406        HTMLClueFlow *para;
407
408        /* FIXME TODO region */
409
410        *style = HTML_CLUEFLOW_STYLE_NORMAL;
411        *item_type = HTML_LIST_TYPE_UNORDERED;
412
413        g_return_if_fail (engine != NULL);
414        g_return_if_fail (HTML_IS_ENGINE (engine));
415
416        para = get_current_para (engine);
417        if (para) {
418                *style = para->style;
419                *item_type = para->item_type;
420        }
421}
422 
423guint
424html_engine_get_current_clueflow_indentation (HTMLEngine *engine)
425{
426        HTMLClueFlow *para;
427
428        /* FIXME TODO region */
429
430        g_return_val_if_fail (engine != NULL, 0);
431        g_return_val_if_fail (HTML_IS_ENGINE (engine), 0);
432
433        para = get_current_para (engine);
434        if (para == NULL)
435                return 0;
436       
437        /* FIXME levels TODO levels */
438        return para->levels->len;
439}
440
441HTMLHAlignType
442html_engine_get_current_clueflow_alignment (HTMLEngine *engine)
443{
444        HTMLClueFlow *para;
445
446        /* FIXME TODO region */
447
448        g_return_val_if_fail (engine != NULL, HTML_HALIGN_LEFT);
449        g_return_val_if_fail (HTML_IS_ENGINE (engine), HTML_HALIGN_LEFT);
450
451        para = get_current_para (engine);
452        if (para == NULL)
453                return 0;
454
455        return html_clueflow_get_halignment (para);
456}
Note: See TracBrowser for help on using the repository browser.