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