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