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