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