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