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