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