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