]> git.lyx.org Git - lyx.git/blob - src/insets/insettext.C
17f6610888718a878df1ac6efa069750733f932c
[lyx.git] / src / insets / insettext.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1998-2001 The LyX Team.
7  *
8  * ======================================================
9  */
10
11 #include <config.h>
12
13 #include <fstream>
14 #include <algorithm>
15
16 #include <cstdlib>
17 //#include <signal.h>
18
19 #ifdef __GNUG__
20 #pragma implementation
21 #endif
22
23 #include "insettext.h"
24 #include "paragraph.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 "LColor.h"
41 #include "support/textutils.h"
42 #include "support/LAssert.h"
43 #include "lyxrow.h"
44 #include "lyxrc.h"
45 #include "intl.h"
46 #include "trans_mgr.h"
47 #include "lyxscreen.h"
48 #include "WorkArea.h"
49 #include "gettext.h"
50 #include "lyxfunc.h"
51 #include "ParagraphParameters.h"
52 #include "undo_funcs.h"
53 #include "lyxfind.h"
54
55 using std::ostream;
56 using std::ifstream;
57 using std::endl;
58 using std::min;
59 using std::max;
60 using std::make_pair;
61
62 extern unsigned char getCurrentTextClass(Buffer *);
63 extern bool math_insert_greek(BufferView *, char);
64 extern int greek_kb_flag;
65
66
67 #warning this functions should probably go into bufferview_funcs somehow (Jug)
68
69 void InsetText::saveLyXTextState(LyXText * t) const
70 {
71         sstate.lpar = t->cursor.par();
72         sstate.pos = t->cursor.pos();
73         sstate.boundary = t->cursor.boundary();
74         sstate.selstartpar = t->selection.start.par();
75         sstate.selstartpos = t->selection.start.pos();
76         sstate.selstartboundary = t->selection.start.boundary();
77         sstate.selendpar = t->selection.end.par();
78         sstate.selendpos = t->selection.end.pos();
79         sstate.selendboundary = t->selection.end.boundary();
80         sstate.selection = t->selection.set();
81         sstate.mark_set = t->selection.mark();
82 }
83
84 void InsetText::restoreLyXTextState(BufferView * bv, LyXText * t) const
85 {
86         if (sstate.lpar) {
87                 t->selection.set(true);
88                 /* at this point just to avoid the Delete-Empty-Paragraph
89                  * Mechanism when setting the cursor */
90                 t->selection.mark(sstate.mark_set);
91                 if (sstate.selection) {
92                         t->setCursor(bv, sstate.selstartpar, sstate.selstartpos,
93                                      true, sstate.selstartboundary);
94                         t->selection.cursor = t->cursor;
95                         t->setCursor(bv, sstate.selendpar, sstate.selendpos,
96                                      true, sstate.selendboundary);
97                         t->setSelection(bv);
98                         t->setCursor(bv, sstate.lpar, sstate.pos);
99                 } else {
100                         t->setCursor(bv, sstate.lpar, sstate.pos, true, sstate.boundary);
101                         t->selection.cursor = t->cursor;
102                         t->selection.set(false);
103                 }
104         }
105 }
106
107
108 InsetText::InnerCache::InnerCache(boost::shared_ptr<LyXText> t)
109 {
110         text = t;
111         remove = false;
112 }
113
114
115 InsetText::InsetText()
116 {
117         par = new Paragraph;
118         init();
119 }
120
121
122 InsetText::InsetText(InsetText const & ins, bool same_id)
123         : UpdatableInset()
124 {
125         par = 0;
126         init(&ins, same_id);
127         autoBreakRows = ins.autoBreakRows;
128 }
129
130
131 InsetText & InsetText::operator=(InsetText const & it)
132 {
133         init(&it);
134         autoBreakRows = it.autoBreakRows;
135         return * this;
136 }
137
138
139 void InsetText::init(InsetText const * ins, bool same_id)
140 {
141         top_y = 0;
142         last_width = 0;
143         last_height = 0;
144         insetAscent = 0;
145         insetDescent = 0;
146         insetWidth = 0;
147         the_locking_inset = 0;
148         old_max_width = 0;
149         no_selection = false;
150         need_update = INIT;
151         drawTextXOffset = 0;
152         drawTextYOffset = 0;
153         autoBreakRows = false;
154         drawFrame_ = NEVER;
155         xpos = 0.0;
156         if (ins) {
157                 setParagraphData(ins->par);
158                 autoBreakRows = ins->autoBreakRows;
159                 drawFrame_ = ins->drawFrame_;
160                 if (same_id)
161                         id_ = ins->id_;
162         }
163         par->setInsetOwner(this);
164         frame_color = LColor::insetframe;
165         locked = false;
166         old_par = 0;
167         last_drawn_width = -1;
168         frame_is_visible = false;
169         cached_bview = 0;
170         sstate.lpar = 0;
171         lt = 0;
172 }
173
174
175 InsetText::~InsetText()
176 {
177         cached_bview = 0;
178
179         // NOTE
180         
181         while (par) {
182                 Paragraph * tmp = par->next();
183                 delete par;
184                 par = tmp;
185         }
186 }
187
188
189 void InsetText::clear()
190 {
191         cached_bview = 0;
192
193         // now also delete all caches this should be safe, hopefully
194         cache.clear();
195
196         while (par) {
197                 Paragraph * tmp = par->next();
198                 delete par;
199                 par = tmp;
200         }
201         par = new Paragraph;
202 }
203
204
205 Inset * InsetText::clone(Buffer const &, bool same_id) const
206 {
207         InsetText * t = new InsetText(*this, same_id);
208         return t;
209 }
210
211
212 void InsetText::write(Buffer const * buf, ostream & os) const
213 {
214         os << "Text\n";
215         writeParagraphData(buf, os);
216 }
217
218
219 void InsetText::writeParagraphData(Buffer const * buf, ostream & os) const
220 {
221         par->writeFile(buf, os, buf->params, 0);
222 }
223
224
225 void InsetText::read(Buffer const * buf, LyXLex & lex)
226 {
227         string token;
228         int pos = 0;
229         Paragraph * return_par = 0;
230         Paragraph::depth_type depth = 0; 
231         LyXFont font(LyXFont::ALL_INHERIT);
232
233         clear();
234         
235         while (lex.IsOK()) {
236                 lex.nextToken();
237                 token = lex.GetString();
238                 if (token.empty())
239                         continue;
240                 if (token == "\\end_inset")
241                         break;
242                 if (const_cast<Buffer*>(buf)->
243                         parseSingleLyXformat2Token(lex, par, return_par,
244                                                    token, pos, depth, font)) {
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                 return_par = return_par->next();
256         }
257         
258         if (token != "\\end_inset") {
259                 lex.printError("Missing \\end_inset at this point. "
260                                            "Read: `$$Token'");
261         }
262         need_update = INIT;
263 }
264
265
266 int InsetText::ascent(BufferView * bv, LyXFont const &) const
267 {
268         int y_temp = 0;
269         Row * row = getLyXText(bv)->getRowNearY(y_temp);
270         insetAscent = row->ascent_of_text() + TEXT_TO_INSET_OFFSET;
271         return insetAscent;
272 }
273
274
275 int InsetText::descent(BufferView * bv, LyXFont const &) const
276 {
277         bool clear = false;
278         if (!lt) {
279                 lt = getLyXText(bv);
280                 clear = true;
281         }
282         int y_temp = 0;
283         Row * row = lt->getRowNearY(y_temp);
284         insetDescent = lt->height - row->ascent_of_text() +
285         TEXT_TO_INSET_OFFSET;
286         if (clear)
287                 lt = 0;
288         return insetDescent;
289 }
290
291
292 int InsetText::width(BufferView * bv, LyXFont const &) const
293 {
294         insetWidth = max(textWidth(bv),
295                          (int)getLyXText(bv)->width + (2 * TEXT_TO_INSET_OFFSET));
296         return insetWidth;
297 }
298
299
300 int InsetText::textWidth(BufferView * bv) const
301 {
302         int const w = getMaxWidth(bv, this);
303         return w;
304 }
305
306
307 void InsetText::draw(BufferView * bv, LyXFont const & f,
308                      int baseline, float & x, bool cleared) const
309 {
310         if (nodraw())
311                 return;
312
313         Painter & pain = bv->painter();
314
315         // no draw is necessary !!!
316         if ((drawFrame_ == LOCKED) && !locked && !par->size()) {
317                 top_x = int(x);
318                 top_baseline = baseline;
319                 x += width(bv, f);
320                 if (!cleared && (need_update & CLEAR_FRAME))
321                         clearFrame(pain, cleared);
322                 else if (cleared)
323                         frame_is_visible = false;
324                 need_update = NONE;
325                 return;
326         }
327
328         xpos = x;
329 #if 0
330         UpdatableInset::draw(bv, f, baseline, x, cleared);
331 #else
332         if (!owner())
333                 x += static_cast<float>(scroll());
334 #endif
335 #if 0
336         // update insetWidth and insetHeight with dummy calls
337         (void)ascent(bv, f);
338         (void)descent(bv, f);
339         (void)width(bv, f);
340 #endif
341
342         // if top_x differs we have a rule down and we don't have to clear anything
343         if (!cleared && (top_x == int(x)) &&
344                 ((need_update&(INIT|FULL)) || (top_baseline!=baseline) ||
345                  (last_drawn_width!=insetWidth))) {
346                 clearInset(pain, baseline, cleared);
347         }
348         if (cleared)
349                 frame_is_visible = false;
350
351         if (!cleared && (need_update == NONE))
352                 return;
353
354         if (top_x != int(x)) {
355                 if ((getMaxWidth(bv, this) > 0) &&
356                         (getLyXText(bv)->width != old_max_width)) {
357                         resizeLyXText(bv);
358                         need_update |= FULL;
359                         old_max_width = getLyXText(bv)->width;
360                         bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
361                 }
362                 top_x = int(x);
363                 clearInset(pain, baseline, cleared);
364         }
365
366 //      lyxerr << "InsetText::draw[" << this << "](" << need_update << ":" << int(x) << ":" << top_x << ")\n";
367
368         if (cleared || (last_drawn_width != insetWidth)) {
369                 need_update |= FULL;
370                 last_drawn_width = insetWidth;
371         }
372
373         top_baseline = baseline;
374         top_y = baseline - ascent(bv, f);
375         last_width = width(bv, f);
376         last_height = ascent(bv, f) + descent(bv, f);
377
378         if (the_locking_inset && (cpar(bv) == inset_par)
379                 && (cpos(bv) == inset_pos)) {
380                 inset_x = cx(bv) - top_x + drawTextXOffset;
381                 inset_y = cy(bv) + drawTextYOffset;
382         }
383         if (!cleared && (need_update == CURSOR)
384                 && !getLyXText(bv)->selection.set()) {
385                 drawFrame(pain, cleared);
386                 x += last_width; // was width(bv, f);
387                 need_update = NONE;
388                 return;
389         }
390         bool clear = false;
391         if (!lt) {
392                 lt = getLyXText(bv);
393                 clear = true;
394         }
395         x += TEXT_TO_INSET_OFFSET;
396
397         int y = 0;
398         Row * row = lt->getRowNearY(y);
399         int y_offset = baseline - row->ascent_of_text();
400         int ph = pain.paperHeight();
401         int first = 0;
402         y = y_offset;
403         while ((row != 0) && ((y+row->height()) <= 0)) {
404                 y += row->height();
405                 first += row->height();
406                 row = row->next();
407         }
408         if (y_offset < 0)
409                 y_offset = y;
410         lt->first = first;
411         if (cleared) {
412                 int yf = y_offset;
413                 y = 0;
414                 while ((row != 0) && (yf < ph)) {
415                         lt->getVisibleRow(bv, y+y_offset, int(x), row,
416                                                 y+first, cleared);
417                         y += row->height();
418                         yf += row->height();
419                         row = row->next();
420                 }
421         } else if (!locked) {
422                 if (need_update & CURSOR) {
423                         bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
424                         lt->clearSelection(bv);
425                         lt->selection.cursor = lt->cursor;
426                 }
427                 bv->screen()->update(lt, bv, y_offset, int(x));
428         } else {
429                 locked = false;
430                 if (need_update & SELECTION)
431                         bv->screen()->toggleToggle(lt, bv, y_offset, int(x));
432                 else if (need_update & CURSOR) {
433                         bv->screen()->toggleSelection(lt, bv, true, y_offset,int(x));
434                         lt->clearSelection(bv);
435                         lt->selection.cursor = lt->cursor;
436                 }
437                 bv->screen()->update(lt, bv, y_offset, int(x));
438                 locked = true;
439         }
440
441         lt->refresh_y = 0;
442         lt->status(bv, LyXText::UNCHANGED);
443         if ((need_update != CURSOR_PAR) &&
444                 ((drawFrame_ == ALWAYS) || ((drawFrame_ == LOCKED) && locked)))
445                 drawFrame(pain, cleared);
446         else if (need_update & CLEAR_FRAME)
447                 clearFrame(pain, cleared);
448         x += last_width /* was width(bv, f) */ - TEXT_TO_INSET_OFFSET;
449         if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
450                 need_update |= INIT;
451         } else if (need_update != INIT)
452                 need_update = NONE;
453         if (clear)
454                 lt = 0;
455 }
456
457
458 void InsetText::drawFrame(Painter & pain, bool cleared) const
459 {
460         if (!frame_is_visible || cleared) {
461                 pain.rectangle(top_x + 1, top_baseline - insetAscent + 1,
462                                insetWidth - 1, insetAscent + insetDescent - 1,
463                                frame_color);
464                 frame_is_visible = true;
465         }
466 }
467
468
469 void InsetText::clearFrame(Painter & pain, bool cleared) const
470 {
471         if (frame_is_visible) {
472                 if (!cleared) {
473                         pain.rectangle(top_x + 1, top_baseline - insetAscent + 1,
474                                        insetWidth - 1, insetAscent + insetDescent - 1,
475                                        LColor::background);
476                 }
477                 frame_is_visible = false;
478         }
479 }
480
481
482 void InsetText::update(BufferView * bv, LyXFont const & font, bool reinit)
483 {
484         if (reinit) {
485                 need_update |= INIT;
486                 resizeLyXText(bv);
487                 if (owner())
488                         owner()->update(bv, font, true);
489                 return;
490         }
491         if (the_locking_inset) {
492                 inset_x = cx(bv) - top_x + drawTextXOffset;
493                 inset_y = cy(bv) + drawTextYOffset;
494                 the_locking_inset->update(bv, font, reinit);
495         }
496
497         bool clear = false;
498         if (!lt) {
499                 lt = getLyXText(bv);
500                 clear = true;
501         }
502         int oldw = insetWidth;
503         insetWidth = lt->width + (2 * TEXT_TO_INSET_OFFSET);
504         if (oldw != insetWidth) {
505                 resizeLyXText(bv);
506                 need_update |= FULL;
507                 if (clear)
508                         lt = 0;
509                 return;
510         }
511         if ((need_update & CURSOR_PAR) && (lt->status() == LyXText::UNCHANGED) &&
512                 the_locking_inset)
513         {
514                 lt->updateInset(bv, the_locking_inset);
515         }
516         if (lt->status() == LyXText::NEED_MORE_REFRESH)
517                 need_update |= FULL;
518         if (clear)
519                 lt = 0;
520 }
521
522
523 void InsetText::setUpdateStatus(BufferView * bv, int what) const
524 {
525         bool clear = false;
526         if (!lt) {
527                 lt = getLyXText(bv);
528                 clear = true;
529         }
530         need_update |= what;
531         if (lt->status() == LyXText::NEED_MORE_REFRESH)
532                 need_update |= FULL;
533         else if (lt->status() == LyXText::NEED_VERY_LITTLE_REFRESH)
534                 need_update |= CURSOR_PAR;
535
536         // this to not draw a selection when we redraw all of it!
537         if ((need_update & (INIT|FULL)) && (need_update & CURSOR))
538                 lt->clearSelection(bv);
539         if (clear)
540                 lt = 0;
541 }
542
543
544 void InsetText::updateLocal(BufferView * bv, int what, bool mark_dirty) const
545 {
546         bool clear = false;
547         if (!lt) {
548                 lt = getLyXText(bv);
549                 clear = true;
550         }
551         lt->fullRebreak(bv);
552         setUpdateStatus(bv, what);
553         if ((need_update != CURSOR) || (lt->status() != LyXText::UNCHANGED) ||
554                 lt->selection.set())
555         {
556                 bv->updateInset(const_cast<InsetText *>(this), mark_dirty);
557         }
558         bv->owner()->showState();
559         if (old_par != cpar(bv)) {
560                 bv->owner()->setLayout(cpar(bv)->getLayout());
561                 old_par = cpar(bv);
562         }
563         if (clear)
564                 lt = 0;
565 }
566
567
568 string const InsetText::editMessage() const
569 {
570         return _("Opened Text Inset");
571 }
572
573
574 void InsetText::edit(BufferView * bv, int x, int y, unsigned int button)
575 {
576         UpdatableInset::edit(bv, x, y, button);
577         
578         if (!bv->lockInset(this)) {
579                 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
580                 return;
581         }
582         locked = true;
583         the_locking_inset = 0;
584         inset_pos = inset_x = inset_y = 0;
585         inset_boundary = false;
586         inset_par = 0;
587         old_par = 0;
588         int tmp_y = (y < 0) ? 0 : y;
589         bool clear = false;
590         if (!lt) {
591                 lt = getLyXText(bv);
592                 clear = true;
593         }
594
595         if (!checkAndActivateInset(bv, x, tmp_y, button))
596                 lt->setCursorFromCoordinates(bv, x - drawTextXOffset,
597                                             y + insetAscent);
598         lt->clearSelection(bv);
599         finishUndo();
600         showInsetCursor(bv);
601         updateLocal(bv, CURSOR, false);
602
603         // If the inset is empty set the language of the current font to the
604         // language to the surronding text (if different).
605         if (par->size() == 0 && !par->next() &&
606                 bv->getParentLanguage(this) != lt->current_font.language()) {
607                 LyXFont font(LyXFont::ALL_IGNORE);
608                 font.setLanguage(bv->getParentLanguage(this));
609                 setFont(bv, font, false);
610         }
611         if (clear)
612                 lt = 0;
613 }
614
615
616 void InsetText::edit(BufferView * bv, bool front)
617 {
618         UpdatableInset::edit(bv, front);
619         
620         if (!bv->lockInset(this)) {
621                 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
622                 return;
623         }
624         locked = true;
625         the_locking_inset = 0;
626         inset_pos = inset_x = inset_y = 0;
627         inset_boundary = false;
628         inset_par = 0;
629         old_par = 0;
630         bool clear = false;
631         if (!lt) {
632                 lt = getLyXText(bv);
633                 clear = true;
634         }
635         if (front)
636                 lt->setCursor(bv, par, 0);
637         else {
638                 Paragraph * p = par;
639                 while(p->next())
640                         p = p->next();
641                 lt->setCursor(bv, p, p->size()-1);
642         }
643         lt->clearSelection(bv);
644         finishUndo();
645         showInsetCursor(bv);
646         updateLocal(bv, CURSOR, false);
647
648         // If the inset is empty set the language of the current font to the
649         // language to the surronding text (if different).
650         if (par->size() == 0 && !par->next() &&
651                 bv->getParentLanguage(this) != lt->current_font.language()) {
652                 LyXFont font(LyXFont::ALL_IGNORE);
653                 font.setLanguage(bv->getParentLanguage(this));
654                 setFont(bv, font, false);
655         }
656         if (clear)
657                 lt = 0;
658 }
659
660
661 void InsetText::insetUnlock(BufferView * bv)
662 {
663         if (the_locking_inset) {
664                 the_locking_inset->insetUnlock(bv);
665                 the_locking_inset = 0;
666         }
667         hideInsetCursor(bv);
668         no_selection = false;
669         locked = false;
670         int code = CURSOR|CLEAR_FRAME;
671         bool clear = false;
672         if (!lt) {
673                 lt = getLyXText(bv);
674                 clear = true;
675         }
676         if (lt->selection.set()) {
677                 lt->clearSelection(bv);
678                 code = FULL;
679         } else if (owner()) {
680                 bv->owner()->setLayout(owner()->getLyXText(bv)
681                                        ->cursor.par()->getLayout());
682         } else
683                 bv->owner()->setLayout(bv->text->cursor.par()->getLayout());
684         updateLocal(bv, code, false);
685         if (clear)
686                 lt = 0;
687 }
688
689
690 bool InsetText::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
691 {
692         lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset("
693                               << inset << "): ";
694         if (!inset)
695                 return false;
696         if (inset == cpar(bv)->getInset(cpos(bv))) {
697                 lyxerr[Debug::INSETS] << "OK" << endl;
698                 the_locking_inset = inset;
699                 inset_x = cx(bv) - top_x + drawTextXOffset;
700                 inset_y = cy(bv) + drawTextYOffset;
701                 inset_pos = cpos(bv);
702                 inset_par = cpar(bv);
703                 inset_boundary = cboundary(bv);
704                 updateLocal(bv, CURSOR, false);
705                 return true;
706         } else if (the_locking_inset && (the_locking_inset == inset)) {
707                 if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
708                         lyxerr[Debug::INSETS] << "OK" << endl;
709                         inset_x = cx(bv) - top_x + drawTextXOffset;
710                         inset_y = cy(bv) + drawTextYOffset;
711                 } else {
712                         lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
713                 }
714         } else if (the_locking_inset) {
715                 lyxerr[Debug::INSETS] << "MAYBE" << endl;
716                 return the_locking_inset->lockInsetInInset(bv, inset);
717         }
718         lyxerr[Debug::INSETS] << "NOT OK" << endl;
719         return false;
720 }
721
722
723 bool InsetText::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
724                                    bool lr)
725 {
726         if (!the_locking_inset)
727                 return false;
728         if (the_locking_inset == inset) {
729                 the_locking_inset->insetUnlock(bv);
730                 getLyXText(bv)->updateInset(bv, inset);
731                 the_locking_inset = 0;
732                 if (lr)
733                         moveRight(bv, false);
734                 old_par = 0; // force layout setting
735                 if (scroll())
736                         scroll(bv, 0.0F);
737                 else
738                         updateLocal(bv, CURSOR, false);
739                 return true;
740         }
741         return the_locking_inset->unlockInsetInInset(bv, inset, lr);
742 }
743
744
745 bool InsetText::updateInsetInInset(BufferView * bv, Inset * inset)
746 {
747         if (!the_locking_inset)
748                 return false;
749         if (the_locking_inset != inset) {
750                 getLyXText(bv)->updateInset(bv, the_locking_inset);
751                 setUpdateStatus(bv, CURSOR_PAR);
752                 return the_locking_inset->updateInsetInInset(bv, inset);
753         }
754 //    updateLocal(bv, FULL, false);
755         if (getLyXText(bv)->updateInset(bv, inset))
756                 updateLocal(bv, CURSOR_PAR, false);
757         if (cpar(bv) == inset_par && cpos(bv) == inset_pos) {
758                 inset_x = cx(bv) - top_x + drawTextXOffset;
759                 inset_y = cy(bv) + drawTextYOffset;
760         }
761         return true;
762 }
763
764
765 void InsetText::insetButtonPress(BufferView * bv, int x, int y, int button)
766 {
767         no_selection = true;
768
769         int tmp_x = x - drawTextXOffset;
770         int tmp_y = y + insetAscent - getLyXText(bv)->first;
771         Inset * inset = bv->checkInsetHit(getLyXText(bv), tmp_x, tmp_y, button);
772
773         hideInsetCursor(bv);
774         if (the_locking_inset) {
775                 if (the_locking_inset == inset) {
776                         the_locking_inset->insetButtonPress(bv,x-inset_x,y-inset_y,button);
777                         no_selection = false;
778                         return;
779                 } else if (inset) {
780                         // otherwise unlock the_locking_inset and lock the new inset
781                         the_locking_inset->insetUnlock(bv);
782                         inset_x = cx(bv) - top_x + drawTextXOffset;
783                         inset_y = cy(bv) + drawTextYOffset;
784                         the_locking_inset = static_cast<UpdatableInset*>(inset);
785                         inset->insetButtonPress(bv, x - inset_x, y - inset_y, button);
786                         inset->edit(bv, x - inset_x, y - inset_y, button);
787                         if (the_locking_inset)
788                                 updateLocal(bv, CURSOR, false);
789                         no_selection = false;
790                         return;
791                 }
792                 // otherwise only unlock the_locking_inset
793                 the_locking_inset->insetUnlock(bv);
794                 the_locking_inset = 0;
795         }
796         if (bv->theLockingInset()) {
797                 if (inset && inset->editable() == Inset::HIGHLY_EDITABLE) {
798                         UpdatableInset * uinset = static_cast<UpdatableInset*>(inset);
799                         inset_x = cx(bv) - top_x + drawTextXOffset;
800                         inset_y = cy(bv) + drawTextYOffset;
801                         inset_pos = cpos(bv);
802                         inset_par = cpar(bv);
803                         inset_boundary = cboundary(bv);
804                         the_locking_inset = uinset;
805                         uinset->insetButtonPress(bv, x - inset_x, y - inset_y,
806                                                  button);
807                         uinset->edit(bv, x - inset_x, y - inset_y, 0);
808                         if (the_locking_inset)
809                                 updateLocal(bv, CURSOR, false);
810                         no_selection = false;
811                         return;
812                 }
813         }
814         if (!inset) { // && (button == 2)) {
815                 bool paste_internally = false;
816                 if ((button == 2) && getLyXText(bv)->selection.set()) {
817                         localDispatch(bv, LFUN_COPY, "");
818                         paste_internally = true;
819                 }
820                 getLyXText(bv)->setCursorFromCoordinates(bv, x-drawTextXOffset,
821                                                          y + insetAscent);
822                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
823                 updateLocal(bv, CURSOR, false);
824                 bv->owner()->setLayout(cpar(bv)->getLayout());
825                 old_par = cpar(bv);
826                 // Insert primary selection with middle mouse
827                 // if there is a local selection in the current buffer,
828                 // insert this
829                 if (button == 2) {
830                         if (paste_internally)
831                                 localDispatch(bv, LFUN_PASTE, "");
832                         else
833                                 localDispatch(bv, LFUN_PASTESELECTION,
834                                               "paragraph");
835                 }
836         }
837         showInsetCursor(bv);
838         no_selection = false;
839 }
840
841
842 void InsetText::insetButtonRelease(BufferView * bv, int x, int y, int button)
843 {
844         UpdatableInset * inset = 0;
845
846         if (the_locking_inset) {
847                 the_locking_inset->insetButtonRelease(bv,
848                                                       x - inset_x, y - inset_y,
849                                                       button);
850         } else {
851                 if (cpar(bv)->getChar(cpos(bv)) == Paragraph::META_INSET) {
852                         inset = static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
853                         if (inset->editable() == Inset::HIGHLY_EDITABLE) {
854                                 inset->insetButtonRelease(bv,
855                                                           x - inset_x,
856                                                           y - inset_y, button);
857                         } else {
858                                 inset_x = cx(bv) - top_x + drawTextXOffset;
859                                 inset_y = cy(bv) + drawTextYOffset;
860                                 inset->insetButtonRelease(bv,
861                                                           x - inset_x,
862                                                           y - inset_y, button);
863                                 inset->edit(bv,
864                                             x - inset_x, y - inset_y, button);
865                         }
866                         updateLocal(bv, CURSOR_PAR, false);
867                 }
868         }
869         no_selection = false;
870 }
871
872
873 void InsetText::insetMotionNotify(BufferView * bv, int x, int y, int state)
874 {
875         if (no_selection)
876                 return;
877         if (the_locking_inset) {
878                 the_locking_inset->insetMotionNotify(bv, x - inset_x,
879                                                      y - inset_y,state);
880                 return;
881         }
882         LyXText * t = getLyXText(bv);
883         hideInsetCursor(bv);
884         t->setCursorFromCoordinates(bv, x - drawTextXOffset, y + insetAscent);
885         t->setSelection(bv);
886         if (t->toggle_cursor.par() != t->toggle_end_cursor.par() ||
887                 t->toggle_cursor.pos() != t->toggle_end_cursor.pos())
888                 updateLocal(bv, SELECTION, false);
889         showInsetCursor(bv);
890 }
891
892
893 void InsetText::insetKeyPress(XKeyEvent * xke)
894 {
895         if (the_locking_inset) {
896                 the_locking_inset->insetKeyPress(xke);
897                 return;
898         }
899 }
900
901
902 UpdatableInset::RESULT
903 InsetText::localDispatch(BufferView * bv,
904                          kb_action action, string const & arg)
905 {
906         no_selection = false;
907         UpdatableInset::RESULT
908                 result= UpdatableInset::localDispatch(bv, action, arg);
909         if (result != UNDISPATCHED) {
910                 return DISPATCHED;
911         }
912
913         result = DISPATCHED;
914         if ((action < 0) && arg.empty())
915                 return FINISHED;
916
917         if (the_locking_inset) {
918                 result = the_locking_inset->localDispatch(bv, action, arg);
919                 if (result == DISPATCHED_NOUPDATE)
920                         return result;
921                 else if (result == DISPATCHED) {
922                         updateLocal(bv, CURSOR_PAR, false);
923                         return result;
924                 } else if (result == FINISHED) {
925                         bool dispatched = false;
926                         switch (action) {
927                         case LFUN_UNKNOWN_ACTION:
928                         case LFUN_BREAKPARAGRAPH:
929                         case LFUN_BREAKLINE:
930                                 moveRightIntern(bv, false, false);
931                                 break;
932                         case LFUN_RIGHT:
933                                 if (!getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
934                                         moveRightIntern(bv, false, false);
935                                 dispatched = true;
936                                 break;
937                         case LFUN_LEFT:
938                                 if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
939                                         moveRightIntern(bv, false, false);
940                                 dispatched = true;
941                                 break;
942                         default:
943                                 break;
944                         }
945                         the_locking_inset = 0;
946                         if (dispatched)
947                                 return DISPATCHED;
948                 }
949         }
950         hideInsetCursor(bv);
951         bool clear = false;
952         if (!lt) {
953                 lt = getLyXText(bv);
954                 clear = true;
955         }
956         switch (action) {
957         // Normal chars
958         case LFUN_SELFINSERT:
959                 if (bv->buffer()->isReadonly()) {
960 //          setErrorMessage(N_("Document is read only"));
961                         break;
962                 }
963                 if (!arg.empty()) {
964                         /* Automatically delete the currently selected
965                          * text and replace it with what is being
966                          * typed in now. Depends on lyxrc settings
967                          * "auto_region_delete", which defaults to
968                          * true (on). */
969
970                         setUndo(bv, Undo::INSERT,
971                                 lt->cursor.par(), lt->cursor.par()->next());
972                         bv->setState();
973                         if (lyxrc.auto_region_delete) {
974                                 if (lt->selection.set()) {
975                                         lt->cutSelection(bv, false);
976                                 }
977                         }
978                         lt->clearSelection(bv);
979                         for (string::size_type i = 0; i < arg.length(); ++i) {
980                                 if (greek_kb_flag) {
981                                         if (!math_insert_greek(bv, arg[i])) {
982                                                 bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
983                                         } else if (!the_locking_inset) {
984                                                 (void)moveRight(bv, false);
985                                         }
986                                 } else {
987                                         bv->owner()->getIntl()->getTrans().TranslateAndInsert(arg[i], lt);
988                                 }
989                         }
990                 }
991                 lt->selection.cursor = lt->cursor;
992                 updateLocal(bv, CURSOR_PAR, true);
993                 result = DISPATCHED_NOUPDATE;
994                 break;
995                 // --- Cursor Movements -----------------------------------
996         case LFUN_RIGHTSEL:
997                 finishUndo();
998                 moveRight(bv, false, true);
999                 lt->setSelection(bv);
1000                 updateLocal(bv, SELECTION, false);
1001                 break;
1002         case LFUN_RIGHT:
1003                 result = moveRight(bv);
1004                 finishUndo();
1005                 updateLocal(bv, CURSOR, false);
1006                 break;
1007         case LFUN_LEFTSEL:
1008                 finishUndo();
1009                 moveLeft(bv, false, true);
1010                 lt->setSelection(bv);
1011                 updateLocal(bv, SELECTION, false);
1012                 break;
1013         case LFUN_LEFT:
1014                 finishUndo();
1015                 result = moveLeft(bv);
1016                 updateLocal(bv, CURSOR, false);
1017                 break;
1018         case LFUN_DOWNSEL:
1019                 finishUndo();
1020                 moveDown(bv);
1021                 lt->setSelection(bv);
1022                 updateLocal(bv, SELECTION, false);
1023                 break;
1024         case LFUN_DOWN:
1025                 finishUndo();
1026                 result = moveDown(bv);
1027                 updateLocal(bv, CURSOR, false);
1028                 break;
1029         case LFUN_UPSEL:
1030                 finishUndo();
1031                 moveUp(bv);
1032                 lt->setSelection(bv);
1033                 updateLocal(bv, SELECTION, false);
1034                 break;
1035         case LFUN_UP:
1036                 finishUndo();
1037                 result = moveUp(bv);
1038                 updateLocal(bv, CURSOR, false);
1039                 break;
1040         case LFUN_HOME:
1041                 finishUndo();
1042                 lt->cursorHome(bv);
1043                 updateLocal(bv, CURSOR, false);
1044                 break;
1045         case LFUN_END:
1046                 lt->cursorEnd(bv);
1047                 updateLocal(bv, CURSOR, false);
1048                 break;
1049         case LFUN_BACKSPACE: {
1050                 setUndo(bv, Undo::DELETE,
1051                         lt->cursor.par(), lt->cursor.par()->next());
1052                 if (lt->selection.set())
1053                         lt->cutSelection(bv);
1054                 else
1055                         lt->backspace(bv);
1056                 updateLocal(bv, CURSOR_PAR, true);
1057         }
1058         break;
1059         
1060         case LFUN_DELETE: {
1061                 setUndo(bv, Undo::DELETE,
1062                         lt->cursor.par(), lt->cursor.par()->next());
1063                 if (lt->selection.set()) {
1064                         lt->cutSelection(bv);
1065                 } else {
1066                         lt->Delete(bv);
1067                 }
1068                 updateLocal(bv, CURSOR_PAR, true);
1069         }
1070         break;
1071         
1072         case LFUN_CUT: {
1073                 setUndo(bv, Undo::DELETE,
1074                         lt->cursor.par(), lt->cursor.par()->next());
1075                 lt->cutSelection(bv);
1076                 updateLocal(bv, CURSOR_PAR, true);
1077         }
1078         break;
1079
1080         case LFUN_COPY:
1081                 finishUndo();
1082                 lt->copySelection(bv);
1083                 updateLocal(bv, CURSOR_PAR, false);
1084                 break;
1085         case LFUN_PASTESELECTION:
1086         {
1087                 string const clip(bv->getClipboard());
1088         
1089                 if (clip.empty())
1090                         break;
1091                 if (arg == "paragraph") {
1092                         lt->insertStringAsParagraphs(bv, clip);
1093                 } else {
1094                         lt->insertStringAsLines(bv, clip);
1095                 }
1096                 updateLocal(bv, CURSOR_PAR, true);
1097                 break;
1098         }
1099         case LFUN_PASTE: {
1100                 if (!autoBreakRows) {
1101
1102                         if (CutAndPaste::nrOfParagraphs() > 1) {
1103                                 WriteAlert(_("Impossible operation"),
1104                                                    _("Cannot include more than one paragraph!"),
1105                                                    _("Sorry."));
1106                                 break;
1107                         }
1108                 }
1109                 setUndo(bv, Undo::INSERT,
1110                         lt->cursor.par(), lt->cursor.par()->next());
1111                 lt->pasteSelection(bv);
1112                 updateLocal(bv, CURSOR_PAR, true);
1113         }
1114         break;
1115
1116         case LFUN_BREAKPARAGRAPH:
1117                 if (!autoBreakRows) {
1118                         result = DISPATCHED;
1119                         break;
1120                 }
1121                 lt->breakParagraph(bv, 0);
1122                 updateLocal(bv, FULL, true);
1123                 break;
1124         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
1125                 if (!autoBreakRows) {
1126                         result = DISPATCHED;
1127                         break;
1128                 }
1129                 lt->breakParagraph(bv, 1);
1130                 updateLocal(bv, FULL, true);
1131                 break;
1132
1133         case LFUN_BREAKLINE: {
1134                 if (!autoBreakRows) {
1135                         result = DISPATCHED;
1136                         break;
1137                 }
1138                 setUndo(bv, Undo::INSERT,
1139                         lt->cursor.par(), lt->cursor.par()->next());
1140                 lt->insertChar(bv, Paragraph::META_NEWLINE);
1141                 updateLocal(bv, CURSOR_PAR, true);
1142         }
1143         break;
1144
1145         case LFUN_LAYOUT:
1146                 // do not set layouts on non breakable textinsets
1147                 if (autoBreakRows) {
1148                         LyXTextClass::size_type cur_layout = cpar(bv)->layout;
1149           
1150                         // Derive layout number from given argument (string)
1151                         // and current buffer's textclass (number). */    
1152                         LyXTextClassList::ClassList::size_type tclass =
1153                                 bv->buffer()->params.textclass;
1154                         std::pair <bool, LyXTextClass::size_type> layout = 
1155                                 textclasslist.NumberOfLayout(tclass, arg);
1156
1157                         // If the entry is obsolete, use the new one instead.
1158                         if (layout.first) {
1159                                 string obs = textclasslist.Style(tclass,layout.second).
1160                                         obsoleted_by();
1161                                 if (!obs.empty()) 
1162                                         layout = textclasslist.NumberOfLayout(tclass, obs);
1163                         }
1164
1165                         // see if we found the layout number:
1166                         if (!layout.first) {
1167                                 string const msg = string(N_("Layout ")) + arg + N_(" not known");
1168                                 bv->owner()->getLyXFunc()->dispatch(LFUN_MESSAGE, msg);
1169                                 break;
1170                         }
1171
1172                         if (cur_layout != layout.second) {
1173                                 cur_layout = layout.second;
1174                                 lt->setLayout(bv, layout.second);
1175                                 bv->owner()->setLayout(cpar(bv)->getLayout());
1176                                 updateLocal(bv, CURSOR_PAR, true);
1177                         }
1178                 } else {
1179                         // reset the layout box
1180                         bv->owner()->setLayout(cpar(bv)->getLayout());
1181                 }
1182                 break;
1183         case LFUN_PARAGRAPH_SPACING:
1184                 // This one is absolutely not working. When fiddling with this
1185                 // it also seems to me that the paragraphs inside the insettext
1186                 // inherit bufferparams/paragraphparams in a strange way. (Lgb)
1187         {
1188                 Paragraph * par = lt->cursor.par();
1189                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
1190                 float cur_value = 1.0;
1191                 if (cur_spacing == Spacing::Other) {
1192                         cur_value = par->params().spacing().getValue();
1193                 }
1194                                 
1195                 istringstream istr(arg.c_str());
1196                 string tmp;
1197                 istr >> tmp;
1198                 Spacing::Space new_spacing = cur_spacing;
1199                 float new_value = cur_value;
1200                 if (tmp.empty()) {
1201                         lyxerr << "Missing argument to `paragraph-spacing'"
1202                                    << endl;
1203                 } else if (tmp == "single") {
1204                         new_spacing = Spacing::Single;
1205                 } else if (tmp == "onehalf") {
1206                         new_spacing = Spacing::Onehalf;
1207                 } else if (tmp == "double") {
1208                         new_spacing = Spacing::Double;
1209                 } else if (tmp == "other") {
1210                         new_spacing = Spacing::Other;
1211                         float tmpval = 0.0;
1212                         istr >> tmpval;
1213                         lyxerr << "new_value = " << tmpval << endl;
1214                         if (tmpval != 0.0)
1215                                 new_value = tmpval;
1216                 } else if (tmp == "default") {
1217                         new_spacing = Spacing::Default;
1218                 } else {
1219                         lyxerr << _("Unknown spacing argument: ")
1220                                    << arg << endl;
1221                 }
1222                 if (cur_spacing != new_spacing || cur_value != new_value) {
1223                         par->params().spacing(Spacing(new_spacing, new_value));
1224                         updateLocal(bv, CURSOR_PAR, true);
1225                 }
1226         }
1227         break;
1228         
1229         default:
1230                 if (!bv->Dispatch(action, arg))
1231                         result = UNDISPATCHED;
1232                 break;
1233         }
1234
1235         /// If the action has deleted all text in the inset, we need to change the
1236         // language to the language of the surronding text.
1237         if (par->size() == 0 && !par->next()) {
1238                 LyXFont font(LyXFont::ALL_IGNORE);
1239                 font.setLanguage(bv->getParentLanguage(this));
1240                 setFont(bv, font, false);
1241         }
1242
1243         if (result != FINISHED) {
1244                 showInsetCursor(bv);
1245         } else
1246                 bv->unlockInset(this);
1247         if (clear)
1248                 lt = 0;
1249         return result;
1250 }
1251
1252
1253 int InsetText::latex(Buffer const * buf, ostream & os, bool, bool) const
1254 {
1255         TexRow texrow;
1256         buf->latexParagraphs(os, par, 0, texrow);
1257         return texrow.rows();
1258 }
1259
1260
1261 int InsetText::ascii(Buffer const * buf, ostream & os, int linelen) const
1262 {
1263         Paragraph * p = par;
1264         unsigned int lines = 0;
1265         
1266         while (p) {
1267                 string const tmp = buf->asciiParagraph(p, linelen);
1268                 lines += countChar(tmp, '\n');
1269                 os << tmp;
1270                 p = p->next();
1271         }
1272         return lines;
1273 }
1274
1275
1276 int InsetText::docBook(Buffer const * buf, ostream & os) const
1277 {
1278         Paragraph * p = par;
1279         unsigned int lines = 0;
1280         int desc = 0;
1281         
1282         string tmp;
1283         while (p) {
1284                 buf->simpleDocBookOnePar(os, tmp, p, desc, 0);
1285                 p = p->next();
1286         }
1287         
1288         return lines;
1289 }
1290
1291
1292 void InsetText::validate(LaTeXFeatures & features) const
1293 {
1294         Paragraph * p = par;
1295         while (p) {
1296                 p->validate(features);
1297                 p = p->next();
1298         }
1299 }
1300
1301
1302 int InsetText::beginningOfMainBody(Buffer const * buf, Paragraph * p) const
1303 {
1304         if (textclasslist.Style(buf->params.textclass,
1305                                 p->getLayout()).labeltype != LABEL_MANUAL)
1306                 return 0;
1307         else
1308                 return p->beginningOfMainBody();
1309 }
1310
1311
1312 void InsetText::getCursorPos(BufferView * bv,
1313                              int & x, int & y) const
1314 {
1315         if (the_locking_inset) {
1316                 the_locking_inset->getCursorPos(bv, x, y);
1317                 return;
1318         }
1319         x = cx(bv);
1320         y = cy(bv);
1321 }
1322
1323
1324 unsigned int InsetText::insetInInsetY()
1325 {
1326         if (!the_locking_inset)
1327                 return 0;
1328
1329         return (inset_y + the_locking_inset->insetInInsetY());
1330 }
1331
1332
1333 void InsetText::toggleInsetCursor(BufferView * bv)
1334 {
1335         if (the_locking_inset) {
1336                 the_locking_inset->toggleInsetCursor(bv);
1337                 return;
1338         }
1339
1340         LyXFont const font(getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv)));
1341
1342         int const asc = lyxfont::maxAscent(font);
1343         int const desc = lyxfont::maxDescent(font);
1344   
1345         if (isCursorVisible())
1346                 bv->hideLockedInsetCursor();
1347         else
1348                 bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1349         toggleCursorVisible();
1350 }
1351
1352
1353 void InsetText::showInsetCursor(BufferView * bv, bool show)
1354 {
1355         if (the_locking_inset) {
1356                 the_locking_inset->showInsetCursor(bv, show);
1357                 return;
1358         }
1359         if (!isCursorVisible()) {
1360                 LyXFont const font =
1361                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1362         
1363                 int const asc = lyxfont::maxAscent(font);
1364                 int const desc = lyxfont::maxDescent(font);
1365
1366                 bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1367                 if (show)
1368                         bv->showLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1369                 setCursorVisible(true);
1370         }
1371 }
1372
1373
1374 void InsetText::hideInsetCursor(BufferView * bv)
1375 {
1376         if (isCursorVisible()) {
1377                 bv->hideLockedInsetCursor();
1378                 setCursorVisible(false);
1379         }
1380         if (the_locking_inset)
1381                 the_locking_inset->hideInsetCursor(bv);
1382 }
1383
1384
1385 void InsetText::fitInsetCursor(BufferView * bv) const
1386 {
1387         if (the_locking_inset) {
1388                 the_locking_inset->fitInsetCursor(bv);
1389                 return;
1390         }
1391         LyXFont const font =
1392                 getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1393         
1394         int const asc = lyxfont::maxAscent(font);
1395         int const desc = lyxfont::maxDescent(font);
1396
1397         bv->fitLockedInsetCursor(cx(bv), cy(bv), asc, desc);
1398 }
1399
1400
1401 UpdatableInset::RESULT
1402 InsetText::moveRight(BufferView * bv, bool activate_inset, bool selecting)
1403 {
1404         if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1405                 return moveLeftIntern(bv, false, activate_inset, selecting);
1406         else
1407                 return moveRightIntern(bv, false, activate_inset, selecting);
1408 }
1409
1410
1411 UpdatableInset::RESULT
1412 InsetText::moveLeft(BufferView * bv, bool activate_inset, bool selecting)
1413 {
1414         if (getLyXText(bv)->cursor.par()->isRightToLeftPar(bv->buffer()->params))
1415                 return moveRightIntern(bv, true, activate_inset, selecting);
1416         else
1417                 return moveLeftIntern(bv, true, activate_inset, selecting);
1418 }
1419
1420
1421 UpdatableInset::RESULT
1422 InsetText::moveRightIntern(BufferView * bv, bool behind, 
1423                            bool activate_inset, bool selecting)
1424 {
1425         if (!cpar(bv)->next() && (cpos(bv) >= cpar(bv)->size()))
1426                 return FINISHED;
1427         if (activate_inset && checkAndActivateInset(bv, behind))
1428                 return DISPATCHED;
1429         getLyXText(bv)->cursorRight(bv);
1430         if (!selecting)
1431                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1432         return DISPATCHED_NOUPDATE;
1433 }
1434
1435
1436 UpdatableInset::RESULT
1437 InsetText::moveLeftIntern(BufferView * bv, bool behind,
1438                           bool activate_inset, bool selecting)
1439 {
1440         if (!cpar(bv)->previous() && (cpos(bv) <= 0))
1441                 return FINISHED;
1442         getLyXText(bv)->cursorLeft(bv);
1443         if (!selecting)
1444                 getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1445         if (activate_inset && checkAndActivateInset(bv, behind))
1446                 return DISPATCHED;
1447         return DISPATCHED_NOUPDATE;
1448 }
1449
1450
1451 UpdatableInset::RESULT
1452 InsetText::moveUp(BufferView * bv)
1453 {
1454         if (!crow(bv)->previous())
1455                 return FINISHED;
1456         getLyXText(bv)->cursorUp(bv);
1457         return DISPATCHED_NOUPDATE;
1458 }
1459
1460
1461 UpdatableInset::RESULT
1462 InsetText::moveDown(BufferView * bv)
1463 {
1464         if (!crow(bv)->next())
1465                 return FINISHED;
1466         getLyXText(bv)->cursorDown(bv);
1467         return DISPATCHED_NOUPDATE;
1468 }
1469
1470
1471 bool InsetText::insertInset(BufferView * bv, Inset * inset)
1472 {
1473         if (the_locking_inset) {
1474                 if (the_locking_inset->insetAllowed(inset))
1475                         return the_locking_inset->insertInset(bv, inset);
1476                 return false;
1477         }
1478         inset->setOwner(this);
1479         hideInsetCursor(bv);
1480
1481         bool clear = false;
1482         if (!lt) {
1483                 lt = getLyXText(bv);
1484                 clear = true;
1485         }
1486         lt->insertInset(bv, inset);
1487         if ((cpar(bv)->getChar(cpos(bv)) != Paragraph::META_INSET) ||
1488                 (cpar(bv)->getInset(cpos(bv)) != inset))
1489                 lt->cursorLeft(bv);
1490         bv->fitCursor(lt);
1491         updateLocal(bv, CURSOR_PAR|CURSOR, true);
1492         showInsetCursor(bv);
1493         if (clear)
1494                 lt = 0;
1495         return true;
1496 }
1497
1498
1499 bool InsetText::insetAllowed(Inset::Code code) const
1500 {
1501         if (the_locking_inset)
1502                 return the_locking_inset->insetAllowed(code);
1503         return true;
1504 }
1505
1506
1507 UpdatableInset * InsetText::getLockingInset() const
1508 {
1509         return the_locking_inset ? the_locking_inset->getLockingInset() :
1510                 const_cast<InsetText *>(this);
1511 }
1512
1513
1514 UpdatableInset * InsetText::getFirstLockingInsetOfType(Inset::Code c)
1515 {
1516         if (c == lyxCode())
1517                 return this;
1518         if (the_locking_inset)
1519                 return the_locking_inset->getFirstLockingInsetOfType(c);
1520         return 0;
1521 }
1522
1523
1524 bool InsetText::showInsetDialog(BufferView * bv) const
1525 {
1526         if (the_locking_inset)
1527                 return the_locking_inset->showInsetDialog(bv);
1528         return false;
1529 }
1530
1531
1532 std::vector<string> const InsetText::getLabelList() const 
1533 {
1534         std::vector<string> label_list;
1535
1536         Paragraph * tpar = par;
1537         while (tpar) {
1538                 Paragraph::inset_iterator beg = tpar->inset_iterator_begin();
1539                 Paragraph::inset_iterator end = tpar->inset_iterator_end();
1540                 for (; beg != end; ++beg) {
1541                         std::vector<string> const l = (*beg)->getLabelList();
1542                         label_list.insert(label_list.end(), l.begin(), l.end());
1543                 }
1544                 tpar = tpar->next();
1545         }
1546         return label_list;
1547 }
1548
1549
1550 void InsetText::setFont(BufferView * bv, LyXFont const & font, bool toggleall,
1551                         bool selectall)
1552 {
1553         if (the_locking_inset) {
1554                 the_locking_inset->setFont(bv, font, toggleall, selectall);
1555                 return;
1556         }
1557         bool clear = false;
1558         if (!lt) {
1559                 lt = getLyXText(bv);
1560                 clear = true;
1561         }
1562         if (lt->selection.set()) {
1563                 setUndo(bv, Undo::EDIT, lt->cursor.par(), lt->cursor.par()->next());
1564         }
1565         if (selectall)
1566                 selectAll(bv);
1567 #if 1
1568         lt->toggleFree(bv, font, toggleall);
1569 #else
1570         lt->setFont(bv, font, toggleall);
1571 #endif
1572         if (selectall)
1573                 lt->clearSelection(bv);
1574         bv->fitCursor(lt);
1575         if (selectall || lt->selection.set())
1576                 updateLocal(bv, FULL, true);
1577         else
1578                 updateLocal(bv, CURSOR_PAR, true);
1579         if (clear)
1580                 lt = 0;
1581 }
1582
1583
1584 bool InsetText::checkAndActivateInset(BufferView * bv, bool behind)
1585 {
1586         if (cpar(bv)->getChar(cpos(bv)) == Paragraph::META_INSET) {
1587                 unsigned int x;
1588                 unsigned int y;
1589                 Inset * inset =
1590                         static_cast<UpdatableInset*>(cpar(bv)->getInset(cpos(bv)));
1591                 if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
1592                         return false;
1593                 LyXFont const font =
1594                         getLyXText(bv)->getFont(bv->buffer(), cpar(bv), cpos(bv));
1595                 if (behind) {
1596                         x = inset->width(bv, font);
1597                         y = font.isRightToLeft() ? 0 : inset->descent(bv, font);
1598                 } else {
1599                         x = 0;
1600                         y = font.isRightToLeft() ? inset->descent(bv, font) : 0;
1601                 }
1602                 //inset_x = cx(bv) - top_x + drawTextXOffset;
1603                 //inset_y = cy(bv) + drawTextYOffset;
1604                 inset->edit(bv, x, y, 0);
1605                 if (!the_locking_inset)
1606                         return false;
1607                 updateLocal(bv, CURSOR, false);
1608                 return true;
1609         }
1610         return false;
1611 }
1612
1613
1614 bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
1615                                       int button)
1616 {
1617         x -= drawTextXOffset;
1618         int dummyx = x;
1619         int dummyy = y + insetAscent;
1620         Inset * inset = bv->checkInsetHit(getLyXText(bv), dummyx, dummyy, button);
1621
1622         if (inset) {
1623                 if (x < 0)
1624                         x = insetWidth;
1625                 if (y < 0)
1626                         y = insetDescent;
1627                 inset_x = cx(bv) - top_x + drawTextXOffset;
1628                 inset_y = cy(bv) + drawTextYOffset;
1629                 inset->edit(bv, x - inset_x, y - inset_y, button);
1630                 if (!the_locking_inset)
1631                         return false;
1632                 updateLocal(bv, CURSOR, false);
1633                 return true;
1634         }
1635         return false;
1636 }
1637
1638
1639 int InsetText::getMaxWidth(BufferView * bv, UpdatableInset const * inset) const
1640 {
1641         int w = UpdatableInset::getMaxWidth(bv, inset);
1642         if (w < 0) {
1643                 return w;
1644         }
1645         if (owner()) {
1646                 w = w - top_x + owner()->x();
1647                 return w;
1648         }
1649         w -= (2 * TEXT_TO_INSET_OFFSET);
1650         return w - top_x;
1651 //    return  w - (2*TEXT_TO_INSET_OFFSET);
1652 }
1653
1654
1655 void InsetText::setParagraphData(Paragraph * p)
1656 {
1657         cached_bview = 0;
1658
1659         // now also delete all caches this should be safe, hopefully
1660         cache.clear();
1661
1662         while (par) {
1663                 Paragraph * tmp = par->next();
1664                 delete par;
1665                 par = tmp;
1666         }
1667
1668         par = new Paragraph(*p);
1669         par->setInsetOwner(this);
1670         Paragraph * np = par;
1671         while (p->next()) {
1672                 p = p->next();
1673                 np->next(new Paragraph(*p));
1674                 np->next()->previous(np);
1675                 np = np->next();
1676                 np->setInsetOwner(this);
1677         }
1678
1679         need_update = INIT;
1680 }
1681
1682
1683 void InsetText::setText(string const & data)
1684 {
1685         clear();
1686         LyXFont font(LyXFont::ALL_SANE);
1687         for (unsigned int i=0; i < data.length(); ++i)
1688                 par->insertChar(i, data[i], font);
1689 }
1690
1691
1692 void InsetText::setAutoBreakRows(bool flag)
1693 {
1694         if (flag != autoBreakRows) {
1695                 autoBreakRows = flag;
1696                 need_update = FULL;
1697                 if (!flag)
1698                         removeNewlines();
1699         }
1700 }
1701
1702
1703 void InsetText::setDrawFrame(BufferView * bv, DrawFrame how)
1704 {
1705         if (how != drawFrame_) {
1706                 drawFrame_ = how;
1707                 if (bv)
1708                         updateLocal(bv, DRAW_FRAME, false);
1709         }
1710 }
1711
1712
1713 void InsetText::setFrameColor(BufferView * bv, LColor::color col)
1714 {
1715         if (frame_color != col) {
1716                 frame_color = col;
1717                 if (bv)
1718                         updateLocal(bv, DRAW_FRAME, false);
1719         }
1720 }
1721
1722
1723 int InsetText::cx(BufferView * bv) const
1724 {
1725         bool clear = false;
1726         if (!lt) {
1727                 lt = getLyXText(bv);
1728                 clear = true;
1729         }
1730         int x = lt->cursor.x() + top_x + TEXT_TO_INSET_OFFSET;
1731         if (the_locking_inset) {
1732                 LyXFont font = lt->getFont(bv->buffer(),
1733                                              lt->cursor.par(),
1734                                              lt->cursor.pos());
1735                 if (font.isVisibleRightToLeft())
1736                         x -= the_locking_inset->width(bv, font);
1737         }
1738         if (clear)
1739                 lt = 0;
1740         return x;
1741 }
1742
1743
1744 int InsetText::cy(BufferView * bv) const
1745 {
1746         LyXFont font;
1747         return getLyXText(bv)->cursor.y() - ascent(bv, font) + TEXT_TO_INSET_OFFSET;
1748 }
1749
1750
1751 Paragraph::size_type InsetText::cpos(BufferView * bv) const
1752 {
1753         return getLyXText(bv)->cursor.pos();
1754 }
1755
1756
1757 Paragraph * InsetText::cpar(BufferView * bv) const
1758 {
1759         return getLyXText(bv)->cursor.par();
1760 }
1761
1762
1763 bool InsetText::cboundary(BufferView * bv) const
1764 {
1765         return getLyXText(bv)->cursor.boundary();
1766 }
1767
1768
1769 Row * InsetText::crow(BufferView * bv) const
1770 {
1771         return getLyXText(bv)->cursor.row();
1772 }
1773
1774
1775 LyXText * InsetText::getLyXText(BufferView const * lbv,
1776                                           bool const recursive) const
1777 {
1778         if (!recursive && (cached_bview == lbv))
1779                 return cached_text.get();
1780         
1781         // Super UGLY! (Lgb)
1782         BufferView * bv = const_cast<BufferView *>(lbv);
1783         
1784         cached_bview = bv;
1785         Cache::iterator it = cache.find(bv);
1786         
1787         if (it != cache.end() && (lt || !it->second.remove)) {
1788                 lyx::Assert(it->second.text.get());
1789                         
1790                 cached_text = it->second.text;
1791                 if (recursive && the_locking_inset) {
1792                         return the_locking_inset->getLyXText(bv);
1793                 }
1794                 return cached_text.get();
1795         } else if (it->second.remove) {
1796                 if (locked) {
1797                         saveLyXTextState(it->second.text.get());
1798                 } else {
1799                         sstate.lpar = 0;
1800                 }
1801                 cache.erase(bv);
1802 //              raise(SIGSTOP);
1803         }
1804
1805         cached_text.reset(new LyXText(const_cast<InsetText *>(this)));
1806         cached_text->init(bv);
1807         restoreLyXTextState(bv, cached_text.get());
1808
1809         cache.insert(make_pair(bv, cached_text));
1810         
1811         if (the_locking_inset && recursive) {
1812                 return the_locking_inset->getLyXText(bv);
1813         }
1814         return cached_text.get();
1815 }
1816
1817
1818 void InsetText::deleteLyXText(BufferView * bv, bool recursive) const
1819 {
1820         cached_bview = 0;
1821
1822         Cache::iterator it = cache.find(bv);
1823         
1824         if (it == cache.end()) {
1825                 return;
1826         }
1827
1828         lyx::Assert(it->second.text.get());
1829
1830         it->second.remove = true;
1831         if (recursive) {
1832                 /// then remove all LyXText in text-insets
1833                 Paragraph * p = par;
1834                 for (; p; p = p->next()) {
1835                         p->deleteInsetsLyXText(bv);
1836                 }
1837         }
1838 }
1839
1840
1841 void InsetText::resizeLyXText(BufferView * bv, bool force) const
1842 {
1843         if (!par->next() && !par->size()) // no data, resize not neccessary!
1844                 return;
1845         // one endless line, resize normally not necessary
1846         if (!force && getMaxWidth(bv, this) < 0)
1847                 return;
1848
1849         Cache::iterator it = cache.find(bv);
1850         if (it == cache.end()) {
1851                 return;
1852         }
1853         lyx::Assert(it->second.text.get());
1854
1855         LyXText * t = it->second.text.get();
1856         saveLyXTextState(t);
1857         for (Paragraph * p = par; p; p = p->next()) {
1858                 p->resizeInsetsLyXText(bv);
1859         }
1860         t->init(bv, true);
1861         restoreLyXTextState(bv, t);
1862         if (the_locking_inset) {
1863                 inset_x = cx(bv) - top_x + drawTextXOffset;
1864                 inset_y = cy(bv) + drawTextYOffset;
1865         }
1866
1867         if (bv->screen()) {
1868                         t->first = bv->screen()->topCursorVisible(t);
1869         }
1870         if (!owner())
1871                 updateLocal(bv, FULL, false);
1872         else
1873                 need_update = FULL;
1874         // this will scroll the screen such that the cursor becomes visible 
1875         bv->updateScrollbar();
1876 }
1877
1878
1879 void InsetText::removeNewlines()
1880 {
1881         for (Paragraph * p = par; p; p = p->next()) {
1882                 for (int i = 0; i < p->size(); ++i) {
1883                         if (p->getChar(i) == Paragraph::META_NEWLINE)
1884                                 p->erase(i);
1885                 }
1886         }
1887 }
1888
1889
1890 bool InsetText::nodraw() const
1891 {
1892         if (the_locking_inset)
1893                 return the_locking_inset->nodraw();
1894         return UpdatableInset::nodraw();
1895 }
1896
1897
1898 int InsetText::scroll(bool recursive) const
1899 {
1900         int sx = UpdatableInset::scroll(false);
1901
1902         if (recursive && the_locking_inset)
1903                 sx += the_locking_inset->scroll(recursive);
1904
1905         return sx;
1906 }
1907
1908
1909 bool InsetText::doClearArea() const
1910 {
1911         return !locked || (need_update & (FULL|INIT));
1912 }
1913
1914
1915 void InsetText::selectAll(BufferView * bv)
1916 {
1917         getLyXText(bv)->cursorTop(bv);
1918         getLyXText(bv)->selection.cursor = getLyXText(bv)->cursor;
1919         getLyXText(bv)->cursorBottom(bv);
1920         getLyXText(bv)->setSelection(bv);
1921 }
1922
1923
1924 void InsetText::clearSelection(BufferView * bv)
1925 {
1926         getLyXText(bv)->clearSelection(bv);
1927 }
1928
1929
1930 void InsetText::clearInset(Painter & pain, int baseline, bool & cleared) const
1931 {
1932         int w =  insetWidth;
1933         int h = insetAscent + insetDescent;
1934         int ty = baseline - insetAscent;
1935         
1936         if (ty < 0) {
1937                 h += ty;
1938                 ty = 0;
1939         }
1940         if ((ty + h) > pain.paperHeight())
1941                 h = pain.paperHeight();
1942         if ((top_x + drawTextXOffset + w) > pain.paperWidth())
1943                 w = pain.paperWidth();
1944         pain.fillRectangle(top_x+drawTextXOffset, ty, w, h);
1945         cleared = true;
1946         need_update = FULL;
1947 }
1948
1949
1950 Paragraph * InsetText::getParFromID(int id) const
1951 {
1952         Paragraph * result = par;
1953         Paragraph * ires = 0;
1954         while (result && result->id() != id) {
1955                 if ((ires = result->getParFromID(id)))
1956                         return ires;
1957                 result = result->next();
1958         }
1959         return result;
1960 }
1961
1962
1963 Paragraph * InsetText::firstParagraph() const
1964 {
1965         Paragraph * result;
1966         if (the_locking_inset)
1967                 if ((result = the_locking_inset->firstParagraph()))
1968                         return result;
1969         return par;
1970 }
1971
1972
1973 LyXCursor const & InsetText::cursor(BufferView * bv) const
1974 {
1975                 if (the_locking_inset)
1976                                 return the_locking_inset->cursor(bv);
1977                 return getLyXText(bv)->cursor;
1978 }
1979
1980
1981 Paragraph * InsetText::paragraph() const
1982 {
1983         return par;
1984 }
1985
1986
1987 void InsetText::paragraph(Paragraph * p)
1988 {
1989         par = p;
1990 #if 0
1991         // we now have to update/redraw all instances
1992         for (Cache::iterator cit = cache.begin(); cit != cache.end(); ++cit) {
1993                 delete cit->second;
1994                 cit->second = 0;
1995         }
1996 #endif
1997         // redraw myself when asked for
1998         need_update |= INIT;
1999 }
2000
2001
2002 Inset * InsetText::getInsetFromID(int id_arg) const
2003 {
2004         if (id_arg == id())
2005                 return const_cast<InsetText *>(this);
2006
2007         Paragraph * lp = par;
2008
2009         while(lp) {
2010                 for (Paragraph::inset_iterator it = lp->inset_iterator_begin(),
2011                          en = lp->inset_iterator_end();
2012                          it != en; ++it)
2013                 {
2014                         if ((*it)->id() == id_arg)
2015                                 return *it;
2016                         Inset * in = (*it)->getInsetFromID(id_arg);
2017                         if (in)
2018                                 return in;
2019                 }
2020                 lp = lp->next();
2021         }
2022         return 0;
2023 }
2024
2025
2026 string InsetText::selectNextWord(BufferView * bv, float & value) const
2027 {
2028         bool clear = false;
2029         string str;
2030
2031         if (!lt) {
2032                 lt = getLyXText(bv);
2033                 clear = true;
2034         }
2035         if (the_locking_inset) {
2036                 str = the_locking_inset->selectNextWord(bv, value);
2037                 if (!str.empty()) {
2038                         value += cy(bv);
2039                         if (clear)
2040                                 lt = 0;
2041                         return str;
2042                 }
2043 #warning Dekel please have a look on this one RTL? (Jug)
2044                 // we have to go on checking so move cusor to the right
2045                 lt->cursor.pos(lt->cursor.pos() + 1);
2046         }
2047         str = lt->selectNextWord(bv, value);
2048         if (str.empty())
2049                 bv->unlockInset(const_cast<InsetText *>(this));
2050         else
2051                 value = cy(bv);
2052         if (clear)
2053                 lt = 0;
2054         return str;
2055 }
2056
2057
2058 void InsetText::selectSelectedWord(BufferView * bv)
2059 {
2060         if (the_locking_inset) {
2061                 the_locking_inset->selectSelectedWord(bv);
2062                 return;
2063         }
2064         getLyXText(bv)->selectSelectedWord(bv);
2065         updateLocal(bv, SELECTION, false);
2066 }
2067
2068
2069 void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
2070 {
2071         if (the_locking_inset) {
2072                 the_locking_inset->toggleSelection(bv, kill_selection);
2073         }
2074         bool clear = false;
2075         if (!lt) {
2076                 lt = getLyXText(bv);
2077                 clear = true;
2078         }
2079
2080         int x = top_x + TEXT_TO_INSET_OFFSET;
2081
2082         int y = 0;
2083         Row * row = lt->getRowNearY(y);
2084         int y_offset = top_baseline - row->ascent_of_text();
2085         y = y_offset;
2086         while ((row != 0) && ((y+row->height()) <= 0)) {
2087                 y += row->height();
2088                 row = row->next();
2089         }
2090         if (y_offset < 0)
2091                 y_offset = y;
2092         
2093         if (need_update & SELECTION)
2094                 need_update = NONE;
2095         bv->screen()->toggleSelection(lt, bv, kill_selection, y_offset, x);
2096         if (clear)
2097                 lt = 0;
2098 }
2099
2100
2101 bool InsetText::searchForward(BufferView * bv, string const & str,
2102                               bool const & cs, bool const & mw)
2103 {
2104         if (the_locking_inset)
2105                 if (the_locking_inset->searchForward(bv, str, cs, mw))
2106                         return true;
2107         if (LyXFind(bv, str, true, true, cs , mw)) {
2108                 return true;
2109         }
2110         // we have to unlock ourself in this function by default!
2111         bv->unlockInset(const_cast<InsetText *>(this));
2112         return false;
2113 }
2114
2115 bool InsetText::searchBackward(BufferView * bv, string const & str,
2116                                bool const & cs, bool const & mw)
2117 {
2118         if (the_locking_inset)
2119                 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2120                         return true;
2121         if (LyXFind(bv, str, false, true, cs, mw)) {
2122                 return true;
2123         }
2124         // we have to unlock ourself in this function by default!
2125         bv->unlockInset(const_cast<InsetText *>(this));
2126         return false;
2127 }