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