source: trunk/third/gtkhtml3/src/htmlselection.c @ 21116

Revision 21116, 10.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) 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   MERCHcANTABILITY 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 <gtk/gtkselection.h>
23#include <gtk/gtkmain.h>
24
25#include "htmlcursor.h"
26#include "htmlengine-edit-cursor.h"
27#include "htmlengine-edit-cut-and-paste.h"
28#include "htmlentity.h"
29#include "htmlinterval.h"
30#include "htmlselection.h"
31#include "htmlengine-edit.h"
32#include "htmlengine-edit-selection-updater.h"
33
34static gboolean
35optimize_selection (HTMLEngine *e, HTMLInterval *i)
36{
37        HTMLInterval *s = e->selection;
38        gboolean optimized = FALSE;
39
40        g_return_val_if_fail (s, FALSE);
41
42        /* printf ("change selection (%3d,%3d) --> (%3d,%3d)\n",
43           s->from.offset, s->to.offset,
44           i->from.offset, i->to.offset); */
45        if (html_point_eq (&i->from, &s->from)) {
46                HTMLPoint *max;
47
48                max = html_point_max (&i->to, &s->to);
49                if (max) {
50                        if (max == &i->to) {
51                                HTMLInterval *sel;
52
53                                /* printf ("optimize 1\n"); */
54                                sel = html_interval_new (s->to.object, i->to.object,
55                                                         i->from.object == s->to.object
56                                                         ? i->from.offset : (html_object_is_container (s->to.object) ? s->to.offset : 0), i->to.offset);
57                                html_interval_select (sel, e);
58                                html_interval_destroy (sel);
59                                html_interval_destroy (s);
60                                e->selection = i;
61                                optimized = TRUE;
62                        } else {
63                                HTMLInterval *usel;
64
65                                /* printf ("optimize 2\n"); */
66                                usel = html_interval_new (i->to.object, s->to.object,
67                                                          html_object_is_container (i->to.object) ? i->to.offset : 0, s->to.offset);
68                                html_interval_unselect (usel, e);
69                                if (!html_object_is_container (i->to.object) && i->to.offset) {
70                                        gint from = i->from.object == i->to.object ? i->from.offset : 0;
71                                        html_object_select_range (i->to.object, e,
72                                                                  from, i->to.offset - from,
73                                                                  !html_engine_frozen (e));
74                                }
75                                html_interval_destroy (usel);
76                                html_interval_destroy (s);
77                                e->selection = i;
78                                optimized = TRUE;
79                        }
80                }
81        } else if (html_point_eq (&i->to, &s->to)) {
82                HTMLPoint *min;
83
84                min = html_point_min (&i->from, &s->from);
85                if (min) {
86                        if (min == &i->from) {
87                                HTMLInterval *sel;
88
89                                /* printf ("optimize 3\n"); */
90                                sel = html_interval_new (i->from.object, s->from.object,
91                                                         i->from.offset,
92                                                         i->to.object == s->from.object
93                                                         ? i->to.offset
94                                                         : (html_object_is_container (s->from.object) ? s->from.offset : html_object_get_length (s->from.object)));
95                                html_interval_select (sel, e);
96                                html_interval_destroy (sel);
97                                html_interval_destroy (s);
98                                e->selection = i;
99                                optimized = TRUE;
100                        } else {
101                                HTMLInterval *usel;
102
103                                /* printf ("optimize 4\n"); */
104                                usel = html_interval_new (s->from.object, i->from.object,
105                                                          s->from.offset,
106                                                          html_object_is_container (i->from.object) ? i->from.offset : html_object_get_length (i->from.object));
107                                html_interval_unselect (usel, e);
108                                if (!html_object_is_container (i->from.object) && i->from.offset != html_object_get_length (i->from.object)) {
109                                        gint to = i->to.object == i->from.object
110                                                ? s->to.offset
111                                                : html_object_get_length (i->from.object);
112                                        html_object_select_range (i->from.object, e,
113                                                                  i->from.offset, to - i->from.offset,
114                                                                  !html_engine_frozen (e));
115                                }
116                                html_interval_destroy (usel);
117                                html_interval_destroy (s);
118                                e->selection = i;
119                                optimized = TRUE;
120                        }
121                }
122        }
123
124        /* if (optimized)
125           printf ("Optimized\n"); */
126
127        return optimized;
128}
129
130static void
131clear_primary (HTMLEngine *e) {
132        if (e->primary)
133                html_object_destroy (e->primary);
134
135        e->primary = NULL;
136        e->primary_len = 0;
137}
138
139void
140html_engine_select_interval (HTMLEngine *e, HTMLInterval *i)
141{
142        e = html_engine_get_top_html_engine (e);
143        html_engine_hide_cursor (e);
144        if (e->selection && html_interval_eq (e->selection, i))
145                html_interval_destroy (i);
146        else {
147                if (!e->selection || !optimize_selection (e, i)) {
148                        html_engine_unselect_all (e);
149                        e->selection = i;
150                        html_interval_select (e->selection, e);
151                }
152        }
153
154        html_engine_show_cursor (e);
155}
156
157void
158html_engine_select_region (HTMLEngine *e,
159                           gint x1, gint y1,
160                           gint x2, gint y2)
161{
162        HTMLPoint *a, *b;
163
164        g_return_if_fail (e != NULL);
165        g_return_if_fail (HTML_IS_ENGINE (e));
166
167        e = html_engine_get_top_html_engine (e);
168        if (e->clue == NULL)
169                return;
170
171        a = html_engine_get_point_at (e, x1, y1, TRUE);
172        b = html_engine_get_point_at (e, x2, y2, TRUE);
173
174        if (a && b) {
175                HTMLInterval *new_selection;
176
177                new_selection = html_interval_new_from_points (a, b);
178                html_interval_validate (new_selection);
179                html_engine_select_interval (e, new_selection);
180        }
181
182        if (a)
183                html_point_destroy (a);
184        if (b)
185                html_point_destroy (b);
186}
187
188void
189html_engine_select_all (HTMLEngine *e)
190{
191        HTMLObject *a, *b;
192
193        g_return_if_fail (e != NULL);
194        g_return_if_fail (HTML_IS_ENGINE (e));
195
196        e = html_engine_get_top_html_engine (e);
197        if (e->clue == NULL || HTML_CLUE (e->clue)->head == NULL)
198                return;
199
200        a = html_object_get_head_leaf (e->clue);
201        b = html_object_get_tail_leaf (e->clue);
202
203        if (a && b) {
204                HTMLInterval *new_selection;
205
206                new_selection = html_interval_new (a, b, 0, html_object_get_length (b));
207                html_interval_validate (new_selection);
208                html_engine_select_interval (e, new_selection);
209        }
210}
211
212void
213html_engine_clear_selection (HTMLEngine *e)
214{
215        /* printf ("clear selection\n"); */
216
217        if (e->selection) {
218                html_interval_destroy (e->selection);
219                html_engine_edit_selection_updater_reset (e->selection_updater);
220                e->selection = NULL;
221               
222                /*
223                if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (e->widget)->window)
224                        gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
225                                                 html_selection_current_time ());   
226                */
227        }
228}
229
230void
231html_engine_unselect_all (HTMLEngine *e)
232{
233        e = html_engine_get_top_html_engine (e);
234        if (e->selection) {
235                html_engine_hide_cursor (e);
236                html_interval_unselect (e->selection, e);
237                html_engine_clear_selection (e);
238                html_engine_show_cursor (e);
239        }
240}
241
242static void
243remove_mark (HTMLEngine *e)
244{
245        if (e->editable || e->caret_mode) {
246                if (e->mark == NULL)
247                        return;
248
249                html_cursor_destroy (e->mark);
250                e->mark = NULL;
251        }
252}
253
254void
255html_engine_deactivate_selection (HTMLEngine *e)
256{
257        remove_mark (e);
258        html_engine_clear_selection (e);
259}
260
261void
262html_engine_disable_selection (HTMLEngine *e)
263{
264        g_return_if_fail (e != NULL);
265        g_return_if_fail (HTML_IS_ENGINE (e));
266
267        html_engine_hide_cursor (e);
268        remove_mark (e);
269        html_engine_unselect_all (e);
270        e->selection_mode = FALSE;
271        html_engine_show_cursor (e);
272}
273
274static gboolean
275line_interval (HTMLEngine *e, HTMLCursor *begin, HTMLCursor *end)
276{
277        return html_cursor_beginning_of_line (begin, e) && html_cursor_end_of_line (end, e);
278}
279
280gboolean
281html_selection_word (gunichar uc)
282{
283        return uc && uc != ' ' && uc != '\t' && uc != ENTITY_NBSP         /* white space */
284                && uc != '(' && uc != ')' && uc != '[' && uc != ']';
285}
286
287gboolean
288html_selection_spell_word (gunichar uc, gboolean *cited)
289{
290        if (uc == '\'' || uc == '`') {
291                *cited = TRUE;
292                return FALSE;
293        } else {
294                return g_unichar_isalpha (uc);
295        }
296}
297
298static gboolean
299word_interval (HTMLEngine *e, HTMLCursor *begin, HTMLCursor *end)
300{
301        /* move to the begin of word */
302        while (html_selection_word (html_cursor_get_prev_char (begin)))
303                html_cursor_backward (begin, e);
304        /* move to the end of word */
305        while (html_selection_word (html_cursor_get_current_char (end)))
306                html_cursor_forward (end, e);
307
308        return (begin->object && end->object);
309}
310
311static void
312selection_helper (HTMLEngine *e, gboolean (*get_interval)(HTMLEngine *e, HTMLCursor *begin, HTMLCursor *end))
313{
314        HTMLCursor *cursor, *begin, *end;
315        HTMLInterval *i;
316
317        html_engine_unselect_all (e);
318        cursor = html_engine_get_cursor (e);
319
320        if (cursor->object) {
321                begin  = html_cursor_dup (cursor);
322                end    = html_cursor_dup (cursor);
323
324                if ((*get_interval) (e, begin, end)) {
325                        i = html_interval_new_from_cursor (begin, end);
326                        html_engine_select_interval (e, i);
327                }
328
329                html_cursor_destroy (begin);
330                html_cursor_destroy (end);
331        }
332        html_cursor_destroy (cursor);   
333}
334
335void
336html_engine_select_word (HTMLEngine *e)
337{
338        selection_helper (e, word_interval);
339}
340
341void
342html_engine_select_line (HTMLEngine *e)
343{
344        selection_helper (e, line_interval);
345}
346
347gboolean
348html_engine_is_selection_active (HTMLEngine *e)
349{
350        html_engine_edit_selection_updater_do_idle (e->selection_updater);
351        if (e->selection) {
352                g_return_val_if_fail (!html_engine_get_editable (e) || e->mark, FALSE);
353                return (!html_engine_get_editable (e) || e->mark) ? TRUE : FALSE;
354        }
355
356        return FALSE;
357}
358
359static void
360test_point (HTMLObject *o, HTMLEngine *e, gpointer data)
361{
362        HTMLPoint *point = (HTMLPoint *) data;
363
364        if (point->object == o) {
365                if (point->object == e->selection->from.object && point->offset < e->selection->from.offset)
366                        return;
367                if (point->object == e->selection->to.object && point->offset > e->selection->to.offset)
368                        return;
369
370                /* this indicates that object is IN the selection */
371                point->object = NULL;
372        }
373}
374
375gboolean
376html_engine_point_in_selection (HTMLEngine *e, HTMLObject *obj, guint offset)
377{
378        HTMLPoint *point;
379        gboolean rv;
380
381        if (!html_engine_is_selection_active (e) || !obj)
382                return FALSE;
383
384        point = html_point_new (obj, offset);
385        html_interval_forall (e->selection, e, test_point, point);
386        rv = point->object == NULL;
387
388        html_point_destroy (point);
389
390        return rv;
391}
392
393void
394html_engine_activate_selection (HTMLEngine *e, guint32 time)
395{
396        /* printf ("activate selection\n"); */
397
398        if (e->selection && e->block_selection == 0 && GTK_WIDGET_REALIZED (e->widget)) {
399                gtk_selection_owner_set (GTK_WIDGET (e->widget), GDK_SELECTION_PRIMARY, time); 
400                /* printf ("activated (%u).\n", time); */
401                clear_primary (e);
402                html_engine_copy_object (e, &e->primary, &e->primary_len);
403        }
404}
405
406void
407html_engine_block_selection (HTMLEngine *e)
408{
409        e->block_selection ++;
410}
411
412void
413html_engine_unblock_selection (HTMLEngine *e)
414{
415        e->block_selection --;
416}
417
418void
419html_engine_update_selection_active_state (HTMLEngine *e, guint32 time)
420{
421        if (html_engine_is_selection_active (e))
422                html_engine_activate_selection (e, time ? time : gtk_get_current_event_time ());
423        else
424                html_engine_deactivate_selection (e);
425}
Note: See TracBrowser for help on using the repository browser.