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