]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
Added function firstRow() to LyXText as this function is needed in
[lyx.git] / src / insets / insettext.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1998-2001 The LyX Team.
7  *
8  * ======================================================
9  */
10
11 #include <config.h>
12
13 #include <fstream>
14 #include <algorithm>
15
16 #include <cstdlib>
17 //#include <signal.h>
18
19 #ifdef __GNUG__
20 #pragma implementation
21 #endif
22
23 #include "insettext.h"
24 #include "paragraph.h"
25 #include "lyxlex.h"
26 #include "debug.h"
27 #include "lyxfont.h"
28 #include "commandtags.h"
29 #include "buffer.h"
30 #include "LyXView.h"
31 #include "BufferView.h"
32 #include "layout.h"
33 #include "LaTeXFeatures.h"
34 #include "Painter.h"
35 #include "frontends/Alert.h"
36 #include "lyxtext.h"
37 #include "lyxcursor.h"
38 #include "CutAndPaste.h"
39 #include "font.h"
40 #include "LColor.h"
41 #include "support/textutils.h"
42 #include "support/LAssert.h"
43 #include "support/lstrings.h"
44 #include "lyxrow.h"
45 #include "lyxrc.h"
46 #include "intl.h"
47 #include "trans_mgr.h"
48 #include "lyxscreen.h"
49 #include "WorkArea.h"
50 #include "gettext.h"
51 #include "lyxfunc.h"
52 #include "ParagraphParameters.h"
53 #include "undo_funcs.h"
54 #include "lyxfind.h"
55
56 using std::ostream;
57 using std::ifstream;
58 using std::endl;
59 using std::min;
60 using std::max;
61 using std::make_pair;
62 using std::vector;
63
64 using lyx::pos_type;
65
66 extern unsigned char getCurrentTextClass(Buffer *);
67 extern bool math_insert_greek(BufferView *, char);
68 extern int greek_kb_flag;
69
70
71 // These functions should probably go into bufferview_funcs somehow (Jug)
72
73 void InsetText::saveLyXTextState(LyXText * t) const
74 {
75         // check if my paragraphs are still valid
76         Paragraph * p = par;
77         while(p) {
78                 if (p == t->cursor.par())
79                         break;
80                 p = p->next();
81         }
82         
83         if (p && t->cursor.pos() <= p->size()) {
84                 sstate.lpar = t->cursor.par();
85                 sstate.pos = t->cursor.pos();
86                 sstate.boundary = t->cursor.boundary();
87                 sstate.selstartpar = t->selection.start.par();
88                 sstate.selstartpos = t->selection.start.pos();
89                 sstate.selstartboundary = t->selection.start.boundary();
90                 sstate.selendpar = t->selection.end.par();
91                 sstate.selendpos = t->selection.end.pos();
92                 sstate.selendboundary = t->selection.end.boundary();
93                 sstate.selection = t->selection.set();
94                 sstate.mark_set = t->selection.mark();
95                 sstate.refresh = t->refresh_row != 0;
96         } else {
97                 sstate.lpar = 0;
98         }
99 }
100
101 void InsetText::restoreLyXTextState(BufferView * bv, LyXText * t) const
102 {
103         if (sstate.lpar) {
104                 t->selection.set(true);
105                 /* at this point just to avoid the Delete-Empty-Paragraph
106                  * Mechanism when setting the cursor */
107                 t->selection.mark(sstate.mark_set);
108                 if (sstate.selection) {
109                         t->setCursor(bv, sstate.selstartpar, sstate.selstartpos,
110                                      true, sstate.selstartboundary);
111                         t->selection.cursor = t->cursor;
112                         t->setCursor(bv, sstate.selendpar, sstate.selendpos,
113                                      true, sstate.selendboundary);
114                         t->setSelection(bv);
115                         t->setCursor(bv, sstate.lpar, sstate.pos);
116                 } else {
117                         t->setCursor(bv, sstate.lpar, sstate.pos, true, sstate.boundary);
118                         t->selection.cursor = t->cursor;
119                         t->selection.set(false);
120                 }
121                 if (sstate.refresh) {
122                 }
123         }
124 }
125
126
127 InsetText::InnerCache::InnerCache(boost::shared_ptr<LyXText> t)
128 {
129         text = t;
130         remove = false;
131 }
132
133
134 InsetText::InsetText()
135         : UpdatableInset(), lt(0), in_update(false), do_resize(0),
136           do_reinit(false)
137 {
138         par = new Paragraph;
139         init();
140 }
141
142
143 InsetText::InsetText(InsetText const & in, bool same_id)
144         : UpdatableInset(in, same_id), lt(0), in_update(false), do_resize(0),
145           do_reinit(false)
146 {
147         par = 0;
148         init(&in, same_id);
149 }
150
151
152 InsetText & InsetText::operator=(InsetText const & it)
153 {
154         init(&it);
155         return * this;
156 }
157
158
159 void InsetText::init(InsetText const * ins, bool same_id)
160 {
161         if (ins) {
162                 setParagraphData(ins->par);
163                 autoBreakRows = ins->autoBreakRows;
164                 drawFrame_ = ins->drawFrame_;
165                 frame_color = ins->frame_color;
166                 if (same_id)
167                         id_ = ins->id_;
168         } else {
169                 Paragraph * p = par;
170                 while(p) {
171                         p->setInsetOwner(this);
172                         p = p->next();
173                 }
174                 the_locking_inset = 0;
175                 drawFrame_ = NEVER;
176                 frame_color = LColor::insetframe;
177                 autoBreakRows = false;
178         }
179         top_y = 0;
180         last_width = 0;
181         last_height = 0;
182         insetAscent = 0;
183         insetDescent = 0;
184         insetWidth = 0;
185         old_max_width = 0;
186         no_selection = false;
187         need_update = FULL;
188         drawTextXOffset = 0;
189         drawTextYOffset = 0;
190         xpos = 0.0;
191         locked = false;
192         old_par = 0;
193         last_drawn_width = -1;
194         frame_is_visible = false;
195         cached_bview = 0;
196         sstate.lpar = 0;
197 }
198
199
200 InsetText::~InsetText()
201 {
202         cached_bview = 0;
203
204         // NOTE
205         
206         while (par) {
207                 Paragraph * tmp = par->next();
208                 delete par;
209                 par = tmp;
210         }
211 }
212
213
214 void InsetText::clear()
215 {
216         while (par) {
217                 Paragraph * tmp = par->next();
218                 delete par;
219                 par = tmp;
220         }
221         par = new Paragraph;
222         reinitLyXText();
223         need_update = INIT;
224 }
225
226
227 Inset * InsetText::clone(Buffer const &, bool same_id) const
228 {
229         return  new InsetText(*this, same_id);
230 }
231
232
233 void InsetText::write(Buffer const * buf, ostream & os) const
234 {
235         os << "Text\n";
236         writeParagraphData(buf, os);
237 }
238
239
240 void InsetText::writeParagraphData(Buffer const * buf, ostream & os) const
241 {
242         par->writeFile(buf, os, buf->params, 0);
243 }
244
245
246 void InsetText::read(Buffer const * buf, LyXLex & lex)
247 {
248         string token;
249         int pos = 0;
250         Paragraph * return_par = 0;
251         Paragraph::depth_type depth = 0; 
252         LyXFont font(LyXFont::ALL_INHERIT);
253
254         clear();
255         
256         while (lex.isOK()) {
257                 lex.nextToken();
258                 token = lex.getString();
259                 if (token.empty())
260                         continue;
261                 if (token == "\\end_inset") {
262 #ifndef NO_COMPABILITY
263                         const_cast<Buffer*>(buf)->insertErtContents(par, pos, font, false);
264 #endif
265                         break;
266                 }
267                 
268                 if (const_cast<Buffer*>(buf)->
269                         parseSingleLyXformat2Token(lex, par, return_par,
270                                                    token, pos, depth, font)) {
271                         // the_end read this should NEVER happen
272                         lex.printError("\\the_end read in inset! Error in document!");
273                         return;
274                 }
275         }
276         if (!return_par)
277                 return_par = par;
278         par = return_par;
279         while(return_par) {
280                 return_par->setInsetOwner(this);
281                 return_par = return_par->next();
282         }
283         
284         if (token != "\\end_inset") {
285                 lex.printError("Missing \\end_inset at this point. "
286                                            "Read: `$$Token'");
287         }
288         need_update = FULL;
289 }
290
291
292 int InsetText::ascent(BufferView * bv, LyXFont const &) const
293 {
294         bool clear = false;
295         if (!lt) {
296                 lt = getLyXText(bv);
297                 clear = true;
298         }
299         insetAscent = lt->firstRow()->ascent_of_text() + TEXT_TO_INSET_OFFSET;
300         if (clear)
301                 lt = 0;
302         return insetAscent;
303 }
304
305
306 int InsetText::descent(BufferView * bv, LyXFont const &) const
307 {
308         bool clear = false;
309         if (!lt) {
310                 lt = getLyXText(bv);
311                 clear = true;
312         }
313         insetDescent = lt->height - lt->firstRow()->ascent_of_text() +
314                 TEXT_TO_INSET_OFFSET;
315         if (clear)
316                 lt = 0;
317         return insetDescent;
318 }
319
320
321 int InsetText::width(BufferView * bv, LyXFont const &) const
322 {
323         insetWidth = max(textWidth(bv), (int)getLyXText(bv)->width) +
324                 (2 * TEXT_TO_INSET_OFFSET);
325         insetWidth = max(insetWidth, 10);
326         return insetWidth;
327 }
328
329
330 int InsetText::textWidth(BufferView * bv, bool fordraw) const
331 {
332         int w;
333         if (!autoBreakRows) {
334                 w = -1;
335         } else {
336                 w = getMaxWidth(bv, this);
337         }
338         if (fordraw) {
339                 return max(w - (2 * TEXT_TO_INSET_OFFSET),
340                            (int)getLyXText(bv)->width);
341         } else if (w < 0) {
342             return -1;
343         }
344         return w - (2 * TEXT_TO_INSET_OFFSET);
345 }
346
347
348 void InsetText::draw(BufferView * bv, LyXFont const & f,
349                      int baseline, float & x, bool cleared) const
350 {
351         if (nodraw())
352                 return;
353
354         Painter & pain = bv->painter();
355         
356         // this is the first thing we have to ask because if the x pos
357         // changed we have to do a complete rebreak of the text as we
358         // may have few space to draw in. Well we should check on this too
359         int old_x = top_x;
360         if (top_x != int(x)) {
361                 top_x = int(x);
362                 int nw = getMaxWidth(bv, this);
363                 if (nw > 0 && old_max_width != nw) {
364                         need_update = INIT;
365                         old_max_width = nw;
366                         bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
367                         topx_set = true;
368                         return;
369                 } else {
370                         top_x = old_x;
371                 }
372         }
373
374         // repaint the background if needed
375         if (cleared && backgroundColor() != LColor::background) {
376                 top_x = int(x);
377                 clearInset(pain, baseline, cleared);
378                 top_x = old_x;
379         }
380
381         // no draw is necessary !!!
382         if ((drawFrame_ == LOCKED) && !locked && !par->size()) {
383                 top_x = int(x);
384                 topx_set = true;
385                 top_baseline = baseline;
386                 x += width(bv, f);
387                 if (need_update & CLEAR_FRAME)
388                         clearFrame(pain, cleared);
389                 need_update = NONE;
390                 return;
391         }
392
393         xpos = x;
394         if (!owner())
395                 x += static_cast<float>(scroll());
396
397         // if top_x differs we did it already
398         if (!cleared && (top_x == int(x)) &&
399                 ((need_update&(INIT|FULL)) || (top_baseline!=baseline) ||
400                  (last_drawn_width!=insetWidth))) {
401                 clearInset(pain, baseline, cleared);
402         }
403
404         top_x = int(x);
405         topx_set = true;
406         if (cleared)
407                 frame_is_visible = false;
408
409         if (!cleared && (need_update == NONE)) {
410                 if (locked)
411                         drawFrame(pain, cleared);
412                 return;
413         }
414
415         top_baseline = baseline;
416         top_y = baseline - ascent(bv, f);
417         last_width = width(bv, f);
418         last_height = ascent(bv, f) + descent(bv, f);
419
420         if (cleared || (last_drawn_width != insetWidth)) {
421                 if (!cleared) 
422                         clearInset(pain, baseline, cleared);
423                 need_update |= FULL;
424                 last_drawn_width = insetWidth;
425         }
426
427         if (the_locking_inset && (cpar(bv) == inset_par)
428                 && (cpos(bv) == inset_pos)) {
429                 inset_x = cx(bv) - top_x + drawTextXOffset;
430                 inset_y = cy(bv) + drawTextYOffset;
431         }
432         if (!cleared && (need_update == CURSOR)
433             && !getLyXText(bv)->selection.set()) {
434                 drawFrame(pain, cleared);
435                 x += last_width; // was width(bv, f);
436                 need_update = NONE;
437                 return;
438         }
439         bool clear = false;
440         if (!lt) {
441                 lt = getLyXText(bv);
442                 clear = true;
443         }
444         x += TEXT_TO_INSET_OFFSET;
445
446         Row * row = lt->firstRow();
447         int y_offset = baseline - row->ascent_of_text();
448         int ph = pain.paperHeight();
449         int first = 0;
450         int y = y_offset;
451         while ((row != 0) && ((y+row->height()) <= 0)) {
452                 y += row->height();
453                 first += row->height();
454                 row = row->next();
455         }
456         if (y_offset < 0)
457                 y_offset = y;
458         lt->first = first;
459         if (cleared || (need_update&(INIT|FULL))) {
460                 int yf = y_offset;
461                 y = 0;
462                 while ((row != 0) && (yf < ph)) {
463                         lt->getVisibleRow(bv, y+y_offset, int(x), row,
464                                                 y+first, cleared);
465                         y += row->height();
466                         yf += row->height();
467                         row = row->next();
468                 }
469         } else if (!locked) {
470                 if (need_update & CURSOR) {
471                         bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
472                         lt->clearSelection();
473                         lt->selection.cursor = lt->cursor;
474                 }
475                 bv->screen()->update(lt, bv, y_offset, int(x));
476         } else {
477                 locked = false;
478                 if (need_update & SELECTION) {
479                         bv->screen()->toggleToggle(lt, bv, y_offset, int(x));
480                 } else if (need_update & CURSOR) {
481                         bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
482                         lt->clearSelection();
483                         lt->selection.cursor = lt->cursor;
484                 }
485                 bv->screen()->update(lt, bv, y_offset, int(x));
486                 locked = true;
487         }
488
489         lt->refresh_y = 0;
490         lt->status(bv, LyXText::UNCHANGED);
491         if ((need_update != CURSOR_PAR) &&
492             ((drawFrame_ == ALWAYS) || ((drawFrame_ == LOCKED) && locked))) {
493                 drawFrame(pain, cleared);
494         } else if (need_update & CLEAR_FRAME) {
495                 clearFrame(pain, cleared);
496         }
497         
498         x += last_width /* was width(bv, f) */ - TEXT_TO_INSET_OFFSET;
499         
500         if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
501                 need_update |= FULL;
502         } else if (need_update != INIT) {
503                 need_update = NONE;
504         }
505         
506         if (clear)
507                 lt = 0;
508 }
509
510
511 void InsetText::drawFrame(Painter & pain, bool cleared) const
512 {
513         static int const ttoD2 = TEXT_TO_INSET_OFFSET / 2;
514         if (!frame_is_visible || cleared) {
515                 frame_x = top_x + ttoD2;
516                 frame_y = top_baseline - insetAscent + ttoD2;
517                 frame_w = last_width - TEXT_TO_INSET_OFFSET;
518                 frame_h = insetAscent + insetDescent - TEXT_TO_INSET_OFFSET;
519                 pain.rectangle(frame_x, frame_y,
520                                frame_w, frame_h,
521                                frame_color);
522                 frame_is_visible = true;
523         }
524 }
525
526
527 void InsetText::clearFrame(Painter & pain, bool cleared) const
528 {
529         if (frame_is_visible) {
530                 if (!cleared) {
531                         pain.rectangle(frame_x, frame_y, frame_w, frame_h,
532                                        backgroundColor());
533                 }
534                 frame_is_visible = false;
535         }
536 }
537
538
539 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
540 {
541         if (in_update) {
542                 if (reinit && owner()) {
543                         reinitLyXText();
544                         owner()->update(bv, font, true);
545                 }
546                 return;
547         }
548         in_update = true;
549         if (reinit || need_update == INIT) {
550                 need_update = FULL;
551                 // we should put this call where we set need_update to INIT!
552                 reinitLyXText();
553                 if (owner())
554                         owner()->update(bv, font, true);
555                 in_update = false;
556                 return;
557         }
558         if (the_locking_inset) {
559                 inset_x = cx(bv) - top_x + drawTextXOffset;
560                 inset_y = cy(bv) + drawTextYOffset;
561                 the_locking_inset->update(bv, font, reinit);
562         }
563
564         bool clear = false;
565         if (!lt) {
566                 lt = getLyXText(bv);
567                 clear = true;
568         }
569 #if 0
570         int oldw = insetWidth;
571         insetWidth = lt->width + (2 * TEXT_TO_INSET_OFFSET);
572         if (oldw != insetWidth) {
573                 resizeLyXText(bv);
574                 need_update |= FULL;
575                 if (clear)
576                         lt = 0;
577                 in_update = false;
578                 return;
579         }
580 #endif
581         if ((need_update & CURSOR_PAR) && (lt->status() == LyXText::UNCHANGED) &&
582                 the_locking_inset)
583         {
584                 lt->updateInset(bv, the_locking_inset);
585         }
586         if (lt->status() == LyXText::NEED_MORE_REFRESH)
587                 need_update |= FULL;
588         if (clear)
589                 lt = 0;
590         in_update = false;
591 }
592
593
594 void InsetText::setUpdateStatus(BufferView * bv, int what) const
595 {
596         bool clear = false;
597         if (!lt) {
598                 lt = getLyXText(bv);
599                 clear = true;
600         }
601         need_update |= what;
602         // we have to redraw us full if our LyXText NEEDS_MORE_REFRES or
603         // if we don't break row so that we only have one row to update!
604         if ((lt->status() == LyXText::NEED_MORE_REFRESH) ||
605             (!autoBreakRows &&
606              (lt->status() == LyXText::NEED_VERY_LITTLE_REFRESH)))
607         {
608                 need_update |= FULL;
609         } else if (lt->status() == LyXText::NEED_VERY_LITTLE_REFRESH) {
610                 need_update |= CURSOR_PAR;
611         }
612
613         // this to not draw a selection when we redraw all of it!
614         if (need_update & CURSOR && !(need_update & SELECTION)) {
615                 if (lt->selection.set())
616                         need_update = FULL;
617                 lt->clearSelection();
618         }
619         if (clear)
620                 lt = 0;
621 }
622
623
624 void InsetText::updateLocal(BufferView * bv, int what, bool mark_dirty) const
625 {
626         bool clear = false;
627         if (!lt) {
628                 lt = getLyXText(bv);
629                 clear = true;
630         }
631         lt->fullRebreak(bv);
632         setUpdateStatus(bv, what);
633         if (((need_update != CURSOR) && (need_update != NONE)) ||
634             (lt->status() != LyXText::UNCHANGED) || lt->selection.set())
635         {
636                 bv->updateInset(const_cast<InsetText *>(this), mark_dirty);
637         }
638         if (need_update == CURSOR)
639                 need_update = NONE;
640         bv->owner()->showState();
641         if (old_par != cpar(bv)) {
642                 bv->owner()->setLayout(cpar(bv)->getLayout());
643                 old_par = cpar(bv);
644         }
645         if (clear)
646                 lt = 0;
647 }
648
649
650 string const InsetText::editMessage() const
651 {
652         return _("Opened Text Inset");
653 }
654
655
656 void InsetText::edit(BufferView * bv, int x, int y, unsigned int button)
657 {
658         UpdatableInset::edit(bv, x, y, button);
659         
660         if (!bv->lockInset(this)) {
661                 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
662                 return;
663         }
664         locked = true;
665         the_locking_inset = 0;
666         inset_pos = inset_x = inset_y = 0;
667         inset_boundary = false;
668         inset_par = 0;
669         old_par = 0;
670         int tmp_y = (y < 0) ? 0 : y;
671         bool clear = false;
672         if (!lt) {
673                 lt = getLyXText(bv);
674                 clear = true;
675         }
676
677         if (!checkAndActivateInset(bv, x, tmp_y, button))
678                 lt->setCursorFromCoordinates(bv, x - drawTextXOffset,
679                                             y + insetAscent);
680         lt->clearSelection();
681         finishUndo();
682         showInsetCursor(bv);
683         updateLocal(bv, CURSOR, false);
684
685         // If the inset is empty set the language of the current font to the
686         // language to the surronding text (if different).
687         if (par->size() == 0 && !par->next() &&
688                 bv->getParentLanguage(this) != lt->current_font.language()) {
689                 LyXFont font(LyXFont::ALL_IGNORE);
690                 font.setLanguage(bv->getParentLanguage(this));
691                 setFont(bv, font, false);
692         }
693         if (clear)
694                 lt = 0;
695 }
696
697
698 void InsetText::edit(BufferView * bv, bool front)
699 {
700         UpdatableInset::edit(bv, front);
701         
702         if (!bv->lockInset(this)) {
703                 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
704                 return;
705         }
706         locked = true;
707         the_locking_inset = 0;
708         inset_pos = inset_x = inset_y = 0;
709         inset_boundary = false;
710         inset_par = 0;
711         old_par = 0;
712         bool clear = false;
713         if (!lt) {
714                 lt = getLyXText(bv);
715                 clear = true;
716         }
717         if (front)
718                 lt->setCursor(bv, par, 0);
719         else {
720                 Paragraph * p = par;
721                 while(p->next())
722                         p = p->next();
723 //              int const pos = (p->size() ? p->size()-1 : p->size());
724                 lt->setCursor(bv, p, p->size());
725         }
726         lt->clearSelection();
727         finishUndo();
728         showInsetCursor(bv);
729         updateLocal(bv, CURSOR, false);
730
731         // If the inset is empty set the language of the current font to the
732         // language to the surronding text (if different).
733         if (par->size() == 0 && !par->next() &&
734                 bv->getParentLanguage(this) != lt->current_font.language()) {
735                 LyXFont font(LyXFont::ALL_IGNORE);
736                 font.setLanguage(bv->getParentLanguage(this));
737                 setFont(bv, font, false);
738         }
739         if (clear)
740                 lt = 0;
741 }
742
743
744 void InsetText::insetUnlock(BufferView * bv)
745 {
746         if (the_locking_inset) {
747                 the_locking_inset->insetUnlock(bv);
748                 the_locking_inset = 0;
749         }
750         hideInsetCursor(bv);
751         no_selection = false;
752         locked = false;
753         int code;
754         if (drawFrame_ == LOCKED)
755                 code = CURSOR|CLEAR_FRAME;
756         else 
757                 code = CURSOR;
758         bool clear = false;
759         if (!lt) {
760                 lt = getLyXText(bv);
761                 clear = true;
762         }
763         if (lt->selection.set()) {
764                 lt->clearSelection();
765                 code = FULL;
766         } else if (owner()) {
767                 bv->owner()->setLayout(owner()->getLyXText(bv)
768                                        ->cursor.par()->getLayout());
769         } else
770                 bv->owner()->setLayout(bv->text->cursor.par()->getLayout());
771         // hack for deleteEmptyParMech
772         lt->setCursor(bv, par, 0);
773         updateLocal(bv, code, false);
774         if (clear)
775                 lt = 0;
776 }
777
778
779 bool InsetText::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
780 {
781         lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset("
782                               << inset << "): ";
783         if (!inset)
784                 return false;
785         if (inset == cpar(bv)->getInset(cpos(bv))) {
786                 lyxerr[Debug::INSETS] << "OK" << endl;
787                 the_locking_inset = inset;
788                 inset_x = cx(bv) - top_x + drawTextXOffset;
789                 inset_y = cy(bv) + drawTextYOffset;
790                 inset_pos = cpos(bv);
791                 inset_par = cpar(bv);
792                 inset_boundary = cboundary(bv);
793                 updateLocal(bv, CURSOR, false);
794                 return true;
795         } else if (the_locking_inset && (the_locking_inset == inset)) {
796                 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
797                         lyxerr[Debug::INSETS] << "OK" << endl;
798                         inset_x = cx(bv) - top_x + drawTextXOffset;
799                         inset_y = cy(bv) + drawTextYOffset;
800                 } else {
801                         lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
802                 }
803         } else if (the_locking_inset) {
804                 lyxerr[Debug::INSETS] << "MAYBE" << endl;
805                 return the_locking_inset->lockInsetInInset(bv, inset);
806         }
807         lyxerr[Debug::INSETS] << "NOT OK" << endl;
808         return false;
809 }
810
811
812 bool InsetText::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
813                                    bool lr)
814 {
815         if (!the_locking_inset)
816                 return false;
817         if (the_locking_inset == inset) {
818                 the_locking_inset->insetUnlock(bv);
819                 getLyXText(bv)->updateInset(bv, inset);
820                 the_locking_inset = 0;
821                 if (lr)
822                         moveRight(bv, false);
823                 old_par = 0; // force layout setting
824                 if (scroll())
825                         scroll(bv, 0.0F);
826                 else
827                         updateLocal(bv, CURSOR, false);
828                 return true;
829         }
830         return the_locking_inset->unlockInsetInInset(bv, inset, lr);
831 }
832
833
834 bool InsetText::updateInsetInInset(BufferView * bv, Inset * inset)
835 {
836         if (!the_locking_inset)
837                 return false;
838         if (the_locking_inset != inset) {
839                 getLyXText(bv)->updateInset(bv, the_locking_inset);
840                 setUpdateStatus(bv, CURSOR_PAR);
841                 return the_locking_inset->updateInsetInInset(bv, inset);
842         }
843         if (getLyXText(bv)->updateInset(bv, inset))
844                 updateLocal(bv, CURSOR_PAR, false);
845         if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
846                 inset_x = cx(bv) - top_x + drawTextXOffset;
847                 inset_y = cy(bv) + drawTextYOffset;
848         }
849         return true;
850 }
851
852
853 void InsetText::insetButtonPress(BufferView * bv, int x, int y, int button)
854 {
855         no_selection = true;
856
857         int tmp_x = x - drawTextXOffset;
858         int tmp_y = y + insetAscent - getLyXText(bv)->first;
859         Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y, button);
860
861         hideInsetCursor(bv);
862         if (the_locking_inset) {
863                 if (the_locking_inset == inset) {
864                         the_locking_inset->insetButtonPress(bv,x-inset_x,y-inset_y,button);
865                         no_selection = false;
866                         return;
867                 } else if (inset) {
868                         // otherwise unlock the_locking_inset and lock the new inset
869                         the_locking_inset->insetUnlock(bv);
870                         inset_x = cx(bv) - top_x + drawTextXOffset;
871                         inset_y = cy(bv) + drawTextYOffset;
872                         the_locking_inset = static_cast<UpdatableInset*>(inset);
873                         inset->insetButtonPress(bv, x - inset_x, y - inset_y, button);
874                         inset->edit(bv, x - inset_x, y - inset_y, button);
875                         if (the_locking_inset)
876                                 updateLocal(bv, CURSOR, false);
877                         no_selection = false;
878                         return;
879                 }
880                 // otherwise only unlock the_locking_inset
881                 the_locking_inset->insetUnlock(bv);
882                 the_locking_inset = 0;
883         }
884         if (bv->theLockingInset()) {
885                 if (isHighlyEditableInset(inset)) {
886                         UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
887                         inset_x = cx(bv) - top_x + drawTextXOffset;
888                         inset_y = cy(bv) + drawTextYOffset;
889                         inset_pos = cpos(bv);
890                         inset_par = cpar(bv);
891                         inset_boundary = cboundary(bv);
892                         the_locking_inset = uinset;
893                         uinset->insetButtonPress(bv, x - inset_x, y - inset_y,
894                                                  button);
895                         uinset->edit(bv, x - inset_x, y - inset_y, 0);
896                         if (the_locking_inset)
897                                 updateLocal(bv, CURSOR, false);
898                         no_selection = false;
899                         return;
900                 }
901         }
902         if (!inset) { // && (button == 2)) {
903                 bool paste_internally = false;
904                 if ((button == 2) && getLyXText(bv)->selection.set()) {
905                         localDispatch(bv, LFUN_COPY, "");
906                         paste_internally = true;
907                 }
908                 bool clear = false;
909                 if (!lt) {
910                         lt = getLyXText(bv);
911                         clear = true;
912                 }
913                 lt->setCursorFromCoordinates(bv, x-drawTextXOffset, y + insetAscent);
914                 if (lt->selection.set()) {
915                         lt->clearSelection();
916                         updateLocal(bv, FULL, false);
917                 } else {
918                         lt->clearSelection();
919                 }
920                 bv->owner()->setLayout(cpar(bv)->getLayout());
921                 old_par = cpar(bv);
922                 // Insert primary selection with middle mouse
923                 // if there is a local selection in the current buffer,
924                 // insert this
925                 if (button == 2) {
926                         if (paste_internally)
927                                 localDispatch(bv, LFUN_PASTE, "");
928                         else
929                                 localDispatch(bv, LFUN_PASTESELECTION,
930                                               "paragraph");
931                 }
932                 if (clear)
933                         lt = 0;
934         }
935         showInsetCursor(bv);
936         no_selection = false;
937 }
938
939
940 void InsetText::insetButtonRelease(BufferView * bv, int x, int y, int button)
941 {
942         UpdatableInset * inset = 0;
943
944         if (the_locking_inset) {
945                 the_locking_inset->insetButtonRelease(bv,
946                                                       x - inset_x, y - inset_y,
947                                                       button);
948         } else {
949                 if (cpar(bv)->isInset(cpos(bv))) {
950                         inset = static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
951                         if (isHighlyEditableInset(inset)) {
952                                 inset->insetButtonRelease(bv,
953                                                           x - inset_x,
954                                                           y - inset_y, button);
955                         } else {
956                                 inset_x = cx(bv) - top_x + drawTextXOffset;
957                                 inset_y = cy(bv) + drawTextYOffset;
958                                 inset->insetButtonRelease(bv,
959                                                           x - inset_x,
960                                                           y - inset_y, button);
961                                 inset->edit(bv,
962                                             x - inset_x, y - inset_y, button);
963                         }
964                         updateLocal(bv, CURSOR_PAR, false);
965                 }
966         }
967         no_selection = false;
968 }
969
970
971 void InsetText::insetMotionNotify(BufferView * bv, int x, int y, int state)
972 {
973         if (no_selection)
974                 return;
975         if (the_locking_inset) {
976                 the_locking_inset->insetMotionNotify(bv, x - inset_x,
977                                                      y - inset_y,state);
978                 return;
979         }
980         LyXText * t = getLyXText(bv);
981         hideInsetCursor(bv);
982         t->setCursorFromCoordinates(bv, x - drawTextXOffset, y + insetAscent);
983         t->setSelection(bv);
984         if (t->toggle_cursor.par() != t->toggle_end_cursor.par() ||
985                 t->toggle_cursor.pos() != t->toggle_end_cursor.pos())
986                 updateLocal(bv, SELECTION, false);
987         showInsetCursor(bv);
988 }
989
990
991 void InsetText::insetKeyPress(XKeyEvent * xke)
992 {
993         if (the_locking_inset) {
994                 the_locking_inset->insetKeyPress(xke);
995                 return;
996         }
997 }
998
999
1000 UpdatableInset::RESULT
1001 InsetText::localDispatch(BufferView * bv,
1002                          kb_action action, string const & arg)
1003 {
1004         bool was_empty = par->size() == 0 && !par->next();
1005         no_selection = false;
1006         UpdatableInset::RESULT
1007                 result= UpdatableInset::localDispatch(bv, action, arg);
1008         if (result != UNDISPATCHED) {
1009                 return DISPATCHED;
1010         }
1011
1012         result = DISPATCHED;
1013         if ((action < 0) && arg.empty())
1014                 return FINISHED;
1015
1016         if (the_locking_inset) {
1017                 result = the_locking_inset->localDispatch(bv, action, arg);
1018                 if (result == DISPATCHED_NOUPDATE)
1019                         return result;
1020                 else if (result == DISPATCHED) {
1021                         updateLocal(bv, CURSOR_PAR, false);
1022                         return result;
1023                 } else if (result >= FINISHED) {
1024                         switch(result) {
1025                         case FINISHED_RIGHT:
1026                                 moveRightIntern(bv, false, false);
1027                                 result = DISPATCHED;
1028                                 break;
1029                         case FINISHED_UP:
1030                                 if ((result = moveUp(bv)) >= FINISHED) {
1031                                         updateLocal(bv, CURSOR, false);
1032                                         bv->unlockInset(this);
1033                                 }
1034                                 break;
1035                         case FINISHED_DOWN:
1036                                 if ((result = moveDown(bv)) >= FINISHED) {
1037                                         updateLocal(bv, CURSOR, false);
1038                                         bv->unlockInset(this);
1039                                 }
1040                                 break;
1041                         default:
1042                                 result = DISPATCHED;
1043                                 break;
1044                         }
1045                         the_locking_inset = 0;
1046 #ifdef WITH_WARNINGS
1047 #warning I changed this to always return Dispatched maybe it is wrong (20011001 Jug)
1048 #endif
1049                         return result;
1050                 }
1051         }
1052         hideInsetCursor(bv);
1053         bool clear = false;
1054         if (!lt) {
1055                 lt = getLyXText(bv);
1056                 clear = true;
1057         }
1058         switch (action) {
1059         // Normal chars
1060         case LFUN_SELFINSERT:
1061                 if (bv->buffer()->isReadonly()) {
1062 //          setErrorMessage(N_("Document is read only"));
1063                         break;
1064                 }
1065                 if (!arg.empty()) {
1066                         /* Automatically delete the currently selected
1067                          * text and replace it with what is being
1068                          * typed in now. Depends on lyxrc settings
1069                          * "auto_region_delete", which defaults to
1070                          * true (on). */
1071
1072                         setUndo(bv, Undo::INSERT,
1073                                 lt->cursor.par(), lt->cursor.par()->next());
1074                         bv->setState();
1075                         if (lyxrc.auto_region_delete) {
1076                                 if (lt->selection.set()) {
1077                                         lt->cutSelection(bv, false);
1078                                 }
1079                         }
1080                         lt->clearSelection();
1081                         for (string::size_type i = 0; i < arg.length(); ++i) {
1082                                 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
1083                         }
1084                 }
1085                 lt->selection.cursor = lt->cursor;
1086                 updateLocal(bv, CURSOR_PAR, true);
1087                 result = DISPATCHED_NOUPDATE;
1088                 break;
1089                 // --- Cursor Movements -----------------------------------
1090         case LFUN_RIGHTSEL:
1091                 finishUndo();
1092                 moveRight(bv, false, true);
1093                 lt->setSelection(bv);
1094                 updateLocal(bv, SELECTION, false);
1095                 break;
1096         case LFUN_RIGHT:
1097                 result = moveRight(bv);
1098                 finishUndo();
1099                 updateLocal(bv, CURSOR, false);
1100                 break;
1101         case LFUN_LEFTSEL:
1102                 finishUndo();
1103                 moveLeft(bv, false, true);
1104                 lt->setSelection(bv);
1105                 updateLocal(bv, SELECTION, false);
1106                 break;
1107         case LFUN_LEFT:
1108                 finishUndo();
1109                 result = moveLeft(bv);
1110                 updateLocal(bv, CURSOR, false);
1111                 break;
1112         case LFUN_DOWNSEL:
1113                 finishUndo();
1114                 moveDown(bv);
1115                 lt->setSelection(bv);
1116                 updateLocal(bv, SELECTION, false);
1117                 break;
1118         case LFUN_DOWN:
1119                 finishUndo();
1120                 result = moveDown(bv);
1121                 updateLocal(bv, CURSOR, false);
1122                 break;
1123         case LFUN_UPSEL:
1124                 finishUndo();
1125                 moveUp(bv);
1126                 lt->setSelection(bv);
1127                 updateLocal(bv, SELECTION, false);
1128                 break;
1129         case LFUN_UP:
1130                 finishUndo();
1131                 result = moveUp(bv);
1132                 updateLocal(bv, CURSOR, false);
1133                 break;
1134         case LFUN_HOME:
1135                 finishUndo();
1136                 lt->cursorHome(bv);
1137                 updateLocal(bv, CURSOR, false);
1138                 break;
1139         case LFUN_END:
1140                 lt->cursorEnd(bv);
1141                 updateLocal(bv, CURSOR, false);
1142                 break;
1143         case LFUN_BACKSPACE: {
1144                 setUndo(bv, Undo::DELETE,
1145                         lt->cursor.par(), lt->cursor.par()->next());
1146                 if (lt->selection.set())
1147                         lt->cutSelection(bv);
1148                 else
1149                         lt->backspace(bv);
1150                 updateLocal(bv, CURSOR_PAR, true);
1151         }
1152         break;
1153         
1154         case LFUN_DELETE: {
1155                 setUndo(bv, Undo::DELETE,
1156                         lt->cursor.par(), lt->cursor.par()->next());
1157                 if (lt->selection.set()) {
1158                         lt->cutSelection(bv);
1159                 } else {
1160                         lt->Delete(bv);
1161                 }
1162                 updateLocal(bv, CURSOR_PAR, true);
1163         }
1164         break;
1165         
1166         case LFUN_CUT: {
1167                 setUndo(bv, Undo::DELETE,
1168                         lt->cursor.par(), lt->cursor.par()->next());
1169                 lt->cutSelection(bv);
1170                 updateLocal(bv, CURSOR_PAR, true);
1171         }
1172         break;
1173
1174         case LFUN_COPY:
1175                 finishUndo();
1176                 lt->copySelection(bv);
1177                 updateLocal(bv, CURSOR_PAR, false);
1178                 break;
1179         case LFUN_PASTESELECTION:
1180         {
1181                 string const clip(bv->getClipboard());
1182         
1183                 if (clip.empty())
1184                         break;
1185                 if (arg == "paragraph") {
1186                         lt->insertStringAsParagraphs(bv, clip);
1187                 } else {
1188                         lt->insertStringAsLines(bv, clip);
1189                 }
1190                 updateLocal(bv, CURSOR_PAR, true);
1191                 break;
1192         }
1193         case LFUN_PASTE: {
1194                 if (!autoBreakRows) {
1195
1196                         if (CutAndPaste::nrOfParagraphs() > 1) {
1197                                 Alert::alert(_("Impossible operation"),
1198                                                    _("Cannot include more than one paragraph!"),
1199                                                    _("Sorry."));
1200                                 break;
1201                         }
1202                 }
1203                 setUndo(bv, Undo::INSERT,
1204                         lt->cursor.par(), lt->cursor.par()->next());
1205                 lt->pasteSelection(bv);
1206                 updateLocal(bv, CURSOR_PAR, true);
1207         }
1208         break;
1209
1210         case LFUN_BREAKPARAGRAPH:
1211                 if (!autoBreakRows) {
1212                         result = DISPATCHED;
1213                         break;
1214                 }
1215                 lt->breakParagraph(bv, 0);
1216                 updateLocal(bv, FULL, true);
1217                 break;
1218         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1219                 if (!autoBreakRows) {
1220                         result = DISPATCHED;
1221                         break;
1222                 }
1223                 lt->breakParagraph(bv, 1);
1224                 updateLocal(bv, FULL, true);
1225                 break;
1226
1227         case LFUN_BREAKLINE: {
1228                 if (!autoBreakRows) {
1229                         result = DISPATCHED;
1230                         break;
1231                 }
1232                 setUndo(bv, Undo::INSERT,
1233                         lt->cursor.par(), lt->cursor.par()->next());
1234                 lt->insertChar(bv, Paragraph::META_NEWLINE);
1235                 updateLocal(bv, CURSOR_PAR, true);
1236         }
1237         break;
1238
1239         case LFUN_LAYOUT:
1240                 // do not set layouts on non breakable textinsets
1241                 if (autoBreakRows) {
1242                         LyXTextClass::size_type cur_layout = cpar(bv)->layout;
1243           
1244                         // Derive layout number from given argument (string)
1245                         // and current buffer's textclass (number). */    
1246                         LyXTextClassList::ClassList::size_type tclass =
1247                                 bv->buffer()->params.textclass;
1248                         std::pair <bool, LyXTextClass::size_type> layout = 
1249                                 textclasslist.NumberOfLayout(tclass, arg);
1250
1251                         // If the entry is obsolete, use the new one instead.
1252                         if (layout.first) {
1253                                 string obs = textclasslist.Style(tclass,layout.second).
1254                                         obsoleted_by();
1255                                 if (!obs.empty()) 
1256                                         layout = textclasslist.NumberOfLayout(tclass, obs);
1257                         }
1258
1259                         // see if we found the layout number:
1260                         if (!layout.first) {
1261                                 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1262                                 bv->owner()->getLyXFunc()->dispatch(LFUN_MESSAGE, msg);
1263                                 break;
1264                         }
1265
1266                         if (cur_layout != layout.second) {
1267                                 cur_layout = layout.second;
1268                                 lt->setLayout(bv, layout.second);
1269                                 bv->owner()->setLayout(cpar(bv)->getLayout());
1270                                 updateLocal(bv, CURSOR_PAR, true);
1271                         }
1272                 } else {
1273                         // reset the layout box
1274                         bv->owner()->setLayout(cpar(bv)->getLayout());
1275                 }
1276                 break;
1277         case LFUN_PARAGRAPH_SPACING:
1278                 // This one is absolutely not working. When fiddling with this
1279                 // it also seems to me that the paragraphs inside the insettext
1280                 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1281         {
1282                 Paragraph * par = lt->cursor.par();
1283                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
1284                 float cur_value = 1.0;
1285                 if (cur_spacing == Spacing::Other) {
1286                         cur_value = par->params().spacing().getValue();
1287                 }
1288                                 
1289                 istringstream istr(arg.c_str());
1290                 string tmp;
1291                 istr >> tmp;
1292                 Spacing::Space new_spacing = cur_spacing;
1293                 float new_value = cur_value;
1294                 if (tmp.empty()) {
1295                         lyxerr << "Missing argument to `paragraph-spacing'"
1296                                    << endl;
1297                 } else if (tmp == "single") {
1298                         new_spacing = Spacing::Single;
1299                 } else if (tmp == "onehalf") {
1300                         new_spacing = Spacing::Onehalf;
1301                 } else if (tmp == "double") {
1302                         new_spacing = Spacing::Double;
1303                 } else if (tmp == "other") {
1304                         new_spacing = Spacing::Other;
1305                         float tmpval = 0.0;
1306                         istr >> tmpval;
1307                         lyxerr << "new_value = " << tmpval << endl;
1308                         if (tmpval != 0.0)
1309                                 new_value = tmpval;
1310                 } else if (tmp == "default") {
1311                         new_spacing = Spacing::Default;
1312                 } else {
1313                         lyxerr << _("Unknown spacing argument: ")
1314                                    << arg << endl;
1315                 }
1316                 if (cur_spacing != new_spacing || cur_value != new_value) {
1317                         par->params().spacing(Spacing(new_spacing, new_value));
1318                         updateLocal(bv, CURSOR_PAR, true);
1319                 }
1320         }
1321         break;
1322         
1323         default:
1324                 if (!bv->Dispatch(action, arg))
1325                         result = UNDISPATCHED;
1326                 break;
1327         }
1328
1329         /// If the action has deleted all text in the inset, we need to change the
1330         // language to the language of the surronding text.
1331         if (!was_empty && par->size() == 0 && !par->next()) {
1332                 LyXFont font(LyXFont::ALL_IGNORE);
1333                 font.setLanguage(bv->getParentLanguage(this));
1334                 setFont(bv, font, false);
1335         }
1336
1337         if (result < FINISHED) {
1338                 showInsetCursor(bv);
1339         } else
1340                 bv->unlockInset(this);
1341         if (clear)
1342                 lt = 0;
1343         return result;
1344 }
1345
1346
1347 int InsetText::latex(Buffer const * buf, ostream & os, bool, bool) const
1348 {
1349         TexRow texrow;
1350         buf->latexParagraphs(os, par, 0, texrow);
1351         return texrow.rows();
1352 }
1353
1354
1355 int InsetText::ascii(Buffer const * buf, ostream & os, int linelen) const
1356 {
1357         Paragraph * p = par;
1358         unsigned int lines = 0;
1359         
1360         while (p) {
1361                 string const tmp = buf->asciiParagraph(p, linelen);
1362                 lines += countChar(tmp, '\n');
1363                 os << tmp;
1364                 p = p->next();
1365         }
1366         return lines;
1367 }
1368
1369
1370 int InsetText::docbook(Buffer const * buf, ostream & os) const
1371 {
1372         Paragraph * p = par;
1373         unsigned int lines = 0;
1374
1375         vector<string> environment_stack(10);
1376         vector<string> environment_inner(10);
1377         
1378         int const command_depth = 0;
1379         string item_name;
1380         
1381         Paragraph::depth_type depth = 0; // paragraph depth
1382
1383         while (p) {
1384                 string sgmlparam;
1385                 int desc_on = 0; // description mode
1386
1387                 LyXLayout const & style =
1388                         textclasslist.Style(buf->params.textclass,
1389                                             p->layout);
1390
1391                 // environment tag closing
1392                 for (; depth > p->params().depth(); --depth) {
1393                         if (environment_inner[depth] != "!-- --") {
1394                                 item_name = "listitem";
1395                                 buf->sgmlCloseTag(os, command_depth + depth,
1396                                              item_name);
1397                                 if (environment_inner[depth] == "varlistentry")
1398                                         buf->sgmlCloseTag(os, depth+command_depth,
1399                                                      environment_inner[depth]);
1400                         }
1401                         buf->sgmlCloseTag(os, depth + command_depth,
1402                                      environment_stack[depth]);
1403                         environment_stack[depth].erase();
1404                         environment_inner[depth].erase();
1405                 }
1406
1407                 if (depth == p->params().depth()
1408                    && environment_stack[depth] != style.latexname()
1409                    && !environment_stack[depth].empty()) {
1410                         if (environment_inner[depth] != "!-- --") {
1411                                 item_name= "listitem";
1412                                 buf->sgmlCloseTag(os, command_depth+depth,
1413                                                   item_name);
1414                                 if (environment_inner[depth] == "varlistentry")
1415                                         buf->sgmlCloseTag(os,
1416                                                           depth + command_depth,
1417                                                           environment_inner[depth]);
1418                         }
1419                         
1420                         buf->sgmlCloseTag(os, depth + command_depth,
1421                                           environment_stack[depth]);
1422                         
1423                         environment_stack[depth].erase();
1424                         environment_inner[depth].erase();
1425                 }
1426
1427                 // Write opening SGML tags.
1428                 switch (style.latextype) {
1429                 case LATEX_PARAGRAPH:
1430                         buf->sgmlOpenTag(os, depth + command_depth,
1431                                          style.latexname());
1432                         break;
1433
1434                 case LATEX_COMMAND:
1435                         buf->sgmlError(p, 0,
1436                                        _("Error : LatexType Command not allowed here.\n"));
1437                         return -1;
1438                         break;
1439
1440                 case LATEX_ENVIRONMENT:
1441                 case LATEX_ITEM_ENVIRONMENT:
1442                         if (depth < p->params().depth()) {
1443                                 depth = p->params().depth();
1444                                 environment_stack[depth].erase();
1445                         }
1446
1447                         if (environment_stack[depth] != style.latexname()) {
1448                                 if(environment_stack.size() == depth + 1) {
1449                                         environment_stack.push_back("!-- --");
1450                                         environment_inner.push_back("!-- --");
1451                                 }
1452                                 environment_stack[depth] = style.latexname();
1453                                 environment_inner[depth] = "!-- --";
1454                                 buf->sgmlOpenTag(os, depth + command_depth,
1455                                                  environment_stack[depth]);
1456                         } else {
1457                                 if (environment_inner[depth] != "!-- --") {
1458                                         item_name= "listitem";
1459                                         buf->sgmlCloseTag(os,
1460                                                           command_depth + depth,
1461                                                           item_name);
1462                                         if (environment_inner[depth] == "varlistentry")
1463                                                 buf->sgmlCloseTag(os,
1464                                                                   depth + command_depth,
1465                                                                   environment_inner[depth]);
1466                                 }
1467                         }
1468                         
1469                         if (style.latextype == LATEX_ENVIRONMENT) {
1470                                 if (!style.latexparam().empty()) {
1471                                         if(style.latexparam() == "CDATA")
1472                                                 os << "<![CDATA[";
1473                                         else
1474                                                 buf->sgmlOpenTag(os, depth + command_depth,
1475                                                                  style.latexparam());
1476                                 }
1477                                 break;
1478                         }
1479
1480                         desc_on = (style.labeltype == LABEL_MANUAL);
1481
1482                         if (desc_on)
1483                                 environment_inner[depth]= "varlistentry";
1484                         else
1485                                 environment_inner[depth]= "listitem";
1486
1487                         buf->sgmlOpenTag(os, depth + 1 + command_depth,
1488                                          environment_inner[depth]);
1489
1490                         if (desc_on) {
1491                                 item_name= "term";
1492                                 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1493                                                  item_name);
1494                         } else {
1495                                 item_name= "para";
1496                                 buf->sgmlOpenTag(os, depth + 1 + command_depth,
1497                                                  item_name);
1498                         }
1499                         break;
1500                 default:
1501                         buf->sgmlOpenTag(os, depth + command_depth,
1502                                          style.latexname());
1503                         break;
1504                 }
1505
1506                 buf->simpleDocBookOnePar(os, p, desc_on,
1507                                          depth + 1 + command_depth);
1508                 p = p->next();
1509
1510                 string end_tag;
1511                 // write closing SGML tags
1512                 switch (style.latextype) {
1513                 case LATEX_ENVIRONMENT:
1514                         if (!style.latexparam().empty()) {
1515                                 if(style.latexparam() == "CDATA")
1516                                         os << "]]>";
1517                                 else
1518                                         buf->sgmlCloseTag(os, depth + command_depth,
1519                                                           style.latexparam());
1520                         }
1521                         break;
1522                 case LATEX_ITEM_ENVIRONMENT:
1523                         if (desc_on == 1) break;
1524                         end_tag= "para";
1525                         buf->sgmlCloseTag(os, depth + 1 + command_depth, end_tag);
1526                         break;
1527                 case LATEX_PARAGRAPH:
1528                         buf->sgmlCloseTag(os, depth + command_depth, style.latexname());
1529                         break;
1530                 default:
1531                         buf->sgmlCloseTag(os, depth + command_depth, style.latexname());
1532                         break;
1533                 }
1534         }
1535
1536         // Close open tags
1537         for (int d = depth; d >= 0; --d) {
1538                 if (!environment_stack[depth].empty()) {
1539                         if (environment_inner[depth] != "!-- --") {
1540                                 item_name = "listitem";
1541                                 buf->sgmlCloseTag(os, command_depth + depth,
1542                                                   item_name);
1543                                if (environment_inner[depth] == "varlistentry")
1544                                        buf->sgmlCloseTag(os, depth + command_depth,
1545                                                          environment_inner[depth]);
1546                         }
1547                         
1548                         buf->sgmlCloseTag(os, depth + command_depth,
1549                                           environment_stack[depth]);
1550                 }
1551         }
1552         
1553         return lines;
1554 }
1555
1556
1557 void InsetText::validate(LaTeXFeatures & features) const
1558 {
1559         Paragraph * p = par;
1560         while (p) {
1561                 p->validate(features);
1562                 p = p->next();
1563         }
1564 }
1565
1566
1567 int InsetText::beginningOfMainBody(Buffer const * buf, Paragraph * p) const
1568 {
1569         if (textclasslist.Style(buf->params.textclass,
1570                                 p->getLayout()).labeltype != LABEL_MANUAL)
1571                 return 0;
1572         else
1573                 return p->beginningOfMainBody();
1574 }
1575
1576
1577 void InsetText::getCursorPos(BufferView * bv,
1578                              int & x, int & y) const
1579 {
1580         if (the_locking_inset) {
1581                 the_locking_inset->getCursorPos(bv, x, y);
1582                 return;
1583         }
1584         x = cx(bv);
1585         y = cy(bv);
1586 }
1587
1588
1589 unsigned int InsetText::insetInInsetY()
1590 {
1591         if (!the_locking_inset)
1592                 return 0;
1593
1594         return (inset_y + the_locking_inset->insetInInsetY());
1595 }
1596
1597
1598 void InsetText::toggleInsetCursor(BufferView * bv)
1599 {
1600         if (the_locking_inset) {
1601                 the_locking_inset->toggleInsetCursor(bv);
1602                 return;
1603         }
1604
1605         LyXFont const font(getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv)));
1606
1607         int const asc = lyxfont::maxAscent(font);
1608         int const desc = lyxfont::maxDescent(font);
1609   
1610         if (isCursorVisible())
1611                 bv->hideLockedInsetCursor();
1612         else
1613                 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1614         toggleCursorVisible();
1615 }
1616
1617
1618 void InsetText::showInsetCursor(BufferView * bv, bool show)
1619 {
1620         if (the_locking_inset) {
1621                 the_locking_inset->showInsetCursor(bv, show);
1622                 return;
1623         }
1624         if (!isCursorVisible()) {
1625                 LyXFont const font =
1626                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1627         
1628                 int const asc = lyxfont::maxAscent(font);
1629                 int const desc = lyxfont::maxDescent(font);
1630
1631                 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1632                 if (show)
1633                         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1634                 setCursorVisible(true);
1635         }
1636 }
1637
1638
1639 void InsetText::hideInsetCursor(BufferView * bv)
1640 {
1641         if (isCursorVisible()) {
1642                 bv->hideLockedInsetCursor();
1643                 setCursorVisible(false);
1644         }
1645         if (the_locking_inset)
1646                 the_locking_inset->hideInsetCursor(bv);
1647 }
1648
1649
1650 void InsetText::fitInsetCursor(BufferView * bv) const
1651 {
1652         if (the_locking_inset) {
1653                 the_locking_inset->fitInsetCursor(bv);
1654                 return;
1655         }
1656         LyXFont const font =
1657                 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1658         
1659         int const asc = lyxfont::maxAscent(font);
1660         int const desc = lyxfont::maxDescent(font);
1661
1662         bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1663 }
1664
1665
1666 UpdatableInset::RESULT
1667 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1668 {
1669         if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1670                 return moveLeftIntern(bv, false, activate_inset, selecting);
1671         else
1672                 return moveRightIntern(bv, false, activate_inset, selecting);
1673 }
1674
1675
1676 UpdatableInset::RESULT
1677 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1678 {
1679         if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1680                 return moveRightIntern(bv, true, activate_inset, selecting);
1681         else
1682                 return moveLeftIntern(bv, true, activate_inset, selecting);
1683 }
1684
1685
1686 UpdatableInset::RESULT
1687 InsetText::moveRightIntern(BufferView * bv, bool behind, 
1688                            bool activate_inset, bool selecting)
1689 {
1690         if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1691                 return FINISHED_RIGHT;
1692         if (activate_inset && checkAndActivateInset(bv, behind))
1693                 return DISPATCHED;
1694         getLyXText(bv)->cursorRight(bv);
1695         if (!selecting)
1696                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1697         return DISPATCHED_NOUPDATE;
1698 }
1699
1700
1701 UpdatableInset::RESULT
1702 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1703                           bool activate_inset, bool selecting)
1704 {
1705         if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1706                 return FINISHED;
1707         getLyXText(bv)->cursorLeft(bv);
1708         if (!selecting)
1709                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1710         if (activate_inset && checkAndActivateInset(bv, behind))
1711                 return DISPATCHED;
1712         return DISPATCHED_NOUPDATE;
1713 }
1714
1715
1716 UpdatableInset::RESULT
1717 InsetText::moveUp(BufferView * bv)
1718 {
1719         if (!crow(bv)->previous())
1720                 return FINISHED_UP;
1721         getLyXText(bv)->cursorUp(bv);
1722         return DISPATCHED_NOUPDATE;
1723 }
1724
1725
1726 UpdatableInset::RESULT
1727 InsetText::moveDown(BufferView * bv)
1728 {
1729         if (!crow(bv)->next())
1730                 return FINISHED_DOWN;
1731         getLyXText(bv)->cursorDown(bv);
1732         return DISPATCHED_NOUPDATE;
1733 }
1734
1735
1736 bool InsetText::insertInset(BufferView * bv, Inset * inset)
1737 {
1738         if (the_locking_inset) {
1739                 if (the_locking_inset->insetAllowed(inset))
1740                         return the_locking_inset->insertInset(bv, inset);
1741                 return false;
1742         }
1743         inset->setOwner(this);
1744         hideInsetCursor(bv);
1745
1746         bool clear = false;
1747         if (!lt) {
1748                 lt = getLyXText(bv);
1749                 clear = true;
1750         }
1751         lt->insertInset(bv, inset);
1752 #if 0
1753         if ((!cpar(bv)->isInset(cpos(bv))) ||
1754                 (cpar(bv)->getInset(cpos(bv)) != inset))
1755                 lt->cursorLeft(bv);
1756 #endif
1757         bv->fitCursor();
1758         updateLocal(bv, CURSOR_PAR|CURSOR, true);
1759         showInsetCursor(bv);
1760         if (clear)
1761                 lt = 0;
1762         return true;
1763 }
1764
1765
1766 bool InsetText::insetAllowed(Inset::Code code) const
1767 {
1768         if (the_locking_inset)
1769                 return the_locking_inset->insetAllowed(code);
1770         return true;
1771 }
1772
1773
1774 UpdatableInset * InsetText::getLockingInset() const
1775 {
1776         return the_locking_inset ? the_locking_inset->getLockingInset() :
1777                 const_cast<InsetText *>(this);
1778 }
1779
1780
1781 UpdatableInset * InsetText::getFirstLockingInsetOfType(Inset::Code c)
1782 {
1783         if (c == lyxCode())
1784                 return this;
1785         if (the_locking_inset)
1786                 return the_locking_inset->getFirstLockingInsetOfType(c);
1787         return 0;
1788 }
1789
1790
1791 bool InsetText::showInsetDialog(BufferView * bv) const
1792 {
1793         if (the_locking_inset)
1794                 return the_locking_inset->showInsetDialog(bv);
1795         return false;
1796 }
1797
1798
1799 std::vector<string> const InsetText::getLabelList() const 
1800 {
1801         std::vector<string> label_list;
1802
1803         Paragraph * tpar = par;
1804         while (tpar) {
1805                 Paragraph::inset_iterator beg = tpar->inset_iterator_begin();
1806                 Paragraph::inset_iterator end = tpar->inset_iterator_end();
1807                 for (; beg != end; ++beg) {
1808                         std::vector<string> const l = (*beg)->getLabelList();
1809                         label_list.insert(label_list.end(), l.begin(), l.end());
1810                 }
1811                 tpar = tpar->next();
1812         }
1813         return label_list;
1814 }
1815
1816
1817 void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
1818                         bool selectall)
1819 {
1820         if (the_locking_inset) {
1821                 the_locking_inset->setFont(bv, font, toggleall, selectall);
1822                 return;
1823         }
1824         if ((!par->next() && !par->size()) || !cpar(bv)->size()) {
1825                 getLyXText(bv)->setFont(bv, font, toggleall);
1826                 return;
1827         }
1828         bool clear = false;
1829         if (!lt) {
1830                 lt = getLyXText(bv);
1831                 clear = true;
1832         }
1833         if (lt->selection.set()) {
1834                 setUndo(bv, Undo::EDIT, lt->cursor.par(), lt->cursor.par()->next());
1835         }
1836         if (selectall)
1837                 selectAll(bv);
1838         lt->toggleFree(bv, font, toggleall);
1839         if (selectall)
1840                 lt->clearSelection();
1841         bv->fitCursor();
1842         if (selectall || lt->selection.set())
1843                 updateLocal(bv, FULL, true);
1844         else
1845                 updateLocal(bv, CURSOR_PAR, true);
1846         if (clear)
1847                 lt = 0;
1848 }
1849
1850
1851 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1852 {
1853         if (cpar(bv)->isInset(cpos(bv))) {
1854                 unsigned int x;
1855                 unsigned int y;
1856                 Inset * inset =
1857                         static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1858                 if (!isHighlyEditableInset(inset))
1859                         return false;
1860                 LyXFont const font =
1861                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1862                 if (behind) {
1863                         x = inset->width(bv, font);
1864                         y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1865                 } else {
1866                         x = 0;
1867                         y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1868                 }
1869                 //inset_x = cx(bv) - top_x + drawTextXOffset;
1870                 //inset_y = cy(bv) + drawTextYOffset;
1871                 inset->edit(bv, x, y, 0);
1872                 if (!the_locking_inset)
1873                         return false;
1874                 updateLocal(bv, CURSOR, false);
1875                 return true;
1876         }
1877         return false;
1878 }
1879
1880
1881 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1882                                       int button)
1883 {
1884         x -= drawTextXOffset;
1885         int dummyx = x;
1886         int dummyy = y + insetAscent;
1887         Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy, button);
1888
1889         if (inset) {
1890                 if (x < 0)
1891                         x = insetWidth;
1892                 if (y < 0)
1893                         y = insetDescent;
1894                 inset_x = cx(bv) - top_x + drawTextXOffset;
1895                 inset_y = cy(bv) + drawTextYOffset;
1896                 inset->edit(bv, x - inset_x, y - inset_y, button);
1897                 if (!the_locking_inset)
1898                         return false;
1899                 updateLocal(bv, CURSOR, false);
1900                 return true;
1901         }
1902         return false;
1903 }
1904
1905
1906 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1907 {
1908 #if 0
1909         int w = UpdatableInset::getMaxWidth(bv, inset);
1910         if (w < 0) {
1911                 return -1;
1912         }
1913         if (owner()) {
1914                 w = w - top_x + owner()->x();
1915                 return w;
1916         }
1917         w -= (2 * TEXT_TO_INSET_OFFSET);
1918         return w - top_x;
1919 #else
1920         return UpdatableInset::getMaxWidth(bv, inset);
1921 #endif
1922 }
1923
1924
1925 void InsetText::setParagraphData(Paragraph * p)
1926 {
1927         // we have to unlock any locked inset otherwise we're in troubles
1928         the_locking_inset = 0;
1929         while (par) {
1930                 Paragraph * tmp = par->next();
1931                 delete par;
1932                 par = tmp;
1933         }
1934
1935         par = new Paragraph(*p, false);
1936         par->setInsetOwner(this);
1937         Paragraph * np = par;
1938         while (p->next()) {
1939                 p = p->next();
1940                 np->next(new Paragraph(*p, false));
1941                 np->next()->previous(np);
1942                 np = np->next();
1943                 np->setInsetOwner(this);
1944         }
1945         reinitLyXText();
1946         need_update = INIT;
1947 }
1948
1949
1950 void InsetText::setText(string const & data)
1951 {
1952         clear();
1953         LyXFont font(LyXFont::ALL_SANE);
1954         for (unsigned int i=0; i < data.length(); ++i)
1955                 par->insertChar(i, data[i], font);
1956 }
1957
1958
1959 void InsetText::setAutoBreakRows(bool flag)
1960 {
1961         if (flag != autoBreakRows) {
1962                 autoBreakRows = flag;
1963                 if (!flag)
1964                         removeNewlines();
1965                 need_update = INIT;
1966         }
1967 }
1968
1969
1970 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
1971 {
1972         if (how != drawFrame_) {
1973                 drawFrame_ = how;
1974                 if (bv)
1975                         updateLocal(bv, DRAW_FRAME, false);
1976         }
1977 }
1978
1979
1980 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
1981 {
1982         if (frame_color != col) {
1983                 frame_color = col;
1984                 if (bv)
1985                         updateLocal(bv, DRAW_FRAME, false);
1986         }
1987 }
1988
1989
1990 int InsetText::cx(BufferView * bv) const
1991 {
1992         bool clear = false;
1993         if (!lt) {
1994                 lt = getLyXText(bv);
1995                 clear = true;
1996         }
1997         int x = lt->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1998         if (the_locking_inset) {
1999                 LyXFont font = lt->getFont(bv->buffer(),
2000                                              lt->cursor.par(),
2001                                              lt->cursor.pos());
2002                 if (font.isVisibleRightToLeft())
2003                         x -= the_locking_inset->width(bv, font);
2004         }
2005         if (clear)
2006                 lt = 0;
2007         return x;
2008 }
2009
2010
2011 int InsetText::cy(BufferView * bv) const
2012 {
2013         LyXFont font;
2014         return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
2015 }
2016
2017
2018 pos_type InsetText::cpos(BufferView * bv) const
2019 {
2020         return getLyXText(bv)->cursor.pos();
2021 }
2022
2023
2024 Paragraph * InsetText::cpar(BufferView * bv) const
2025 {
2026         return getLyXText(bv)->cursor.par();
2027 }
2028
2029
2030 bool InsetText::cboundary(BufferView * bv) const
2031 {
2032         return getLyXText(bv)->cursor.boundary();
2033 }
2034
2035
2036 Row * InsetText::crow(BufferView * bv) const
2037 {
2038         return getLyXText(bv)->cursor.row();
2039 }
2040
2041
2042 LyXText * InsetText::getLyXText(BufferView const * lbv,
2043                                 bool const recursive) const
2044 {
2045         if (!recursive && (cached_bview == lbv)) {
2046                 LyXText * lt = cached_text.get();
2047                 lyx::Assert(lt && lt->firstRow()->par() == par);
2048                 return cached_text.get();
2049         }
2050         
2051         // Super UGLY! (Lgb)
2052         BufferView * bv = const_cast<BufferView *>(lbv);
2053         
2054         cached_bview = bv;
2055         Cache::iterator it = cache.find(bv);
2056
2057         if (it != cache.end()) {
2058                 if (do_reinit)
2059                         reinitLyXText();
2060                 else if (do_resize)
2061                         resizeLyXText(do_resize);
2062                 if (lt || !it->second.remove) {
2063                         lyx::Assert(it->second.text.get());
2064                         cached_text = it->second.text;
2065                         if (recursive && the_locking_inset) {
2066                                 return the_locking_inset->getLyXText(bv, true);
2067                         }
2068                         return cached_text.get();
2069                 } else if (it->second.remove) {
2070                         if (locked) {
2071                                 saveLyXTextState(it->second.text.get());
2072                         } else {
2073                                 sstate.lpar = 0;
2074                         }
2075                 }
2076         }
2077         
2078         cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
2079         cached_text->init(bv);
2080         restoreLyXTextState(bv, cached_text.get());
2081
2082         cache.insert(make_pair(bv, cached_text));
2083         
2084         if (the_locking_inset && recursive) {
2085                 return the_locking_inset->getLyXText(bv);
2086         }
2087         return cached_text.get();
2088 }
2089
2090
2091 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
2092 {
2093         cached_bview = 0;
2094
2095         Cache::iterator it = cache.find(bv);
2096         
2097         if (it == cache.end()) {
2098                 return;
2099         }
2100
2101         lyx::Assert(it->second.text.get());
2102
2103         it->second.remove = true;
2104         if (recursive) {
2105                 /// then remove all LyXText in text-insets
2106                 Paragraph * p = par;
2107                 for (; p; p = p->next()) {
2108                         p->deleteInsetsLyXText(bv);
2109                 }
2110         }
2111 }
2112
2113
2114 void InsetText::resizeLyXText(BufferView * bv, bool force) const
2115 {
2116         if (lt) {
2117                 // we cannot resize this because we are in use!
2118                 // so do this on the next possible getLyXText()
2119                 do_resize = bv;
2120                 return;
2121         }
2122         do_resize = 0;
2123 //      lyxerr << "InsetText::resizeLyXText\n";
2124         if (!par->next() && !par->size()) // no data, resize not neccessary!
2125                 return;
2126         // one endless line, resize normally not necessary
2127         if (!force && getMaxWidth(bv, this) < 0)
2128                 return;
2129
2130         Cache::iterator it = cache.find(bv);
2131         if (it == cache.end()) {
2132                 return;
2133         }
2134         lyx::Assert(it->second.text.get());
2135
2136         LyXText * t = it->second.text.get();
2137         saveLyXTextState(t);
2138         for (Paragraph * p = par; p; p = p->next()) {
2139                 p->resizeInsetsLyXText(bv);
2140         }
2141         t->init(bv, true);
2142         restoreLyXTextState(bv, t);
2143         if (the_locking_inset) {
2144                 inset_x = cx(bv) - top_x + drawTextXOffset;
2145                 inset_y = cy(bv) + drawTextYOffset;
2146         }
2147
2148         if (bv->screen()) {
2149                 t->first = bv->screen()->topCursorVisible(t);
2150         }
2151         if (!owner()) {
2152                 updateLocal(bv, FULL, false);
2153                 // this will scroll the screen such that the cursor becomes visible 
2154                 bv->updateScrollbar();
2155         } else {
2156                 need_update |= FULL;
2157         }
2158 }
2159
2160
2161 void InsetText::reinitLyXText() const
2162 {
2163         if (lt) {
2164                 // we cannot resize this because we are in use!
2165                 // so do this on the next possible getLyXText()
2166                 do_reinit = true;
2167                 return;
2168         }
2169         do_reinit = false;
2170         do_resize = 0;
2171 //      lyxerr << "InsetText::reinitLyXText\n";
2172         for(Cache::iterator it = cache.begin(); it != cache.end(); ++it) {
2173                 lyx::Assert(it->second.text.get());
2174
2175                 LyXText * t = it->second.text.get();
2176                 BufferView * bv = it->first;
2177
2178                 saveLyXTextState(t);
2179                 for (Paragraph * p = par; p; p = p->next()) {
2180                         p->resizeInsetsLyXText(bv);
2181                 }
2182                 t->init(bv, true);
2183                 restoreLyXTextState(bv, t);
2184                 if (the_locking_inset) {
2185                         inset_x = cx(bv) - top_x + drawTextXOffset;
2186                         inset_y = cy(bv) + drawTextYOffset;
2187                 }
2188                 if (bv->screen()) {
2189                         t->first = bv->screen()->topCursorVisible(t);
2190                 }
2191                 if (!owner()) {
2192                         updateLocal(bv, FULL, false);
2193                         // this will scroll the screen such that the cursor becomes visible 
2194                         bv->updateScrollbar();
2195                 } else {
2196                         need_update = FULL;
2197                 }
2198         }
2199 }
2200
2201
2202 void InsetText::removeNewlines()
2203 {
2204         for (Paragraph * p = par; p; p = p->next()) {
2205                 for (int i = 0; i < p->size(); ++i) {
2206                         if (p->getChar(i) == Paragraph::META_NEWLINE)
2207                                 p->erase(i);
2208                 }
2209         }
2210 }
2211
2212
2213 bool InsetText::nodraw() const
2214 {
2215         if (the_locking_inset)
2216                 return the_locking_inset->nodraw();
2217         return UpdatableInset::nodraw();
2218 }
2219
2220
2221 int InsetText::scroll(bool recursive) const
2222 {
2223         int sx = UpdatableInset::scroll(false);
2224
2225         if (recursive && the_locking_inset)
2226                 sx += the_locking_inset->scroll(recursive);
2227
2228         return sx;
2229 }
2230
2231
2232 bool InsetText::doClearArea() const
2233 {
2234         return !locked || (need_update & (FULL|INIT));
2235 }
2236
2237
2238 void InsetText::selectAll(BufferView * bv)
2239 {
2240         getLyXText(bv)->cursorTop(bv);
2241         getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
2242         getLyXText(bv)->cursorBottom(bv);
2243         getLyXText(bv)->setSelection(bv);
2244 }
2245
2246
2247 void InsetText::clearSelection(BufferView * bv)
2248 {
2249         getLyXText(bv)->clearSelection();
2250 }
2251
2252
2253 void InsetText::clearInset(Painter & pain, int baseline, bool & cleared) const
2254 {
2255         int w = insetWidth;
2256         int h = insetAscent + insetDescent;
2257         int ty = baseline - insetAscent;
2258         
2259         if (ty < 0) {
2260                 h += ty;
2261                 ty = 0;
2262         }
2263         if ((ty + h) > pain.paperHeight())
2264                 h = pain.paperHeight();
2265         if ((top_x + drawTextXOffset + w) > pain.paperWidth())
2266                 w = pain.paperWidth();
2267 //      w -= TEXT_TO_INSET_OFFSET;
2268         pain.fillRectangle(top_x, ty, w+1, h+1, backgroundColor());
2269         cleared = true;
2270         need_update = FULL;
2271         frame_is_visible = false;
2272 }
2273
2274
2275 Paragraph * InsetText::getParFromID(int id) const
2276 {
2277 #if 0
2278         Paragraph * result = par;
2279         Paragraph * ires = 0;
2280         while (result && result->id() != id) {
2281                 if ((ires = result->getParFromID(id)))
2282                         return ires;
2283                 result = result->next();
2284         }
2285         return result;
2286 #else
2287         Paragraph * tmp = par;
2288         while (tmp) {
2289                 int tmp_id = tmp->id();
2290                 lyxerr << "Looking at paragraph: " << tmp_id << endl;
2291                 if (tmp->id() == id) {
2292                         return tmp;
2293                 }
2294                 Paragraph * tmp2 = tmp->getParFromID(id);
2295                 if (tmp2 != 0) {
2296                         return tmp2;
2297                 }
2298                 tmp = tmp->next();
2299         }
2300         return 0;
2301 #endif
2302 }
2303
2304
2305 Paragraph * InsetText::firstParagraph() const
2306 {
2307         Paragraph * result;
2308         if (the_locking_inset)
2309                 if ((result = the_locking_inset->firstParagraph()))
2310                         return result;
2311         return par;
2312 }
2313
2314
2315 Paragraph * InsetText::getFirstParagraph(int i) const
2316 {
2317         return (i == 0) ? par : 0;
2318 }
2319
2320
2321 LyXCursor const & InsetText::cursor(BufferView * bv) const
2322 {
2323                 if (the_locking_inset)
2324                                 return the_locking_inset->cursor(bv);
2325                 return getLyXText(bv)->cursor;
2326 }
2327
2328
2329 Paragraph * InsetText::paragraph() const
2330 {
2331         return par;
2332 }
2333
2334
2335 void InsetText::paragraph(Paragraph * p)
2336 {
2337         par = p;
2338         reinitLyXText();
2339         // redraw myself when asked for
2340         need_update = INIT;
2341 }
2342
2343
2344 Inset * InsetText::getInsetFromID(int id_arg) const
2345 {
2346         if (id_arg == id())
2347                 return const_cast<InsetText *>(this);
2348
2349         Paragraph * lp = par;
2350
2351         while(lp) {
2352                 for (Paragraph::inset_iterator it = lp->inset_iterator_begin(),
2353                          en = lp->inset_iterator_end();
2354                          it != en; ++it)
2355                 {
2356                         if ((*it)->id() == id_arg)
2357                                 return *it;
2358                         Inset * in = (*it)->getInsetFromID(id_arg);
2359                         if (in)
2360                                 return in;
2361                 }
2362                 lp = lp->next();
2363         }
2364         return 0;
2365 }
2366
2367
2368 string const InsetText::selectNextWordToSpellcheck(BufferView * bv, float & value) const
2369 {
2370         bool clear = false;
2371         string str;
2372
2373         if (!lt) {
2374                 lt = getLyXText(bv);
2375                 clear = true;
2376         }
2377         if (the_locking_inset) {
2378                 str = the_locking_inset->selectNextWordToSpellcheck(bv, value);
2379                 if (!str.empty()) {
2380                         value += cy(bv);
2381                         if (clear)
2382                                 lt = 0;
2383                         return str;
2384                 }
2385 #warning Dekel please have a look on this one RTL? (Jug)
2386 #warning DEKEL!
2387                 // we have to go on checking so move cusor to the right
2388                 lt->cursor.pos(lt->cursor.pos() + 1);
2389         }
2390         str = lt->selectNextWordToSpellcheck(bv, value);
2391         if (str.empty())
2392                 bv->unlockInset(const_cast<InsetText *>(this));
2393         else
2394                 value = cy(bv);
2395         if (clear)
2396                 lt = 0;
2397         return str;
2398 }
2399
2400
2401 void InsetText::selectSelectedWord(BufferView * bv)
2402 {
2403         if (the_locking_inset) {
2404                 the_locking_inset->selectSelectedWord(bv);
2405                 return;
2406         }
2407         getLyXText(bv)->selectSelectedWord(bv);
2408         updateLocal(bv, SELECTION, false);
2409 }
2410
2411
2412 void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
2413 {
2414         if (the_locking_inset) {
2415                 the_locking_inset->toggleSelection(bv, kill_selection);
2416         }
2417         bool clear = false;
2418         if (!lt) {
2419                 lt = getLyXText(bv);
2420                 clear = true;
2421         }
2422
2423         int x = top_x + TEXT_TO_INSET_OFFSET;
2424
2425         Row * row = lt->firstRow();
2426         int y_offset = top_baseline - row->ascent_of_text();
2427         int y = y_offset;
2428         while ((row != 0) && ((y+row->height()) <= 0)) {
2429                 y += row->height();
2430                 row = row->next();
2431         }
2432         if (y_offset < 0)
2433                 y_offset = y;
2434         
2435         if (need_update & SELECTION)
2436                 need_update = NONE;
2437         bv->screen()->toggleSelection(lt, bv, kill_selection, y_offset, x);
2438         if (clear)
2439                 lt = 0;
2440 }
2441
2442
2443 bool InsetText::searchForward(BufferView * bv, string const & str,
2444                               bool const & cs, bool const & mw)
2445 {
2446         if (the_locking_inset) {
2447                 if (the_locking_inset->searchForward(bv, str, cs, mw))
2448                         return true;
2449                 bool clear = false;
2450                 if (!lt) {
2451                         lt = getLyXText(bv);
2452                         clear = true;
2453                 }
2454                 Paragraph * lpar = lt->cursor.par();
2455                 pos_type pos = lt->cursor.pos();
2456                 if (pos < lpar->size() - 1)
2457                         ++pos;
2458                 else {
2459                         pos = 0;
2460                         lpar = lpar->next();
2461                 }
2462                 if (!lpar) {
2463                         if (clear)
2464                                 lt = 0;
2465                         // we have to unlock ourself in this function by default!
2466                         bv->unlockInset(const_cast<InsetText *>(this));
2467                         return false;
2468                 }
2469                 lt->setCursor(bv, lpar, pos);
2470                 if (clear)
2471                         lt = 0;
2472         }
2473         if (LyXFind(bv, str, true, true, cs , mw)) {
2474                 return true;
2475         }
2476         // we have to unlock ourself in this function by default!
2477         bv->unlockInset(const_cast<InsetText *>(this));
2478         return false;
2479 }
2480
2481 bool InsetText::searchBackward(BufferView * bv, string const & str,
2482                                bool const & cs, bool const & mw)
2483 {
2484         if (the_locking_inset)
2485                 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2486                         return true;
2487         if (LyXFind(bv, str, false, true, cs, mw)) {
2488                 return true;
2489         }
2490         // we have to unlock ourself in this function by default!
2491         bv->unlockInset(const_cast<InsetText *>(this));
2492         return false;
2493 }
2494
2495
2496 bool InsetText::checkInsertChar(LyXFont & font)
2497 {
2498         if (owner())
2499                 return owner()->checkInsertChar(font);
2500         return true;
2501 }