]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
Toolbar icons and banner are now read when needed from disk. Read ChangeLog.
[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,
603                                                   x - inset_x, y - inset_y,
604                                                   button);
605     } else {
606         if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
607             inset = static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
608             if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
609                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
610             } else {
611                 inset_x = cx(bv) - top_x + drawTextXOffset;
612                 inset_y = cy(bv) + drawTextYOffset;
613                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
614                 inset->Edit(bv, x - inset_x, y - inset_y, button);
615             }
616             UpdateLocal(bv, CURSOR_PAR, false);
617         }
618     }
619     no_selection = false;
620 }
621
622
623 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
624 {
625     if (the_locking_inset) {
626         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
627                                              y - inset_y,state);
628         return;
629     }
630     if (!no_selection) {
631         HideInsetCursor(bv);
632         TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
633                                            y+TEXT(bv)->first+insetAscent);
634         TEXT(bv)->SetSelection();
635         if (TEXT(bv)->toggle_cursor.par()!=TEXT(bv)->toggle_end_cursor.par() ||
636             TEXT(bv)->toggle_cursor.pos()!=TEXT(bv)->toggle_end_cursor.pos())
637             UpdateLocal(bv, SELECTION, false);
638         ShowInsetCursor(bv);
639     }
640     no_selection = false;
641 }
642
643
644 void InsetText::InsetKeyPress(XKeyEvent * xke)
645 {
646     if (the_locking_inset) {
647         the_locking_inset->InsetKeyPress(xke);
648         return;
649     }
650 }
651
652
653 UpdatableInset::RESULT
654 InsetText::LocalDispatch(BufferView * bv,
655                          int action, string const & arg)
656 {
657     no_selection = false;
658     UpdatableInset::RESULT
659         result= UpdatableInset::LocalDispatch(bv, action, arg);
660     if (result != UNDISPATCHED) {
661 //      resetPos(bv->painter());
662         return DISPATCHED;
663     }
664
665     result=DISPATCHED;
666     if ((action < 0) && arg.empty())
667         return FINISHED;
668
669     if (the_locking_inset) {
670         result = the_locking_inset->LocalDispatch(bv, action, arg);
671         if (result == DISPATCHED_NOUPDATE)
672             return result;
673         else if (result == DISPATCHED) {
674             UpdateLocal(bv, CURSOR_PAR, false);
675             return result;
676         } else if (result == FINISHED) {
677             switch(action) {
678             case -1:
679             case LFUN_RIGHT:
680                 moveRight(bv, false);
681                 break;
682             case LFUN_DOWN:
683                 moveDown(bv);
684                 break;
685             }
686             the_locking_inset = 0;
687             return DISPATCHED;
688         }
689     }
690     HideInsetCursor(bv);
691     switch (action) {
692         // Normal chars
693     case -1:
694         if (bv->buffer()->isReadonly()) {
695             LyXBell();
696 //          setErrorMessage(N_("Document is read only"));
697             break;
698         }
699         if (!arg.empty()) {
700             /* Automatically delete the currently selected
701              * text and replace it with what is being
702              * typed in now. Depends on lyxrc settings
703              * "auto_region_delete", which defaults to
704              * true (on). */
705
706             bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
707                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
708                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
709             if (lyxrc.auto_region_delete) {
710                 if (TEXT(bv)->selection){
711                     TEXT(bv)->CutSelection(bv, false);
712                 }
713             }
714             TEXT(bv)->ClearSelection();
715             for (string::size_type i = 0; i < arg.length(); ++i) {
716                 bv->owner()->getIntl()->getTrans()->TranslateAndInsert(arg[i], TEXT(bv));
717             }
718         }
719         UpdateLocal(bv, CURSOR_PAR, true);
720         break;
721         // --- Cursor Movements ---------------------------------------------
722     case LFUN_RIGHTSEL:
723         bv->text->FinishUndo();
724         moveRight(bv, false);
725         TEXT(bv)->SetSelection();
726         UpdateLocal(bv, SELECTION, false);
727         break;
728     case LFUN_RIGHT:
729         result = moveRight(bv);
730         bv->text->FinishUndo();
731         UpdateLocal(bv, CURSOR, false);
732         break;
733     case LFUN_LEFTSEL:
734         bv->text->FinishUndo();
735         moveLeft(bv, false);
736         TEXT(bv)->SetSelection();
737         UpdateLocal(bv, SELECTION, false);
738         break;
739     case LFUN_LEFT:
740         bv->text->FinishUndo();
741         result= moveLeft(bv);
742         UpdateLocal(bv, CURSOR, false);
743         break;
744     case LFUN_DOWNSEL:
745         bv->text->FinishUndo();
746         moveDown(bv);
747         TEXT(bv)->SetSelection();
748         UpdateLocal(bv, SELECTION, false);
749         break;
750     case LFUN_DOWN:
751         bv->text->FinishUndo();
752         result = moveDown(bv);
753         UpdateLocal(bv, CURSOR, false);
754         break;
755     case LFUN_UPSEL:
756         bv->text->FinishUndo();
757         moveUp(bv);
758         TEXT(bv)->SetSelection();
759         UpdateLocal(bv, SELECTION, false);
760         break;
761     case LFUN_UP:
762         bv->text->FinishUndo();
763         result = moveUp(bv);
764         UpdateLocal(bv, CURSOR, false);
765         break;
766     case LFUN_HOME:
767         bv->text->FinishUndo();
768         TEXT(bv)->CursorHome(bv);
769         UpdateLocal(bv, CURSOR, false);
770         break;
771     case LFUN_END:
772         TEXT(bv)->CursorEnd(bv);
773         UpdateLocal(bv, CURSOR, false);
774         break;
775     case LFUN_BACKSPACE:
776         bv->text->SetUndo(bv->buffer(), Undo::DELETE, 
777           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
778           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
779         TEXT(bv)->Backspace(bv);
780         UpdateLocal(bv, CURSOR_PAR, true);
781         break;
782     case LFUN_DELETE:
783         bv->text->SetUndo(bv->buffer(), Undo::DELETE, 
784           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
785           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
786         TEXT(bv)->Delete(bv);
787         UpdateLocal(bv, CURSOR_PAR, true);
788         break;
789     case LFUN_CUT:
790         bv->text->SetUndo(bv->buffer(), Undo::DELETE, 
791           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
792           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
793         TEXT(bv)->CutSelection(bv);
794         UpdateLocal(bv, CURSOR_PAR, true);
795         break;
796     case LFUN_COPY:
797         bv->text->FinishUndo();
798         TEXT(bv)->CopySelection(bv);
799         UpdateLocal(bv, CURSOR_PAR, false);
800         break;
801     case LFUN_PASTE:
802         if (!autoBreakRows) {
803             CutAndPaste cap;
804
805             if (cap.nrOfParagraphs() > 1) {
806                 WriteAlert(_("Impossible operation"),
807                            _("Cannot include more than one paragraph!"),
808                            _("Sorry."));
809                 break;
810             }
811         }
812         bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
813           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
814           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
815         TEXT(bv)->PasteSelection(bv);
816         UpdateLocal(bv, CURSOR_PAR, true);
817         break;
818     case LFUN_BREAKPARAGRAPH:
819         if (!autoBreakRows)
820             return DISPATCHED;
821         TEXT(bv)->BreakParagraph(bv, 0);
822         UpdateLocal(bv, FULL, true);
823         break;
824     case LFUN_BREAKLINE:
825         if (!autoBreakRows)
826             return DISPATCHED;
827         bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
828             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
829             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
830         TEXT(bv)->InsertChar(bv, LyXParagraph::META_NEWLINE);
831         UpdateLocal(bv, CURSOR_PAR, true);
832         break;
833     case LFUN_LAYOUT:
834     {
835       static LyXTextClass::size_type cur_layout = cpar(bv)->layout;
836       
837         // Derive layout number from given argument (string)
838         // and current buffer's textclass (number). */    
839         LyXTextClassList::ClassList::size_type tclass =
840             bv->buffer()->params.textclass;
841         std::pair <bool, LyXTextClass::size_type> layout = 
842             textclasslist.NumberOfLayout(tclass, arg);
843
844         // If the entry is obsolete, use the new one instead.
845         if (layout.first) {
846             string obs = textclasslist.Style(tclass,layout.second).
847                 obsoleted_by();
848             if (!obs.empty()) 
849                 layout = textclasslist.NumberOfLayout(tclass, obs);
850         }
851
852         // see if we found the layout number:
853         if (!layout.first) {
854             string msg = string(N_("Layout ")) + arg + N_(" not known");
855
856             bv->owner()->getMiniBuffer()->Set(msg);
857             break;
858         }
859
860         if (cur_layout != layout.second) {
861             cur_layout = layout.second;
862             TEXT(bv)->SetLayout(bv, layout.second);
863             bv->owner()->getToolbar()->combox->select(cpar(bv)->GetLayout()+1);
864             UpdateLocal(bv, CURSOR_PAR, true);
865         }
866     }
867     break;
868     case LFUN_PARAGRAPH_SPACING:
869             // This one is absolutely not working. When fiddling with this
870             // it also seems to me that the paragraphs inside the insettext
871             // inherit bufferparams/paragraphparams in a strange way. (Lgb)
872     {
873             LyXParagraph * par = TEXT(bv)->cursor.par();
874             Spacing::Space cur_spacing = par->spacing.getSpace();
875             float cur_value = 1.0;
876             if (cur_spacing == Spacing::Other) {
877                     cur_value = par->spacing.getValue();
878             }
879                         
880 #ifdef HAVE_SSTREAM
881             std::istringstream istr(arg);
882 #else
883             istrstream istr(arg.c_str());
884 #endif
885             string tmp;
886             istr >> tmp;
887             Spacing::Space new_spacing = cur_spacing;
888             float new_value = cur_value;
889             if (tmp.empty()) {
890                     lyxerr << "Missing argument to `paragraph-spacing'"
891                            << endl;
892             } else if (tmp == "single") {
893                     new_spacing = Spacing::Single;
894             } else if (tmp == "onehalf") {
895                     new_spacing = Spacing::Onehalf;
896             } else if (tmp == "double") {
897                     new_spacing = Spacing::Double;
898             } else if (tmp == "other") {
899                     new_spacing = Spacing::Other;
900                     float tmpval = 0.0;
901                     istr >> tmpval;
902                     lyxerr << "new_value = " << tmpval << endl;
903                     if (tmpval != 0.0)
904                             new_value = tmpval;
905             } else if (tmp == "default") {
906                     new_spacing = Spacing::Default;
907             } else {
908                     lyxerr << _("Unknown spacing argument: ")
909                            << arg << endl;
910             }
911             if (cur_spacing != new_spacing || cur_value != new_value) {
912                     par->spacing.set(new_spacing, new_value);
913                     //TEXT(bv)->RedoParagraph(owner->view());
914                     UpdateLocal(bv, CURSOR_PAR, true);
915                     //bv->update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
916             }
917     }
918     break;
919         
920     default:
921         result = UNDISPATCHED;
922         break;
923     }
924     if (result != FINISHED) {
925         ShowInsetCursor(bv);
926     } else
927         bv->unlockInset(this);
928     return result;
929 }
930
931
932 int InsetText::Latex(Buffer const * buf, ostream & os, bool, bool) const
933 {
934     TexRow texrow;
935     buf->latexParagraphs(os, par, 0, texrow);
936     return texrow.rows();
937 }
938
939
940 void InsetText::Validate(LaTeXFeatures & features) const
941 {
942     LyXParagraph * p = par;
943     while(p) {
944         p->validate(features);
945         p = p->next;
946     }
947 }
948
949
950 int InsetText::BeginningOfMainBody(Buffer const * buf, LyXParagraph * p) const
951 {
952     if (textclasslist.Style(buf->params.textclass,
953                             p->GetLayout()).labeltype != LABEL_MANUAL)
954         return 0;
955     else
956         return p->BeginningOfMainBody();
957 }
958
959
960 void InsetText::GetCursorPos(BufferView * bv, int & x, int & y) const
961 {
962     x = cx(bv);
963     y = cy(bv);
964 }
965
966
967 int InsetText::InsetInInsetY()
968 {
969     if (!the_locking_inset)
970         return 0;
971
972     return (inset_y + the_locking_inset->InsetInInsetY());
973 }
974
975
976 void InsetText::ToggleInsetCursor(BufferView * bv)
977 {
978     if (the_locking_inset) {
979         the_locking_inset->ToggleInsetCursor(bv);
980         return;
981     }
982
983     LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
984
985     int asc = lyxfont::maxAscent(font);
986     int desc = lyxfont::maxDescent(font);
987   
988     if (cursor_visible)
989         bv->hideLockedInsetCursor();
990     else
991         bv->showLockedInsetCursor(cx(bv)-1, cy(bv),
992                                   asc, desc);
993     cursor_visible = !cursor_visible;
994 }
995
996
997 void InsetText::ShowInsetCursor(BufferView * bv)
998 {
999     if (the_locking_inset) {
1000         the_locking_inset->ShowInsetCursor(bv);
1001         return;
1002     }
1003     if (!cursor_visible) {
1004         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1005         
1006         int asc = lyxfont::maxAscent(font);
1007         int desc = lyxfont::maxDescent(font);
1008
1009         bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1010         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1011         cursor_visible = true;
1012     }
1013 }
1014
1015
1016 void InsetText::HideInsetCursor(BufferView * bv)
1017 {
1018     if (cursor_visible) {
1019         bv->hideLockedInsetCursor();
1020         cursor_visible = false;
1021     }
1022     if (the_locking_inset)
1023         the_locking_inset->HideInsetCursor(bv);
1024 }
1025
1026
1027 UpdatableInset::RESULT
1028 InsetText::moveRight(BufferView * bv, bool activate_inset)
1029 {
1030     if (!cpar(bv)->next && (cpos(bv) >= cpar(bv)->Last()))
1031         return FINISHED;
1032     if (activate_inset && checkAndActivateInset(bv, false))
1033         return DISPATCHED;
1034     TEXT(bv)->CursorRight(bv);
1035     return DISPATCHED_NOUPDATE;
1036 }
1037
1038
1039 UpdatableInset::RESULT
1040 InsetText::moveLeft(BufferView * bv, bool activate_inset)
1041 {
1042     if (!cpar(bv)->previous && (cpos(bv) <= 0))
1043         return FINISHED;
1044     TEXT(bv)->CursorLeft(bv);
1045     if (activate_inset && checkAndActivateInset(bv, true))
1046         return DISPATCHED;
1047     return DISPATCHED_NOUPDATE;
1048 }
1049
1050
1051 UpdatableInset::RESULT
1052 InsetText::moveUp(BufferView * bv)
1053 {
1054     if (!crow(bv)->previous())
1055         return FINISHED;
1056     TEXT(bv)->CursorUp(bv);
1057     return DISPATCHED_NOUPDATE;
1058 }
1059
1060
1061 UpdatableInset::RESULT
1062 InsetText::moveDown(BufferView * bv)
1063 {
1064     if (!crow(bv)->next())
1065         return FINISHED;
1066     TEXT(bv)->CursorDown(bv);
1067     return DISPATCHED_NOUPDATE;
1068 }
1069
1070
1071 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1072 {
1073     if (the_locking_inset) {
1074         if (the_locking_inset->InsertInsetAllowed(inset))
1075             return the_locking_inset->InsertInset(bv, inset);
1076         return false;
1077     }
1078     bv->text->SetUndo(bv->buffer(), Undo::INSERT, 
1079               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
1080               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
1081     if (inset->Editable() == Inset::IS_EDITABLE) {
1082         UpdatableInset * i = static_cast<UpdatableInset *>(inset);
1083         i->setOwner(static_cast<UpdatableInset *>(this));
1084     }
1085     TEXT(bv)->InsertInset(bv, inset);
1086     TEXT(bv)->selection = 0;
1087     UpdateLocal(bv, CURSOR_PAR, true);
1088     static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
1089     return true;
1090 }
1091
1092
1093 UpdatableInset * InsetText::GetLockingInset()
1094 {
1095     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1096 }
1097
1098
1099 UpdatableInset * InsetText::GetFirstLockingInsetOfType(Inset::Code c)
1100 {
1101     if (c == LyxCode())
1102         return this;
1103     if (the_locking_inset)
1104         return the_locking_inset->GetFirstLockingInsetOfType(c);
1105     return 0;
1106 }
1107
1108
1109 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1110 {
1111     TEXT(bv)->SetFont(bv, font, toggleall);
1112 }
1113
1114
1115 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1116 {
1117     if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
1118         int x, y;
1119         Inset * inset =
1120             static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
1121         if (!inset || inset->Editable() != Inset::HIGHLY_EDITABLE)
1122             return false;
1123         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1124         if (behind) {
1125             x = inset->width(bv, font);
1126             y = inset->descent(bv, font);
1127         } else {
1128             x = y = 0;
1129         }
1130         inset_x = cx(bv) - top_x + drawTextXOffset;
1131         inset_y = cy(bv) + drawTextYOffset;
1132         inset->Edit(bv, x-inset_x, y-inset_y, 0);
1133         if (!the_locking_inset)
1134             return false;
1135         UpdateLocal(bv, CURSOR_PAR, false);
1136         return true;
1137     }
1138     return false;
1139 }
1140
1141
1142 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1143                                       int button)
1144 {
1145     int tmp_x = x - drawTextXOffset;
1146     int tmp_y = y + insetAscent;
1147     Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
1148
1149     if (inset) {
1150         if (x < 0)
1151             x = insetWidth;
1152         if (y < 0)
1153             y = insetDescent;
1154         inset_x = cx(bv) - top_x + drawTextXOffset;
1155         inset_y = cy(bv) + drawTextYOffset;
1156         inset->Edit(bv, x - inset_x, y - inset_y, button);
1157         if (!the_locking_inset)
1158             return false;
1159         UpdateLocal(bv, CURSOR_PAR, false);
1160         return true;
1161     }
1162     return false;
1163 }
1164
1165
1166 int InsetText::getMaxWidth(Painter & pain, UpdatableInset const * inset) const
1167 {
1168     int w = UpdatableInset::getMaxWidth(pain, inset);
1169     if (w < 0)
1170         return w;
1171     return  w - (2*TEXT_TO_INSET_OFFSET);
1172 }
1173
1174
1175 void InsetText::SetParagraphData(LyXParagraph *p)
1176 {
1177     LyXParagraph * np;
1178
1179     if (par) {
1180         np = par->next;
1181         delete par;
1182         while(np) {
1183             par = np;
1184             np = np->next;
1185             delete par;
1186         }
1187     }
1188     par = p->Clone();
1189     par->SetInsetOwner(this);
1190     np = par;
1191     while(p->next) {
1192         p = p->next;
1193         np->next = p->Clone();
1194         np->next->previous = np;
1195         np = np->next;
1196         np->SetInsetOwner(this);
1197     }
1198     need_update = INIT;
1199 }
1200
1201
1202 void InsetText::SetAutoBreakRows(bool flag)
1203 {
1204     if (flag != autoBreakRows) {
1205         autoBreakRows = flag;
1206         need_update = FULL;
1207     }
1208 }
1209
1210
1211 void InsetText::SetDrawFrame(BufferView * bv, DrawFrame how)
1212 {
1213     if (how != drawFrame) {
1214         drawFrame = how;
1215         if (bv)
1216             UpdateLocal(bv, DRAW_FRAME, false);
1217     }
1218 }
1219
1220
1221 void InsetText::SetFrameColor(BufferView * bv, LColor::color col)
1222 {
1223     if (frame_color != col) {
1224         frame_color = col;
1225         if (bv)
1226             UpdateLocal(bv, DRAW_FRAME, false);
1227     }
1228 }
1229
1230 #if 0
1231 LyXFont InsetText::GetDrawFont(BufferView * bv, LyXParagraph * p, int pos) const
1232 {
1233     return TEXT(bv)->GetFont(bv->buffer(), p, pos);
1234 }
1235 #endif
1236
1237 int InsetText::cx(BufferView * bv) const
1238 {
1239     return TEXT(bv)->cursor.x() + top_x + 1;
1240 }
1241
1242
1243 int InsetText::cy(BufferView * bv) const
1244 {
1245     long int y_dummy = 0;
1246     Row * tmprow = TEXT(bv)->GetRowNearY(y_dummy);
1247     return TEXT(bv)->cursor.y() - tmprow->baseline();
1248 }
1249
1250
1251 int InsetText::cpos(BufferView * bv) const
1252 {
1253     return TEXT(bv)->cursor.pos();
1254 }
1255
1256
1257 LyXParagraph * InsetText::cpar(BufferView * bv) const
1258 {
1259     return TEXT(bv)->cursor.par();
1260 }
1261
1262
1263 Row * InsetText::crow(BufferView * bv) const
1264 {
1265     return TEXT(bv)->cursor.row();
1266 }
1267
1268
1269 LyXText * InsetText::getLyXText(BufferView * bv) const
1270 {
1271     if (cache.find(bv) != cache.end())
1272         return cache[bv];
1273     LyXText * lt = new LyXText(const_cast<InsetText *>(this));
1274     lt->init(bv);
1275     cache[bv] = lt;
1276     if (the_locking_inset) {
1277         lt->SetCursor(bv, inset_par, inset_pos);
1278     }
1279     return lt;
1280 }
1281
1282
1283 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1284 {
1285     cache.erase(bv);
1286     if (recursive) {
1287         /// then remove all LyXText in text-insets
1288         LyXParagraph * p = par;
1289         for(;p;p = p->next) {
1290             p->deleteInsetsLyXText(bv);
1291         }
1292     }
1293 }
1294
1295 void InsetText::resizeLyXText(BufferView * bv) const
1296 {
1297     if (!par->next && !par->size()) // not neccessary!
1298         return;
1299
1300     LyXParagraph * lpar = 0;
1301     LyXParagraph * selstartpar = 0;
1302     LyXParagraph * selendpar = 0;
1303     int pos = 0;
1304     int selstartpos = 0;
1305     int selendpos = 0;
1306     int selection = 0;
1307     int mark_set = 0;
1308
1309 //    ProhibitInput(bv);
1310
1311     lpar = TEXT(bv)->cursor.par();
1312     pos = TEXT(bv)->cursor.pos();
1313     selstartpar = TEXT(bv)->sel_start_cursor.par();
1314     selstartpos = TEXT(bv)->sel_start_cursor.pos();
1315     selendpar = TEXT(bv)->sel_end_cursor.par();
1316     selendpos = TEXT(bv)->sel_end_cursor.pos();
1317     selection = TEXT(bv)->selection;
1318     mark_set = TEXT(bv)->mark_set;
1319     deleteLyXText(bv, (the_locking_inset == 0));
1320
1321     if (lpar) {
1322         TEXT(bv)->selection = true;
1323         /* at this point just to avoid the Delete-Empty-Paragraph
1324          * Mechanism when setting the cursor */
1325         TEXT(bv)->mark_set = mark_set;
1326         if (selection) {
1327             TEXT(bv)->SetCursor(bv, selstartpar, selstartpos);
1328             TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1329             TEXT(bv)->SetCursor(bv, selendpar, selendpos);
1330             TEXT(bv)->SetSelection();
1331             TEXT(bv)->SetCursor(bv, lpar, pos);
1332         } else {
1333             TEXT(bv)->SetCursor(bv, lpar, pos);
1334             TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1335             TEXT(bv)->selection = false;
1336         }
1337     }
1338     if (bv->screen())
1339             TEXT(bv)->first = bv->screen()->TopCursorVisible(TEXT(bv));
1340     // this will scroll the screen such that the cursor becomes visible 
1341     bv->updateScrollbar();
1342 //    AllowInput(bv);
1343     if (the_locking_inset) {
1344         /// then resize all LyXText in text-insets
1345         inset_x = cx(bv) - top_x + drawTextXOffset;
1346         inset_y = cy(bv) + drawTextYOffset;
1347         LyXParagraph * p = par;
1348         for(;p;p = p->next) {
1349             p->resizeInsetsLyXText(bv);
1350         }
1351     }
1352     need_update = FULL;
1353 }