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