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