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