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