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