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