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