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