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