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