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