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