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