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