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