]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
Added lyx-func tabular-feature for menu structure.
[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 "LColor.h"
42 #include "support/textutils.h"
43 #include "support/LAssert.h"
44 #include "lyxrow.h"
45 #include "lyxrc.h"
46 #include "intl.h"
47 #include "trans_mgr.h"
48 #include "lyxscreen.h"
49
50 using std::ostream;
51 using std::ifstream;
52 using std::endl;
53 using std::min;
54 using std::max;
55
56 extern unsigned char getCurrentTextClass(Buffer *);
57
58 InsetText::InsetText()
59 {
60     par = new LyXParagraph();
61     init();
62 }
63
64
65 InsetText::InsetText(InsetText const & ins)
66         : UpdatableInset()
67 {
68     par = 0;
69     init(&ins);
70     autoBreakRows = ins.autoBreakRows;
71 }
72
73
74 InsetText & InsetText::operator=(InsetText const & it)
75 {
76     init(&it);
77     autoBreakRows = it.autoBreakRows;
78     return * this;
79 }
80
81 void InsetText::init(InsetText const * ins)
82 {
83     top_y = last_width = last_height = 0;
84     insetAscent = insetDescent = insetWidth = 0;
85     the_locking_inset = 0;
86     cursor_visible = false;
87     interline_space = 1;
88     no_selection = false;
89     need_update = INIT;
90     drawTextXOffset = drawTextYOffset = 0;
91     autoBreakRows = false;
92     drawFrame = NEVER;
93     xpos = 0.0;
94     if (ins) {
95         SetParagraphData(ins->par);
96         autoBreakRows = ins->autoBreakRows;
97         drawFrame = ins->drawFrame;
98     }
99     par->SetInsetOwner(this);
100     frame_color = LColor::insetframe;
101     locked = false;
102     old_par = 0;
103 }
104
105
106 InsetText::~InsetText()
107 {
108     LyXParagraph * p = par->next;
109     delete par;
110     while(p) {
111         par = p;
112         p = p->next;
113         delete par;
114     }
115 }
116
117
118 void InsetText::clear()
119 {
120     LyXParagraph * p = par->next;
121     delete par;
122     while(p) {
123         par = p;
124         p = p->next;
125         delete par;
126     }
127     par = new LyXParagraph();
128 }
129
130
131 Inset * InsetText::Clone() const
132 {
133     InsetText * t = new InsetText(*this);
134     return t;
135 }
136
137
138 void InsetText::Write(Buffer const * buf, ostream & os) const
139 {
140     os << "Text\n";
141     WriteParagraphData(buf, os);
142 }
143
144
145 void InsetText::WriteParagraphData(Buffer const * buf, ostream & os) const
146 {
147     par->writeFile(buf, os, buf->params, 0, 0);
148 }
149
150
151 void InsetText::Read(Buffer const * buf, LyXLex & lex)
152 {
153     string token;
154     int pos = 0;
155     LyXParagraph * return_par = 0;
156     char depth = 0; // signed or unsigned?
157 #ifndef NEW_INSETS
158     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
159     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
160 #endif
161     LyXFont font(LyXFont::ALL_INHERIT);
162
163     LyXParagraph * p = par->next;
164     delete par;
165     while(p) {
166         par = p;
167         p = p->next;
168         delete par;
169     }
170     par = new LyXParagraph;
171     while (lex.IsOK()) {
172         lex.nextToken();
173         token = lex.GetString();
174         if (token.empty())
175             continue;
176         if (token == "\\end_inset")
177             break;
178         if (const_cast<Buffer*>(buf)->parseSingleLyXformat2Token(lex, par, return_par,
179                                             token, pos, depth,
180                                             font
181 #ifndef NEW_INSETS
182                                                                  , footnoteflag,
183                                             footnotekind
184 #endif
185                 )) {
186             // the_end read this should NEVER happen
187             lex.printError("\\the_end read in inset! Error in document!");
188             return;
189         }
190     }
191     if (!return_par)
192             return_par = par;
193     par = return_par;
194     while(return_par) {
195         return_par->SetInsetOwner(this);
196         return_par = return_par->next;
197     }
198     
199     if (token != "\\end_inset") {
200         lex.printError("Missing \\end_inset at this point. "
201                        "Read: `$$Token'");
202     }
203     need_update = INIT;
204 }
205
206
207 int InsetText::ascent(BufferView * bv, LyXFont const &) const
208 {
209     long int y_temp = 0;
210     Row * row = TEXT(bv)->GetRowNearY(y_temp);
211     insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
212     return insetAscent;
213 }
214
215
216 int InsetText::descent(BufferView * bv, LyXFont const &) const
217 {
218     long int y_temp = 0;
219     Row * row = TEXT(bv)->GetRowNearY(y_temp);
220     insetDescent = TEXT(bv)->height - row->ascent_of_text() +
221         TEXT_TO_INSET_OFFSET;
222     return insetDescent;
223 }
224
225
226 int InsetText::width(BufferView * bv, LyXFont const &) const
227 {
228     insetWidth = TEXT(bv)->width + (2 * TEXT_TO_INSET_OFFSET);
229     return insetWidth;
230 }
231
232
233 int InsetText::textWidth(Painter & pain) const
234 {
235     int w = getMaxWidth(pain, this);
236     if (w < 0) {
237         return w;
238     }
239     if (owner()) {
240         w = w - top_x + owner()->x();
241         return w;
242     }
243     w -= (2 * TEXT_TO_INSET_OFFSET);
244     return w - top_x;
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, int(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, int(x));
309     } else {
310         locked = false;
311         if (need_update == CURSOR) {
312             bv->screen()->ToggleSelection(TEXT(bv), true, y, int(x));
313             TEXT(bv)->ClearSelection();
314             TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
315         }
316         bv->screen()->Update(TEXT(bv), y, int(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()->setLayout(cpar(bv)->GetLayout());
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()->setLayout(owner()->getLyXText(bv)
465                                     ->cursor.par()->GetLayout());
466     else
467             bv->owner()->setLayout(bv->text->cursor.par()->GetLayout());
468 }
469
470
471 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
472 {
473     lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
474     if (!inset)
475         return false;
476     if (inset == cpar(bv)->GetInset(cpos(bv))) {
477         lyxerr[Debug::INSETS] << "OK" << endl;
478         the_locking_inset = inset;
479         inset_x = cx(bv) - top_x + drawTextXOffset;
480         inset_y = cy(bv) + drawTextYOffset;
481         inset_pos = cpos(bv);
482         inset_par = cpar(bv);
483         TEXT(bv)->UpdateInset(bv, the_locking_inset);
484         return true;
485     } else if (the_locking_inset && (the_locking_inset == inset)) {
486         if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
487             lyxerr[Debug::INSETS] << "OK" << endl;
488             inset_x = cx(bv) - top_x + drawTextXOffset;
489             inset_y = cy(bv) + drawTextYOffset;
490         } else {
491             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
492         }
493     } else if (the_locking_inset) {
494         lyxerr[Debug::INSETS] << "MAYBE" << endl;
495         return the_locking_inset->LockInsetInInset(bv, inset);
496     }
497     lyxerr[Debug::INSETS] << "NOT OK" << endl;
498     return false;
499 }
500
501
502 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
503                                    bool lr)
504 {
505     if (!the_locking_inset)
506         return false;
507     if (the_locking_inset == inset) {
508         the_locking_inset->InsetUnlock(bv);
509         TEXT(bv)->UpdateInset(bv, inset);
510         the_locking_inset = 0;
511         if (lr)
512             moveRight(bv, false);
513         old_par = 0; // force layout setting
514         UpdateLocal(bv, CURSOR_PAR, false);
515         return true;
516     }
517     return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
518 }
519
520
521 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
522 {
523     if (!the_locking_inset)
524         return false;
525     if (the_locking_inset != inset) {
526         TEXT(bv)->UpdateInset(bv, the_locking_inset);
527         need_update = CURSOR_PAR;
528         return the_locking_inset->UpdateInsetInInset(bv, inset);
529     }
530 //    UpdateLocal(bv, FULL, false);
531     if (TEXT(bv)->UpdateInset(bv, inset))
532         UpdateLocal(bv, CURSOR_PAR, false);
533     if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
534         inset_x = cx(bv) - top_x + drawTextXOffset;
535         inset_y = cy(bv) + drawTextYOffset;
536     }
537     return true;
538 }
539
540
541 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
542 {
543     no_selection = false;
544
545     int tmp_x = x - drawTextXOffset;
546 //    int tmp_y = y + TEXT(bv)->first + insetAscent;
547     int tmp_y = y + insetAscent;
548     Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
549
550     if (the_locking_inset) {
551         if (the_locking_inset == inset) {
552             the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
553             return;
554         } else if (inset) {
555             // otherwise unlock the_locking_inset and lock the new inset
556             the_locking_inset->InsetUnlock(bv);
557             inset_x = cx(bv) - top_x + drawTextXOffset;
558             inset_y = cy(bv) + drawTextYOffset;
559             inset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
560             inset->Edit(bv, x - inset_x, y - inset_y, button);
561             if (the_locking_inset) {
562                 UpdateLocal(bv, CURSOR_PAR, false);
563             }
564             return;
565         }
566         // otherwise only unlock the_locking_inset
567         the_locking_inset->InsetUnlock(bv);
568         the_locking_inset = 0;
569     }
570     if (bv->the_locking_inset) {
571         if (inset && inset->Editable() == Inset::HIGHLY_EDITABLE) {
572             UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
573             inset_x = cx(bv) - top_x + drawTextXOffset;
574             inset_y = cy(bv) + drawTextYOffset;
575             inset_pos = cpos(bv);
576             inset_par = cpar(bv);
577             uinset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
578             uinset->Edit(bv, x - inset_x, y - inset_y, 0);
579             if (the_locking_inset) {
580                 UpdateLocal(bv, CURSOR_PAR, false);
581             }
582             return;
583         }
584     }
585     if (!inset) {
586         TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
587                                            y+TEXT(bv)->first+insetAscent);
588         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
589         UpdateLocal(bv, CURSOR, false);
590         bv->owner()->setLayout(cpar(bv)->GetLayout());
591         old_par = cpar(bv);
592     }
593 }
594
595
596 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
597 {
598     UpdatableInset * inset = 0;
599
600     if (the_locking_inset) {
601             the_locking_inset->InsetButtonRelease(bv,
602                                                   x - inset_x, y - inset_y,
603                                                   button);
604     } else {
605         if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
606             inset = static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
607             if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
608                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
609             } else {
610                 inset_x = cx(bv) - top_x + drawTextXOffset;
611                 inset_y = cy(bv) + drawTextYOffset;
612                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
613                 inset->Edit(bv, x - inset_x, y - inset_y, button);
614             }
615             UpdateLocal(bv, CURSOR_PAR, false);
616         }
617     }
618     no_selection = false;
619 }
620
621
622 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
623 {
624     if (the_locking_inset) {
625         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
626                                              y - inset_y,state);
627         return;
628     }
629     if (!no_selection) {
630         HideInsetCursor(bv);
631         TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
632                                            y+TEXT(bv)->first+insetAscent);
633         TEXT(bv)->SetSelection();
634         if (TEXT(bv)->toggle_cursor.par()!=TEXT(bv)->toggle_end_cursor.par() ||
635             TEXT(bv)->toggle_cursor.pos()!=TEXT(bv)->toggle_end_cursor.pos())
636             UpdateLocal(bv, SELECTION, false);
637         ShowInsetCursor(bv);
638     }
639     no_selection = false;
640 }
641
642
643 void InsetText::InsetKeyPress(XKeyEvent * xke)
644 {
645     if (the_locking_inset) {
646         the_locking_inset->InsetKeyPress(xke);
647         return;
648     }
649 }
650
651
652 UpdatableInset::RESULT
653 InsetText::LocalDispatch(BufferView * bv,
654                          int action, string const & arg)
655 {
656     no_selection = false;
657     UpdatableInset::RESULT
658         result= UpdatableInset::LocalDispatch(bv, action, arg);
659     if (result != UNDISPATCHED) {
660 //      resetPos(bv->painter());
661         return DISPATCHED;
662     }
663
664     result=DISPATCHED;
665     if ((action < 0) && arg.empty())
666         return FINISHED;
667
668     if (the_locking_inset) {
669         result = the_locking_inset->LocalDispatch(bv, action, arg);
670         if (result == DISPATCHED_NOUPDATE)
671             return result;
672         else if (result == DISPATCHED) {
673             UpdateLocal(bv, CURSOR_PAR, false);
674             return result;
675         } else if (result == FINISHED) {
676             switch(action) {
677             case -1:
678             case LFUN_RIGHT:
679                 moveRight(bv, false);
680                 break;
681             case LFUN_DOWN:
682                 moveDown(bv);
683                 break;
684             }
685             the_locking_inset = 0;
686             return DISPATCHED;
687         }
688     }
689     HideInsetCursor(bv);
690     switch (action) {
691         // Normal chars
692     case -1:
693         if (bv->buffer()->isReadonly()) {
694             LyXBell();
695 //          setErrorMessage(N_("Document is read only"));
696             break;
697         }
698         if (!arg.empty()) {
699             /* Automatically delete the currently selected
700              * text and replace it with what is being
701              * typed in now. Depends on lyxrc settings
702              * "auto_region_delete", which defaults to
703              * true (on). */
704
705             bv->text->SetUndo(bv->buffer(), Undo::INSERT,
706 #ifndef NEW_INSETS
707                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
708                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
709 #else
710                               bv->text->cursor.par()->previous,
711                               bv->text->cursor.par()->next
712 #endif
713                     );
714             if (lyxrc.auto_region_delete) {
715                 if (TEXT(bv)->selection){
716                     TEXT(bv)->CutSelection(bv, false);
717                 }
718             }
719             TEXT(bv)->ClearSelection();
720             for (string::size_type i = 0; i < arg.length(); ++i) {
721                 bv->owner()->getIntl()->getTrans()->TranslateAndInsert(arg[i], TEXT(bv));
722             }
723         }
724         UpdateLocal(bv, CURSOR_PAR, true);
725         break;
726         // --- Cursor Movements ---------------------------------------------
727     case LFUN_RIGHTSEL:
728         bv->text->FinishUndo();
729         moveRight(bv, false);
730         TEXT(bv)->SetSelection();
731         UpdateLocal(bv, SELECTION, false);
732         break;
733     case LFUN_RIGHT:
734         result = moveRight(bv);
735         bv->text->FinishUndo();
736         UpdateLocal(bv, CURSOR, false);
737         break;
738     case LFUN_LEFTSEL:
739         bv->text->FinishUndo();
740         moveLeft(bv, false);
741         TEXT(bv)->SetSelection();
742         UpdateLocal(bv, SELECTION, false);
743         break;
744     case LFUN_LEFT:
745         bv->text->FinishUndo();
746         result= moveLeft(bv);
747         UpdateLocal(bv, CURSOR, false);
748         break;
749     case LFUN_DOWNSEL:
750         bv->text->FinishUndo();
751         moveDown(bv);
752         TEXT(bv)->SetSelection();
753         UpdateLocal(bv, SELECTION, false);
754         break;
755     case LFUN_DOWN:
756         bv->text->FinishUndo();
757         result = moveDown(bv);
758         UpdateLocal(bv, CURSOR, false);
759         break;
760     case LFUN_UPSEL:
761         bv->text->FinishUndo();
762         moveUp(bv);
763         TEXT(bv)->SetSelection();
764         UpdateLocal(bv, SELECTION, false);
765         break;
766     case LFUN_UP:
767         bv->text->FinishUndo();
768         result = moveUp(bv);
769         UpdateLocal(bv, CURSOR, false);
770         break;
771     case LFUN_HOME:
772         bv->text->FinishUndo();
773         TEXT(bv)->CursorHome(bv);
774         UpdateLocal(bv, CURSOR, false);
775         break;
776     case LFUN_END:
777         TEXT(bv)->CursorEnd(bv);
778         UpdateLocal(bv, CURSOR, false);
779         break;
780     case LFUN_BACKSPACE:
781         bv->text->SetUndo(bv->buffer(), Undo::DELETE,
782 #ifndef NEW_INSETS
783           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
784           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
785 #else
786           bv->text->cursor.par()->previous,
787           bv->text->cursor.par()->next
788 #endif
789                 );
790         TEXT(bv)->Backspace(bv);
791         UpdateLocal(bv, CURSOR_PAR, true);
792         break;
793     case LFUN_DELETE:
794         bv->text->SetUndo(bv->buffer(), Undo::DELETE,
795 #ifndef NEW_INSETS
796           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
797           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
798 #else
799           bv->text->cursor.par()->previous,
800           bv->text->cursor.par()->next
801 #endif
802                 );
803         TEXT(bv)->Delete(bv);
804         UpdateLocal(bv, CURSOR_PAR, true);
805         break;
806     case LFUN_CUT:
807         bv->text->SetUndo(bv->buffer(), Undo::DELETE,
808 #ifndef NEW_INSETS
809           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
810           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
811 #else
812           bv->text->cursor.par()->previous,
813           bv->text->cursor.par()->next
814 #endif
815                 );
816         TEXT(bv)->CutSelection(bv);
817         UpdateLocal(bv, CURSOR_PAR, true);
818         break;
819     case LFUN_COPY:
820         bv->text->FinishUndo();
821         TEXT(bv)->CopySelection(bv);
822         UpdateLocal(bv, CURSOR_PAR, false);
823         break;
824     case LFUN_PASTE:
825         if (!autoBreakRows) {
826             CutAndPaste cap;
827
828             if (cap.nrOfParagraphs() > 1) {
829                 WriteAlert(_("Impossible operation"),
830                            _("Cannot include more than one paragraph!"),
831                            _("Sorry."));
832                 break;
833             }
834         }
835         bv->text->SetUndo(bv->buffer(), Undo::INSERT,
836 #ifndef NEW_INSETS
837           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
838           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
839 #else
840           bv->text->cursor.par()->previous,
841           bv->text->cursor.par()->next
842 #endif
843                 );
844         TEXT(bv)->PasteSelection(bv);
845         UpdateLocal(bv, CURSOR_PAR, true);
846         break;
847     case LFUN_BREAKPARAGRAPH:
848         if (!autoBreakRows)
849             return DISPATCHED;
850         TEXT(bv)->BreakParagraph(bv, 0);
851         UpdateLocal(bv, FULL, true);
852         break;
853     case LFUN_BREAKLINE:
854         if (!autoBreakRows)
855             return DISPATCHED;
856         bv->text->SetUndo(bv->buffer(), Undo::INSERT,
857 #ifndef NEW_INSETS
858             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
859             bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
860 #else
861             bv->text->cursor.par()->previous,
862             bv->text->cursor.par()->next
863 #endif
864                 );
865         TEXT(bv)->InsertChar(bv, LyXParagraph::META_NEWLINE);
866         UpdateLocal(bv, CURSOR_PAR, true);
867         break;
868     case LFUN_LAYOUT:
869     {
870       static LyXTextClass::size_type cur_layout = cpar(bv)->layout;
871       
872         // Derive layout number from given argument (string)
873         // and current buffer's textclass (number). */    
874         LyXTextClassList::ClassList::size_type tclass =
875             bv->buffer()->params.textclass;
876         std::pair <bool, LyXTextClass::size_type> layout = 
877             textclasslist.NumberOfLayout(tclass, arg);
878
879         // If the entry is obsolete, use the new one instead.
880         if (layout.first) {
881             string obs = textclasslist.Style(tclass,layout.second).
882                 obsoleted_by();
883             if (!obs.empty()) 
884                 layout = textclasslist.NumberOfLayout(tclass, obs);
885         }
886
887         // see if we found the layout number:
888         if (!layout.first) {
889             string msg = string(N_("Layout ")) + arg + N_(" not known");
890
891             bv->owner()->getMiniBuffer()->Set(msg);
892             break;
893         }
894
895         if (cur_layout != layout.second) {
896             cur_layout = layout.second;
897             TEXT(bv)->SetLayout(bv, layout.second);
898             bv->owner()->setLayout(cpar(bv)->GetLayout());
899             UpdateLocal(bv, CURSOR_PAR, true);
900         }
901     }
902     break;
903     case LFUN_PARAGRAPH_SPACING:
904             // This one is absolutely not working. When fiddling with this
905             // it also seems to me that the paragraphs inside the insettext
906             // inherit bufferparams/paragraphparams in a strange way. (Lgb)
907     {
908             LyXParagraph * par = TEXT(bv)->cursor.par();
909             Spacing::Space cur_spacing = par->spacing.getSpace();
910             float cur_value = 1.0;
911             if (cur_spacing == Spacing::Other) {
912                     cur_value = par->spacing.getValue();
913             }
914                         
915 #ifdef HAVE_SSTREAM
916             std::istringstream istr(arg.c_str());
917 #else
918             istrstream istr(arg.c_str());
919 #endif
920             string tmp;
921             istr >> tmp;
922             Spacing::Space new_spacing = cur_spacing;
923             float new_value = cur_value;
924             if (tmp.empty()) {
925                     lyxerr << "Missing argument to `paragraph-spacing'"
926                            << endl;
927             } else if (tmp == "single") {
928                     new_spacing = Spacing::Single;
929             } else if (tmp == "onehalf") {
930                     new_spacing = Spacing::Onehalf;
931             } else if (tmp == "double") {
932                     new_spacing = Spacing::Double;
933             } else if (tmp == "other") {
934                     new_spacing = Spacing::Other;
935                     float tmpval = 0.0;
936                     istr >> tmpval;
937                     lyxerr << "new_value = " << tmpval << endl;
938                     if (tmpval != 0.0)
939                             new_value = tmpval;
940             } else if (tmp == "default") {
941                     new_spacing = Spacing::Default;
942             } else {
943                     lyxerr << _("Unknown spacing argument: ")
944                            << arg << endl;
945             }
946             if (cur_spacing != new_spacing || cur_value != new_value) {
947                     par->spacing.set(new_spacing, new_value);
948                     //TEXT(bv)->RedoParagraph(owner->view());
949                     UpdateLocal(bv, CURSOR_PAR, true);
950                     //bv->update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
951             }
952     }
953     break;
954         
955     default:
956         result = UNDISPATCHED;
957         break;
958     }
959     if (result != FINISHED) {
960         ShowInsetCursor(bv);
961     } else
962         bv->unlockInset(this);
963     return result;
964 }
965
966
967 int InsetText::Latex(Buffer const * buf, ostream & os, bool, bool) const
968 {
969     TexRow texrow;
970     buf->latexParagraphs(os, par, 0, texrow);
971     return texrow.rows();
972 }
973
974
975 void InsetText::Validate(LaTeXFeatures & features) const
976 {
977     LyXParagraph * p = par;
978     while(p) {
979         p->validate(features);
980         p = p->next;
981     }
982 }
983
984
985 int InsetText::BeginningOfMainBody(Buffer const * buf, LyXParagraph * p) const
986 {
987     if (textclasslist.Style(buf->params.textclass,
988                             p->GetLayout()).labeltype != LABEL_MANUAL)
989         return 0;
990     else
991         return p->BeginningOfMainBody();
992 }
993
994
995 void InsetText::GetCursorPos(BufferView * bv, int & x, int & y) const
996 {
997     x = cx(bv);
998     y = cy(bv);
999 }
1000
1001
1002 int InsetText::InsetInInsetY()
1003 {
1004     if (!the_locking_inset)
1005         return 0;
1006
1007     return (inset_y + the_locking_inset->InsetInInsetY());
1008 }
1009
1010
1011 void InsetText::ToggleInsetCursor(BufferView * bv)
1012 {
1013     if (the_locking_inset) {
1014         the_locking_inset->ToggleInsetCursor(bv);
1015         return;
1016     }
1017
1018     LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1019
1020     int asc = lyxfont::maxAscent(font);
1021     int desc = lyxfont::maxDescent(font);
1022   
1023     if (cursor_visible)
1024         bv->hideLockedInsetCursor();
1025     else
1026         bv->showLockedInsetCursor(cx(bv)-1, cy(bv),
1027                                   asc, desc);
1028     cursor_visible = !cursor_visible;
1029 }
1030
1031
1032 void InsetText::ShowInsetCursor(BufferView * bv)
1033 {
1034     if (the_locking_inset) {
1035         the_locking_inset->ShowInsetCursor(bv);
1036         return;
1037     }
1038     if (!cursor_visible) {
1039         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1040         
1041         int asc = lyxfont::maxAscent(font);
1042         int desc = lyxfont::maxDescent(font);
1043
1044         bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1045         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1046         cursor_visible = true;
1047     }
1048 }
1049
1050
1051 void InsetText::HideInsetCursor(BufferView * bv)
1052 {
1053     if (cursor_visible) {
1054         bv->hideLockedInsetCursor();
1055         cursor_visible = false;
1056     }
1057     if (the_locking_inset)
1058         the_locking_inset->HideInsetCursor(bv);
1059 }
1060
1061
1062 UpdatableInset::RESULT
1063 InsetText::moveRight(BufferView * bv, bool activate_inset)
1064 {
1065     if (!cpar(bv)->next && (cpos(bv) >= cpar(bv)->Last()))
1066         return FINISHED;
1067     if (activate_inset && checkAndActivateInset(bv, false))
1068         return DISPATCHED;
1069     TEXT(bv)->CursorRight(bv);
1070     return DISPATCHED_NOUPDATE;
1071 }
1072
1073
1074 UpdatableInset::RESULT
1075 InsetText::moveLeft(BufferView * bv, bool activate_inset)
1076 {
1077     if (!cpar(bv)->previous && (cpos(bv) <= 0))
1078         return FINISHED;
1079     TEXT(bv)->CursorLeft(bv);
1080     if (activate_inset && checkAndActivateInset(bv, true))
1081         return DISPATCHED;
1082     return DISPATCHED_NOUPDATE;
1083 }
1084
1085
1086 UpdatableInset::RESULT
1087 InsetText::moveUp(BufferView * bv)
1088 {
1089     if (!crow(bv)->previous())
1090         return FINISHED;
1091     TEXT(bv)->CursorUp(bv);
1092     return DISPATCHED_NOUPDATE;
1093 }
1094
1095
1096 UpdatableInset::RESULT
1097 InsetText::moveDown(BufferView * bv)
1098 {
1099     if (!crow(bv)->next())
1100         return FINISHED;
1101     TEXT(bv)->CursorDown(bv);
1102     return DISPATCHED_NOUPDATE;
1103 }
1104
1105
1106 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1107 {
1108     if (the_locking_inset) {
1109         if (the_locking_inset->InsertInsetAllowed(inset))
1110             return the_locking_inset->InsertInset(bv, inset);
1111         return false;
1112     }
1113     bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1114 #ifndef NEW_INSETS
1115               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
1116               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
1117 #else
1118               bv->text->cursor.par()->previous,
1119               bv->text->cursor.par()->next
1120 #endif
1121             );
1122     if (inset->Editable() == Inset::IS_EDITABLE) {
1123         UpdatableInset * i = static_cast<UpdatableInset *>(inset);
1124         i->setOwner(static_cast<UpdatableInset *>(this));
1125     }
1126     TEXT(bv)->InsertInset(bv, inset);
1127     TEXT(bv)->selection = 0;
1128     UpdateLocal(bv, CURSOR_PAR, true);
1129     static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
1130     return true;
1131 }
1132
1133
1134 UpdatableInset * InsetText::GetLockingInset()
1135 {
1136     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1137 }
1138
1139
1140 UpdatableInset * InsetText::GetFirstLockingInsetOfType(Inset::Code c)
1141 {
1142     if (c == LyxCode())
1143         return this;
1144     if (the_locking_inset)
1145         return the_locking_inset->GetFirstLockingInsetOfType(c);
1146     return 0;
1147 }
1148
1149
1150 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1151 {
1152     TEXT(bv)->SetFont(bv, font, toggleall);
1153 }
1154
1155
1156 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1157 {
1158     if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
1159         int x, y;
1160         Inset * inset =
1161             static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
1162         if (!inset || inset->Editable() != Inset::HIGHLY_EDITABLE)
1163             return false;
1164         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1165         if (behind) {
1166             x = inset->width(bv, font);
1167             y = inset->descent(bv, font);
1168         } else {
1169             x = y = 0;
1170         }
1171         inset_x = cx(bv) - top_x + drawTextXOffset;
1172         inset_y = cy(bv) + drawTextYOffset;
1173         inset->Edit(bv, x-inset_x, y-inset_y, 0);
1174         if (!the_locking_inset)
1175             return false;
1176         UpdateLocal(bv, CURSOR_PAR, false);
1177         return true;
1178     }
1179     return false;
1180 }
1181
1182
1183 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1184                                       int button)
1185 {
1186     int tmp_x = x - drawTextXOffset;
1187     int tmp_y = y + insetAscent;
1188     Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
1189
1190     if (inset) {
1191         if (x < 0)
1192             x = insetWidth;
1193         if (y < 0)
1194             y = insetDescent;
1195         inset_x = cx(bv) - top_x + drawTextXOffset;
1196         inset_y = cy(bv) + drawTextYOffset;
1197         inset->Edit(bv, x - inset_x, y - inset_y, button);
1198         if (!the_locking_inset)
1199             return false;
1200         UpdateLocal(bv, CURSOR_PAR, false);
1201         return true;
1202     }
1203     return false;
1204 }
1205
1206
1207 int InsetText::getMaxWidth(Painter & pain, UpdatableInset const * inset) const
1208 {
1209     int w = UpdatableInset::getMaxWidth(pain, inset);
1210     if (w < 0)
1211         return w;
1212     return  w - (2*TEXT_TO_INSET_OFFSET);
1213 }
1214
1215
1216 void InsetText::SetParagraphData(LyXParagraph *p)
1217 {
1218     LyXParagraph * np;
1219
1220     if (par) {
1221         np = par->next;
1222         delete par;
1223         while(np) {
1224             par = np;
1225             np = np->next;
1226             delete par;
1227         }
1228     }
1229     par = p->Clone();
1230     par->SetInsetOwner(this);
1231     np = par;
1232     while(p->next) {
1233         p = p->next;
1234         np->next = p->Clone();
1235         np->next->previous = np;
1236         np = np->next;
1237         np->SetInsetOwner(this);
1238     }
1239     need_update = INIT;
1240 }
1241
1242
1243 void InsetText::SetAutoBreakRows(bool flag)
1244 {
1245     if (flag != autoBreakRows) {
1246         autoBreakRows = flag;
1247         need_update = FULL;
1248     }
1249 }
1250
1251
1252 void InsetText::SetDrawFrame(BufferView * bv, DrawFrame how)
1253 {
1254     if (how != drawFrame) {
1255         drawFrame = how;
1256         if (bv)
1257             UpdateLocal(bv, DRAW_FRAME, false);
1258     }
1259 }
1260
1261
1262 void InsetText::SetFrameColor(BufferView * bv, LColor::color col)
1263 {
1264     if (frame_color != col) {
1265         frame_color = col;
1266         if (bv)
1267             UpdateLocal(bv, DRAW_FRAME, false);
1268     }
1269 }
1270
1271 #if 0
1272 LyXFont InsetText::GetDrawFont(BufferView * bv, LyXParagraph * p, int pos) const
1273 {
1274     return TEXT(bv)->GetFont(bv->buffer(), p, pos);
1275 }
1276 #endif
1277
1278 int InsetText::cx(BufferView * bv) const
1279 {
1280     return TEXT(bv)->cursor.x() + top_x + 1;
1281 }
1282
1283
1284 int InsetText::cy(BufferView * bv) const
1285 {
1286     long int y_dummy = 0;
1287     Row * tmprow = TEXT(bv)->GetRowNearY(y_dummy);
1288     return TEXT(bv)->cursor.y() - tmprow->baseline();
1289 }
1290
1291
1292 int InsetText::cpos(BufferView * bv) const
1293 {
1294     return TEXT(bv)->cursor.pos();
1295 }
1296
1297
1298 LyXParagraph * InsetText::cpar(BufferView * bv) const
1299 {
1300     return TEXT(bv)->cursor.par();
1301 }
1302
1303
1304 Row * InsetText::crow(BufferView * bv) const
1305 {
1306     return TEXT(bv)->cursor.row();
1307 }
1308
1309
1310 LyXText * InsetText::getLyXText(BufferView * bv) const
1311 {
1312     if (cache.find(bv) != cache.end())
1313         return cache[bv];
1314     LyXText * lt = new LyXText(const_cast<InsetText *>(this));
1315     lt->init(bv);
1316     cache[bv] = lt;
1317     if (the_locking_inset) {
1318         lt->SetCursor(bv, inset_par, inset_pos);
1319     }
1320     return lt;
1321 }
1322
1323
1324 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1325 {
1326     cache.erase(bv);
1327     if (recursive) {
1328         /// then remove all LyXText in text-insets
1329         LyXParagraph * p = par;
1330         for(;p;p = p->next) {
1331             p->deleteInsetsLyXText(bv);
1332         }
1333     }
1334 }
1335
1336 void InsetText::resizeLyXText(BufferView * bv) const
1337 {
1338     if (!par->next && !par->size()) // not neccessary!
1339         return;
1340
1341     LyXParagraph * lpar = 0;
1342     LyXParagraph * selstartpar = 0;
1343     LyXParagraph * selendpar = 0;
1344     int pos = 0;
1345     int selstartpos = 0;
1346     int selendpos = 0;
1347     int selection = 0;
1348     int mark_set = 0;
1349
1350 //    ProhibitInput(bv);
1351
1352     lpar = TEXT(bv)->cursor.par();
1353     pos = TEXT(bv)->cursor.pos();
1354     selstartpar = TEXT(bv)->sel_start_cursor.par();
1355     selstartpos = TEXT(bv)->sel_start_cursor.pos();
1356     selendpar = TEXT(bv)->sel_end_cursor.par();
1357     selendpos = TEXT(bv)->sel_end_cursor.pos();
1358     selection = TEXT(bv)->selection;
1359     mark_set = TEXT(bv)->mark_set;
1360     deleteLyXText(bv, (the_locking_inset == 0));
1361
1362     if (lpar) {
1363         TEXT(bv)->selection = true;
1364         /* at this point just to avoid the Delete-Empty-Paragraph
1365          * Mechanism when setting the cursor */
1366         TEXT(bv)->mark_set = mark_set;
1367         if (selection) {
1368             TEXT(bv)->SetCursor(bv, selstartpar, selstartpos);
1369             TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1370             TEXT(bv)->SetCursor(bv, selendpar, selendpos);
1371             TEXT(bv)->SetSelection();
1372             TEXT(bv)->SetCursor(bv, lpar, pos);
1373         } else {
1374             TEXT(bv)->SetCursor(bv, lpar, pos);
1375             TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1376             TEXT(bv)->selection = false;
1377         }
1378     }
1379     if (bv->screen())
1380             TEXT(bv)->first = bv->screen()->TopCursorVisible(TEXT(bv));
1381     // this will scroll the screen such that the cursor becomes visible 
1382     bv->updateScrollbar();
1383 //    AllowInput(bv);
1384     if (the_locking_inset) {
1385         /// then resize all LyXText in text-insets
1386         inset_x = cx(bv) - top_x + drawTextXOffset;
1387         inset_y = cy(bv) + drawTextYOffset;
1388         LyXParagraph * p = par;
1389         for(;p;p = p->next) {
1390             p->resizeInsetsLyXText(bv);
1391         }
1392     }
1393     need_update = FULL;
1394 }