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