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