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