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