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