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