]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
encoding patch and mousewheelpatch
[lyx.git] / src / insets / insettext.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ======================================================
4  * 
5  *           LyX, The Document Processor
6  *
7  *           Copyright 1998-2000 The LyX Team.
8  *
9  * ======================================================
10  */
11
12 #include <config.h>
13
14 #include <fstream>
15 #include <algorithm>
16
17 #include <cstdlib>
18
19 #ifdef __GNUG__
20 #pragma implementation
21 #endif
22
23 #include "insettext.h"
24 #include "lyxparagraph.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 "minibuffer.h"
41 #include "toolbar.h"
42 #include "LColor.h"
43 #include "support/textutils.h"
44 #include "support/LAssert.h"
45 #include "lyxrow.h"
46 #include "lyxrc.h"
47 #include "intl.h"
48 #include "trans_mgr.h"
49 #include "lyxscreen.h"
50
51 using std::ostream;
52 using std::ifstream;
53 using std::endl;
54 using std::min;
55 using std::max;
56
57 extern unsigned char getCurrentTextClass(Buffer *);
58
59 InsetText::InsetText()
60 {
61     par = new LyXParagraph();
62     init();
63 }
64
65
66 InsetText::InsetText(InsetText const & ins)
67         : UpdatableInset()
68 {
69     par = 0;
70     init(&ins);
71     autoBreakRows = ins.autoBreakRows;
72 }
73
74
75 InsetText & InsetText::operator=(InsetText const & it)
76 {
77     init(&it);
78     autoBreakRows = it.autoBreakRows;
79     return * this;
80 }
81
82 void InsetText::init(InsetText const * ins)
83 {
84     top_y = last_width = last_height = 0;
85     insetAscent = insetDescent = insetWidth = 0;
86     the_locking_inset = 0;
87     cursor_visible = false;
88     interline_space = 1;
89     no_selection = false;
90     need_update = INIT;
91     drawTextXOffset = drawTextYOffset = 0;
92     autoBreakRows = false;
93     drawFrame = NEVER;
94     xpos = 0.0;
95     if (ins) {
96         SetParagraphData(ins->par);
97         autoBreakRows = ins->autoBreakRows;
98         drawFrame = ins->drawFrame;
99     }
100     par->SetInsetOwner(this);
101     frame_color = LColor::insetframe;
102     locked = false;
103     old_par = 0;
104 }
105
106
107 InsetText::~InsetText()
108 {
109     LyXParagraph * p = par->next;
110     delete par;
111     while(p) {
112         par = p;
113         p = p->next;
114         delete par;
115     }
116 }
117
118
119 Inset * InsetText::Clone() const
120 {
121     InsetText * t = new InsetText(*this);
122     return t;
123 }
124
125
126 void InsetText::Write(Buffer const * buf, ostream & os) const
127 {
128     os << "Text\n";
129     WriteParagraphData(buf, os);
130 }
131
132
133 void InsetText::WriteParagraphData(Buffer const * buf, ostream & os) const
134 {
135     par->writeFile(buf, os, buf->params, 0, 0);
136 }
137
138
139 void InsetText::Read(Buffer const * buf, LyXLex & lex)
140 {
141     string token;
142     int pos = 0;
143     LyXParagraph * return_par = 0;
144     char depth = 0; // signed or unsigned?
145     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
146     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
147     LyXFont font(LyXFont::ALL_INHERIT);
148
149     LyXParagraph * p = par->next;
150     delete par;
151     while(p) {
152         par = p;
153         p = p->next;
154         delete par;
155     }
156     par = new LyXParagraph;
157     while (lex.IsOK()) {
158         lex.nextToken();
159         token = lex.GetString();
160         if (token.empty())
161             continue;
162         if (token == "\\end_inset")
163             break;
164         if (const_cast<Buffer*>(buf)->parseSingleLyXformat2Token(lex, par, return_par,
165                                             token, pos, depth,
166                                             font, footnoteflag,
167                                             footnotekind)) {
168             // the_end read this should NEVER happen
169             lex.printError("\\the_end read in inset! Error in document!");
170             return;
171         }
172     }
173     if (!return_par)
174             return_par = par;
175     par = return_par;
176     while(return_par) {
177         return_par->SetInsetOwner(this);
178         return_par = return_par->next;
179     }
180     
181     if (token != "\\end_inset") {
182         lex.printError("Missing \\end_inset at this point. "
183                        "Read: `$$Token'");
184     }
185     need_update = INIT;
186 }
187
188
189 int InsetText::ascent(Painter &, LyXFont const &) const
190 {
191     return insetAscent;
192 }
193
194
195 int InsetText::descent(Painter &, LyXFont const &) const
196 {
197     return insetDescent;
198 }
199
200
201 int InsetText::width(Painter &, LyXFont const &) const
202 {
203     return insetWidth;
204 }
205
206
207 int InsetText::textWidth(Painter & pain) const
208 {
209     int w = getMaxWidth(pain, this);
210     if (w < 0) {
211 //      printf("WW1: %d\n",w);
212         return w;
213     }
214 #if 0
215     if (owner()) {
216         w = w - top_x; // + owner()->x();
217 //      printf("WW2: %d\n",w);
218         return w; // - top_x + owner()->x();
219     }
220 #endif
221     w -= (2 * TEXT_TO_INSET_OFFSET);
222 //    printf("WW2: %d\n",w);
223     return w - top_x; // - top_x - (2 * TEXT_TO_INSET_OFFSET);
224 }
225
226
227 void InsetText::draw(BufferView * bv, LyXFont const & f,
228                      int baseline, float & x, bool cleared) const
229 {
230     Painter & pain = bv->painter();
231
232     if (!cleared && ((need_update==FULL) || (top_x!=int(x)) ||
233                      (top_baseline!=baseline))) {
234         int w =  insetWidth;
235         int h = insetAscent + insetDescent;
236         int ty = baseline - insetAscent;
237         
238         if (ty < 0)
239             ty = 0;
240         if ((ty + h) > pain.paperHeight())
241             h = pain.paperHeight();
242         if ((top_x + drawTextXOffset + w) > pain.paperWidth())
243             w = pain.paperWidth();
244         pain.fillRectangle(top_x+drawTextXOffset, ty, w, h);
245         cleared = true;
246         need_update = FULL;
247     }
248
249     if (!cleared && (need_update == NONE))
250         return;
251
252     xpos = x;
253     UpdatableInset::draw(bv, f, baseline, x, cleared);
254  
255     top_baseline = baseline;
256     top_x = int(x);
257     top_y = baseline - ascent(pain, f);
258     last_width = width(pain, f);
259     last_height = ascent(pain, f) + descent(pain, f);
260
261     if (the_locking_inset && (cpar(bv) == inset_par) && (cpos(bv) == inset_pos)) {
262         inset_x = cx(bv) - top_x + drawTextXOffset;
263         inset_y = cy(bv) + drawTextYOffset;
264     }
265     if (!cleared && (need_update == CURSOR)) {
266         x += width(pain, f);
267         need_update = NONE;
268         return;
269     }
270     x += TEXT_TO_INSET_OFFSET; // place for border
271     long int y = 0;
272     Row * row = TEXT(bv)->GetRowNearY(y);
273     y += baseline - row->ascent_of_text() + 1;
274     if (cleared || !locked || (need_update == FULL)) {
275         while (row != 0) {
276             TEXT(bv)->GetVisibleRow(bv, y, x, row, y, cleared);
277             y += row->height();
278             row = row->next();
279         }
280     } else if (need_update == SELECTION) {
281         bv->screen()->ToggleToggle(getLyXText(bv), y, x);
282     } else {
283         locked = false;
284         bv->screen()->Update(TEXT(bv), y, x);
285         locked = true;
286     }
287     TEXT(bv)->refresh_y = 0;
288     TEXT(bv)->status = LyXText::UNCHANGED;
289     if ((drawFrame == ALWAYS) || ((drawFrame == LOCKED) && locked)) {
290             pain.rectangle(top_x, baseline - insetAscent, insetWidth,
291                            insetAscent + insetDescent, frame_color);
292     } else if (need_update == CLEAR_FRAME) {
293             pain.rectangle(top_x, baseline - insetAscent, insetWidth,
294                            insetAscent + insetDescent,
295                            LColor::background);
296     }
297     x += insetWidth - TEXT_TO_INSET_OFFSET;
298     need_update = NONE;
299 }
300
301
302 void InsetText::update(BufferView * bv, LyXFont const & font, bool dodraw)
303 {
304     if (the_locking_inset)
305         the_locking_inset->update(bv, font, dodraw);
306     if (need_update == INIT) {
307         deleteLyXText(bv);
308         need_update = FULL;
309     }
310     int oldw = insetWidth;
311 #if 1
312     insetWidth = TEXT(bv)->width + (2 * TEXT_TO_INSET_OFFSET);
313     // max(textWidth(bv->painter()),
314     // static_cast<int>(TEXT(bv)->width) + drawTextXOffset) +
315     // (2 * TEXT_TO_INSET_OFFSET);
316 #else
317     insetWidth = textWidth(bv->painter());
318     if (insetWidth < 0)
319             insetWidth = static_cast<int>(TEXT(bv)->width);
320 #endif
321     if (oldw != insetWidth) {
322             printf("TW(%p): %d-%d-%d-%d\n",this,insetWidth, oldw,
323                    textWidth(bv->painter()),static_cast<int>(TEXT(bv)->width));
324         deleteLyXText(bv);
325         need_update = FULL;
326 #if 0
327         if (owner()) {
328             owner()->update(bv, font, dodraw);
329             return;
330         } else {
331             update(bv, font, dodraw);
332         }
333 #else
334 #if 1
335         update(bv, font, dodraw);
336 #else
337         UpdateLocal(bv, INIT, false);
338 #endif
339 #endif
340         return;
341     }
342     if (dodraw && (need_update != CURSOR))
343             need_update = FULL;
344
345     TEXT(bv)->FullRebreak(bv);
346
347     if ((need_update==CURSOR_PAR) && (TEXT(bv)->status==LyXText::UNCHANGED) &&
348         the_locking_inset)
349     {
350         TEXT(bv)->UpdateInset(bv, the_locking_inset);
351     }
352
353     if (TEXT(bv)->status == LyXText::NEED_MORE_REFRESH)
354         need_update = FULL;
355
356     long int y_temp = 0;
357     Row * row = TEXT(bv)->GetRowNearY(y_temp);
358     insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
359     insetDescent = TEXT(bv)->height - row->ascent_of_text() +
360         TEXT_TO_INSET_OFFSET;
361 }
362
363
364 void InsetText::UpdateLocal(BufferView * bv, UpdateCodes what, bool mark_dirty)
365 {
366     TEXT(bv)->FullRebreak(bv);
367     if (TEXT(bv)->status == LyXText::NEED_MORE_REFRESH)
368         need_update = FULL;
369     else if (!the_locking_inset || (what != CURSOR))
370         need_update = what;
371     if ((need_update != CURSOR) || (TEXT(bv)->status != LyXText::UNCHANGED))
372             bv->updateInset(this, mark_dirty);
373     if (old_par != cpar(bv)) {
374             bv->owner()->getToolbar()->combox->select(cpar(bv)->GetLayout()+1);
375             old_par = cpar(bv);
376     }
377 }
378
379
380 char const * InsetText::EditMessage() const
381 {
382     return _("Opened Text Inset");
383 }
384
385
386 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
387 {
388 //    par->SetInsetOwner(this);
389     UpdatableInset::Edit(bv, x, y, button);
390
391     if (!bv->lockInset(this)) {
392         lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
393         return;
394     }
395     locked = true;
396     the_locking_inset = 0;
397     inset_pos = inset_x = inset_y = 0;
398     inset_par = 0;
399     if (!checkAndActivateInset(bv, x, y, button))
400         TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset, y);
401     TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
402     bv->text->FinishUndo();
403     UpdateLocal(bv, FULL, false);
404 }
405
406
407 void InsetText::InsetUnlock(BufferView * bv)
408 {
409     if (the_locking_inset) {
410         the_locking_inset->InsetUnlock(bv);
411         the_locking_inset = 0;
412     }
413     HideInsetCursor(bv);
414     no_selection = false;
415     locked = false;
416     TEXT(bv)->selection = 0;
417     UpdateLocal(bv, CLEAR_FRAME, false);
418     bv->owner()->getToolbar()->combox->select(bv->text->cursor.par()->GetLayout()+1);
419 }
420
421
422 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
423 {
424     lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
425     if (!inset)
426         return false;
427     if (inset == cpar(bv)->GetInset(cpos(bv))) {
428         lyxerr[Debug::INSETS] << "OK" << endl;
429         the_locking_inset = inset;
430         inset_x = cx(bv) - top_x + drawTextXOffset;
431         inset_y = cy(bv) + drawTextYOffset;
432         inset_pos = cpos(bv);
433         inset_par = cpar(bv);
434         TEXT(bv)->UpdateInset(bv, the_locking_inset);
435         return true;
436     } else if (the_locking_inset && (the_locking_inset == inset)) {
437         if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
438             lyxerr[Debug::INSETS] << "OK" << endl;
439             inset_x = cx(bv) - top_x + drawTextXOffset;
440             inset_y = cy(bv) + drawTextYOffset;
441         } else {
442             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
443         }
444     } else if (the_locking_inset) {
445         lyxerr[Debug::INSETS] << "MAYBE" << endl;
446         return the_locking_inset->LockInsetInInset(bv, inset);
447     }
448     lyxerr[Debug::INSETS] << "NOT OK" << endl;
449     return false;
450 }
451
452
453 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
454                                    bool lr)
455 {
456     if (!the_locking_inset)
457         return false;
458     if (the_locking_inset == inset) {
459         the_locking_inset->InsetUnlock(bv);
460         TEXT(bv)->UpdateInset(bv, inset);
461         the_locking_inset = 0;
462         if (lr)
463             moveRight(bv, false);
464         UpdateLocal(bv, CURSOR_PAR, false);
465         return true;
466     }
467     return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
468 }
469
470
471 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
472 {
473     if (!the_locking_inset)
474         return false;
475     if (the_locking_inset != inset) {
476         TEXT(bv)->UpdateInset(bv, the_locking_inset);
477         need_update = CURSOR_PAR;
478         return the_locking_inset->UpdateInsetInInset(bv, inset);
479     }
480 //    UpdateLocal(bv, FULL, false);
481     if (TEXT(bv)->UpdateInset(bv, inset))
482         UpdateLocal(bv, CURSOR_PAR, false);
483     if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
484         inset_x = cx(bv) - top_x + drawTextXOffset;
485         inset_y = cy(bv) + drawTextYOffset;
486     }
487     return true;
488 }
489
490
491 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
492 {
493     if (TEXT(bv)->selection) {
494         TEXT(bv)->selection = 0;
495         UpdateLocal(bv, FULL, false);
496     }
497     no_selection = false;
498
499     int tmp_x = x - drawTextXOffset;
500 //    int tmp_y = y + TEXT(bv)->first + insetAscent;
501     int tmp_y = y + insetAscent;
502     Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
503
504     if (the_locking_inset) {
505         if (the_locking_inset == inset) {
506             the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
507             return;
508         } else if (inset) {
509             // otherwise unlock the_locking_inset and lock the new inset
510             the_locking_inset->InsetUnlock(bv);
511             inset_x = cx(bv) - top_x + drawTextXOffset;
512             inset_y = cy(bv) + drawTextYOffset;
513             inset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
514             inset->Edit(bv, x - inset_x, y - inset_y, button);
515             if (the_locking_inset)
516                 UpdateLocal(bv, CURSOR_PAR, false);
517             return;
518         }
519         // otherwise only unlock the_locking_inset
520         the_locking_inset->InsetUnlock(bv);
521         the_locking_inset = 0;
522     }
523     if (bv->the_locking_inset) {
524         if (inset && inset->Editable() == Inset::HIGHLY_EDITABLE) {
525             UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
526             inset_x = cx(bv) - top_x + drawTextXOffset;
527             inset_y = cy(bv) + drawTextYOffset;
528             inset_pos = cpos(bv);
529             inset_par = cpar(bv);
530             uinset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
531             uinset->Edit(bv, x - inset_x, y - inset_y, 0);
532             if (the_locking_inset)
533                 UpdateLocal(bv, CURSOR_PAR, false);
534             return;
535         }
536     }
537     if (!inset)
538         TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
539                                            y+TEXT(bv)->first+insetAscent);
540 }
541
542
543 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
544 {
545     UpdatableInset * inset = 0;
546
547     if (the_locking_inset) {
548             the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
549     } else {
550         if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
551             inset = static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
552             if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
553                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
554             } else {
555                 inset_x = cx(bv) - top_x + drawTextXOffset;
556                 inset_y = cy(bv) + drawTextYOffset;
557                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
558                 inset->Edit(bv, x - inset_x, y - inset_y, button);
559             }
560         }
561     }
562     no_selection = false;
563 }
564
565
566 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
567 {
568     if (the_locking_inset) {
569         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
570                                              y - inset_y,state);
571         return;
572     }
573 #warning REDO this (Jug)
574     if (!no_selection) {
575 //      LyXCursor old = selection_end_cursor;
576         HideInsetCursor(bv);
577 //      setPos(bv->painter(), x, y);
578 //      selection_end_cursor = cursor;
579 //      if (old != selection_end_cursor)
580 //          UpdateLocal(bv, false, false);
581         ShowInsetCursor(bv);
582     }
583     no_selection = false;
584 }
585
586
587 void InsetText::InsetKeyPress(XKeyEvent * xke)
588 {
589     if (the_locking_inset) {
590         the_locking_inset->InsetKeyPress(xke);
591         return;
592     }
593 }
594
595
596 UpdatableInset::RESULT
597 InsetText::LocalDispatch(BufferView * bv,
598                          int action, string const & arg)
599 {
600     no_selection = false;
601     UpdatableInset::RESULT
602         result= UpdatableInset::LocalDispatch(bv, action, arg);
603     if (result != UNDISPATCHED) {
604 //      resetPos(bv->painter());
605         return DISPATCHED;
606     }
607
608     result=DISPATCHED;
609     if ((action < 0) && arg.empty())
610         return FINISHED;
611
612     if (the_locking_inset) {
613         result = the_locking_inset->LocalDispatch(bv, action, arg);
614         if (result == DISPATCHED_NOUPDATE)
615             return result;
616         else if (result == DISPATCHED) {
617             UpdateLocal(bv, CURSOR_PAR, false);
618             return result;
619         } else if (result == FINISHED) {
620             switch(action) {
621             case -1:
622             case LFUN_RIGHT:
623                 moveRight(bv, false);
624                 break;
625             case LFUN_DOWN:
626                 moveDown(bv);
627                 break;
628             }
629             the_locking_inset = 0;
630             return DISPATCHED;
631         }
632     }
633     HideInsetCursor(bv);
634     switch (action) {
635         // Normal chars
636     case -1:
637         if (bv->buffer()->isReadonly()) {
638             LyXBell();
639 //          setErrorMessage(N_("Document is read only"));
640             break;
641         }
642         if (!arg.empty()) {
643             /* Automatically delete the currently selected
644              * text and replace it with what is being
645              * typed in now. Depends on lyxrc settings
646              * "auto_region_delete", which defaults to
647              * true (on). */
648
649             bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
650                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
651                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
652             if (lyxrc.auto_region_delete) {
653                 if (TEXT(bv)->selection){
654                     TEXT(bv)->CutSelection(bv, false);
655                 }
656             }
657             TEXT(bv)->ClearSelection();
658             for (string::size_type i = 0; i < arg.length(); ++i) {
659                 bv->owner()->getIntl()->getTrans()->TranslateAndInsert(arg[i], TEXT(bv));
660             }
661         }
662         UpdateLocal(bv, CURSOR_PAR, true);
663         break;
664         // --- Cursor Movements ---------------------------------------------
665     case LFUN_RIGHTSEL:
666         bv->text->FinishUndo();
667         moveRight(bv, false);
668         TEXT(bv)->SetSelection();
669         UpdateLocal(bv, SELECTION, false);
670         break;
671     case LFUN_RIGHT:
672         bv->text->FinishUndo();
673         result = moveRight(bv);
674         TEXT(bv)->selection = 0;
675         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
676         UpdateLocal(bv, CURSOR, false);
677         break;
678     case LFUN_LEFTSEL:
679         bv->text->FinishUndo();
680         moveLeft(bv, false);
681         TEXT(bv)->SetSelection();
682         UpdateLocal(bv, SELECTION, false);
683         break;
684     case LFUN_LEFT:
685         bv->text->FinishUndo();
686         result= moveLeft(bv);
687         TEXT(bv)->selection = 0;
688         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
689         UpdateLocal(bv, CURSOR, false);
690         break;
691     case LFUN_DOWNSEL:
692         bv->text->FinishUndo();
693         moveDown(bv);
694         TEXT(bv)->SetSelection();
695         UpdateLocal(bv, SELECTION, false);
696         break;
697     case LFUN_DOWN:
698         bv->text->FinishUndo();
699         result = moveDown(bv);
700         TEXT(bv)->selection = 0;
701         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
702         UpdateLocal(bv, CURSOR, false);
703         break;
704     case LFUN_UPSEL:
705         bv->text->FinishUndo();
706         moveUp(bv);
707         TEXT(bv)->SetSelection();
708         UpdateLocal(bv, SELECTION, false);
709         break;
710     case LFUN_UP:
711         bv->text->FinishUndo();
712         result = moveUp(bv);
713         TEXT(bv)->selection = 0;
714         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
715         UpdateLocal(bv, CURSOR, false);
716         break;
717     case LFUN_HOME:
718         bv->text->FinishUndo();
719         TEXT(bv)->CursorHome(bv);
720         TEXT(bv)->selection = 0;
721         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
722         UpdateLocal(bv, CURSOR, false);
723         break;
724     case LFUN_END:
725         TEXT(bv)->CursorEnd(bv);
726         TEXT(bv)->selection = 0;
727         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
728         UpdateLocal(bv, CURSOR, false);
729         break;
730     case LFUN_BACKSPACE:
731         bv->text->SetUndo(bv->buffer(), Undo::DELETE, 
732           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
733           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
734         TEXT(bv)->Backspace(bv);
735         UpdateLocal(bv, CURSOR_PAR, true);
736         break;
737     case LFUN_DELETE:
738         bv->text->SetUndo(bv->buffer(), Undo::DELETE, 
739           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
740           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
741         TEXT(bv)->Delete(bv);
742         UpdateLocal(bv, CURSOR_PAR, true);
743         break;
744     case LFUN_CUT:
745         bv->text->SetUndo(bv->buffer(), Undo::DELETE, 
746           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
747           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
748         TEXT(bv)->CutSelection(bv);
749         UpdateLocal(bv, CURSOR_PAR, true);
750         break;
751     case LFUN_COPY:
752         bv->text->FinishUndo();
753         TEXT(bv)->CopySelection(bv);
754         UpdateLocal(bv, CURSOR_PAR, false);
755         break;
756     case LFUN_PASTE:
757         bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
758           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
759           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
760         TEXT(bv)->PasteSelection(bv);
761         UpdateLocal(bv, CURSOR_PAR, true);
762         break;
763     case LFUN_BREAKPARAGRAPH:
764         if (!autoBreakRows)
765             return DISPATCHED;
766         TEXT(bv)->BreakParagraph(bv, 0);
767         UpdateLocal(bv, FULL, true);
768         break;
769     case LFUN_BREAKLINE:
770         if (!autoBreakRows)
771             return DISPATCHED;
772         bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
773             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
774             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
775         TEXT(bv)->InsertChar(bv, LyXParagraph::META_NEWLINE);
776         UpdateLocal(bv, CURSOR_PAR, true);
777         break;
778     case LFUN_LAYOUT:
779     {
780       static LyXTextClass::size_type cur_layout = cpar(bv)->layout;
781       
782         // Derive layout number from given argument (string)
783         // and current buffer's textclass (number). */    
784         LyXTextClassList::ClassList::size_type tclass =
785             bv->buffer()->params.textclass;
786         std::pair <bool, LyXTextClass::size_type> layout = 
787             textclasslist.NumberOfLayout(tclass, arg);
788
789         // If the entry is obsolete, use the new one instead.
790         if (layout.first) {
791             string obs = textclasslist.Style(tclass,layout.second).
792                 obsoleted_by();
793             if (!obs.empty()) 
794                 layout = textclasslist.NumberOfLayout(tclass, obs);
795         }
796
797         // see if we found the layout number:
798         if (!layout.first) {
799             string msg = string(N_("Layout ")) + arg + N_(" not known");
800
801             bv->owner()->getMiniBuffer()->Set(msg);
802             break;
803         }
804
805         if (cur_layout != layout.second) {
806             cur_layout = layout.second;
807             TEXT(bv)->SetLayout(bv, layout.second);
808             bv->owner()->getToolbar()->combox->select(cpar(bv)->GetLayout()+1);
809             UpdateLocal(bv, CURSOR_PAR, true);
810         }
811     }
812     break;
813     case LFUN_PARAGRAPH_SPACING:
814             // This one is absolutely not working. When fiddling with this
815             // it also seems to me that the paragraphs inside the insettext
816             // inherit bufferparams/paragraphparams in a strange way. (Lgb)
817     {
818             LyXParagraph * par = TEXT(bv)->cursor.par();
819             Spacing::Space cur_spacing = par->spacing.getSpace();
820             float cur_value = 1.0;
821             if (cur_spacing == Spacing::Other) {
822                     cur_value = par->spacing.getValue();
823             }
824                         
825 #ifdef HAVE_SSTREAM
826             std::istringstream istr(arg);
827 #else
828             istrstream istr(arg.c_str());
829 #endif
830             string tmp;
831             istr >> tmp;
832             Spacing::Space new_spacing = cur_spacing;
833             float new_value = cur_value;
834             if (tmp.empty()) {
835                     lyxerr << "Missing argument to `paragraph-spacing'"
836                            << endl;
837             } else if (tmp == "single") {
838                     new_spacing = Spacing::Single;
839             } else if (tmp == "onehalf") {
840                     new_spacing = Spacing::Onehalf;
841             } else if (tmp == "double") {
842                     new_spacing = Spacing::Double;
843             } else if (tmp == "other") {
844                     new_spacing = Spacing::Other;
845                     float tmpval = 0.0;
846                     istr >> tmpval;
847                     lyxerr << "new_value = " << tmpval << endl;
848                     if (tmpval != 0.0)
849                             new_value = tmpval;
850             } else if (tmp == "default") {
851                     new_spacing = Spacing::Default;
852             } else {
853                     lyxerr << _("Unknown spacing argument: ")
854                            << arg << endl;
855             }
856             if (cur_spacing != new_spacing || cur_value != new_value) {
857                     par->spacing.set(new_spacing, new_value);
858                     //TEXT(bv)->RedoParagraph(owner->view());
859                     UpdateLocal(bv, CURSOR_PAR, true);
860                     //bv->update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
861             }
862     }
863     break;
864         
865     default:
866         result = UNDISPATCHED;
867         break;
868     }
869     if (result != FINISHED) {
870         ShowInsetCursor(bv);
871     } else
872         bv->unlockInset(this);
873     return result;
874 }
875
876
877 int InsetText::Latex(Buffer const * buf, ostream & os, bool, bool) const
878 {
879     TexRow texrow;
880     buf->latexParagraphs(os, par, 0, texrow);
881     return texrow.rows();
882 }
883
884
885 void InsetText::Validate(LaTeXFeatures & features) const
886 {
887     LyXParagraph * p = par;
888     while(p) {
889         p->validate(features);
890         p = p->next;
891     }
892 }
893
894
895 int InsetText::BeginningOfMainBody(Buffer const * buf, LyXParagraph * p) const
896 {
897     if (textclasslist.Style(buf->params.textclass,
898                             p->GetLayout()).labeltype != LABEL_MANUAL)
899         return 0;
900     else
901         return p->BeginningOfMainBody();
902 }
903
904
905 void InsetText::GetCursorPos(BufferView * bv, int & x, int & y) const
906 {
907     x = cx(bv);
908     y = cy(bv);
909 }
910
911
912 int InsetText::InsetInInsetY()
913 {
914     if (!the_locking_inset)
915         return 0;
916
917     return (inset_y + the_locking_inset->InsetInInsetY());
918 }
919
920
921 void InsetText::ToggleInsetCursor(BufferView * bv)
922 {
923     if (the_locking_inset) {
924         the_locking_inset->ToggleInsetCursor(bv);
925         return;
926     }
927
928     LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
929
930     int asc = lyxfont::maxAscent(font);
931     int desc = lyxfont::maxDescent(font);
932   
933     if (cursor_visible)
934         bv->hideLockedInsetCursor();
935     else
936         bv->showLockedInsetCursor(cx(bv), cy(bv),
937                                   asc, desc);
938     cursor_visible = !cursor_visible;
939 }
940
941
942 void InsetText::ShowInsetCursor(BufferView * bv)
943 {
944     if (the_locking_inset) {
945         the_locking_inset->ShowInsetCursor(bv);
946         return;
947     }
948     if (!cursor_visible) {
949         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
950         
951         int asc = lyxfont::maxAscent(font);
952         int desc = lyxfont::maxDescent(font);
953
954         bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
955         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
956         cursor_visible = true;
957     }
958 }
959
960
961 void InsetText::HideInsetCursor(BufferView * bv)
962 {
963     if (cursor_visible) {
964         bv->hideLockedInsetCursor();
965         cursor_visible = false;
966     }
967     if (the_locking_inset)
968         the_locking_inset->HideInsetCursor(bv);
969 }
970
971
972 UpdatableInset::RESULT
973 InsetText::moveRight(BufferView * bv, bool activate_inset)
974 {
975     if (!cpar(bv)->next && (cpos(bv) >= cpar(bv)->Last()))
976         return FINISHED;
977     if (activate_inset && checkAndActivateInset(bv, false))
978         return DISPATCHED;
979     TEXT(bv)->CursorRight(bv);
980     return DISPATCHED_NOUPDATE;
981 }
982
983
984 UpdatableInset::RESULT
985 InsetText::moveLeft(BufferView * bv, bool activate_inset)
986 {
987     if (!cpar(bv)->previous && (cpos(bv) <= 0))
988         return FINISHED;
989     TEXT(bv)->CursorLeft(bv);
990     if (activate_inset && checkAndActivateInset(bv, true))
991         return DISPATCHED;
992     return DISPATCHED_NOUPDATE;
993 }
994
995
996 UpdatableInset::RESULT
997 InsetText::moveUp(BufferView * bv)
998 {
999     if (!crow(bv)->previous())
1000         return FINISHED;
1001     TEXT(bv)->CursorUp(bv);
1002     return DISPATCHED_NOUPDATE;
1003 }
1004
1005
1006 UpdatableInset::RESULT
1007 InsetText::moveDown(BufferView * bv)
1008 {
1009     if (!crow(bv)->next())
1010         return FINISHED;
1011     TEXT(bv)->CursorDown(bv);
1012     return DISPATCHED_NOUPDATE;
1013 }
1014
1015
1016 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1017 {
1018     if (the_locking_inset) {
1019         if (the_locking_inset->InsertInsetAllowed(inset))
1020             return the_locking_inset->InsertInset(bv, inset);
1021         return false;
1022     }
1023     bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
1024               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
1025               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
1026     if (inset->Editable() == Inset::IS_EDITABLE) {
1027         UpdatableInset * i = static_cast<UpdatableInset *>(inset);
1028         i->setOwner(static_cast<UpdatableInset *>(this));
1029     }
1030     cpar(bv)->InsertInset(cpos(bv), inset);
1031     TEXT(bv)->selection = 0;
1032     UpdateLocal(bv, CURSOR_PAR, true);
1033     static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
1034     return true;
1035 }
1036
1037
1038 UpdatableInset * InsetText::GetLockingInset()
1039 {
1040     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1041 }
1042
1043
1044 UpdatableInset * InsetText::GetFirstLockingInsetOfType(Inset::Code c)
1045 {
1046     if (c == LyxCode())
1047         return this;
1048     if (the_locking_inset)
1049         return the_locking_inset->GetFirstLockingInsetOfType(c);
1050     return 0;
1051 }
1052
1053
1054 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1055 {
1056     TEXT(bv)->SetFont(bv, font, toggleall);
1057 }
1058
1059
1060 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1061 {
1062     if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
1063         int x, y;
1064         Inset * inset =
1065             static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
1066         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1067         if (behind) {
1068             x = inset->width(bv->painter(), font);
1069             y = inset->descent(bv->painter(), font);
1070         } else {
1071             x = y = 0;
1072         }
1073         inset_x = cx(bv) - top_x + drawTextXOffset;
1074         inset_y = cy(bv) + drawTextYOffset;
1075         inset->Edit(bv, x-inset_x, y-inset_y, 0);
1076         if (!the_locking_inset)
1077             return false;
1078         UpdateLocal(bv, CURSOR_PAR, false);
1079         return true;
1080     }
1081     return false;
1082 }
1083
1084
1085 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1086                                       int button)
1087 {
1088     int tmp_x = x - drawTextXOffset;
1089     int tmp_y = y + insetAscent;
1090     Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
1091
1092     if (inset) {
1093         if (x < 0)
1094             x = insetWidth;
1095         if (y < 0)
1096             y = insetDescent;
1097         inset_x = cx(bv) - top_x + drawTextXOffset;
1098         inset_y = cy(bv) + drawTextYOffset;
1099         inset->Edit(bv, x - inset_x, y - inset_y, button);
1100         if (!the_locking_inset)
1101             return false;
1102         UpdateLocal(bv, CURSOR_PAR, false);
1103         return true;
1104     }
1105     return false;
1106 }
1107
1108
1109 int InsetText::getMaxWidth(Painter & pain, UpdatableInset const * inset) const
1110 {
1111     return UpdatableInset::getMaxWidth(pain, inset) - (2*TEXT_TO_INSET_OFFSET);
1112 }
1113
1114
1115 void InsetText::SetParagraphData(LyXParagraph *p)
1116 {
1117     LyXParagraph * np;
1118
1119     if (par) {
1120         np = par->next;
1121         delete par;
1122         while(np) {
1123             par = np;
1124             np = np->next;
1125             delete par;
1126         }
1127     }
1128     par = p->Clone();
1129     par->SetInsetOwner(this);
1130     np = par;
1131     while(p->next) {
1132         p = p->next;
1133         np->next = p->Clone();
1134         np->next->previous = np;
1135         np = np->next;
1136         np->SetInsetOwner(this);
1137     }
1138     need_update = INIT;
1139 }
1140
1141
1142 void InsetText::SetAutoBreakRows(bool flag)
1143 {
1144     if (flag != autoBreakRows) {
1145         autoBreakRows = flag;
1146         need_update = FULL;
1147     }
1148 }
1149
1150
1151 void InsetText::SetDrawFrame(BufferView * bv, DrawFrame how)
1152 {
1153     if (how != drawFrame) {
1154         drawFrame = how;
1155         if (bv)
1156             UpdateLocal(bv, DRAW_FRAME, false);
1157     }
1158 }
1159
1160
1161 void InsetText::SetFrameColor(BufferView * bv, LColor::color col)
1162 {
1163     if (frame_color != col) {
1164         frame_color = col;
1165         if (bv)
1166             UpdateLocal(bv, DRAW_FRAME, false);
1167     }
1168 }
1169
1170 #if 0
1171 LyXFont InsetText::GetDrawFont(BufferView * bv, LyXParagraph * p, int pos) const
1172 {
1173     return TEXT(bv)->GetFont(bv->buffer(), p, pos);
1174 }
1175 #endif
1176
1177 int InsetText::cx(BufferView * bv) const
1178 {
1179     return TEXT(bv)->cursor.x() + top_x + 1;
1180 }
1181
1182
1183 int InsetText::cy(BufferView * bv) const
1184 {
1185     long int y_dummy = 0;
1186     Row * tmprow = TEXT(bv)->GetRowNearY(y_dummy);
1187     return TEXT(bv)->cursor.y() - tmprow->baseline();
1188 }
1189
1190
1191 int InsetText::cpos(BufferView * bv) const
1192 {
1193     return TEXT(bv)->cursor.pos();
1194 }
1195
1196
1197 LyXParagraph * InsetText::cpar(BufferView * bv) const
1198 {
1199     return TEXT(bv)->cursor.par();
1200 }
1201
1202
1203 Row * InsetText::crow(BufferView * bv) const
1204 {
1205     return TEXT(bv)->cursor.row();
1206 }
1207
1208
1209 LyXText * InsetText::getLyXText(BufferView * bv) const
1210 {
1211     if (cache.find(bv) != cache.end())
1212         return cache[bv];
1213     LyXText * lt = new LyXText(const_cast<InsetText *>(this));
1214     lt->init(bv);
1215     cache[bv] = lt;
1216     if (the_locking_inset) {
1217         lt->SetCursor(bv, inset_par, inset_pos);
1218     }
1219     return lt;
1220 }
1221
1222
1223 void InsetText::deleteLyXText(BufferView * bv)
1224 {
1225     cache.erase(bv);
1226     /// then remove all LyXText in text-insets
1227     LyXParagraph * p = par;
1228     for(;p;p = p->next) {
1229             p->deleteInsetsLyXText(bv);
1230     }
1231 }