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