]> git.lyx.org Git - lyx.git/blob - src/text2.C
fix the outstanding painter drawing problems, now tablelines, mathframe, specialchars...
[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-1999 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include <cctype>
14 #include FORMS_H_LOCATION
15
16
17 #ifdef __GNUG__
18 #pragma implementation "lyxtext.h"
19 #endif
20
21 #include "LString.h"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
24 #include "layout.h"
25 #include "LyXView.h"
26 #include "support/textutils.h"
27 #include "lyx_cb.h"
28 #include "undo.h"
29 #include "minibuffer.h"
30 #include "buffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
33 #include "lyxtext.h"
34 #include "gettext.h"
35 #include "BufferView.h"
36 #include "LyXView.h"
37 #include "lyxrow.h"
38
39 #define FIX_DOUBLE_SPACE 1
40
41 extern BufferView * current_view;
42
43 using std::copy;
44
45 LyXText::LyXText(BufferView * bv, int pw, Buffer * p)
46 {
47         owner_ = bv;
48         firstrow = 0;
49         lastrow = 0;
50         currentrow = 0;
51         currentrow_y = 0;
52         paperwidth = pw;
53         parameters = &p->params;
54         params = p;
55         number_of_rows = 0;
56         refresh_y = 0;
57         status = LyXText::UNCHANGED;
58         LyXParagraph * par = p->paragraph;
59         current_font = GetFont(par, 0);
60    
61         height = 0;
62    
63         while (par) {
64                 InsertParagraph(par, lastrow);
65                 par = par->Next();
66         }
67         // set cursor at the very top position
68         selection = true;           /* these setting is necessary 
69                                        because of the delete-empty-
70                                        paragraph mechanism in
71                                        SetCursor */
72         SetCursor(firstrow->par, 0);
73         sel_cursor = cursor;
74         selection = false;
75         mark_set = false;
76    
77         // no rebreak necessary
78         need_break_row = 0;
79    
80         undo_finished = true;
81         undo_frozen = false;
82
83         // Default layouttype for copy environment type
84         copylayouttype = 0;
85 }
86
87
88 LyXText::~LyXText()
89 {
90         // Delete all rows, this does not touch the paragraphs!
91         Row * tmprow = firstrow;
92         while (firstrow) {
93                 tmprow = firstrow->next;
94                 delete firstrow;
95                 firstrow = tmprow;
96         }
97 }
98
99
100 void LyXText::owner(BufferView * bv)
101 {
102         if (owner_ && bv) lyxerr << "LyXText::owner_ already set!" << endl;
103         owner_ = bv;
104 }
105
106 // Gets the fully instantiated font at a given position in a paragraph
107 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
108 // The difference is that this one is used for displaying, and thus we
109 // are allowed to make cosmetic improvements. For instance make footnotes
110 // smaller. (Asger)
111 // If position is -1, we get the layout font of the paragraph.
112 // If position is -2, we get the font of the manual label of the paragraph.
113 LyXFont LyXText::GetFont(LyXParagraph * par,
114                          LyXParagraph::size_type pos) const
115 {
116         LyXLayout const & layout = 
117                 textclasslist.Style(parameters->textclass, par->GetLayout());
118
119         char par_depth = par->GetDepth();
120         // We specialize the 95% common case:
121         if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
122                 if (pos >= 0){
123                         // 95% goes here
124                         if (layout.labeltype == LABEL_MANUAL
125                             && pos < BeginningOfMainBody(par)) {
126                                 // 1% goes here
127                                 return par->GetFontSettings(pos).
128                                                 realize(layout.reslabelfont);
129                         } else
130                                 return par->GetFontSettings(pos).
131                                                 realize(layout.resfont);
132                 } else {
133                         // 5% goes here.
134                         // process layoutfont for pos == -1 and labelfont for pos < -1
135                         if (pos == -1)
136                                 return layout.resfont;
137                         else
138                                 return layout.reslabelfont;
139                 }
140         }
141
142         // The uncommon case need not be optimized as much
143
144         LyXFont layoutfont, tmpfont;
145
146         if (pos >= 0){
147                 // 95% goes here
148                 if (pos < BeginningOfMainBody(par)) {
149                         // 1% goes here
150                         layoutfont = layout.labelfont;
151                 } else {
152                         // 99% goes here
153                         layoutfont = layout.font;
154                 }
155                 tmpfont = par->GetFontSettings(pos);
156                 tmpfont.realize(layoutfont);
157         } else {
158                 // 5% goes here.
159                 // process layoutfont for pos == -1 and labelfont for pos < -1
160                 if (pos == -1)
161                         tmpfont = layout.font;
162                 else
163                         tmpfont = layout.labelfont;
164         }
165
166         // Resolve against environment font information
167         while (par && par_depth && !tmpfont.resolved()) {
168                 par = par->DepthHook(par_depth - 1);
169                 if (par) {
170                         tmpfont.realize(textclasslist.
171                                         Style(parameters->textclass,
172                                               par->GetLayout()).font);
173                         par_depth = par->GetDepth();
174                 }
175         }
176
177         tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
178
179         // Cosmetic improvement: If this is an open footnote, make the font 
180         // smaller.
181         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
182             && par->footnotekind == LyXParagraph::FOOTNOTE) {
183                 tmpfont.decSize();
184         }
185
186         return tmpfont;
187 }
188
189
190 void LyXText::SetCharFont(LyXParagraph * par,
191                           LyXParagraph::size_type pos,
192                           LyXFont const & fnt)
193 {
194         LyXFont font(fnt);
195         // Let the insets convert their font
196         if (par->GetChar(pos) == LyXParagraph::META_INSET) {
197                 if (par->GetInset(pos))
198                         font = par->GetInset(pos)->ConvertFont(font);
199         }
200
201         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
202                                            par->GetLayout());
203
204         // Get concrete layout font to reduce against
205         LyXFont layoutfont;
206
207         if (pos < BeginningOfMainBody(par))
208                 layoutfont = layout.labelfont;
209         else
210                 layoutfont = layout.font;
211
212         // Realize against environment font information
213         if (par->GetDepth()){
214                 LyXParagraph * tp = par;
215                 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
216                         tp = tp->DepthHook(tp->GetDepth()-1);
217                         if (tp)
218                                 layoutfont.realize(textclasslist.
219                                                 Style(parameters->textclass,
220                                                       tp->GetLayout()).font);
221                 }
222         }
223
224         layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
225
226         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
227             && par->footnotekind == LyXParagraph::FOOTNOTE) {
228                 layoutfont.decSize();
229         }
230
231         // Now, reduce font against full layout font
232         font.reduce(layoutfont);
233
234         par->SetFont(pos, font);
235 }
236
237
238 /* inserts a new row behind the specified row, increments
239  * the touched counters */
240 void LyXText::InsertRow(Row * row, LyXParagraph * par,
241                         LyXParagraph::size_type pos) const
242 {
243         Row * tmprow = new Row;
244         if (!row) {
245                 tmprow->previous = 0;
246                 tmprow->next = firstrow;
247                 firstrow = tmprow;
248         }
249         else {
250                 tmprow->previous = row;
251                 tmprow->next = row->next;
252                 row->next = tmprow;
253         }
254    
255         if (tmprow->next)
256                 tmprow->next->previous = tmprow;
257    
258         if (tmprow->previous)
259                 tmprow->previous->next = tmprow;
260    
261    
262         tmprow->par = par;
263         tmprow->pos = pos;
264    
265         if (row == lastrow)
266                 lastrow = tmprow;
267         ++number_of_rows; // one more row
268 }
269
270
271 // removes the row and reset the touched counters
272 void LyXText::RemoveRow(Row * row) const
273 {
274         /* this must not happen before the currentrow for clear reasons.
275            so the trick is just to set the current row onto the previous
276            row of this row */
277         long unused_y;
278         GetRow(row->par, row->pos, unused_y);
279         currentrow = currentrow->previous;
280         if (currentrow)
281                 currentrow_y -= currentrow->height;
282         else
283                 currentrow_y = 0;
284    
285         if (row->next)
286                 row->next->previous = row->previous;
287         if (!row->previous) {
288                 firstrow = row->next;
289         }
290         else  {
291                 row->previous->next = row->next;
292         }
293         if (row == lastrow)
294                 lastrow = row->previous;
295    
296         height -= row->height;   // the text becomes smaller
297    
298         delete row;
299         --number_of_rows;       // one row less
300 }
301
302
303 // remove all following rows of the paragraph of the specified row.
304 void LyXText::RemoveParagraph(Row * row) const
305 {
306         LyXParagraph * tmppar = row->par;
307         row = row->next;
308     
309         Row * tmprow;
310         while (row && row->par == tmppar) {
311                 tmprow = row->next;
312                 RemoveRow(row);
313                 row = tmprow;
314         }
315 }
316    
317   
318 // insert the specified paragraph behind the specified row
319 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
320 {
321         InsertRow(row, par, 0);        /* insert a new row, starting 
322                                         * at postition 0 */
323
324         SetCounter(par);  // set the counters
325    
326         // and now append the whole paragraph behind the new row
327         if (!row) {
328                 firstrow->height = 0;
329                 AppendParagraph(firstrow);
330         }
331         else {
332                 row->next->height = 0;
333                 AppendParagraph(row->next);
334         }
335 }
336     
337
338 void LyXText::ToggleFootnote()
339 {
340         LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
341         if (par->next
342             && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
343                 OpenFootnote();
344                 current_view->owner()->getMiniBuffer()->Set(_("Opened float"));
345         } else {
346                 current_view->owner()->getMiniBuffer()->Set(_("Closed float"));
347                 CloseFootnote();
348         }
349 }
350
351
352 void LyXText::OpenStuff()
353 {
354         if (cursor.pos == 0 && cursor.par->bibkey){
355                 cursor.par->bibkey->Edit(0, 0);
356         }
357         else if (cursor.pos < cursor.par->Last() 
358                  && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
359                  && cursor.par->GetInset(cursor.pos)->Editable()) {
360                 current_view->owner()->getMiniBuffer()
361                         ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
362                 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
363                         SetCursorParUndo();
364                 cursor.par->GetInset(cursor.pos)->Edit(0, 0);
365         } else {
366                 ToggleFootnote();
367         }
368 }
369
370
371 void LyXText::CloseFootnote()
372 {
373         LyXParagraph * tmppar;
374         LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
375    
376         // if the cursor is not in an open footnote, or 
377         // there is no open footnote in this paragraph, just return.
378         if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
379       
380                 if (!par->next ||
381                     par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
382                         current_view->owner()->getMiniBuffer()
383                                 ->Set(_("Nothing to do"));
384                         return;
385                 }
386    
387                 // ok, move the cursor right before the footnote
388                 // just a little faster than using CursorRight()
389                 for (cursor.pos = 0;
390                      cursor.par->ParFromPos(cursor.pos) != par;
391                      cursor.pos++)
392                         {}
393                 
394                 // now the cursor is at the beginning of the physical par
395                 SetCursor(cursor.par,
396                           cursor.pos +
397                           cursor.par->ParFromPos(cursor.pos)->text.size());
398         } else  {
399                 /* we are in a footnote, so let us move at the beginning */ 
400                 /* this is just faster than using just CursorLeft() */ 
401        
402                 tmppar = cursor.par;
403                 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
404                         // just a little bit faster than movin the cursor
405                         tmppar = tmppar->Previous();
406                 }
407                 SetCursor(tmppar, tmppar->Last());
408         }
409    
410         // the cursor must be exactly before the footnote
411         par = cursor.par->ParFromPos(cursor.pos);
412    
413         status = LyXText::NEED_MORE_REFRESH;
414         refresh_row = cursor.row;
415         refresh_y = cursor.y - cursor.row->baseline;
416    
417         tmppar = cursor.par;
418         LyXParagraph * endpar = par->NextAfterFootnote()->Next();
419         Row * row = cursor.row;
420    
421         tmppar->CloseFootnote(cursor.pos);
422
423         while (tmppar != endpar) {
424                 RemoveRow(row->next);
425                 if (row->next)
426                         tmppar = row->next->par;
427                 else
428                         tmppar = 0;
429         }
430    
431         AppendParagraph(cursor.row);
432    
433         SetCursor(cursor.par, cursor.pos);
434         sel_cursor = cursor;
435    
436         // just necessary
437         if (cursor.row->next)
438                 SetHeightOfRow(cursor.row->next);
439 }
440
441
442 /* used in setlayout */
443 // Asger is not sure we want to do this...
444 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
445 {
446         LyXFont layoutfont, tmpfont;
447    
448         LyXLayout const & layout =
449                 textclasslist.Style(parameters->textclass, par->GetLayout());
450
451         for (LyXParagraph::size_type pos = 0;
452              pos < par->Last(); ++pos) {
453                 if (pos < BeginningOfMainBody(par))
454                         layoutfont = layout.labelfont;
455                 else
456                         layoutfont = layout.font;
457       
458                 tmpfont = par->GetFontSettings(pos);
459                 tmpfont.reduce(layoutfont);
460                 par->SetFont(pos, tmpfont);
461         }
462 }
463
464
465 // set layout over selection and make a total rebreak of those paragraphs
466 void  LyXText::SetLayout(char layout)
467 {
468         LyXCursor tmpcursor;
469
470         // if there is no selection just set the layout
471         // of the current paragraph  */
472         if (!selection) {
473                 sel_start_cursor = cursor;  // dummy selection
474                 sel_end_cursor = cursor;
475         }
476
477         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
478         LyXParagraph * undoendpar = endpar;
479
480         if (endpar && endpar->GetDepth()) {
481                 while (endpar && endpar->GetDepth()) {
482                         endpar = endpar->LastPhysicalPar()->Next();
483                         undoendpar = endpar;
484                 }
485         }
486         else if (endpar) {
487                 endpar = endpar->Next(); // because of parindents etc.
488         }
489    
490         SetUndo(Undo::EDIT, 
491                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
492                 undoendpar);
493
494         tmpcursor = cursor;                    /* store the current cursor  */
495
496         /* ok we have a selection. This is always between sel_start_cursor
497          * and sel_end cursor */ 
498         cursor = sel_start_cursor;
499    
500         LyXLayout const & lyxlayout =
501                 textclasslist.Style(parameters->textclass, layout);
502    
503         while (cursor.par != sel_end_cursor.par) {
504                 if (cursor.par->footnoteflag ==
505                     sel_start_cursor.par->footnoteflag) {
506                         cursor.par->SetLayout(layout);
507                         MakeFontEntriesLayoutSpecific(cursor.par);
508                         LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
509                         fppar->added_space_top = lyxlayout.fill_top ?
510                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
511                         fppar->added_space_bottom = lyxlayout.fill_bottom ? 
512                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
513                         if (lyxlayout.margintype == MARGIN_MANUAL)
514                                 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
515                         if (lyxlayout.labeltype != LABEL_BIBLIO
516                             && fppar->bibkey) {
517                                 delete fppar->bibkey;
518                                 fppar->bibkey = 0;
519                         }
520                 }
521                 cursor.par = cursor.par->Next();
522         }
523         if (cursor.par->footnoteflag ==
524             sel_start_cursor.par->footnoteflag) {
525                 cursor.par->SetLayout(layout);
526                 MakeFontEntriesLayoutSpecific(cursor.par);
527                 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
528                 fppar->added_space_top = lyxlayout.fill_top ?
529                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
530                 fppar->added_space_bottom = lyxlayout.fill_bottom ? 
531                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
532                 if (lyxlayout.margintype == MARGIN_MANUAL)
533                         cursor.par->SetLabelWidthString(lyxlayout.labelstring());
534                 if (lyxlayout.labeltype != LABEL_BIBLIO
535                     && fppar->bibkey) {
536                         delete fppar->bibkey;
537                         fppar->bibkey = 0;
538                 }
539         }
540    
541         RedoParagraphs(sel_start_cursor, endpar);
542    
543         // we have to reset the selection, because the
544         // geometry could have changed */ 
545         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
546         sel_cursor = cursor;
547         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
548         UpdateCounters(cursor.row);
549         ClearSelection();
550         SetSelection();
551         SetCursor(tmpcursor.par, tmpcursor.pos);
552 }
553
554
555 // increment depth over selection and
556 // make a total rebreak of those paragraphs
557 void  LyXText::IncDepth()
558 {
559         // If there is no selection, just use the current paragraph
560         if (!selection) {
561                 sel_start_cursor = cursor; // dummy selection
562                 sel_end_cursor = cursor;
563         }
564
565         // We end at the next paragraph with depth 0
566         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
567         LyXParagraph * undoendpar = endpar;
568
569         if (endpar && endpar->GetDepth()) {
570                 while (endpar && endpar->GetDepth()) {
571                         endpar = endpar->LastPhysicalPar()->Next();
572                         undoendpar = endpar;
573                 }
574         }
575         else if (endpar) {
576                 endpar = endpar->Next(); // because of parindents etc.
577         }
578         
579         SetUndo(Undo::EDIT, 
580                 sel_start_cursor
581                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
582                 undoendpar);
583
584         LyXCursor tmpcursor = cursor; // store the current cursor
585
586         // ok we have a selection. This is always between sel_start_cursor
587         // and sel_end cursor
588         cursor = sel_start_cursor;
589    
590         bool anything_changed = false;
591    
592         while (true) {
593                 // NOTE: you can't change the depth of a bibliography entry
594                 if (cursor.par->footnoteflag ==
595                     sel_start_cursor.par->footnoteflag
596                     && textclasslist.Style(parameters->textclass,
597                                       cursor.par->GetLayout()
598                                      ).labeltype != LABEL_BIBLIO) {
599                         LyXParagraph * prev =
600                                 cursor.par->FirstPhysicalPar()->Previous();
601                         if (prev 
602                             && (prev->GetDepth() - cursor.par->GetDepth() > 0
603                                 || (prev->GetDepth() == cursor.par->GetDepth()
604                                     && textclasslist.Style(parameters->textclass,
605                                                       prev->GetLayout()).isEnvironment()))) {
606                                 cursor.par->FirstPhysicalPar()->depth++;
607                                 anything_changed = true;
608                                 }
609                 }
610                 if (cursor.par == sel_end_cursor.par)
611                        break;
612                 cursor.par = cursor.par->Next();
613         }
614    
615         // if nothing changed set all depth to 0
616         if (!anything_changed) {
617                 cursor = sel_start_cursor;
618                 while (cursor.par != sel_end_cursor.par) {
619                         cursor.par->FirstPhysicalPar()->depth = 0;
620                         cursor.par = cursor.par->Next();
621                 }
622                 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
623                         cursor.par->FirstPhysicalPar()->depth = 0;
624         }
625    
626         RedoParagraphs(sel_start_cursor, endpar);
627    
628         // we have to reset the selection, because the
629         // geometry could have changed
630         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
631         sel_cursor = cursor;
632         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
633         UpdateCounters(cursor.row);
634         ClearSelection();
635         SetSelection();
636         SetCursor(tmpcursor.par, tmpcursor.pos);
637 }
638
639
640 // decrement depth over selection and
641 // make a total rebreak of those paragraphs
642 void  LyXText::DecDepth()
643 {
644         // if there is no selection just set the layout
645         // of the current paragraph
646         if (!selection) {
647                 sel_start_cursor = cursor; // dummy selection
648                 sel_end_cursor = cursor;
649         }
650    
651         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
652         LyXParagraph * undoendpar = endpar;
653
654         if (endpar && endpar->GetDepth()) {
655                 while (endpar && endpar->GetDepth()) {
656                         endpar = endpar->LastPhysicalPar()->Next();
657                         undoendpar = endpar;
658                 }
659         }
660         else if (endpar) {
661                 endpar = endpar->Next(); // because of parindents etc.
662         }
663    
664         SetUndo(Undo::EDIT, 
665                 sel_start_cursor
666                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
667                 undoendpar);
668
669         LyXCursor tmpcursor = cursor; // store the current cursor
670
671         // ok we have a selection. This is always between sel_start_cursor
672         // and sel_end cursor
673         cursor = sel_start_cursor;
674
675         while (true) {
676                 if (cursor.par->footnoteflag ==
677                     sel_start_cursor.par->footnoteflag) {
678                         if (cursor.par->FirstPhysicalPar()->depth)
679                                 cursor.par->FirstPhysicalPar()->depth--;
680                 }
681                 if (cursor.par == sel_end_cursor.par)
682                         break;
683                 cursor.par = cursor.par->Next();
684         }
685
686         RedoParagraphs(sel_start_cursor, endpar);
687    
688         // we have to reset the selection, because the
689         // geometry could have changed
690         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
691         sel_cursor = cursor;
692         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
693         UpdateCounters(cursor.row);
694         ClearSelection();
695         SetSelection();
696         SetCursor(tmpcursor.par, tmpcursor.pos);
697 }
698
699
700 // set font over selection and make a total rebreak of those paragraphs
701 void  LyXText::SetFont(LyXFont const & font, bool toggleall)
702 {
703         // if there is no selection just set the current_font
704         if (!selection) {
705                 // Determine basis font
706                 LyXFont layoutfont;
707                 if (cursor.pos < BeginningOfMainBody(cursor.par))
708                         layoutfont = GetFont(cursor.par, -2);
709                 else
710                         layoutfont = GetFont(cursor.par, -1);
711                 // Update current font
712                 real_current_font.update(font, toggleall);
713
714                 // Reduce to implicit settings
715                 current_font = real_current_font;
716                 current_font.reduce(layoutfont);
717                 // And resolve it completely
718                 real_current_font.realize(layoutfont);
719                 return;
720         }
721
722         LyXCursor tmpcursor = cursor; // store the current cursor
723    
724         // ok we have a selection. This is always between sel_start_cursor
725         // and sel_end cursor
726    
727         SetUndo(Undo::EDIT, 
728                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
729                 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
730         cursor = sel_start_cursor;
731         while (cursor.par != sel_end_cursor.par ||
732                (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
733                 && cursor.pos < sel_end_cursor.pos)) 
734         {
735                 if (cursor.pos < cursor.par->Last()
736                     && cursor.par->footnoteflag
737                     == sel_start_cursor.par->footnoteflag) {
738                         // an open footnote should behave
739                         // like a closed one
740                         LyXFont newfont = GetFont(cursor.par, cursor.pos);
741                         newfont.update(font, toggleall);
742                         SetCharFont(cursor.par, cursor.pos, newfont);
743                         cursor.pos++;
744                 } else {
745                         cursor.pos = 0;
746                         cursor.par = cursor.par->Next();
747                 }
748         }
749    
750         RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
751    
752         // we have to reset the selection, because the
753         // geometry could have changed
754         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
755         sel_cursor = cursor;
756         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
757         ClearSelection();
758         SetSelection();
759         SetCursor(tmpcursor.par, tmpcursor.pos);
760 }
761
762
763 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
764 {
765         Row * tmprow = cur.row;
766         long y = cur.y - tmprow->baseline;
767
768         SetHeightOfRow(tmprow);
769         LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
770         // find the first row of the paragraph
771         if (first_phys_par != tmprow->par)
772                 while (tmprow->previous
773                        && tmprow->previous->par != first_phys_par) {
774                         tmprow = tmprow->previous;
775                         y -= tmprow->height;
776                         SetHeightOfRow(tmprow);
777                 }
778         while (tmprow->previous && tmprow->previous->par == first_phys_par) {
779                 tmprow = tmprow->previous;
780                 y -= tmprow->height;
781                 SetHeightOfRow(tmprow);
782         }
783         
784         // we can set the refreshing parameters now
785         status = LyXText::NEED_MORE_REFRESH;
786         refresh_y = y;
787         refresh_row = tmprow;
788         SetCursor(cur.par, cur.pos);
789 }
790
791
792 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
793 {
794         Row * tmprow = cur.row;
795    
796         long y = cur.y - tmprow->baseline;
797         SetHeightOfRow(tmprow);
798         LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
799         // find the first row of the paragraph
800         if (first_phys_par != tmprow->par)
801                 while (tmprow->previous && tmprow->previous->par != first_phys_par)  {
802                         tmprow = tmprow->previous;
803                         y -= tmprow->height;
804                 }
805         while (tmprow->previous && tmprow->previous->par == first_phys_par)  {
806                 tmprow = tmprow->previous;
807                 y -= tmprow->height;
808         }
809    
810         // we can set the refreshing parameters now
811         if (status == LyXText::UNCHANGED || y < refresh_y) {
812                 refresh_y = y;
813                 refresh_row = tmprow;
814         }
815         status = LyXText::NEED_MORE_REFRESH;
816         SetCursor(cur.par, cur.pos);
817 }
818
819
820 /* deletes and inserts again all paragaphs between the cursor
821 * and the specified par 
822 * This function is needed after SetLayout and SetFont etc. */
823 void LyXText::RedoParagraphs(LyXCursor const & cur,
824                              LyXParagraph const * endpar) const
825 {
826         Row * tmprow2;
827         LyXParagraph * tmppar, * first_phys_par;
828    
829         Row * tmprow = cur.row;
830    
831         long y = cur.y - tmprow->baseline;
832    
833         if (!tmprow->previous){
834                 first_phys_par = FirstParagraph();   // a trick/hack for UNDO
835         } else {
836                 first_phys_par = tmprow->par->FirstPhysicalPar();
837                 // find the first row of the paragraph
838                 if (first_phys_par != tmprow->par)
839                         while (tmprow->previous
840                                && tmprow->previous->par != first_phys_par) {
841                                 tmprow = tmprow->previous;
842                                 y -= tmprow->height;
843                         }
844                 while (tmprow->previous
845                        && tmprow->previous->par == first_phys_par) {
846                         tmprow = tmprow->previous;
847                         y -= tmprow->height;
848                 }
849         }
850    
851         // we can set the refreshing parameters now
852         status = LyXText::NEED_MORE_REFRESH;
853         refresh_y = y;
854         refresh_row = tmprow->previous;  /* the real refresh row will
855                                             be deleted, so I store
856                                             the previous here */ 
857         // remove it
858         if (tmprow->next)
859                 tmppar = tmprow->next->par;
860         else
861                 tmppar = 0;
862         while (tmppar != endpar) {
863                 RemoveRow(tmprow->next);
864                 if (tmprow->next)
865                         tmppar = tmprow->next->par;
866                 else
867                         tmppar = 0;
868         }  
869    
870         // remove the first one
871         tmprow2 = tmprow;     /* this is because tmprow->previous
872                                  can be 0 */
873         tmprow = tmprow->previous;
874         RemoveRow(tmprow2);
875    
876         tmppar = first_phys_par;
877
878         do {
879                 if (tmppar) {
880                         InsertParagraph(tmppar, tmprow);
881                         if (!tmprow)
882                                 tmprow = firstrow;
883                         while (tmprow->next && tmprow->next->par == tmppar)
884                                 tmprow = tmprow->next;
885                         tmppar = tmppar->Next();
886                 }
887         } while (tmppar != endpar);
888    
889         // this is because of layout changes
890         if (refresh_row) {
891                 refresh_y -= refresh_row->height;
892                 SetHeightOfRow(refresh_row);   
893         } else {
894                 refresh_row = firstrow;
895                 refresh_y = 0;
896                 SetHeightOfRow(refresh_row);   
897         }
898    
899         if (tmprow && tmprow->next)
900                 SetHeightOfRow(tmprow->next);
901 }
902
903
904 int LyXText::FullRebreak()
905 {
906         if (need_break_row) {
907                 BreakAgain(need_break_row);
908                 need_break_row = 0;
909                 return 1;
910         }
911         return 0;
912 }
913
914
915 /* important for the screen */
916
917
918 /* the cursor set functions have a special mechanism. When they
919 * realize, that you left an empty paragraph, they will delete it.
920 * They also delet the corresponding row */
921    
922 // need the selection cursor:
923 void LyXText::SetSelection()
924 {
925         if (!selection) {
926                 last_sel_cursor = sel_cursor;
927                 sel_start_cursor = sel_cursor;
928                 sel_end_cursor = sel_cursor;
929         }
930    
931         selection = True;
932    
933         // first the toggling area
934         if (cursor.y < last_sel_cursor.y ||
935             (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
936                 toggle_end_cursor = last_sel_cursor;
937                 toggle_cursor = cursor;
938         }
939         else {
940                 toggle_end_cursor = cursor;
941                 toggle_cursor = last_sel_cursor;
942         }
943    
944         last_sel_cursor = cursor;
945    
946         // and now the whole selection
947
948         if (sel_cursor.par == cursor.par)
949            if (sel_cursor.pos < cursor.pos) {
950                 sel_end_cursor = cursor;
951                 sel_start_cursor = sel_cursor;
952         } else {
953                 sel_end_cursor = sel_cursor; 
954                 sel_start_cursor = cursor;
955         }
956         else if (sel_cursor.y < cursor.y ||
957             (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
958                 sel_end_cursor = cursor;
959                 sel_start_cursor = sel_cursor;
960         }
961         else {
962                 sel_end_cursor = sel_cursor; 
963                 sel_start_cursor = cursor;
964         }
965    
966         // a selection with no contents is not a selection
967         if (sel_start_cursor.x == sel_end_cursor.x && 
968             sel_start_cursor.y == sel_end_cursor.y)
969                 selection = false;
970 }
971
972
973 void LyXText::ClearSelection() const
974 {
975         selection = false;
976         mark_set = false;
977 }
978
979
980 void LyXText::CursorHome() const
981 {
982         SetCursor(cursor.par, cursor.row->pos);
983 }
984
985
986 void  LyXText::CursorEnd() const
987 {
988         if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
989                 SetCursor(cursor.par, RowLast(cursor.row) + 1);
990         else {
991                 if (cursor.par->Last() && 
992                     (cursor.par->GetChar(RowLast(cursor.row)) == ' '
993                      || cursor.par->IsNewline(RowLast(cursor.row))))
994                         SetCursor(cursor.par, RowLast(cursor.row));
995                 else
996                         SetCursor(cursor.par, RowLast(cursor.row) + 1);
997         }
998         if (cursor.par->table) {
999                 int cell = NumberOfCell(cursor.par, cursor.pos);
1000                 if (cursor.par->table->RowHasContRow(cell) &&
1001                     cursor.par->table->CellHasContRow(cell)<0) {
1002                         if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1003                                 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1004                         else {
1005                                 if (cursor.par->Last() && 
1006                                     (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1007                                      || cursor.par->IsNewline(RowLast(cursor.row))))
1008                                         SetCursor(cursor.par, RowLast(cursor.row));
1009                                 else
1010                                         SetCursor(cursor.par, RowLast(cursor.row) + 1);
1011                         }
1012                 }
1013         }
1014 }
1015
1016
1017 void  LyXText::CursorTop() const
1018 {
1019         while (cursor.par->Previous())
1020                 cursor.par = cursor.par->Previous();
1021         SetCursor(cursor.par, 0);
1022 }
1023
1024
1025 void  LyXText::CursorBottom() const
1026 {
1027         while (cursor.par->Next())
1028                 cursor.par = cursor.par->Next();
1029         SetCursor(cursor.par, cursor.par->Last());
1030 }
1031    
1032    
1033 /* returns a pointer to the row near the specified y-coordinate
1034 * (relative to the whole text). y is set to the real beginning
1035 * of this row */ 
1036 Row * LyXText::GetRowNearY(long & y) const
1037 {
1038         Row * tmprow;
1039         long tmpy;
1040    
1041         if (currentrow) {
1042                 tmprow = currentrow;
1043                 tmpy = currentrow_y;
1044         } else {
1045                 tmprow = firstrow;
1046                 tmpy = 0;
1047         }
1048
1049         if (tmpy <= y)
1050                 while (tmprow->next && tmpy + tmprow->height <= y) {
1051                         tmpy += tmprow->height;
1052                         tmprow = tmprow->next;
1053                 }
1054         else
1055                 while (tmprow->previous && tmpy > y) {
1056                         tmprow = tmprow->previous;
1057                         tmpy -= tmprow->height;
1058                 }
1059
1060         currentrow = tmprow;
1061         currentrow_y = tmpy;
1062
1063         y = tmpy;   // return the real y
1064         return tmprow;
1065 }
1066    
1067
1068 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1069 {
1070         // If the mask is completely neutral, tell user
1071         if (font == LyXFont(LyXFont::ALL_IGNORE)){
1072                 // Could only happen with user style
1073                 current_view->owner()->getMiniBuffer()
1074                         ->Set(_("No font change defined. Use Character under"
1075                                   " the Layout menu to define font change."));
1076                 return;
1077         }
1078
1079         // Try implicit word selection
1080         LyXCursor resetCursor = cursor;
1081         int implicitSelection = SelectWordWhenUnderCursor();
1082
1083         // Set font
1084         SetFont(font, toggleall);
1085
1086         /* Implicit selections are cleared afterwards and cursor is set to the
1087            original position. */
1088         if (implicitSelection) {
1089                 ClearSelection();
1090                 cursor = resetCursor;
1091                 SetCursor( cursor.par, cursor.pos );
1092                 sel_cursor = cursor;
1093         }
1094 }
1095
1096
1097 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1098 {
1099         if (textclasslist.Style(parameters->textclass,
1100                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1101                 return 0;
1102         else
1103                 return par->BeginningOfMainBody();
1104 }
1105
1106
1107 /* if there is a selection, reset every environment you can find
1108 * in the selection, otherwise just the environment you are in */ 
1109 void LyXText::MeltFootnoteEnvironment()
1110 {
1111         LyXParagraph * tmppar, * firsttmppar;
1112    
1113         ClearSelection();
1114    
1115         /* is is only allowed, if the cursor is IN an open footnote.
1116          * Otherwise it is too dangerous */ 
1117         if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1118                 return;
1119    
1120         SetUndo(Undo::FINISH, 
1121                 cursor.par->PreviousBeforeFootnote()->previous,
1122                 cursor.par->NextAfterFootnote()->next);
1123
1124         /* ok, move to the beginning of the footnote. */ 
1125         while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1126                 cursor.par = cursor.par->Previous();
1127    
1128         SetCursor(cursor.par, cursor.par->Last());
1129         /* this is just faster than using CursorLeft(); */ 
1130    
1131         firsttmppar = cursor.par->ParFromPos(cursor.pos);
1132         tmppar = firsttmppar;
1133         /* tmppar is now the paragraph right before the footnote */
1134
1135         char first_footnote_par_is_not_empty = tmppar->next->text.size();
1136    
1137         while (tmppar->next
1138                && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1139                 tmppar = tmppar->next;   /* I use next instead of Next(),
1140                                           * because there cannot be any
1141                                           * footnotes in a footnote
1142                                           * environment */
1143                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1144       
1145                 /* remember the captions and empty paragraphs */
1146                 if ((textclasslist.Style(parameters->textclass,
1147                                          tmppar->GetLayout())
1148                      .labeltype == LABEL_SENSITIVE)
1149                     || !tmppar->Last())
1150                         tmppar->SetLayout(0);
1151         }
1152    
1153         // now we will paste the ex-footnote, if the layouts allow it
1154         // first restore the layout of the paragraph right behind
1155         // the footnote
1156         if (tmppar->next) 
1157                 tmppar->next->MakeSameLayout(cursor.par);
1158
1159         // first the end
1160         if ((!tmppar->GetLayout() && !tmppar->table)
1161             || (tmppar->Next()
1162                 && (!tmppar->Next()->Last()
1163                     || tmppar->Next()->HasSameLayout(tmppar)))) {
1164                 if (tmppar->Next()->Last()
1165                     && tmppar->Next()->IsLineSeparator(0))
1166                         tmppar->Next()->Erase(0);
1167                 tmppar->PasteParagraph();
1168         }
1169
1170         tmppar = tmppar->Next();  /* make sure tmppar cannot be touched
1171                                    * by the pasting of the beginning */
1172
1173         /* then the beginning */ 
1174         /* if there is no space between the text and the footnote, so we insert
1175          * a blank 
1176          * (only if the previous par and the footnotepar are not empty!) */
1177         if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1178             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1179                 if (firsttmppar->text.size()
1180                     && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1181                     && first_footnote_par_is_not_empty) {
1182                         firsttmppar->next->InsertChar(0, ' ');
1183                 }
1184                 firsttmppar->PasteParagraph();
1185         }
1186    
1187         /* now redo the paragaphs */
1188         RedoParagraphs(cursor, tmppar);
1189    
1190         SetCursor(cursor.par, cursor.pos);
1191    
1192         /* sometimes it can happen, that there is a counter change */ 
1193         Row * row = cursor.row;
1194         while (row->next && row->par != tmppar && row->next->par != tmppar)
1195                 row = row->next;
1196         UpdateCounters(row);
1197    
1198    
1199         ClearSelection();
1200 }
1201
1202
1203 /* the DTP switches for paragraphs. LyX will store them in the 
1204 * first physicla paragraph. When a paragraph is broken, the top settings 
1205 * rest, the bottom settings are given to the new one. So I can make shure, 
1206 * they do not duplicate themself and you cannnot make dirty things with 
1207 * them!  */ 
1208
1209 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1210                            bool pagebreak_top, bool pagebreak_bottom,
1211                            VSpace const & space_top,
1212                            VSpace const & space_bottom,
1213                            LyXAlignment align, 
1214                            string labelwidthstring,
1215                            bool noindent) 
1216 {
1217         LyXCursor tmpcursor = cursor;
1218         if (!selection) {
1219                 sel_start_cursor = cursor;
1220                 sel_end_cursor = cursor;
1221         }
1222
1223         // make sure that the depth behind the selection are restored, too
1224         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1225         LyXParagraph * undoendpar = endpar;
1226
1227         if (endpar && endpar->GetDepth()) {
1228                 while (endpar && endpar->GetDepth()) {
1229                         endpar = endpar->LastPhysicalPar()->Next();
1230                         undoendpar = endpar;
1231                 }
1232         }
1233         else if (endpar) {
1234                 endpar = endpar->Next(); // because of parindents etc.
1235         }
1236    
1237         SetUndo(Undo::EDIT, 
1238                 sel_start_cursor
1239                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1240                 undoendpar);
1241
1242         
1243         LyXParagraph * tmppar = sel_end_cursor.par;
1244         while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1245                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1246                 status = LyXText::NEED_MORE_REFRESH;
1247                 refresh_row = cursor.row;
1248                 refresh_y = cursor.y - cursor.row->baseline;
1249                 if (cursor.par->footnoteflag ==
1250                     sel_start_cursor.par->footnoteflag) {
1251                         cursor.par->line_top = line_top;
1252                         cursor.par->line_bottom = line_bottom;
1253                         cursor.par->pagebreak_top = pagebreak_top;
1254                         cursor.par->pagebreak_bottom = pagebreak_bottom;
1255                         cursor.par->added_space_top = space_top;
1256                         cursor.par->added_space_bottom = space_bottom;
1257                         // does the layout allow the new alignment?
1258                         if (align == LYX_ALIGN_LAYOUT)
1259                                 align = textclasslist
1260                                         .Style(parameters->textclass,
1261                                                cursor.par->GetLayout()).align;
1262                         if (align & textclasslist
1263                             .Style(parameters->textclass,
1264                                    cursor.par->GetLayout()).alignpossible) {
1265                                 if (align == textclasslist
1266                                     .Style(parameters->textclass,
1267                                            cursor.par->GetLayout()).align)
1268                                         cursor.par->align = LYX_ALIGN_LAYOUT;
1269                                 else
1270                                         cursor.par->align = align;
1271                         }
1272                         cursor.par->SetLabelWidthString(labelwidthstring);
1273                         cursor.par->noindent = noindent;
1274                 }
1275                 
1276                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1277         }
1278         
1279         RedoParagraphs(sel_start_cursor, endpar);
1280         
1281         ClearSelection();
1282         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1283         sel_cursor = cursor;
1284         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1285         SetSelection();
1286         SetCursor(tmpcursor.par, tmpcursor.pos);
1287 }
1288
1289
1290 void LyXText::SetParagraphExtraOpt(int type,
1291                                    char const * width,
1292                                    char const * widthp,
1293                                    int alignment, bool hfill,
1294                                    bool start_minipage)
1295 {
1296         LyXCursor tmpcursor = cursor;
1297         LyXParagraph * tmppar;
1298         if (!selection) {
1299                 sel_start_cursor = cursor;
1300                 sel_end_cursor = cursor;
1301         }
1302
1303         // make sure that the depth behind the selection are restored, too
1304         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1305         LyXParagraph * undoendpar = endpar;
1306
1307         if (endpar && endpar->GetDepth()) {
1308                 while (endpar && endpar->GetDepth()) {
1309                         endpar = endpar->LastPhysicalPar()->Next();
1310                         undoendpar = endpar;
1311                 }
1312         }
1313         else if (endpar) {
1314                 endpar = endpar->Next(); // because of parindents etc.
1315         }
1316    
1317         SetUndo(Undo::EDIT, 
1318                 sel_start_cursor
1319                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1320                 undoendpar);
1321         
1322         tmppar = sel_end_cursor.par;
1323         while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1324                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1325                 status = LyXText::NEED_MORE_REFRESH;
1326                 refresh_row = cursor.row;
1327                 refresh_y = cursor.y - cursor.row->baseline;
1328                 if (cursor.par->footnoteflag ==
1329                     sel_start_cursor.par->footnoteflag) {
1330                         if (type == LyXParagraph::PEXTRA_NONE) {
1331                                 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1332                                         cursor.par->UnsetPExtraType();
1333                                         cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1334                                 }
1335                         } else {
1336                                 cursor.par->SetPExtraType(type, width, widthp);
1337                                 cursor.par->pextra_hfill = hfill;
1338                                 cursor.par->pextra_start_minipage = start_minipage;
1339                                 cursor.par->pextra_alignment = alignment;
1340                         }
1341                 }
1342                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1343         }
1344         RedoParagraphs(sel_start_cursor, endpar);
1345         ClearSelection();
1346         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1347         sel_cursor = cursor;
1348         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1349         SetSelection();
1350         SetCursor(tmpcursor.par, tmpcursor.pos);
1351 }
1352
1353
1354 static char const * alphaCounter(int n) {
1355         static char result[2];
1356         result[1] = 0;
1357         if (n == 0)
1358                 return "";
1359         else {
1360                 result[0] = 'A' + n;
1361                 if (n > 'Z')
1362                         return "??";
1363         }
1364         return result;
1365 }
1366
1367
1368 // set the counter of a paragraph. This includes the labels
1369 void LyXText::SetCounter(LyXParagraph * par) const
1370 {
1371         // this is only relevant for the beginning of paragraph
1372         par = par->FirstPhysicalPar();
1373
1374         LyXLayout const & layout = textclasslist.Style(parameters->textclass, 
1375                                                        par->GetLayout());
1376
1377         LyXTextClass const & textclass =
1378                 textclasslist.TextClass(parameters->textclass);
1379
1380         /* copy the prev-counters to this one, unless this is the start of a 
1381            footnote or of a bibliography or the very first paragraph */
1382         if (par->Previous()
1383             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1384                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1385                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1386             && !(textclasslist.Style(parameters->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->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1394                 if (!par->appendix && par->start_of_appendix){
1395                   par->appendix = true;
1396                   for (int i = 0; i < 10; ++i) {
1397                     par->setCounter(i, 0);
1398                   }  
1399                 }
1400                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1401                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1402         }
1403         else {
1404                 for (int i = 0; i < 10; ++i) {
1405                         par->setCounter(i, 0);
1406                 }  
1407                 par->appendix = par->start_of_appendix;
1408                 par->enumdepth = 0;
1409                 par->itemdepth = 0;
1410         }
1411
1412         // if this is an open marginnote and this is the first
1413         // entry in the marginnote and the enclosing
1414         // environment is an enum/item then correct for the
1415         // LaTeX behaviour (ARRae)
1416         if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1417            && par->footnotekind == LyXParagraph::MARGIN
1418            && par->Previous()
1419            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1420            && (par->PreviousBeforeFootnote()
1421                && textclasslist.Style(parameters->textclass,
1422                                  par->PreviousBeforeFootnote()->GetLayout()
1423                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1424                 // Any itemize or enumerate environment in a marginnote
1425                 // that is embedded in an itemize or enumerate
1426                 // paragraph is seen by LaTeX as being at a deeper
1427                 // level within that enclosing itemization/enumeration
1428                 // even if there is a "standard" layout at the start of
1429                 // the marginnote.
1430                 par->enumdepth++;
1431                 par->itemdepth++;
1432         }
1433
1434         /* Maybe we have to increment the enumeration depth.
1435          * BUT, enumeration in a footnote is considered in isolation from its
1436          *      surrounding paragraph so don't increment if this is the
1437          *      first line of the footnote
1438          * AND, bibliographies can't have their depth changed ie. they
1439          *      are always of depth 0
1440          */
1441         if (par->Previous()
1442             && par->Previous()->GetDepth() < par->GetDepth()
1443             && textclasslist.Style(parameters->textclass,
1444                               par->Previous()->GetLayout()
1445                              ).labeltype == LABEL_COUNTER_ENUMI
1446             && par->enumdepth < 3
1447             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1448                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1449                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1450             && layout.labeltype != LABEL_BIBLIO) {
1451                 par->enumdepth++;
1452         }
1453
1454         /* Maybe we have to decrement the enumeration depth, see note above */
1455         if (par->Previous()
1456             && par->Previous()->GetDepth() > par->GetDepth()
1457             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1458                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1459                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1460             && layout.labeltype != LABEL_BIBLIO) {
1461                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1462                 par->setCounter(6 + par->enumdepth,
1463                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1464                 /* reset the counters.
1465                  * A depth change is like a breaking layout
1466                  */
1467                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1468                         par->setCounter(i, 0);
1469         }
1470    
1471         if (!par->labelstring.empty()) {
1472                 par->labelstring.clear();
1473         }
1474    
1475         if (layout.margintype == MARGIN_MANUAL) {
1476                 if (par->labelwidthstring.empty()) {
1477                         par->SetLabelWidthString(layout.labelstring());
1478                 }
1479         }
1480         else {
1481                 par->SetLabelWidthString(string());
1482         }
1483    
1484         /* is it a layout that has an automatic label ? */ 
1485         if (layout.labeltype >=  LABEL_FIRST_COUNTER) {
1486       
1487                 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1488                 if (i >= 0 && i<= parameters->secnumdepth) {
1489                         par->incCounter(i);     // increment the counter  
1490          
1491                         char * s = new char[50];
1492
1493                         // Is there a label? Useful for Chapter layout
1494                         if (!par->appendix){
1495                                 if (!layout.labelstring().empty())
1496                                         par->labelstring = layout.labelstring();
1497                                 else
1498                                         par->labelstring.clear();
1499                         } else {
1500                                 if (!layout.labelstring_appendix().empty())
1501                                         par->labelstring = layout.labelstring_appendix();
1502                                 else
1503                                         par->labelstring.clear();
1504                         }
1505  
1506                         if (!par->appendix){
1507                                 switch (2 * LABEL_FIRST_COUNTER -
1508                                         textclass.maxcounter() + i) {
1509                                 case LABEL_COUNTER_CHAPTER:
1510                                         sprintf(s, "%d",
1511                                                 par->getCounter(i));
1512                                         break;
1513                                 case LABEL_COUNTER_SECTION:
1514                                         sprintf(s, "%d.%d",
1515                                                 par->getCounter(i - 1),
1516                                                 par->getCounter(i));
1517                                         break;
1518                                 case LABEL_COUNTER_SUBSECTION:
1519                                         sprintf(s, "%d.%d.%d",
1520                                                 par->getCounter(i-2),
1521                                                 par->getCounter(i-1),
1522                                                 par->getCounter(i));
1523                                         break;
1524                                 case LABEL_COUNTER_SUBSUBSECTION:
1525                                         sprintf(s, "%d.%d.%d.%d",
1526                                                 par->getCounter(i-3),
1527                                                 par->getCounter(i-2),
1528                                                 par->getCounter(i-1),
1529                                                 par->getCounter(i));
1530                                         break;
1531                                 case LABEL_COUNTER_PARAGRAPH:
1532                                         sprintf(s, "%d.%d.%d.%d.%d",
1533                                                 par->getCounter(i-4),
1534                                                 par->getCounter(i-3),
1535                                                 par->getCounter(i-2),
1536                                                 par->getCounter(i-1),
1537                                                 par->getCounter(i));
1538                                         break;
1539                                 case LABEL_COUNTER_SUBPARAGRAPH:
1540                                         sprintf(s, "%d.%d.%d.%d.%d.%d",
1541                                                 par->getCounter(i-5),
1542                                                 par->getCounter(i-4),
1543                                                 par->getCounter(i-3),
1544                                                 par->getCounter(i-2),
1545                                                 par->getCounter(i-1),
1546                                                 par->getCounter(i));
1547                                         break;
1548                                 default:
1549                                         sprintf(s, "%d.", par->getCounter(i));
1550                                         break;
1551                                 }
1552                         } else {
1553                                 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1554                                 case LABEL_COUNTER_CHAPTER:
1555                                         sprintf(s, "%s",
1556                                                 alphaCounter(par->getCounter(i)));
1557                                         break;
1558                                 case LABEL_COUNTER_SECTION:
1559                                         sprintf(s, "%s.%d",
1560                                                 alphaCounter(par->getCounter(i - 1)),
1561                                                 par->getCounter(i));
1562                                         break;
1563                                 case LABEL_COUNTER_SUBSECTION:
1564                                         sprintf(s, "%s.%d.%d",
1565                                                 alphaCounter(par->getCounter(i-2)),
1566                                                 par->getCounter(i-1),
1567                                                 par->getCounter(i));
1568                                         break;
1569                                 case LABEL_COUNTER_SUBSUBSECTION:
1570                                         sprintf(s, "%s.%d.%d.%d",
1571                                                 alphaCounter(par->getCounter(i-3)),
1572                                                 par->getCounter(i-2),
1573                                                 par->getCounter(i-1),
1574                                                 par->getCounter(i));
1575                                         break;
1576                                 case LABEL_COUNTER_PARAGRAPH:
1577                                         sprintf(s, "%s.%d.%d.%d.%d",
1578                                                 alphaCounter(par->getCounter(i-4)),
1579                                                 par->getCounter(i-3),
1580                                                 par->getCounter(i-2),
1581                                                 par->getCounter(i-1),
1582                                                 par->getCounter(i));
1583                                         break;
1584                                 case LABEL_COUNTER_SUBPARAGRAPH:
1585                                         sprintf(s, "%s.%d.%d.%d.%d.%d",
1586                                                 alphaCounter(par->getCounter(i-5)),
1587                                                 par->getCounter(i-4),
1588                                                 par->getCounter(i-3),
1589                                                 par->getCounter(i-2),
1590                                                 par->getCounter(i-1),
1591                                                 par->getCounter(i));
1592                                         break;
1593                                 default:
1594                                         sprintf(s, "%c.", par->getCounter(i));
1595                                         break;
1596                                 }
1597                         }
1598          
1599                         par->labelstring += s;
1600                         delete[] s;
1601          
1602                         for (i++; i < 10; ++i) {
1603                                 // reset the following counters
1604                                 par->setCounter(i, 0);
1605                         }
1606                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1607                         for (i++; i < 10; ++i) {
1608                                 // reset the following counters
1609                                 par->setCounter(i, 0);
1610                         }
1611                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1612                         par->incCounter(i + par->enumdepth);
1613                         char * s = new char[25];
1614                         int number = par->getCounter(i + par->enumdepth);
1615
1616                         static const char *roman[20] = {
1617                                 "i",   "ii",  "iii", "iv", "v",
1618                                 "vi",  "vii", "viii", "ix", "x",
1619                                 "xi",  "xii", "xiii", "xiv", "xv",
1620                                 "xvi", "xvii", "xviii", "xix", "xx"
1621                         };
1622                         static const char hebrew[22] = {
1623                                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1624                                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1625                                 '÷', 'ø', 'ù', 'ú'
1626                         };
1627
1628                         switch (par->enumdepth) {
1629                         case 1:
1630                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1631                                         sprintf(s, "(%c)", ((number-1) % 26) + 'a');
1632                                 else
1633                                         sprintf(s, "(%c)", hebrew[(number-1) % 22]);
1634                                 break;
1635                         case 2:
1636                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1637                                         sprintf(s, "%s.", roman[(number-1) % 20]);
1638                                 else
1639                                         sprintf(s, ".%s", roman[(number-1) % 20]);
1640                                 break;
1641                         case 3:
1642                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1643                                         sprintf(s, "%c.", ((number-1) % 26) + 'A');
1644                                 else
1645                                         sprintf(s, ".%c", ((number-1) % 26) + 'A');
1646                                 break;
1647                         default:
1648                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1649                                         sprintf(s, "%d.", number);
1650                                 else
1651                                         sprintf(s, ".%d", number);      
1652                                 break;
1653                         }
1654                         par->labelstring = s;
1655                         delete[] s;
1656
1657                         for (i += par->enumdepth + 1; i < 10; ++i)
1658                                 par->setCounter(i, 0);  /* reset the following counters  */
1659          
1660                 } 
1661         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1662                 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1663                 par->incCounter(i);
1664                 int number = par->getCounter(i);
1665                 if (!par->bibkey)
1666                         par->bibkey = new InsetBibKey();
1667                 par->bibkey->setCounter(number);
1668                 par->labelstring = layout.labelstring();
1669                 
1670                 // In biblio should't be following counters but...
1671         } else {
1672                 string s = layout.labelstring();
1673                 
1674                 // the caption hack:
1675       
1676                 if (layout.labeltype == LABEL_SENSITIVE) {
1677                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1678                             && (par->footnotekind == LyXParagraph::FIG
1679                                 || par->footnotekind == LyXParagraph::WIDE_FIG))
1680                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1681                                         s = "Figure:";
1682                                 else
1683                                         s = ":øåéà";
1684                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1685                                  && (par->footnotekind == LyXParagraph::TAB
1686                                      || par->footnotekind == LyXParagraph::WIDE_TAB))
1687                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1688                                         s = "Table:";
1689                                 else
1690                                         s = ":äìáè";
1691                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1692                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1693                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1694                                         s = "Algorithm:";
1695                                 else
1696                                         s = ":íúéøåâìà";
1697                         else {
1698                                 /* par->SetLayout(0); 
1699                                    s = layout->labelstring;  */
1700                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1701                                         s = "Senseless: ";
1702                                 else
1703                                         s = " :úåòîùî Ã¸Ã±Ã§";
1704            
1705                         }
1706                 }
1707                 par->labelstring = s;
1708                 
1709                 /* reset the enumeration counter. They are always resetted
1710                  * when there is any other layout between */ 
1711                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1712                         par->setCounter(i, 0);
1713         }
1714 }
1715
1716
1717 /* Updates all counters BEHIND the row. Changed paragraphs
1718 * with a dynamic left margin will be rebroken. */ 
1719 void LyXText::UpdateCounters(Row * row) const
1720 {
1721         LyXParagraph * par;
1722         if (!row) {
1723                 row = firstrow;
1724                 par = row->par;
1725         }
1726         else {
1727                 if (row->par->next
1728                     && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1729                         par = row->par->LastPhysicalPar()->Next();
1730                 } else {
1731                         par = row->par->next;
1732                 }
1733         }
1734
1735         while (par) {
1736                 while (row->par != par)
1737                         row = row->next;
1738                 
1739                 SetCounter(par);
1740                 
1741                 /* now  check for the headline layouts. remember that they
1742                  * have a dynamic left margin */ 
1743                 if (!par->IsDummy()
1744                     && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1745                          || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1746                         ){
1747          
1748                         /* Rebreak the paragraph */ 
1749                         RemoveParagraph(row);
1750                         AppendParagraph(row);
1751        
1752                         /* think about the damned open footnotes! */ 
1753                         while (par->Next() &&
1754                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1755                                 || par->Next()->IsDummy())){
1756                                 par = par->Next();
1757                                 if (par->IsDummy()) {
1758                                         while (row->par != par)
1759                                                 row = row->next;
1760                                         RemoveParagraph(row);
1761                                         AppendParagraph(row);
1762                                 }
1763                         }
1764                 }
1765      
1766                 par = par->LastPhysicalPar()->Next();
1767      
1768         }
1769 }
1770
1771
1772 /* insets an inset. */ 
1773 void LyXText::InsertInset(Inset *inset)
1774 {
1775         SetUndo(Undo::INSERT, 
1776                 cursor.par->ParFromPos(cursor.pos)->previous, 
1777                 cursor.par->ParFromPos(cursor.pos)->next);
1778         cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1779         cursor.par->InsertInset(cursor.pos, inset);
1780         InsertChar(LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1781                                       * The character will not be inserted a
1782                                       * second time */
1783 }
1784
1785
1786 // this is for the simple cut and paste mechanism
1787 static LyXParagraph * simple_cut_buffer = 0;
1788 static char simple_cut_buffer_textclass = 0;
1789
1790 void DeleteSimpleCutBuffer()
1791 {
1792         if (!simple_cut_buffer)
1793                 return;
1794         LyXParagraph * tmppar;
1795
1796         while (simple_cut_buffer) {
1797                 tmppar =  simple_cut_buffer;
1798                 simple_cut_buffer = simple_cut_buffer->next;
1799                 delete tmppar;
1800         }
1801         simple_cut_buffer = 0;
1802 }
1803
1804
1805 void LyXText::copyEnvironmentType()
1806 {
1807         copylayouttype = cursor.par->GetLayout();
1808 }
1809
1810
1811 void LyXText::pasteEnvironmentType()
1812 {
1813         SetLayout(copylayouttype);
1814 }
1815
1816
1817 void LyXText::CutSelection(bool doclear)
1818 {
1819         // This doesn't make sense, if there is no selection
1820         if (!selection)
1821                 return;
1822    
1823         // OK, we have a selection. This is always between sel_start_cursor
1824         // and sel_end cursor
1825         LyXParagraph * tmppar;
1826    
1827         // Check whether there are half footnotes in the selection
1828         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1829             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1830                 tmppar = sel_start_cursor.par;
1831                 while (tmppar != sel_end_cursor.par){
1832                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1833                                 WriteAlert(_("Impossible operation"),
1834                                            _("Don't know what to do with half floats."),
1835                                            _("sorry."));
1836                                 return;
1837                         }
1838                         tmppar = tmppar->Next();
1839                 }
1840         }
1841
1842         /* table stuff -- begin */
1843         if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1844                 if ( sel_start_cursor.par != sel_end_cursor.par) {
1845                         WriteAlert(_("Impossible operation"),
1846                                    _("Don't know what to do with half tables."),
1847                                    _("sorry."));
1848                         return;
1849                 }
1850                 sel_start_cursor.par->table->Reinit();
1851         }
1852         /* table stuff -- end */
1853
1854         // make sure that the depth behind the selection are restored, too
1855         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1856         LyXParagraph * undoendpar = endpar;
1857
1858         if (endpar && endpar->GetDepth()) {
1859                 while (endpar && endpar->GetDepth()) {
1860                         endpar = endpar->LastPhysicalPar()->Next();
1861                         undoendpar = endpar;
1862                 }
1863         } else if (endpar) {
1864                 endpar = endpar->Next(); // because of parindents etc.
1865         }
1866    
1867         SetUndo(Undo::DELETE, 
1868                 sel_start_cursor
1869                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1870                 undoendpar);
1871    
1872         // clear the simple_cut_buffer
1873         DeleteSimpleCutBuffer();
1874    
1875         // set the textclass
1876         simple_cut_buffer_textclass = parameters->textclass;
1877
1878 #ifdef WITH_WARNINGS
1879 #warning Asger: Make cut more intelligent here.
1880 #endif
1881         /* 
1882            White paper for "intelligent" cutting:
1883            
1884            Example: "This is our text."
1885            Using " our " as selection, cutting will give "This istext.".
1886            Using "our" as selection, cutting will give "This is text.".
1887            Using " our" as selection, cutting will give "This is text.".
1888            Using "our " as selection, cutting will give "This is text.".
1889            
1890            All those four selections will (however) paste identically:
1891            Pasting with the cursor right after the "is" will give the
1892            original text with all four selections.
1893            
1894            The rationale is to be intelligent such that words are copied,
1895            cut and pasted in a functional manner.
1896            
1897            This is not implemented yet. (Asger)
1898
1899            The changes below sees to do a lot of what you want. However
1900            I have not verified that all cases work as they should:
1901                      - cut in single row
1902                      - cut in multiple row
1903                      - cut with insets
1904                      - cut across footnotes and paragraph
1905            My simplistic tests show that the idea are basically sound but
1906            there are some items to fix up...we only need to find them
1907            first.
1908
1909            As do redo Asger's example above (with | beeing the cursor in the
1910            result after cutting.):
1911            
1912            Example: "This is our text."
1913            Using " our " as selection, cutting will give "This is|text.".
1914            Using "our"   as selection, cutting will give "This is | text.".
1915            Using " our"  as selection, cutting will give "This is| text.".
1916            Using "our "  as selection, cutting will give "This is |text.".
1917
1918            (Lgb)
1919         */
1920
1921 #ifndef FIX_DOUBLE_SPACE
1922         bool space_wrapped =
1923                 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1924         if (sel_end_cursor.pos > 0
1925             && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1926                 // please break before a space at the end
1927                 sel_end_cursor.pos--;
1928                 space_wrapped = true;
1929         }
1930         // cut behind a space if there is one
1931         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1932                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1933                && (sel_start_cursor.par != sel_end_cursor.par
1934                    || sel_start_cursor.pos < sel_end_cursor.pos))
1935                 sel_start_cursor.pos++; 
1936 #endif
1937         // there are two cases: cut only within one paragraph or
1938         // more than one paragraph
1939    
1940         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
1941             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1942                 // only within one paragraph
1943                 simple_cut_buffer = new LyXParagraph;
1944                 LyXParagraph::size_type i =
1945                         sel_start_cursor.pos;
1946                 for (; i < sel_end_cursor.pos; ++i) {
1947                         /* table stuff -- begin */
1948                         if (sel_start_cursor.par->table
1949                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
1950                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1951                                 sel_start_cursor.pos++;
1952                         } else {
1953                                 /* table stuff -- end */
1954                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1955                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1956                         }
1957                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1958                 }
1959 #ifndef FIX_DOUBLE_SPACE
1960                 // check for double spaces
1961                 if (sel_start_cursor.pos &&
1962                     sel_start_cursor.par->Last() > sel_start_cursor.pos
1963                     && sel_start_cursor.par
1964                     ->IsLineSeparator(sel_start_cursor.pos - 1)
1965                     && sel_start_cursor.par
1966                     ->IsLineSeparator(sel_start_cursor.pos)) {
1967                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1968                 }
1969                 if (space_wrapped)
1970                         simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
1971                                                       ' ');
1972 #endif
1973                 endpar = sel_end_cursor.par->Next();
1974         } else {
1975                 // cut more than one paragraph
1976    
1977                 sel_end_cursor.par
1978                         ->BreakParagraphConservative(sel_end_cursor.pos);
1979 #ifndef FIX_DOUBLE_SPACE
1980                 // insert a space at the end if there was one
1981                 if (space_wrapped)
1982                         sel_end_cursor.par
1983                                 ->InsertChar(sel_end_cursor.par->Last(), ' ');
1984 #endif
1985                 sel_end_cursor.par = sel_end_cursor.par->Next();
1986                 sel_end_cursor.pos = 0;
1987    
1988                 cursor = sel_end_cursor;
1989
1990 #ifndef FIX_DOUBLE_SPACE
1991                 // please break behind a space, if there is one.
1992                 // The space should be copied too
1993                 if (sel_start_cursor.par
1994                     ->IsLineSeparator(sel_start_cursor.pos))
1995                         sel_start_cursor.pos++;
1996 #endif   
1997                 sel_start_cursor.par
1998                         ->BreakParagraphConservative(sel_start_cursor.pos);
1999 #ifndef FIX_DOUBLE_SPACE
2000                 if (!sel_start_cursor.pos
2001                     || sel_start_cursor.par
2002                     ->IsLineSeparator(sel_start_cursor.pos - 1)
2003                     || sel_start_cursor.par
2004                     ->IsNewline(sel_start_cursor.pos - 1)) {
2005                         sel_start_cursor.par->Next()->InsertChar(0, ' ');
2006                 }
2007 #endif
2008                 // store the endparagraph for redoing later
2009                 endpar = sel_end_cursor.par->Next(); /* needed because
2010                                                         the sel_end_
2011                                                         cursor.par
2012                                                         will be pasted! */
2013    
2014                 // store the selection
2015                 simple_cut_buffer = sel_start_cursor.par
2016                         ->ParFromPos(sel_start_cursor.pos)->next;
2017                 simple_cut_buffer->previous = 0;
2018                 sel_end_cursor.par->previous->next = 0;
2019
2020                 // cut the selection
2021                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
2022                         = sel_end_cursor.par;
2023    
2024                 sel_end_cursor.par->previous 
2025                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2026
2027                 // care about footnotes
2028                 if (simple_cut_buffer->footnoteflag) {
2029                         LyXParagraph * tmppar = simple_cut_buffer;
2030                         while (tmppar){
2031                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2032                                 tmppar = tmppar->next;
2033                         }
2034                 }
2035
2036                 // the cut selection should begin with standard layout
2037                 simple_cut_buffer->Clear(); 
2038    
2039                 // paste the paragraphs again, if possible
2040                 if (doclear)
2041                         sel_start_cursor.par->Next()->ClearParagraph();
2042                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2043                     || 
2044                     !sel_start_cursor.par->Next()->Last())
2045                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2046
2047 #ifndef FIX_DOUBLE_SPACE
2048                 // maybe a forgotten blank
2049                 if (sel_start_cursor.pos 
2050                     && sel_start_cursor.par
2051                     ->IsLineSeparator(sel_start_cursor.pos)
2052                     && sel_start_cursor.par
2053                     ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2054                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
2055                 }
2056 #endif
2057         }
2058
2059         // sometimes necessary
2060         if (doclear)
2061                 sel_start_cursor.par->ClearParagraph();
2062
2063         RedoParagraphs(sel_start_cursor, endpar);
2064    
2065         ClearSelection();
2066         cursor = sel_start_cursor;
2067         SetCursor(cursor.par, cursor.pos);
2068         sel_cursor = cursor;
2069         UpdateCounters(cursor.row);
2070 }
2071
2072     
2073 void LyXText::CopySelection()
2074 {
2075         // this doesnt make sense, if there is no selection
2076         if (!selection)
2077                 return;
2078
2079         // ok we have a selection. This is always between sel_start_cursor
2080         // and sel_end cursor
2081         LyXParagraph * tmppar;
2082    
2083         /* check wether there are half footnotes in the selection */
2084         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2085             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2086                 tmppar = sel_start_cursor.par;
2087                 while (tmppar != sel_end_cursor.par) {
2088                         if (tmppar->footnoteflag !=
2089                             sel_end_cursor.par->footnoteflag) {
2090                                 WriteAlert(_("Impossible operation"),
2091                                            _("Don't know what to do"
2092                                              " with half floats."),
2093                                            _("sorry."));
2094                                 return;
2095                         }
2096                         tmppar = tmppar->Next();
2097                 }
2098         }
2099
2100         /* table stuff -- begin */
2101         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2102                 if ( sel_start_cursor.par != sel_end_cursor.par){
2103                         WriteAlert(_("Impossible operation"),
2104                                    _("Don't know what to do with half tables."),
2105                                    _("sorry."));
2106                         return;
2107                 }
2108         }
2109         /* table stuff -- end */
2110    
2111         // delete the simple_cut_buffer
2112         DeleteSimpleCutBuffer();
2113
2114         // set the textclass
2115         simple_cut_buffer_textclass = parameters->textclass;
2116
2117 #ifdef FIX_DOUBLE_SPACE
2118         // copy behind a space if there is one
2119         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2120                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2121                && (sel_start_cursor.par != sel_end_cursor.par
2122                    || sel_start_cursor.pos < sel_end_cursor.pos))
2123                 sel_start_cursor.pos++; 
2124 #endif
2125         // there are two cases: copy only within one paragraph
2126         // or more than one paragraph
2127         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2128             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2129                 // only within one paragraph
2130                 simple_cut_buffer = new LyXParagraph;
2131                 LyXParagraph::size_type i = 0;
2132                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2133                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2134                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2135                 }
2136         } else {
2137                 // copy more than one paragraph
2138                 // clone the paragraphs within the selection
2139                 tmppar =
2140                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2141                 simple_cut_buffer = tmppar->Clone();
2142                 LyXParagraph *tmppar2 = simple_cut_buffer;
2143      
2144                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2145                        && tmppar->next) {
2146                         tmppar = tmppar->next;
2147                         tmppar2->next = tmppar->Clone();
2148                         tmppar2->next->previous = tmppar2;
2149                         tmppar2 = tmppar2->next;
2150                 }
2151                 tmppar2->next = 0;
2152
2153                 // care about footnotes
2154                 if (simple_cut_buffer->footnoteflag) {
2155                         tmppar = simple_cut_buffer;
2156                         while (tmppar){
2157                                 tmppar->footnoteflag =
2158                                         LyXParagraph::NO_FOOTNOTE;
2159                                 tmppar = tmppar->next;
2160                         }
2161                 }
2162                 
2163                 // the simple_cut_buffer paragraph is too big
2164                 LyXParagraph::size_type tmpi2 =
2165                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2166                 for (; tmpi2; --tmpi2)
2167                         simple_cut_buffer->Erase(0);
2168                 
2169                 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2170      
2171                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2172                 while (tmppar2->size() > tmpi2) {
2173                         tmppar2->Erase(tmppar2->text.size() - 1);
2174                 }
2175         }
2176 }
2177           
2178
2179 void LyXText::PasteSelection()
2180 {
2181         // this does not make sense, if there is nothing to paste
2182         if (!simple_cut_buffer)
2183                 return;
2184
2185         LyXParagraph * tmppar;
2186         LyXParagraph * endpar;
2187
2188         LyXCursor tmpcursor;
2189
2190         // be carefull with footnotes in footnotes
2191         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2192       
2193                 // check whether the cut_buffer includes a footnote
2194                 tmppar = simple_cut_buffer;
2195                 while (tmppar
2196                        && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2197                         tmppar = tmppar->next;
2198       
2199                 if (tmppar) {
2200                         WriteAlert(_("Impossible operation"),
2201                                    _("Can't paste float into float!"),
2202                                    _("Sorry."));
2203                         return;
2204                 }
2205         }
2206
2207         /* table stuff -- begin */
2208         if (cursor.par->table) {
2209                 if (simple_cut_buffer->next) {
2210                         WriteAlert(_("Impossible operation"),
2211                                    _("Table cell cannot include more than one paragraph!"),
2212                                    _("Sorry."));
2213                         return;
2214                 }
2215         }
2216         /* table stuff -- end */
2217    
2218         SetUndo(Undo::INSERT, 
2219                 cursor.par->ParFromPos(cursor.pos)->previous, 
2220                 cursor.par->ParFromPos(cursor.pos)->next); 
2221
2222         tmpcursor = cursor;
2223
2224         // There are two cases: cutbuffer only one paragraph or many
2225         if (!simple_cut_buffer->next) {
2226                 // only within a paragraph
2227
2228 #ifndef FIX_DOUBLE_SPACE
2229                 // please break behind a space, if there is one
2230                 while (tmpcursor.par->Last() > tmpcursor.pos
2231                        && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2232                         tmpcursor.pos++; 
2233 #endif
2234                 tmppar = simple_cut_buffer->Clone();
2235                 /* table stuff -- begin */
2236                 bool table_too_small = false;
2237                 if (tmpcursor.par->table) {
2238                         while (simple_cut_buffer->text.size()
2239                                && !table_too_small) {
2240                                 if (simple_cut_buffer->IsNewline(0)){
2241                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2242                                                 tmpcursor.pos++;
2243                                         simple_cut_buffer->Erase(0);
2244                                         if (tmpcursor.pos < tmpcursor.par->Last())
2245                                                 tmpcursor.pos++;
2246                                         else
2247                                                 table_too_small = true;
2248                                 } else {
2249 #ifdef FIX_DOUBLE_SPACE
2250                                         // This is an attempt to fix the
2251                                         // "never insert a space at the
2252                                         // beginning of a paragraph" problem.
2253                                         if (tmpcursor.pos == 0
2254                                             && simple_cut_buffer->IsLineSeparator(0)) {
2255                                                 simple_cut_buffer->Erase(0);
2256                                         } else {
2257                                                 simple_cut_buffer->CutIntoMinibuffer(0);
2258                                                 simple_cut_buffer->Erase(0);
2259                                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2260                                                 tmpcursor.pos++;
2261                                         }
2262 #else
2263                                         simple_cut_buffer->CutIntoMinibuffer(0);
2264                                         simple_cut_buffer->Erase(0);
2265                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2266                                         tmpcursor.pos++;
2267 #endif
2268                                 }
2269                         }
2270                 } else {
2271                         /* table stuff -- end */
2272                         // Some provisions should be done here for checking
2273                         // if we are inserting at the beginning of a
2274                         // paragraph. If there are a space at the beginning
2275                         // of the text to insert and we are inserting at
2276                         // the beginning of the paragraph the space should
2277                         // be removed.
2278                         while (simple_cut_buffer->text.size()) {
2279 #ifdef FIX_DOUBLE_SPACE
2280                                 // This is an attempt to fix the
2281                                 // "never insert a space at the
2282                                 // beginning of a paragraph" problem.
2283                                 if (tmpcursor.pos == 0
2284                                     && simple_cut_buffer->IsLineSeparator(0)) {
2285                                         simple_cut_buffer->Erase(0);
2286                                 } else {
2287                                         simple_cut_buffer->CutIntoMinibuffer(0);
2288                                         simple_cut_buffer->Erase(0);
2289                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2290                                         tmpcursor.pos++;
2291                                 }
2292 #else
2293                                 simple_cut_buffer->CutIntoMinibuffer(0);
2294                                 simple_cut_buffer->Erase(0);
2295                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2296                                 tmpcursor.pos++;
2297 #endif
2298                         }
2299                 }
2300                 delete simple_cut_buffer;
2301                 simple_cut_buffer = tmppar;
2302                 endpar = tmpcursor.par->Next();
2303         } else {
2304                 // many paragraphs
2305
2306                 // make a copy of the simple cut_buffer
2307                 tmppar = simple_cut_buffer;
2308                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2309                 LyXParagraph * tmppar2 = simple_cut_clone;
2310                 if (cursor.par->footnoteflag){
2311                         tmppar->footnoteflag = cursor.par->footnoteflag;
2312                         tmppar->footnotekind = cursor.par->footnotekind;
2313                 }
2314                 while (tmppar->next) {
2315                         tmppar = tmppar->next;
2316                         tmppar2->next = tmppar->Clone();
2317                         tmppar2->next->previous = tmppar2;
2318                         tmppar2 = tmppar2->next;
2319                         if (cursor.par->footnoteflag){
2320                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2321                                 tmppar->footnotekind = cursor.par->footnotekind;
2322                         }
2323                 }
2324      
2325                 // make sure there is no class difference
2326                 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2327                                             parameters->textclass,
2328                                             simple_cut_buffer);
2329      
2330                 // make the simple_cut_buffer exactly the same layout than
2331                 // the cursor paragraph
2332                 simple_cut_buffer->MakeSameLayout(cursor.par);
2333      
2334                 // find the end of the buffer
2335                 LyXParagraph * lastbuffer = simple_cut_buffer;
2336                 while (lastbuffer->Next())
2337                         lastbuffer = lastbuffer->Next();
2338      
2339 #ifndef FIX_DOUBLE_SPACE
2340                 // Please break behind a space, if there is one. The space 
2341                 // should be copied too.
2342                 if (cursor.par->Last() > cursor.pos
2343                     && cursor.par->IsLineSeparator(cursor.pos))
2344                         cursor.pos++; 
2345 #endif
2346                 bool paste_the_end = false;
2347
2348                 // open the paragraph for inserting the simple_cut_buffer
2349                 // if necessary
2350                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2351                         cursor.par->BreakParagraphConservative(cursor.pos);
2352                         paste_the_end = true;
2353                 }
2354
2355 #ifndef FIX_DOUBLE_SPACE
2356                 // be careful with double spaces
2357                 if ((!cursor.par->Last()
2358                      || cursor.par->IsLineSeparator(cursor.pos - 1)
2359                      || cursor.par->IsNewline(cursor.pos - 1))
2360                     && simple_cut_buffer->text.size()
2361                     && simple_cut_buffer->IsLineSeparator(0))
2362                         simple_cut_buffer->Erase(0);
2363 #endif
2364                 // set the end for redoing later
2365                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2366      
2367                 // paste it!
2368                 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2369                         cursor.par->ParFromPos(cursor.pos)->next;
2370                 cursor.par->ParFromPos(cursor.pos)->next->previous =
2371                         lastbuffer->ParFromPos(lastbuffer->Last());
2372      
2373                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2374                 simple_cut_buffer->previous =
2375                         cursor.par->ParFromPos(cursor.pos);
2376    
2377                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2378                         lastbuffer = cursor.par;
2379      
2380                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2381      
2382                 // store the new cursor position
2383                 tmpcursor.par = lastbuffer;
2384                 tmpcursor.pos = lastbuffer->Last();
2385      
2386                 // maybe some pasting
2387                 if (lastbuffer->Next() && paste_the_end) {
2388                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2389 #ifndef FIX_DOUBLE_SPACE
2390                                 // be careful with double spaces
2391                                 if ((!lastbuffer->Last()
2392                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2393                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2394                                     && lastbuffer->Next()->Last()
2395                                     && lastbuffer->Next()->IsLineSeparator(0))
2396                                         lastbuffer->Next()->Erase(0);
2397 #endif
2398                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2399          
2400                         } else if (!lastbuffer->Next()->Last()) {
2401                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2402 #ifndef FIX_DOUBLE_SPACE
2403                                 // be careful witth double spaces
2404                                 if ((!lastbuffer->Last()
2405                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2406                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2407                                     && lastbuffer->Next()->Last()
2408                                     && lastbuffer->Next()->IsLineSeparator(0))
2409                                         lastbuffer->Next()->Erase(0);
2410 #endif
2411                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2412          
2413                         } else if (!lastbuffer->Last()) {
2414                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2415 #ifndef FIX_DOUBLE_SPACE
2416                                 // be careful witth double spaces
2417                                 if ((!lastbuffer->Last()
2418                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2419                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2420                                     && lastbuffer->Next()->Last()
2421                                     && lastbuffer->Next()->IsLineSeparator(0))
2422                                         lastbuffer->Next()->Erase(0);
2423 #endif
2424                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2425          
2426                         } else
2427                                 lastbuffer->Next()->ClearParagraph();
2428                 }
2429
2430                 // restore the simple cut buffer
2431                 simple_cut_buffer = simple_cut_clone;
2432         }
2433
2434         RedoParagraphs(cursor, endpar);
2435     
2436         SetCursor(cursor.par, cursor.pos);
2437         ClearSelection();
2438    
2439         sel_cursor = cursor;
2440         SetCursor(tmpcursor.par, tmpcursor.pos);
2441         SetSelection();
2442         UpdateCounters(cursor.row);
2443 }
2444    
2445
2446 // returns a pointer to the very first LyXParagraph
2447 LyXParagraph * LyXText::FirstParagraph() const
2448 {
2449         return params->paragraph;
2450 }
2451
2452
2453 // returns true if the specified string is at the specified position
2454 bool LyXText::IsStringInText(LyXParagraph * par,
2455                              LyXParagraph::size_type pos,
2456                              char const * str) const
2457 {
2458         if (par) {
2459                 int i = 0;
2460                 while (pos + i < par->Last() && str[i] && 
2461                        str[i] == par->GetChar(pos + i)) {
2462                         ++i;
2463                 }
2464                 if (!str[i])
2465                         return true;
2466         }
2467         return false;
2468 }
2469
2470
2471 // sets the selection over the number of characters of string, no check!!
2472 void LyXText::SetSelectionOverString(char const * string)
2473 {
2474         sel_cursor = cursor;
2475         for (int i = 0; string[i]; ++i)
2476                 CursorRight();
2477         SetSelection();
2478 }
2479
2480
2481 // simple replacing. The font of the first selected character is used
2482 void LyXText::ReplaceSelectionWithString(char const * str)
2483 {
2484         SetCursorParUndo();
2485         FreezeUndo();
2486
2487         if (!selection) { // create a dummy selection
2488                 sel_end_cursor = cursor;
2489                 sel_start_cursor = cursor;
2490         }
2491
2492         // Get font setting before we cut
2493         LyXParagraph::size_type pos = sel_end_cursor.pos;
2494         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2495
2496         // Insert the new string
2497         for (int i = 0; str[i]; ++i) {
2498                 sel_end_cursor.par->InsertChar(pos, str[i]);
2499                 sel_end_cursor.par->SetFont(pos, font);
2500                 ++pos;
2501         }
2502
2503         // Cut the selection
2504         CutSelection();
2505
2506         UnFreezeUndo();
2507 }
2508
2509
2510 // if the string can be found: return true and set the cursor to
2511 // the new position
2512 bool LyXText::SearchForward(char const * str) const
2513 {
2514         LyXParagraph * par = cursor.par;
2515         LyXParagraph::size_type pos = cursor.pos;
2516         while (par && !IsStringInText(par, pos, str)) {
2517                 if (pos < par->Last() - 1)
2518                         ++pos;
2519                 else {
2520                         pos = 0;
2521                         par = par->Next();
2522                 }
2523         }
2524         if (par) {
2525                 SetCursor(par, pos);
2526                 return true;
2527         }
2528         else
2529                 return false;
2530 }
2531
2532
2533 bool LyXText::SearchBackward(char const * string) const
2534 {
2535         LyXParagraph * par = cursor.par;
2536         int pos = cursor.pos;
2537
2538         do {
2539                 if (pos > 0)
2540                         --pos;
2541                 else {
2542                         // We skip empty paragraphs (Asger)
2543                         do {
2544                                 par = par->Previous();
2545                                 if (par)
2546                                         pos = par->Last() - 1;
2547                         } while (par && pos < 0);
2548                 }
2549         } while (par && !IsStringInText(par, pos, string));
2550   
2551         if (par) {
2552                 SetCursor(par, pos);
2553                 return true;
2554         } else
2555                 return false;
2556 }
2557
2558
2559 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2560 {
2561         char * str = new char[text.size() + 1];
2562         copy(text.begin(), text.end(), str);
2563         str[text.size()] = '\0';
2564         InsertStringA(str);
2565         delete [] str;
2566 }
2567
2568
2569 // needed to insert the selection
2570 void LyXText::InsertStringA(char const * s)
2571 {
2572         string str(s);
2573         LyXParagraph * par = cursor.par;
2574         LyXParagraph::size_type pos = cursor.pos;
2575         LyXParagraph::size_type a = 0;
2576         int cell = 0;
2577         LyXParagraph * endpar = cursor.par->Next();
2578         
2579         SetCursorParUndo();
2580         
2581         char flag =
2582                 textclasslist.Style(parameters->textclass, 
2583                                     cursor.par->GetLayout()).isEnvironment();
2584         // only to be sure, should not be neccessary
2585         ClearSelection();
2586         
2587         // insert the string, don't insert doublespace
2588         string::size_type i = 0;
2589         while (i < str.length()) {
2590                 if (str[i] != '\n') {
2591                         if (str[i] == ' ' 
2592                             && i + 1 < str.length() && str[i + 1] != ' '
2593                             && pos && par->GetChar(pos - 1)!= ' ') {
2594                                 par->InsertChar(pos,' ');
2595                                 ++pos;
2596                         } else if (par->table) {
2597                                 if (str[i] == '\t') {
2598                                         while((pos < par->size()) &&
2599                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2600                                                 ++pos;
2601                                         if (pos < par->size())
2602                                                 ++pos;
2603                                         else // no more fields to fill skip the rest
2604                                                 break;
2605                                 } else if ((str[i] != 13) &&
2606                                            ((str[i] & 127) >= ' ')) {
2607                                         par->InsertChar(pos, str[i]);
2608                                         ++pos;
2609                                 }
2610                         } else if (str[i] == ' ') {
2611                                 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2612                                 ++pos;
2613                         } else if (str[i] == '\t') {
2614                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2615                                         par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2616                                 }
2617                                 pos = a;
2618                         } else if (str[i]!= 13 && 
2619                                    // Ignore unprintables
2620                                    (str[i] & 127) >= ' ') {
2621                                 par->InsertChar(pos, str[i]);
2622                                 ++pos;
2623                         }
2624                 } else {
2625                         if (par->table) {
2626                                 if (i + 1 >= str.length()) {
2627                                         ++pos;
2628                                         break;
2629                                 }
2630                                 while((pos < par->size()) &&
2631                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2632                                         ++pos;
2633                                 ++pos;
2634                                 cell = NumberOfCell(par, pos);
2635                                 while((pos < par->size()) &&
2636                                       !(par->table->IsFirstCell(cell))) {
2637                                         while((pos < par->size()) &&
2638                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2639                                                 ++pos;
2640                                         ++pos;
2641                                         cell = NumberOfCell(par, pos);
2642                                 }
2643                                 if (pos >= par->size())
2644                                         // no more fields to fill skip the rest
2645                                         break;
2646                         } else {
2647                                 if (!par->text.size()) {
2648                                         par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2649                                         ++pos;
2650                                 }
2651                                 par->BreakParagraph(pos, flag);
2652                                 par = par->Next();
2653                                 pos = 0;
2654                         }
2655                 }
2656                 ++i;
2657         }
2658         
2659         RedoParagraphs(cursor, endpar);
2660         SetCursor(cursor.par, cursor.pos);
2661         sel_cursor = cursor;
2662         SetCursor(par, pos);
2663         SetSelection();
2664 }
2665
2666
2667 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2668 {
2669         char * str = new char[text.size() + 1];
2670         copy(text.begin(), text.end(), str);
2671         str[text.size()] = '\0';
2672         InsertStringB(str);
2673         delete [] str;
2674 }
2675
2676
2677 /* turns double-CR to single CR, others where converted into one blank and 13s 
2678  * that are ignored .Double spaces are also converted into one. Spaces at
2679  * the beginning of a paragraph are forbidden. tabs are converted into one
2680  * space. then InsertStringA is called */ 
2681 void LyXText::InsertStringB(char const * s)
2682 {
2683         string str(s);
2684         LyXParagraph * par = cursor.par;
2685         string::size_type i = 1;
2686         while (i < str.length()) {
2687                 if (str[i] == '\t' && !par->table)
2688                         str[i] = ' ';
2689                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2690                         str[i] = 13;
2691                 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2692                         if (str[i + 1] != '\n') {
2693                                 if (str[i - 1] != ' ')
2694                                         str[i] = ' ';
2695                                 else
2696                                         str[i] = 13;
2697                         }
2698                         while (i + 1 < str.length() 
2699                                && (str[i + 1] == ' ' 
2700                                    || str[i + 1] == '\t'
2701                                    || str[i + 1] == '\n' 
2702                                    || str[i + 1] == 13)) {
2703                                 str[i + 1] = 13;
2704                                 ++i;
2705                         }
2706                 }
2707                 ++i;
2708         }
2709         InsertStringA(str.c_str());
2710 }
2711
2712
2713 bool LyXText::GotoNextError() const
2714 {
2715         LyXCursor res = cursor;
2716         do {
2717                 if (res.pos < res.par->Last() - 1) {
2718                         res.pos++;
2719                 }
2720                 else  {
2721                         res.par = res.par->Next();
2722                         res.pos = 0;
2723                 }
2724       
2725         } while (res.par && 
2726                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2727                    && res.par->GetInset(res.pos)->AutoDelete()));
2728    
2729         if (res.par) {
2730                 SetCursor(res.par, res.pos);
2731                 return true;
2732         }
2733         return false;
2734 }
2735
2736
2737 bool LyXText::GotoNextNote() const
2738 {
2739         LyXCursor res = cursor;
2740         do {
2741                 if (res.pos < res.par->Last() - 1) {
2742                         res.pos++;
2743                 } else  {
2744                         res.par = res.par->Next();
2745                         res.pos = 0;
2746                 }
2747       
2748         } while (res.par && 
2749                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2750                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2751    
2752         if (res.par) {
2753                 SetCursor(res.par, res.pos);
2754                 return true;
2755         }
2756         return false;
2757 }
2758
2759
2760 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2761                                          LyXParagraph * par)
2762 {
2763         int ret = 0;
2764         if (!par || class1 == class2)
2765                 return ret;
2766         par = par->FirstPhysicalPar();
2767         while (par) {
2768                 string name = textclasslist.NameOfLayout(class1, par->layout);
2769                 int lay = 0;
2770                 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2771                         textclasslist.NumberOfLayout(class2, name);
2772                 if (pp.first) {
2773                         lay = pp.second;
2774                 } else { // layout not found
2775                         // use default layout "Standard" (0)
2776                         lay = 0;
2777                 }
2778                 par->layout = lay;
2779       
2780                 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2781                         ++ret;
2782                         string s = "Layout had to be changed from\n"
2783                                 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2784                                 + "\nbecause of class conversion from\n"
2785                                 + textclasslist.NameOfClass(class1) + " to "
2786                                 + textclasslist.NameOfClass(class2);
2787                         InsetError * new_inset = new InsetError(s);
2788                         par->InsertChar(0, LyXParagraph::META_INSET);
2789                         par->InsertInset(0, new_inset);
2790                 }
2791       
2792                 par = par->next;
2793         }
2794         return ret;
2795 }
2796
2797
2798 void LyXText::CheckParagraph(LyXParagraph * par,
2799                              LyXParagraph::size_type pos)
2800 {
2801   
2802         LyXCursor tmpcursor;
2803
2804         /* table stuff -- begin*/
2805    
2806         if (par->table) {
2807                 CheckParagraphInTable(par, pos);
2808         }
2809         else {
2810                 /* table stuff -- end*/
2811      
2812                 long y = 0;
2813                 LyXParagraph::size_type z;
2814                 Row * row = GetRow(par, pos, y);
2815      
2816                 // is there a break one row above
2817                 if (row->previous && row->previous->par == row->par) {
2818                         z = NextBreakPoint(row->previous, paperwidth);
2819                         if ( z >= row->pos) {
2820                                 // set the dimensions of the row above
2821                                 y -= row->previous->height;
2822                                 refresh_y = y;
2823                                 refresh_row = row->previous;
2824                                 status = LyXText::NEED_MORE_REFRESH;
2825        
2826                                 BreakAgain(row->previous);
2827
2828                                 // set the cursor again. Otherwise
2829                                 // dangling pointers are possible
2830                                 SetCursor(cursor.par, cursor.pos);
2831                                 sel_cursor = cursor;
2832                                 return;
2833                         }
2834                 }
2835
2836                 int tmpheight = row->height;
2837                 LyXParagraph::size_type tmplast = RowLast(row);
2838                 refresh_y = y;
2839                 refresh_row = row;
2840
2841                 BreakAgain(row);
2842                 if (row->height == tmpheight && RowLast(row) == tmplast)
2843                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2844                 else
2845                         status = LyXText::NEED_MORE_REFRESH; 
2846    
2847                 // check the special right address boxes
2848                 if (textclasslist.Style(parameters->textclass,
2849                                         par->GetLayout()).margintype
2850                     == MARGIN_RIGHT_ADDRESS_BOX) {
2851                         tmpcursor.par = par;
2852                         tmpcursor.row = row;
2853                         tmpcursor.y = y;
2854                         tmpcursor.x = 0;
2855                         tmpcursor.x_fix = 0;
2856                         tmpcursor.pos = pos;
2857                         RedoDrawingOfParagraph(tmpcursor); 
2858                 }
2859    
2860         }
2861
2862         // set the cursor again. Otherwise dangling pointers are possible
2863         // also set the selection
2864    
2865         if (selection) {
2866                 tmpcursor = cursor;
2867                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2868                 sel_cursor = cursor; 
2869                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2870                 sel_start_cursor = cursor; 
2871                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2872                 sel_end_cursor = cursor; 
2873                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2874                 last_sel_cursor = cursor; 
2875                 cursor = tmpcursor;
2876         }
2877         SetCursorIntern(cursor.par, cursor.pos);
2878 }
2879
2880
2881 // returns 0 if inset wasn't found
2882 int LyXText::UpdateInset(Inset * inset)
2883 {
2884         // first check the current paragraph
2885         int pos = cursor.par->GetPositionOfInset(inset);
2886         if (pos != -1){
2887                 CheckParagraph(cursor.par, pos);
2888                 return 1;
2889         }
2890   
2891         // check every paragraph
2892   
2893         LyXParagraph * par = FirstParagraph();
2894         do {
2895                 // make sure the paragraph is open
2896                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2897                         pos = par->GetPositionOfInset(inset);
2898                         if (pos != -1){
2899                                 CheckParagraph(par, pos);
2900                                 return 1;
2901                         }
2902                 }
2903                 par = par->Next();
2904         } while (par);
2905   
2906         return 0;
2907 }
2908
2909
2910 void LyXText::SetCursor(LyXParagraph * par,
2911                         LyXParagraph::size_type pos, bool setfont) const
2912 {
2913         LyXCursor old_cursor = cursor;
2914         SetCursorIntern(par, pos, setfont);
2915         DeleteEmptyParagraphMechanism(old_cursor);
2916 }
2917
2918
2919 void LyXText::SetCursorIntern(LyXParagraph * par,
2920                               LyXParagraph::size_type pos, bool setfont) const
2921 {
2922         long y;
2923         Row * row;
2924         LyXParagraph * tmppar;
2925         LyXParagraph::size_type vpos,cursor_vpos;
2926
2927         // correct the cursor position if impossible
2928         if (pos > par->Last()){
2929                 tmppar = par->ParFromPos(pos);
2930                 pos = par->PositionInParFromPos(pos);
2931                 par = tmppar;
2932         }
2933         if (par->IsDummy() && par->previous &&
2934             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2935                 while (par->previous &&
2936                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2937                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2938                         par = par->previous ;
2939                         if (par->IsDummy() &&
2940                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2941                                 pos += par->text.size() + 1;
2942                 }
2943                 if (par->previous) {
2944                         par = par->previous;
2945                 }
2946                 pos += par->text.size() + 1;
2947         }
2948
2949         cursor.par = par;
2950         cursor.pos = pos;
2951
2952         if (setfont)
2953                 if (cursor.pos && 
2954                     (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2955                      || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2956                          && !cursor.par->IsSeparator(cursor.pos))
2957                      || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
2958                      )) {
2959                         current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2960                         real_current_font = GetFont(cursor.par, cursor.pos - 1);
2961                 } else {
2962                         current_font = cursor.par->GetFontSettings(cursor.pos);
2963                         real_current_font = GetFont(cursor.par, cursor.pos);
2964                         if (pos == 0 && par->size() == 0 
2965                             && current_view->buffer()->params.getDocumentDirection() == LYX_DIR_RIGHT_TO_LEFT) {
2966                                 current_font.setDirection(LyXFont::RTL_DIR);
2967                                 real_current_font.setDirection(LyXFont::RTL_DIR);
2968                         }
2969                 }
2970
2971         /* get the cursor y position in text  */
2972         row = GetRow(par, pos, y);
2973         /* y is now the beginning of the cursor row */ 
2974         y += row->baseline;
2975         /* y is now the cursor baseline */ 
2976         cursor.y = y;
2977    
2978         /* now get the cursors x position */
2979         float x;
2980         float fill_separator, fill_hfill, fill_label_hfill;
2981         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2982
2983         LyXParagraph::size_type last = RowLast(row);
2984         if (row->pos > last)
2985                 cursor_vpos = 0;
2986         else if (pos <= last ) {
2987                 LyXDirection letter_direction =
2988                         row->par->getLetterDirection(pos);
2989                 LyXDirection font_direction =
2990                         real_current_font.getFontDirection();
2991                 if (letter_direction == font_direction || pos == 0)
2992                         cursor_vpos = (letter_direction == LYX_DIR_LEFT_TO_RIGHT)
2993                                 ? log2vis(pos) : log2vis(pos)+1;
2994                 else
2995                         cursor_vpos = (font_direction == LYX_DIR_LEFT_TO_RIGHT)
2996                                 ? log2vis(pos-1)+1 : log2vis(pos-1);
2997         } else
2998                 cursor_vpos = (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
2999                         ? log2vis(last)+1 : log2vis(last);
3000
3001         /* table stuff -- begin*/
3002         if (row->par->table) {
3003                 int cell = NumberOfCell(row->par, row->pos);
3004                 float x_old = x;
3005                 x += row->par->table->GetBeginningOfTextInCell(cell);
3006                 for (vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3007                         pos = vis2log(vpos);
3008                         if (row->par->IsNewline(pos)) {
3009                                 x = x_old + row->par->table->WidthOfColumn(cell);
3010                                 x_old = x;
3011                                 ++cell;
3012                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3013                         } else {
3014                                 x += SingleWidth(row->par, pos);
3015                         }
3016                 }
3017         } else {
3018                 /* table stuff -- end*/
3019                 LyXParagraph::size_type main_body =
3020                         BeginningOfMainBody(row->par);
3021                 if (main_body > 0 &&
3022                     (main_body-1 > last || 
3023                      !row->par->IsLineSeparator(main_body-1)))
3024                         main_body = 0;
3025
3026                 for (vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3027                         pos = vis2log(vpos);
3028                         if (main_body > 0 && pos == main_body-1) {
3029                                 x += fill_label_hfill +
3030                                         GetFont(row->par, -2).stringWidth(
3031                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3032                                 if (row->par->IsLineSeparator(main_body-1))
3033                                         x -= SingleWidth(row->par, main_body-1);
3034                         }
3035       
3036                         x += SingleWidth(row->par, pos);
3037                         if (HfillExpansion(row, pos)) {
3038                                 if (pos >= main_body)
3039                                         x += fill_hfill;
3040                                 else 
3041                                         x += fill_label_hfill;
3042                         }
3043                         else if (pos >= main_body && row->par->IsSeparator(pos)) {
3044                                 x+= fill_separator;
3045                         }
3046                 }
3047         }
3048    
3049         cursor.x = int(x);
3050    
3051         cursor.x_fix = cursor.x;
3052         cursor.row = row;
3053 }
3054
3055
3056 void LyXText::SetCursorFromCoordinates(int x, long y) const
3057 {
3058         LyXCursor old_cursor = cursor;
3059    
3060         /* get the row first */ 
3061    
3062         Row * row = GetRowNearY(y);
3063    
3064         cursor.par = row->par;
3065    
3066         int column = GetColumnNearX(row, x);
3067         cursor.pos = row->pos + column;
3068         cursor.x = x;
3069         cursor.y = y + row->baseline;
3070    
3071         cursor.row = row;
3072     
3073         if (cursor.pos && 
3074             (cursor.pos == cursor.par->Last()
3075              || cursor.par->IsSeparator(cursor.pos)
3076              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3077                  && !cursor.par->IsSeparator(cursor.pos))
3078              || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3079                     )) {
3080                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3081                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3082         } else {
3083                 current_font = cursor.par->GetFontSettings(cursor.pos);
3084                 real_current_font = GetFont(cursor.par, cursor.pos);
3085         }
3086         DeleteEmptyParagraphMechanism(old_cursor);
3087 }
3088
3089
3090 void LyXText::CursorLeft() const
3091 {
3092         CursorLeftIntern();
3093         if (cursor.par->table) {
3094                 int cell = NumberOfCell(cursor.par, cursor.pos);
3095                 if (cursor.par->table->IsContRow(cell) &&
3096                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3097                         CursorUp();
3098                 }
3099         }
3100 }
3101
3102
3103 void LyXText::CursorLeftIntern() const
3104 {
3105         if (cursor.pos > 0) {
3106                 SetCursor(cursor.par, cursor.pos - 1);
3107         }
3108         else if (cursor.par->Previous()) {
3109                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3110         }
3111 }
3112
3113
3114 void LyXText::CursorRight() const
3115 {
3116         CursorRightIntern();
3117         if (cursor.par->table) {
3118                 int cell = NumberOfCell(cursor.par, cursor.pos);
3119                 if (cursor.par->table->IsContRow(cell) &&
3120                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3121                         CursorUp();
3122                 }
3123         }
3124 }
3125
3126
3127 void LyXText::CursorRightIntern() const
3128 {
3129         if (cursor.pos < cursor.par->Last()) {
3130                 SetCursor(cursor.par, cursor.pos + 1);
3131         }
3132         else if (cursor.par->Next()) {
3133                 SetCursor(cursor.par->Next(), 0);
3134         }
3135 }
3136
3137
3138 void LyXText::CursorUp() const
3139 {
3140         SetCursorFromCoordinates(cursor.x_fix, 
3141                                  cursor.y - cursor.row->baseline - 1);
3142         if (cursor.par->table) {
3143                 int cell = NumberOfCell(cursor.par, cursor.pos);
3144                 if (cursor.par->table->IsContRow(cell) &&
3145                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3146                         CursorUp();
3147                 }
3148         }
3149 }
3150
3151
3152 void LyXText::CursorDown() const
3153 {
3154         if (cursor.par->table &&
3155             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3156             !cursor.par->next)
3157                 return;
3158         SetCursorFromCoordinates(cursor.x_fix, 
3159                                  cursor.y - cursor.row->baseline
3160                                  + cursor.row->height + 1);
3161         if (cursor.par->table) {
3162                 int cell = NumberOfCell(cursor.par, cursor.pos);
3163                 int cell_above = cursor.par->table->GetCellAbove(cell);
3164                 while(cursor.par->table &&
3165                       cursor.par->table->IsContRow(cell) &&
3166                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3167                     SetCursorFromCoordinates(cursor.x_fix, 
3168                                              cursor.y - cursor.row->baseline
3169                                              + cursor.row->height + 1);
3170                     if (cursor.par->table) {
3171                         cell = NumberOfCell(cursor.par, cursor.pos);
3172                         cell_above = cursor.par->table->GetCellAbove(cell);
3173                     }
3174                 }
3175         }
3176 }
3177
3178
3179 void LyXText::CursorUpParagraph() const
3180 {
3181         if (cursor.pos > 0) {
3182                 SetCursor(cursor.par, 0);
3183         }
3184         else if (cursor.par->Previous()) {
3185                 SetCursor(cursor.par->Previous(), 0);
3186         }
3187 }
3188
3189
3190 void LyXText::CursorDownParagraph() const
3191 {
3192         if (cursor.par->Next()) {
3193                 SetCursor(cursor.par->Next(), 0);
3194         } else {
3195                 SetCursor(cursor.par, cursor.par->Last());
3196         }
3197 }
3198
3199
3200
3201 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3202 {
3203         bool deleted = false;
3204         
3205         // this is the delete-empty-paragraph-mechanism.
3206         if (selection) return;
3207
3208 #ifdef FIX_DOUBLE_SPACE
3209         /* Ok I'll put some comments here about what is missing.
3210            I have fixed BackSpace (and thus Delete) to not delete
3211            double-spaces automagically. I have also changed Cut,
3212            Copy and Paste to hopefully do some sensible things.
3213            There are still some small problems that can lead to
3214            double spaces stored in the document file or space at
3215            the beginning of paragraphs. This happens if you have
3216            the cursor betwenn to spaces and then save. Or if you
3217            cut and paste and the selection have a space at the
3218            beginning and then save right after the paste. I am
3219            sure none of these are very hard to fix, but I will
3220            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3221            that I can get some feedback. (Lgb)
3222         */
3223
3224         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3225         // delete the LineSeparator.
3226         // MISSING
3227
3228         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3229         // delete the LineSeparator.
3230         // MISSING
3231
3232         // If the pos around the old_cursor were spaces, delete one of them.
3233         if (!(old_cursor.par == cursor.par && old_cursor.pos == cursor.pos)
3234             && old_cursor.pos > 0
3235             && old_cursor.pos < old_cursor.par->Last()
3236             && old_cursor.par->IsLineSeparator(old_cursor.pos)
3237             && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3238                 old_cursor.par->Erase(old_cursor.pos - 1);
3239                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3240                 // or RedoDrawingOfParagraph(old_cursor);
3241                 // correct cursor
3242                 if (old_cursor.par == cursor.par &&
3243                     cursor.pos > old_cursor.pos)
3244                         SetCursor(cursor.par, cursor.pos - 1);
3245                 else
3246                         SetCursor(cursor.par, cursor.pos);
3247                 return;
3248         }
3249 #endif
3250         //
3251         // Paragraph should not be deleted if empty
3252         if ((textclasslist.Style(parameters->textclass,
3253                                  old_cursor.par->GetLayout())).keepempty)
3254                 return;
3255
3256         LyXCursor tmpcursor;
3257
3258         if (old_cursor.par != cursor.par) {
3259                 if ( (old_cursor.par->Last() == 0
3260                       || (old_cursor.par->Last() == 1
3261                           && (old_cursor.par->IsLineSeparator(0))))
3262                      && old_cursor.par->FirstPhysicalPar()
3263                      == old_cursor.par->LastPhysicalPar()) {
3264                         
3265                         // ok, we will delete anything
3266                         
3267                         // make sure that you do not delete any environments
3268                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3269                              !(old_cursor.row->previous 
3270                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3271                              && !(old_cursor.row->next 
3272                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3273                             || 
3274                             (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3275                              ((old_cursor.row->previous 
3276                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3277                               || 
3278                               (old_cursor.row->next
3279                                && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3280                                     )) {
3281                                 status = LyXText::NEED_MORE_REFRESH;
3282                                 deleted = true;
3283                                 
3284                                 if (old_cursor.row->previous) {
3285                                         refresh_row = old_cursor.row->previous;
3286                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3287                                         tmpcursor = cursor;
3288                                         cursor = old_cursor; // that undo can restore the right cursor position
3289                                         LyXParagraph * endpar = old_cursor.par->next;
3290                                         if (endpar && endpar->GetDepth()) {
3291                                                 while (endpar && endpar->GetDepth()) {
3292                                                         endpar = endpar->LastPhysicalPar()->Next();
3293                                                 }
3294                                         }
3295                                         SetUndo(Undo::DELETE,
3296                                                 old_cursor.par->previous,
3297                                                 endpar);
3298                                         cursor = tmpcursor;
3299
3300                                         // delete old row
3301                                         RemoveRow(old_cursor.row);
3302                                         if (params->paragraph == old_cursor.par) {
3303                                                 params->paragraph = params->paragraph->next;
3304                                         }
3305                                         // delete old par
3306                                         delete old_cursor.par;
3307                                         
3308                                         /* Breakagain the next par. Needed
3309                                          * because of the parindent that
3310                                          * can occur or dissappear. The
3311                                          * next row can change its height,
3312                                          * if there is another layout before */
3313                                         if (refresh_row->next) {
3314                                                 BreakAgain(refresh_row->next);
3315                                                 UpdateCounters(refresh_row);
3316                                         }
3317                                         SetHeightOfRow(refresh_row);
3318                                 } else {
3319                                         refresh_row = old_cursor.row->next;
3320                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3321                                         
3322                                         tmpcursor = cursor;
3323                                         cursor = old_cursor; // that undo can restore the right cursor position
3324                                         LyXParagraph *endpar = old_cursor.par->next;
3325                                         if (endpar && endpar->GetDepth()) {
3326                                                 while (endpar && endpar->GetDepth()) {
3327                                                         endpar = endpar->LastPhysicalPar()->Next();
3328                                                 }
3329                                         }
3330                                         SetUndo(Undo::DELETE,
3331                                                 old_cursor.par->previous,
3332                                                 endpar);
3333                                         cursor = tmpcursor;
3334
3335                                         // delete old row
3336                                         RemoveRow(old_cursor.row);
3337                                         // delete old par
3338                                         if (params->paragraph == old_cursor.par) {
3339                                                 params->paragraph = params->paragraph->next;
3340                                         }
3341                                         delete old_cursor.par;
3342                                         
3343                                         /* Breakagain the next par. Needed
3344                                            because of the parindent that can
3345                                            occur or dissappear.
3346                                            The next row can change its height,
3347                                            if there is another layout before
3348                                         */ 
3349                                         if (refresh_row) {
3350                                                 BreakAgain(refresh_row);
3351                                                 UpdateCounters(refresh_row->previous);
3352                                         }
3353                                 }
3354                                 
3355                                 // correct cursor y
3356                                 SetCursor(cursor.par, cursor.pos);
3357                                 
3358                                 /* if (cursor.y > old_cursor.y)
3359                                    cursor.y -= old_cursor.row->height; */ 
3360          
3361                                 if (sel_cursor.par  == old_cursor.par
3362                                     && sel_cursor.pos == sel_cursor.pos) {
3363                                         // correct selection
3364                                         sel_cursor = cursor;
3365                                 }
3366                         }
3367                 }
3368                 if (!deleted) {
3369                         if (old_cursor.par->ClearParagraph()){
3370                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3371                                 // correct cursor y
3372                                 SetCursor(cursor.par, cursor.pos);
3373                                 sel_cursor = cursor;
3374                         }
3375                 }
3376         }
3377 }
3378
3379
3380 LyXParagraph * LyXText::GetParFromID(int id)
3381 {
3382         LyXParagraph * result = FirstParagraph();
3383         while (result && result->id() != id)
3384                 result = result->next;
3385         return result;
3386 }
3387
3388
3389 // undo functions
3390 bool LyXText::TextUndo()
3391 {
3392         // returns false if no undo possible
3393         Undo * undo = params->undostack.pop();
3394         if (undo) {
3395                 FinishUndo();
3396                 if (!undo_frozen)
3397                         params->redostack
3398                                 .push(CreateUndo(undo->kind, 
3399                                                  GetParFromID(undo->number_of_before_par),
3400                                                  GetParFromID(undo->number_of_behind_par)));
3401         }
3402         return TextHandleUndo(undo);
3403 }
3404
3405
3406 bool LyXText::TextRedo()
3407 {
3408         // returns false if no redo possible
3409         Undo * undo = params->redostack.pop();
3410         if (undo) {
3411                 FinishUndo();
3412                 if (!undo_frozen)
3413                         params->undostack
3414                                 .push(CreateUndo(undo->kind, 
3415                                                  GetParFromID(undo->number_of_before_par),
3416                                                  GetParFromID(undo->number_of_behind_par)));
3417         }
3418         return TextHandleUndo(undo);
3419 }
3420
3421
3422 bool LyXText::TextHandleUndo(Undo * undo)
3423 {
3424         // returns false if no undo possible
3425         bool result = false;
3426         if (undo) {
3427                 LyXParagraph * before =
3428                         GetParFromID(undo->number_of_before_par); 
3429                 LyXParagraph * behind =
3430                         GetParFromID(undo->number_of_behind_par); 
3431                 LyXParagraph * tmppar;
3432                 LyXParagraph * tmppar2;
3433                 LyXParagraph * tmppar3;
3434                 LyXParagraph * tmppar4;
3435                 LyXParagraph * endpar;
3436                 LyXParagraph * tmppar5;
3437     
3438                 // if there's no before take the beginning
3439                 // of the document for redoing
3440                 if (!before)
3441                         SetCursorIntern(FirstParagraph(), 0);
3442
3443                 // replace the paragraphs with the undo informations
3444
3445                 tmppar3 = undo->par;
3446                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3447                 tmppar4 = tmppar3;
3448                 if (tmppar4){
3449                         while (tmppar4->next)
3450                                 tmppar4 = tmppar4->next;
3451                 } // get last undo par
3452     
3453                 // now remove the old text if there is any
3454                 if (before != behind || (!behind && !before)){
3455                         if (before)
3456                                 tmppar5 = before->next;
3457                         else
3458                                 tmppar5 = params->paragraph;
3459                         tmppar2 = tmppar3;
3460                         while (tmppar5 && tmppar5 != behind){
3461                                 tmppar = tmppar5;
3462                                 tmppar5 = tmppar5->next;
3463                                 // a memory optimization for edit: Only layout information
3464                                 // is stored in the undo. So restore the text informations.
3465                                 if (undo->kind == Undo::EDIT){
3466                                         tmppar2->text = tmppar->text;
3467                                         tmppar->text.clear();
3468                                         tmppar2 = tmppar2->next;
3469                                 }
3470                                 if ( currentrow && currentrow->par == tmppar )
3471                                         currentrow = currentrow -> previous;
3472                                 // Commenting out this might remove the error
3473                                 // reported by Purify, but it might also
3474                                 // introduce a memory leak. We need to
3475                                 // check this (Lgb)
3476                                 //delete tmppar;
3477                         }
3478                 }
3479     
3480                 // put the new stuff in the list if there is one
3481                 if (tmppar3){
3482                         if (before)
3483                                 before->next = tmppar3;
3484                         else
3485                                 params->paragraph = tmppar3;
3486                         tmppar3->previous = before;
3487                 }
3488                 else {
3489                         if (!before)
3490                                 params->paragraph = behind;
3491                 }
3492                 if (tmppar4) {
3493                         tmppar4->next = behind;
3494                         if (behind)
3495                                 behind->previous = tmppar4;
3496                 }
3497     
3498     
3499                 // Set the cursor for redoing
3500                 if (before){
3501                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3502                         // check wether before points to a closed float and open it if necessary
3503                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3504                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3505                                 tmppar4 = before;
3506                                 while (tmppar4->previous && 
3507                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3508                                         tmppar4 = tmppar4->previous;
3509                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3510                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3511                                         tmppar4 = tmppar4->next;
3512                                 }
3513                         }
3514                 }
3515     
3516                 // open a cosed footnote at the end if necessary
3517                 if (behind && behind->previous && 
3518                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3519                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3520                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3521                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3522                                 behind = behind->next;
3523                         }
3524                 }
3525     
3526                 // calculate the endpar for redoing the paragraphs.
3527                 if (behind){
3528                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3529                                 endpar = behind->LastPhysicalPar()->Next();
3530                         else
3531                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3532                 }
3533                 else
3534                         endpar = behind;
3535     
3536                 tmppar = GetParFromID(undo->number_of_cursor_par);
3537                 RedoParagraphs(cursor, endpar); 
3538                 if (tmppar){
3539                         SetCursorIntern(tmppar, undo->cursor_pos);
3540                         UpdateCounters(cursor.row);
3541                 }
3542                 result = true;
3543                 delete undo;
3544         }
3545         FinishUndo();
3546         return result;
3547 }
3548
3549
3550 void LyXText::FinishUndo()
3551 {
3552         // makes sure the next operation will be stored
3553         undo_finished = True;
3554 }
3555
3556
3557 void LyXText::FreezeUndo()
3558 {
3559         // this is dangerous and for internal use only
3560         undo_frozen = True;
3561 }
3562
3563
3564 void LyXText::UnFreezeUndo()
3565 {
3566         // this is dangerous and for internal use only
3567         undo_frozen = false;
3568 }
3569
3570
3571 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3572                       LyXParagraph const * behind) const
3573 {
3574         if (!undo_frozen)
3575                 params->undostack.push(CreateUndo(kind, before, behind));
3576         params->redostack.clear();
3577 }
3578
3579
3580 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3581                       LyXParagraph const * behind)
3582 {
3583         params->redostack.push(CreateUndo(kind, before, behind));
3584 }
3585
3586
3587 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3588                           LyXParagraph const * behind) const
3589 {
3590         int before_number = -1;
3591         int behind_number = -1;
3592         if (before)
3593                 before_number = before->id();
3594         if (behind)
3595                 behind_number = behind->id();
3596         // Undo::EDIT  and Undo::FINISH are
3597         // always finished. (no overlapping there)
3598         // overlapping only with insert and delete inside one paragraph: 
3599         // Nobody wants all removed  character
3600         // appear one by one when undoing. 
3601         // EDIT is special since only layout information, not the
3602         // contents of a paragaph are stored.
3603         if (!undo_finished && kind != Undo::EDIT && 
3604             kind != Undo::FINISH){
3605                 // check wether storing is needed
3606                 if (!params->undostack.empty() && 
3607                     params->undostack.top()->kind == kind &&
3608                     params->undostack.top()->number_of_before_par ==  before_number &&
3609                     params->undostack.top()->number_of_behind_par ==  behind_number ){
3610                         // no undo needed
3611                         return 0;
3612                 }
3613         }
3614         // create a new Undo
3615         LyXParagraph * undopar;
3616         LyXParagraph * tmppar;
3617         LyXParagraph * tmppar2;
3618
3619         LyXParagraph * start = 0;
3620         LyXParagraph * end = 0;
3621   
3622         if (before)
3623                 start = before->next;
3624         else
3625                 start = FirstParagraph();
3626         if (behind)
3627                 end = behind->previous;
3628         else {
3629                 end = FirstParagraph();
3630                 while (end->next)
3631                         end = end->next;
3632         }
3633
3634         if (start && end
3635             && start != end->next
3636             && (before != behind || (!before && !behind))) {
3637                 tmppar = start;
3638                 tmppar2 = tmppar->Clone();
3639                 tmppar2->id(tmppar->id());
3640
3641                 // a memory optimization: Just store the layout information
3642                 // when only edit
3643                 if (kind == Undo::EDIT){
3644                         tmppar2->text.clear();
3645                 }
3646
3647                 undopar = tmppar2;
3648   
3649                 while (tmppar != end && tmppar->next) {
3650                         tmppar = tmppar->next;
3651                         tmppar2->next = tmppar->Clone();
3652                         tmppar2->next->id(tmppar->id());
3653                         // a memory optimization: Just store the layout
3654                         // information when only edit
3655                         if (kind == Undo::EDIT){
3656                                 tmppar2->next->text.clear();
3657                         }
3658                         tmppar2->next->previous = tmppar2;
3659                         tmppar2 = tmppar2->next;
3660                 }
3661                 tmppar2->next = 0;
3662         } else
3663                 undopar = 0; // nothing to replace (undo of delete maybe)
3664   
3665         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3666         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3667
3668         Undo * undo = new Undo(kind, 
3669                                before_number, behind_number,  
3670                                cursor_par, cursor_pos, 
3671                                undopar);
3672   
3673         undo_finished = false;
3674         return undo;
3675 }
3676
3677
3678 void LyXText::SetCursorParUndo()
3679 {
3680         SetUndo(Undo::FINISH, 
3681                 cursor.par->ParFromPos(cursor.pos)->previous, 
3682                 cursor.par->ParFromPos(cursor.pos)->next); 
3683 }
3684
3685
3686 void LyXText::RemoveTableRow(LyXCursor * cur) const
3687 {
3688         int cell = -1;
3689         int cell_org = 0;
3690         int ocell = 0;
3691     
3692         // move to the previous row
3693         int cell_act = NumberOfCell(cur->par, cur->pos);
3694         if (cell < 0)
3695                 cell = cell_act;
3696         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3697                 cur->pos--;
3698         while (cur->pos && 
3699                !cur->par->table->IsFirstCell(cell_act)) {
3700                 cur->pos--;
3701                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3702                         cur->pos--;
3703                 --cell;
3704                 --cell_act;
3705         }
3706         // now we have to pay attention if the actual table is the
3707         //   main row of TableContRows and if yes to delete all of them
3708         if (!cell_org)
3709                 cell_org = cell;
3710         do {
3711                 ocell = cell;
3712                 // delete up to the next row
3713                 while (cur->pos < cur->par->Last() && 
3714                        (cell_act == ocell
3715                         || !cur->par->table->IsFirstCell(cell_act))) {
3716                         while (cur->pos < cur->par->Last() &&
3717                                !cur->par->IsNewline(cur->pos))
3718                                 cur->par->Erase(cur->pos);
3719                         ++cell;
3720                         ++cell_act;
3721                         if (cur->pos < cur->par->Last())
3722                                 cur->par->Erase(cur->pos);
3723                 }
3724                 if (cur->pos && cur->pos == cur->par->Last()) {
3725                         cur->pos--;
3726                         cur->par->Erase(cur->pos); // no newline at very end!
3727                 }
3728         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3729                  !cur->par->table->IsContRow(cell_org) &&
3730                  cur->par->table->IsContRow(cell));
3731         cur->par->table->DeleteRow(cell_org);
3732         return;
3733 }
3734
3735
3736 bool LyXText::IsEmptyTableCell() const
3737 {
3738         LyXParagraph::size_type pos = cursor.pos - 1;
3739         while (pos >= 0 && pos < cursor.par->Last()
3740                && !cursor.par->IsNewline(pos))
3741                 --pos;
3742         return cursor.par->IsNewline(pos + 1);
3743 }
3744
3745
3746 void LyXText::toggleAppendix(){
3747         LyXParagraph * par = cursor.par->FirstPhysicalPar();
3748         bool start = !par->start_of_appendix;
3749
3750         // ensure that we have only one start_of_appendix in this document
3751         LyXParagraph * tmp = FirstParagraph();
3752         for (; tmp; tmp = tmp->next)
3753                 tmp->start_of_appendix = 0;
3754         par->start_of_appendix = start;
3755
3756         // we can set the refreshing parameters now
3757         status = LyXText::NEED_MORE_REFRESH;
3758         refresh_y = 0;
3759         refresh_row = 0; // not needed for full update
3760         UpdateCounters(0);
3761         SetCursor(cursor.par, cursor.pos);
3762 }
3763