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