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