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