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