]> git.lyx.org Git - lyx.git/blob - src/text2.C
c0ae0663ed2ce7586c7229ee377f05e3c4de653c
[lyx.git] / src / text2.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2001 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include FORMS_H_LOCATION
14
15
16 #ifdef __GNUG__
17 #pragma implementation "lyxtext.h"
18 #endif
19
20 #include "lyxtext.h"
21 #include "LString.h"
22 #include "paragraph.h"
23 #include "insets/inseterror.h"
24 #include "insets/insetbib.h"
25 #include "insets/insetspecialchar.h"
26 #include "insets/insettext.h"
27 #include "insets/insetfloat.h"
28 #include "layout.h"
29 #include "LyXView.h"
30 #include "support/textutils.h"
31 #include "undo.h"
32 #include "buffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
35 #include "gettext.h"
36 #include "BufferView.h"
37 #include "LyXView.h"
38 #include "CutAndPaste.h"
39 #include "Painter.h"
40 #include "font.h"
41 #include "debug.h"
42 #include "lyxrc.h"
43 #include "FloatList.h"
44 #include "language.h"
45 #include "ParagraphParameters.h"
46
47 using std::copy;
48 using std::find;
49 using std::endl;
50 using std::find;
51 using std::pair;
52
53
54 LyXText::LyXText(BufferView * bv)
55 {
56         bv_owner = bv;
57         inset_owner = 0;
58         init();
59 }
60
61
62 LyXText::LyXText(InsetText * inset)
63 {
64         inset_owner = inset;
65         bv_owner = 0;
66         init();
67 }
68
69
70 void LyXText::init()
71 {
72         the_locking_inset = 0;
73         firstrow = 0;
74         lastrow = 0;
75         number_of_rows = 0;
76         refresh_y = 0;
77         height = 0;
78         width = 0;
79         first = 0;
80         status = LyXText::UNCHANGED;
81
82         // set cursor at the very top position
83 #if 0
84         selection = true;           /* these setting is necessary 
85                                        because of the delete-empty-
86                                        paragraph mechanism in
87                                        SetCursor */
88 #else
89         selection.set(true);        /* these setting is necessary 
90                                        because of the delete-empty-
91                                        paragraph mechanism in
92                                        SetCursor */
93 #endif
94         if (bv_owner) {
95                 Paragraph * par = ownerParagraph();
96                 current_font = getFont(bv_owner->buffer(), par, 0);
97                 while (par) {
98                         insertParagraph(bv_owner, par, lastrow);
99                         par = par->next();
100                 }
101                 setCursor(bv_owner, firstrow->par(), 0);
102         } else
103                 current_font = LyXFont(LyXFont::ALL_SANE);
104
105 #if 0
106         sel_cursor = cursor;
107         selection = false;
108         mark_set = false;
109 #else
110         selection.cursor = cursor;
111         selection.set(false);
112         selection.mark(false);
113 #endif
114         
115         // no rebreak necessary
116         need_break_row = 0;
117    
118         undo_finished = true;
119         undo_frozen = false;
120
121         // Default layouttype for copy environment type
122         copylayouttype = 0;
123
124 #if 0
125         // Dump all rowinformation:
126         Row * tmprow = firstrow;
127         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
128         while (tmprow) {
129                 lyxerr << tmprow->baseline() << '\t'
130                        << tmprow->par << '\t'
131                        << tmprow->pos() << '\t'
132                        << tmprow->height << '\t'
133                        << tmprow->ascent_of_text << '\t'
134                        << tmprow->fill << '\n';
135                 tmprow = tmprow->next();
136         }
137         lyxerr.flush();
138 #endif
139 }
140
141
142 void LyXText::init(BufferView * bview)
143 {
144         if (firstrow)
145                 return;
146
147         Paragraph * par = ownerParagraph();
148         current_font = getFont(bview->buffer(), par, 0);
149         while (par) {
150                 insertParagraph(bview, par, lastrow);
151                 par = par->next();
152         }
153         setCursorIntern(bview, firstrow->par(), 0);
154 #if 0
155         sel_cursor = cursor;
156 #else
157         selection.cursor = cursor;
158 #endif
159 #if 0
160         printf("TP = %x\n",inset_owner->owner());
161         // Dump all rowinformation:
162         Row * tmprow = firstrow;
163         lyxerr << "Width = " << width << endl;
164         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
165         while (tmprow) {
166                 lyxerr << tmprow->baseline() << '\t'
167                        << tmprow->par() << '\t'
168                        << tmprow->pos() << '\t'
169                        << tmprow->height() << '\t'
170                        << tmprow->ascent_of_text() << '\t'
171                        << tmprow->fill() << '\n';
172                 tmprow = tmprow->next();
173         }
174         lyxerr.flush();
175 #endif
176 }
177
178 LyXText::~LyXText()
179 {
180         // Delete all rows, this does not touch the paragraphs!
181         Row * tmprow = firstrow;
182         while (firstrow) {
183                 tmprow = firstrow->next();
184                 delete firstrow;
185                 firstrow = tmprow;
186         }
187 }
188
189
190 // Gets the fully instantiated font at a given position in a paragraph
191 // Basically the same routine as Paragraph::getFont() in paragraph.C.
192 // The difference is that this one is used for displaying, and thus we
193 // are allowed to make cosmetic improvements. For instance make footnotes
194 // smaller. (Asger)
195 // If position is -1, we get the layout font of the paragraph.
196 // If position is -2, we get the font of the manual label of the paragraph.
197 LyXFont const LyXText::getFont(Buffer const * buf, Paragraph * par,
198                          Paragraph::size_type pos) const
199 {
200         LyXLayout const & layout = 
201                 textclasslist.Style(buf->params.textclass, par->getLayout());
202
203         Paragraph::depth_type par_depth = par->getDepth();
204         // We specialize the 95% common case:
205         if (!par_depth) {
206                 if (pos >= 0){
207                         // 95% goes here
208                         if (layout.labeltype == LABEL_MANUAL
209                             && pos < beginningOfMainBody(buf, par)) {
210                                 // 1% goes here
211                                 LyXFont f = par->getFontSettings(buf->params,
212                                                                  pos);
213                                 return f.realize(layout.reslabelfont);
214                         } else {
215                                 LyXFont f = par->getFontSettings(buf->params, pos);
216                                 return f.realize(layout.resfont);
217                         }
218                         
219                 } else {
220                         // 5% goes here.
221                         // process layoutfont for pos == -1 and labelfont for pos < -1
222                         if (pos == -1)
223                                 return layout.resfont;
224                         else
225                                 return layout.reslabelfont;
226                 }
227         }
228
229         // The uncommon case need not be optimized as much
230
231         LyXFont layoutfont, tmpfont;
232
233         if (pos >= 0){
234                 // 95% goes here
235                 if (pos < beginningOfMainBody(buf, par)) {
236                         // 1% goes here
237                         layoutfont = layout.labelfont;
238                 } else {
239                         // 99% goes here
240                         layoutfont = layout.font;
241                 }
242                 tmpfont = par->getFontSettings(buf->params, pos);
243                 tmpfont.realize(layoutfont);
244         } else {
245                 // 5% goes here.
246                 // process layoutfont for pos == -1 and labelfont for pos < -1
247                 if (pos == -1)
248                         tmpfont = layout.font;
249                 else
250                         tmpfont = layout.labelfont;
251         }
252
253         // Resolve against environment font information
254         while (par && par_depth && !tmpfont.resolved()) {
255                 par = par->outerHook();
256                 if (par) {
257                         tmpfont.realize(textclasslist.
258                                         Style(buf->params.textclass,
259                                               par->getLayout()).font);
260                         par_depth = par->getDepth();
261                 }
262         }
263
264         tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
265
266         return tmpfont;
267 }
268
269
270 void LyXText::setCharFont(BufferView * bv, Paragraph * par,
271                           Paragraph::size_type pos, LyXFont const & fnt,
272                           bool toggleall)
273 {
274         Buffer const * buf = bv->buffer();
275         LyXFont font = getFont(buf, par, pos);
276         font.update(fnt, buf->params.language, toggleall);
277         // Let the insets convert their font
278         if (par->getChar(pos) == Paragraph::META_INSET) {
279                 Inset * inset = par->getInset(pos);
280                 if (inset) {
281                         if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
282                                 UpdatableInset * uinset = static_cast<UpdatableInset *>(inset);
283                                 uinset->SetFont(bv, fnt, toggleall, true);
284                         }
285                         font = inset->ConvertFont(font);
286                 }
287         }
288
289         LyXLayout const & layout =
290                 textclasslist.Style(buf->params.textclass,
291                                     par->getLayout());
292
293         // Get concrete layout font to reduce against
294         LyXFont layoutfont;
295
296         if (pos < beginningOfMainBody(buf, par))
297                 layoutfont = layout.labelfont;
298         else
299                 layoutfont = layout.font;
300
301         // Realize against environment font information
302         if (par->getDepth()){
303                 Paragraph * tp = par;
304                 while (!layoutfont.resolved() && tp && tp->getDepth()) {
305                         tp = tp->outerHook();
306                         if (tp)
307                                 layoutfont.realize(textclasslist.
308                                                 Style(buf->params.textclass,
309                                                       tp->getLayout()).font);
310                 }
311         }
312
313         layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
314
315         // Now, reduce font against full layout font
316         font.reduce(layoutfont);
317
318         par->setFont(pos, font);
319 }
320
321 void LyXText::setCharFont(Buffer const * buf, Paragraph * par,
322                           Paragraph::size_type pos, LyXFont const & fnt)
323 {
324         LyXFont font(fnt);
325         // Let the insets convert their font
326         if (par->getChar(pos) == Paragraph::META_INSET) {
327                 font = par->getInset(pos)->ConvertFont(font);
328         }
329
330         LyXLayout const & layout =
331                 textclasslist.Style(buf->params.textclass,
332                                     par->getLayout());
333
334         // Get concrete layout font to reduce against
335         LyXFont layoutfont;
336
337         if (pos < beginningOfMainBody(buf, par))
338                 layoutfont = layout.labelfont;
339         else
340                 layoutfont = layout.font;
341
342         // Realize against environment font information
343         if (par->getDepth()){
344                 Paragraph * tp = par;
345                 while (!layoutfont.resolved() && tp && tp->getDepth()) {
346                         tp = tp->outerHook();
347                         if (tp)
348                                 layoutfont.realize(textclasslist.
349                                                 Style(buf->params.textclass,
350                                                       tp->getLayout()).font);
351                 }
352         }
353
354         layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
355
356         // Now, reduce font against full layout font
357         font.reduce(layoutfont);
358
359         par->setFont(pos, font);
360 }
361
362
363 /* inserts a new row behind the specified row, increments
364  * the touched counters */
365 void LyXText::insertRow(Row * row, Paragraph * par,
366                         Paragraph::size_type pos) const
367 {
368         Row * tmprow = new Row;
369         if (!row) {
370                 tmprow->previous(0);
371                 tmprow->next(firstrow);
372                 firstrow = tmprow;
373         } else {
374                 tmprow->previous(row);
375                 tmprow->next(row->next());
376                 row->next(tmprow);
377         }
378    
379         if (tmprow->next())
380                 tmprow->next()->previous(tmprow);
381    
382         if (tmprow->previous())
383                 tmprow->previous()->next(tmprow);
384    
385    
386         tmprow->par(par);
387         tmprow->pos(pos);
388
389         if (row == lastrow)
390                 lastrow = tmprow;
391         ++number_of_rows; // one more row
392 }
393
394
395 // removes the row and reset the touched counters
396 void LyXText::removeRow(Row * row) const
397 {
398         /* this must not happen before the currentrow for clear reasons.
399            so the trick is just to set the current row onto the previous
400            row of this row */
401         int unused_y;
402         getRow(row->par(), row->pos(), unused_y);
403    
404         if (row->next())
405                 row->next()->previous(row->previous());
406         if (!row->previous()) {
407                 firstrow = row->next();
408         } else  {
409                 row->previous()->next(row->next());
410         }
411         if (row == lastrow)
412                 lastrow = row->previous();
413    
414         height -= row->height(); // the text becomes smaller
415    
416         delete row;
417         --number_of_rows;       // one row less
418 }
419
420
421 // remove all following rows of the paragraph of the specified row.
422 void LyXText::removeParagraph(Row * row) const
423 {
424         Paragraph * tmppar = row->par();
425         row = row->next();
426     
427         Row * tmprow;
428         while (row && row->par() == tmppar) {
429                 tmprow = row->next();
430                 removeRow(row);
431                 row = tmprow;
432         }
433 }
434    
435
436 // insert the specified paragraph behind the specified row
437 void LyXText::insertParagraph(BufferView * bview, Paragraph * par,
438                               Row * row) const
439 {
440         insertRow(row, par, 0);        /* insert a new row, starting 
441                                         * at postition 0 */
442
443         setCounter(bview->buffer(), par);  // set the counters
444    
445         // and now append the whole paragraph behind the new row
446         if (!row) {
447                 firstrow->height(0);
448                 appendParagraph(bview, firstrow);
449         } else {
450                 row->next()->height(0);
451                 appendParagraph(bview, row->next());
452         }
453 }
454
455
456 /* used in setlayout */
457 // Asger is not sure we want to do this...
458 void LyXText::makeFontEntriesLayoutSpecific(Buffer const * buf,
459                                             Paragraph * par)
460 {
461    
462         LyXLayout const & layout =
463                 textclasslist.Style(buf->params.textclass, par->getLayout());
464
465         LyXFont layoutfont, tmpfont;
466         for (Paragraph::size_type pos = 0;
467              pos < par->size(); ++pos) {
468                 if (pos < beginningOfMainBody(buf, par))
469                         layoutfont = layout.labelfont;
470                 else
471                         layoutfont = layout.font;
472       
473                 tmpfont = par->getFontSettings(buf->params, pos);
474                 tmpfont.reduce(layoutfont);
475                 par->setFont(pos, tmpfont);
476         }
477 }
478
479
480 Paragraph * LyXText::setLayout(BufferView * bview,
481                                   LyXCursor & cur, LyXCursor & sstart_cur,
482                                   LyXCursor & send_cur,
483                                   LyXTextClass::size_type layout)
484 {
485         Paragraph * endpar = send_cur.par()->next();
486         Paragraph * undoendpar = endpar;
487         
488         if (endpar && endpar->getDepth()) {
489                 while (endpar && endpar->getDepth()) {
490                         endpar = endpar->next();
491                         undoendpar = endpar;
492                 }
493         } else if (endpar) {
494                 endpar = endpar->next(); // because of parindents etc.
495         }
496         
497         setUndo(bview->buffer(), Undo::EDIT,
498                 sstart_cur.par()->previous(),
499                 undoendpar);
500         
501         /* ok we have a selection. This is always between sstart_cur
502          * and sel_end cursor */ 
503         cur = sstart_cur;
504         
505         LyXLayout const & lyxlayout =
506                 textclasslist.Style(bview->buffer()->params.textclass, layout);
507         
508         while (cur.par() != send_cur.par()) {
509                 cur.par()->setLayout(layout);
510                 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
511                 Paragraph * fppar = cur.par();
512                 fppar->params().spaceTop(lyxlayout.fill_top ?
513                                        VSpace(VSpace::VFILL)
514                                        : VSpace(VSpace::NONE));
515                 fppar->params().spaceBottom(lyxlayout.fill_bottom ? 
516                                           VSpace(VSpace::VFILL)
517                                           : VSpace(VSpace::NONE));
518                 if (lyxlayout.margintype == MARGIN_MANUAL)
519                         cur.par()->setLabelWidthString(lyxlayout.labelstring());
520                 if (lyxlayout.labeltype != LABEL_BIBLIO
521                     && fppar->bibkey) {
522                         delete fppar->bibkey;
523                         fppar->bibkey = 0;
524                 }
525                 cur.par(cur.par()->next());
526         }
527         cur.par()->setLayout(layout);
528         makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
529         Paragraph * fppar = cur.par();
530         fppar->params().spaceTop(lyxlayout.fill_top ?
531                                VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
532         fppar->params().spaceBottom(lyxlayout.fill_bottom ? 
533                                   VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
534         if (lyxlayout.margintype == MARGIN_MANUAL)
535                 cur.par()->setLabelWidthString(lyxlayout.labelstring());
536         if (lyxlayout.labeltype != LABEL_BIBLIO
537             && fppar->bibkey) {
538                 delete fppar->bibkey;
539                 fppar->bibkey = 0;
540         }
541         return endpar;
542 }
543
544
545 // set layout over selection and make a total rebreak of those paragraphs
546 void LyXText::setLayout(BufferView * bview, LyXTextClass::size_type layout)
547 {
548 #if 0
549         LyXCursor tmpcursor = cursor;  /* store the current cursor  */
550
551         // if there is no selection just set the layout
552         // of the current paragraph  */
553         if (!selection) {
554                 sel_start_cursor = cursor;  // dummy selection
555                 sel_end_cursor = cursor;
556         }
557         Paragraph *
558                 endpar = SetLayout(bview, cursor, sel_start_cursor,
559                                    sel_end_cursor, layout);
560         RedoParagraphs(bview, sel_start_cursor, endpar);
561    
562         // we have to reset the selection, because the
563         // geometry could have changed
564         SetCursor(bview, sel_start_cursor.par(),
565                   sel_start_cursor.pos(), false);
566         sel_cursor = cursor;
567         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
568                   false);
569         UpdateCounters(bview, cursor.row());
570         ClearSelection(bview);
571         SetSelection(bview);
572         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
573 #else
574         LyXCursor tmpcursor = cursor;  /* store the current cursor  */
575
576         // if there is no selection just set the layout
577         // of the current paragraph  */
578         if (!selection.set()) {
579                 selection.start = cursor;  // dummy selection
580                 selection.end = cursor;
581         }
582         Paragraph * endpar = setLayout(bview, cursor, selection.start,
583                                           selection.end, layout);
584         redoParagraphs(bview, selection.start, endpar);
585    
586         // we have to reset the selection, because the
587         // geometry could have changed
588         setCursor(bview, selection.start.par(),
589                   selection.start.pos(), false);
590         selection.cursor = cursor;
591         setCursor(bview, selection.end.par(), selection.end.pos(),
592                   false);
593         updateCounters(bview, cursor.row());
594         clearSelection(bview);
595         setSelection(bview);
596         setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
597 #endif
598 }
599
600
601 #if 0
602 // increment depth over selection and
603 // make a total rebreak of those paragraphs
604 void  LyXText::IncDepth(BufferView * bview)
605 {
606         // If there is no selection, just use the current paragraph
607         if (!selection) {
608                 sel_start_cursor = cursor; // dummy selection
609                 sel_end_cursor = cursor;
610         }
611
612         // We end at the next paragraph with depth 0
613         Paragraph * endpar = sel_end_cursor.par()->next();
614
615         Paragraph * undoendpar = endpar;
616
617         if (endpar && endpar->getDepth()) {
618                 while (endpar && endpar->getDepth()) {
619                         endpar = endpar->next();
620                         undoendpar = endpar;
621                 }
622         }
623         else if (endpar) {
624                 endpar = endpar->next(); // because of parindents etc.
625         }
626         
627         SetUndo(bview->buffer(), Undo::EDIT,
628                 sel_start_cursor.par()->previous(),
629                 undoendpar);
630
631         LyXCursor tmpcursor = cursor; // store the current cursor
632
633         // ok we have a selection. This is always between sel_start_cursor
634         // and sel_end cursor
635         cursor = sel_start_cursor;
636    
637         bool anything_changed = false;
638    
639         while (true) {
640                 // NOTE: you can't change the depth of a bibliography entry
641                 if (
642                     textclasslist.Style(bview->buffer()->params.textclass,
643                                       cursor.par()->GetLayout()
644                                      ).labeltype != LABEL_BIBLIO) {
645                         Paragraph * prev = cursor.par()->previous();
646
647                         if (prev 
648                             && (prev->GetDepth() - cursor.par()->GetDepth() > 0
649                                 || (prev->GetDepth() == cursor.par()->GetDepth()
650                                     && textclasslist.Style(bview->buffer()->params.textclass,
651                                                       prev->GetLayout()).isEnvironment()))) {
652                                 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
653                                 anything_changed = true;
654                                 }
655                 }
656                 if (cursor.par() == sel_end_cursor.par())
657                        break;
658                 cursor.par(cursor.par()->next());
659         }
660    
661         // if nothing changed set all depth to 0
662         if (!anything_changed) {
663                 cursor = sel_start_cursor;
664                 while (cursor.par() != sel_end_cursor.par()) {
665                         cursor.par()->params.depth(0);
666                         cursor.par(cursor.par()->next());
667                 }
668                 cursor.par()->params.depth(0);
669         }
670    
671         redoParagraphs(bview, sel_start_cursor, endpar);
672    
673         // we have to reset the selection, because the
674         // geometry could have changed
675         setCursor(bview, sel_start_cursor.par(),
676                   sel_start_cursor.pos());
677         sel_cursor = cursor;
678         setCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
679         updateCounters(bview, cursor.row());
680         clearSelection(bview);
681         setSelection(bview);
682         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
683 }
684 #else
685 // increment depth over selection and
686 // make a total rebreak of those paragraphs
687 void  LyXText::incDepth(BufferView * bview)
688 {
689         // If there is no selection, just use the current paragraph
690         if (!selection.set()) {
691                 selection.start = cursor; // dummy selection
692                 selection.end = cursor;
693         }
694
695         // We end at the next paragraph with depth 0
696         Paragraph * endpar = selection.end.par()->next();
697
698         Paragraph * undoendpar = endpar;
699
700         if (endpar && endpar->getDepth()) {
701                 while (endpar && endpar->getDepth()) {
702                         endpar = endpar->next();
703                         undoendpar = endpar;
704                 }
705         }
706         else if (endpar) {
707                 endpar = endpar->next(); // because of parindents etc.
708         }
709         
710         setUndo(bview->buffer(), Undo::EDIT,
711                 selection.start.par()->previous(),
712                 undoendpar);
713
714         LyXCursor tmpcursor = cursor; // store the current cursor
715
716         // ok we have a selection. This is always between sel_start_cursor
717         // and sel_end cursor
718         cursor = selection.start;
719    
720         bool anything_changed = false;
721    
722         while (true) {
723                 // NOTE: you can't change the depth of a bibliography entry
724                 if (
725                     textclasslist.Style(bview->buffer()->params.textclass,
726                                       cursor.par()->getLayout()
727                                      ).labeltype != LABEL_BIBLIO) {
728                         Paragraph * prev = cursor.par()->previous();
729
730                         if (prev 
731                             && (prev->getDepth() - cursor.par()->getDepth() > 0
732                                 || (prev->getDepth() == cursor.par()->getDepth()
733                                     && textclasslist.Style(bview->buffer()->params.textclass,
734                                                       prev->getLayout()).isEnvironment()))) {
735                                 cursor.par()->params().depth(cursor.par()->params().depth() + 1);
736                                 anything_changed = true;
737                                 }
738                 }
739                 if (cursor.par() == selection.end.par())
740                        break;
741                 cursor.par(cursor.par()->next());
742         }
743    
744         // if nothing changed set all depth to 0
745         if (!anything_changed) {
746                 cursor = selection.start;
747                 while (cursor.par() != selection.end.par()) {
748                         cursor.par()->params().depth(0);
749                         cursor.par(cursor.par()->next());
750                 }
751                 cursor.par()->params().depth(0);
752         }
753    
754         redoParagraphs(bview, selection.start, endpar);
755    
756         // we have to reset the selection, because the
757         // geometry could have changed
758         setCursor(bview, selection.start.par(), selection.start.pos());
759         selection.cursor = cursor;
760         setCursor(bview, selection.end.par(), selection.end.pos());
761         updateCounters(bview, cursor.row());
762         clearSelection(bview);
763         setSelection(bview);
764         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
765 }
766 #endif
767
768
769 // decrement depth over selection and
770 // make a total rebreak of those paragraphs
771 void  LyXText::decDepth(BufferView * bview)
772 {
773         // if there is no selection just set the layout
774         // of the current paragraph
775         if (!selection.set()) {
776                 selection.start = cursor; // dummy selection
777                 selection.end = cursor;
778         }
779         Paragraph * endpar = selection.end.par()->next();
780         Paragraph * undoendpar = endpar;
781
782         if (endpar && endpar->getDepth()) {
783                 while (endpar && endpar->getDepth()) {
784                         endpar = endpar->next();
785                         undoendpar = endpar;
786                 }
787         } else if (endpar) {
788                 endpar = endpar->next(); // because of parindents etc.
789         }
790    
791         setUndo(bview->buffer(), Undo::EDIT,
792                 selection.start.par()->previous(),
793                 undoendpar);
794
795         LyXCursor tmpcursor = cursor; // store the current cursor
796
797         // ok we have a selection. This is always between sel_start_cursor
798         // and sel_end cursor
799         cursor = selection.start;
800
801         while (true) {
802                 if (cursor.par()->params().depth())
803                         cursor.par()->params().depth(cursor.par()->params().depth() - 1);
804                 if (cursor.par() == selection.end.par())
805                         break;
806                 cursor.par(cursor.par()->next());
807         }
808
809         redoParagraphs(bview, selection.start, endpar);
810    
811         // we have to reset the selection, because the
812         // geometry could have changed
813         setCursor(bview, selection.start.par(),
814                   selection.start.pos());
815         selection.cursor = cursor;
816         setCursor(bview, selection.end.par(), selection.end.pos());
817         updateCounters(bview, cursor.row());
818         clearSelection(bview);
819         setSelection(bview);
820         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
821 }
822
823
824 // set font over selection and make a total rebreak of those paragraphs
825 void LyXText::setFont(BufferView * bview, LyXFont const & font, bool toggleall)
826 {
827         // if there is no selection just set the current_font
828         if (!selection.set()) {
829                 // Determine basis font
830                 LyXFont layoutfont;
831                 if (cursor.pos() < beginningOfMainBody(bview->buffer(),
832                                                        cursor.par()))
833                         layoutfont = getFont(bview->buffer(), cursor.par(),-2);
834                 else
835                         layoutfont = getFont(bview->buffer(), cursor.par(),-1);
836                 // Update current font
837                 real_current_font.update(font,
838                                          bview->buffer()->params.language,
839                                          toggleall);
840
841                 // Reduce to implicit settings
842                 current_font = real_current_font;
843                 current_font.reduce(layoutfont);
844                 // And resolve it completely
845                 real_current_font.realize(layoutfont);
846                 return;
847         }
848
849         LyXCursor tmpcursor = cursor; // store the current cursor
850    
851         // ok we have a selection. This is always between sel_start_cursor
852         // and sel_end cursor
853    
854         setUndo(bview->buffer(), Undo::EDIT,
855                 selection.start.par()->previous(),
856                 selection.end.par()->next()); 
857         freezeUndo();
858         cursor = selection.start;
859         while (cursor.par() != selection.end.par() ||
860                (cursor.pos() < selection.end.pos())) {
861                 if (cursor.pos() < cursor.par()->size()) {
862                         // an open footnote should behave
863                         // like a closed one
864                         setCharFont(bview, cursor.par(), cursor.pos(), font, toggleall);
865                         cursor.pos(cursor.pos() + 1);
866                 } else {
867                         cursor.pos(0);
868                         cursor.par(cursor.par()->next());
869                 }
870         }
871         unFreezeUndo();
872    
873         redoParagraphs(bview, selection.start, selection.end.par()->next());
874    
875         // we have to reset the selection, because the
876         // geometry could have changed
877         setCursor(bview, selection.start.par(), selection.start.pos());
878         selection.cursor = cursor;
879         setCursor(bview, selection.end.par(), selection.end.pos());
880         clearSelection(bview);
881         setSelection(bview);
882         setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
883                   tmpcursor.boundary());
884 }
885
886
887 void LyXText::redoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
888 {
889         Row * tmprow = cur.row();
890         int y = cur.y() - tmprow->baseline();
891
892         setHeightOfRow(bview, tmprow);
893         Paragraph * first_phys_par = tmprow->par();
894
895         // find the first row of the paragraph
896         if (first_phys_par != tmprow->par())
897                 while (tmprow->previous()
898                        && tmprow->previous()->par() != first_phys_par) {
899                         tmprow = tmprow->previous();
900                         y -= tmprow->height();
901                         setHeightOfRow(bview, tmprow);
902                 }
903         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
904                 tmprow = tmprow->previous();
905                 y -= tmprow->height();
906                 setHeightOfRow(bview, tmprow);
907         }
908         
909         // we can set the refreshing parameters now
910         status = LyXText::NEED_MORE_REFRESH;
911         refresh_y = y;
912         refresh_row = tmprow;
913         setCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
914 }
915
916
917 void LyXText::redoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
918 {
919         Row * tmprow = cur.row();
920    
921         int y = cur.y() - tmprow->baseline();
922         setHeightOfRow(bview, tmprow);
923         Paragraph * first_phys_par = tmprow->par();
924
925         // find the first row of the paragraph
926         if (first_phys_par != tmprow->par())
927                 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par)  {
928                         tmprow = tmprow->previous();
929                         y -= tmprow->height();
930                 }
931         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par)  {
932                 tmprow = tmprow->previous();
933                 y -= tmprow->height();
934         }
935    
936         // we can set the refreshing parameters now
937         if (status == LyXText::UNCHANGED || y < refresh_y) {
938                 refresh_y = y;
939                 refresh_row = tmprow;
940         }
941         status = LyXText::NEED_MORE_REFRESH;
942         setCursor(bview, cur.par(), cur.pos());
943 }
944
945
946 /* deletes and inserts again all paragaphs between the cursor
947 * and the specified par 
948 * This function is needed after SetLayout and SetFont etc. */
949 void LyXText::redoParagraphs(BufferView * bview, LyXCursor const & cur,
950                              Paragraph const * endpar) const
951 {
952         Row * tmprow2;
953         Paragraph * tmppar = 0, * first_phys_par = 0;
954    
955         Row * tmprow = cur.row();
956    
957         int y = cur.y() - tmprow->baseline();
958    
959         if (!tmprow->previous()){
960                 first_phys_par = firstParagraph();   // a trick/hack for UNDO
961         } else {
962                 first_phys_par = tmprow->par();
963                 // find the first row of the paragraph
964                 if (first_phys_par != tmprow->par())
965                         while (tmprow->previous() &&
966                                (tmprow->previous()->par() != first_phys_par)) {
967                                 tmprow = tmprow->previous();
968                                 y -= tmprow->height();
969                         }
970                 while (tmprow->previous()
971                        && tmprow->previous()->par() == first_phys_par) {
972                         tmprow = tmprow->previous();
973                         y -= tmprow->height();
974                 }
975         }
976    
977         // we can set the refreshing parameters now
978         status = LyXText::NEED_MORE_REFRESH;
979         refresh_y = y;
980         refresh_row = tmprow->previous();        /* the real refresh row will
981                                             be deleted, so I store
982                                             the previous here */ 
983         // remove it
984         if (tmprow->next())
985                 tmppar = tmprow->next()->par();
986         else
987                 tmppar = 0;
988         while (tmppar != endpar) {
989                 removeRow(tmprow->next());
990                 if (tmprow->next())
991                         tmppar = tmprow->next()->par();
992                 else
993                         tmppar = 0;
994         }  
995    
996         // remove the first one
997         tmprow2 = tmprow;     /* this is because tmprow->previous()
998                                  can be 0 */
999         tmprow = tmprow->previous();
1000         removeRow(tmprow2);
1001    
1002         tmppar = first_phys_par;
1003
1004         do {
1005                 if (tmppar) {
1006                         insertParagraph(bview, tmppar, tmprow);
1007                         if (!tmprow)
1008                                 tmprow = firstrow;
1009                         while (tmprow->next() && tmprow->next()->par() == tmppar)
1010                                 tmprow = tmprow->next();
1011                         tmppar = tmppar->next();
1012                 }
1013         } while (tmppar != endpar);
1014    
1015         // this is because of layout changes
1016         if (refresh_row) {
1017                 refresh_y -= refresh_row->height();
1018                 setHeightOfRow(bview, refresh_row);   
1019         } else {
1020                 refresh_row = firstrow;
1021                 refresh_y = 0;
1022                 setHeightOfRow(bview, refresh_row);   
1023         }
1024    
1025         if (tmprow && tmprow->next())
1026                 setHeightOfRow(bview, tmprow->next());
1027 }
1028
1029
1030 bool LyXText::fullRebreak(BufferView * bview)
1031 {
1032         if (!firstrow) {
1033                 init(bview);
1034                 return true;
1035         }
1036         if (need_break_row) {
1037                 breakAgain(bview, need_break_row);
1038                 need_break_row = 0;
1039                 return true;
1040         }
1041         return false;
1042 }
1043
1044
1045 /* important for the screen */
1046
1047
1048 /* the cursor set functions have a special mechanism. When they
1049  * realize, that you left an empty paragraph, they will delete it.
1050  * They also delete the corresponding row */
1051    
1052 // need the selection cursor:
1053 void LyXText::setSelection(BufferView * bview)
1054 {
1055         bool const lsel = selection.set();
1056
1057         if (!selection.set()) {
1058                 last_sel_cursor = selection.cursor;
1059                 selection.start = selection.cursor;
1060                 selection.end = selection.cursor;
1061         }
1062    
1063         selection.set(true);
1064    
1065         // first the toggling area
1066         if (cursor.y() < last_sel_cursor.y()
1067             || (cursor.y() == last_sel_cursor.y()
1068              && cursor.x() < last_sel_cursor.x())) {
1069                 toggle_end_cursor = last_sel_cursor;
1070                 toggle_cursor = cursor;
1071         } else {
1072                 toggle_end_cursor = cursor;
1073                 toggle_cursor = last_sel_cursor;
1074         }
1075    
1076         last_sel_cursor = cursor;
1077    
1078         // and now the whole selection
1079
1080         if (selection.cursor.par() == cursor.par())
1081            if (selection.cursor.pos() < cursor.pos()) {
1082                 selection.end = cursor;
1083                 selection.start = selection.cursor;
1084         } else {
1085                 selection.end = selection.cursor; 
1086                 selection.start = cursor;
1087         }
1088         else if (selection.cursor.y() < cursor.y() ||
1089             (selection.cursor.y() == cursor.y() && selection.cursor.x() < cursor.x())) {
1090                 selection.end = cursor;
1091                 selection.start = selection.cursor;
1092         }
1093         else {
1094                 selection.end = selection.cursor; 
1095                 selection.start = cursor;
1096         }
1097    
1098         // a selection with no contents is not a selection
1099         if (selection.start.par() == selection.end.par() && 
1100             selection.start.pos() == selection.end.pos())
1101                 selection.set(false);
1102
1103         if (inset_owner && (selection.set() || lsel))
1104                 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1105 }
1106
1107
1108 string const LyXText::selectionAsString(Buffer const * buffer) const
1109 {
1110         if (!selection.set()) return string();
1111         string result;
1112         
1113         // Special handling if the whole selection is within one paragraph
1114         if (selection.start.par() == selection.end.par()) {
1115                 result += selection.start.par()->asString(buffer,
1116                                                          selection.start.pos(),
1117                                                          selection.end.pos());
1118                 return result;
1119         }
1120         
1121         // The selection spans more than one paragraph
1122
1123         // First paragraph in selection
1124         result += selection.start.par()->asString(buffer,
1125                                                  selection.start.pos(),
1126                                                  selection.start.par()->size())
1127                 + "\n\n";
1128         
1129         // The paragraphs in between (if any)
1130         LyXCursor tmpcur(selection.start);
1131         tmpcur.par(tmpcur.par()->next());
1132         while (tmpcur.par() != selection.end.par()) {
1133                 result += tmpcur.par()->asString(buffer, 0, tmpcur.par()->size()) + "\n\n";
1134                 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1135         }
1136
1137         // Last paragraph in selection
1138         result += selection.end.par()->asString(buffer, 0, selection.end.pos());
1139         
1140         return result;
1141 }
1142
1143
1144 void LyXText::clearSelection(BufferView * /*bview*/) const
1145 {
1146         selection.set(false);
1147         selection.mark(false);
1148         selection.end = selection.start = cursor;
1149 }
1150
1151
1152 void LyXText::cursorHome(BufferView * bview) const
1153 {
1154         setCursor(bview, cursor.par(), cursor.row()->pos());
1155 }
1156
1157
1158 void LyXText::cursorEnd(BufferView * bview) const
1159 {
1160         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1161                 setCursor(bview, cursor.par(), rowLast(cursor.row()) + 1);
1162         else {
1163                 if (cursor.par()->size() &&
1164                     (cursor.par()->getChar(rowLast(cursor.row())) == ' '
1165                      || cursor.par()->isNewline(rowLast(cursor.row()))))
1166                         setCursor(bview, cursor.par(), rowLast(cursor.row()));
1167                 else
1168                         setCursor(bview,cursor.par(), rowLast(cursor.row()) + 1);
1169         }
1170 }
1171
1172
1173 void LyXText::cursorTop(BufferView * bview) const
1174 {
1175         while (cursor.par()->previous())
1176                 cursor.par(cursor.par()->previous());
1177         setCursor(bview, cursor.par(), 0);
1178 }
1179
1180
1181 void LyXText::cursorBottom(BufferView * bview) const
1182 {
1183         while (cursor.par()->next())
1184                 cursor.par(cursor.par()->next());
1185         setCursor(bview, cursor.par(), cursor.par()->size());
1186 }
1187    
1188    
1189 void LyXText::toggleFree(BufferView * bview,
1190                          LyXFont const & font, bool toggleall)
1191 {
1192         // If the mask is completely neutral, tell user
1193         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1194                 // Could only happen with user style
1195                 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1196                 return;
1197         }
1198
1199         // Try implicit word selection
1200         // If there is a change in the language the implicit word selection 
1201         // is disabled.
1202         LyXCursor resetCursor = cursor;
1203         bool implicitSelection = (font.language() == ignore_language
1204                                   && font.number() == LyXFont::IGNORE)
1205                 ? selectWordWhenUnderCursor(bview) : false;
1206
1207         // Set font
1208         setFont(bview, font, toggleall);
1209
1210         /* Implicit selections are cleared afterwards and cursor is set to the
1211            original position. */
1212         if (implicitSelection) {
1213                 clearSelection(bview);
1214                 cursor = resetCursor;
1215                 setCursor(bview, cursor.par(), cursor.pos());
1216                 selection.cursor = cursor;
1217         }
1218         if (inset_owner)
1219                 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1220 }
1221
1222
1223 Paragraph::size_type
1224 LyXText::beginningOfMainBody(Buffer const * buf,
1225                              Paragraph const * par) const
1226 {
1227         if (textclasslist.Style(buf->params.textclass,
1228                                 par->getLayout()).labeltype != LABEL_MANUAL)
1229                 return 0;
1230         else
1231                 return par->beginningOfMainBody();
1232 }
1233
1234
1235 /* the DTP switches for paragraphs. LyX will store them in the 
1236 * first physicla paragraph. When a paragraph is broken, the top settings 
1237 * rest, the bottom settings are given to the new one. So I can make shure, 
1238 * they do not duplicate themself and you cannnot make dirty things with 
1239 * them!  */ 
1240
1241 void LyXText::setParagraph(BufferView * bview,
1242                            bool line_top, bool line_bottom,
1243                            bool pagebreak_top, bool pagebreak_bottom,
1244                            VSpace const & space_top,
1245                            VSpace const & space_bottom,
1246                            LyXAlignment align, 
1247                            string labelwidthstring,
1248                            bool noindent) 
1249 {
1250         LyXCursor tmpcursor = cursor;
1251         if (!selection.set()) {
1252                 selection.start = cursor;
1253                 selection.end = cursor;
1254         }
1255
1256         // make sure that the depth behind the selection are restored, too
1257         Paragraph * endpar = selection.end.par()->next();
1258         Paragraph * undoendpar = endpar;
1259
1260         if (endpar && endpar->getDepth()) {
1261                 while (endpar && endpar->getDepth()) {
1262                         endpar = endpar->next();
1263                         undoendpar = endpar;
1264                 }
1265         }
1266         else if (endpar) {
1267                 endpar = endpar->next(); // because of parindents etc.
1268         }
1269    
1270         setUndo(bview->buffer(), Undo::EDIT,
1271                 selection.start.par()->previous(),
1272                 undoendpar);
1273
1274         
1275         Paragraph * tmppar = selection.end.par();
1276         while (tmppar != selection.start.par()->previous()) {
1277                 setCursor(bview, tmppar, 0);
1278                 status = LyXText::NEED_MORE_REFRESH;
1279                 refresh_row = cursor.row();
1280                 refresh_y = cursor.y() - cursor.row()->baseline();
1281                         cursor.par()->params().lineTop(line_top);
1282                         cursor.par()->params().lineBottom(line_bottom);
1283                         cursor.par()->params().pagebreakTop(pagebreak_top);
1284                         cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1285                         cursor.par()->params().spaceTop(space_top);
1286                         cursor.par()->params().spaceBottom(space_bottom);
1287                         // does the layout allow the new alignment?
1288                         if (align == LYX_ALIGN_LAYOUT)
1289                                 align = textclasslist
1290                                         .Style(bview->buffer()->params.textclass,
1291                                                cursor.par()->getLayout()).align;
1292                         if (align & textclasslist
1293                             .Style(bview->buffer()->params.textclass,
1294                                    cursor.par()->getLayout()).alignpossible) {
1295                                 if (align == textclasslist
1296                                     .Style(bview->buffer()->params.textclass,
1297                                            cursor.par()->getLayout()).align)
1298                                         cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1299                                 else
1300                                         cursor.par()->params().align(align);
1301                         }
1302                         cursor.par()->setLabelWidthString(labelwidthstring);
1303                         cursor.par()->params().noindent(noindent);
1304                 tmppar = cursor.par()->previous();
1305         }
1306         
1307         redoParagraphs(bview, selection.start, endpar);
1308         
1309         clearSelection(bview);
1310         setCursor(bview, selection.start.par(), selection.start.pos());
1311         selection.cursor = cursor;
1312         setCursor(bview, selection.end.par(), selection.end.pos());
1313         setSelection(bview);
1314         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1315         if (inset_owner)
1316             bview->updateInset(inset_owner, true);
1317 }
1318
1319
1320 char loweralphaCounter(int n)
1321 {
1322         if (n < 1 || n > 26)
1323                 return '?';
1324         else
1325                 return 'a' + n - 1;
1326 }
1327
1328
1329 namespace {
1330
1331 inline
1332 char alphaCounter(int n)
1333 {
1334         if (n < 1 || n > 26)
1335                 return '?';
1336         else
1337                 return 'A' + n - 1;
1338 }
1339
1340
1341 inline
1342 char hebrewCounter(int n)
1343 {
1344         static const char hebrew[22] = {
1345                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1346                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1347                 '÷', 'ø', 'ù', 'ú'
1348         };
1349         if (n < 1 || n > 22)
1350                 return '?';
1351         else
1352                 return hebrew[n-1];
1353 }
1354
1355
1356 inline
1357 string const romanCounter(int n)
1358 {
1359         static char const * roman[20] = {
1360                 "i",   "ii",  "iii", "iv", "v",
1361                 "vi",  "vii", "viii", "ix", "x",
1362                 "xi",  "xii", "xiii", "xiv", "xv",
1363                 "xvi", "xvii", "xviii", "xix", "xx"
1364         };
1365         if (n < 1 || n > 20)
1366                 return "??";
1367         else
1368                 return roman[n-1];
1369 }
1370
1371 } // namespace anon
1372
1373
1374 // set the counter of a paragraph. This includes the labels
1375 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1376 {
1377         LyXLayout const & layout =
1378                 textclasslist.Style(buf->params.textclass, 
1379                                     par->getLayout());
1380
1381         LyXTextClass const & textclass =
1382                 textclasslist.TextClass(buf->params.textclass);
1383
1384         /* copy the prev-counters to this one, unless this is the start of a 
1385            footnote or of a bibliography or the very first paragraph */
1386         if (par->previous()
1387             && !(textclasslist.Style(buf->params.textclass,
1388                                 par->previous()->getLayout()
1389                                 ).labeltype != LABEL_BIBLIO
1390                  && layout.labeltype == LABEL_BIBLIO)) {
1391                 for (int i = 0; i < 10; ++i) {
1392                         par->setCounter(i, par->previous()->getFirstCounter(i));
1393                 }
1394                 par->params().appendix(par->previous()->params().appendix());
1395                 if (!par->params().appendix() && par->params().startOfAppendix()) {
1396                   par->params().appendix(true);
1397                   for (int i = 0; i < 10; ++i) {
1398                     par->setCounter(i, 0);
1399                   }  
1400                 }
1401                 par->enumdepth = par->previous()->enumdepth;
1402                 par->itemdepth = par->previous()->itemdepth;
1403         } else {
1404                 for (int i = 0; i < 10; ++i) {
1405                         par->setCounter(i, 0);
1406                 }  
1407                 par->params().appendix(par->params().startOfAppendix());
1408                 par->enumdepth = 0;
1409                 par->itemdepth = 0;
1410         }
1411
1412         /* Maybe we have to increment the enumeration depth.
1413          * BUT, enumeration in a footnote is considered in isolation from its
1414          *      surrounding paragraph so don't increment if this is the
1415          *      first line of the footnote
1416          * AND, bibliographies can't have their depth changed ie. they
1417          *      are always of depth 0
1418          */
1419         if (par->previous()
1420             && par->previous()->getDepth() < par->getDepth()
1421             && textclasslist.Style(buf->params.textclass,
1422                               par->previous()->getLayout()
1423                              ).labeltype == LABEL_COUNTER_ENUMI
1424             && par->enumdepth < 3
1425             && layout.labeltype != LABEL_BIBLIO) {
1426                 par->enumdepth++;
1427         }
1428
1429         /* Maybe we have to decrement the enumeration depth, see note above */
1430         if (par->previous()
1431             && par->previous()->getDepth() > par->getDepth()
1432             && layout.labeltype != LABEL_BIBLIO) {
1433                 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1434                 par->setCounter(6 + par->enumdepth,
1435                         par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1436                 /* reset the counters.
1437                  * A depth change is like a breaking layout
1438                  */
1439                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1440                         par->setCounter(i, 0);
1441         }
1442    
1443         if (!par->params().labelString().empty()) {
1444                 par->params().labelString(string());
1445         }
1446    
1447         if (layout.margintype == MARGIN_MANUAL) {
1448                 if (par->params().labelWidthString().empty()) {
1449                         par->setLabelWidthString(layout.labelstring());
1450                 }
1451         } else {
1452                 par->setLabelWidthString(string());
1453         }
1454    
1455         /* is it a layout that has an automatic label ? */ 
1456         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1457       
1458                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1459                 if (i >= 0 && i<= buf->params.secnumdepth) {
1460                         par->incCounter(i);     // increment the counter  
1461          
1462                         // Is there a label? Useful for Chapter layout
1463                         if (!par->params().appendix()) {
1464                                 if (!layout.labelstring().empty())
1465                                         par->params().labelString(layout.labelstring());
1466                                 else
1467                                         par->params().labelString(string());
1468                         } else {
1469                                 if (!layout.labelstring_appendix().empty())
1470                                         par->params().labelString(layout.labelstring_appendix());
1471                                 else
1472                                         par->params().labelString(string());
1473                         }
1474
1475                         std::ostringstream s;
1476
1477                         if (!par->params().appendix()) {
1478                                 switch (2 * LABEL_COUNTER_CHAPTER -
1479                                         textclass.maxcounter() + i) {
1480                                 case LABEL_COUNTER_CHAPTER:
1481                                         s << par->getCounter(i);
1482                                         break;
1483                                 case LABEL_COUNTER_SECTION:
1484                                         s << par->getCounter(i - 1) << '.'
1485                                            << par->getCounter(i);
1486                                         break;
1487                                 case LABEL_COUNTER_SUBSECTION:
1488                                         s << par->getCounter(i - 2) << '.'
1489                                           << par->getCounter(i - 1) << '.'
1490                                           << par->getCounter(i);
1491                                         break;
1492                                 case LABEL_COUNTER_SUBSUBSECTION:
1493                                         s << par->getCounter(i - 3) << '.'
1494                                           << par->getCounter(i - 2) << '.'
1495                                           << par->getCounter(i - 1) << '.'
1496                                           << par->getCounter(i);
1497                                         
1498                                         break;
1499                                 case LABEL_COUNTER_PARAGRAPH:
1500                                         s << par->getCounter(i - 4) << '.'
1501                                           << par->getCounter(i - 3) << '.'
1502                                           << par->getCounter(i - 2) << '.'
1503                                           << par->getCounter(i - 1) << '.'
1504                                           << par->getCounter(i);
1505                                         break;
1506                                 case LABEL_COUNTER_SUBPARAGRAPH:
1507                                         s << par->getCounter(i - 5) << '.'
1508                                           << par->getCounter(i - 4) << '.'
1509                                           << par->getCounter(i - 3) << '.'
1510                                           << par->getCounter(i - 2) << '.'
1511                                           << par->getCounter(i - 1) << '.'
1512                                           << par->getCounter(i);
1513
1514                                         break;
1515                                 default:
1516                                         // Can this ever be reached? And in the
1517                                         // case it is, how can this be correct?
1518                                         // (Lgb)
1519                                         s << par->getCounter(i) << '.';
1520                                         break;
1521                                 }
1522                         } else { // appendix
1523                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1524                                 case LABEL_COUNTER_CHAPTER:
1525                                         if (par->isRightToLeftPar(buf->params))
1526                                                 s << hebrewCounter(par->getCounter(i));
1527                                         else
1528                                                 s << alphaCounter(par->getCounter(i));
1529                                         break;
1530                                 case LABEL_COUNTER_SECTION:
1531                                         if (par->isRightToLeftPar(buf->params))
1532                                                 s << hebrewCounter(par->getCounter(i - 1));
1533                                         else
1534                                                 s << alphaCounter(par->getCounter(i - 1));
1535
1536                                         s << '.'
1537                                           << par->getCounter(i);
1538
1539                                         break;
1540                                 case LABEL_COUNTER_SUBSECTION:
1541                                         if (par->isRightToLeftPar(buf->params))
1542                                                 s << hebrewCounter(par->getCounter(i - 2));
1543                                         else
1544                                                 s << alphaCounter(par->getCounter(i - 2));
1545
1546                                         s << '.'
1547                                           << par->getCounter(i-1) << '.'
1548                                           << par->getCounter(i);
1549
1550                                         break;
1551                                 case LABEL_COUNTER_SUBSUBSECTION:
1552                                         if (par->isRightToLeftPar(buf->params))
1553                                                 s << hebrewCounter(par->getCounter(i-3));
1554                                         else
1555                                                 s << alphaCounter(par->getCounter(i-3));
1556
1557                                         s << '.'
1558                                           << par->getCounter(i-2) << '.'
1559                                           << par->getCounter(i-1) << '.'
1560                                           << par->getCounter(i);
1561
1562                                         break;
1563                                 case LABEL_COUNTER_PARAGRAPH:
1564                                         if (par->isRightToLeftPar(buf->params))
1565                                                 s << hebrewCounter(par->getCounter(i-4));
1566                                         else
1567                                                 s << alphaCounter(par->getCounter(i-4));
1568
1569                                         s << '.'
1570                                           << par->getCounter(i-3) << '.'
1571                                           << par->getCounter(i-2) << '.'
1572                                           << par->getCounter(i-1) << '.'
1573                                           << par->getCounter(i);
1574
1575                                         break;
1576                                 case LABEL_COUNTER_SUBPARAGRAPH:
1577                                         if (par->isRightToLeftPar(buf->params))
1578                                                 s << hebrewCounter(par->getCounter(i-5));
1579                                         else
1580                                                 s << alphaCounter(par->getCounter(i-5));
1581
1582                                         s << '.'
1583                                           << par->getCounter(i-4) << '.'
1584                                           << par->getCounter(i-3) << '.'
1585                                           << par->getCounter(i-2) << '.'
1586                                           << par->getCounter(i-1) << '.'
1587                                           << par->getCounter(i);
1588
1589                                         break;
1590                                 default:
1591                                         // Can this ever be reached? And in the
1592                                         // case it is, how can this be correct?
1593                                         // (Lgb)
1594                                         s << par->getCounter(i) << '.';
1595                                         
1596                                         break;
1597                                 }
1598                         }
1599
1600                         par->params().labelString(par->params().labelString() +s.str().c_str());
1601                         // We really want to remove the c_str as soon as
1602                         // possible...
1603                         
1604                         for (i++; i < 10; ++i) {
1605                                 // reset the following counters
1606                                 par->setCounter(i, 0);
1607                         }
1608                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1609                         for (i++; i < 10; ++i) {
1610                                 // reset the following counters
1611                                 par->setCounter(i, 0);
1612                         }
1613                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1614                         par->incCounter(i + par->enumdepth);
1615                         int number = par->getCounter(i + par->enumdepth);
1616
1617                         std::ostringstream s;
1618
1619                         switch (par->enumdepth) {
1620                         case 1:
1621                                 if (par->isRightToLeftPar(buf->params))
1622                                         s << '('
1623                                           << hebrewCounter(number)
1624                                           << ')';
1625                                 else
1626                                         s << '('
1627                                           << loweralphaCounter(number)
1628                                           << ')';
1629                                 break;
1630                         case 2:
1631                                 if (par->isRightToLeftPar(buf->params))
1632                                         s << '.' << romanCounter(number);
1633                                 else
1634                                         s << romanCounter(number) << '.';
1635                                 break;
1636                         case 3:
1637                                 if (par->isRightToLeftPar(buf->params))
1638                                         s << '.'
1639                                           << alphaCounter(number);
1640                                 else
1641                                         s << alphaCounter(number)
1642                                           << '.';
1643                                 break;
1644                         default:
1645                                 if (par->isRightToLeftPar(buf->params))
1646                                         s << '.' << number;
1647                                 else
1648                                         s << number << '.';
1649                                 break;
1650                         }
1651
1652                         par->params().labelString(s.str().c_str());
1653                         // we really want to get rid of that c_str()
1654
1655                         for (i += par->enumdepth + 1; i < 10; ++i)
1656                                 par->setCounter(i, 0);  /* reset the following counters  */
1657          
1658                 } 
1659         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1660                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1661                 par->incCounter(i);
1662                 int number = par->getCounter(i);
1663                 if (!par->bibkey) {
1664                         InsetCommandParams p( "bibitem" );
1665                         par->bibkey = new InsetBibKey(p);
1666                 }
1667                 par->bibkey->setCounter(number);
1668                 par->params().labelString(layout.labelstring());
1669                 
1670                 // In biblio should't be following counters but...
1671         } else {
1672                 string s = layout.labelstring();
1673                 
1674                 // the caption hack:
1675                 if (layout.labeltype == LABEL_SENSITIVE) {
1676                         bool isOK (par->InInset() && par->InInset()->owner() &&
1677                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1678                         
1679                         if (isOK) {
1680                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1681                                 Floating const & fl
1682                                         = floatList.getType(tmp->type());
1683                                 // We should get the correct number here too.
1684                                 s = fl.name() + " #:";
1685                         } else {
1686                                 /* par->SetLayout(0); 
1687                                    s = layout->labelstring;  */
1688                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1689                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1690                         }
1691                 }
1692                 par->params().labelString(s);
1693                 
1694                 /* reset the enumeration counter. They are always resetted
1695                  * when there is any other layout between */ 
1696                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1697                         par->setCounter(i, 0);
1698         }
1699 }
1700
1701
1702 /* Updates all counters BEHIND the row. Changed paragraphs
1703 * with a dynamic left margin will be rebroken. */ 
1704 void LyXText::updateCounters(BufferView * bview, Row * row) const
1705 {
1706         Paragraph * par;
1707
1708         if (!row) {
1709                 row = firstrow;
1710                 par = row->par();
1711         } else {
1712                 par = row->par()->next();
1713         }
1714
1715         while (par) {
1716                 while (row->par() != par)
1717                         row = row->next();
1718                 
1719                 setCounter(bview->buffer(), par);
1720                 
1721                 /* now  check for the headline layouts. remember that they
1722                  * have a dynamic left margin */ 
1723                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1724                                          par->layout).margintype == MARGIN_DYNAMIC
1725                      || textclasslist.Style(bview->buffer()->params.textclass,
1726                                             par->layout).labeltype == LABEL_SENSITIVE)) {
1727                         
1728                         /* Rebreak the paragraph */ 
1729                         removeParagraph(row);
1730                         appendParagraph(bview, row);
1731                 }
1732                 par = par->next();
1733         }
1734 }
1735
1736
1737 /* insets an inset. */ 
1738 void LyXText::insertInset(BufferView * bview, Inset * inset)
1739 {
1740         if (!cursor.par()->insertInsetAllowed(inset))
1741                 return;
1742         setUndo(bview->buffer(), Undo::INSERT,
1743                 cursor.par()->previous(),
1744                 cursor.par()->next());
1745         cursor.par()->insertInset(cursor.pos(), inset);
1746         insertChar(bview, Paragraph::META_INSET);  /* just to rebreak and refresh correctly.
1747                                       * The character will not be inserted a
1748                                       * second time */
1749 #if 1
1750         // If we enter a highly editable inset the cursor should be to before
1751         // the inset. This couldn't happen before as Undo was not handled inside
1752         // inset now after the Undo LyX tries to call inset->Edit(...) again
1753         // and cannot do this as the cursor is behind the inset and GetInset
1754         // does not return the inset!
1755         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1756                 cursorLeft(bview, true);
1757         }
1758 #endif
1759 }
1760
1761
1762 void LyXText::copyEnvironmentType()
1763 {
1764         copylayouttype = cursor.par()->getLayout();
1765 }
1766
1767
1768 void LyXText::pasteEnvironmentType(BufferView * bview)
1769 {
1770         setLayout(bview, copylayouttype);
1771 }
1772
1773
1774 void LyXText::cutSelection(BufferView * bview, bool doclear)
1775 {
1776         // Stuff what we got on the clipboard. Even if there is no selection.
1777
1778         // There is a problem with having the stuffing here in that the
1779         // larger the selection the slower LyX will get. This can be
1780         // solved by running the line below only when the selection has
1781         // finished. The solution used currently just works, to make it
1782         // faster we need to be more clever and probably also have more
1783         // calls to stuffClipboard. (Lgb)
1784         bview->stuffClipboard(selectionAsString(bview->buffer()));
1785
1786         // This doesn't make sense, if there is no selection
1787         if (!selection.set())
1788                 return;
1789    
1790         // OK, we have a selection. This is always between selection.start
1791         // and selection.end
1792
1793         // make sure that the depth behind the selection are restored, too
1794         Paragraph * endpar = selection.end.par()->next();
1795         Paragraph * undoendpar = endpar;
1796     
1797         if (endpar && endpar->getDepth()) {
1798                 while (endpar && endpar->getDepth()) {
1799                         endpar = endpar->next();
1800                         undoendpar = endpar;
1801                 }
1802         } else if (endpar) {
1803                 endpar = endpar->next(); // because of parindents etc.
1804         }
1805     
1806         setUndo(bview->buffer(), Undo::DELETE,
1807                 selection.start.par()->previous(),
1808                 undoendpar);
1809     
1810         CutAndPaste cap;
1811
1812         // there are two cases: cut only within one paragraph or
1813         // more than one paragraph
1814         if (selection.start.par() == selection.end.par()) {
1815                 // only within one paragraph
1816                 endpar = selection.end.par();
1817                 int pos = selection.end.pos();
1818                 cap.cutSelection(selection.start.par(), &endpar,
1819                                  selection.start.pos(), pos,
1820                                  bview->buffer()->params.textclass, doclear);
1821                 selection.end.pos(pos);
1822         } else {
1823                 endpar = selection.end.par();
1824                 int pos = selection.end.pos();
1825                 cap.cutSelection(selection.start.par(), &endpar,
1826                                  selection.start.pos(), pos,
1827                                  bview->buffer()->params.textclass, doclear);
1828                 cursor.par(endpar);
1829                 selection.end.par(endpar);
1830                 selection.end.pos(pos);
1831                 cursor.pos(selection.end.pos());
1832         }
1833         endpar = endpar->next();
1834
1835         // sometimes necessary
1836         if (doclear)
1837                 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1838
1839         redoParagraphs(bview, selection.start, endpar);
1840
1841         // cutSelection can invalidate the cursor so we need to set
1842         // it anew. (Lgb)
1843         cursor = selection.start;
1844
1845         // need a valid cursor. (Lgb)
1846         clearSelection(bview);
1847
1848         setCursor(bview, cursor.par(), cursor.pos());
1849         selection.cursor = cursor;
1850         updateCounters(bview, cursor.row());
1851 }
1852
1853
1854 void LyXText::copySelection(BufferView * bview)
1855 {
1856         // Stuff what we got on the clipboard. Even if there is no selection.
1857
1858         // There is a problem with having the stuffing here in that the
1859         // larger the selection the slower LyX will get. This can be
1860         // solved by running the line below only when the selection has
1861         // finished. The solution used currently just works, to make it
1862         // faster we need to be more clever and probably also have more
1863         // calls to stuffClipboard. (Lgb)
1864         bview->stuffClipboard(selectionAsString(bview->buffer()));
1865
1866         // this doesnt make sense, if there is no selection
1867         if (!selection.set())
1868                 return;
1869
1870         // ok we have a selection. This is always between selection.start
1871         // and sel_end cursor
1872
1873         // copy behind a space if there is one
1874         while (selection.start.par()->size() > selection.start.pos()
1875                && selection.start.par()->isLineSeparator(selection.start.pos())
1876                && (selection.start.par() != selection.end.par()
1877                    || selection.start.pos() < selection.end.pos()))
1878                 selection.start.pos(selection.start.pos() + 1); 
1879
1880         CutAndPaste cap;
1881
1882         cap.copySelection(selection.start.par(), selection.end.par(),
1883                           selection.start.pos(), selection.end.pos(),
1884                           bview->buffer()->params.textclass);
1885 }
1886
1887
1888 void LyXText::pasteSelection(BufferView * bview)
1889 {
1890         CutAndPaste cap;
1891
1892         // this does not make sense, if there is nothing to paste
1893         if (!cap.checkPastePossible(cursor.par()))
1894                 return;
1895
1896         setUndo(bview->buffer(), Undo::INSERT,
1897                 cursor.par()->previous(),
1898                 cursor.par()->next()); 
1899
1900         Paragraph * endpar;
1901         Paragraph * actpar = cursor.par();
1902
1903         int pos = cursor.pos();
1904         cap.pasteSelection(&actpar, &endpar, pos,
1905                            bview->buffer()->params.textclass);
1906     
1907         redoParagraphs(bview, cursor, endpar);
1908         
1909         setCursor(bview, cursor.par(), cursor.pos());
1910         clearSelection(bview);
1911    
1912         selection.cursor = cursor;
1913         setCursor(bview, actpar, pos);
1914         setSelection(bview);
1915         updateCounters(bview, cursor.row());
1916 }
1917
1918
1919 // returns a pointer to the very first Paragraph
1920 Paragraph * LyXText::firstParagraph() const
1921 {
1922         return ownerParagraph();
1923 }
1924
1925
1926 // sets the selection over the number of characters of string, no check!!
1927 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1928 {
1929         if (str.empty())
1930                 return;
1931         
1932         selection.cursor = cursor;
1933         for (string::size_type i = 0; i < str.length(); ++i)
1934                 cursorRight(bview);
1935         setSelection(bview);
1936 }
1937
1938
1939 // simple replacing. The font of the first selected character is used
1940 void LyXText::replaceSelectionWithString(BufferView * bview,
1941                                          string const & str)
1942 {
1943         setCursorParUndo(bview->buffer());
1944         freezeUndo();
1945
1946         if (!selection.set()) { // create a dummy selection
1947                 selection.end = cursor;
1948                 selection.start = cursor;
1949         }
1950
1951         // Get font setting before we cut
1952         Paragraph::size_type pos = selection.end.pos();
1953         LyXFont const font = selection.start.par()
1954                 ->getFontSettings(bview->buffer()->params,
1955                                   selection.start.pos());
1956
1957         // Insert the new string
1958         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1959                 selection.end.par()->insertChar(pos, (*cit), font);
1960                 ++pos;
1961         }
1962         
1963         // Cut the selection
1964         cutSelection(bview);
1965
1966         unFreezeUndo();
1967 }
1968
1969
1970 // needed to insert the selection
1971 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1972 {
1973         Paragraph * par = cursor.par();
1974         Paragraph::size_type pos = cursor.pos();
1975         Paragraph * endpar = cursor.par()->next();
1976         
1977         setCursorParUndo(bview->buffer());
1978         
1979         bool isEnvironment =
1980                 textclasslist.Style(bview->buffer()->params.textclass, 
1981                                     cursor.par()->getLayout()).isEnvironment();
1982         bool free_spacing =
1983                 textclasslist.Style(bview->buffer()->params.textclass, 
1984                                     cursor.par()->getLayout()).free_spacing;
1985         bool keepempty =
1986                 textclasslist.Style(bview->buffer()->params.textclass, 
1987                                     cursor.par()->getLayout()).keepempty;
1988
1989         // only to be sure, should not be neccessary
1990         clearSelection(bview);
1991         
1992         // insert the string, don't insert doublespace
1993         bool space_inserted = true;
1994         for(string::const_iterator cit = str.begin(); 
1995             cit != str.end(); ++cit) {
1996                 if (*cit == '\n') {
1997                         if (par->size() || keepempty) { 
1998                                 par->breakParagraph(bview->buffer()->params, 
1999                                                     pos, isEnvironment);
2000                                 par = par->next();
2001                                 pos = 0;
2002                                 space_inserted = true;
2003                         } else {
2004                                 continue;
2005                         }
2006                 // do not insert consecutive spaces if !free_spacing
2007                 } else if ((*cit == ' ' || *cit == '\t')
2008                     && space_inserted && !free_spacing) {
2009                         continue;
2010                 } else if (*cit == '\t') {
2011                         if (!free_spacing) {
2012                                 // tabs are like spaces here
2013                                 par->insertChar(pos, ' ', 
2014                                                 current_font);
2015                                 ++pos;
2016                                 space_inserted = true;
2017                         } else {
2018                                 const Paragraph::value_type nb = 8 - pos % 8;
2019                                 for (Paragraph::size_type a = 0; 
2020                                      a < nb ; ++a) {
2021                                         par->insertChar(pos, ' ', 
2022                                                         current_font);
2023                                         ++pos;
2024                                 }
2025                                 space_inserted = true;
2026                         }
2027                 } else if (!IsPrintable(*cit)) {
2028                         // Ignore unprintables
2029                         continue;
2030                 } else {
2031                         // just insert the character
2032                         par->insertChar(pos, *cit, current_font);
2033                         ++pos;
2034                         space_inserted = (*cit == ' ');
2035                 }
2036
2037         }       
2038
2039         redoParagraphs(bview, cursor, endpar);
2040         setCursor(bview, cursor.par(), cursor.pos());
2041         selection.cursor = cursor;
2042         setCursor(bview, par, pos);
2043         setSelection(bview);
2044 }
2045
2046
2047 /* turns double-CR to single CR, others where converted into one
2048    blank. Then InsertStringAsLines is called */
2049 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
2050 {
2051         string linestr(str);
2052         bool newline_inserted = false;
2053         for (string::size_type i = 0; i < linestr.length(); ++i) {
2054                 if (linestr[i] == '\n') {
2055                         if (newline_inserted) {
2056                                 // we know that \r will be ignored by
2057                                 // InsertStringA. Of course, it is a dirty
2058                                 // trick, but it works...
2059                                 linestr[i - 1] = '\r';
2060                                 linestr[i] = '\n';
2061                         } else {
2062                                 linestr[i] = ' ';
2063                                 newline_inserted = true;
2064                         } 
2065                 } else if (IsPrintable(linestr[i])) {
2066                         newline_inserted = false;
2067                 }
2068         }
2069         insertStringAsLines(bview, linestr);
2070 }
2071
2072
2073 bool LyXText::gotoNextInset(BufferView * bview,
2074                             std::vector<Inset::Code> const & codes,
2075                             string const & contents) const
2076 {
2077         LyXCursor res = cursor;
2078         Inset * inset;
2079         do {
2080                 if (res.pos() < res.par()->size() - 1) {
2081                         res.pos(res.pos() + 1);
2082                 } else  {
2083                         res.par(res.par()->next());
2084                         res.pos(0);
2085                 }
2086       
2087         } while (res.par() && 
2088                  !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
2089                    && (inset = res.par()->getInset(res.pos())) != 0
2090                    && find(codes.begin(), codes.end(), inset->LyxCode())
2091                       != codes.end()
2092                    && (contents.empty() ||
2093                        static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
2094                        == contents)));
2095
2096         if (res.par()) {
2097                 setCursor(bview, res.par(), res.pos());
2098                 return true;
2099         }
2100         return false;
2101 }
2102
2103
2104 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
2105                              Paragraph::size_type pos)
2106 {
2107         LyXCursor tmpcursor;                    
2108
2109         int y = 0;
2110         Paragraph::size_type z;
2111         Row * row = getRow(par, pos, y);
2112         
2113         // is there a break one row above
2114         if (row->previous() && row->previous()->par() == row->par()) {
2115                 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
2116                 if (z >= row->pos()) {
2117                         // set the dimensions of the row above
2118                         y -= row->previous()->height();
2119                         refresh_y = y;
2120                         refresh_row = row->previous();
2121                         status = LyXText::NEED_MORE_REFRESH;
2122                         
2123                         breakAgain(bview, row->previous());
2124                         
2125                         // set the cursor again. Otherwise
2126                         // dangling pointers are possible
2127                         setCursor(bview, cursor.par(), cursor.pos(),
2128                                   false, cursor.boundary());
2129                         selection.cursor = cursor;
2130                         return;
2131                 }
2132         }
2133
2134         int const tmpheight = row->height();
2135         Paragraph::size_type const tmplast = rowLast(row);
2136         refresh_y = y;
2137         refresh_row = row;
2138         
2139         breakAgain(bview, row);
2140         if (row->height() == tmpheight && rowLast(row) == tmplast)
2141                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2142         else
2143                 status = LyXText::NEED_MORE_REFRESH; 
2144         
2145         // check the special right address boxes
2146         if (textclasslist.Style(bview->buffer()->params.textclass,
2147                                 par->getLayout()).margintype
2148             == MARGIN_RIGHT_ADDRESS_BOX) {
2149                 tmpcursor.par(par);
2150                 tmpcursor.row(row);
2151                 tmpcursor.y(y);
2152                 tmpcursor.x(0);
2153                 tmpcursor.x_fix(0);
2154                 tmpcursor.pos(pos);
2155                 redoDrawingOfParagraph(bview, tmpcursor); 
2156         }
2157
2158         // set the cursor again. Otherwise dangling pointers are possible
2159         // also set the selection
2160    
2161         if (selection.set()) {
2162                 tmpcursor = cursor;
2163                 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2164                                 false, selection.cursor.boundary());
2165                 selection.cursor = cursor; 
2166                 setCursorIntern(bview, selection.start.par(),
2167                                 selection.start.pos(),
2168                                 false, selection.start.boundary());
2169                 selection.start = cursor; 
2170                 setCursorIntern(bview, selection.end.par(),
2171                                 selection.end.pos(),
2172                                 false, selection.end.boundary());
2173                 selection.end = cursor; 
2174                 setCursorIntern(bview, last_sel_cursor.par(),
2175                                 last_sel_cursor.pos(),
2176                                 false, last_sel_cursor.boundary());
2177                 last_sel_cursor = cursor; 
2178                 cursor = tmpcursor;
2179         }
2180         setCursorIntern(bview, cursor.par(), cursor.pos(),
2181                         false, cursor.boundary());
2182 }
2183
2184
2185 // returns false if inset wasn't found
2186 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2187 {
2188         // first check the current paragraph
2189         int pos = cursor.par()->getPositionOfInset(inset);
2190         if (pos != -1){
2191                 checkParagraph(bview, cursor.par(), pos);
2192                 return true;
2193         }
2194   
2195         // check every paragraph
2196   
2197         Paragraph * par = firstParagraph();
2198         do {
2199                         pos = par->getPositionOfInset(inset);
2200                         if (pos != -1){
2201                                 checkParagraph(bview, par, pos);
2202                                 return true;
2203                         }
2204                 par = par->next();
2205         } while (par);
2206   
2207         return false;
2208 }
2209
2210
2211 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2212                         Paragraph::size_type pos, 
2213                         bool setfont, bool boundary) const
2214 {
2215         LyXCursor old_cursor = cursor;
2216         setCursorIntern(bview, par, pos, setfont, boundary);
2217         deleteEmptyParagraphMechanism(bview, old_cursor);
2218 }
2219
2220
2221 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2222                         Paragraph::size_type pos, bool boundary) const
2223 {
2224         cur.par(par);
2225         cur.pos(pos);
2226         cur.boundary(boundary);
2227
2228         /* get the cursor y position in text  */
2229         int y = 0;
2230         Row * row = getRow(par, pos, y);
2231         /* y is now the beginning of the cursor row */ 
2232         y += row->baseline();
2233         /* y is now the cursor baseline */ 
2234         cur.y(y);
2235    
2236         /* now get the cursors x position */
2237         float x;
2238         float fill_separator;
2239         float fill_hfill;
2240         float fill_label_hfill;
2241         prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2242                        fill_label_hfill);
2243         Paragraph::size_type cursor_vpos = 0;
2244         Paragraph::size_type last = rowLastPrintable(row);
2245
2246         if (pos > last + 1)   // This shouldn't happen.
2247                 pos = last + 1;
2248         else if (pos < row->pos())
2249                 pos = row->pos();
2250
2251         if (last < row->pos())
2252                 cursor_vpos = row->pos();
2253         else if (pos > last && !boundary)
2254                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2255                         ? row->pos() : last + 1; 
2256         else if (pos > row->pos() &&
2257                  (pos > last || boundary))
2258                 /// Place cursor after char at (logical) position pos - 1
2259                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2260                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2261         else
2262                 /// Place cursor before char at (logical) position pos
2263                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2264                         ? log2vis(pos) : log2vis(pos) + 1;
2265         
2266         Paragraph::size_type main_body =
2267                 beginningOfMainBody(bview->buffer(), row->par());
2268         if ((main_body > 0) &&
2269             ((main_body-1 > last) || 
2270              !row->par()->isLineSeparator(main_body-1)))
2271                 main_body = 0;
2272         
2273         for (Paragraph::size_type vpos = row->pos();
2274              vpos < cursor_vpos; ++vpos) {
2275                 pos = vis2log(vpos);
2276                 if (main_body > 0 && pos == main_body - 1) {
2277                         x += fill_label_hfill +
2278                                 lyxfont::width(textclasslist.Style(
2279                                         bview->buffer()->params.textclass,
2280                                         row->par()->getLayout())
2281                                                .labelsep,
2282                                                getFont(bview->buffer(), row->par(), -2));
2283                         if (row->par()->isLineSeparator(main_body-1))
2284                                 x -= singleWidth(bview, row->par(),main_body-1);
2285                 }
2286                 if (hfillExpansion(bview->buffer(), row, pos)) {
2287                         x += singleWidth(bview, row->par(), pos);
2288                         if (pos >= main_body)
2289                                 x += fill_hfill;
2290                         else 
2291                                 x += fill_label_hfill;
2292                 } else if (row->par()->isSeparator(pos)) {
2293                         x += singleWidth(bview, row->par(), pos);
2294                         if (pos >= main_body)
2295                                 x += fill_separator;
2296                 } else
2297                         x += singleWidth(bview, row->par(), pos);
2298         }
2299         
2300         cur.x(int(x));
2301         cur.x_fix(cur.x());
2302         cur.row(row);
2303 }
2304
2305
2306 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2307                               Paragraph::size_type pos,
2308                               bool setfont, bool boundary) const
2309 {
2310         setCursor(bview, cursor, par, pos, boundary);
2311         if (setfont)
2312                 setCurrentFont(bview);
2313 }
2314
2315
2316 void LyXText::setCurrentFont(BufferView * bview) const
2317 {
2318         Paragraph::size_type pos = cursor.pos();
2319         if (cursor.boundary() && pos > 0)
2320                 --pos;
2321
2322         if (pos > 0) {
2323                 if (pos == cursor.par()->size())
2324                         --pos;
2325                 else // potentional bug... BUG (Lgb)
2326                 if (cursor.par()->isSeparator(pos)) {
2327                         if (pos > cursor.row()->pos() &&
2328                             bidi_level(pos) % 2 == 
2329                             bidi_level(pos - 1) % 2)
2330                                 --pos;
2331                         else if (pos + 1 < cursor.par()->size())
2332                                 ++pos;
2333                 }
2334         }
2335
2336         current_font =
2337                 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2338         real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2339
2340         if (cursor.pos() == cursor.par()->size() &&
2341             isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2342             !cursor.boundary()) {
2343                 Language const * lang =
2344                         cursor.par()->getParLanguage(bview->buffer()->params);
2345                 current_font.setLanguage(lang);
2346                 current_font.setNumber(LyXFont::OFF);
2347                 real_current_font.setLanguage(lang);
2348                 real_current_font.setNumber(LyXFont::OFF);
2349         }
2350 }
2351
2352
2353 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2354 {
2355         LyXCursor old_cursor = cursor;
2356    
2357         /* get the row first */ 
2358    
2359         Row * row = getRowNearY(y);
2360         cursor.par(row->par());
2361
2362         bool bound = false;
2363         int column = getColumnNearX(bview, row, x, bound);
2364         cursor.pos(row->pos() + column);
2365         cursor.x(x);
2366         cursor.y(y + row->baseline());
2367         cursor.row(row);
2368         cursor.boundary(bound);
2369         setCurrentFont(bview);
2370         deleteEmptyParagraphMechanism(bview, old_cursor);
2371 }
2372
2373
2374 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2375                                        int x, int y) const
2376 {
2377         /* get the row first */ 
2378    
2379         Row * row = getRowNearY(y);
2380         bool bound = false;
2381         int column = getColumnNearX(bview, row, x, bound);
2382    
2383         cur.par(row->par());
2384         cur.pos(row->pos() + column);
2385         cur.x(x);
2386         cur.y(y + row->baseline());
2387         cur.row(row);
2388         cur.boundary(bound);
2389 }
2390
2391
2392 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2393 {
2394         if (cursor.pos() > 0) {
2395                 bool boundary = cursor.boundary();
2396                 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2397                 if (!internal && !boundary &&
2398                     isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2399                         setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2400         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2401                 Paragraph * par = cursor.par()->previous();
2402                 setCursor(bview, par, par->size());
2403         }
2404 }
2405
2406
2407 void LyXText::cursorRight(BufferView * bview, bool internal) const
2408 {
2409         if (!internal && cursor.boundary() &&
2410             !cursor.par()->isNewline(cursor.pos()))
2411                 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2412         else if (cursor.pos() < cursor.par()->size()) {
2413                 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2414                 if (!internal &&
2415                     isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2416                         setCursor(bview, cursor.par(), cursor.pos(), true, true);
2417         } else if (cursor.par()->next())
2418                 setCursor(bview, cursor.par()->next(), 0);
2419 }
2420
2421
2422 void LyXText::cursorUp(BufferView * bview) const
2423 {
2424         setCursorFromCoordinates(bview, cursor.x_fix(), 
2425                                  cursor.y() - cursor.row()->baseline() - 1);
2426 }
2427
2428
2429 void LyXText::cursorDown(BufferView * bview) const
2430 {
2431         setCursorFromCoordinates(bview, cursor.x_fix(), 
2432                                  cursor.y() - cursor.row()->baseline()
2433                                  + cursor.row()->height() + 1);
2434 }
2435
2436
2437 void LyXText::cursorUpParagraph(BufferView * bview) const
2438 {
2439         if (cursor.pos() > 0) {
2440                 setCursor(bview, cursor.par(), 0);
2441         }
2442         else if (cursor.par()->previous()) {
2443                 setCursor(bview, cursor.par()->previous(), 0);
2444         }
2445 }
2446
2447
2448 void LyXText::cursorDownParagraph(BufferView * bview) const
2449 {
2450         if (cursor.par()->next()) {
2451                 setCursor(bview, cursor.par()->next(), 0);
2452         } else {
2453                 setCursor(bview, cursor.par(), cursor.par()->size());
2454         }
2455 }
2456
2457
2458 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2459                                             LyXCursor const & old_cursor) const
2460 {
2461         // Would be wrong to delete anything if we have a selection.
2462         if (selection.set()) return;
2463
2464         // We allow all kinds of "mumbo-jumbo" when freespacing.
2465         if (textclasslist.Style(bview->buffer()->params.textclass,
2466                                 old_cursor.par()->getLayout()).free_spacing)
2467                 return;
2468
2469         bool deleted = false;
2470         
2471         /* Ok I'll put some comments here about what is missing.
2472            I have fixed BackSpace (and thus Delete) to not delete
2473            double-spaces automagically. I have also changed Cut,
2474            Copy and Paste to hopefully do some sensible things.
2475            There are still some small problems that can lead to
2476            double spaces stored in the document file or space at
2477            the beginning of paragraphs. This happens if you have
2478            the cursor betwenn to spaces and then save. Or if you
2479            cut and paste and the selection have a space at the
2480            beginning and then save right after the paste. I am
2481            sure none of these are very hard to fix, but I will
2482            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2483            that I can get some feedback. (Lgb)
2484         */
2485
2486         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2487         // delete the LineSeparator.
2488         // MISSING
2489
2490         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2491         // delete the LineSeparator.
2492         // MISSING
2493
2494         // If the pos around the old_cursor were spaces, delete one of them.
2495         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2496                 // Only if the cursor has really moved
2497                 
2498                 if (old_cursor.pos() > 0
2499                     && old_cursor.pos() < old_cursor.par()->size()
2500                     && old_cursor.par()->isLineSeparator(old_cursor.pos())
2501                     && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2502                         old_cursor.par()->erase(old_cursor.pos() - 1);
2503                         redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2504                         // correct cursor
2505                         if (old_cursor.par() == cursor.par() &&
2506                             cursor.pos() > old_cursor.pos()) {
2507                                 setCursorIntern(bview, cursor.par(),
2508                                                 cursor.pos() - 1);
2509                         } else
2510                                 setCursorIntern(bview, cursor.par(),
2511                                                 cursor.pos());
2512                         return;
2513                 }
2514         }
2515
2516         // Do not delete empty paragraphs with keepempty set.
2517         if ((textclasslist.Style(bview->buffer()->params.textclass,
2518                                  old_cursor.par()->getLayout())).keepempty)
2519                 return;
2520
2521         LyXCursor tmpcursor;
2522
2523         if (old_cursor.par() != cursor.par()) {
2524                 if ((old_cursor.par()->size() == 0
2525                       || (old_cursor.par()->size() == 1
2526                           && old_cursor.par()->isLineSeparator(0)))) {
2527                         // ok, we will delete anything
2528                         
2529                         // make sure that you do not delete any environments
2530                                 status = LyXText::NEED_MORE_REFRESH;
2531                                 deleted = true;
2532                                 
2533                                 if (old_cursor.row()->previous()) {
2534                                         refresh_row = old_cursor.row()->previous();
2535                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2536                                         tmpcursor = cursor;
2537                                         cursor = old_cursor; // that undo can restore the right cursor position
2538                                         Paragraph * endpar = old_cursor.par()->next();
2539                                         if (endpar && endpar->getDepth()) {
2540                                                 while (endpar && endpar->getDepth()) {
2541                                                         endpar = endpar->next();
2542                                                 }
2543                                         }
2544                                         setUndo(bview->buffer(), Undo::DELETE,
2545                                                 old_cursor.par()->previous(),
2546                                                 endpar);
2547                                         cursor = tmpcursor;
2548
2549                                         // delete old row
2550                                         removeRow(old_cursor.row());
2551                                         if (ownerParagraph() == old_cursor.par()) {
2552                                                 ownerParagraph(ownerParagraph()->next());
2553                                         }
2554                                         // delete old par
2555                                         delete old_cursor.par();
2556                                         
2557                                         /* Breakagain the next par. Needed
2558                                          * because of the parindent that
2559                                          * can occur or dissappear. The
2560                                          * next row can change its height,
2561                                          * if there is another layout before */
2562                                         if (refresh_row->next()) {
2563                                                 breakAgain(bview, refresh_row->next());
2564                                                 updateCounters(bview, refresh_row);
2565                                         }
2566                                         setHeightOfRow(bview, refresh_row);
2567                                 } else {
2568                                         refresh_row = old_cursor.row()->next();
2569                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2570                                         
2571                                         tmpcursor = cursor;
2572                                         cursor = old_cursor; // that undo can restore the right cursor position
2573                                         Paragraph * endpar = old_cursor.par()->next();
2574                                         if (endpar && endpar->getDepth()) {
2575                                                 while (endpar && endpar->getDepth()) {
2576                                                         endpar = endpar->next();
2577                                                 }
2578                                         }
2579                                         setUndo(bview->buffer(), Undo::DELETE,
2580                                                 old_cursor.par()->previous(),
2581                                                 endpar);
2582                                         cursor = tmpcursor;
2583
2584                                         // delete old row
2585                                         removeRow(old_cursor.row());
2586                                         // delete old par
2587                                         if (ownerParagraph() == old_cursor.par()) {
2588                                                 ownerParagraph(ownerParagraph()->next());
2589                                         }
2590
2591                                         delete old_cursor.par();
2592                                         
2593                                         /* Breakagain the next par. Needed
2594                                            because of the parindent that can
2595                                            occur or dissappear.
2596                                            The next row can change its height,
2597                                            if there is another layout before
2598                                         */ 
2599                                         if (refresh_row) {
2600                                                 breakAgain(bview, refresh_row);
2601                                                 updateCounters(bview, refresh_row->previous());
2602                                         }
2603                                 }
2604                                 
2605                                 // correct cursor y
2606
2607                                 setCursorIntern(bview, cursor.par(), cursor.pos());
2608
2609                                 if (selection.cursor.par()  == old_cursor.par()
2610                                     && selection.cursor.pos() == selection.cursor.pos()) {
2611                                         // correct selection
2612                                         selection.cursor = cursor;
2613                                 }
2614                 }
2615                 if (!deleted) {
2616                         if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2617                                 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2618                                 // correct cursor y
2619                                 setCursorIntern(bview, cursor.par(), cursor.pos());
2620                                 selection.cursor = cursor;
2621                         }
2622                 }
2623         }
2624 }
2625
2626
2627 Paragraph * LyXText::getParFromID(int id)
2628 {
2629         Paragraph * result = firstParagraph();
2630         while (result && result->id() != id)
2631                 result = result->next();
2632         return result;
2633 }
2634
2635
2636 // undo functions
2637 bool LyXText::textUndo(BufferView * bview)
2638 {
2639         if (inset_owner)
2640                 return false;
2641         // returns false if no undo possible
2642         Undo * undo = bview->buffer()->undostack.pop();
2643         if (undo) {
2644                 finishUndo();
2645                 if (!undo_frozen)
2646                         bview->buffer()->redostack
2647                                 .push(createUndo(bview->buffer(), undo->kind, 
2648                                                  getParFromID(undo->number_of_before_par),
2649                                                  getParFromID(undo->number_of_behind_par)));
2650         }
2651         return textHandleUndo(bview, undo);
2652 }
2653
2654
2655 bool LyXText::textRedo(BufferView * bview)
2656 {
2657         if (inset_owner)
2658                 return false;
2659         // returns false if no redo possible
2660         Undo * undo = bview->buffer()->redostack.pop();
2661         if (undo) {
2662                 finishUndo();
2663                 if (!undo_frozen)
2664                         bview->buffer()->undostack
2665                                 .push(createUndo(bview->buffer(), undo->kind, 
2666                                                  getParFromID(undo->number_of_before_par),
2667                                                  getParFromID(undo->number_of_behind_par)));
2668         }
2669         return textHandleUndo(bview, undo);
2670 }
2671
2672
2673 bool LyXText::textHandleUndo(BufferView * bview, Undo * undo)
2674 {
2675         if (inset_owner)
2676                 return false;
2677         // returns false if no undo possible
2678         bool result = false;
2679         if (undo) {
2680                 Paragraph * before =
2681                         getParFromID(undo->number_of_before_par); 
2682                 Paragraph * behind =
2683                         getParFromID(undo->number_of_behind_par); 
2684                 Paragraph * tmppar;
2685                 Paragraph * tmppar2;
2686                 Paragraph * endpar;
2687                 Paragraph * tmppar5;
2688     
2689                 // if there's no before take the beginning
2690                 // of the document for redoing
2691                 if (!before)
2692                         setCursorIntern(bview, firstParagraph(), 0);
2693
2694                 // replace the paragraphs with the undo informations
2695
2696                 Paragraph * tmppar3 = undo->par;
2697                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2698                 Paragraph * tmppar4 = tmppar3;
2699
2700                 if (tmppar4) {
2701                         while (tmppar4->next())
2702                                 tmppar4 = tmppar4->next();
2703                 } // get last undo par
2704     
2705                 // now remove the old text if there is any
2706                 if (before != behind || (!behind && !before)) {
2707                         if (before)
2708                                 tmppar5 = before->next();
2709                         else
2710                                 tmppar5 = ownerParagraph();
2711                         tmppar2 = tmppar3;
2712                         while (tmppar5 && tmppar5 != behind) {
2713                                 tmppar = tmppar5;
2714                                 tmppar5 = tmppar5->next();
2715                                 // a memory optimization for edit: Only layout information
2716                                 // is stored in the undo. So restore the text informations.
2717                                 if (undo->kind == Undo::EDIT) {
2718                                         tmppar2->setContentsFromPar(tmppar);
2719                                         tmppar->clearContents();
2720                                         tmppar2 = tmppar2->next();
2721                                 }
2722                         }
2723                 }
2724     
2725                 // put the new stuff in the list if there is one
2726                 if (tmppar3){
2727                         if (before)
2728                                 before->next(tmppar3);
2729                         else
2730                                 ownerParagraph(tmppar3);
2731                         tmppar3->previous(before);
2732                 } else {
2733                         if (!before)
2734                                 ownerParagraph(behind);
2735                 }
2736                 if (tmppar4) {
2737                         tmppar4->next(behind);
2738                         if (behind)
2739                                 behind->previous(tmppar4);
2740                 }
2741     
2742     
2743                 // Set the cursor for redoing
2744                 if (before) {
2745                         setCursorIntern(bview, before, 0);
2746                 }
2747
2748                 // calculate the endpar for redoing the paragraphs.
2749                 if (behind) {
2750                                 endpar = behind->next();
2751                 } else
2752                         endpar = behind;
2753     
2754                 tmppar = getParFromID(undo->number_of_cursor_par);
2755                 redoParagraphs(bview, cursor, endpar); 
2756                 if (tmppar){
2757                         setCursorIntern(bview, tmppar, undo->cursor_pos);
2758                         updateCounters(bview, cursor.row());
2759                 }
2760                 result = true;
2761                 delete undo;
2762         }
2763         finishUndo();
2764         return result;
2765 }
2766
2767
2768 void LyXText::finishUndo()
2769 {
2770         if (inset_owner)
2771                 return;
2772         // makes sure the next operation will be stored
2773         undo_finished = true;
2774 }
2775
2776
2777 void LyXText::freezeUndo()
2778 {
2779         if (inset_owner)
2780                 return;
2781         // this is dangerous and for internal use only
2782         undo_frozen = true;
2783 }
2784
2785
2786 void LyXText::unFreezeUndo()
2787 {
2788         if (inset_owner)
2789                 return;
2790         // this is dangerous and for internal use only
2791         undo_frozen = false;
2792 }
2793
2794
2795 void LyXText::setUndo(Buffer * buf, Undo::undo_kind kind,
2796                       Paragraph const * before,
2797                       Paragraph const * behind) const
2798 {
2799         if (inset_owner)
2800                 return;
2801         if (!undo_frozen)
2802                 buf->undostack.push(createUndo(buf, kind, before, behind));
2803         buf->redostack.clear();
2804 }
2805
2806
2807 void LyXText::setRedo(Buffer * buf, Undo::undo_kind kind,
2808                       Paragraph const * before, Paragraph const * behind)
2809 {
2810         if (inset_owner)
2811                 return;
2812         buf->redostack.push(createUndo(buf, kind, before, behind));
2813 }
2814
2815
2816 Undo * LyXText::createUndo(Buffer * buf, Undo::undo_kind kind,
2817                            Paragraph const * before,
2818                            Paragraph const * behind) const
2819 {
2820         if (inset_owner)
2821                 return 0;
2822
2823         int before_number = -1;
2824         int behind_number = -1;
2825         if (before)
2826                 before_number = before->id();
2827         if (behind)
2828                 behind_number = behind->id();
2829         // Undo::EDIT  and Undo::FINISH are
2830         // always finished. (no overlapping there)
2831         // overlapping only with insert and delete inside one paragraph: 
2832         // Nobody wants all removed  character
2833         // appear one by one when undoing. 
2834         // EDIT is special since only layout information, not the
2835         // contents of a paragaph are stored.
2836         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2837                 // check wether storing is needed
2838                 if (!buf->undostack.empty() && 
2839                     buf->undostack.top()->kind == kind &&
2840                     buf->undostack.top()->number_of_before_par ==  before_number &&
2841                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
2842                         // no undo needed
2843                         return 0;
2844                 }
2845         }
2846         // create a new Undo
2847         Paragraph * undopar;
2848
2849         Paragraph * start = 0;
2850         Paragraph * end = 0;
2851
2852         if (before)
2853                 start = const_cast<Paragraph*>(before->next());
2854         else
2855                 start = firstParagraph();
2856         if (behind)
2857                 end = const_cast<Paragraph*>(behind->previous());
2858         else {
2859                 end = firstParagraph();
2860                 while (end->next())
2861                         end = end->next();
2862         }
2863         if (start && end && (start != end->next()) &&
2864             ((before != behind) || (!before && !behind))) {
2865                 Paragraph * tmppar = start;
2866                 Paragraph * tmppar2 = new Paragraph(*tmppar);
2867                 tmppar2->id(tmppar->id());
2868                 
2869                 // a memory optimization: Just store the layout information
2870                 // when only edit
2871                 if (kind == Undo::EDIT){
2872                         //tmppar2->text.clear();
2873                         tmppar2->clearContents();
2874                 }
2875
2876                 undopar = tmppar2;
2877   
2878                 while (tmppar != end && tmppar->next()) {
2879                         tmppar = tmppar->next();
2880                         tmppar2->next(new Paragraph(*tmppar));
2881                         tmppar2->next()->id(tmppar->id());
2882                         // a memory optimization: Just store the layout
2883                         // information when only edit
2884                         if (kind == Undo::EDIT){
2885                                 //tmppar2->next->text.clear();
2886                                 tmppar2->clearContents();
2887                         }
2888                         tmppar2->next()->previous(tmppar2);
2889                         tmppar2 = tmppar2->next();
2890                 }
2891                 tmppar2->next(0);
2892         } else
2893                 undopar = 0; // nothing to replace (undo of delete maybe)
2894
2895         int cursor_par = cursor.par()->id();
2896         int cursor_pos =  cursor.pos();
2897         
2898         Undo * undo = new Undo(kind, 
2899                                before_number, behind_number,  
2900                                cursor_par, cursor_pos, 
2901                                undopar);
2902   
2903         undo_finished = false;
2904         return undo;
2905 }
2906
2907
2908 void LyXText::setCursorParUndo(Buffer * buf)
2909 {
2910         if (inset_owner)
2911                 return;
2912         setUndo(buf, Undo::FINISH,
2913                 cursor.par()->previous(),
2914                 cursor.par()->next()); 
2915 }
2916
2917
2918 void LyXText::toggleAppendix(BufferView * bview)
2919 {
2920         Paragraph * par = cursor.par();
2921         bool start = !par->params().startOfAppendix();
2922
2923         // ensure that we have only one start_of_appendix in this document
2924         Paragraph * tmp = firstParagraph();
2925         for (; tmp; tmp = tmp->next())
2926                 tmp->params().startOfAppendix(false);
2927
2928         par->params().startOfAppendix(start);
2929
2930         // we can set the refreshing parameters now
2931         status = LyXText::NEED_MORE_REFRESH;
2932         refresh_y = 0;
2933         refresh_row = 0; // not needed for full update
2934         updateCounters(bview, 0);
2935         setCursor(bview, cursor.par(), cursor.pos());
2936 }
2937
2938
2939 Paragraph * LyXText::ownerParagraph() const
2940 {
2941         if (inset_owner)
2942                 return inset_owner->par;
2943
2944         return bv_owner->buffer()->paragraph;
2945 }
2946
2947
2948 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2949 {
2950         if (inset_owner)
2951                 inset_owner->par = p;
2952         else
2953                 bv_owner->buffer()->paragraph = p;
2954         return 0;
2955 }