]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
clear()->erase() ; lots of using directives for cxx
[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 "lyxlex.h"
25 #include "debug.h"
26 #include "lyxfont.h"
27 #include "lyxlex.h"
28 #include "commandtags.h"
29 #include "buffer.h"
30 #include "LyXView.h"
31 #include "BufferView.h"
32 #include "support/textutils.h"
33 #include "layout.h"
34 #include "insetlatexaccent.h"
35 #include "insetquotes.h"
36 #include "mathed/formulamacro.h"
37 #include "figinset.h"
38 #include "insetinfo.h"
39 #include "insetinclude.h"
40 #include "insetbib.h"
41 #include "insetcommand.h"
42 #include "insetindex.h"
43 #include "insetlabel.h"
44 #include "insetref.h"
45 //#include "insettabular.h"
46 #include "insetert.h"
47 #include "insetspecialchar.h"
48 #include "LaTeXFeatures.h"
49 #include "Painter.h"
50 #include "lyx_gui_misc.h"
51 #include "support/LAssert.h"
52 #include "lyxtext.h"
53 #include "lyxcursor.h"
54 #include "CutAndPaste.h"
55 #include "font.h"
56 #include "minibuffer.h"
57 #include "toolbar.h"
58
59 using std::ostream;
60 using std::ifstream;
61 using std::endl;
62 using std::min;
63 using std::max;
64
65 extern unsigned char getCurrentTextClass(Buffer *);
66 extern LyXTextClass::size_type current_layout;
67
68
69 InsetText::InsetText(Buffer * buf)
70 {
71     par = new LyXParagraph();
72     init(buf);
73 }
74
75
76 InsetText::InsetText(InsetText const & ins, Buffer * buf)
77 {
78     par = 0;
79     init(buf, &ins);
80     autoBreakRows = ins.autoBreakRows;
81 }
82
83
84 void InsetText::init(Buffer * buf, InsetText const * ins)
85 {
86     the_locking_inset = 0;
87     buffer = buf;
88     cursor_visible = false;
89     cursor.x_fix = -1;
90     interline_space = 1;
91     no_selection = false;
92     init_inset = true;
93     maxAscent = maxDescent = insetWidth = 0;
94     drawTextXOffset = drawTextYOffset = 0;
95     autoBreakRows = false;
96     xpos = 0.0;
97     if (ins) {
98         SetParagraphData(ins->par);
99         autoBreakRows = ins->autoBreakRows;
100     }
101     par->SetInsetOwner(this);
102     cursor.par = par;
103     cursor.pos = 0;
104     selection_start_cursor = selection_end_cursor = cursor;
105 }
106
107
108 InsetText::~InsetText()
109 {
110     delete par;
111 }
112
113
114 Inset * InsetText::Clone() const
115 {
116     InsetText * t = new InsetText(*this, buffer);
117     return t;
118 }
119
120
121 void InsetText::Write(ostream & os) const
122 {
123     os << "Text\n";
124     WriteParagraphData(os);
125 }
126
127
128 void InsetText::WriteParagraphData(ostream & os) const
129 {
130     par->writeFile(os, buffer->params, 0, 0);
131 }
132
133
134 void InsetText::Read(LyXLex & lex)
135 {
136     string token, tmptok;
137     int pos = 0;
138     LyXParagraph * return_par = 0;
139     char depth = 0; // signed or unsigned?
140     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
141     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
142     LyXFont font(LyXFont::ALL_INHERIT);
143
144     delete par;
145     par = new LyXParagraph;
146     par->SetInsetOwner(this);
147     
148     while (lex.IsOK()) {
149         lex.nextToken();
150         token = lex.GetString();
151         if (token.empty())
152             continue;
153         if (token == "\\end_inset")
154             break;
155         if (buffer->parseSingleLyXformat2Token(lex, par, return_par,
156                                                token, pos, depth,
157                                                font, footnoteflag,
158                                                footnotekind)) {
159             // the_end read this should NEVER happen
160             lex.printError("\\the_end read in inset! Error in document!");
161             return;
162         }
163     }
164     if (token != "\\end_inset") {
165         lex.printError("Missing \\end_inset at this point. "
166                        "Read: `$$Token'");
167     }
168     init_inset = true;
169 }
170
171
172 int InsetText::ascent(Painter & pain, LyXFont const & font) const
173 {
174     if (init_inset) {
175         computeTextRows(pain, xpos);
176         resetPos(pain);
177         init_inset = false;
178     }
179     if (maxAscent)
180         return maxAscent;
181     return lyxfont::maxAscent(font);
182 }
183
184
185 int InsetText::descent(Painter & pain, LyXFont const & font) const
186 {
187     if (init_inset) {
188         computeTextRows(pain, xpos);
189         resetPos(pain);
190         init_inset = false;
191     }
192     if (maxDescent)
193         return maxDescent;
194     return lyxfont::maxDescent(font);
195 }
196
197
198 int InsetText::width(Painter & pain, LyXFont const &) const
199 {
200     if (init_inset) {
201         computeTextRows(pain, xpos);
202         resetPos(pain);
203         init_inset = false;
204     }
205     return insetWidth;
206 }
207
208
209 void InsetText::draw(Painter & pain, LyXFont const & f,
210                      int baseline, float & x) const
211 {
212     xpos = x;
213     UpdatableInset::draw(pain, f, baseline, x);
214     
215     if (init_inset || (baseline != top_baseline) || (top_x != int(x))) {
216         top_baseline = baseline;
217         if (init_inset || (top_x != int(x))) {
218             top_x = int(x);
219             computeTextRows(pain, x);
220             init_inset = false;
221         }
222         computeBaselines(baseline);
223     }
224     if (the_locking_inset && (cursor.pos == inset_pos)) {
225         resetPos(pain);
226         inset_x = cursor.x - top_x + drawTextXOffset;
227         inset_y = cursor.y + drawTextYOffset;
228     }
229     for(RowList::size_type r = 0; r < rows.size() - 1; ++r) {
230         drawRowSelection(pain, rows[r].pos, rows[r + 1].pos, r, 
231                          rows[r].baseline, x);
232         drawRowText(pain, rows[r].pos, rows[r + 1].pos, rows[r].baseline, x);
233     }
234     x += insetWidth;
235 }
236
237
238 void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
239                                  int row, int baseline, float x) const
240 {
241     if (!hasSelection())
242         return;
243
244     int s_start, s_end;
245     if (selection_start_cursor.pos > selection_end_cursor.pos) {
246         s_start = selection_end_cursor.pos;
247         s_end = selection_start_cursor.pos;
248     } else {
249         s_start = selection_start_cursor.pos;
250         s_end = selection_end_cursor.pos;
251     }
252     if ((s_start > endpos) || (s_end < startpos))
253         return;
254     
255     int esel_x;
256     int ssel_x = esel_x = int(x);
257     LyXFont font;
258     int p = startpos;
259     for(; p < endpos; ++p) {
260         if (p == s_start)
261             ssel_x = int(x);
262         if ((p >= s_start) && (p <= s_end))
263             esel_x = int(x);
264         char ch = par->GetChar(p);
265         font = GetDrawFont(par,p);
266         if (IsFloatChar(ch)) {
267             // skip for now
268         } else if (ch == LyXParagraph::META_INSET) {
269             Inset const * tmpinset = par->GetInset(p);
270             x += tmpinset->width(pain, font);
271         } else {
272             x += lyxfont::width(ch, font);
273         }
274     }
275     if (p == s_start)
276         ssel_x = int(x);
277     if ((p >= s_start) && (p <= s_end))
278         esel_x = int(x);
279     if (ssel_x < esel_x) {
280         pain.fillRectangle(int(ssel_x), baseline-rows[row].asc,
281                            int(esel_x - ssel_x),
282                            rows[row].asc + rows[row].desc,
283                            LColor::selection);
284     }
285 }
286
287
288 void InsetText::drawRowText(Painter & pain, int startpos, int endpos,
289                             int baseline, float x) const
290 {
291     Assert(endpos <= par->Last());
292
293     for(int p = startpos; p < endpos; ++p) {
294         char ch = par->GetChar(p);
295         LyXFont font = GetDrawFont(par,p);
296         if (IsFloatChar(ch)) {
297             // skip for now
298         } else if (par->IsNewline(p)) {
299                 // Draw end-of-line marker
300                 int wid = lyxfont::width('n', font);
301                 int asc = lyxfont::maxAscent(font);
302                 int y = baseline;
303                 int xp[3], yp[3];
304                 
305                 xp[0] = int(x + wid * 0.375);
306                 yp[0] = int(y - 0.875 * asc * 0.75);
307                 
308                 xp[1] = int(x);
309                 yp[1] = int(y - 0.500 * asc * 0.75);
310                 
311                 xp[2] = int(x + wid * 0.375);
312                 yp[2] = int(y - 0.125 * asc * 0.75);
313                 
314                 pain.lines(xp, yp, 3, LColor::eolmarker);
315                 
316                 xp[0] = int(x);
317                 yp[0] = int(y - 0.500 * asc * 0.75);
318                 
319                 xp[1] = int(x + wid);
320                 yp[1] = int(y - 0.500 * asc * 0.75);
321                 
322                 xp[2] = int(x + wid);
323                 yp[2] = int(y - asc * 0.75);
324                         
325                 pain.lines(xp, yp, 3, LColor::eolmarker);
326                 x += wid;
327         } else if (ch == LyXParagraph::META_INSET) {
328             Inset * tmpinset = par->GetInset(p);
329             if (tmpinset) 
330                 tmpinset->draw(pain, font, baseline, x);
331         } else {
332             pain.text(int(x), baseline, ch, font);
333             x += lyxfont::width(ch, font);
334         }
335     }
336 }
337
338
339 char const * InsetText::EditMessage() const
340 {
341     return _("Opened Text Inset");
342 }
343
344
345 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
346 {
347     par->SetInsetOwner(this);
348     UpdatableInset::Edit(bv, x, y, button);
349
350     if (!bv->lockInset(this)) {
351         lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
352         return;
353     }
354     the_locking_inset = 0;
355     inset_pos = inset_x = inset_y = 0;
356     setPos(bv->painter(), x, y);
357     checkAndActivateInset(bv, x, y, button);
358     selection_start_cursor = selection_end_cursor = cursor;
359     current_font = real_current_font = GetFont(par, cursor.pos);
360     bv->text->FinishUndo();
361     UpdateLocal(bv, true);
362 }
363
364
365 void InsetText::InsetUnlock(BufferView * bv)
366 {
367     if (the_locking_inset) {
368         the_locking_inset->InsetUnlock(bv);
369         the_locking_inset = 0;
370     }
371     HideInsetCursor(bv);
372     lyxerr[Debug::INSETS] << "InsetText::InsetUnlock(" << this <<
373             ")" << endl;
374     if (hasSelection()) {
375         selection_start_cursor = selection_end_cursor = cursor;
376         UpdateLocal(bv, false);
377     }
378     no_selection = false;
379 }
380
381
382 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
383 {
384     lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
385     if (!inset)
386         return false;
387     if (inset == par->GetInset(cursor.pos)) {
388         lyxerr[Debug::INSETS] << "OK" << endl;
389         the_locking_inset = inset;
390         resetPos(bv->painter());
391         inset_x = cursor.x - top_x + drawTextXOffset;
392         inset_y = cursor.y + drawTextYOffset;
393         inset_pos = cursor.pos;
394         return true;
395     } else if (the_locking_inset && (the_locking_inset == inset)) {
396         if (cursor.pos == inset_pos) {
397             lyxerr[Debug::INSETS] << "OK" << endl;
398             resetPos(bv->painter());
399             inset_x = cursor.x - top_x + drawTextXOffset;
400             inset_y = cursor.y + drawTextYOffset;
401         } else {
402             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
403         }
404     } else if (the_locking_inset) {
405         lyxerr[Debug::INSETS] << "MAYBE" << endl;
406         return the_locking_inset->LockInsetInInset(bv, inset);
407     }
408     lyxerr[Debug::INSETS] << "NOT OK" << endl;
409     return false;
410 }
411
412
413 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
414                                    bool lr)
415 {
416     if (!the_locking_inset)
417         return false;
418     if (the_locking_inset == inset) {
419         the_locking_inset->InsetUnlock(bv);
420         the_locking_inset = 0;
421         if (lr)
422             moveRight(bv, false);
423         return true;
424     }
425     return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
426 }
427
428
429 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
430 {
431     if (!the_locking_inset)
432         return false;
433     if (the_locking_inset != inset)
434         return the_locking_inset->UpdateInsetInInset(bv, inset);
435     lyxerr[Debug::INSETS] << "InsetText::UpdateInsetInInset(" << inset <<
436             ")" << endl;
437     UpdateLocal(bv, true);
438     if (cursor.pos == inset_pos) {
439         inset_x = cursor.x - top_x + drawTextXOffset;
440         inset_y = cursor.y + drawTextYOffset;
441     }
442     return true;
443 }
444
445
446 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
447 {
448     if (hasSelection()) {
449         selection_start_cursor = selection_end_cursor = cursor;
450         UpdateLocal(bv, false);
451     }
452     no_selection = false;
453     setPos(bv->painter(), x, y);
454     cursor.x_fix = -1;
455     if (the_locking_inset) {
456         UpdatableInset
457             *inset = 0;
458         if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET)
459             inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
460         if (the_locking_inset == inset) {
461             the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
462             return;
463         } else if (inset) {
464             // otherwise unlock the_locking_inset and lock the new inset
465             the_locking_inset->InsetUnlock(bv);
466             inset_x = cursor.x - top_x + drawTextXOffset;
467             inset_y = cursor.y + drawTextYOffset;
468             inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
469             inset->Edit(bv, x - inset_x, y - inset_y, button);
470             UpdateLocal(bv, true);
471             return;
472         }
473         // otherwise only unlock the_locking_inset
474         the_locking_inset->InsetUnlock(bv);
475         the_locking_inset = 0;
476     }
477     if (bv->the_locking_inset) {
478         if ((par->GetChar(cursor.pos) == LyXParagraph::META_INSET) &&
479             par->GetInset(cursor.pos) &&
480             (par->GetInset(cursor.pos)->Editable() == Inset::HIGHLY_EDITABLE)) {
481             UpdatableInset *inset =
482                 static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
483             inset_x = cursor.x - top_x + drawTextXOffset;
484             inset_y = cursor.y + drawTextYOffset;
485             inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
486             inset->Edit(bv, x-inset_x, y-inset_y, 0);
487             UpdateLocal(bv, true);
488         }
489     }
490     selection_start_cursor = selection_end_cursor = cursor;
491 }
492
493
494 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
495 {
496     UpdatableInset * inset = 0;
497
498     if (the_locking_inset) {
499             the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
500     } else {
501         if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
502             inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
503             if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
504                 inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
505             } else {
506                 inset_x = cursor.x - top_x + drawTextXOffset;
507                 inset_y = cursor.y + drawTextYOffset;
508                 inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
509                 inset->Edit(bv, x-inset_x, y-inset_y, button);
510             }
511         }
512     }
513     no_selection = false;
514 }
515
516
517 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
518 {
519     if (the_locking_inset) {
520         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
521                                              y - inset_y,state);
522         return;
523     }
524     if (!no_selection) {
525         LyXCursor old = selection_end_cursor;
526         HideInsetCursor(bv);
527         setPos(bv->painter(), x, y);
528         selection_end_cursor = cursor;
529         if (old != selection_end_cursor)
530             UpdateLocal(bv, false);
531         ShowInsetCursor(bv);
532     }
533     no_selection = false;
534 }
535
536
537 void InsetText::InsetKeyPress(XKeyEvent * xke)
538 {
539     if (the_locking_inset) {
540         the_locking_inset->InsetKeyPress(xke);
541         return;
542     }
543 }
544
545
546 UpdatableInset::RESULT
547 InsetText::LocalDispatch(BufferView * bv,
548                          int action, string const & arg)
549 {
550     no_selection = false;
551     UpdatableInset::RESULT
552         result= UpdatableInset::LocalDispatch(bv, action, arg);
553     if (result != UNDISPATCHED) {
554         resetPos(bv->painter());
555         return DISPATCHED;
556     }
557
558     result=DISPATCHED;
559     if ((action < 0) && arg.empty())
560         return FINISHED;
561
562     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
563         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
564         cursor.x_fix = -1;
565     if (the_locking_inset) {
566         result = the_locking_inset->LocalDispatch(bv, action, arg);
567         if (result == DISPATCHED_NOUPDATE)
568             return result;
569         else if (result == DISPATCHED) {
570             the_locking_inset->ToggleInsetCursor(bv);
571             UpdateLocal(bv, false);
572             the_locking_inset->ToggleInsetCursor(bv);
573             return result;
574         } else if (result == FINISHED) {
575             switch(action) {
576             case -1:
577             case LFUN_RIGHT:
578                 cursor.pos = inset_pos + 1;
579                 resetPos(bv->painter());
580                 break;
581             case LFUN_DOWN:
582                 moveDown(bv);
583                 break;
584             }
585             the_locking_inset = 0;
586             return DISPATCHED;
587         }
588     }
589     HideInsetCursor(bv);
590     switch (action) {
591         // Normal chars
592     case -1:
593         bv->text->SetUndo(Undo::INSERT, 
594             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
595             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
596         cutSelection();
597         cursor = selection_start_cursor;
598         par->InsertChar(cursor.pos,arg[0]);
599         SetCharFont(cursor.pos,current_font);
600         ++cursor.pos;
601         selection_start_cursor = selection_end_cursor = cursor;
602         UpdateLocal(bv, true);
603         break;
604         // --- Cursor Movements ---------------------------------------------
605     case LFUN_RIGHTSEL:
606         bv->text->FinishUndo();
607         moveRight(bv, false);
608         selection_end_cursor = cursor;
609         UpdateLocal(bv, false);
610         break;
611     case LFUN_RIGHT:
612         bv->text->FinishUndo();
613         result = moveRight(bv);
614         if (hasSelection()) {
615             selection_start_cursor = selection_end_cursor = cursor;
616             UpdateLocal(bv, false);
617         } else {
618             selection_start_cursor = selection_end_cursor = cursor;
619         }
620         break;
621     case LFUN_LEFTSEL:
622         bv->text->FinishUndo();
623         moveLeft(bv, false);
624         selection_end_cursor = cursor;
625         UpdateLocal(bv, false);
626         break;
627     case LFUN_LEFT:
628         bv->text->FinishUndo();
629         result= moveLeft(bv);
630         if (hasSelection()) {
631                 selection_start_cursor = selection_end_cursor = cursor;
632                 UpdateLocal(bv, false);
633         } else {
634                 selection_start_cursor = selection_end_cursor = cursor;
635         }
636         break;
637     case LFUN_DOWNSEL:
638         bv->text->FinishUndo();
639         moveDown(bv);
640         selection_end_cursor = cursor;
641         UpdateLocal(bv, false);
642         break;
643     case LFUN_DOWN:
644         bv->text->FinishUndo();
645         result = moveDown(bv);
646         if (hasSelection()) {
647             selection_start_cursor = selection_end_cursor = cursor;
648             UpdateLocal(bv, false);
649         } else {
650             selection_start_cursor = selection_end_cursor = cursor;
651         }
652         break;
653     case LFUN_UPSEL:
654         bv->text->FinishUndo();
655         moveUp(bv);
656         selection_end_cursor = cursor;
657         UpdateLocal(bv, false);
658         break;
659     case LFUN_UP:
660         bv->text->FinishUndo();
661         result = moveUp(bv);
662         if (hasSelection()) {
663             selection_start_cursor = selection_end_cursor = cursor;
664             UpdateLocal(bv, false);
665         } else {
666             selection_start_cursor = selection_end_cursor = cursor;
667         }
668         break;
669     case LFUN_BACKSPACE:
670         if (!cursor.pos) {
671             if (hasSelection()) {
672                 selection_start_cursor = selection_end_cursor = cursor;
673                 UpdateLocal(bv, false);
674             }
675             break;
676         }
677         moveLeft(bv);
678     case LFUN_DELETE:
679     {
680         bv->text->SetUndo(Undo::DELETE, 
681             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
682             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
683         bool ret = true;
684         if (hasSelection()) {
685             LyXParagraph::size_type i = selection_start_cursor.pos;
686             for (; i < selection_end_cursor.pos; ++i) {
687                 par->Erase(selection_start_cursor.pos);
688             }
689         } else
690             ret = Delete();
691         if (ret) { // we need update
692             selection_start_cursor = selection_end_cursor = cursor;
693             UpdateLocal(bv, true);
694         } else if (hasSelection()) {
695             selection_start_cursor = selection_end_cursor = cursor;
696             UpdateLocal(bv, false);
697         }
698     }
699     resetPos(bv->painter());
700     break;
701     case LFUN_CUT:
702         bv->text->SetUndo(Undo::DELETE, 
703           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
704           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
705
706         if (cutSelection()) {
707             // we need update
708             cursor = selection_end_cursor = selection_start_cursor;
709             UpdateLocal(bv, true);
710         } else if (hasSelection()) {
711             selection_start_cursor = selection_end_cursor = cursor;
712             UpdateLocal(bv, false);
713         }
714         resetPos(bv->painter());
715         break;
716     case LFUN_COPY:
717         bv->text->FinishUndo();
718         if (copySelection()) {
719             // we need update
720             selection_start_cursor = selection_end_cursor = cursor;
721             UpdateLocal(bv, true);
722         } else if (hasSelection()) {
723             selection_start_cursor = selection_end_cursor = cursor;
724             UpdateLocal(bv, false);
725         }
726         break;
727     case LFUN_PASTE:
728     {
729         bv->text->SetUndo(Undo::INSERT, 
730           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
731           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
732         if (pasteSelection()) {
733             selection_start_cursor = selection_end_cursor = cursor;
734             UpdateLocal(bv, true);
735         }
736     }
737     resetPos(bv->painter());
738     break;
739     case LFUN_HOME:
740         bv->text->FinishUndo();
741         for(; cursor.pos > rows[actrow].pos; --cursor.pos)
742             cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
743         cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
744         if (hasSelection()) {
745             selection_start_cursor = selection_end_cursor = cursor;
746             UpdateLocal(bv, false);
747         } else {
748             selection_start_cursor = selection_end_cursor = cursor;
749         }
750         resetPos(bv->painter());
751         break;
752     case LFUN_END:
753     {
754         bv->text->FinishUndo();
755         int checkpos = (int)rows[actrow + 1].pos;
756         if ((actrow + 2) < (int)rows.size())
757             --checkpos;
758         for(; cursor.pos < checkpos; ++cursor.pos)
759             cursor.x += SingleWidth(bv->painter(), par, cursor.pos);
760         if (hasSelection()) {
761             selection_start_cursor = selection_end_cursor = cursor;
762             UpdateLocal(bv, false);
763         } else {
764             selection_start_cursor = selection_end_cursor = cursor;
765         }
766     }
767     resetPos(bv->painter());
768     break;
769     case LFUN_MATH_MODE:
770         InsertInset(bv, new InsetFormula);
771         return DISPATCHED;
772     case LFUN_INSET_ERT:
773         InsertInset(bv, new InsetERT(buffer));
774         return DISPATCHED;
775     case LFUN_BREAKPARAGRAPH:
776     case LFUN_BREAKLINE:
777         if (!autoBreakRows)
778             return DISPATCHED;
779         bv->text->SetUndo(Undo::INSERT, 
780             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
781             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
782         par->InsertChar(cursor.pos,LyXParagraph::META_NEWLINE);
783         SetCharFont(cursor.pos,current_font);
784         UpdateLocal(bv, true);
785         ++cursor.pos;
786         selection_start_cursor = selection_end_cursor = cursor;
787         resetPos(bv->painter());
788         break;
789     case LFUN_LAYOUT:
790     {
791         // Derive layout number from given argument (string)
792         // and current buffer's textclass (number). */    
793         LyXTextClassList::ClassList::size_type tclass =
794             buffer->params.textclass;
795         std::pair <bool, LyXTextClass::size_type> layout = 
796             textclasslist.NumberOfLayout(tclass, arg);
797
798         // If the entry is obsolete, use the new one instead.
799         if (layout.first) {
800             string obs = textclasslist.Style(tclass,layout.second).
801                 obsoleted_by();
802             if (!obs.empty()) 
803                 layout = textclasslist.NumberOfLayout(tclass, obs);
804         }
805
806         // see if we found the layout number:
807         if (!layout.first) {
808             string msg = string(N_("Layout ")) + arg + N_(" not known");
809
810             bv->owner()->getMiniBuffer()->Set(msg);
811             break;
812         }
813
814         if (current_layout != layout.second) {
815             bv->text->SetLayout(cursor, selection_start_cursor,
816                                 selection_end_cursor, layout.second);
817             bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1);
818             UpdateLocal(bv, true);
819         }
820     }
821     break;
822     default:
823         result = UNDISPATCHED;
824         break;
825     }
826     if (result != FINISHED) {
827         ShowInsetCursor(bv);
828     } else
829         bv->unlockInset(this);
830     return result;
831 }
832
833
834 int InsetText::Latex(ostream & os, bool /*fragile*/, bool /*fp*/) const
835 {
836     TexRow texrow;
837     buffer->latexParagraphs(os, par, 0, texrow);
838     return texrow.rows();
839 }
840
841
842 void InsetText::Validate(LaTeXFeatures & features) const
843 {
844     par->validate(features);
845 }
846
847
848 // Returns the width of a character at a certain spot
849 int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
850 {
851     LyXFont font = GetDrawFont(par, pos);
852     char c = par->GetChar(pos);
853
854     if (IsPrintable(c)) {
855         return lyxfont::width(c, font);
856     } else if (c == LyXParagraph::META_INSET) {
857         Inset const * tmpinset = par->GetInset(pos);
858         if (tmpinset)
859             return tmpinset->width(pain, font);
860         else
861             return 0;
862     } else if (IsSeparatorChar(c))
863         c = ' ';
864     else if (IsNewlineChar(c))
865         c = 'n';
866     return lyxfont::width(c, font);
867 }
868
869
870 // Returns the width of a character at a certain spot
871 void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos,
872                              int & asc, int & desc) const
873 {
874     LyXFont font = GetDrawFont(par, pos);
875     char c = par->GetChar(pos);
876
877     asc = desc = 0;
878     if (c == LyXParagraph::META_INSET) {
879         Inset const * tmpinset=par->GetInset(pos);
880         if (tmpinset) {
881             asc = tmpinset->ascent(pain, font);
882             desc = tmpinset->descent(pain, font);
883         }
884     } else {
885         asc = lyxfont::maxAscent(font);
886         desc = lyxfont::maxDescent(font);
887     }
888     return;
889 }
890
891
892 // Gets the fully instantiated font at a given position in a paragraph
893 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
894 // The difference is that this one is used for displaying, and thus we
895 // are allowed to make cosmetic improvements. For instance make footnotes
896 // smaller. (Asger)
897 // If position is -1, we get the layout font of the paragraph.
898 // If position is -2, we get the font of the manual label of the paragraph.
899 LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
900 {
901     char par_depth = par->GetDepth();
902
903     LyXLayout const & layout =
904             textclasslist.Style(buffer->params.textclass, par->GetLayout());
905
906     // We specialize the 95% common case:
907     if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
908         if (pos >= 0) {
909             // 95% goes here
910             if (layout.labeltype == LABEL_MANUAL
911                 && pos < BeginningOfMainBody(par)) {
912                 // 1% goes here
913                 return par->GetFontSettings(pos).realize(layout.reslabelfont);
914             } else
915                 return par->GetFontSettings(pos).realize(layout.resfont);
916         } else {
917             // 5% goes here.
918             // process layoutfont for pos == -1 and labelfont for pos < -1
919             if (pos == -1)
920                 return layout.resfont;
921             else
922                 return layout.reslabelfont;
923         }
924     }
925     // The uncommon case need not be optimized as much
926
927     LyXFont layoutfont, tmpfont;
928
929     if (pos >= 0){
930         // 95% goes here
931         if (pos < BeginningOfMainBody(par)) {
932             // 1% goes here
933             layoutfont = layout.labelfont;
934         } else {
935             // 99% goes here
936             layoutfont = layout.font;
937         }
938         tmpfont = par->GetFontSettings(pos);
939         tmpfont.realize(layoutfont);
940     } else{
941         // 5% goes here.
942         // process layoutfont for pos == -1 and labelfont for pos < -1
943         if (pos == -1)
944             tmpfont = layout.font;
945         else
946             tmpfont = layout.labelfont;
947     }
948     
949     // Resolve against environment font information
950     //if (par->GetDepth()){ // already in while condition
951     while (par && par_depth && !tmpfont.resolved()) {
952         par = par->DepthHook(par_depth - 1);
953         if (par) {
954             tmpfont.realize(textclasslist.Style(buffer->params.textclass,
955                                                 par->GetLayout()).font);
956             par_depth = par->GetDepth();
957         }
958     }
959     tmpfont.realize((textclasslist.TextClass(buffer->params.textclass).
960                     defaultfont()));
961     return tmpfont;
962 }
963
964
965 // the font for drawing may be different from the real font
966 LyXFont InsetText::GetDrawFont(LyXParagraph * par, int pos) const
967 {
968     return GetFont(par, pos);
969 }
970
971
972 int InsetText::BeginningOfMainBody(LyXParagraph * par) const
973 {
974     if (textclasslist.Style(buffer->params.textclass,
975                        par->GetLayout()).labeltype != LABEL_MANUAL)
976         return 0;
977     else
978         return par->BeginningOfMainBody();
979 }
980
981
982 void InsetText::GetCursorPos(int & x, int & y) const
983 {
984     x = cursor.x;
985     y = cursor.y;
986 }
987
988
989 int InsetText::InsetInInsetY()
990 {
991     if (!the_locking_inset)
992         return 0;
993
994     return (inset_y + the_locking_inset->InsetInInsetY());
995 }
996
997
998 void InsetText::ToggleInsetCursor(BufferView * bv)
999 {
1000     if (the_locking_inset) {
1001         the_locking_inset->ToggleInsetCursor(bv);
1002         return;
1003     }
1004
1005     LyXFont font = GetDrawFont(par, cursor.pos);
1006
1007     int asc = lyxfont::maxAscent(font);
1008     int desc = lyxfont::maxDescent(font);
1009   
1010     if (cursor_visible)
1011         bv->hideLockedInsetCursor();
1012     else
1013         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
1014     cursor_visible = !cursor_visible;
1015 }
1016
1017
1018 void InsetText::ShowInsetCursor(BufferView * bv)
1019 {
1020     if (the_locking_inset) {
1021         the_locking_inset->ShowInsetCursor(bv);
1022         return;
1023     }
1024     if (!cursor_visible) {
1025         LyXFont font = GetDrawFont(par, cursor.pos);
1026         
1027         int asc = lyxfont::maxAscent(font);
1028         int desc = lyxfont::maxDescent(font);
1029         bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc);
1030         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
1031         cursor_visible = true;
1032     }
1033 }
1034
1035
1036 void InsetText::HideInsetCursor(BufferView * bv)
1037 {
1038     if (cursor_visible) {
1039         bv->hideLockedInsetCursor();
1040         cursor_visible = false;
1041     }
1042     if (the_locking_inset)
1043         the_locking_inset->HideInsetCursor(bv);
1044 }
1045
1046
1047 void InsetText::setPos(Painter & pain, int x, int y) const
1048 {
1049     x -= drawTextXOffset;
1050     y -= drawTextYOffset;
1051     // search right X-pos x==0 -> top_x
1052     cursor.pos = actrow = 0;
1053     cursor.y = top_baseline;
1054     y += cursor.y;
1055     for(unsigned int i = 1;
1056         (long(cursor.y + rows[i - 1].desc) < y)
1057                 && (i < rows.size() - 1); ++i) {
1058         cursor.y = rows[i].baseline;
1059         cursor.pos = rows[i].pos;
1060         actrow = i;
1061     }
1062     cursor.y -= top_baseline;
1063     cursor.x = top_x;
1064     x += top_x;
1065
1066     int swh;
1067     int sw = swh = SingleWidth(pain, par,cursor.pos);
1068     if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
1069         swh /= 2;
1070     int checkpos = rows[actrow + 1].pos;
1071     if ((actrow+2) < (int)rows.size())
1072         --checkpos;
1073     while ((cursor.pos < checkpos) && ((cursor.x + swh) < x)) {
1074         cursor.x += sw;
1075         ++cursor.pos;
1076         sw = swh = SingleWidth(pain, par,cursor.pos);
1077         if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
1078             swh /= 2;
1079     }
1080 }
1081
1082
1083 void InsetText::resetPos(Painter & pain) const
1084 {
1085     cursor.par = par;
1086
1087     if (!rows.size())
1088         return;
1089
1090     int old_pos = cursor.pos;
1091
1092     cursor.y = top_baseline;
1093     actrow = 0;
1094     for(unsigned int i = 0;
1095         (i < (rows.size()-1)) && (rows[i].pos <= cursor.pos);
1096         ++i) {
1097         cursor.y = rows[i].baseline;
1098         actrow = i;
1099     }
1100     cursor.y -= top_baseline;
1101     setPos(pain, 0, cursor.y);
1102     cursor.x = top_x;
1103     while(cursor.pos < old_pos) {
1104         cursor.x += SingleWidth(pain, par,cursor.pos);
1105         ++cursor.pos;
1106     }
1107 }
1108
1109
1110 UpdatableInset::RESULT
1111 InsetText::moveRight(BufferView * bv, bool activate_inset)
1112 {
1113     if (cursor.pos >= par->Last())
1114         return FINISHED;
1115     if (activate_inset && checkAndActivateInset(bv)) {
1116         return DISPATCHED;
1117     }
1118     ++cursor.pos;
1119     resetPos(bv->painter());
1120     real_current_font = current_font = GetFont(par, cursor.pos);
1121     return DISPATCHED_NOUPDATE;
1122 }
1123
1124
1125 UpdatableInset::RESULT
1126 InsetText::moveLeft(BufferView * bv, bool activate_inset)
1127 {
1128     if (cursor.pos <= 0)
1129         return FINISHED;
1130     --cursor.pos;
1131     resetPos(bv->painter());
1132     if (activate_inset)
1133         if (checkAndActivateInset(bv, -1, -1))
1134             return DISPATCHED;
1135     return DISPATCHED_NOUPDATE;
1136 }
1137
1138
1139 UpdatableInset::RESULT
1140 InsetText::moveUp(BufferView * bv)
1141 {
1142     if (!actrow)
1143         return FINISHED;
1144     cursor.y = rows[actrow - 1].baseline - top_baseline;
1145     if (cursor.x_fix < 0)
1146         cursor.x_fix = cursor.x;
1147     setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
1148     return DISPATCHED_NOUPDATE;
1149 }
1150
1151
1152 UpdatableInset::RESULT
1153 InsetText::moveDown(BufferView * bv)
1154 {
1155     if (actrow >= int(rows.size() - 2))
1156         return FINISHED;
1157     cursor.y = rows[actrow + 1].baseline - top_baseline;
1158     if (cursor.x_fix < 0)
1159         cursor.x_fix = cursor.x;
1160     setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
1161     return DISPATCHED_NOUPDATE;
1162 }
1163
1164
1165 bool InsetText::Delete()
1166 {
1167     if ((par->GetChar(cursor.pos)==LyXParagraph::META_INSET) &&
1168         !par->GetInset(cursor.pos)->Deletable()) {
1169         return false;
1170     }
1171     par->Erase(cursor.pos);
1172     return true;
1173 }
1174
1175
1176 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1177 {
1178     bv->text->SetUndo(Undo::INSERT, 
1179               bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
1180               bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
1181     if (inset->Editable() == Inset::IS_EDITABLE) {
1182         UpdatableInset *i = (UpdatableInset *)inset;
1183         i->setOwner((UpdatableInset *)this);
1184     }
1185     par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1186     par->InsertInset(cursor.pos, inset);
1187     if (hasSelection()) {
1188         selection_start_cursor = selection_end_cursor = cursor;
1189     } else {
1190         selection_start_cursor = selection_end_cursor = cursor;
1191     }
1192     UpdateLocal(bv, true);
1193     static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
1194     return true;
1195 }
1196
1197
1198 UpdatableInset * InsetText::GetLockingInset()
1199 {
1200     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1201 }
1202
1203
1204 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1205 {
1206     // if there is no selection just set the current_font
1207     if (!hasSelection()) {
1208         // Determine basis font
1209         LyXFont layoutfont;
1210         if (cursor.pos < BeginningOfMainBody(par))
1211             layoutfont = GetFont(par, -2);
1212         else
1213             layoutfont = GetFont(par, -1);
1214         
1215         // Update current font
1216         real_current_font.update(font, bv->buffer()->params.language_info,
1217                                  toggleall);
1218         
1219         // Reduce to implicit settings
1220         current_font = real_current_font;
1221         current_font.reduce(layoutfont);
1222         // And resolve it completely
1223         real_current_font.realize(layoutfont);
1224         return;
1225     }
1226     
1227     int s_start, s_end;
1228     if (selection_start_cursor.pos > selection_end_cursor.pos) {
1229         s_start = selection_end_cursor.pos;
1230         s_end = selection_start_cursor.pos;
1231     } else {
1232         s_start = selection_start_cursor.pos;
1233         s_end = selection_end_cursor.pos;
1234     }
1235     LyXFont newfont;
1236     while(s_start < s_end) {
1237         newfont = GetFont(par,s_start);
1238         newfont.update(font, bv->buffer()->params.language_info, toggleall);
1239         SetCharFont(s_start, newfont);
1240         ++s_start;
1241     }
1242     UpdateLocal(bv, true);
1243 }
1244
1245
1246 void InsetText::SetCharFont(int pos, LyXFont const & f)
1247 {
1248     /* let the insets convert their font */
1249         LyXFont font(f);
1250         
1251     if (par->GetChar(pos) == LyXParagraph::META_INSET) {
1252         if (par->GetInset(pos))
1253             font = par->GetInset(pos)->ConvertFont(font);
1254     }
1255     LyXLayout const & layout =
1256             textclasslist.Style(buffer->params.textclass,par->GetLayout());
1257
1258     // Get concrete layout font to reduce against
1259     LyXFont layoutfont;
1260
1261     if (pos < BeginningOfMainBody(par))
1262         layoutfont = layout.labelfont;
1263     else
1264         layoutfont = layout.font;
1265
1266
1267     layoutfont.realize((textclasslist.TextClass(buffer->params.textclass).
1268                        defaultfont()));
1269
1270     // Now, reduce font against full layout font
1271     font.reduce(layoutfont);
1272
1273     par->SetFont(pos, font);
1274 }
1275
1276
1277 void InsetText::computeTextRows(Painter & pain, float x) const
1278 {
1279     int p,
1280         nwp = 0,
1281         asc = 0,
1282         desc = 0,
1283         oasc = 0,
1284         odesc = 0,
1285         owidth = 0,
1286         wordAscent,
1287         wordDescent;
1288     row_struct row;
1289
1290     if (rows.size())
1291             rows.clear();
1292     int width = wordAscent = wordDescent = 0;
1293     insetWidth = maxAscent = maxDescent = 0;
1294     row.asc      = 0;
1295     row.desc     = 0;
1296     row.pos      = 0;
1297     row.baseline = 0;
1298     rows.push_back(row);
1299     if (!autoBreakRows) {
1300         for(p = 0; p < par->Last(); ++p) {
1301             insetWidth += SingleWidth(pain, par, p);
1302             SingleHeight(pain, par, p, asc, desc);
1303             maxAscent = max(maxAscent, asc);
1304             maxDescent = max(maxDescent, desc);
1305         }
1306         rows[0].asc = maxAscent;
1307         rows[0].desc = maxDescent;
1308         // alocate a dummy row for the endpos
1309         row.pos = par->Last();
1310         rows.push_back(row);
1311         return;
1312     }
1313
1314     bool is_first_word_in_row = true;
1315     int cw, lastWordWidth = 0;
1316     int maxWidth = getMaxTextWidth(pain, this, x);
1317
1318     for(p = 0; p < par->Last(); ++p) {
1319         cw = SingleWidth(pain, par, p);
1320         width += cw;
1321         lastWordWidth += cw;
1322         SingleHeight(pain, par, p, asc, desc);
1323         wordAscent = max(wordAscent, asc);
1324         wordDescent = max(wordDescent, desc);
1325         if (par->IsNewline(p)) {
1326             if (!is_first_word_in_row && (width >= maxWidth)) {
1327                 // we have to split also the row above
1328                 rows.back().asc = oasc;
1329                 rows.back().desc = odesc;
1330                 row.pos = nwp;
1331                 rows.push_back(row);
1332                 oasc = wordAscent;
1333                 odesc = wordDescent;
1334                 insetWidth = max(insetWidth, owidth);
1335                 width = lastWordWidth;
1336                 lastWordWidth = 0;
1337             }
1338             rows.back().asc = wordAscent;
1339             rows.back().desc = wordDescent;
1340             row.pos = ++p;
1341             rows.push_back(row);
1342             SingleHeight(pain, par, p, oasc, odesc);
1343             insetWidth = max(insetWidth, owidth);
1344             width = 0;
1345             is_first_word_in_row = true;
1346             wordAscent = wordDescent = lastWordWidth = 0;
1347             nwp = p;
1348             continue;
1349         }
1350         Inset * inset = 0;
1351         if (((p + 1) < par->Last()) &&
1352             (par->GetChar(p + 1)==LyXParagraph::META_INSET))
1353             inset = par->GetInset(p + 1);
1354         if (inset) {
1355                 inset->setOwner(const_cast<InsetText*>(this)); // is this safe?
1356             if (inset->display()) {
1357                 if (!is_first_word_in_row && (width >= maxWidth)) {
1358                     // we have to split also the row above
1359                     rows.back().asc = oasc;
1360                     rows.back().desc = odesc;
1361                     row.pos = nwp;
1362                     rows.push_back(row);
1363                     oasc = wordAscent;
1364                     odesc = wordDescent;
1365                     insetWidth = max(insetWidth, owidth);
1366                     width = lastWordWidth;
1367                     lastWordWidth = 0;
1368                 } else {
1369                     oasc = max(oasc, wordAscent);
1370                     odesc = max(odesc, wordDescent);
1371                 }
1372                 rows.back().asc = oasc;
1373                 rows.back().desc = odesc;
1374                 row.pos = ++p;
1375                 rows.push_back(row);
1376                 SingleHeight(pain, par, p, asc, desc);
1377                 rows.back().asc = asc;
1378                 rows.back().desc = desc;
1379                 row.pos = nwp = p + 1;
1380                 rows.push_back(row);
1381                 oasc = odesc = width = lastWordWidth = 0;
1382                 is_first_word_in_row = true;
1383                 wordAscent = wordDescent = 0;
1384                 continue;
1385             }
1386         } else if (par->IsSeparator(p)) {
1387             if (width >= maxWidth) {
1388                 if (is_first_word_in_row) {
1389                     rows.back().asc = wordAscent;
1390                     rows.back().desc = wordDescent;
1391                     row.pos = p + 1;
1392                     rows.push_back(row);
1393                     oasc = odesc = width = 0;
1394                 } else {
1395                     rows.back().asc = oasc;
1396                     rows.back().desc = odesc;
1397                     row.pos = nwp;
1398                     rows.push_back(row);
1399                     oasc = wordAscent;
1400                     odesc = wordDescent;
1401                     insetWidth = max(insetWidth, owidth);
1402                     width = lastWordWidth;
1403                 }
1404                 wordAscent = wordDescent = lastWordWidth = 0;
1405                 nwp = p + 1;
1406                 continue;
1407             }
1408             owidth = width;
1409             oasc = max(oasc, wordAscent);
1410             odesc = max(odesc, wordDescent);
1411             wordAscent = wordDescent = lastWordWidth = 0;
1412             nwp = p + 1;
1413             is_first_word_in_row = false;
1414         }
1415     }
1416     // if we have some data in the paragraph we have ascent/descent
1417     if (p) {
1418         if (width >= maxWidth) {
1419             // assign upper row
1420             rows.back().asc = oasc;
1421             rows.back().desc = odesc;
1422             // assign and allocate lower row
1423             row.pos = nwp;
1424             rows.push_back(row);
1425             rows.back().asc = wordAscent;
1426             rows.back().desc = wordDescent;
1427             width -= lastWordWidth;
1428         } else {
1429             // assign last row data
1430             rows.back().asc = max(oasc, wordAscent);
1431             rows.back().desc = max(odesc, wordDescent);
1432         }
1433     }
1434     insetWidth = max(insetWidth, width);
1435     // alocate a dummy row for the endpos
1436     row.pos = par->Last();
1437     rows.push_back(row);
1438     // calculate maxAscent/Descent
1439     maxAscent = rows[0].asc;
1440     maxDescent = rows[0].desc;
1441     for (RowList::size_type i = 1; i < rows.size() - 1; ++i) {
1442         maxDescent += rows[i].asc + rows[i].desc + interline_space;
1443     }
1444 }
1445
1446
1447 void InsetText::computeBaselines(int baseline) const
1448 {
1449     rows[0].baseline = baseline;
1450     for (unsigned int i = 1; i < rows.size() - 1; i++) {
1451         rows[i].baseline = rows[i - 1].baseline + rows[i - 1].desc + 
1452             rows[i].asc + interline_space;
1453     }
1454 }
1455
1456
1457 void InsetText::UpdateLocal(BufferView * bv, bool flag)
1458 {
1459     if (flag) {
1460         computeTextRows(bv->painter(), xpos);
1461         computeBaselines(top_baseline);
1462     }
1463     bv->updateInset(this, flag);
1464     if (flag)
1465         resetPos(bv->painter());
1466     bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1);
1467 }
1468
1469
1470 bool InsetText::cutSelection()
1471 {
1472     if (!hasSelection())
1473         return false;
1474
1475     CutAndPaste cap;
1476
1477     LyXParagraph * endpar = par;
1478     int start, end;
1479     if (selection_start_cursor.pos > selection_end_cursor.pos) {
1480             start = selection_end_cursor.pos;
1481             end = selection_start_cursor.pos;
1482     } else {
1483             start = selection_start_cursor.pos;
1484             end = selection_end_cursor.pos;
1485     }
1486
1487     return cap.cutSelection(par, &endpar, start, end,buffer->params.textclass);
1488 }
1489
1490
1491 bool InsetText::copySelection()
1492 {
1493     if (!hasSelection())
1494         return false;
1495
1496     CutAndPaste cap;
1497
1498     int start, end;
1499     if (selection_start_cursor.pos > selection_end_cursor.pos) {
1500             start = selection_end_cursor.pos;
1501             end = selection_start_cursor.pos;
1502     } else {
1503             start = selection_start_cursor.pos;
1504             end = selection_end_cursor.pos;
1505     }
1506     return cap.copySelection(par, par, start, end, buffer->params.textclass);
1507 }
1508
1509
1510 bool InsetText::pasteSelection()
1511 {
1512     CutAndPaste cap;
1513
1514     if (cap.nrOfParagraphs() > 1) {
1515         WriteAlert(_("Impossible operation"),
1516                    _("Cannot include more than one paragraph!"),
1517                    _("Sorry."));
1518         return false;
1519     }
1520     LyXParagraph *endpar;
1521     LyXParagraph *actpar = par;
1522
1523     return cap.pasteSelection(&actpar, &endpar, cursor.pos,
1524                               buffer->params.textclass);
1525 }
1526
1527
1528 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1529                                       int button)
1530 {
1531     if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
1532         UpdatableInset * inset =
1533             static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
1534         LyXFont font = GetFont(par, cursor.pos);
1535         if (x < 0)
1536             x = inset->width(bv->painter(), font);
1537         if (y < 0)
1538             y = inset->descent(bv->painter(), font);
1539         inset_x = cursor.x - top_x + drawTextXOffset;
1540         inset_y = cursor.y + drawTextYOffset;
1541         inset->Edit(bv, x-inset_x, y-inset_y, button);
1542         if (!the_locking_inset)
1543             return false;
1544         UpdateLocal(bv, true);
1545         return true;
1546     }
1547     return false;
1548 }
1549
1550
1551 int InsetText::getMaxTextWidth(Painter & pain, UpdatableInset const * inset,
1552                                int x) const
1553 {
1554     return getMaxWidth(pain, inset) - x;
1555 }
1556
1557 void InsetText::SetParagraphData(LyXParagraph *p)
1558 {
1559     if (par)
1560         delete par;
1561     par = p->Clone();
1562     par->SetInsetOwner(this);
1563     init_inset = true;
1564 }