]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
get rid of NO_LATEX, split some methods, small cleanup
[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 #ifndef NO_COMPABILITY
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         if ((!par->next() && !par->size()) || !cpar(bv)->size()) {
1583                 getLyXText(bv)->setFont(bv, font, toggleall);
1584                 return;
1585         }
1586         bool clear = false;
1587         if (!lt) {
1588                 lt = getLyXText(bv);
1589                 clear = true;
1590         }
1591         if (lt->selection.set()) {
1592                 setUndo(bv, Undo::EDIT, lt->cursor.par(), lt->cursor.par()->next());
1593         }
1594         if (selectall)
1595                 selectAll(bv);
1596         lt->toggleFree(bv, font, toggleall);
1597         if (selectall)
1598                 lt->clearSelection();
1599         bv->fitCursor();
1600         if (selectall || lt->selection.set())
1601                 updateLocal(bv, FULL, true);
1602         else
1603                 updateLocal(bv, CURSOR_PAR, true);
1604         if (clear)
1605                 lt = 0;
1606 }
1607
1608
1609 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1610 {
1611         if (cpar(bv)->getChar(cpos(bv)) == Paragraph::META_INSET) {
1612                 unsigned int x;
1613                 unsigned int y;
1614                 Inset * inset =
1615                         static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1616                 if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
1617                         return false;
1618                 LyXFont const font =
1619                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1620                 if (behind) {
1621                         x = inset->width(bv, font);
1622                         y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1623                 } else {
1624                         x = 0;
1625                         y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1626                 }
1627                 //inset_x = cx(bv) - top_x + drawTextXOffset;
1628                 //inset_y = cy(bv) + drawTextYOffset;
1629                 inset->edit(bv, x, y, 0);
1630                 if (!the_locking_inset)
1631                         return false;
1632                 updateLocal(bv, CURSOR, false);
1633                 return true;
1634         }
1635         return false;
1636 }
1637
1638
1639 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1640                                       int button)
1641 {
1642         x -= drawTextXOffset;
1643         int dummyx = x;
1644         int dummyy = y + insetAscent;
1645         Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy, button);
1646
1647         if (inset) {
1648                 if (x < 0)
1649                         x = insetWidth;
1650                 if (y < 0)
1651                         y = insetDescent;
1652                 inset_x = cx(bv) - top_x + drawTextXOffset;
1653                 inset_y = cy(bv) + drawTextYOffset;
1654                 inset->edit(bv, x - inset_x, y - inset_y, button);
1655                 if (!the_locking_inset)
1656                         return false;
1657                 updateLocal(bv, CURSOR, false);
1658                 return true;
1659         }
1660         return false;
1661 }
1662
1663
1664 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1665 {
1666         int w = UpdatableInset::getMaxWidth(bv, inset);
1667         if (w < 0) {
1668                 return w;
1669         }
1670         if (owner()) {
1671                 w = w - top_x + owner()->x();
1672                 return w;
1673         }
1674         w -= (2 * TEXT_TO_INSET_OFFSET);
1675         return w - top_x;
1676 }
1677
1678
1679 void InsetText::setParagraphData(Paragraph * p)
1680 {
1681         while (par) {
1682                 Paragraph * tmp = par->next();
1683                 delete par;
1684                 par = tmp;
1685         }
1686
1687         par = new Paragraph(*p);
1688         par->setInsetOwner(this);
1689         Paragraph * np = par;
1690         while (p->next()) {
1691                 p = p->next();
1692                 np->next(new Paragraph(*p));
1693                 np->next()->previous(np);
1694                 np = np->next();
1695                 np->setInsetOwner(this);
1696         }
1697         reinitLyXText();
1698 }
1699
1700
1701 void InsetText::setText(string const & data)
1702 {
1703         clear();
1704         LyXFont font(LyXFont::ALL_SANE);
1705         for (unsigned int i=0; i < data.length(); ++i)
1706                 par->insertChar(i, data[i], font);
1707 }
1708
1709
1710 void InsetText::setAutoBreakRows(bool flag)
1711 {
1712         if (flag != autoBreakRows) {
1713                 autoBreakRows = flag;
1714                 need_update = FULL;
1715                 if (!flag)
1716                         removeNewlines();
1717                 reinitLyXText();
1718         }
1719 }
1720
1721
1722 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
1723 {
1724         if (how != drawFrame_) {
1725                 drawFrame_ = how;
1726                 if (bv)
1727                         updateLocal(bv, DRAW_FRAME, false);
1728         }
1729 }
1730
1731
1732 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
1733 {
1734         if (frame_color != col) {
1735                 frame_color = col;
1736                 if (bv)
1737                         updateLocal(bv, DRAW_FRAME, false);
1738         }
1739 }
1740
1741
1742 int InsetText::cx(BufferView * bv) const
1743 {
1744         bool clear = false;
1745         if (!lt) {
1746                 lt = getLyXText(bv);
1747                 clear = true;
1748         }
1749         int x = lt->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1750         if (the_locking_inset) {
1751                 LyXFont font = lt->getFont(bv->buffer(),
1752                                              lt->cursor.par(),
1753                                              lt->cursor.pos());
1754                 if (font.isVisibleRightToLeft())
1755                         x -= the_locking_inset->width(bv, font);
1756         }
1757         if (clear)
1758                 lt = 0;
1759         return x;
1760 }
1761
1762
1763 int InsetText::cy(BufferView * bv) const
1764 {
1765         LyXFont font;
1766         return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
1767 }
1768
1769
1770 Paragraph::size_type InsetText::cpos(BufferView * bv) const
1771 {
1772         return getLyXText(bv)->cursor.pos();
1773 }
1774
1775
1776 Paragraph * InsetText::cpar(BufferView * bv) const
1777 {
1778         return getLyXText(bv)->cursor.par();
1779 }
1780
1781
1782 bool InsetText::cboundary(BufferView * bv) const
1783 {
1784         return getLyXText(bv)->cursor.boundary();
1785 }
1786
1787
1788 Row * InsetText::crow(BufferView * bv) const
1789 {
1790         return getLyXText(bv)->cursor.row();
1791 }
1792
1793
1794 LyXText * InsetText::getLyXText(BufferView const * lbv,
1795                                           bool const recursive) const
1796 {
1797         if (!recursive && (cached_bview == lbv))
1798                 return cached_text.get();
1799         
1800         // Super UGLY! (Lgb)
1801         BufferView * bv = const_cast<BufferView *>(lbv);
1802         
1803         cached_bview = bv;
1804         Cache::iterator it = cache.find(bv);
1805
1806         if (it != cache.end()) {
1807                 if (lt || !it->second.remove) {
1808                         lyx::Assert(it->second.text.get());
1809                         cached_text = it->second.text;
1810                         if (recursive && the_locking_inset) {
1811                                 return the_locking_inset->getLyXText(bv, true);
1812                         }
1813                         return cached_text.get();
1814                 } else if (it->second.remove) {
1815                         if (locked) {
1816                                 saveLyXTextState(it->second.text.get());
1817                         } else {
1818                                 sstate.lpar = 0;
1819                         }
1820                 }
1821         }
1822         
1823         cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
1824         cached_text->init(bv);
1825         restoreLyXTextState(bv, cached_text.get());
1826
1827         cache.insert(make_pair(bv, cached_text));
1828         
1829         if (the_locking_inset && recursive) {
1830                 return the_locking_inset->getLyXText(bv);
1831         }
1832         return cached_text.get();
1833 }
1834
1835
1836 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1837 {
1838         cached_bview = 0;
1839
1840         Cache::iterator it = cache.find(bv);
1841         
1842         if (it == cache.end()) {
1843                 return;
1844         }
1845
1846         lyx::Assert(it->second.text.get());
1847
1848         it->second.remove = true;
1849         if (recursive) {
1850                 /// then remove all LyXText in text-insets
1851                 Paragraph * p = par;
1852                 for (; p; p = p->next()) {
1853                         p->deleteInsetsLyXText(bv);
1854                 }
1855         }
1856 }
1857
1858
1859 void InsetText::resizeLyXText(BufferView * bv, bool force) const
1860 {
1861         if (!par->next() && !par->size()) // no data, resize not neccessary!
1862                 return;
1863         // one endless line, resize normally not necessary
1864         if (!force && getMaxWidth(bv, this) < 0)
1865                 return;
1866
1867         Cache::iterator it = cache.find(bv);
1868         if (it == cache.end()) {
1869                 return;
1870         }
1871         lyx::Assert(it->second.text.get());
1872
1873         LyXText * t = it->second.text.get();
1874         saveLyXTextState(t);
1875         for (Paragraph * p = par; p; p = p->next()) {
1876                 p->resizeInsetsLyXText(bv);
1877         }
1878         t->init(bv, true);
1879         restoreLyXTextState(bv, t);
1880         if (the_locking_inset) {
1881                 inset_x = cx(bv) - top_x + drawTextXOffset;
1882                 inset_y = cy(bv) + drawTextYOffset;
1883         }
1884
1885         if (bv->screen()) {
1886                         t->first = bv->screen()->topCursorVisible(t);
1887         }
1888         if (!owner())
1889                 updateLocal(bv, FULL, false);
1890         else
1891                 need_update |= FULL;
1892         // this will scroll the screen such that the cursor becomes visible 
1893         bv->updateScrollbar();
1894 }
1895
1896
1897 void InsetText::reinitLyXText() const
1898 {
1899         for(Cache::iterator it = cache.begin(); it != cache.end(); ++it) {
1900                 lyx::Assert(it->second.text.get());
1901
1902                 LyXText * t = it->second.text.get();
1903                 BufferView * bv = it->first;
1904
1905                 saveLyXTextState(t);
1906                 for (Paragraph * p = par; p; p = p->next()) {
1907                         p->resizeInsetsLyXText(bv);
1908                 }
1909                 t->init(bv, true);
1910                 restoreLyXTextState(bv, t);
1911                 if (the_locking_inset) {
1912                         inset_x = cx(bv) - top_x + drawTextXOffset;
1913                         inset_y = cy(bv) + drawTextYOffset;
1914                 }
1915                 if (bv->screen()) {
1916                         t->first = bv->screen()->topCursorVisible(t);
1917                 }
1918                 if (!owner())
1919                         updateLocal(bv, FULL, false);
1920                 else
1921                         need_update = FULL;
1922                 // this will scroll the screen such that the cursor becomes visible 
1923                 bv->updateScrollbar();
1924         }
1925 }
1926
1927
1928 void InsetText::removeNewlines()
1929 {
1930         for (Paragraph * p = par; p; p = p->next()) {
1931                 for (int i = 0; i < p->size(); ++i) {
1932                         if (p->getChar(i) == Paragraph::META_NEWLINE)
1933                                 p->erase(i);
1934                 }
1935         }
1936 }
1937
1938
1939 bool InsetText::nodraw() const
1940 {
1941         if (the_locking_inset)
1942                 return the_locking_inset->nodraw();
1943         return UpdatableInset::nodraw();
1944 }
1945
1946
1947 int InsetText::scroll(bool recursive) const
1948 {
1949         int sx = UpdatableInset::scroll(false);
1950
1951         if (recursive && the_locking_inset)
1952                 sx += the_locking_inset->scroll(recursive);
1953
1954         return sx;
1955 }
1956
1957
1958 bool InsetText::doClearArea() const
1959 {
1960         return !locked || (need_update & (FULL|INIT));
1961 }
1962
1963
1964 void InsetText::selectAll(BufferView * bv)
1965 {
1966         getLyXText(bv)->cursorTop(bv);
1967         getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1968         getLyXText(bv)->cursorBottom(bv);
1969         getLyXText(bv)->setSelection(bv);
1970 }
1971
1972
1973 void InsetText::clearSelection(BufferView * bv)
1974 {
1975         getLyXText(bv)->clearSelection();
1976 }
1977
1978
1979 void InsetText::clearInset(Painter & pain, int baseline, bool & cleared) const
1980 {
1981         int w =  insetWidth;
1982         int h = insetAscent + insetDescent;
1983         int ty = baseline - insetAscent;
1984         
1985         if (ty < 0) {
1986                 h += ty;
1987                 ty = 0;
1988         }
1989         if ((ty + h) > pain.paperHeight())
1990                 h = pain.paperHeight();
1991         if ((top_x + drawTextXOffset + w) > pain.paperWidth())
1992                 w = pain.paperWidth();
1993         pain.fillRectangle(top_x+drawTextXOffset, ty, w, h, backgroundColor());
1994         cleared = true;
1995         need_update = FULL;
1996 }
1997
1998
1999 Paragraph * InsetText::getParFromID(int id) const
2000 {
2001         Paragraph * result = par;
2002         Paragraph * ires = 0;
2003         while (result && result->id() != id) {
2004                 if ((ires = result->getParFromID(id)))
2005                         return ires;
2006                 result = result->next();
2007         }
2008         return result;
2009 }
2010
2011
2012 Paragraph * InsetText::firstParagraph() const
2013 {
2014         Paragraph * result;
2015         if (the_locking_inset)
2016                 if ((result = the_locking_inset->firstParagraph()))
2017                         return result;
2018         return par;
2019 }
2020
2021
2022 LyXCursor const & InsetText::cursor(BufferView * bv) const
2023 {
2024                 if (the_locking_inset)
2025                                 return the_locking_inset->cursor(bv);
2026                 return getLyXText(bv)->cursor;
2027 }
2028
2029
2030 Paragraph * InsetText::paragraph() const
2031 {
2032         return par;
2033 }
2034
2035
2036 void InsetText::paragraph(Paragraph * p)
2037 {
2038         par = p;
2039 #if 0
2040         // we now have to update/redraw all instances
2041         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit) {
2042                 delete cit->second;
2043                 cit->second = 0;
2044         }
2045 #endif
2046         // redraw myself when asked for
2047         need_update |= INIT;
2048 }
2049
2050
2051 Inset * InsetText::getInsetFromID(int id_arg) const
2052 {
2053         if (id_arg == id())
2054                 return const_cast<InsetText *>(this);
2055
2056         Paragraph * lp = par;
2057
2058         while(lp) {
2059                 for (Paragraph::inset_iterator it = lp->inset_iterator_begin(),
2060                          en = lp->inset_iterator_end();
2061                          it != en; ++it)
2062                 {
2063                         if ((*it)->id() == id_arg)
2064                                 return *it;
2065                         Inset * in = (*it)->getInsetFromID(id_arg);
2066                         if (in)
2067                                 return in;
2068                 }
2069                 lp = lp->next();
2070         }
2071         return 0;
2072 }
2073
2074
2075 string const InsetText::selectNextWord(BufferView * bv, float & value) const
2076 {
2077         bool clear = false;
2078         string str;
2079
2080         if (!lt) {
2081                 lt = getLyXText(bv);
2082                 clear = true;
2083         }
2084         if (the_locking_inset) {
2085                 str = the_locking_inset->selectNextWord(bv, value);
2086                 if (!str.empty()) {
2087                         value += cy(bv);
2088                         if (clear)
2089                                 lt = 0;
2090                         return str;
2091                 }
2092 #warning Dekel please have a look on this one RTL? (Jug)
2093                 // we have to go on checking so move cusor to the right
2094                 lt->cursor.pos(lt->cursor.pos() + 1);
2095         }
2096         str = lt->selectNextWord(bv, value);
2097         if (str.empty())
2098                 bv->unlockInset(const_cast<InsetText *>(this));
2099         else
2100                 value = cy(bv);
2101         if (clear)
2102                 lt = 0;
2103         return str;
2104 }
2105
2106
2107 void InsetText::selectSelectedWord(BufferView * bv)
2108 {
2109         if (the_locking_inset) {
2110                 the_locking_inset->selectSelectedWord(bv);
2111                 return;
2112         }
2113         getLyXText(bv)->selectSelectedWord(bv);
2114         updateLocal(bv, SELECTION, false);
2115 }
2116
2117
2118 void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
2119 {
2120         if (the_locking_inset) {
2121                 the_locking_inset->toggleSelection(bv, kill_selection);
2122         }
2123         bool clear = false;
2124         if (!lt) {
2125                 lt = getLyXText(bv);
2126                 clear = true;
2127         }
2128
2129         int x = top_x + TEXT_TO_INSET_OFFSET;
2130
2131         int y = 0;
2132         Row * row = lt->getRowNearY(y);
2133         int y_offset = top_baseline - row->ascent_of_text();
2134         y = y_offset;
2135         while ((row != 0) && ((y+row->height()) <= 0)) {
2136                 y += row->height();
2137                 row = row->next();
2138         }
2139         if (y_offset < 0)
2140                 y_offset = y;
2141         
2142         if (need_update & SELECTION)
2143                 need_update = NONE;
2144         bv->screen()->toggleSelection(lt, bv, kill_selection, y_offset, x);
2145         if (clear)
2146                 lt = 0;
2147 }
2148
2149
2150 bool InsetText::searchForward(BufferView * bv, string const & str,
2151                               bool const & cs, bool const & mw)
2152 {
2153         if (the_locking_inset) {
2154                 if (the_locking_inset->searchForward(bv, str, cs, mw))
2155                         return true;
2156                 bool clear = false;
2157                 if (!lt) {
2158                         lt = getLyXText(bv);
2159                         clear = true;
2160                 }
2161                 Paragraph * lpar = lt->cursor.par();
2162                 Paragraph::size_type pos = lt->cursor.pos();
2163                 if (pos < lpar->size() - 1)
2164                         ++pos;
2165                 else {
2166                         pos = 0;
2167                         lpar = lpar->next();
2168                 }
2169                 if (!lpar) {
2170                         if (clear)
2171                                 lt = 0;
2172                         return false;
2173                 }
2174                 lt->setCursor(bv, lpar, pos);
2175                 if (clear)
2176                         lt = 0;
2177         }
2178         if (LyXFind(bv, str, true, true, cs , mw)) {
2179                 return true;
2180         }
2181         // we have to unlock ourself in this function by default!
2182         bv->unlockInset(const_cast<InsetText *>(this));
2183         return false;
2184 }
2185
2186 bool InsetText::searchBackward(BufferView * bv, string const & str,
2187                                bool const & cs, bool const & mw)
2188 {
2189         if (the_locking_inset)
2190                 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2191                         return true;
2192         if (LyXFind(bv, str, false, true, cs, mw)) {
2193                 return true;
2194         }
2195         // we have to unlock ourself in this function by default!
2196         bv->unlockInset(const_cast<InsetText *>(this));
2197         return false;
2198 }