]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
6ec23b24d5eb782a82224f1ab9f53a2cb95b721c
[lyx.git] / src / insets / insettext.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ======================================================
4  * 
5  *           LyX, The Document Processor
6  *
7  *           Copyright 1998-2000 The LyX Team.
8  *
9  * ======================================================
10  */
11
12 #include <config.h>
13
14 #include <fstream>
15 #include <algorithm>
16
17 #include <cstdlib>
18
19 #ifdef __GNUG__
20 #pragma implementation
21 #endif
22
23 #include "insettext.h"
24 #include "lyxparagraph.h"
25 #include "lyxlex.h"
26 #include "debug.h"
27 #include "lyxfont.h"
28 #include "commandtags.h"
29 #include "buffer.h"
30 #include "LyXView.h"
31 #include "BufferView.h"
32 #include "layout.h"
33 #include "LaTeXFeatures.h"
34 #include "Painter.h"
35 #include "lyx_gui_misc.h"
36 #include "lyxtext.h"
37 #include "lyxcursor.h"
38 #include "CutAndPaste.h"
39 #include "font.h"
40 #include "minibuffer.h"
41 #include "LColor.h"
42 #include "support/textutils.h"
43 #include "support/LAssert.h"
44 #include "lyxrow.h"
45 #include "lyxrc.h"
46 #include "intl.h"
47 #include "trans_mgr.h"
48 #include "lyxscreen.h"
49 #include "WorkArea.h"
50
51 using std::ostream;
52 using std::ifstream;
53 using std::endl;
54 using std::min;
55 using std::max;
56
57 extern unsigned char getCurrentTextClass(Buffer *);
58 extern bool math_insert_greek(BufferView *, char);
59 extern int greek_kb_flag;
60
61 InsetText::InsetText()
62 {
63         par = new LyXParagraph();
64         init();
65 }
66
67
68 InsetText::InsetText(InsetText const & ins)
69         : UpdatableInset()
70 {
71         par = 0;
72         init(&ins);
73         autoBreakRows = ins.autoBreakRows;
74 }
75
76
77 InsetText & InsetText::operator=(InsetText const & it)
78 {
79         init(&it);
80         autoBreakRows = it.autoBreakRows;
81         return * this;
82 }
83
84
85 void InsetText::init(InsetText const * ins)
86 {
87         top_y = 0;
88         last_width = 0;
89         last_height = 0;
90         insetAscent = 0;
91         insetDescent = 0;
92         insetWidth = 0;
93         the_locking_inset = 0;
94         cursor_visible = false;
95         interline_space = 1;
96         no_selection = false;
97         need_update = INIT;
98         drawTextXOffset = 0;
99         drawTextYOffset = 0;
100         autoBreakRows = false;
101         drawFrame = NEVER;
102         xpos = 0.0;
103         if (ins) {
104         SetParagraphData(ins->par);
105         autoBreakRows = ins->autoBreakRows;
106         drawFrame = ins->drawFrame;
107         }
108         par->SetInsetOwner(this);
109         frame_color = LColor::insetframe;
110         locked = false;
111         old_par = 0;
112         last_drawn_width = -1;
113 }
114
115
116 InsetText::~InsetText()
117 {
118         // delete all instances of LyXText before deleting the paragraps used
119         // by it.
120         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit){
121         delete (*cit).second;
122         (*cit).second = 0;
123         }
124 #ifndef NEW_INSETS
125         LyXParagraph * p = par->next_;
126         delete par;
127         while(p) {
128         par = p;
129         p = p->next_;
130         delete par;
131         }
132 #else
133         LyXParagraph * p = par->next();
134         delete par;
135         while(p) {
136         par = p;
137         p = p->next();
138         delete par;
139         }
140 #endif
141 }
142
143
144 void InsetText::clear()
145 {
146         // delete all instances of LyXText before deleting the paragraps used
147         // by it.
148         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit){
149                 delete (*cit).second;
150                 (*cit).second = 0;
151         }
152 #ifndef NEW_INSETS
153         LyXParagraph * p = par->next_;
154         delete par;
155         while(p) {
156                 par = p;
157                 p = p->next_;
158                 delete par;
159         }
160 #else
161         LyXParagraph * p = par->next();
162         delete par;
163         while(p) {
164                 par = p;
165                 p = p->next();
166                 delete par;
167         }
168 #endif
169         par = new LyXParagraph();
170 }
171
172
173 Inset * InsetText::Clone(Buffer const &) const
174 {
175         InsetText * t = new InsetText(*this);
176         return t;
177 }
178
179
180 void InsetText::Write(Buffer const * buf, ostream & os) const
181 {
182         os << "Text\n";
183         WriteParagraphData(buf, os);
184 }
185
186
187 void InsetText::WriteParagraphData(Buffer const * buf, ostream & os) const
188 {
189         par->writeFile(buf, os, buf->params, 0, 0);
190 }
191
192
193 void InsetText::Read(Buffer const * buf, LyXLex & lex)
194 {
195         string token;
196         int pos = 0;
197         LyXParagraph * return_par = 0;
198         char depth = 0; // signed or unsigned?
199 #ifndef NEW_INSETS
200         LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
201         LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
202 #endif
203         LyXFont font(LyXFont::ALL_INHERIT);
204
205         // delete all instances of LyXText before deleting the paragraps used
206         // by it.
207         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit) {
208                 delete (*cit).second;
209                 (*cit).second = 0;
210         }
211
212 #ifndef NEW_INSETS
213         LyXParagraph * p = par->next_;
214         delete par;
215         while(p) {
216                 par = p;
217                 p = p->next_;
218                 delete par;
219         }
220 #else
221         LyXParagraph * p = par->next();
222         delete par;
223         while(p) {
224                 par = p;
225                 p = p->next();
226                 delete par;
227         }
228 #endif
229         par = new LyXParagraph;
230         while (lex.IsOK()) {
231                 lex.nextToken();
232                 token = lex.GetString();
233                 if (token.empty())
234                         continue;
235                 if (token == "\\end_inset")
236                         break;
237                 if (const_cast<Buffer*>(buf)->
238                         parseSingleLyXformat2Token(lex, par, return_par,token, pos, depth,
239                                                                            font
240 #ifndef NEW_INSETS
241                                                                            , footnoteflag, footnotekind
242 #endif
243                                                                            ))
244                 {
245                         // the_end read this should NEVER happen
246                         lex.printError("\\the_end read in inset! Error in document!");
247                         return;
248                 }
249         }
250         if (!return_par)
251                 return_par = par;
252         par = return_par;
253         while(return_par) {
254                 return_par->SetInsetOwner(this);
255 #ifndef NEW_INSETS
256                 return_par = return_par->next_;
257 #else
258                 return_par = return_par->next();
259 #endif
260         }
261         
262         if (token != "\\end_inset") {
263                 lex.printError("Missing \\end_inset at this point. "
264                                            "Read: `$$Token'");
265         }
266         need_update = INIT;
267 }
268
269
270 int InsetText::ascent(BufferView * bv, LyXFont const &) const
271 {
272         int y_temp = 0;
273         Row * row = TEXT(bv)->GetRowNearY(y_temp);
274         insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
275         return insetAscent;
276 }
277
278
279 int InsetText::descent(BufferView * bv, LyXFont const &) const
280 {
281         int y_temp = 0;
282         Row * row = TEXT(bv)->GetRowNearY(y_temp);
283         insetDescent = TEXT(bv)->height - row->ascent_of_text() +
284         TEXT_TO_INSET_OFFSET;
285         return insetDescent;
286 }
287
288
289 int InsetText::width(BufferView * bv, LyXFont const &) const
290 {
291         insetWidth = max(textWidth(bv),
292                          (int)TEXT(bv)->width + (2 * TEXT_TO_INSET_OFFSET));
293         return insetWidth;
294 }
295
296
297 int InsetText::textWidth(BufferView * bv) const
298 {
299         int const w = getMaxWidth(bv, this);
300         return w;
301 }
302
303
304 void InsetText::draw(BufferView * bv, LyXFont const & f,
305                          int baseline, float & x, bool cleared) const
306 {
307         Painter & pain = bv->painter();
308
309         // no draw is necessary !!!
310         if ((drawFrame == LOCKED) && !locked && !par->size()) {
311                 if (!cleared && (need_update & CLEAR_FRAME)) {
312                         pain.rectangle(top_x + 1, baseline - insetAscent + 1,
313                                                    width(bv, f) - 1,
314                                                    insetAscent + insetDescent - 1,
315                                                    LColor::background);
316                 }
317                 top_x = int(x);
318                 top_baseline = baseline;
319                 x += width(bv, f);
320                 need_update = NONE;
321                 return;
322         }
323
324         xpos = x;
325         UpdatableInset::draw(bv, f, baseline, x, cleared);
326
327         // update insetWidth and insetHeight with dummy calls
328         (void)ascent(bv, f);
329         (void)descent(bv, f);
330         (void)width(bv, f);
331
332         // if top_x differs we have a rule down and we don't have to clear anything
333         if (!cleared && (top_x == int(x)) &&
334                 ((need_update==INIT)||(need_update==FULL)||(top_baseline!=baseline) ||
335                  (last_drawn_width!=insetWidth)))
336         {
337                 int w =  insetWidth;
338                 int h = insetAscent + insetDescent;
339                 int ty = baseline - insetAscent;
340         
341                 if (ty < 0) {
342                         h += ty;
343                         ty = 0;
344                 }
345                 if ((ty + h) > pain.paperHeight())
346                         h = pain.paperHeight();
347                 if ((top_x + drawTextXOffset + w) > pain.paperWidth())
348                         w = pain.paperWidth();
349                 pain.fillRectangle(top_x+drawTextXOffset, ty, w, h);
350                 cleared = true;
351                 need_update = FULL;
352         }
353         if (!cleared && (need_update == NONE))
354                 return;
355
356         if (top_x != int(x)) {
357                 need_update = INIT;
358                 top_x = int(x);
359                 bv->text->status = LyXText::CHANGED_IN_DRAW;
360                 return;
361         }
362         if (cleared || (last_drawn_width != insetWidth)) {
363                 need_update |= FULL;
364                 last_drawn_width = insetWidth;
365         }
366
367         top_baseline = baseline;
368         top_y = baseline - ascent(bv, f);
369         last_width = width(bv, f);
370         last_height = ascent(bv, f) + descent(bv, f);
371
372         if (the_locking_inset && (cpar(bv) == inset_par) && (cpos(bv) == inset_pos)) {
373                 inset_x = cx(bv) - top_x + drawTextXOffset;
374                 inset_y = cy(bv) + drawTextYOffset;
375         }
376         if (!cleared && (need_update == CURSOR) && !TEXT(bv)->selection) {
377                 x += width(bv, f);
378                 need_update = NONE;
379                 return;
380         }
381         x += TEXT_TO_INSET_OFFSET;
382         {
383         int y = 0;
384         Row * row = TEXT(bv)->GetRowNearY(y);
385         int y_offset = baseline - row->ascent_of_text();
386         int ph = pain.paperHeight();
387         int first = 0;
388         y = y_offset;
389         while ((row != 0) && ((y+row->height()) <= 0)) {
390                 y += row->height();
391                 first += row->height();
392                 row = row->next();
393         }
394         if (y_offset < 0)
395                 y_offset = y;
396         TEXT(bv)->first = first;
397         if (cleared) { // (need_update&FULL) || (need_update&INIT)
398                 int yf = y_offset;
399                 y = 0;
400                 while ((row != 0) && (yf < ph)) {
401                         TEXT(bv)->GetVisibleRow(bv, y+y_offset, int(x), row,
402                                                 y+first, cleared);
403                 y += row->height();
404                 yf += row->height();
405                 row = row->next();
406                 }
407         } else if (!locked) {
408                 if (need_update & CURSOR) {
409                         bv->screen()->ToggleSelection(TEXT(bv), bv, true, y_offset,int(x));
410                         TEXT(bv)->ClearSelection(bv);
411                         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
412                 }
413                 bv->screen()->Update(TEXT(bv), bv, y_offset, int(x));
414         } else {
415                 locked = false;
416                 if (need_update & SELECTION)
417                         bv->screen()->ToggleToggle(TEXT(bv), bv, y_offset, int(x));
418                 else if (need_update & CURSOR) {
419                         bv->screen()->ToggleSelection(TEXT(bv), bv, true, y_offset,int(x));
420                         TEXT(bv)->ClearSelection(bv);
421                         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
422                 }
423                 bv->screen()->Update(TEXT(bv), bv, y_offset, int(x));
424                 locked = true;
425         }
426         }
427         TEXT(bv)->refresh_y = 0;
428         TEXT(bv)->status = LyXText::UNCHANGED;
429         if ((need_update != CURSOR_PAR) &&
430                 ((drawFrame == ALWAYS) || ((drawFrame == LOCKED) && locked)))
431         {
432                 pain.rectangle(top_x + 1, baseline - insetAscent + 1,
433                                            width(bv, f) - 1, insetAscent + insetDescent - 1,
434                                            frame_color);
435         } else if (need_update & CLEAR_FRAME) {
436                 pain.rectangle(top_x + 1, baseline - insetAscent + 1,
437                                            width(bv, f) - 1, insetAscent + insetDescent - 1,
438                                            LColor::background);
439         }
440         x += width(bv, f) - TEXT_TO_INSET_OFFSET;
441         if (bv->text->status==LyXText::CHANGED_IN_DRAW) {
442                 need_update = INIT;
443         } else if (need_update != INIT)
444                 need_update = NONE;
445 }
446
447
448 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
449 {
450         if (reinit) {  // && (need_update != CURSOR)) {
451                 need_update = INIT;
452                 resizeLyXText(bv);
453                 if (owner())
454                         owner()->update(bv, font, true);
455                 return;
456         }
457         if (the_locking_inset) {
458                 inset_x = cx(bv) - top_x + drawTextXOffset;
459                 inset_y = cy(bv) + drawTextYOffset;
460                 the_locking_inset->update(bv, font, reinit);
461         }
462         if (need_update == INIT) {
463                 resizeLyXText(bv);
464                 need_update = FULL;
465         }
466         int oldw = insetWidth;
467 #if 1
468         insetWidth = TEXT(bv)->width + (2 * TEXT_TO_INSET_OFFSET);
469         // max(textWidth(bv->painter()),
470         // static_cast<int>(TEXT(bv)->width) + drawTextXOffset) +
471         // (2 * TEXT_TO_INSET_OFFSET);
472 #else
473         insetWidth = textWidth(bv);
474         if (insetWidth < 0)
475                 insetWidth = static_cast<int>(TEXT(bv)->width);
476 #endif
477         if (oldw != insetWidth) {
478 //          printf("TW(%p): %d-%d-%d-%d\n",this,insetWidth, oldw,
479 //                 textWidth(bv->painter()),static_cast<int>(TEXT(bv)->width));
480                 resizeLyXText(bv);
481                 need_update = FULL;
482                 update(bv, font, reinit);
483                 return;
484         }
485         if ((need_update==CURSOR_PAR) && (TEXT(bv)->status==LyXText::UNCHANGED) &&
486                 the_locking_inset)
487         {
488                 TEXT(bv)->UpdateInset(bv, the_locking_inset);
489         }
490         
491         if (TEXT(bv)->status == LyXText::NEED_MORE_REFRESH)
492                 need_update = FULL;
493
494         int y_temp = 0;
495         Row * row = TEXT(bv)->GetRowNearY(y_temp);
496         insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
497         insetDescent = TEXT(bv)->height - row->ascent_of_text() +
498                 TEXT_TO_INSET_OFFSET;
499 }
500
501 void InsetText::SetUpdateStatus(BufferView * bv, int what)
502 {
503         need_update |= what;
504         if (TEXT(bv)->status == LyXText::NEED_MORE_REFRESH)
505                 need_update |= FULL;
506         else if (TEXT(bv)->status == LyXText::NEED_VERY_LITTLE_REFRESH)
507                 need_update |= CURSOR_PAR;
508
509         // this to not draw a selection when we redraw all of it!
510         if ((need_update & (INIT|FULL)) && (need_update & CURSOR))
511                 TEXT(bv)->ClearSelection(bv);
512 }
513
514 void InsetText::UpdateLocal(BufferView * bv, int what, bool mark_dirty)
515 {
516         TEXT(bv)->FullRebreak(bv);
517         SetUpdateStatus(bv, what);
518         if ((need_update != CURSOR) || (TEXT(bv)->status != LyXText::UNCHANGED) ||
519                 TEXT(bv)->selection)
520                 bv->updateInset(this, mark_dirty);
521         bv->owner()->showState();
522         if (old_par != cpar(bv)) {
523                 bv->owner()->setLayout(cpar(bv)->GetLayout());
524                 old_par = cpar(bv);
525         }
526 }
527
528
529 string const InsetText::EditMessage() const
530 {
531         return _("Opened Text Inset");
532 }
533
534
535 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
536 {
537 //    par->SetInsetOwner(this);
538         UpdatableInset::Edit(bv, x, y, button);
539
540         if (!bv->lockInset(this)) {
541                 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
542                 return;
543         }
544         locked = true;
545         the_locking_inset = 0;
546         inset_pos = inset_x = inset_y = 0;
547         inset_boundary = false;
548         inset_par = 0;
549         old_par = 0;
550         if (!checkAndActivateInset(bv, x, y, button))
551                 TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
552                                                                                    y+insetAscent);
553         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
554         bv->text->FinishUndo();
555         ShowInsetCursor(bv);
556         UpdateLocal(bv, FULL, false);
557
558         // If the inset is empty set the language of the current font to the
559         // language to the surronding text.
560 #ifndef NEW_INSETS
561         if (par->Last() == 0 && !par->next_)
562 #else
563         if (par->size() == 0 && !par->next())
564 #endif
565         {
566                 LyXFont font(LyXFont::ALL_IGNORE);
567                 font.setLanguage(bv->getParentLanguage(this));
568                 SetFont(bv, font, false);
569         }
570 }
571
572
573 void InsetText::InsetUnlock(BufferView * bv)
574 {
575         if (the_locking_inset) {
576                 the_locking_inset->InsetUnlock(bv);
577                 the_locking_inset = 0;
578         }
579         HideInsetCursor(bv);
580         no_selection = false;
581         locked = false;
582         UpdateLocal(bv, CLEAR_FRAME|CURSOR, false);
583         if (owner())
584                 bv->owner()->setLayout(owner()->getLyXText(bv)
585                                                            ->cursor.par()->GetLayout());
586         else
587                 bv->owner()->setLayout(bv->text->cursor.par()->GetLayout());
588 }
589
590
591 bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
592 {
593         lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
594         if (!inset)
595                 return false;
596         if (inset == cpar(bv)->GetInset(cpos(bv))) {
597                 lyxerr[Debug::INSETS] << "OK" << endl;
598                 the_locking_inset = inset;
599                 inset_x = cx(bv) - top_x + drawTextXOffset;
600                 inset_y = cy(bv) + drawTextYOffset;
601                 inset_pos = cpos(bv);
602                 inset_par = cpar(bv);
603                 inset_boundary = cboundary(bv);
604 #if 0
605                 TEXT(bv)->ClearSelection(bv);
606                 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
607                 TEXT(bv)->UpdateInset(bv, the_locking_inset);
608 #else
609                 UpdateLocal(bv, CURSOR, false);
610 #endif
611                 return true;
612         } else if (the_locking_inset && (the_locking_inset == inset)) {
613                 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
614                         lyxerr[Debug::INSETS] << "OK" << endl;
615                         inset_x = cx(bv) - top_x + drawTextXOffset;
616                         inset_y = cy(bv) + drawTextYOffset;
617                 } else {
618                         lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
619                 }
620         } else if (the_locking_inset) {
621                 lyxerr[Debug::INSETS] << "MAYBE" << endl;
622                 return the_locking_inset->LockInsetInInset(bv, inset);
623         }
624         lyxerr[Debug::INSETS] << "NOT OK" << endl;
625         return false;
626 }
627
628
629 bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
630                                                                    bool lr)
631 {
632         if (!the_locking_inset)
633                 return false;
634         if (the_locking_inset == inset) {
635                 the_locking_inset->InsetUnlock(bv);
636                 TEXT(bv)->UpdateInset(bv, inset);
637                 the_locking_inset = 0;
638                 if (lr)
639                         moveRight(bv, false);
640                 old_par = 0; // force layout setting
641                 UpdateLocal(bv, CURSOR_PAR, false);
642                 return true;
643         }
644         return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
645 }
646
647
648 bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
649 {
650         if (!the_locking_inset)
651                 return false;
652         if (the_locking_inset != inset) {
653                 TEXT(bv)->UpdateInset(bv, the_locking_inset);
654                 SetUpdateStatus(bv, CURSOR_PAR);
655                 return the_locking_inset->UpdateInsetInInset(bv, inset);
656         }
657 //    UpdateLocal(bv, FULL, false);
658         if (TEXT(bv)->UpdateInset(bv, inset))
659                 UpdateLocal(bv, CURSOR_PAR, false);
660         if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
661                 inset_x = cx(bv) - top_x + drawTextXOffset;
662                 inset_y = cy(bv) + drawTextYOffset;
663         }
664         return true;
665 }
666
667
668 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
669 {
670         no_selection = true;
671
672         int tmp_x = x - drawTextXOffset;
673         int tmp_y = y + insetAscent - TEXT(bv)->first;
674         Inset * inset = bv->checkInsetHit(TEXT(bv), tmp_x, tmp_y, button);
675
676         HideInsetCursor(bv);
677         if (the_locking_inset) {
678                 if (the_locking_inset == inset) {
679                         the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
680                         no_selection = false;
681                         return;
682                 } else if (inset) {
683                         // otherwise unlock the_locking_inset and lock the new inset
684                         the_locking_inset->InsetUnlock(bv);
685                         inset_x = cx(bv) - top_x + drawTextXOffset;
686                         inset_y = cy(bv) + drawTextYOffset;
687                         the_locking_inset = static_cast<UpdatableInset*>(inset);
688                         inset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
689                         inset->Edit(bv, x - inset_x, y - inset_y, button);
690                         if (the_locking_inset)
691                                 UpdateLocal(bv, CURSOR, false);
692                         no_selection = false;
693                         return;
694                 }
695                 // otherwise only unlock the_locking_inset
696                 the_locking_inset->InsetUnlock(bv);
697                 the_locking_inset = 0;
698         }
699         if (bv->theLockingInset()) {
700                 if (inset && inset->Editable() == Inset::HIGHLY_EDITABLE) {
701                         UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
702                         inset_x = cx(bv) - top_x + drawTextXOffset;
703                         inset_y = cy(bv) + drawTextYOffset;
704                         inset_pos = cpos(bv);
705                         inset_par = cpar(bv);
706                         inset_boundary = cboundary(bv);
707                         the_locking_inset = uinset;
708                         uinset->InsetButtonPress(bv, x - inset_x, y - inset_y, button);
709                         uinset->Edit(bv, x - inset_x, y - inset_y, 0);
710                         if (the_locking_inset)
711                                 UpdateLocal(bv, CURSOR, false);
712                         no_selection = false;
713                         return;
714                 }
715         }
716         if (!inset && (button == 2)) {
717                 bool paste_internally = false;
718                 if ((button == 2) && TEXT(bv)->selection) {
719                         LocalDispatch(bv, LFUN_COPY, "");
720                         paste_internally = true;
721                 }
722                 TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
723                                                                                    y + insetAscent);
724                 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
725                 UpdateLocal(bv, CURSOR, false);
726                 bv->owner()->setLayout(cpar(bv)->GetLayout());
727                 old_par = cpar(bv);
728                 // Insert primary selection with middle mouse
729                 // if there is a local selection in the current buffer,
730                 // insert this
731                 if (button == 2) {
732                         if (paste_internally)
733                                 LocalDispatch(bv, LFUN_PASTE, "");
734                         else
735                                 LocalDispatch(bv, LFUN_PASTESELECTION, "paragraph");
736                 }
737         }
738         ShowInsetCursor(bv);
739         no_selection = false;
740 }
741
742
743 void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
744 {
745         UpdatableInset * inset = 0;
746
747         if (the_locking_inset) {
748                 the_locking_inset->InsetButtonRelease(bv,
749                                                                                           x - inset_x, y - inset_y,
750                                                                                           button);
751         } else {
752                 if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
753                         inset = static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
754                         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
755                                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
756                         } else {
757                                 inset_x = cx(bv) - top_x + drawTextXOffset;
758                                 inset_y = cy(bv) + drawTextYOffset;
759                                 inset->InsetButtonRelease(bv, x - inset_x, y - inset_y,button);
760                                 inset->Edit(bv, x - inset_x, y - inset_y, button);
761                         }
762                         UpdateLocal(bv, CURSOR_PAR, false);
763                 }
764         }
765         no_selection = false;
766 }
767
768
769 void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
770 {
771         if (no_selection)
772                 return;
773         if (the_locking_inset) {
774                 the_locking_inset->InsetMotionNotify(bv, x - inset_x,
775                                                                                          y - inset_y,state);
776                 return;
777         }
778         HideInsetCursor(bv);
779         TEXT(bv)->SetCursorFromCoordinates(bv, x-drawTextXOffset,
780                                                                            y+insetAscent);
781         TEXT(bv)->SetSelection(bv);
782         if (TEXT(bv)->toggle_cursor.par()!=TEXT(bv)->toggle_end_cursor.par() ||
783                 TEXT(bv)->toggle_cursor.pos()!=TEXT(bv)->toggle_end_cursor.pos())
784                 UpdateLocal(bv, SELECTION, false);
785         ShowInsetCursor(bv);
786 }
787
788
789 void InsetText::InsetKeyPress(XKeyEvent * xke)
790 {
791         if (the_locking_inset) {
792                 the_locking_inset->InsetKeyPress(xke);
793                 return;
794         }
795 }
796
797
798 UpdatableInset::RESULT
799 InsetText::LocalDispatch(BufferView * bv,
800                                                  kb_action action, string const & arg)
801 {
802         no_selection = false;
803         UpdatableInset::RESULT
804                 result= UpdatableInset::LocalDispatch(bv, action, arg);
805         if (result != UNDISPATCHED) {
806                 return DISPATCHED;
807         }
808
809         result=DISPATCHED;
810         if ((action < 0) && arg.empty())
811                 return FINISHED;
812
813         if (the_locking_inset) {
814                 result = the_locking_inset->LocalDispatch(bv, action, arg);
815                 if (result == DISPATCHED_NOUPDATE)
816                         return result;
817                 else if (result == DISPATCHED) {
818                         UpdateLocal(bv, CURSOR_PAR, false);
819                         return result;
820                 } else if (result == FINISHED) {
821                         bool dispatched = false;
822                         switch (action) {
823                         case LFUN_UNKNOWN_ACTION:
824                         case LFUN_BREAKPARAGRAPH:
825                         case LFUN_BREAKLINE:
826                                 moveRightIntern(bv, false, false);
827                                 break;
828                         case LFUN_RIGHT:
829                                 if (!TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
830                                         moveRightIntern(bv, false, false);
831                                 dispatched = true;
832                                 break;
833                         case LFUN_LEFT:
834                                 if (TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
835                                         moveRightIntern(bv, false, false);
836                                 dispatched = true;
837                                 break;
838                         default:
839                                 break;
840                         }
841                         the_locking_inset = 0;
842                         if (dispatched)
843                                 return DISPATCHED;
844                 }
845         }
846         HideInsetCursor(bv);
847         switch (action) {
848         // Normal chars
849         case LFUN_UNKNOWN_ACTION:
850                 if (bv->buffer()->isReadonly()) {
851 //          setErrorMessage(N_("Document is read only"));
852                         break;
853                 }
854                 if (!arg.empty()) {
855                         /* Automatically delete the currently selected
856                          * text and replace it with what is being
857                          * typed in now. Depends on lyxrc settings
858                          * "auto_region_delete", which defaults to
859                          * true (on). */
860
861                         bv->text->SetUndo(bv->buffer(), Undo::INSERT,
862 #ifndef NEW_INSETS
863                                                           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
864                                                           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
865 #else
866                                                           bv->text->cursor.par()->previous(),
867                                                           bv->text->cursor.par()->next()
868 #endif
869                                                           );
870                         bv->setState();
871                         if (lyxrc.auto_region_delete) {
872                                 if (TEXT(bv)->selection){
873                                         TEXT(bv)->CutSelection(bv, false);
874                                 }
875                         }
876                         TEXT(bv)->ClearSelection(bv);
877                         for (string::size_type i = 0; i < arg.length(); ++i) {
878                                 if (greek_kb_flag) {
879                                         if (!math_insert_greek(bv, arg[i])) {
880                                                 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], TEXT(bv));
881                                         } else if (!the_locking_inset) {
882                                                 (void)moveRight(bv, false);
883                                         }
884                                 } else {
885                                         bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], TEXT(bv));
886                                 }
887                         }
888                 }
889                 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
890                 UpdateLocal(bv, CURSOR_PAR, true);
891                 result=DISPATCHED_NOUPDATE;
892                 break;
893                 // --- Cursor Movements ---------------------------------------------
894         case LFUN_RIGHTSEL:
895                 bv->text->FinishUndo();
896                 moveRight(bv, false, true);
897                 TEXT(bv)->SetSelection(bv);
898                 UpdateLocal(bv, SELECTION, false);
899                 break;
900         case LFUN_RIGHT:
901                 result = moveRight(bv);
902                 bv->text->FinishUndo();
903                 UpdateLocal(bv, CURSOR, false);
904                 break;
905         case LFUN_LEFTSEL:
906                 bv->text->FinishUndo();
907                 moveLeft(bv, false, true);
908                 TEXT(bv)->SetSelection(bv);
909                 UpdateLocal(bv, SELECTION, false);
910                 break;
911         case LFUN_LEFT:
912                 bv->text->FinishUndo();
913                 result = moveLeft(bv);
914                 UpdateLocal(bv, CURSOR, false);
915                 break;
916         case LFUN_DOWNSEL:
917                 bv->text->FinishUndo();
918                 moveDown(bv);
919                 TEXT(bv)->SetSelection(bv);
920                 UpdateLocal(bv, SELECTION, false);
921                 break;
922         case LFUN_DOWN:
923                 bv->text->FinishUndo();
924                 result = moveDown(bv);
925                 UpdateLocal(bv, CURSOR, false);
926                 break;
927         case LFUN_UPSEL:
928                 bv->text->FinishUndo();
929                 moveUp(bv);
930                 TEXT(bv)->SetSelection(bv);
931                 UpdateLocal(bv, SELECTION, false);
932                 break;
933         case LFUN_UP:
934                 bv->text->FinishUndo();
935                 result = moveUp(bv);
936                 UpdateLocal(bv, CURSOR, false);
937                 break;
938         case LFUN_HOME:
939                 bv->text->FinishUndo();
940                 TEXT(bv)->CursorHome(bv);
941                 UpdateLocal(bv, CURSOR, false);
942                 break;
943         case LFUN_END:
944                 TEXT(bv)->CursorEnd(bv);
945                 UpdateLocal(bv, CURSOR, false);
946                 break;
947         case LFUN_BACKSPACE:
948                 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
949 #ifndef NEW_INSETS
950                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
951                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
952 #else
953                                                   bv->text->cursor.par()->previous(),
954                                                   bv->text->cursor.par()->next()
955 #endif
956                                                   );
957                 if (TEXT(bv)->selection)
958                         TEXT(bv)->CutSelection(bv);
959                 else
960                         TEXT(bv)->Backspace(bv);
961                 UpdateLocal(bv, CURSOR_PAR, true);
962                 break;
963         case LFUN_DELETE:
964                 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
965 #ifndef NEW_INSETS
966                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
967                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
968 #else
969                                                   bv->text->cursor.par()->previous(),
970                                                   bv->text->cursor.par()->next()
971 #endif
972                                                   );
973                 if (TEXT(bv)->selection)
974                         TEXT(bv)->CutSelection(bv);
975                 else
976                         TEXT(bv)->Delete(bv);
977                 UpdateLocal(bv, CURSOR_PAR, true);
978                 break;
979         case LFUN_CUT:
980                 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
981 #ifndef NEW_INSETS
982                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
983                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
984 #else
985                                                   bv->text->cursor.par()->previous(),
986                                                   bv->text->cursor.par()->next()
987 #endif
988                                                   );
989                 TEXT(bv)->CutSelection(bv);
990                 UpdateLocal(bv, CURSOR_PAR, true);
991                 break;
992         case LFUN_COPY:
993                 bv->text->FinishUndo();
994                 TEXT(bv)->CopySelection(bv);
995                 UpdateLocal(bv, CURSOR_PAR, false);
996                 break;
997         case LFUN_PASTESELECTION:
998         {
999                 string clip(bv->workarea()->getClipboard());
1000         
1001                 if (clip.empty())
1002                         break;
1003                 if (arg == "paragraph") {
1004                         TEXT(bv)->InsertStringB(bv, clip);
1005                 } else {
1006                         TEXT(bv)->InsertStringA(bv, clip);
1007                 }
1008                 UpdateLocal(bv, CURSOR_PAR, true);
1009                 break;
1010         }
1011         case LFUN_PASTE:
1012                 if (!autoBreakRows) {
1013                         CutAndPaste cap;
1014
1015                         if (cap.nrOfParagraphs() > 1) {
1016                                 WriteAlert(_("Impossible operation"),
1017                                                    _("Cannot include more than one paragraph!"),
1018                                                    _("Sorry."));
1019                                 break;
1020                         }
1021                 }
1022                 bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1023 #ifndef NEW_INSETS
1024                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1025                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1026 #else
1027                                                   bv->text->cursor.par()->previous(),
1028                                                   bv->text->cursor.par()->next()
1029 #endif
1030                                                   );
1031                 TEXT(bv)->PasteSelection(bv);
1032                 UpdateLocal(bv, CURSOR_PAR, true);
1033                 break;
1034         case LFUN_BREAKPARAGRAPH:
1035                 if (!autoBreakRows)
1036                         return DISPATCHED;
1037                 TEXT(bv)->BreakParagraph(bv, 0);
1038                 UpdateLocal(bv, FULL, true);
1039                 break;
1040         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1041                 if (!autoBreakRows)
1042                         return DISPATCHED;
1043                 TEXT(bv)->BreakParagraph(bv, 1);
1044                 UpdateLocal(bv, FULL, true);
1045                 break;
1046         case LFUN_BREAKLINE:
1047                 if (!autoBreakRows)
1048                         return DISPATCHED;
1049                 bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1050 #ifndef NEW_INSETS
1051                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1052                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1053 #else
1054                                                   bv->text->cursor.par()->previous(),
1055                                                   bv->text->cursor.par()->next()
1056 #endif
1057                                                   );
1058                 TEXT(bv)->InsertChar(bv, LyXParagraph::META_NEWLINE);
1059                 UpdateLocal(bv, CURSOR_PAR, true);
1060                 break;
1061         case LFUN_LAYOUT:
1062                 // do not set layouts on non breakable textinsets
1063                 if (autoBreakRows) {
1064                         LyXTextClass::size_type cur_layout = cpar(bv)->layout;
1065           
1066                         // Derive layout number from given argument (string)
1067                         // and current buffer's textclass (number). */    
1068                         LyXTextClassList::ClassList::size_type tclass =
1069                                 bv->buffer()->params.textclass;
1070                         std::pair <bool, LyXTextClass::size_type> layout = 
1071                                 textclasslist.NumberOfLayout(tclass, arg);
1072
1073                         // If the entry is obsolete, use the new one instead.
1074                         if (layout.first) {
1075                                 string obs = textclasslist.Style(tclass,layout.second).
1076                                         obsoleted_by();
1077                                 if (!obs.empty()) 
1078                                         layout = textclasslist.NumberOfLayout(tclass, obs);
1079                         }
1080
1081                         // see if we found the layout number:
1082                         if (!layout.first) {
1083                                 string msg = string(N_("Layout ")) + arg + N_(" not known");
1084
1085                                 bv->owner()->getMiniBuffer()->Set(msg);
1086                                 break;
1087                         }
1088
1089                         if (cur_layout != layout.second) {
1090                                 cur_layout = layout.second;
1091                                 TEXT(bv)->SetLayout(bv, layout.second);
1092                                 bv->owner()->setLayout(cpar(bv)->GetLayout());
1093                                 UpdateLocal(bv, CURSOR_PAR, true);
1094                         }
1095                 } else {
1096                         // reset the layout box
1097                         bv->owner()->setLayout(cpar(bv)->GetLayout());
1098                 }
1099                 break;
1100         case LFUN_PARAGRAPH_SPACING:
1101                 // This one is absolutely not working. When fiddling with this
1102                 // it also seems to me that the paragraphs inside the insettext
1103                 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1104         {
1105                 LyXParagraph * par = TEXT(bv)->cursor.par();
1106                 Spacing::Space cur_spacing = par->params.spacing().getSpace();
1107                 float cur_value = 1.0;
1108                 if (cur_spacing == Spacing::Other) {
1109                         cur_value = par->params.spacing().getValue();
1110                 }
1111                                 
1112                 std::istringstream istr(arg.c_str());
1113                 string tmp;
1114                 istr >> tmp;
1115                 Spacing::Space new_spacing = cur_spacing;
1116                 float new_value = cur_value;
1117                 if (tmp.empty()) {
1118                         lyxerr << "Missing argument to `paragraph-spacing'"
1119                                    << endl;
1120                 } else if (tmp == "single") {
1121                         new_spacing = Spacing::Single;
1122                 } else if (tmp == "onehalf") {
1123                         new_spacing = Spacing::Onehalf;
1124                 } else if (tmp == "double") {
1125                         new_spacing = Spacing::Double;
1126                 } else if (tmp == "other") {
1127                         new_spacing = Spacing::Other;
1128                         float tmpval = 0.0;
1129                         istr >> tmpval;
1130                         lyxerr << "new_value = " << tmpval << endl;
1131                         if (tmpval != 0.0)
1132                                 new_value = tmpval;
1133                 } else if (tmp == "default") {
1134                         new_spacing = Spacing::Default;
1135                 } else {
1136                         lyxerr << _("Unknown spacing argument: ")
1137                                    << arg << endl;
1138                 }
1139                 if (cur_spacing != new_spacing || cur_value != new_value) {
1140                         par->params.spacing(Spacing(new_spacing, new_value));
1141                         //TEXT(bv)->RedoParagraph(owner->view());
1142                         UpdateLocal(bv, CURSOR_PAR, true);
1143                         //bv->update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1144                 }
1145         }
1146         break;
1147         
1148         default:
1149                 if (!bv->Dispatch(action, arg))
1150                         result = UNDISPATCHED;
1151                 break;
1152         }
1153
1154         /// If the action has deleted all text in the inset, we need to change the
1155         // language to the language to the surronding text.
1156 #ifndef NEW_INSETS
1157         if (par->Last() == 0 && !par->next_)
1158 #else
1159         if (par->size() == 0 && !par->next())
1160 #endif
1161         {
1162                 LyXFont font(LyXFont::ALL_IGNORE);
1163                 font.setLanguage(bv->getParentLanguage(this));
1164                 SetFont(bv, font, false);
1165         }
1166
1167         if (result != FINISHED) {
1168                 ShowInsetCursor(bv);
1169         } else
1170                 bv->unlockInset(this);
1171         return result;
1172 }
1173
1174
1175 int InsetText::Latex(Buffer const * buf, ostream & os, bool, bool) const
1176 {
1177         TexRow texrow;
1178         buf->latexParagraphs(os, par, 0, texrow);
1179         return texrow.rows();
1180 }
1181
1182
1183 int InsetText::Ascii(Buffer const * buf, ostream & os, int linelen) const
1184 {
1185         LyXParagraph * p = par;
1186         unsigned int lines = 0;
1187         
1188         string tmp;
1189         while (p) {
1190                 tmp = buf->asciiParagraph(p, linelen);
1191                 lines += countChar(tmp, '\n');
1192                 os << tmp;
1193 #ifndef NEW_INSETS
1194                 p = p->next();
1195 #else
1196                 p = p->next();
1197 #endif
1198         }
1199         return lines;
1200 }
1201
1202
1203 int InsetText::DocBook(Buffer const * buf, ostream & os) const
1204 {
1205         LyXParagraph * p = par;
1206         unsigned int lines = 0;
1207         int desc=0;
1208         
1209         string tmp;
1210         while (p) {
1211                 buf->SimpleDocBookOnePar(os,tmp,p,desc,0);
1212 #ifndef NEW_INSETS
1213                 p = p->next_;
1214 #else
1215                 p = p->next();
1216 #endif
1217         }
1218         
1219         return lines;
1220 }
1221
1222
1223 void InsetText::Validate(LaTeXFeatures & features) const
1224 {
1225         LyXParagraph * p = par;
1226         while(p) {
1227                 p->validate(features);
1228 #ifndef NEW_INSETS
1229                 p = p->next_;
1230 #else
1231                 p = p->next();
1232 #endif
1233         }
1234 }
1235
1236
1237 int InsetText::BeginningOfMainBody(Buffer const * buf, LyXParagraph * p) const
1238 {
1239         if (textclasslist.Style(buf->params.textclass,
1240                                                         p->GetLayout()).labeltype != LABEL_MANUAL)
1241                 return 0;
1242         else
1243                 return p->BeginningOfMainBody();
1244 }
1245
1246
1247 void InsetText::GetCursorPos(BufferView * bv,
1248                                                          int & x, int & y) const
1249 {
1250         x = cx(bv);
1251         y = cy(bv);
1252 }
1253
1254
1255 unsigned int InsetText::InsetInInsetY()
1256 {
1257         if (!the_locking_inset)
1258                 return 0;
1259
1260         return (inset_y + the_locking_inset->InsetInInsetY());
1261 }
1262
1263
1264 void InsetText::ToggleInsetCursor(BufferView * bv)
1265 {
1266         if (the_locking_inset) {
1267                 the_locking_inset->ToggleInsetCursor(bv);
1268                 return;
1269         }
1270
1271         LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1272
1273         int asc = lyxfont::maxAscent(font);
1274         int desc = lyxfont::maxDescent(font);
1275   
1276         if (cursor_visible)
1277                 bv->hideLockedInsetCursor();
1278         else
1279                 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1280         cursor_visible = !cursor_visible;
1281 }
1282
1283
1284 void InsetText::ShowInsetCursor(BufferView * bv, bool show)
1285 {
1286         if (the_locking_inset) {
1287                 the_locking_inset->ShowInsetCursor(bv);
1288                 return;
1289         }
1290         if (!cursor_visible) {
1291                 LyXFont font = TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1292         
1293                 int asc = lyxfont::maxAscent(font);
1294                 int desc = lyxfont::maxDescent(font);
1295
1296                 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1297                 if (show)
1298                         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1299                 cursor_visible = true;
1300         }
1301 }
1302
1303
1304 void InsetText::HideInsetCursor(BufferView * bv)
1305 {
1306         if (cursor_visible) {
1307                 bv->hideLockedInsetCursor();
1308                 cursor_visible = false;
1309         }
1310         if (the_locking_inset)
1311                 the_locking_inset->HideInsetCursor(bv);
1312 }
1313
1314
1315 UpdatableInset::RESULT
1316 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1317 {
1318         if (TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1319                 return moveLeftIntern(bv, false, activate_inset, selecting);
1320         else
1321                 return moveRightIntern(bv, false, activate_inset, selecting);
1322 }
1323
1324 UpdatableInset::RESULT
1325 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1326 {
1327         if (TEXT(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1328                 return moveRightIntern(bv, true, activate_inset, selecting);
1329         else
1330                 return moveLeftIntern(bv, true, activate_inset, selecting);
1331 }
1332
1333
1334 UpdatableInset::RESULT
1335 InsetText::moveRightIntern(BufferView * bv, bool behind, 
1336                                                    bool activate_inset, bool selecting)
1337 {
1338 #ifndef NEW_INSETS
1339         if (!cpar(bv)->next_ && (cpos(bv) >= cpar(bv)->Last()))
1340 #else
1341         if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1342 #endif
1343                 return FINISHED;
1344         if (activate_inset && checkAndActivateInset(bv, behind))
1345                 return DISPATCHED;
1346         TEXT(bv)->CursorRight(bv);
1347         if (!selecting)
1348                 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1349         return DISPATCHED_NOUPDATE;
1350 }
1351
1352
1353 UpdatableInset::RESULT
1354 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1355                                                   bool activate_inset, bool selecting)
1356 {
1357 #ifndef NEW_INSETS
1358         if (!cpar(bv)->previous_ && (cpos(bv) <= 0))
1359 #else
1360         if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1361 #endif
1362                 return FINISHED;
1363         TEXT(bv)->CursorLeft(bv);
1364         if (!selecting)
1365                 TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1366         if (activate_inset && checkAndActivateInset(bv, behind))
1367                 return DISPATCHED;
1368         return DISPATCHED_NOUPDATE;
1369 }
1370
1371
1372 UpdatableInset::RESULT
1373 InsetText::moveUp(BufferView * bv)
1374 {
1375         if (!crow(bv)->previous())
1376                 return FINISHED;
1377         TEXT(bv)->CursorUp(bv);
1378         return DISPATCHED_NOUPDATE;
1379 }
1380
1381
1382 UpdatableInset::RESULT
1383 InsetText::moveDown(BufferView * bv)
1384 {
1385         if (!crow(bv)->next())
1386                 return FINISHED;
1387         TEXT(bv)->CursorDown(bv);
1388         return DISPATCHED_NOUPDATE;
1389 }
1390
1391
1392 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
1393 {
1394         if (the_locking_inset) {
1395                 if (the_locking_inset->InsertInsetAllowed(inset))
1396                         return the_locking_inset->InsertInset(bv, inset);
1397                 return false;
1398         }
1399         bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1400 #ifndef NEW_INSETS
1401                                           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1402                                           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1403 #else
1404                                           bv->text->cursor.par()->previous(),
1405                                           bv->text->cursor.par()->next()
1406 #endif
1407                                           );
1408         inset->setOwner(this);
1409         HideInsetCursor(bv);
1410         TEXT(bv)->InsertInset(bv, inset);
1411 #if 0
1412         if ((cpar(bv)->GetChar(cpos(bv)) != LyXParagraph::META_INSET) ||
1413                 (cpar(bv)->GetInset(cpos(bv)) != inset))
1414                 TEXT(bv)->CursorLeft(bv);
1415 #endif
1416         bv->fitCursor(TEXT(bv));
1417         UpdateLocal(bv, CURSOR_PAR|CURSOR, true);
1418         ShowInsetCursor(bv);
1419         return true;
1420 }
1421
1422
1423 UpdatableInset * InsetText::GetLockingInset()
1424 {
1425         return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
1426 }
1427
1428
1429 UpdatableInset * InsetText::GetFirstLockingInsetOfType(Inset::Code c)
1430 {
1431         if (c == LyxCode())
1432                 return this;
1433         if (the_locking_inset)
1434                 return the_locking_inset->GetFirstLockingInsetOfType(c);
1435         return 0;
1436 }
1437
1438
1439 bool InsetText::ShowInsetDialog(BufferView * bv) const
1440 {
1441         if (the_locking_inset)
1442                 return the_locking_inset->ShowInsetDialog(bv);
1443         return false;
1444 }
1445
1446
1447 void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
1448 {
1449         if (TEXT(bv)->selection) {
1450                 bv->text->SetUndo(bv->buffer(), Undo::EDIT,
1451 #ifndef NEW_INSETS
1452                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1453                                                   bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1454 #else
1455                                                   bv->text->cursor.par()->previous(),
1456                                                   bv->text->cursor.par()->next()
1457 #endif
1458                                                   );
1459         }
1460         TEXT(bv)->SetFont(bv, font, toggleall);
1461         bv->fitCursor(TEXT(bv));
1462         UpdateLocal(bv, CURSOR_PAR, true);
1463 }
1464
1465
1466 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1467 {
1468         if (cpar(bv)->GetChar(cpos(bv)) == LyXParagraph::META_INSET) {
1469                 unsigned int x;
1470                 unsigned int y;
1471                 Inset * inset =
1472                         static_cast<UpdatableInset*>(cpar(bv)->GetInset(cpos(bv)));
1473                 if (!inset || inset->Editable() != Inset::HIGHLY_EDITABLE)
1474                         return false;
1475                 LyXFont const font =
1476                         TEXT(bv)->GetFont(bv->buffer(), cpar(bv), cpos(bv));
1477                 if (behind) {
1478                         x = inset->width(bv, font);
1479                         y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1480                 } else {
1481                         x = 0;
1482                         y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1483                 }
1484                 //inset_x = cx(bv) - top_x + drawTextXOffset;
1485                 //inset_y = cy(bv) + drawTextYOffset;
1486                 inset->Edit(bv, x, y, 0);
1487                 if (!the_locking_inset)
1488                         return false;
1489                 UpdateLocal(bv, CURSOR_PAR, false);
1490                 return true;
1491         }
1492         return false;
1493 }
1494
1495
1496 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1497                                                                           int button)
1498 {
1499         int dummyx, dummyy;
1500
1501         dummyx = x = x - drawTextXOffset;
1502         dummyy = y + insetAscent;
1503         Inset * inset = bv->checkInsetHit(TEXT(bv), dummyx, dummyy, button);
1504
1505         if (inset) {
1506                 if (x < 0)
1507                         x = insetWidth;
1508                 if (y < 0)
1509                         y = insetDescent;
1510                 inset_x = cx(bv) - top_x + drawTextXOffset;
1511                 inset_y = cy(bv) + drawTextYOffset;
1512                 inset->Edit(bv, x - inset_x, y - inset_y, button);
1513                 if (!the_locking_inset)
1514                         return false;
1515                 UpdateLocal(bv, CURSOR_PAR, false);
1516                 return true;
1517         }
1518         return false;
1519 }
1520
1521
1522 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1523 {
1524         int w = UpdatableInset::getMaxWidth(bv, inset);
1525         if (w < 0) {
1526                 return w;
1527         }
1528         if (owner()) {
1529                 w = w - top_x + owner()->x();
1530                 return w;
1531         }
1532         w -= (2 * TEXT_TO_INSET_OFFSET);
1533         return w - top_x;
1534 //    return  w - (2*TEXT_TO_INSET_OFFSET);
1535 }
1536
1537
1538 void InsetText::SetParagraphData(LyXParagraph * p)
1539 {
1540         // delete all instances of LyXText before deleting the paragraps used
1541         // by it.
1542         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit){
1543                 delete (*cit).second;
1544                 (*cit).second = 0;
1545         }
1546
1547 #ifndef NEW_INSETS
1548         LyXParagraph * np;
1549         if (par) {
1550                 np = par->next_;
1551                 delete par;
1552                 while (np) {
1553                         par = np;
1554                         np = np->next_;
1555                         delete par;
1556                 }
1557         }
1558         par = p->Clone();
1559         par->SetInsetOwner(this);
1560         np = par;
1561         while (p->next_) {
1562                 p = p->next_;
1563                 np->next(p->Clone());
1564                 np->next_->previous(np);
1565                 np = np->next_;
1566                 np->SetInsetOwner(this);
1567         }
1568 #else
1569         LyXParagraph * np;
1570         if (par) {
1571                 np = par->next();
1572                 delete par;
1573                 while(np) {
1574                         par = np;
1575                         np = np->next();
1576                         delete par;
1577                 }
1578         }
1579         par = p->Clone();
1580         par->SetInsetOwner(this);
1581         np = par;
1582         while(p->next()) {
1583                 p = p->next();
1584                 np->next(p->Clone());
1585                 np->next()->previous(np);
1586                 np = np->next();
1587                 np->SetInsetOwner(this);
1588         }
1589 #endif
1590         need_update = INIT;
1591 }
1592
1593
1594 void InsetText::SetText(string const & data)
1595 {
1596         clear();
1597         LyXFont font(LyXFont::ALL_SANE);
1598         for(unsigned int i=0; i < data.length(); ++i)
1599                 par->InsertChar(i, data[i], font);
1600 }
1601
1602
1603 void InsetText::SetAutoBreakRows(bool flag)
1604 {
1605         if (flag != autoBreakRows) {
1606                 autoBreakRows = flag;
1607                 need_update = FULL;
1608                 if (!flag)
1609                         removeNewlines();
1610         }
1611 }
1612
1613
1614 void InsetText::SetDrawFrame(BufferView * bv, DrawFrame how)
1615 {
1616         if (how != drawFrame) {
1617                 drawFrame = how;
1618                 if (bv)
1619                         UpdateLocal(bv, DRAW_FRAME, false);
1620         }
1621 }
1622
1623
1624 void InsetText::SetFrameColor(BufferView * bv, LColor::color col)
1625 {
1626         if (frame_color != col) {
1627                 frame_color = col;
1628                 if (bv)
1629                         UpdateLocal(bv, DRAW_FRAME, false);
1630         }
1631 }
1632
1633
1634 int InsetText::cx(BufferView * bv) const
1635 {
1636         LyXText * text = TEXT(bv);
1637         int x = text->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1638         if (the_locking_inset) {
1639                 LyXFont font = text->GetFont(bv->buffer(),
1640                                                                          text->cursor.par(), text->cursor.pos());
1641                 if (font.isVisibleRightToLeft())
1642                         x -= the_locking_inset->width(bv, font);
1643         }
1644         return x;
1645 }
1646
1647
1648 int InsetText::cy(BufferView * bv) const
1649 {
1650         LyXFont font;
1651         return TEXT(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
1652 }
1653
1654
1655 LyXParagraph::size_type InsetText::cpos(BufferView * bv) const
1656 {
1657         return TEXT(bv)->cursor.pos();
1658 }
1659
1660
1661 LyXParagraph * InsetText::cpar(BufferView * bv) const
1662 {
1663         return TEXT(bv)->cursor.par();
1664 }
1665
1666 bool InsetText::cboundary(BufferView * bv) const
1667 {
1668         return TEXT(bv)->cursor.boundary();
1669 }
1670
1671
1672 Row * InsetText::crow(BufferView * bv) const
1673 {
1674         return TEXT(bv)->cursor.row();
1675 }
1676
1677
1678 LyXText * InsetText::getLyXText(BufferView const * lbv, bool const recursive) const
1679 {
1680         // Super UGLY! (Lgb)
1681         BufferView * bv = const_cast<BufferView *>(lbv);
1682         
1683         if ((cache.find(bv) != cache.end()) && cache[bv]) {
1684                 if (recursive && the_locking_inset)
1685                         return the_locking_inset->getLyXText(bv);
1686                 return cache[bv];
1687         }
1688         LyXText * lt = new LyXText(const_cast<InsetText *>(this));
1689         lt->init(bv);
1690         cache[bv] = lt;
1691         if (the_locking_inset) {
1692                 lt->SetCursor(bv, inset_par, inset_pos, true, inset_boundary);
1693                 if (recursive)
1694                         return the_locking_inset->getLyXText(bv);
1695         }
1696         return lt;
1697 }
1698
1699
1700 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1701 {
1702         if ((cache.find(bv) == cache.end()) || !cache[bv])
1703                 return;
1704         delete cache[bv];
1705         cache.erase(bv);
1706         if (recursive) {
1707                 /// then remove all LyXText in text-insets
1708                 LyXParagraph * p = par;
1709 #ifndef NEW_INSETS
1710                 for (; p; p = p->next_) {
1711                         p->deleteInsetsLyXText(bv);
1712                 }
1713 #else
1714                 for (; p; p = p->next()) {
1715                         p->deleteInsetsLyXText(bv);
1716                 }
1717 #endif
1718         }
1719 }
1720
1721
1722 void InsetText::resizeLyXText(BufferView * bv) const
1723 {
1724 #ifndef NEW_INSETS
1725         if (!par->next_ && !par->size()) // resize not neccessary!
1726 #else
1727         if (!par->next() && !par->size()) // resize not neccessary!
1728 #endif
1729                 return;
1730         if ((cache.find(bv) == cache.end()) || !cache[bv])
1731                 return;
1732
1733         LyXParagraph * lpar = 0;
1734         LyXParagraph * selstartpar = 0;
1735         LyXParagraph * selendpar = 0;
1736         LyXParagraph::size_type pos = 0;
1737         LyXParagraph::size_type selstartpos = 0;
1738         LyXParagraph::size_type selendpos = 0;
1739         bool boundary = false;
1740         bool selstartboundary = false;
1741         bool selendboundary = false;
1742         int selection = 0;
1743         int mark_set = 0;
1744
1745 //    ProhibitInput(bv);
1746
1747         if (locked) {
1748                 lpar = TEXT(bv)->cursor.par();
1749                 pos = TEXT(bv)->cursor.pos();
1750                 boundary = TEXT(bv)->cursor.boundary();
1751                 selstartpar = TEXT(bv)->sel_start_cursor.par();
1752                 selstartpos = TEXT(bv)->sel_start_cursor.pos();
1753                 selstartboundary = TEXT(bv)->sel_start_cursor.boundary();
1754                 selendpar = TEXT(bv)->sel_end_cursor.par();
1755                 selendpos = TEXT(bv)->sel_end_cursor.pos();
1756                 selendboundary = TEXT(bv)->sel_end_cursor.boundary();
1757                 selection = TEXT(bv)->selection;
1758                 mark_set = TEXT(bv)->mark_set;
1759         }
1760         deleteLyXText(bv, (the_locking_inset == 0));
1761
1762         if (lpar) {
1763                 TEXT(bv)->selection = true;
1764                 /* at this point just to avoid the Delete-Empty-Paragraph
1765                  * Mechanism when setting the cursor */
1766                 TEXT(bv)->mark_set = mark_set;
1767                 if (selection) {
1768                         TEXT(bv)->SetCursor(bv, selstartpar, selstartpos,true, 
1769                                                                 selstartboundary);
1770                         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1771                         TEXT(bv)->SetCursor(bv, selendpar, selendpos, true, selendboundary);
1772                         TEXT(bv)->SetSelection(bv);
1773                         TEXT(bv)->SetCursor(bv, lpar, pos);
1774                 } else {
1775                         TEXT(bv)->SetCursor(bv, lpar, pos, true, boundary);
1776                         TEXT(bv)->sel_cursor = TEXT(bv)->cursor;
1777                         TEXT(bv)->selection = false;
1778                 }
1779         }
1780         if (bv->screen())
1781                 TEXT(bv)->first = bv->screen()->TopCursorVisible(TEXT(bv));
1782         // this will scroll the screen such that the cursor becomes visible 
1783         bv->updateScrollbar();
1784 //    AllowInput(bv);
1785         if (the_locking_inset) {
1786                 /// then resize all LyXText in text-insets
1787                 inset_x = cx(bv) - top_x + drawTextXOffset;
1788                 inset_y = cy(bv) + drawTextYOffset;
1789 #ifndef NEW_INSETS
1790                 for (LyXParagraph * p = par; p; p = p->next_) {
1791                         p->resizeInsetsLyXText(bv);
1792                 }
1793 #else
1794                 for (LyXParagraph * p = par; p; p = p->next()) {
1795                         p->resizeInsetsLyXText(bv);
1796                 }
1797 #endif
1798         }
1799         need_update = FULL;
1800 }
1801
1802
1803 void InsetText::removeNewlines()
1804 {
1805 #ifndef NEW_INSETS
1806         for (LyXParagraph * p = par; p; p = p->next_) {
1807                 for (int i = 0; i < p->Last(); ++i) {
1808 #else
1809         for (LyXParagraph * p = par; p; p = p->next()) {
1810                 for (int i = 0; i < p->size(); ++i) {
1811 #endif
1812                         if (p->GetChar(i) == LyXParagraph::META_NEWLINE)
1813                                 p->Erase(i);
1814                 }
1815         }
1816 }