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