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