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