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