]> git.lyx.org Git - lyx.git/blob - src/text2.C
update libtool
[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                         if (isOK) {
1678                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1679                                 Floating const & fl
1680                                         = floatList.getType(tmp->type());
1681                                 // We should get the correct number here too.
1682                                 s = fl.name() + " #:";
1683                         } else {
1684                                 /* par->SetLayout(0); 
1685                                    s = layout->labelstring;  */
1686                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1687                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1688                         }
1689                 }
1690                 par->params.labelString(s);
1691                 
1692                 /* reset the enumeration counter. They are always resetted
1693                  * when there is any other layout between */ 
1694                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1695                         par->setCounter(i, 0);
1696         }
1697 }
1698
1699
1700 /* Updates all counters BEHIND the row. Changed paragraphs
1701 * with a dynamic left margin will be rebroken. */ 
1702 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1703 {
1704         LyXParagraph * par;
1705
1706         if (!row) {
1707                 row = firstrow;
1708                 par = row->par();
1709         } else {
1710                 par = row->par()->next();
1711         }
1712
1713         while (par) {
1714                 while (row->par() != par)
1715                         row = row->next();
1716                 
1717                 SetCounter(bview->buffer(), par);
1718                 
1719                 /* now  check for the headline layouts. remember that they
1720                  * have a dynamic left margin */ 
1721                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1722                                          par->layout).margintype == MARGIN_DYNAMIC
1723                      || textclasslist.Style(bview->buffer()->params.textclass,
1724                                             par->layout).labeltype == LABEL_SENSITIVE)) {
1725                         
1726                         /* Rebreak the paragraph */ 
1727                         RemoveParagraph(row);
1728                         AppendParagraph(bview, row);
1729                 }
1730                 par = par->next();
1731         }
1732 }
1733
1734
1735 /* insets an inset. */ 
1736 void LyXText::InsertInset(BufferView * bview, Inset * inset)
1737 {
1738         if (!cursor.par()->InsertInsetAllowed(inset))
1739                 return;
1740         SetUndo(bview->buffer(), Undo::INSERT,
1741                 cursor.par()->previous(),
1742                 cursor.par()->next());
1743         cursor.par()->InsertInset(cursor.pos(), inset);
1744         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1745                                       * The character will not be inserted a
1746                                       * second time */
1747 #if 1
1748         // If we enter a highly editable inset the cursor should be to before
1749         // the inset. This couldn't happen before as Undo was not handled inside
1750         // inset now after the Undo LyX tries to call inset->Edit(...) again
1751         // and cannot do this as the cursor is behind the inset and GetInset
1752         // does not return the inset!
1753         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1754                 CursorLeft(bview, true);
1755         }
1756 #endif
1757 }
1758
1759
1760 void LyXText::copyEnvironmentType()
1761 {
1762         copylayouttype = cursor.par()->GetLayout();
1763 }
1764
1765
1766 void LyXText::pasteEnvironmentType(BufferView * bview)
1767 {
1768         SetLayout(bview, copylayouttype);
1769 }
1770
1771
1772 void LyXText::CutSelection(BufferView * bview, bool doclear)
1773 {
1774         // Stuff what we got on the clipboard. Even if there is no selection.
1775
1776         // There is a problem with having the stuffing here in that the
1777         // larger the selection the slower LyX will get. This can be
1778         // solved by running the line below only when the selection has
1779         // finished. The solution used currently just works, to make it
1780         // faster we need to be more clever and probably also have more
1781         // calls to stuffClipboard. (Lgb)
1782         bview->stuffClipboard(selectionAsString(bview->buffer()));
1783
1784         // This doesn't make sense, if there is no selection
1785         if (!selection.set())
1786                 return;
1787    
1788         // OK, we have a selection. This is always between selection.start
1789         // and selection.end
1790
1791         // make sure that the depth behind the selection are restored, too
1792         LyXParagraph * endpar = selection.end.par()->next();
1793         LyXParagraph * undoendpar = endpar;
1794     
1795         if (endpar && endpar->GetDepth()) {
1796                 while (endpar && endpar->GetDepth()) {
1797                         endpar = endpar->next();
1798                         undoendpar = endpar;
1799                 }
1800         } else if (endpar) {
1801                 endpar = endpar->next(); // because of parindents etc.
1802         }
1803     
1804         SetUndo(bview->buffer(), Undo::DELETE,
1805                 selection.start.par()->previous(),
1806                 undoendpar);
1807     
1808         CutAndPaste cap;
1809
1810         // there are two cases: cut only within one paragraph or
1811         // more than one paragraph
1812         if (selection.start.par() == selection.end.par()) {
1813                 // only within one paragraph
1814                 endpar = selection.end.par();
1815                 int pos = selection.end.pos();
1816                 cap.cutSelection(selection.start.par(), &endpar,
1817                                  selection.start.pos(), pos,
1818                                  bview->buffer()->params.textclass, doclear);
1819                 selection.end.pos(pos);
1820         } else {
1821                 endpar = selection.end.par();
1822                 int pos = selection.end.pos();
1823                 cap.cutSelection(selection.start.par(), &endpar,
1824                                  selection.start.pos(), pos,
1825                                  bview->buffer()->params.textclass, doclear);
1826                 cursor.par(endpar);
1827                 selection.end.par(endpar);
1828                 selection.end.pos(pos);
1829                 cursor.pos(selection.end.pos());
1830         }
1831         endpar = endpar->next();
1832
1833         // sometimes necessary
1834         if (doclear)
1835                 selection.start.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
1836
1837         RedoParagraphs(bview, selection.start, endpar);
1838
1839         // cutSelection can invalidate the cursor so we need to set
1840         // it anew. (Lgb)
1841         cursor = selection.start;
1842
1843         // need a valid cursor. (Lgb)
1844         ClearSelection(bview);
1845
1846         SetCursor(bview, cursor.par(), cursor.pos());
1847         selection.cursor = cursor;
1848         UpdateCounters(bview, cursor.row());
1849 }
1850
1851
1852 void LyXText::CopySelection(BufferView * bview)
1853 {
1854         // Stuff what we got on the clipboard. Even if there is no selection.
1855
1856         // There is a problem with having the stuffing here in that the
1857         // larger the selection the slower LyX will get. This can be
1858         // solved by running the line below only when the selection has
1859         // finished. The solution used currently just works, to make it
1860         // faster we need to be more clever and probably also have more
1861         // calls to stuffClipboard. (Lgb)
1862         bview->stuffClipboard(selectionAsString(bview->buffer()));
1863
1864         // this doesnt make sense, if there is no selection
1865         if (!selection.set())
1866                 return;
1867
1868         // ok we have a selection. This is always between selection.start
1869         // and sel_end cursor
1870
1871         // copy behind a space if there is one
1872         while (selection.start.par()->size() > selection.start.pos()
1873                && selection.start.par()->IsLineSeparator(selection.start.pos())
1874                && (selection.start.par() != selection.end.par()
1875                    || selection.start.pos() < selection.end.pos()))
1876                 selection.start.pos(selection.start.pos() + 1); 
1877
1878         CutAndPaste cap;
1879
1880         cap.copySelection(selection.start.par(), selection.end.par(),
1881                           selection.start.pos(), selection.end.pos(),
1882                           bview->buffer()->params.textclass);
1883 }
1884
1885
1886 void LyXText::PasteSelection(BufferView * bview)
1887 {
1888         CutAndPaste cap;
1889
1890         // this does not make sense, if there is nothing to paste
1891         if (!cap.checkPastePossible(cursor.par()))
1892                 return;
1893
1894         SetUndo(bview->buffer(), Undo::INSERT,
1895                 cursor.par()->previous(),
1896                 cursor.par()->next()); 
1897
1898         LyXParagraph * endpar;
1899         LyXParagraph * actpar = cursor.par();
1900
1901         int pos = cursor.pos();
1902         cap.pasteSelection(&actpar, &endpar, pos,
1903                            bview->buffer()->params.textclass);
1904     
1905         RedoParagraphs(bview, cursor, endpar);
1906         
1907         SetCursor(bview, cursor.par(), cursor.pos());
1908         ClearSelection(bview);
1909    
1910         selection.cursor = cursor;
1911         SetCursor(bview, actpar, pos);
1912         SetSelection(bview);
1913         UpdateCounters(bview, cursor.row());
1914 }
1915
1916
1917 // returns a pointer to the very first LyXParagraph
1918 LyXParagraph * LyXText::FirstParagraph() const
1919 {
1920         return OwnerParagraph();
1921 }
1922
1923
1924 // sets the selection over the number of characters of string, no check!!
1925 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
1926 {
1927         selection.cursor = cursor;
1928         for (int i = 0; str[i]; ++i)
1929                 CursorRight(bview);
1930         SetSelection(bview);
1931 }
1932
1933
1934 // simple replacing. The font of the first selected character is used
1935 void LyXText::ReplaceSelectionWithString(BufferView * bview,
1936                                          string const & str)
1937 {
1938         SetCursorParUndo(bview->buffer());
1939         FreezeUndo();
1940
1941         if (!selection.set()) { // create a dummy selection
1942                 selection.end = cursor;
1943                 selection.start = cursor;
1944         }
1945
1946         // Get font setting before we cut
1947         LyXParagraph::size_type pos = selection.end.pos();
1948         LyXFont const font = selection.start.par()
1949                 ->GetFontSettings(bview->buffer()->params,
1950                                   selection.start.pos());
1951
1952         // Insert the new string
1953         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1954                 selection.end.par()->InsertChar(pos, (*cit), font);
1955                 ++pos;
1956         }
1957         
1958         // Cut the selection
1959         CutSelection(bview);
1960
1961         UnFreezeUndo();
1962 }
1963
1964
1965 // needed to insert the selection
1966 void LyXText::InsertStringA(BufferView * bview, string const & str)
1967 {
1968         LyXParagraph * par = cursor.par();
1969         LyXParagraph::size_type pos = cursor.pos();
1970         LyXParagraph::size_type a = 0;
1971         LyXParagraph * endpar = cursor.par()->next();
1972         
1973         SetCursorParUndo(bview->buffer());
1974         
1975         bool flag =
1976                 textclasslist.Style(bview->buffer()->params.textclass, 
1977                                     cursor.par()->GetLayout()).isEnvironment();
1978         // only to be sure, should not be neccessary
1979         ClearSelection(bview);
1980         
1981         // insert the string, don't insert doublespace
1982         string::size_type i = 0;
1983         while (i < str.length()) {
1984                 if (str[i] != '\n') {
1985                         if (str[i] == ' ' 
1986                             && i + 1 < str.length() && str[i + 1] != ' '
1987                             && pos && par->GetChar(pos - 1)!= ' ') {
1988                                 par->InsertChar(pos, ' ', current_font);
1989                                 ++pos;
1990                         } else if (str[i] == ' ') {
1991                                 InsetSpecialChar * new_inset =
1992                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1993                                 if (par->InsertInsetAllowed(new_inset)) {
1994                                         par->InsertInset(pos, new_inset,
1995                                                          current_font);
1996                                 } else {
1997                                         delete new_inset;
1998                                 }
1999                                 ++pos;
2000                         } else if (str[i] == '\t') {
2001                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2002                                 InsetSpecialChar * new_inset =
2003                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2004                                 if (par->InsertInsetAllowed(new_inset)) {
2005                                         par->InsertInset(pos, new_inset,
2006                                                          current_font);
2007                                 } else {
2008                                         delete new_inset;
2009                                 }
2010                                 }
2011                                 pos = a;
2012                         } else if (str[i] != 13 && 
2013                                    // Ignore unprintables
2014                                    (str[i] & 127) >= ' ') {
2015                                 par->InsertChar(pos, str[i], current_font);
2016                                 ++pos;
2017                         }
2018                 } else {
2019                         if (!par->size()) { // par is empty
2020                                 InsetSpecialChar * new_inset =
2021                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2022                                 if (par->InsertInsetAllowed(new_inset)) {
2023                                         par->InsertInset(pos,
2024                                                          new_inset,
2025                                                          current_font);
2026                                 } else {
2027                                         delete new_inset;
2028                                 }
2029                                 ++pos;
2030                         }
2031                         par->BreakParagraph(bview->buffer()->params, pos, flag);
2032                         par = par->next();
2033                         pos = 0;
2034                 }
2035                 ++i;
2036         }
2037         
2038         RedoParagraphs(bview, cursor, endpar);
2039         SetCursor(bview, cursor.par(), cursor.pos());
2040         selection.cursor = cursor;
2041         SetCursor(bview, par, pos);
2042         SetSelection(bview);
2043 }
2044
2045
2046 /* turns double-CR to single CR, others where converted into one blank and 13s 
2047  * that are ignored .Double spaces are also converted into one. Spaces at
2048  * the beginning of a paragraph are forbidden. tabs are converted into one
2049  * space. then InsertStringA is called */ 
2050 void LyXText::InsertStringB(BufferView * bview, string const & s)
2051 {
2052         string str(s);
2053         string::size_type i = 1;
2054         while (i < str.length()) {
2055                 if (str[i] == '\t')
2056                         str[i] = ' ';
2057                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2058                         str[i] = 13;
2059                 if (str[i] == '\n' && i + 1 < str.length()) {
2060                         if (str[i + 1] != '\n') {
2061                                 if (str[i - 1] != ' ')
2062                                         str[i] = ' ';
2063                                 else
2064                                         str[i] = 13;
2065                         }
2066                         while (i + 1 < str.length() 
2067                                && (str[i + 1] == ' ' 
2068                                    || str[i + 1] == '\t'
2069                                    || str[i + 1] == '\n' 
2070                                    || str[i + 1] == 13)) {
2071                                 str[i + 1] = 13;
2072                                 ++i;
2073                         }
2074                 }
2075                 ++i;
2076         }
2077         InsertStringA(bview, str);
2078 }
2079
2080
2081 bool LyXText::GotoNextInset(BufferView * bview,
2082                             std::vector<Inset::Code> const & codes,
2083                             string const & contents) const
2084 {
2085         LyXCursor res = cursor;
2086         Inset * inset;
2087         do {
2088                 if (res.pos() < res.par()->size() - 1) {
2089                         res.pos(res.pos() + 1);
2090                 } else  {
2091                         res.par(res.par()->next());
2092                         res.pos(0);
2093                 }
2094       
2095         } while (res.par() && 
2096                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2097                    && (inset = res.par()->GetInset(res.pos())) != 0
2098                    && find(codes.begin(), codes.end(), inset->LyxCode())
2099                       != codes.end()
2100                    && (contents.empty() ||
2101                        static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2102                        == contents)));
2103
2104         if (res.par()) {
2105                 SetCursor(bview, res.par(), res.pos());
2106                 return true;
2107         }
2108         return false;
2109 }
2110
2111
2112 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2113                              LyXParagraph::size_type pos)
2114 {
2115         LyXCursor tmpcursor;                    
2116
2117         int y = 0;
2118         LyXParagraph::size_type z;
2119         Row * row = GetRow(par, pos, y);
2120         
2121         // is there a break one row above
2122         if (row->previous() && row->previous()->par() == row->par()) {
2123                 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2124                 if (z >= row->pos()) {
2125                         // set the dimensions of the row above
2126                         y -= row->previous()->height();
2127                         refresh_y = y;
2128                         refresh_row = row->previous();
2129                         status = LyXText::NEED_MORE_REFRESH;
2130                         
2131                         BreakAgain(bview, row->previous());
2132                         
2133                         // set the cursor again. Otherwise
2134                         // dangling pointers are possible
2135                         SetCursor(bview, cursor.par(), cursor.pos(),
2136                                   false, cursor.boundary());
2137                         selection.cursor = cursor;
2138                         return;
2139                 }
2140         }
2141
2142         int const tmpheight = row->height();
2143         LyXParagraph::size_type const tmplast = RowLast(row);
2144         refresh_y = y;
2145         refresh_row = row;
2146         
2147         BreakAgain(bview, row);
2148         if (row->height() == tmpheight && RowLast(row) == tmplast)
2149                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2150         else
2151                 status = LyXText::NEED_MORE_REFRESH; 
2152         
2153         // check the special right address boxes
2154         if (textclasslist.Style(bview->buffer()->params.textclass,
2155                                 par->GetLayout()).margintype
2156             == MARGIN_RIGHT_ADDRESS_BOX) {
2157                 tmpcursor.par(par);
2158                 tmpcursor.row(row);
2159                 tmpcursor.y(y);
2160                 tmpcursor.x(0);
2161                 tmpcursor.x_fix(0);
2162                 tmpcursor.pos(pos);
2163                 RedoDrawingOfParagraph(bview, tmpcursor); 
2164         }
2165
2166         // set the cursor again. Otherwise dangling pointers are possible
2167         // also set the selection
2168    
2169         if (selection.set()) {
2170                 tmpcursor = cursor;
2171                 SetCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2172                                 false, selection.cursor.boundary());
2173                 selection.cursor = cursor; 
2174                 SetCursorIntern(bview, selection.start.par(),
2175                                 selection.start.pos(),
2176                                 false, selection.start.boundary());
2177                 selection.start = cursor; 
2178                 SetCursorIntern(bview, selection.end.par(),
2179                                 selection.end.pos(),
2180                                 false, selection.end.boundary());
2181                 selection.end = cursor; 
2182                 SetCursorIntern(bview, last_sel_cursor.par(),
2183                                 last_sel_cursor.pos(),
2184                                 false, last_sel_cursor.boundary());
2185                 last_sel_cursor = cursor; 
2186                 cursor = tmpcursor;
2187         }
2188         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2189                         false, cursor.boundary());
2190 }
2191
2192
2193 // returns false if inset wasn't found
2194 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2195 {
2196         // first check the current paragraph
2197         int pos = cursor.par()->GetPositionOfInset(inset);
2198         if (pos != -1){
2199                 CheckParagraph(bview, cursor.par(), pos);
2200                 return true;
2201         }
2202   
2203         // check every paragraph
2204   
2205         LyXParagraph * par = FirstParagraph();
2206         do {
2207                         pos = par->GetPositionOfInset(inset);
2208                         if (pos != -1){
2209                                 CheckParagraph(bview, par, pos);
2210                                 return true;
2211                         }
2212                 par = par->next();
2213         } while (par);
2214   
2215         return false;
2216 }
2217
2218
2219 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2220                         LyXParagraph::size_type pos, 
2221                         bool setfont, bool boundary) const
2222 {
2223         LyXCursor old_cursor = cursor;
2224         SetCursorIntern(bview, par, pos, setfont, boundary);
2225         DeleteEmptyParagraphMechanism(bview, old_cursor);
2226 }
2227
2228
2229 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2230                         LyXParagraph::size_type pos, bool boundary) const
2231 {
2232         cur.par(par);
2233         cur.pos(pos);
2234         cur.boundary(boundary);
2235
2236         /* get the cursor y position in text  */
2237         int y = 0;
2238         Row * row = GetRow(par, pos, y);
2239         /* y is now the beginning of the cursor row */ 
2240         y += row->baseline();
2241         /* y is now the cursor baseline */ 
2242         cur.y(y);
2243    
2244         /* now get the cursors x position */
2245         float x;
2246         float fill_separator, fill_hfill, fill_label_hfill;
2247         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2248                        fill_label_hfill);
2249         LyXParagraph::size_type cursor_vpos = 0;
2250         LyXParagraph::size_type last = RowLastPrintable(row);
2251
2252         if (pos > last + 1)   // This shouldn't happen.
2253                 pos = last + 1;
2254         else if (pos < row->pos())
2255                 pos = row->pos();
2256
2257         if (last < row->pos())
2258                 cursor_vpos = row->pos();
2259         else if (pos > last && !boundary)
2260                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2261                         ? row->pos() : last + 1; 
2262         else if (pos > row->pos() &&
2263                  (pos > last || boundary))
2264                 /// Place cursor after char at (logical) position pos - 1
2265                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2266                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2267         else
2268                 /// Place cursor before char at (logical) position pos
2269                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2270                         ? log2vis(pos) : log2vis(pos) + 1;
2271         
2272         LyXParagraph::size_type main_body =
2273                 BeginningOfMainBody(bview->buffer(), row->par());
2274         if ((main_body > 0) &&
2275             ((main_body-1 > last) || 
2276              !row->par()->IsLineSeparator(main_body-1)))
2277                 main_body = 0;
2278         
2279         for (LyXParagraph::size_type vpos = row->pos();
2280              vpos < cursor_vpos; ++vpos) {
2281                 pos = vis2log(vpos);
2282                 if (main_body > 0 && pos == main_body - 1) {
2283                         x += fill_label_hfill +
2284                                 lyxfont::width(textclasslist.Style(
2285                                         bview->buffer()->params.textclass,
2286                                         row->par()->GetLayout())
2287                                                .labelsep,
2288                                                GetFont(bview->buffer(), row->par(), -2));
2289                         if (row->par()->IsLineSeparator(main_body-1))
2290                                 x -= SingleWidth(bview, row->par(),main_body-1);
2291                 }
2292                 if (HfillExpansion(bview->buffer(), row, pos)) {
2293                         x += SingleWidth(bview, row->par(), pos);
2294                         if (pos >= main_body)
2295                                 x += fill_hfill;
2296                         else 
2297                                 x += fill_label_hfill;
2298                 } else if (row->par()->IsSeparator(pos)) {
2299                         x += SingleWidth(bview, row->par(), pos);
2300                         if (pos >= main_body)
2301                                 x += fill_separator;
2302                 } else
2303                         x += SingleWidth(bview, row->par(), pos);
2304         }
2305         
2306         cur.x(int(x));
2307         cur.x_fix(cur.x());
2308         cur.row(row);
2309 }
2310
2311
2312 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2313                               LyXParagraph::size_type pos,
2314                               bool setfont, bool boundary) const
2315 {
2316         SetCursor(bview, cursor, par, pos, boundary);
2317         if (setfont)
2318                 SetCurrentFont(bview);
2319 }
2320
2321
2322 void LyXText::SetCurrentFont(BufferView * bview) const
2323 {
2324         LyXParagraph::size_type pos = cursor.pos();
2325         if (cursor.boundary() && pos > 0)
2326                 --pos;
2327
2328         if (pos > 0) {
2329                 if (pos == cursor.par()->size())
2330                         --pos;
2331                 else // potentional bug... BUG (Lgb)
2332                 if (cursor.par()->IsSeparator(pos)) {
2333                         if (pos > cursor.row()->pos() &&
2334                             bidi_level(pos) % 2 == 
2335                             bidi_level(pos - 1) % 2)
2336                                 --pos;
2337                         else if (pos + 1 < cursor.par()->size())
2338                                 ++pos;
2339                 }
2340         }
2341
2342         current_font =
2343                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2344         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2345
2346         if (cursor.pos() == cursor.par()->size() &&
2347             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2348             !cursor.boundary()) {
2349                 Language const * lang =
2350                         cursor.par()->getParLanguage(bview->buffer()->params);
2351                 current_font.setLanguage(lang);
2352                 current_font.setNumber(LyXFont::OFF);
2353                 real_current_font.setLanguage(lang);
2354                 real_current_font.setNumber(LyXFont::OFF);
2355         }
2356 }
2357
2358
2359 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2360 {
2361         LyXCursor old_cursor = cursor;
2362    
2363         /* get the row first */ 
2364    
2365         Row * row = GetRowNearY(y);
2366         cursor.par(row->par());
2367
2368         bool bound = false;
2369         int column = GetColumnNearX(bview, row, x, bound);
2370         cursor.pos(row->pos() + column);
2371         cursor.x(x);
2372         cursor.y(y + row->baseline());
2373         cursor.row(row);
2374         cursor.boundary(bound);
2375         SetCurrentFont(bview);
2376         DeleteEmptyParagraphMechanism(bview, old_cursor);
2377 }
2378
2379
2380 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2381                                        int x, int y) const
2382 {
2383         /* get the row first */ 
2384    
2385         Row * row = GetRowNearY(y);
2386         bool bound = false;
2387         int column = GetColumnNearX(bview, row, x, bound);
2388    
2389         cur.par(row->par());
2390         cur.pos(row->pos() + column);
2391         cur.x(x);
2392         cur.y(y + row->baseline());
2393         cur.row(row);
2394         cur.boundary(bound);
2395 }
2396
2397
2398 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2399 {
2400         if (cursor.pos() > 0) {
2401                 bool boundary = cursor.boundary();
2402                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2403                 if (!internal && !boundary &&
2404                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2405                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2406         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2407                 LyXParagraph * par = cursor.par()->previous();
2408                 SetCursor(bview, par, par->size());
2409         }
2410 }
2411
2412
2413 void LyXText::CursorRight(BufferView * bview, bool internal) const
2414 {
2415         if (!internal && cursor.boundary() &&
2416             !cursor.par()->IsNewline(cursor.pos()))
2417                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2418         else if (cursor.pos() < cursor.par()->size()) {
2419                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2420                 if (!internal &&
2421                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2422                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2423         } else if (cursor.par()->next())
2424                 SetCursor(bview, cursor.par()->next(), 0);
2425 }
2426
2427
2428 void LyXText::CursorUp(BufferView * bview) const
2429 {
2430         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2431                                  cursor.y() - cursor.row()->baseline() - 1);
2432 }
2433
2434
2435 void LyXText::CursorDown(BufferView * bview) const
2436 {
2437         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2438                                  cursor.y() - cursor.row()->baseline()
2439                                  + cursor.row()->height() + 1);
2440 }
2441
2442
2443 void LyXText::CursorUpParagraph(BufferView * bview) const
2444 {
2445         if (cursor.pos() > 0) {
2446                 SetCursor(bview, cursor.par(), 0);
2447         }
2448         else if (cursor.par()->previous()) {
2449                 SetCursor(bview, cursor.par()->previous(), 0);
2450         }
2451 }
2452
2453
2454 void LyXText::CursorDownParagraph(BufferView * bview) const
2455 {
2456         if (cursor.par()->next()) {
2457                 SetCursor(bview, cursor.par()->next(), 0);
2458         } else {
2459                 SetCursor(bview, cursor.par(), cursor.par()->size());
2460         }
2461 }
2462
2463
2464 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2465                                             LyXCursor const & old_cursor) const
2466 {
2467         // Would be wrong to delete anything if we have a selection.
2468         if (selection.set()) return;
2469
2470         // We allow all kinds of "mumbo-jumbo" when freespacing.
2471         if (textclasslist.Style(bview->buffer()->params.textclass,
2472                                 old_cursor.par()->GetLayout()).free_spacing)
2473                 return;
2474
2475         bool deleted = false;
2476         
2477         /* Ok I'll put some comments here about what is missing.
2478            I have fixed BackSpace (and thus Delete) to not delete
2479            double-spaces automagically. I have also changed Cut,
2480            Copy and Paste to hopefully do some sensible things.
2481            There are still some small problems that can lead to
2482            double spaces stored in the document file or space at
2483            the beginning of paragraphs. This happens if you have
2484            the cursor betwenn to spaces and then save. Or if you
2485            cut and paste and the selection have a space at the
2486            beginning and then save right after the paste. I am
2487            sure none of these are very hard to fix, but I will
2488            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2489            that I can get some feedback. (Lgb)
2490         */
2491
2492         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2493         // delete the LineSeparator.
2494         // MISSING
2495
2496         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2497         // delete the LineSeparator.
2498         // MISSING
2499
2500         // If the pos around the old_cursor were spaces, delete one of them.
2501         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2502                 // Only if the cursor has really moved
2503                 
2504                 if (old_cursor.pos() > 0
2505                     && old_cursor.pos() < old_cursor.par()->size()
2506                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
2507                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
2508                         old_cursor.par()->Erase(old_cursor.pos() - 1);
2509                         RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2510                         // correct cursor
2511                         if (old_cursor.par() == cursor.par() &&
2512                             cursor.pos() > old_cursor.pos()) {
2513                                 SetCursorIntern(bview, cursor.par(),
2514                                                 cursor.pos() - 1);
2515                         } else
2516                                 SetCursorIntern(bview, cursor.par(),
2517                                                 cursor.pos());
2518                         return;
2519                 }
2520         }
2521
2522         // Do not delete empty paragraphs with keepempty set.
2523         if ((textclasslist.Style(bview->buffer()->params.textclass,
2524                                  old_cursor.par()->GetLayout())).keepempty)
2525                 return;
2526
2527         LyXCursor tmpcursor;
2528
2529         if (old_cursor.par() != cursor.par()) {
2530                 if ((old_cursor.par()->size() == 0
2531                       || (old_cursor.par()->size() == 1
2532                           && old_cursor.par()->IsLineSeparator(0)))) {
2533                         // ok, we will delete anything
2534                         
2535                         // make sure that you do not delete any environments
2536                                 status = LyXText::NEED_MORE_REFRESH;
2537                                 deleted = true;
2538                                 
2539                                 if (old_cursor.row()->previous()) {
2540                                         refresh_row = old_cursor.row()->previous();
2541                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2542                                         tmpcursor = cursor;
2543                                         cursor = old_cursor; // that undo can restore the right cursor position
2544                                         LyXParagraph * endpar = old_cursor.par()->next();
2545                                         if (endpar && endpar->GetDepth()) {
2546                                                 while (endpar && endpar->GetDepth()) {
2547                                                         endpar = endpar->next();
2548                                                 }
2549                                         }
2550                                         SetUndo(bview->buffer(), Undo::DELETE,
2551                                                 old_cursor.par()->previous(),
2552                                                 endpar);
2553                                         cursor = tmpcursor;
2554
2555                                         // delete old row
2556                                         RemoveRow(old_cursor.row());
2557                                         if (OwnerParagraph() == old_cursor.par()) {
2558                                                 OwnerParagraph(OwnerParagraph()->next());
2559                                         }
2560                                         // delete old par
2561                                         delete old_cursor.par();
2562                                         
2563                                         /* Breakagain the next par. Needed
2564                                          * because of the parindent that
2565                                          * can occur or dissappear. The
2566                                          * next row can change its height,
2567                                          * if there is another layout before */
2568                                         if (refresh_row->next()) {
2569                                                 BreakAgain(bview, refresh_row->next());
2570                                                 UpdateCounters(bview, refresh_row);
2571                                         }
2572                                         SetHeightOfRow(bview, refresh_row);
2573                                 } else {
2574                                         refresh_row = old_cursor.row()->next();
2575                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2576                                         
2577                                         tmpcursor = cursor;
2578                                         cursor = old_cursor; // that undo can restore the right cursor position
2579                                         LyXParagraph * endpar = old_cursor.par()->next();
2580                                         if (endpar && endpar->GetDepth()) {
2581                                                 while (endpar && endpar->GetDepth()) {
2582                                                         endpar = endpar->next();
2583                                                 }
2584                                         }
2585                                         SetUndo(bview->buffer(), Undo::DELETE,
2586                                                 old_cursor.par()->previous(),
2587                                                 endpar);
2588                                         cursor = tmpcursor;
2589
2590                                         // delete old row
2591                                         RemoveRow(old_cursor.row());
2592                                         // delete old par
2593                                         if (OwnerParagraph() == old_cursor.par()) {
2594                                                 OwnerParagraph(OwnerParagraph()->next());
2595                                         }
2596
2597                                         delete old_cursor.par();
2598                                         
2599                                         /* Breakagain the next par. Needed
2600                                            because of the parindent that can
2601                                            occur or dissappear.
2602                                            The next row can change its height,
2603                                            if there is another layout before
2604                                         */ 
2605                                         if (refresh_row) {
2606                                                 BreakAgain(bview, refresh_row);
2607                                                 UpdateCounters(bview, refresh_row->previous());
2608                                         }
2609                                 }
2610                                 
2611                                 // correct cursor y
2612
2613                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
2614
2615                                 if (selection.cursor.par()  == old_cursor.par()
2616                                     && selection.cursor.pos() == selection.cursor.pos()) {
2617                                         // correct selection
2618                                         selection.cursor = cursor;
2619                                 }
2620                 }
2621                 if (!deleted) {
2622                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
2623                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2624                                 // correct cursor y
2625                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
2626                                 selection.cursor = cursor;
2627                         }
2628                 }
2629         }
2630 }
2631
2632
2633 LyXParagraph * LyXText::GetParFromID(int id)
2634 {
2635         LyXParagraph * result = FirstParagraph();
2636         while (result && result->id() != id)
2637                 result = result->next();
2638         return result;
2639 }
2640
2641
2642 // undo functions
2643 bool LyXText::TextUndo(BufferView * bview)
2644 {
2645         if (inset_owner)
2646                 return false;
2647         // returns false if no undo possible
2648         Undo * undo = bview->buffer()->undostack.pop();
2649         if (undo) {
2650                 FinishUndo();
2651                 if (!undo_frozen)
2652                         bview->buffer()->redostack
2653                                 .push(CreateUndo(bview->buffer(), undo->kind, 
2654                                                  GetParFromID(undo->number_of_before_par),
2655                                                  GetParFromID(undo->number_of_behind_par)));
2656         }
2657         return TextHandleUndo(bview, undo);
2658 }
2659
2660
2661 bool LyXText::TextRedo(BufferView * bview)
2662 {
2663         if (inset_owner)
2664                 return false;
2665         // returns false if no redo possible
2666         Undo * undo = bview->buffer()->redostack.pop();
2667         if (undo) {
2668                 FinishUndo();
2669                 if (!undo_frozen)
2670                         bview->buffer()->undostack
2671                                 .push(CreateUndo(bview->buffer(), undo->kind, 
2672                                                  GetParFromID(undo->number_of_before_par),
2673                                                  GetParFromID(undo->number_of_behind_par)));
2674         }
2675         return TextHandleUndo(bview, undo);
2676 }
2677
2678
2679 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
2680 {
2681         if (inset_owner)
2682                 return false;
2683         // returns false if no undo possible
2684         bool result = false;
2685         if (undo) {
2686                 LyXParagraph * before =
2687                         GetParFromID(undo->number_of_before_par); 
2688                 LyXParagraph * behind =
2689                         GetParFromID(undo->number_of_behind_par); 
2690                 LyXParagraph * tmppar;
2691                 LyXParagraph * tmppar2;
2692                 LyXParagraph * endpar;
2693                 LyXParagraph * tmppar5;
2694     
2695                 // if there's no before take the beginning
2696                 // of the document for redoing
2697                 if (!before)
2698                         SetCursorIntern(bview, FirstParagraph(), 0);
2699
2700                 // replace the paragraphs with the undo informations
2701
2702                 LyXParagraph * tmppar3 = undo->par;
2703                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2704                 LyXParagraph * tmppar4 = tmppar3;
2705
2706                 if (tmppar4) {
2707                         while (tmppar4->next())
2708                                 tmppar4 = tmppar4->next();
2709                 } // get last undo par
2710     
2711                 // now remove the old text if there is any
2712                 if (before != behind || (!behind && !before)) {
2713                         if (before)
2714                                 tmppar5 = before->next();
2715                         else
2716                                 tmppar5 = OwnerParagraph();
2717                         tmppar2 = tmppar3;
2718                         while (tmppar5 && tmppar5 != behind) {
2719                                 tmppar = tmppar5;
2720                                 tmppar5 = tmppar5->next();
2721                                 // a memory optimization for edit: Only layout information
2722                                 // is stored in the undo. So restore the text informations.
2723                                 if (undo->kind == Undo::EDIT) {
2724                                         tmppar2->setContentsFromPar(tmppar);
2725                                         tmppar->clearContents();
2726                                         tmppar2 = tmppar2->next();
2727                                 }
2728                         }
2729                 }
2730     
2731                 // put the new stuff in the list if there is one
2732                 if (tmppar3){
2733                         if (before)
2734                                 before->next(tmppar3);
2735                         else
2736                                 OwnerParagraph(tmppar3);
2737                         tmppar3->previous(before);
2738                 } else {
2739                         if (!before)
2740                                 OwnerParagraph(behind);
2741                 }
2742                 if (tmppar4) {
2743                         tmppar4->next(behind);
2744                         if (behind)
2745                                 behind->previous(tmppar4);
2746                 }
2747     
2748     
2749                 // Set the cursor for redoing
2750                 if (before) {
2751                         SetCursorIntern(bview, before, 0);
2752                 }
2753
2754                 // calculate the endpar for redoing the paragraphs.
2755                 if (behind) {
2756                                 endpar = behind->next();
2757                 } else
2758                         endpar = behind;
2759     
2760                 tmppar = GetParFromID(undo->number_of_cursor_par);
2761                 RedoParagraphs(bview, cursor, endpar); 
2762                 if (tmppar){
2763                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
2764                         UpdateCounters(bview, cursor.row());
2765                 }
2766                 result = true;
2767                 delete undo;
2768         }
2769         FinishUndo();
2770         return result;
2771 }
2772
2773
2774 void LyXText::FinishUndo()
2775 {
2776         if (inset_owner)
2777                 return;
2778         // makes sure the next operation will be stored
2779         undo_finished = true;
2780 }
2781
2782
2783 void LyXText::FreezeUndo()
2784 {
2785         if (inset_owner)
2786                 return;
2787         // this is dangerous and for internal use only
2788         undo_frozen = true;
2789 }
2790
2791
2792 void LyXText::UnFreezeUndo()
2793 {
2794         if (inset_owner)
2795                 return;
2796         // this is dangerous and for internal use only
2797         undo_frozen = false;
2798 }
2799
2800
2801 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
2802                       LyXParagraph const * before,
2803                       LyXParagraph const * behind) const
2804 {
2805         if (inset_owner)
2806                 return;
2807         if (!undo_frozen)
2808                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
2809         buf->redostack.clear();
2810 }
2811
2812
2813 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
2814                       LyXParagraph const * before, LyXParagraph const * behind)
2815 {
2816         if (inset_owner)
2817                 return;
2818         buf->redostack.push(CreateUndo(buf, kind, before, behind));
2819 }
2820
2821
2822 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
2823                            LyXParagraph const * before,
2824                            LyXParagraph const * behind) const
2825 {
2826         if (inset_owner)
2827                 return 0;
2828
2829         int before_number = -1;
2830         int behind_number = -1;
2831         if (before)
2832                 before_number = before->id();
2833         if (behind)
2834                 behind_number = behind->id();
2835         // Undo::EDIT  and Undo::FINISH are
2836         // always finished. (no overlapping there)
2837         // overlapping only with insert and delete inside one paragraph: 
2838         // Nobody wants all removed  character
2839         // appear one by one when undoing. 
2840         // EDIT is special since only layout information, not the
2841         // contents of a paragaph are stored.
2842         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2843                 // check wether storing is needed
2844                 if (!buf->undostack.empty() && 
2845                     buf->undostack.top()->kind == kind &&
2846                     buf->undostack.top()->number_of_before_par ==  before_number &&
2847                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
2848                         // no undo needed
2849                         return 0;
2850                 }
2851         }
2852         // create a new Undo
2853         LyXParagraph * undopar;
2854
2855         LyXParagraph * start = 0;
2856         LyXParagraph * end = 0;
2857
2858         if (before)
2859                 start = const_cast<LyXParagraph*>(before->next());
2860         else
2861                 start = FirstParagraph();
2862         if (behind)
2863                 end = const_cast<LyXParagraph*>(behind->previous());
2864         else {
2865                 end = FirstParagraph();
2866                 while (end->next())
2867                         end = end->next();
2868         }
2869         if (start && end && (start != end->next()) &&
2870             ((before != behind) || (!before && !behind))) {
2871                 LyXParagraph * tmppar = start;
2872                 LyXParagraph * tmppar2 = new LyXParagraph(*tmppar);
2873                 tmppar2->id(tmppar->id());
2874                 
2875                 // a memory optimization: Just store the layout information
2876                 // when only edit
2877                 if (kind == Undo::EDIT){
2878                         //tmppar2->text.clear();
2879                         tmppar2->clearContents();
2880                 }
2881
2882                 undopar = tmppar2;
2883   
2884                 while (tmppar != end && tmppar->next()) {
2885                         tmppar = tmppar->next();
2886                         tmppar2->next(new LyXParagraph(*tmppar));
2887                         tmppar2->next()->id(tmppar->id());
2888                         // a memory optimization: Just store the layout
2889                         // information when only edit
2890                         if (kind == Undo::EDIT){
2891                                 //tmppar2->next->text.clear();
2892                                 tmppar2->clearContents();
2893                         }
2894                         tmppar2->next()->previous(tmppar2);
2895                         tmppar2 = tmppar2->next();
2896                 }
2897                 tmppar2->next(0);
2898         } else
2899                 undopar = 0; // nothing to replace (undo of delete maybe)
2900
2901         int cursor_par = cursor.par()->id();
2902         int cursor_pos =  cursor.pos();
2903         
2904         Undo * undo = new Undo(kind, 
2905                                before_number, behind_number,  
2906                                cursor_par, cursor_pos, 
2907                                undopar);
2908   
2909         undo_finished = false;
2910         return undo;
2911 }
2912
2913
2914 void LyXText::SetCursorParUndo(Buffer * buf)
2915 {
2916         if (inset_owner)
2917                 return;
2918         SetUndo(buf, Undo::FINISH,
2919                 cursor.par()->previous(),
2920                 cursor.par()->next()); 
2921 }
2922
2923
2924 void LyXText::toggleAppendix(BufferView * bview)
2925 {
2926         LyXParagraph * par = cursor.par();
2927         bool start = !par->params.startOfAppendix();
2928
2929         // ensure that we have only one start_of_appendix in this document
2930         LyXParagraph * tmp = FirstParagraph();
2931         for (; tmp; tmp = tmp->next())
2932                 tmp->params.startOfAppendix(false);
2933
2934         par->params.startOfAppendix(start);
2935
2936         // we can set the refreshing parameters now
2937         status = LyXText::NEED_MORE_REFRESH;
2938         refresh_y = 0;
2939         refresh_row = 0; // not needed for full update
2940         UpdateCounters(bview, 0);
2941         SetCursor(bview, cursor.par(), cursor.pos());
2942 }
2943
2944
2945 LyXParagraph * LyXText::OwnerParagraph() const
2946 {
2947         if (inset_owner)
2948                 return inset_owner->par;
2949
2950         return bv_owner->buffer()->paragraph;
2951 }
2952
2953
2954 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
2955 {
2956         if (inset_owner)
2957                 inset_owner->par = p;
2958         else
2959                 bv_owner->buffer()->paragraph = p;
2960         return 0;
2961 }