]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
bbe84be37ab8196283afad708f31cfdf369e4d7b
[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                                 if (greek_kb_flag) {
1012                                         if (!math_insert_greek(bv, arg[i])) {
1013                                                 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
1014                                         } else if (!the_locking_inset) {
1015                                                 (void)moveRight(bv, false);
1016                                         }
1017                                 } else {
1018                                         bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
1019                                 }
1020                         }
1021                 }
1022                 lt->selection.cursor = lt->cursor;
1023                 updateLocal(bv, CURSOR_PAR, true);
1024                 result = DISPATCHED_NOUPDATE;
1025                 break;
1026                 // --- Cursor Movements -----------------------------------
1027         case LFUN_RIGHTSEL:
1028                 finishUndo();
1029                 moveRight(bv, false, true);
1030                 lt->setSelection(bv);
1031                 updateLocal(bv, SELECTION, false);
1032                 break;
1033         case LFUN_RIGHT:
1034                 result = moveRight(bv);
1035                 finishUndo();
1036                 updateLocal(bv, CURSOR, false);
1037                 break;
1038         case LFUN_LEFTSEL:
1039                 finishUndo();
1040                 moveLeft(bv, false, true);
1041                 lt->setSelection(bv);
1042                 updateLocal(bv, SELECTION, false);
1043                 break;
1044         case LFUN_LEFT:
1045                 finishUndo();
1046                 result = moveLeft(bv);
1047                 updateLocal(bv, CURSOR, false);
1048                 break;
1049         case LFUN_DOWNSEL:
1050                 finishUndo();
1051                 moveDown(bv);
1052                 lt->setSelection(bv);
1053                 updateLocal(bv, SELECTION, false);
1054                 break;
1055         case LFUN_DOWN:
1056                 finishUndo();
1057                 result = moveDown(bv);
1058                 updateLocal(bv, CURSOR, false);
1059                 break;
1060         case LFUN_UPSEL:
1061                 finishUndo();
1062                 moveUp(bv);
1063                 lt->setSelection(bv);
1064                 updateLocal(bv, SELECTION, false);
1065                 break;
1066         case LFUN_UP:
1067                 finishUndo();
1068                 result = moveUp(bv);
1069                 updateLocal(bv, CURSOR, false);
1070                 break;
1071         case LFUN_HOME:
1072                 finishUndo();
1073                 lt->cursorHome(bv);
1074                 updateLocal(bv, CURSOR, false);
1075                 break;
1076         case LFUN_END:
1077                 lt->cursorEnd(bv);
1078                 updateLocal(bv, CURSOR, false);
1079                 break;
1080         case LFUN_BACKSPACE: {
1081                 setUndo(bv, Undo::DELETE,
1082                         lt->cursor.par(), lt->cursor.par()->next());
1083                 if (lt->selection.set())
1084                         lt->cutSelection(bv);
1085                 else
1086                         lt->backspace(bv);
1087                 updateLocal(bv, CURSOR_PAR, true);
1088         }
1089         break;
1090         
1091         case LFUN_DELETE: {
1092                 setUndo(bv, Undo::DELETE,
1093                         lt->cursor.par(), lt->cursor.par()->next());
1094                 if (lt->selection.set()) {
1095                         lt->cutSelection(bv);
1096                 } else {
1097                         lt->Delete(bv);
1098                 }
1099                 updateLocal(bv, CURSOR_PAR, true);
1100         }
1101         break;
1102         
1103         case LFUN_CUT: {
1104                 setUndo(bv, Undo::DELETE,
1105                         lt->cursor.par(), lt->cursor.par()->next());
1106                 lt->cutSelection(bv);
1107                 updateLocal(bv, CURSOR_PAR, true);
1108         }
1109         break;
1110
1111         case LFUN_COPY:
1112                 finishUndo();
1113                 lt->copySelection(bv);
1114                 updateLocal(bv, CURSOR_PAR, false);
1115                 break;
1116         case LFUN_PASTESELECTION:
1117         {
1118                 string const clip(bv->getClipboard());
1119         
1120                 if (clip.empty())
1121                         break;
1122                 if (arg == "paragraph") {
1123                         lt->insertStringAsParagraphs(bv, clip);
1124                 } else {
1125                         lt->insertStringAsLines(bv, clip);
1126                 }
1127                 updateLocal(bv, CURSOR_PAR, true);
1128                 break;
1129         }
1130         case LFUN_PASTE: {
1131                 if (!autoBreakRows) {
1132
1133                         if (CutAndPaste::nrOfParagraphs() > 1) {
1134                                 WriteAlert(_("Impossible operation"),
1135                                                    _("Cannot include more than one paragraph!"),
1136                                                    _("Sorry."));
1137                                 break;
1138                         }
1139                 }
1140                 setUndo(bv, Undo::INSERT,
1141                         lt->cursor.par(), lt->cursor.par()->next());
1142                 lt->pasteSelection(bv);
1143                 updateLocal(bv, CURSOR_PAR, true);
1144         }
1145         break;
1146
1147         case LFUN_BREAKPARAGRAPH:
1148                 if (!autoBreakRows) {
1149                         result = DISPATCHED;
1150                         break;
1151                 }
1152                 lt->breakParagraph(bv, 0);
1153                 updateLocal(bv, FULL, true);
1154                 break;
1155         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1156                 if (!autoBreakRows) {
1157                         result = DISPATCHED;
1158                         break;
1159                 }
1160                 lt->breakParagraph(bv, 1);
1161                 updateLocal(bv, FULL, true);
1162                 break;
1163
1164         case LFUN_BREAKLINE: {
1165                 if (!autoBreakRows) {
1166                         result = DISPATCHED;
1167                         break;
1168                 }
1169                 setUndo(bv, Undo::INSERT,
1170                         lt->cursor.par(), lt->cursor.par()->next());
1171                 lt->insertChar(bv, Paragraph::META_NEWLINE);
1172                 updateLocal(bv, CURSOR_PAR, true);
1173         }
1174         break;
1175
1176         case LFUN_LAYOUT:
1177                 // do not set layouts on non breakable textinsets
1178                 if (autoBreakRows) {
1179                         LyXTextClass::size_type cur_layout = cpar(bv)->layout;
1180           
1181                         // Derive layout number from given argument (string)
1182                         // and current buffer's textclass (number). */    
1183                         LyXTextClassList::ClassList::size_type tclass =
1184                                 bv->buffer()->params.textclass;
1185                         std::pair <bool, LyXTextClass::size_type> layout = 
1186                                 textclasslist.NumberOfLayout(tclass, arg);
1187
1188                         // If the entry is obsolete, use the new one instead.
1189                         if (layout.first) {
1190                                 string obs = textclasslist.Style(tclass,layout.second).
1191                                         obsoleted_by();
1192                                 if (!obs.empty()) 
1193                                         layout = textclasslist.NumberOfLayout(tclass, obs);
1194                         }
1195
1196                         // see if we found the layout number:
1197                         if (!layout.first) {
1198                                 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1199                                 bv->owner()->getLyXFunc()->dispatch(LFUN_MESSAGE, msg);
1200                                 break;
1201                         }
1202
1203                         if (cur_layout != layout.second) {
1204                                 cur_layout = layout.second;
1205                                 lt->setLayout(bv, layout.second);
1206                                 bv->owner()->setLayout(cpar(bv)->getLayout());
1207                                 updateLocal(bv, CURSOR_PAR, true);
1208                         }
1209                 } else {
1210                         // reset the layout box
1211                         bv->owner()->setLayout(cpar(bv)->getLayout());
1212                 }
1213                 break;
1214         case LFUN_PARAGRAPH_SPACING:
1215                 // This one is absolutely not working. When fiddling with this
1216                 // it also seems to me that the paragraphs inside the insettext
1217                 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1218         {
1219                 Paragraph * par = lt->cursor.par();
1220                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
1221                 float cur_value = 1.0;
1222                 if (cur_spacing == Spacing::Other) {
1223                         cur_value = par->params().spacing().getValue();
1224                 }
1225                                 
1226                 istringstream istr(arg.c_str());
1227                 string tmp;
1228                 istr >> tmp;
1229                 Spacing::Space new_spacing = cur_spacing;
1230                 float new_value = cur_value;
1231                 if (tmp.empty()) {
1232                         lyxerr << "Missing argument to `paragraph-spacing'"
1233                                    << endl;
1234                 } else if (tmp == "single") {
1235                         new_spacing = Spacing::Single;
1236                 } else if (tmp == "onehalf") {
1237                         new_spacing = Spacing::Onehalf;
1238                 } else if (tmp == "double") {
1239                         new_spacing = Spacing::Double;
1240                 } else if (tmp == "other") {
1241                         new_spacing = Spacing::Other;
1242                         float tmpval = 0.0;
1243                         istr >> tmpval;
1244                         lyxerr << "new_value = " << tmpval << endl;
1245                         if (tmpval != 0.0)
1246                                 new_value = tmpval;
1247                 } else if (tmp == "default") {
1248                         new_spacing = Spacing::Default;
1249                 } else {
1250                         lyxerr << _("Unknown spacing argument: ")
1251                                    << arg << endl;
1252                 }
1253                 if (cur_spacing != new_spacing || cur_value != new_value) {
1254                         par->params().spacing(Spacing(new_spacing, new_value));
1255                         updateLocal(bv, CURSOR_PAR, true);
1256                 }
1257         }
1258         break;
1259         
1260         default:
1261                 if (!bv->Dispatch(action, arg))
1262                         result = UNDISPATCHED;
1263                 break;
1264         }
1265
1266         /// If the action has deleted all text in the inset, we need to change the
1267         // language to the language of the surronding text.
1268         if (par->size() == 0 && !par->next()) {
1269                 LyXFont font(LyXFont::ALL_IGNORE);
1270                 font.setLanguage(bv->getParentLanguage(this));
1271                 setFont(bv, font, false);
1272         }
1273
1274         if (result != FINISHED) {
1275                 showInsetCursor(bv);
1276         } else
1277                 bv->unlockInset(this);
1278         if (clear)
1279                 lt = 0;
1280         return result;
1281 }
1282
1283
1284 int InsetText::latex(Buffer const * buf, ostream & os, bool, bool) const
1285 {
1286         TexRow texrow;
1287         buf->latexParagraphs(os, par, 0, texrow);
1288         return texrow.rows();
1289 }
1290
1291
1292 int InsetText::ascii(Buffer const * buf, ostream & os, int linelen) const
1293 {
1294         Paragraph * p = par;
1295         unsigned int lines = 0;
1296         
1297         while (p) {
1298                 string const tmp = buf->asciiParagraph(p, linelen);
1299                 lines += countChar(tmp, '\n');
1300                 os << tmp;
1301                 p = p->next();
1302         }
1303         return lines;
1304 }
1305
1306
1307 int InsetText::docBook(Buffer const * buf, ostream & os) const
1308 {
1309         Paragraph * p = par;
1310         unsigned int lines = 0;
1311         int desc = 0;
1312         
1313         string tmp;
1314         while (p) {
1315                 buf->simpleDocBookOnePar(os, tmp, p, desc, 0);
1316                 p = p->next();
1317         }
1318         
1319         return lines;
1320 }
1321
1322
1323 void InsetText::validate(LaTeXFeatures & features) const
1324 {
1325         Paragraph * p = par;
1326         while (p) {
1327                 p->validate(features);
1328                 p = p->next();
1329         }
1330 }
1331
1332
1333 int InsetText::beginningOfMainBody(Buffer const * buf, Paragraph * p) const
1334 {
1335         if (textclasslist.Style(buf->params.textclass,
1336                                 p->getLayout()).labeltype != LABEL_MANUAL)
1337                 return 0;
1338         else
1339                 return p->beginningOfMainBody();
1340 }
1341
1342
1343 void InsetText::getCursorPos(BufferView * bv,
1344                              int & x, int & y) const
1345 {
1346         if (the_locking_inset) {
1347                 the_locking_inset->getCursorPos(bv, x, y);
1348                 return;
1349         }
1350         x = cx(bv);
1351         y = cy(bv);
1352 }
1353
1354
1355 unsigned int InsetText::insetInInsetY()
1356 {
1357         if (!the_locking_inset)
1358                 return 0;
1359
1360         return (inset_y + the_locking_inset->insetInInsetY());
1361 }
1362
1363
1364 void InsetText::toggleInsetCursor(BufferView * bv)
1365 {
1366         if (the_locking_inset) {
1367                 the_locking_inset->toggleInsetCursor(bv);
1368                 return;
1369         }
1370
1371         LyXFont const font(getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv)));
1372
1373         int const asc = lyxfont::maxAscent(font);
1374         int const desc = lyxfont::maxDescent(font);
1375   
1376         if (isCursorVisible())
1377                 bv->hideLockedInsetCursor();
1378         else
1379                 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1380         toggleCursorVisible();
1381 }
1382
1383
1384 void InsetText::showInsetCursor(BufferView * bv, bool show)
1385 {
1386         if (the_locking_inset) {
1387                 the_locking_inset->showInsetCursor(bv, show);
1388                 return;
1389         }
1390         if (!isCursorVisible()) {
1391                 LyXFont const font =
1392                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1393         
1394                 int const asc = lyxfont::maxAscent(font);
1395                 int const desc = lyxfont::maxDescent(font);
1396
1397                 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1398                 if (show)
1399                         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1400                 setCursorVisible(true);
1401         }
1402 }
1403
1404
1405 void InsetText::hideInsetCursor(BufferView * bv)
1406 {
1407         if (isCursorVisible()) {
1408                 bv->hideLockedInsetCursor();
1409                 setCursorVisible(false);
1410         }
1411         if (the_locking_inset)
1412                 the_locking_inset->hideInsetCursor(bv);
1413 }
1414
1415
1416 void InsetText::fitInsetCursor(BufferView * bv) const
1417 {
1418         if (the_locking_inset) {
1419                 the_locking_inset->fitInsetCursor(bv);
1420                 return;
1421         }
1422         LyXFont const font =
1423                 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1424         
1425         int const asc = lyxfont::maxAscent(font);
1426         int const desc = lyxfont::maxDescent(font);
1427
1428         bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1429 }
1430
1431
1432 UpdatableInset::RESULT
1433 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1434 {
1435         if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1436                 return moveLeftIntern(bv, false, activate_inset, selecting);
1437         else
1438                 return moveRightIntern(bv, false, activate_inset, selecting);
1439 }
1440
1441
1442 UpdatableInset::RESULT
1443 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1444 {
1445         if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1446                 return moveRightIntern(bv, true, activate_inset, selecting);
1447         else
1448                 return moveLeftIntern(bv, true, activate_inset, selecting);
1449 }
1450
1451
1452 UpdatableInset::RESULT
1453 InsetText::moveRightIntern(BufferView * bv, bool behind, 
1454                            bool activate_inset, bool selecting)
1455 {
1456         if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1457                 return FINISHED;
1458         if (activate_inset && checkAndActivateInset(bv, behind))
1459                 return DISPATCHED;
1460         getLyXText(bv)->cursorRight(bv);
1461         if (!selecting)
1462                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1463         return DISPATCHED_NOUPDATE;
1464 }
1465
1466
1467 UpdatableInset::RESULT
1468 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1469                           bool activate_inset, bool selecting)
1470 {
1471         if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1472                 return FINISHED;
1473         getLyXText(bv)->cursorLeft(bv);
1474         if (!selecting)
1475                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1476         if (activate_inset && checkAndActivateInset(bv, behind))
1477                 return DISPATCHED;
1478         return DISPATCHED_NOUPDATE;
1479 }
1480
1481
1482 UpdatableInset::RESULT
1483 InsetText::moveUp(BufferView * bv)
1484 {
1485         if (!crow(bv)->previous())
1486                 return FINISHED;
1487         getLyXText(bv)->cursorUp(bv);
1488         return DISPATCHED_NOUPDATE;
1489 }
1490
1491
1492 UpdatableInset::RESULT
1493 InsetText::moveDown(BufferView * bv)
1494 {
1495         if (!crow(bv)->next())
1496                 return FINISHED;
1497         getLyXText(bv)->cursorDown(bv);
1498         return DISPATCHED_NOUPDATE;
1499 }
1500
1501
1502 bool InsetText::insertInset(BufferView * bv, Inset * inset)
1503 {
1504         if (the_locking_inset) {
1505                 if (the_locking_inset->insetAllowed(inset))
1506                         return the_locking_inset->insertInset(bv, inset);
1507                 return false;
1508         }
1509         inset->setOwner(this);
1510         hideInsetCursor(bv);
1511
1512         bool clear = false;
1513         if (!lt) {
1514                 lt = getLyXText(bv);
1515                 clear = true;
1516         }
1517         lt->insertInset(bv, inset);
1518 #if 0
1519         if ((cpar(bv)->getChar(cpos(bv)) != Paragraph::META_INSET) ||
1520                 (cpar(bv)->getInset(cpos(bv)) != inset))
1521                 lt->cursorLeft(bv);
1522 #endif
1523         bv->fitCursor();
1524         updateLocal(bv, CURSOR_PAR|CURSOR, true);
1525         showInsetCursor(bv);
1526         if (clear)
1527                 lt = 0;
1528         return true;
1529 }
1530
1531
1532 bool InsetText::insetAllowed(Inset::Code code) const
1533 {
1534         if (the_locking_inset)
1535                 return the_locking_inset->insetAllowed(code);
1536         return true;
1537 }
1538
1539
1540 UpdatableInset * InsetText::getLockingInset() const
1541 {
1542         return the_locking_inset ? the_locking_inset->getLockingInset() :
1543                 const_cast<InsetText *>(this);
1544 }
1545
1546
1547 UpdatableInset * InsetText::getFirstLockingInsetOfType(Inset::Code c)
1548 {
1549         if (c == lyxCode())
1550                 return this;
1551         if (the_locking_inset)
1552                 return the_locking_inset->getFirstLockingInsetOfType(c);
1553         return 0;
1554 }
1555
1556
1557 bool InsetText::showInsetDialog(BufferView * bv) const
1558 {
1559         if (the_locking_inset)
1560                 return the_locking_inset->showInsetDialog(bv);
1561         return false;
1562 }
1563
1564
1565 std::vector<string> const InsetText::getLabelList() const 
1566 {
1567         std::vector<string> label_list;
1568
1569         Paragraph * tpar = par;
1570         while (tpar) {
1571                 Paragraph::inset_iterator beg = tpar->inset_iterator_begin();
1572                 Paragraph::inset_iterator end = tpar->inset_iterator_end();
1573                 for (; beg != end; ++beg) {
1574                         std::vector<string> const l = (*beg)->getLabelList();
1575                         label_list.insert(label_list.end(), l.begin(), l.end());
1576                 }
1577                 tpar = tpar->next();
1578         }
1579         return label_list;
1580 }
1581
1582
1583 void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
1584                         bool selectall)
1585 {
1586         if (the_locking_inset) {
1587                 the_locking_inset->setFont(bv, font, toggleall, selectall);
1588                 return;
1589         }
1590         bool clear = false;
1591         if (!lt) {
1592                 lt = getLyXText(bv);
1593                 clear = true;
1594         }
1595         if (lt->selection.set()) {
1596                 setUndo(bv, Undo::EDIT, lt->cursor.par(), lt->cursor.par()->next());
1597         }
1598         if (selectall)
1599                 selectAll(bv);
1600         lt->toggleFree(bv, font, toggleall);
1601         if (selectall)
1602                 lt->clearSelection();
1603         bv->fitCursor();
1604         if (selectall || lt->selection.set())
1605                 updateLocal(bv, FULL, true);
1606         else
1607                 updateLocal(bv, CURSOR_PAR, true);
1608         if (clear)
1609                 lt = 0;
1610 }
1611
1612
1613 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1614 {
1615         if (cpar(bv)->getChar(cpos(bv)) == Paragraph::META_INSET) {
1616                 unsigned int x;
1617                 unsigned int y;
1618                 Inset * inset =
1619                         static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1620                 if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
1621                         return false;
1622                 LyXFont const font =
1623                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1624                 if (behind) {
1625                         x = inset->width(bv, font);
1626                         y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1627                 } else {
1628                         x = 0;
1629                         y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1630                 }
1631                 //inset_x = cx(bv) - top_x + drawTextXOffset;
1632                 //inset_y = cy(bv) + drawTextYOffset;
1633                 inset->edit(bv, x, y, 0);
1634                 if (!the_locking_inset)
1635                         return false;
1636                 updateLocal(bv, CURSOR, false);
1637                 return true;
1638         }
1639         return false;
1640 }
1641
1642
1643 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1644                                       int button)
1645 {
1646         x -= drawTextXOffset;
1647         int dummyx = x;
1648         int dummyy = y + insetAscent;
1649         Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy, button);
1650
1651         if (inset) {
1652                 if (x < 0)
1653                         x = insetWidth;
1654                 if (y < 0)
1655                         y = insetDescent;
1656                 inset_x = cx(bv) - top_x + drawTextXOffset;
1657                 inset_y = cy(bv) + drawTextYOffset;
1658                 inset->edit(bv, x - inset_x, y - inset_y, button);
1659                 if (!the_locking_inset)
1660                         return false;
1661                 updateLocal(bv, CURSOR, false);
1662                 return true;
1663         }
1664         return false;
1665 }
1666
1667
1668 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1669 {
1670         int w = UpdatableInset::getMaxWidth(bv, inset);
1671         if (w < 0) {
1672                 return w;
1673         }
1674         if (owner()) {
1675                 w = w - top_x + owner()->x();
1676                 return w;
1677         }
1678         w -= (2 * TEXT_TO_INSET_OFFSET);
1679         return w - top_x;
1680 }
1681
1682
1683 void InsetText::setParagraphData(Paragraph * p)
1684 {
1685         while (par) {
1686                 Paragraph * tmp = par->next();
1687                 delete par;
1688                 par = tmp;
1689         }
1690
1691         par = new Paragraph(*p);
1692         par->setInsetOwner(this);
1693         Paragraph * np = par;
1694         while (p->next()) {
1695                 p = p->next();
1696                 np->next(new Paragraph(*p));
1697                 np->next()->previous(np);
1698                 np = np->next();
1699                 np->setInsetOwner(this);
1700         }
1701         reinitLyXText();
1702 }
1703
1704
1705 void InsetText::setText(string const & data)
1706 {
1707         clear();
1708         LyXFont font(LyXFont::ALL_SANE);
1709         for (unsigned int i=0; i < data.length(); ++i)
1710                 par->insertChar(i, data[i], font);
1711 }
1712
1713
1714 void InsetText::setAutoBreakRows(bool flag)
1715 {
1716         if (flag != autoBreakRows) {
1717                 autoBreakRows = flag;
1718                 need_update = FULL;
1719                 if (!flag)
1720                         removeNewlines();
1721                 reinitLyXText();
1722         }
1723 }
1724
1725
1726 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
1727 {
1728         if (how != drawFrame_) {
1729                 drawFrame_ = how;
1730                 if (bv)
1731                         updateLocal(bv, DRAW_FRAME, false);
1732         }
1733 }
1734
1735
1736 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
1737 {
1738         if (frame_color != col) {
1739                 frame_color = col;
1740                 if (bv)
1741                         updateLocal(bv, DRAW_FRAME, false);
1742         }
1743 }
1744
1745
1746 int InsetText::cx(BufferView * bv) const
1747 {
1748         bool clear = false;
1749         if (!lt) {
1750                 lt = getLyXText(bv);
1751                 clear = true;
1752         }
1753         int x = lt->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1754         if (the_locking_inset) {
1755                 LyXFont font = lt->getFont(bv->buffer(),
1756                                              lt->cursor.par(),
1757                                              lt->cursor.pos());
1758                 if (font.isVisibleRightToLeft())
1759                         x -= the_locking_inset->width(bv, font);
1760         }
1761         if (clear)
1762                 lt = 0;
1763         return x;
1764 }
1765
1766
1767 int InsetText::cy(BufferView * bv) const
1768 {
1769         LyXFont font;
1770         return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
1771 }
1772
1773
1774 Paragraph::size_type InsetText::cpos(BufferView * bv) const
1775 {
1776         return getLyXText(bv)->cursor.pos();
1777 }
1778
1779
1780 Paragraph * InsetText::cpar(BufferView * bv) const
1781 {
1782         return getLyXText(bv)->cursor.par();
1783 }
1784
1785
1786 bool InsetText::cboundary(BufferView * bv) const
1787 {
1788         return getLyXText(bv)->cursor.boundary();
1789 }
1790
1791
1792 Row * InsetText::crow(BufferView * bv) const
1793 {
1794         return getLyXText(bv)->cursor.row();
1795 }
1796
1797
1798 LyXText * InsetText::getLyXText(BufferView const * lbv,
1799                                           bool const recursive) const
1800 {
1801         if (!recursive && (cached_bview == lbv))
1802                 return cached_text.get();
1803         
1804         // Super UGLY! (Lgb)
1805         BufferView * bv = const_cast<BufferView *>(lbv);
1806         
1807         cached_bview = bv;
1808         Cache::iterator it = cache.find(bv);
1809
1810         if (it != cache.end()) {
1811                 if (lt || !it->second.remove) {
1812                         lyx::Assert(it->second.text.get());
1813                         cached_text = it->second.text;
1814                         if (recursive && the_locking_inset) {
1815                                 return the_locking_inset->getLyXText(bv, true);
1816                         }
1817                         return cached_text.get();
1818                 } else if (it->second.remove) {
1819                         if (locked) {
1820                                 saveLyXTextState(it->second.text.get());
1821                         } else {
1822                                 sstate.lpar = 0;
1823                         }
1824                 }
1825         }
1826         
1827         cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
1828         cached_text->init(bv);
1829         restoreLyXTextState(bv, cached_text.get());
1830
1831         cache.insert(make_pair(bv, cached_text));
1832         
1833         if (the_locking_inset && recursive) {
1834                 return the_locking_inset->getLyXText(bv);
1835         }
1836         return cached_text.get();
1837 }
1838
1839
1840 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1841 {
1842         cached_bview = 0;
1843
1844         Cache::iterator it = cache.find(bv);
1845         
1846         if (it == cache.end()) {
1847                 return;
1848         }
1849
1850         lyx::Assert(it->second.text.get());
1851
1852         it->second.remove = true;
1853         if (recursive) {
1854                 /// then remove all LyXText in text-insets
1855                 Paragraph * p = par;
1856                 for (; p; p = p->next()) {
1857                         p->deleteInsetsLyXText(bv);
1858                 }
1859         }
1860 }
1861
1862
1863 void InsetText::resizeLyXText(BufferView * bv, bool force) const
1864 {
1865         if (!par->next() && !par->size()) // no data, resize not neccessary!
1866                 return;
1867         // one endless line, resize normally not necessary
1868         if (!force && getMaxWidth(bv, this) < 0)
1869                 return;
1870
1871         Cache::iterator it = cache.find(bv);
1872         if (it == cache.end()) {
1873                 return;
1874         }
1875         lyx::Assert(it->second.text.get());
1876
1877         LyXText * t = it->second.text.get();
1878         saveLyXTextState(t);
1879         for (Paragraph * p = par; p; p = p->next()) {
1880                 p->resizeInsetsLyXText(bv);
1881         }
1882         t->init(bv, true);
1883         restoreLyXTextState(bv, t);
1884         if (the_locking_inset) {
1885                 inset_x = cx(bv) - top_x + drawTextXOffset;
1886                 inset_y = cy(bv) + drawTextYOffset;
1887         }
1888
1889         if (bv->screen()) {
1890                         t->first = bv->screen()->topCursorVisible(t);
1891         }
1892         if (!owner())
1893                 updateLocal(bv, FULL, false);
1894         else
1895                 need_update |= FULL;
1896         // this will scroll the screen such that the cursor becomes visible 
1897         bv->updateScrollbar();
1898 }
1899
1900
1901 void InsetText::reinitLyXText() const
1902 {
1903         for(Cache::iterator it = cache.begin(); it != cache.end(); ++it) {
1904                 lyx::Assert(it->second.text.get());
1905
1906                 LyXText * t = it->second.text.get();
1907                 BufferView * bv = it->first;
1908
1909                 saveLyXTextState(t);
1910                 for (Paragraph * p = par; p; p = p->next()) {
1911                         p->resizeInsetsLyXText(bv);
1912                 }
1913                 t->init(bv, true);
1914                 restoreLyXTextState(bv, t);
1915                 if (the_locking_inset) {
1916                         inset_x = cx(bv) - top_x + drawTextXOffset;
1917                         inset_y = cy(bv) + drawTextYOffset;
1918                 }
1919                 if (bv->screen()) {
1920                         t->first = bv->screen()->topCursorVisible(t);
1921                 }
1922                 if (!owner())
1923                         updateLocal(bv, FULL, false);
1924                 else
1925                         need_update = FULL;
1926                 // this will scroll the screen such that the cursor becomes visible 
1927                 bv->updateScrollbar();
1928         }
1929 }
1930
1931
1932 void InsetText::removeNewlines()
1933 {
1934         for (Paragraph * p = par; p; p = p->next()) {
1935                 for (int i = 0; i < p->size(); ++i) {
1936                         if (p->getChar(i) == Paragraph::META_NEWLINE)
1937                                 p->erase(i);
1938                 }
1939         }
1940 }
1941
1942
1943 bool InsetText::nodraw() const
1944 {
1945         if (the_locking_inset)
1946                 return the_locking_inset->nodraw();
1947         return UpdatableInset::nodraw();
1948 }
1949
1950
1951 int InsetText::scroll(bool recursive) const
1952 {
1953         int sx = UpdatableInset::scroll(false);
1954
1955         if (recursive && the_locking_inset)
1956                 sx += the_locking_inset->scroll(recursive);
1957
1958         return sx;
1959 }
1960
1961
1962 bool InsetText::doClearArea() const
1963 {
1964         return !locked || (need_update & (FULL|INIT));
1965 }
1966
1967
1968 void InsetText::selectAll(BufferView * bv)
1969 {
1970         getLyXText(bv)->cursorTop(bv);
1971         getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1972         getLyXText(bv)->cursorBottom(bv);
1973         getLyXText(bv)->setSelection(bv);
1974 }
1975
1976
1977 void InsetText::clearSelection(BufferView * bv)
1978 {
1979         getLyXText(bv)->clearSelection();
1980 }
1981
1982
1983 void InsetText::clearInset(Painter & pain, int baseline, bool & cleared) const
1984 {
1985         int w =  insetWidth;
1986         int h = insetAscent + insetDescent;
1987         int ty = baseline - insetAscent;
1988         
1989         if (ty < 0) {
1990                 h += ty;
1991                 ty = 0;
1992         }
1993         if ((ty + h) > pain.paperHeight())
1994                 h = pain.paperHeight();
1995         if ((top_x + drawTextXOffset + w) > pain.paperWidth())
1996                 w = pain.paperWidth();
1997         pain.fillRectangle(top_x+drawTextXOffset, ty, w, h, backgroundColor());
1998         cleared = true;
1999         need_update = FULL;
2000 }
2001
2002
2003 Paragraph * InsetText::getParFromID(int id) const
2004 {
2005         Paragraph * result = par;
2006         Paragraph * ires = 0;
2007         while (result && result->id() != id) {
2008                 if ((ires = result->getParFromID(id)))
2009                         return ires;
2010                 result = result->next();
2011         }
2012         return result;
2013 }
2014
2015
2016 Paragraph * InsetText::firstParagraph() const
2017 {
2018         Paragraph * result;
2019         if (the_locking_inset)
2020                 if ((result = the_locking_inset->firstParagraph()))
2021                         return result;
2022         return par;
2023 }
2024
2025
2026 LyXCursor const & InsetText::cursor(BufferView * bv) const
2027 {
2028                 if (the_locking_inset)
2029                                 return the_locking_inset->cursor(bv);
2030                 return getLyXText(bv)->cursor;
2031 }
2032
2033
2034 Paragraph * InsetText::paragraph() const
2035 {
2036         return par;
2037 }
2038
2039
2040 void InsetText::paragraph(Paragraph * p)
2041 {
2042         par = p;
2043 #if 0
2044         // we now have to update/redraw all instances
2045         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit) {
2046                 delete cit->second;
2047                 cit->second = 0;
2048         }
2049 #endif
2050         // redraw myself when asked for
2051         need_update |= INIT;
2052 }
2053
2054
2055 Inset * InsetText::getInsetFromID(int id_arg) const
2056 {
2057         if (id_arg == id())
2058                 return const_cast<InsetText *>(this);
2059
2060         Paragraph * lp = par;
2061
2062         while(lp) {
2063                 for (Paragraph::inset_iterator it = lp->inset_iterator_begin(),
2064                          en = lp->inset_iterator_end();
2065                          it != en; ++it)
2066                 {
2067                         if ((*it)->id() == id_arg)
2068                                 return *it;
2069                         Inset * in = (*it)->getInsetFromID(id_arg);
2070                         if (in)
2071                                 return in;
2072                 }
2073                 lp = lp->next();
2074         }
2075         return 0;
2076 }
2077
2078
2079 string const InsetText::selectNextWord(BufferView * bv, float & value) const
2080 {
2081         bool clear = false;
2082         string str;
2083
2084         if (!lt) {
2085                 lt = getLyXText(bv);
2086                 clear = true;
2087         }
2088         if (the_locking_inset) {
2089                 str = the_locking_inset->selectNextWord(bv, value);
2090                 if (!str.empty()) {
2091                         value += cy(bv);
2092                         if (clear)
2093                                 lt = 0;
2094                         return str;
2095                 }
2096 #warning Dekel please have a look on this one RTL? (Jug)
2097                 // we have to go on checking so move cusor to the right
2098                 lt->cursor.pos(lt->cursor.pos() + 1);
2099         }
2100         str = lt->selectNextWord(bv, value);
2101         if (str.empty())
2102                 bv->unlockInset(const_cast<InsetText *>(this));
2103         else
2104                 value = cy(bv);
2105         if (clear)
2106                 lt = 0;
2107         return str;
2108 }
2109
2110
2111 void InsetText::selectSelectedWord(BufferView * bv)
2112 {
2113         if (the_locking_inset) {
2114                 the_locking_inset->selectSelectedWord(bv);
2115                 return;
2116         }
2117         getLyXText(bv)->selectSelectedWord(bv);
2118         updateLocal(bv, SELECTION, false);
2119 }
2120
2121
2122 void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
2123 {
2124         if (the_locking_inset) {
2125                 the_locking_inset->toggleSelection(bv, kill_selection);
2126         }
2127         bool clear = false;
2128         if (!lt) {
2129                 lt = getLyXText(bv);
2130                 clear = true;
2131         }
2132
2133         int x = top_x + TEXT_TO_INSET_OFFSET;
2134
2135         int y = 0;
2136         Row * row = lt->getRowNearY(y);
2137         int y_offset = top_baseline - row->ascent_of_text();
2138         y = y_offset;
2139         while ((row != 0) && ((y+row->height()) <= 0)) {
2140                 y += row->height();
2141                 row = row->next();
2142         }
2143         if (y_offset < 0)
2144                 y_offset = y;
2145         
2146         if (need_update & SELECTION)
2147                 need_update = NONE;
2148         bv->screen()->toggleSelection(lt, bv, kill_selection, y_offset, x);
2149         if (clear)
2150                 lt = 0;
2151 }
2152
2153
2154 bool InsetText::searchForward(BufferView * bv, string const & str,
2155                               bool const & cs, bool const & mw)
2156 {
2157         if (the_locking_inset) {
2158                 if (the_locking_inset->searchForward(bv, str, cs, mw))
2159                         return true;
2160                 bool clear = false;
2161                 if (!lt) {
2162                         lt = getLyXText(bv);
2163                         clear = true;
2164                 }
2165                 Paragraph * lpar = lt->cursor.par();
2166                 Paragraph::size_type pos = lt->cursor.pos();
2167                 if (pos < lpar->size() - 1)
2168                         ++pos;
2169                 else {
2170                         pos = 0;
2171                         lpar = lpar->next();
2172                 }
2173                 if (!lpar) {
2174                         if (clear)
2175                                 lt = 0;
2176                         return false;
2177                 }
2178                 lt->setCursor(bv, lpar, pos);
2179                 if (clear)
2180                         lt = 0;
2181         }
2182         if (LyXFind(bv, str, true, true, cs , mw)) {
2183                 return true;
2184         }
2185         // we have to unlock ourself in this function by default!
2186         bv->unlockInset(const_cast<InsetText *>(this));
2187         return false;
2188 }
2189
2190 bool InsetText::searchBackward(BufferView * bv, string const & str,
2191                                bool const & cs, bool const & mw)
2192 {
2193         if (the_locking_inset)
2194                 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2195                         return true;
2196         if (LyXFind(bv, str, false, true, cs, mw)) {
2197                 return true;
2198         }
2199         // we have to unlock ourself in this function by default!
2200         bv->unlockInset(const_cast<InsetText *>(this));
2201         return false;
2202 }