1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-1999 The LyX Team.
9 * ====================================================== */
14 #include FORMS_H_LOCATION
18 #pragma implementation "lyxtext.h"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
26 #include "support/textutils.h"
29 #include "minibuffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
38 extern MiniBuffer * minibuffer;
41 LyXText::LyXText(int pw, Buffer * p)
48 parameters = &p->params;
52 status = LyXText::UNCHANGED;
53 LyXParagraph * par = p->paragraph;
54 current_font = GetFont(par, 0);
59 InsertParagraph(par, lastrow);
62 /* set cursor at the very top position */
63 selection = true; /* these setting is necessary
64 * because of the delete-empty-
65 * paragraph mechanism in
67 SetCursor(firstrow->par, 0);
72 /* no rebreak necessary */
78 // Default layouttype for copy environment type
86 // Delete all rows, this does not touch the paragraphs!
87 Row * tmprow = firstrow;
89 tmprow = firstrow->next;
96 // Gets the fully instantiated font at a given position in a paragraph
97 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
98 // The difference is that this one is used for displaying, and thus we
99 // are allowed to make cosmetic improvements. For instance make footnotes
101 // If position is -1, we get the layout font of the paragraph.
102 // If position is -2, we get the font of the manual label of the paragraph.
103 LyXFont LyXText::GetFont(LyXParagraph * par,
104 LyXParagraph::size_type pos)
106 LyXLayout const & layout =
107 textclasslist.Style(parameters->textclass, par->GetLayout());
109 char par_depth = par->GetDepth();
110 // We specialize the 95% common case:
111 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
114 if (layout.labeltype == LABEL_MANUAL
115 && pos < BeginningOfMainBody(par)) {
117 return par->GetFontSettings(pos).
118 realize(layout.reslabelfont);
120 return par->GetFontSettings(pos).
121 realize(layout.resfont);
124 // process layoutfont for pos == -1 and labelfont for pos < -1
126 return layout.resfont;
128 return layout.reslabelfont;
132 // The uncommon case need not be optimized as much
134 LyXFont layoutfont, tmpfont;
138 if (pos < BeginningOfMainBody(par)) {
140 layoutfont = layout.labelfont;
143 layoutfont = layout.font;
145 tmpfont = par->GetFontSettings(pos);
146 tmpfont.realize(layoutfont);
149 // process layoutfont for pos == -1 and labelfont for pos < -1
151 tmpfont = layout.font;
153 tmpfont = layout.labelfont;
156 // Resolve against environment font information
157 while (par && par_depth && !tmpfont.resolved()) {
158 par = par->DepthHook(par_depth - 1);
160 tmpfont.realize(textclasslist.
161 Style(parameters->textclass,
162 par->GetLayout()).font);
163 par_depth = par->GetDepth();
167 tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
169 // Cosmetic improvement: If this is an open footnote, make the font
171 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
172 && par->footnotekind == LyXParagraph::FOOTNOTE) {
180 void LyXText::SetCharFont(LyXParagraph * par,
181 LyXParagraph::size_type pos,
184 /* let the insets convert their font */
185 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
186 if (par->GetInset(pos))
187 font = par->GetInset(pos)->ConvertFont(font);
190 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
193 // Get concrete layout font to reduce against
196 if (pos < BeginningOfMainBody(par))
197 layoutfont = layout.labelfont;
199 layoutfont = layout.font;
201 // Realize against environment font information
202 if (par->GetDepth()){
203 LyXParagraph * tp = par;
204 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
205 tp = tp->DepthHook(tp->GetDepth()-1);
207 layoutfont.realize(textclasslist.
208 Style(parameters->textclass,
209 tp->GetLayout()).font);
213 layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
215 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
216 && par->footnotekind == LyXParagraph::FOOTNOTE) {
217 layoutfont.decSize();
220 // Now, reduce font against full layout font
221 font.reduce(layoutfont);
223 par->SetFont(pos, font);
227 /* inserts a new row behind the specified row, increments
228 * the touched counters */
229 void LyXText::InsertRow(Row * row, LyXParagraph * par,
230 LyXParagraph::size_type pos)
232 Row * tmprow = new Row;
234 tmprow->previous = 0;
235 tmprow->next = firstrow;
239 tmprow->previous = row;
240 tmprow->next = row->next;
245 tmprow->next->previous = tmprow;
247 if (tmprow->previous)
248 tmprow->previous->next = tmprow;
256 number_of_rows++; /* one more row */
260 /* removes the row and reset the touched counters */
261 void LyXText::RemoveRow(Row * row)
263 /* this must not happen before the currentrow for clear reasons.
264 so the trick is just to set the current row onto the previous
267 GetRow(row->par, row->pos, unused_y);
268 currentrow = currentrow->previous;
270 currentrow_y -= currentrow->height;
275 row->next->previous = row->previous;
276 if (!row->previous) {
277 firstrow = row->next;
280 row->previous->next = row->next;
283 lastrow = row->previous;
285 height -= row->height; /* the text becomes smaller */
288 --number_of_rows; /* one row less */
292 /* remove all following rows of the paragraph of the specified row. */
293 void LyXText::RemoveParagraph(Row * row)
297 LyXParagraph * tmppar = row->par;
300 while (row && row->par == tmppar) {
308 /* insert the specified paragraph behind the specified row */
309 void LyXText::InsertParagraph(LyXParagraph * par, Row * row)
311 InsertRow(row, par, 0); /* insert a new row, starting
314 SetCounter(par); /* set the counters */
316 /* and now append the whole paragraph behind the new row */
318 firstrow->height = 0;
319 AppendParagraph(firstrow);
322 row->next->height = 0;
323 AppendParagraph(row->next);
328 void LyXText::ToggleFootnote()
330 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
331 if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
333 minibuffer->Set(_("Opened float"));
336 minibuffer->Set(_("Closed float"));
342 void LyXText::OpenStuff()
344 if (cursor.pos == 0 && cursor.par->bibkey){
345 cursor.par->bibkey->Edit(0, 0);
347 else if (cursor.pos < cursor.par->Last()
348 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
349 && cursor.par->GetInset(cursor.pos)->Editable()) {
350 minibuffer->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
351 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
353 cursor.par->GetInset(cursor.pos)->Edit(0, 0);
361 void LyXText::CloseFootnote()
363 LyXParagraph * endpar, * tmppar;
366 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
368 /* if the cursor is not in an open footnote, or
369 * there is no open footnote in this paragraph, just return. */
370 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
373 || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
374 minibuffer->Set(_("Nothing to do"));
378 /* ok, move the cursor right before the footnote */
380 /* just a little faster than using CursorRight() */
381 for (cursor.pos = 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
382 /* now the cursor is at the beginning of the physical par */
383 SetCursor(cursor.par,
385 cursor.par->ParFromPos(cursor.pos)->text.size());
388 /* we are in a footnote, so let us move at the beginning */
389 /* this is just faster than using just CursorLeft() */
392 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
393 /* just a little bit faster than movin the cursor */
394 tmppar = tmppar->Previous();
396 SetCursor(tmppar, tmppar->Last());
399 /* the cursor must be exactly before the footnote */
400 par = cursor.par->ParFromPos(cursor.pos);
402 status = LyXText::NEED_MORE_REFRESH;
403 refresh_row = cursor.row;
404 refresh_y = cursor.y - cursor.row->baseline;
407 endpar = par->NextAfterFootnote()->Next();
410 tmppar->CloseFootnote(cursor.pos);
412 while (tmppar != endpar) {
413 RemoveRow(row->next);
415 tmppar = row->next->par;
420 AppendParagraph(cursor.row);
422 SetCursor(cursor.par, cursor.pos);
426 if (cursor.row->next)
427 SetHeightOfRow(cursor.row->next);
431 /* used in setlayout */
432 // Asger is not sure we want to do this...
433 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
435 LyXFont layoutfont, tmpfont;
437 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
439 for (LyXParagraph::size_type pos = 0;
440 pos < par->Last(); ++pos) {
441 if (pos < BeginningOfMainBody(par))
442 layoutfont = layout.labelfont;
444 layoutfont = layout.font;
446 tmpfont = par->GetFontSettings(pos);
447 tmpfont.reduce(layoutfont);
448 par->SetFont(pos, tmpfont);
453 /* set layout over selection and make a total rebreak of those paragraphs */
454 void LyXText::SetLayout(char layout)
458 /* if there is no selection just set the layout of the current paragraph */
460 sel_start_cursor = cursor; /* dummy selection */
461 sel_end_cursor = cursor;
464 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
465 LyXParagraph * undoendpar = endpar;
467 if (endpar && endpar->GetDepth()) {
468 while (endpar && endpar->GetDepth()) {
469 endpar = endpar->LastPhysicalPar()->Next();
474 endpar = endpar->Next(); /* because of parindents etc. */
478 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
481 tmpcursor = cursor; /* store the current cursor */
483 /* ok we have a selection. This is always between sel_start_cursor
484 * and sel_end cursor */
485 cursor = sel_start_cursor;
487 LyXLayout const & lyxlayout = textclasslist.Style(parameters->textclass, layout);
489 while (cursor.par != sel_end_cursor.par) {
490 if (cursor.par->footnoteflag ==
491 sel_start_cursor.par->footnoteflag) {
492 cursor.par->SetLayout(layout);
493 MakeFontEntriesLayoutSpecific(cursor.par);
494 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
495 fppar->added_space_top = lyxlayout.fill_top ?
496 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
497 fppar->added_space_bottom = lyxlayout.fill_bottom ?
498 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
499 if (lyxlayout.margintype == MARGIN_MANUAL)
500 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
501 if (lyxlayout.labeltype != LABEL_BIBLIO
503 delete fppar->bibkey;
507 cursor.par = cursor.par->Next();
509 if (cursor.par->footnoteflag ==
510 sel_start_cursor.par->footnoteflag) {
511 cursor.par->SetLayout(layout);
512 MakeFontEntriesLayoutSpecific(cursor.par);
513 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
514 fppar->added_space_top = lyxlayout.fill_top ?
515 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
516 fppar->added_space_bottom = lyxlayout.fill_bottom ?
517 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
518 if (lyxlayout.margintype == MARGIN_MANUAL)
519 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
520 if (lyxlayout.labeltype != LABEL_BIBLIO
522 delete fppar->bibkey;
527 RedoParagraphs(sel_start_cursor, endpar);
529 /* we have to reset the selection, because the
530 * geometry could have changed */
531 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
533 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
534 UpdateCounters(cursor.row);
537 SetCursor(tmpcursor.par, tmpcursor.pos);
541 /* increment depth over selection and
542 * make a total rebreak of those paragraphs */
543 void LyXText::IncDepth()
545 // If there is no selection, just use the current paragraph
547 sel_start_cursor = cursor; /* dummy selection */
548 sel_end_cursor = cursor;
551 // We end at the next paragraph with depth 0
552 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
553 LyXParagraph * undoendpar = endpar;
555 if (endpar && endpar->GetDepth()) {
556 while (endpar && endpar->GetDepth()) {
557 endpar = endpar->LastPhysicalPar()->Next();
562 endpar = endpar->Next(); /* because of parindents etc. */
566 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
569 LyXCursor tmpcursor = cursor; /* store the current cursor */
571 /* ok we have a selection. This is always between sel_start_cursor
572 * and sel_end cursor */
573 cursor = sel_start_cursor;
575 bool anything_changed = false;
578 // NOTE: you can't change the depth of a bibliography entry
579 if (cursor.par->footnoteflag ==
580 sel_start_cursor.par->footnoteflag
581 && textclasslist.Style(parameters->textclass,
582 cursor.par->GetLayout()
583 ).labeltype != LABEL_BIBLIO) {
584 LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
586 && (prev->GetDepth() - cursor.par->GetDepth() > 0
587 || (prev->GetDepth() == cursor.par->GetDepth()
588 && textclasslist.Style(parameters->textclass,
589 prev->GetLayout()).isEnvironment()))) {
590 cursor.par->FirstPhysicalPar()->depth++;
591 anything_changed = true;
594 if (cursor.par == sel_end_cursor.par)
596 cursor.par = cursor.par->Next();
599 /* if nothing changed set all depth to 0 */
600 if (!anything_changed) {
601 cursor = sel_start_cursor;
602 while (cursor.par != sel_end_cursor.par) {
603 cursor.par->FirstPhysicalPar()->depth = 0;
604 cursor.par = cursor.par->Next();
606 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
607 cursor.par->FirstPhysicalPar()->depth = 0;
610 RedoParagraphs(sel_start_cursor, endpar);
612 /* we have to reset the selection, because the
613 * geometry could have changed */
614 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
616 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
617 UpdateCounters(cursor.row);
620 SetCursor(tmpcursor.par, tmpcursor.pos);
624 /* decrement depth over selection and
625 * make a total rebreak of those paragraphs */
626 void LyXText::DecDepth()
628 /* if there is no selection just set the layout of the current paragraph */
630 sel_start_cursor = cursor; /* dummy selection */
631 sel_end_cursor = cursor;
634 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
635 LyXParagraph * undoendpar = endpar;
637 if (endpar && endpar->GetDepth()) {
638 while (endpar && endpar->GetDepth()) {
639 endpar = endpar->LastPhysicalPar()->Next();
644 endpar = endpar->Next(); /* because of parindents etc. */
648 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
651 LyXCursor tmpcursor = cursor; /* store the current cursor */
653 /* ok we have a selection. This is always between sel_start_cursor
654 * and sel_end cursor */
655 cursor = sel_start_cursor;
658 if (cursor.par->footnoteflag ==
659 sel_start_cursor.par->footnoteflag) {
660 if (cursor.par->FirstPhysicalPar()->depth)
661 cursor.par->FirstPhysicalPar()->depth--;
663 if (cursor.par == sel_end_cursor.par)
665 cursor.par = cursor.par->Next();
668 RedoParagraphs(sel_start_cursor, endpar);
670 /* we have to reset the selection, because the
671 * geometry could have changed */
672 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
674 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
675 UpdateCounters(cursor.row);
678 SetCursor(tmpcursor.par, tmpcursor.pos);
682 /* set font over selection and make a total rebreak of those paragraphs */
683 void LyXText::SetFont(LyXFont font, bool toggleall)
685 /* if there is no selection just set the current_font */
687 // Determine basis font
689 if (cursor.pos < BeginningOfMainBody(cursor.par))
690 layoutfont = GetFont(cursor.par, -2);
692 layoutfont = GetFont(cursor.par, -1);
693 // Update current font
694 real_current_font.update(font, toggleall);
696 // Reduce to implicit settings
697 current_font = real_current_font;
698 current_font.reduce(layoutfont);
699 // And resolve it completely
700 real_current_font.realize(layoutfont);
704 LyXCursor tmpcursor = cursor; /* store the current cursor */
706 /* ok we have a selection. This is always between sel_start_cursor
707 * and sel_end cursor */
710 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
711 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
712 cursor = sel_start_cursor;
713 while (cursor.par != sel_end_cursor.par ||
714 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
715 && cursor.pos < sel_end_cursor.pos))
717 if (cursor.pos < cursor.par->Last()
718 && cursor.par->footnoteflag
719 == sel_start_cursor.par->footnoteflag) { /* an open footnote
722 LyXFont newfont = GetFont(cursor.par, cursor.pos);
723 newfont.update(font, toggleall);
724 SetCharFont(cursor.par, cursor.pos, newfont);
728 cursor.par = cursor.par->Next();
732 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
734 /* we have to reset the selection, because the
735 * geometry could have changed */
736 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
738 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
741 SetCursor(tmpcursor.par, tmpcursor.pos);
745 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
747 Row * tmprow = cursor.row;
748 long y = cursor.y - tmprow->baseline;
750 SetHeightOfRow(tmprow);
751 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
752 /* find the first row of the paragraph */
753 if (first_phys_par != tmprow->par)
754 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
755 tmprow = tmprow->previous;
757 SetHeightOfRow(tmprow);
759 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
760 tmprow = tmprow->previous;
762 SetHeightOfRow(tmprow);
765 /* we can set the refreshing parameters now */
766 status = LyXText::NEED_MORE_REFRESH;
768 refresh_row = tmprow;
769 SetCursor(cursor.par, cursor.pos);
773 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
775 Row * tmprow = cursor.row;
777 long y = cursor.y - tmprow->baseline;
778 SetHeightOfRow(tmprow);
779 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
780 /* find the first row of the paragraph */
781 if (first_phys_par != tmprow->par)
782 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
783 tmprow = tmprow->previous;
786 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
787 tmprow = tmprow->previous;
792 /* we can set the refreshing parameters now */
793 if (status == LyXText::UNCHANGED || y < refresh_y) {
795 refresh_row = tmprow;
797 status = LyXText::NEED_MORE_REFRESH;
798 SetCursor(cursor.par, cursor.pos);
802 /* deletes and inserts again all paragaphs between the cursor
803 * and the specified par
804 * This function is needed after SetLayout and SetFont etc. */
805 void LyXText::RedoParagraphs(LyXCursor cursor, LyXParagraph * endpar)
808 LyXParagraph * tmppar, * first_phys_par;
810 Row * tmprow = cursor.row;
812 long y = cursor.y - tmprow->baseline;
814 if (!tmprow->previous){
815 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
818 first_phys_par = tmprow->par->FirstPhysicalPar();
819 /* find the first row of the paragraph */
820 if (first_phys_par != tmprow->par)
821 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
822 tmprow = tmprow->previous;
825 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
826 tmprow = tmprow->previous;
831 /* we can set the refreshing parameters now */
832 status = LyXText::NEED_MORE_REFRESH;
834 refresh_row = tmprow->previous; /* the real refresh row will
835 * be deleted, so I store
836 * the previous here */
839 tmppar = tmprow->next->par;
842 while (tmppar != endpar) {
843 RemoveRow(tmprow->next);
845 tmppar = tmprow->next->par;
850 /* remove the first one */
851 tmprow2 = tmprow; /* this is because tmprow->previous
853 tmprow = tmprow->previous;
856 tmppar = first_phys_par;
860 InsertParagraph(tmppar, tmprow);
863 while (tmprow->next && tmprow->next->par == tmppar)
864 tmprow = tmprow->next;
865 tmppar = tmppar->Next();
869 while (tmppar != endpar);
871 /* this is because of layout changes */
873 refresh_y -= refresh_row->height;
874 SetHeightOfRow(refresh_row);
877 refresh_row = firstrow;
879 SetHeightOfRow(refresh_row);
882 if (tmprow && tmprow->next)
883 SetHeightOfRow(tmprow->next);
887 int LyXText::FullRebreak()
889 if (need_break_row) {
890 BreakAgain(need_break_row);
898 /* important for the screen */
901 /* the cursor set functions have a special mechanism. When they
902 * realize, that you left an empty paragraph, they will delete it.
903 * They also delet the corresponding row */
905 /* need the selection cursor: */
906 void LyXText::SetSelection()
909 last_sel_cursor = sel_cursor;
910 sel_start_cursor = sel_cursor;
911 sel_end_cursor = sel_cursor;
916 /* first the toggling area */
917 if (cursor.y < last_sel_cursor.y ||
918 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
919 toggle_end_cursor = last_sel_cursor;
920 toggle_cursor = cursor;
923 toggle_end_cursor = cursor;
924 toggle_cursor = last_sel_cursor;
927 last_sel_cursor = cursor;
929 /* and now the whole selection */
931 if (sel_cursor.y < cursor.y ||
932 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
933 sel_end_cursor = cursor;
934 sel_start_cursor = sel_cursor;
937 sel_end_cursor = sel_cursor;
938 sel_start_cursor = cursor;
941 /* a selection with no contents is not a selection */
942 if (sel_start_cursor.x == sel_end_cursor.x &&
943 sel_start_cursor.y == sel_end_cursor.y)
948 void LyXText::ClearSelection()
955 void LyXText::CursorHome()
957 SetCursor(cursor.par, cursor.row->pos);
961 void LyXText::CursorEnd()
963 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
964 SetCursor(cursor.par, RowLast(cursor.row) + 1);
966 if (cursor.par->Last() &&
967 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
968 || cursor.par->IsNewline(RowLast(cursor.row))))
969 SetCursor(cursor.par, RowLast(cursor.row));
971 SetCursor(cursor.par, RowLast(cursor.row) + 1);
973 if (cursor.par->table) {
974 int cell = NumberOfCell(cursor.par, cursor.pos);
975 if (cursor.par->table->RowHasContRow(cell) &&
976 cursor.par->table->CellHasContRow(cell)<0) {
977 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
978 SetCursor(cursor.par, RowLast(cursor.row) + 1);
980 if (cursor.par->Last() &&
981 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
982 || cursor.par->IsNewline(RowLast(cursor.row))))
983 SetCursor(cursor.par, RowLast(cursor.row));
985 SetCursor(cursor.par, RowLast(cursor.row) + 1);
992 void LyXText::CursorTop()
994 while (cursor.par->Previous())
995 cursor.par = cursor.par->Previous();
996 SetCursor(cursor.par, 0);
1000 void LyXText::CursorBottom()
1002 while (cursor.par->Next())
1003 cursor.par = cursor.par->Next();
1004 SetCursor(cursor.par, cursor.par->Last());
1008 /* returns a pointer to the row near the specified y-coordinate
1009 * (relative to the whole text). y is set to the real beginning
1011 Row * LyXText::GetRowNearY(long & y)
1017 tmprow = currentrow;
1018 tmpy = currentrow_y;
1026 while (tmprow->next && tmpy + tmprow->height <= y) {
1027 tmpy += tmprow->height;
1028 tmprow = tmprow->next;
1031 while (tmprow->previous && tmpy > y) {
1032 tmprow = tmprow->previous;
1033 tmpy -= tmprow->height;
1036 currentrow = tmprow;
1037 currentrow_y = tmpy;
1039 y = tmpy; /* return the real y */
1044 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1046 // If the mask is completely neutral, tell user
1047 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1048 // Could only happen with user style
1049 minibuffer->Set(_("No font change defined. Use Character under"
1050 " the Layout menu to define font change."));
1054 // Try implicit word selection
1055 LyXCursor resetCursor = cursor;
1056 int implicitSelection = SelectWordWhenUnderCursor();
1059 SetFont(font, toggleall);
1060 //minibuffer->Set(_("Font style changed"));
1062 /* Implicit selections are cleared afterwards and cursor is set to the
1063 original position. */
1064 if (implicitSelection) {
1066 cursor = resetCursor;
1067 SetCursor( cursor.par, cursor.pos );
1068 sel_cursor = cursor;
1073 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par)
1075 if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1078 return par->BeginningOfMainBody();
1082 /* if there is a selection, reset every environment you can find
1083 * in the selection, otherwise just the environment you are in */
1084 void LyXText::MeltFootnoteEnvironment()
1086 LyXParagraph * tmppar, * firsttmppar;
1090 /* is is only allowed, if the cursor is IN an open footnote.
1091 * Otherwise it is too dangerous */
1092 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1095 SetUndo(Undo::FINISH,
1096 cursor.par->PreviousBeforeFootnote()->previous,
1097 cursor.par->NextAfterFootnote()->next);
1099 /* ok, move to the beginning of the footnote. */
1100 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1101 cursor.par = cursor.par->Previous();
1103 SetCursor(cursor.par, cursor.par->Last());
1104 /* this is just faster than using CursorLeft(); */
1106 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1107 tmppar = firsttmppar;
1108 /* tmppar is now the paragraph right before the footnote */
1110 char first_footnote_par_is_not_empty = tmppar->next->text.size();
1112 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1113 tmppar = tmppar->next; /* I use next instead of Next(),
1114 * because there cannot be any
1115 * footnotes in a footnote
1117 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1119 /* remember the captions and empty paragraphs */
1120 if ((textclasslist.Style(parameters->textclass,
1121 tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1123 tmppar->SetLayout(0);
1126 /* now we will paste the ex-footnote, if the layouts allow it */
1127 /* first restore the layout of the paragraph right behind the footnote*/
1129 tmppar->next->MakeSameLayout(cursor.par);
1132 if ((!tmppar->GetLayout() && !tmppar->table)
1133 || (tmppar->Next() && (!tmppar->Next()->Last()
1134 || tmppar->Next()->HasSameLayout(tmppar)))) {
1135 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1136 tmppar->Next()->Erase(0);
1137 tmppar->PasteParagraph();
1140 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1141 * by the pasting of the beginning */
1143 /* then the beginning */
1144 /* if there is no space between the text and the footnote, so we insert
1146 * (only if the previous par and the footnotepar are not empty!) */
1147 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1148 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1149 if (firsttmppar->text.size()
1150 && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1151 && first_footnote_par_is_not_empty) {
1152 firsttmppar->next->InsertChar(0, ' ');
1154 firsttmppar->PasteParagraph();
1157 /* now redo the paragaphs */
1158 RedoParagraphs(cursor, tmppar);
1160 SetCursor(cursor.par, cursor.pos);
1162 /* sometimes it can happen, that there is a counter change */
1163 Row * row = cursor.row;
1164 while (row->next && row->par != tmppar && row->next->par != tmppar)
1166 UpdateCounters(row);
1173 /* the DTP switches for paragraphs. LyX will store them in the
1174 * first physicla paragraph. When a paragraph is broken, the top settings
1175 * rest, the bottom settings are given to the new one. So I can make shure,
1176 * they do not duplicate themself and you cannnot make dirty things with
1179 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1180 bool pagebreak_top, bool pagebreak_bottom,
1181 VSpace space_top, VSpace space_bottom,
1183 string labelwidthstring,
1186 LyXCursor tmpcursor = cursor;
1188 sel_start_cursor = cursor;
1189 sel_end_cursor = cursor;
1192 // make sure that the depth behind the selection are restored, too
1193 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1194 LyXParagraph * undoendpar = endpar;
1196 if (endpar && endpar->GetDepth()) {
1197 while (endpar && endpar->GetDepth()) {
1198 endpar = endpar->LastPhysicalPar()->Next();
1199 undoendpar = endpar;
1203 endpar = endpar->Next(); /* because of parindents etc. */
1207 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1211 LyXParagraph * tmppar = sel_end_cursor.par;
1212 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1213 SetCursor(tmppar->FirstPhysicalPar(), 0);
1214 status = LyXText::NEED_MORE_REFRESH;
1215 refresh_row = cursor.row;
1216 refresh_y = cursor.y - cursor.row->baseline;
1217 if (cursor.par->footnoteflag ==
1218 sel_start_cursor.par->footnoteflag) {
1219 cursor.par->line_top = line_top;
1220 cursor.par->line_bottom = line_bottom;
1221 cursor.par->pagebreak_top = pagebreak_top;
1222 cursor.par->pagebreak_bottom = pagebreak_bottom;
1223 cursor.par->added_space_top = space_top;
1224 cursor.par->added_space_bottom = space_bottom;
1225 /* does the layout allow the new alignment? */
1226 if (align == LYX_ALIGN_LAYOUT)
1227 align = textclasslist
1228 .Style(parameters->textclass,
1229 cursor.par->GetLayout()).align;
1230 if (align & textclasslist
1231 .Style(parameters->textclass,
1232 cursor.par->GetLayout()).alignpossible) {
1233 if (align == textclasslist
1234 .Style(parameters->textclass,
1235 cursor.par->GetLayout()).align)
1236 cursor.par->align = LYX_ALIGN_LAYOUT;
1238 cursor.par->align = align;
1240 cursor.par->SetLabelWidthString(labelwidthstring);
1241 cursor.par->noindent = noindent;
1244 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1247 RedoParagraphs(sel_start_cursor, endpar);
1250 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1251 sel_cursor = cursor;
1252 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1254 SetCursor(tmpcursor.par, tmpcursor.pos);
1258 void LyXText::SetParagraphExtraOpt(int type,
1260 char const * widthp,
1261 int alignment, bool hfill,
1262 bool start_minipage)
1264 LyXCursor tmpcursor = cursor;
1265 LyXParagraph * tmppar;
1267 sel_start_cursor = cursor;
1268 sel_end_cursor = cursor;
1271 // make sure that the depth behind the selection are restored, too
1272 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1273 LyXParagraph * undoendpar = endpar;
1275 if (endpar && endpar->GetDepth()) {
1276 while (endpar && endpar->GetDepth()) {
1277 endpar = endpar->LastPhysicalPar()->Next();
1278 undoendpar = endpar;
1282 endpar = endpar->Next(); /* because of parindents etc. */
1286 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1289 tmppar = sel_end_cursor.par;
1290 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1291 SetCursor(tmppar->FirstPhysicalPar(), 0);
1292 status = LyXText::NEED_MORE_REFRESH;
1293 refresh_row = cursor.row;
1294 refresh_y = cursor.y - cursor.row->baseline;
1295 if (cursor.par->footnoteflag ==
1296 sel_start_cursor.par->footnoteflag) {
1297 if (type == LyXParagraph::PEXTRA_NONE) {
1298 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1299 cursor.par->UnsetPExtraType();
1300 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1303 cursor.par->SetPExtraType(type, width, widthp);
1304 cursor.par->pextra_hfill = hfill;
1305 cursor.par->pextra_start_minipage = start_minipage;
1306 cursor.par->pextra_alignment = alignment;
1309 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1311 RedoParagraphs(sel_start_cursor, endpar);
1313 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1314 sel_cursor = cursor;
1315 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1317 SetCursor(tmpcursor.par, tmpcursor.pos);
1321 static char const * alphaCounter(int n){
1322 static char result[2];
1335 /* set the counter of a paragraph. This includes the labels */
1336 void LyXText::SetCounter(LyXParagraph * par)
1340 /* this is only relevant for the beginning of paragraph */
1341 par = par->FirstPhysicalPar();
1343 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1346 LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1348 /* copy the prev-counters to this one, unless this is the start of a
1349 footnote or of a bibliography or the very first paragraph */
1351 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1352 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1353 && par->footnotekind == LyXParagraph::FOOTNOTE)
1354 && !(textclasslist.Style(parameters->textclass,
1355 par->Previous()->GetLayout()
1356 ).labeltype != LABEL_BIBLIO
1357 && layout.labeltype == LABEL_BIBLIO)) {
1358 for (i = 0; i<10; i++) {
1359 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1361 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1362 if (!par->appendix && par->start_of_appendix){
1363 par->appendix = true;
1364 for (i = 0; i<10; i++) {
1365 par->setCounter(i, 0);
1368 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1369 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1372 for (i = 0; i<10; i++) {
1373 par->setCounter(i, 0);
1375 par->appendix = par->start_of_appendix;
1380 // if this is an open marginnote and this is the first
1381 // entry in the marginnote and the enclosing
1382 // environment is an enum/item then correct for the
1383 // LaTeX behaviour (ARRae)
1384 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1385 && par->footnotekind == LyXParagraph::MARGIN
1387 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1388 && (par->PreviousBeforeFootnote()
1389 && textclasslist.Style(parameters->textclass,
1390 par->PreviousBeforeFootnote()->GetLayout()
1391 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1392 // Any itemize or enumerate environment in a marginnote
1393 // that is embedded in an itemize or enumerate
1394 // paragraph is seen by LaTeX as being at a deeper
1395 // level within that enclosing itemization/enumeration
1396 // even if there is a "standard" layout at the start of
1402 /* Maybe we have to increment the enumeration depth.
1403 * BUT, enumeration in a footnote is considered in isolation from its
1404 * surrounding paragraph so don't increment if this is the
1405 * first line of the footnote
1406 * AND, bibliographies can't have their depth changed ie. they
1407 * are always of depth 0
1410 && par->Previous()->GetDepth() < par->GetDepth()
1411 && textclasslist.Style(parameters->textclass,
1412 par->Previous()->GetLayout()
1413 ).labeltype == LABEL_COUNTER_ENUMI
1414 && par->enumdepth < 3
1415 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1416 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1417 && par->footnotekind == LyXParagraph::FOOTNOTE)
1418 && layout.labeltype != LABEL_BIBLIO) {
1422 /* Maybe we have to decrement the enumeration depth, see note above */
1424 && par->Previous()->GetDepth() > par->GetDepth()
1425 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1426 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1427 && par->footnotekind == LyXParagraph::FOOTNOTE)
1428 && layout.labeltype != LABEL_BIBLIO) {
1429 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1430 par->setCounter(6 + par->enumdepth,
1431 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1432 /* reset the counters.
1433 * A depth change is like a breaking layout
1435 for (i = 6 + par->enumdepth + 1; i<10;i++)
1436 par->setCounter(i, 0);
1439 if (!par->labelstring.empty()) {
1440 par->labelstring.clear();
1443 if (layout.margintype == MARGIN_MANUAL) {
1444 if (par->labelwidthstring.empty()) {
1445 par->SetLabelWidthString(layout.labelstring());
1449 par->SetLabelWidthString(string());
1452 /* is it a layout that has an automatic label ? */
1453 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1455 i = layout.labeltype - LABEL_FIRST_COUNTER;
1456 if (i >= 0 && i<= parameters->secnumdepth) {
1457 par->incCounter(i); // increment the counter
1459 char * s = new char[50];
1461 // Is there a label? Useful for Chapter layout
1462 if (!par->appendix){
1463 if (!layout.labelstring().empty())
1464 par->labelstring = layout.labelstring();
1466 par->labelstring.clear();
1469 if (!layout.labelstring_appendix().empty())
1470 par->labelstring = layout.labelstring_appendix();
1472 par->labelstring.clear();
1475 if (!par->appendix){
1476 switch (2 * LABEL_FIRST_COUNTER -
1477 textclass.maxcounter() + i) {
1478 case LABEL_COUNTER_CHAPTER:
1480 par->getCounter(i));
1482 case LABEL_COUNTER_SECTION:
1484 par->getCounter(i - 1),
1485 par->getCounter(i));
1487 case LABEL_COUNTER_SUBSECTION:
1488 sprintf(s, "%d.%d.%d",
1489 par->getCounter(i-2),
1490 par->getCounter(i-1),
1491 par->getCounter(i));
1493 case LABEL_COUNTER_SUBSUBSECTION:
1494 sprintf(s, "%d.%d.%d.%d",
1495 par->getCounter(i-3),
1496 par->getCounter(i-2),
1497 par->getCounter(i-1),
1498 par->getCounter(i));
1500 case LABEL_COUNTER_PARAGRAPH:
1501 sprintf(s, "%d.%d.%d.%d.%d",
1502 par->getCounter(i-4),
1503 par->getCounter(i-3),
1504 par->getCounter(i-2),
1505 par->getCounter(i-1),
1506 par->getCounter(i));
1508 case LABEL_COUNTER_SUBPARAGRAPH:
1509 sprintf(s, "%d.%d.%d.%d.%d.%d",
1510 par->getCounter(i-5),
1511 par->getCounter(i-4),
1512 par->getCounter(i-3),
1513 par->getCounter(i-2),
1514 par->getCounter(i-1),
1515 par->getCounter(i));
1518 sprintf(s, "%d.", par->getCounter(i));
1523 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1524 case LABEL_COUNTER_CHAPTER:
1526 alphaCounter(par->getCounter(i)));
1528 case LABEL_COUNTER_SECTION:
1530 alphaCounter(par->getCounter(i - 1)),
1531 par->getCounter(i));
1533 case LABEL_COUNTER_SUBSECTION:
1534 sprintf(s, "%s.%d.%d",
1535 alphaCounter(par->getCounter(i-2)),
1536 par->getCounter(i-1),
1537 par->getCounter(i));
1539 case LABEL_COUNTER_SUBSUBSECTION:
1540 sprintf(s, "%s.%d.%d.%d",
1541 alphaCounter(par->getCounter(i-3)),
1542 par->getCounter(i-2),
1543 par->getCounter(i-1),
1544 par->getCounter(i));
1546 case LABEL_COUNTER_PARAGRAPH:
1547 sprintf(s, "%s.%d.%d.%d.%d",
1548 alphaCounter(par->getCounter(i-4)),
1549 par->getCounter(i-3),
1550 par->getCounter(i-2),
1551 par->getCounter(i-1),
1552 par->getCounter(i));
1554 case LABEL_COUNTER_SUBPARAGRAPH:
1555 sprintf(s, "%s.%d.%d.%d.%d.%d",
1556 alphaCounter(par->getCounter(i-5)),
1557 par->getCounter(i-4),
1558 par->getCounter(i-3),
1559 par->getCounter(i-2),
1560 par->getCounter(i-1),
1561 par->getCounter(i));
1564 sprintf(s, "%c.", par->getCounter(i));
1569 par->labelstring += s;
1572 for (i++; i<10; i++) {
1573 /* reset the following counters */
1574 par->setCounter(i, 0);
1576 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1577 for (i++; i<10; i++) {
1578 /* reset the following counters */
1579 par->setCounter(i, 0);
1581 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1582 par->incCounter(i + par->enumdepth);
1583 char * s = new char[25];
1584 int number = par->getCounter(i + par->enumdepth);
1585 switch (par->enumdepth) {
1587 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1591 case 1: sprintf(s, "i."); break;
1592 case 2: sprintf(s, "ii."); break;
1593 case 3: sprintf(s, "iii."); break;
1594 case 4: sprintf(s, "iv."); break;
1595 case 5: sprintf(s, "v."); break;
1596 case 6: sprintf(s, "vi."); break;
1597 case 7: sprintf(s, "vii."); break;
1598 case 8: sprintf(s, "viii."); break;
1599 case 9: sprintf(s, "ix."); break;
1600 case 10: sprintf(s, "x."); break;
1601 case 11: sprintf(s, "xi."); break;
1602 case 12: sprintf(s, "xii."); break;
1603 case 13: sprintf(s, "xiii."); break;
1605 sprintf(s, "\\roman{%d}.", number);
1610 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1613 sprintf(s, "%d.", number);
1616 par->labelstring = s;
1619 for (i += par->enumdepth + 1;i<10;i++)
1620 par->setCounter(i, 0); /* reset the following counters */
1623 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1624 i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1626 int number = par->getCounter(i);
1628 par->bibkey = new InsetBibKey();
1629 par->bibkey->setCounter(number);
1630 par->labelstring = layout.labelstring();
1632 // In biblio should't be following counters but...
1635 string s = layout.labelstring();
1637 /* the caption hack: */
1639 if (layout.labeltype == LABEL_SENSITIVE) {
1640 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1641 && (par->footnotekind == LyXParagraph::FIG
1642 || par->footnotekind == LyXParagraph::WIDE_FIG))
1644 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1645 && (par->footnotekind == LyXParagraph::TAB
1646 || par->footnotekind == LyXParagraph::WIDE_TAB))
1648 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1649 && par->footnotekind == LyXParagraph::ALGORITHM)
1652 /* par->SetLayout(0);
1653 s = layout->labelstring; */
1658 par->labelstring = s;
1660 /* reset the enumeration counter. They are always resetted
1661 * when there is any other layout between */
1662 for (i = 6 + par->enumdepth; i<10;i++)
1663 par->setCounter(i, 0);
1668 /* Updates all counters BEHIND the row. Changed paragraphs
1669 * with a dynamic left margin will be rebroken. */
1670 void LyXText::UpdateCounters(Row * row)
1678 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1679 par = row->par->LastPhysicalPar()->Next();
1681 par = row->par->next;
1686 while (row->par != par)
1691 /* now check for the headline layouts. remember that they
1692 * have a dynamic left margin */
1694 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1695 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1698 /* Rebreak the paragraph */
1699 RemoveParagraph(row);
1700 AppendParagraph(row);
1702 /* think about the damned open footnotes! */
1703 while (par->Next() &&
1704 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1705 || par->Next()->IsDummy())){
1707 if (par->IsDummy()) {
1708 while (row->par != par)
1710 RemoveParagraph(row);
1711 AppendParagraph(row);
1716 par = par->LastPhysicalPar()->Next();
1722 /* insets an inset. */
1723 void LyXText::InsertInset(Inset *inset)
1725 SetUndo(Undo::INSERT,
1726 cursor.par->ParFromPos(cursor.pos)->previous,
1727 cursor.par->ParFromPos(cursor.pos)->next);
1728 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1729 cursor.par->InsertInset(cursor.pos, inset);
1730 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1731 * The character will not be inserted a
1736 /* this is for the simple cut and paste mechanism */
1737 static LyXParagraph * simple_cut_buffer = 0;
1738 static char simple_cut_buffer_textclass = 0;
1740 void DeleteSimpleCutBuffer()
1742 if (!simple_cut_buffer)
1744 LyXParagraph *tmppar;
1746 while (simple_cut_buffer) {
1747 tmppar = simple_cut_buffer;
1748 simple_cut_buffer = simple_cut_buffer->next;
1751 simple_cut_buffer = 0;
1755 void LyXText::copyEnvironmentType()
1757 copylayouttype = cursor.par->GetLayout();
1761 void LyXText::pasteEnvironmentType()
1763 SetLayout(copylayouttype);
1767 void LyXText::CutSelection(bool doclear)
1769 /* This doesn't make sense, if there is no selection */
1774 /* OK, we have a selection. This is always between sel_start_cursor
1775 * and sel_end cursor */
1776 LyXParagraph * tmppar;
1778 /* Check whether there are half footnotes in the selection */
1779 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1780 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1781 tmppar = sel_start_cursor.par;
1782 while (tmppar != sel_end_cursor.par){
1783 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1784 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1787 tmppar = tmppar->Next();
1791 /* table stuff -- begin*/
1792 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1793 if ( sel_start_cursor.par != sel_end_cursor.par){
1794 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1797 sel_start_cursor.par->table->Reinit();
1799 /* table stuff -- end*/
1801 // make sure that the depth behind the selection are restored, too
1802 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1803 LyXParagraph * undoendpar = endpar;
1805 if (endpar && endpar->GetDepth()) {
1806 while (endpar && endpar->GetDepth()) {
1807 endpar = endpar->LastPhysicalPar()->Next();
1808 undoendpar = endpar;
1812 endpar = endpar->Next(); /* because of parindents etc. */
1815 SetUndo(Undo::DELETE,
1816 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1819 /* delete the simple_cut_buffer */
1820 DeleteSimpleCutBuffer();
1822 /* set the textclass */
1823 simple_cut_buffer_textclass = parameters->textclass;
1825 #ifdef WITH_WARNINGS
1826 #warning Asger: Make cut more intelligent here.
1829 White paper for "intelligent" cutting:
1831 Example: "This is our text."
1832 Using " our " as selection, cutting will give "This istext.".
1833 Using "our" as selection, cutting will give "This is text.".
1834 Using " our" as selection, cutting will give "This is text.".
1835 Using "our " as selection, cutting will give "This is text.".
1837 All those four selections will (however) paste identically:
1838 Pasting with the cursor right after the "is" will give the
1839 original text with all four selections.
1841 The rationale is to be intelligent such that words are copied,
1842 cut and pasted in a functional manner.
1844 This is not implemented yet.
1847 bool space_wrapped =
1848 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1849 if (sel_end_cursor.pos > 0
1850 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1851 sel_end_cursor.pos--; /* please break before a space at
1853 space_wrapped = true;
1856 // cut behind a space if there is one
1857 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1858 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1859 && (sel_start_cursor.par != sel_end_cursor.par
1860 || sel_start_cursor.pos < sel_end_cursor.pos))
1861 sel_start_cursor.pos++;
1863 /* there are two cases: cut only within one paragraph or
1864 * more than one paragraph */
1866 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1867 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1868 /* only within one paragraph */
1869 simple_cut_buffer = new LyXParagraph;
1870 LyXParagraph::size_type i =
1871 sel_start_cursor.pos;
1872 for (; i< sel_end_cursor.pos; i++){
1873 /* table stuff -- begin*/
1874 if (sel_start_cursor.par->table
1875 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1876 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1877 sel_start_cursor.pos++;
1879 /* table stuff -- end*/
1880 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1881 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1883 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1885 /* check for double spaces */
1886 if (sel_start_cursor.pos &&
1887 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1888 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1889 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1890 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1893 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1894 endpar = sel_end_cursor.par->Next();
1897 /* cut more than one paragraph */
1899 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1900 /* insert a space at the end if there was one */
1902 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1904 sel_end_cursor.par = sel_end_cursor.par->Next();
1905 sel_end_cursor.pos = 0;
1907 cursor = sel_end_cursor;
1909 /* please break behind a space, if there is one. The space should
1911 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1912 sel_start_cursor.pos++;
1914 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1915 if (!sel_start_cursor.pos
1916 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1917 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1918 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1921 /* store the endparagraph for redoing later */
1922 endpar = sel_end_cursor.par->Next(); /* needed because
1927 /*store the selection */
1928 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1929 simple_cut_buffer->previous = 0;
1930 sel_end_cursor.par->previous->next = 0;
1932 /* cut the selection */
1933 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1934 = sel_end_cursor.par;
1936 sel_end_cursor.par->previous
1937 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1939 /* care about footnotes */
1940 if (simple_cut_buffer->footnoteflag) {
1941 LyXParagraph *tmppar = simple_cut_buffer;
1943 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1944 tmppar = tmppar->next;
1948 /* the cut selection should begin with standard layout */
1949 simple_cut_buffer->Clear();
1951 /* paste the paragraphs again, if possible */
1953 sel_start_cursor.par->Next()->ClearParagraph();
1954 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1956 !sel_start_cursor.par->Next()->Last())
1957 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1960 /* maybe a forgotten blank */
1961 if (sel_start_cursor.pos
1962 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1963 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1964 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1969 /* sometimes necessary */
1971 sel_start_cursor.par->ClearParagraph();
1973 RedoParagraphs(sel_start_cursor, endpar);
1976 cursor = sel_start_cursor;
1977 SetCursor(cursor.par, cursor.pos);
1978 sel_cursor = cursor;
1979 UpdateCounters(cursor.row);
1983 void LyXText::CopySelection()
1985 LyXParagraph::size_type i = 0;
1986 /* this doesnt make sense, if there is no selection */
1991 /* ok we have a selection. This is always between sel_start_cursor
1992 * and sel_end cursor */
1993 LyXParagraph * tmppar;
1995 /* check wether there are half footnotes in the selection */
1996 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1997 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1998 tmppar = sel_start_cursor.par;
1999 while (tmppar != sel_end_cursor.par){
2000 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2001 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2004 tmppar = tmppar->Next();
2008 /* table stuff -- begin*/
2009 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2010 if ( sel_start_cursor.par != sel_end_cursor.par){
2011 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2015 /* table stuff -- end*/
2017 /* delete the simple_cut_buffer */
2018 DeleteSimpleCutBuffer();
2020 /* set the textclass */
2021 simple_cut_buffer_textclass = parameters->textclass;
2023 // copy behind a space if there is one
2024 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2025 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2026 && (sel_start_cursor.par != sel_end_cursor.par
2027 || sel_start_cursor.pos < sel_end_cursor.pos))
2028 sel_start_cursor.pos++;
2030 /* there are two cases: copy only within one paragraph or more than one paragraph */
2031 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2032 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2033 /* only within one paragraph */
2034 simple_cut_buffer = new LyXParagraph;
2035 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2036 sel_start_cursor.par->CopyIntoMinibuffer(i);
2037 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2041 /* copy more than one paragraph */
2042 /* clone the paragraphs within the selection*/
2043 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2044 simple_cut_buffer = tmppar->Clone();
2045 LyXParagraph *tmppar2 = simple_cut_buffer;
2047 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2049 tmppar = tmppar->next;
2050 tmppar2->next = tmppar->Clone();
2051 tmppar2->next->previous = tmppar2;
2052 tmppar2 = tmppar2->next;
2056 /* care about footnotes */
2057 if (simple_cut_buffer->footnoteflag) {
2058 tmppar = simple_cut_buffer;
2060 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2061 tmppar = tmppar->next;
2065 /* the simple_cut_buffer paragraph is too big */
2066 LyXParagraph::size_type tmpi2 =
2067 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2068 for (;tmpi2;tmpi2--)
2069 simple_cut_buffer->Erase(0);
2071 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2073 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2074 while (tmppar2->size() > tmpi2) {
2075 tmppar2->Erase(tmppar2->text.size() - 1);
2081 void LyXText::PasteSelection()
2083 /* this does not make sense, if there is nothing to paste */
2084 if (!simple_cut_buffer)
2087 LyXParagraph * tmppar;
2088 LyXParagraph * endpar;
2090 LyXCursor tmpcursor;
2092 /* be carefull with footnotes in footnotes */
2093 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2095 /* check whether the cut_buffer includes a footnote */
2096 tmppar = simple_cut_buffer;
2097 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2098 tmppar = tmppar->next;
2101 WriteAlert(_("Impossible operation"),
2102 _("Can't paste float into float!"), _("Sorry."));
2107 /* table stuff -- begin*/
2108 if (cursor.par->table){
2109 if (simple_cut_buffer->next){
2110 WriteAlert(_("Impossible operation"),
2111 _("Table cell cannot include more than one paragraph!"),
2116 /* table stuff -- end*/
2118 SetUndo(Undo::INSERT,
2119 cursor.par->ParFromPos(cursor.pos)->previous,
2120 cursor.par->ParFromPos(cursor.pos)->next);
2124 /* There are two cases: cutbuffer only one paragraph or many */
2125 if (!simple_cut_buffer->next) {
2126 /* only within a paragraph */
2128 /* please break behind a space, if there is one */
2129 while (tmpcursor.par->Last() > tmpcursor.pos
2130 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2133 tmppar = simple_cut_buffer->Clone();
2134 /* table stuff -- begin*/
2135 bool table_too_small = false;
2136 if (tmpcursor.par->table) {
2137 while (simple_cut_buffer->text.size()
2138 && !table_too_small) {
2139 if (simple_cut_buffer->IsNewline(0)){
2140 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2142 simple_cut_buffer->Erase(0);
2143 if (tmpcursor.pos < tmpcursor.par->Last())
2146 table_too_small = true;
2148 simple_cut_buffer->CutIntoMinibuffer(0);
2149 simple_cut_buffer->Erase(0);
2150 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2155 /* table stuff -- end*/
2156 while (simple_cut_buffer->text.size()){
2157 simple_cut_buffer->CutIntoMinibuffer(0);
2158 simple_cut_buffer->Erase(0);
2159 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2164 delete simple_cut_buffer;
2165 simple_cut_buffer = tmppar;
2166 endpar = tmpcursor.par->Next();
2168 /* many paragraphs */
2170 /* make a copy of the simple cut_buffer */
2171 tmppar = simple_cut_buffer;
2172 LyXParagraph * simple_cut_clone = tmppar->Clone();
2173 LyXParagraph * tmppar2 = simple_cut_clone;
2174 if (cursor.par->footnoteflag){
2175 tmppar->footnoteflag = cursor.par->footnoteflag;
2176 tmppar->footnotekind = cursor.par->footnotekind;
2178 while (tmppar->next) {
2179 tmppar = tmppar->next;
2180 tmppar2->next = tmppar->Clone();
2181 tmppar2->next->previous = tmppar2;
2182 tmppar2 = tmppar2->next;
2183 if (cursor.par->footnoteflag){
2184 tmppar->footnoteflag = cursor.par->footnoteflag;
2185 tmppar->footnotekind = cursor.par->footnotekind;
2189 /* make sure there is no class difference */
2190 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2191 parameters->textclass,
2194 /* make the simple_cut_buffer exactly the same layout than
2195 the cursor paragraph */
2196 simple_cut_buffer->MakeSameLayout(cursor.par);
2198 /* find the end of the buffer */
2199 LyXParagraph *lastbuffer = simple_cut_buffer;
2200 while (lastbuffer->Next())
2201 lastbuffer = lastbuffer->Next();
2203 /* find the physical end of the buffer */
2204 lastbuffer = simple_cut_buffer;
2205 while (lastbuffer->Next())
2206 lastbuffer = lastbuffer->Next();
2208 /* please break behind a space, if there is one. The space
2209 * should be copied too */
2210 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2213 bool paste_the_end = false;
2215 /* open the paragraph for inserting the simple_cut_buffer
2217 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2218 cursor.par->BreakParagraphConservative(cursor.pos);
2219 paste_the_end = true;
2222 /* be careful with double spaces */
2223 if ((!cursor.par->Last()
2224 || cursor.par->IsLineSeparator(cursor.pos - 1)
2225 || cursor.par->IsNewline(cursor.pos - 1))
2226 && simple_cut_buffer->text.size()
2227 && simple_cut_buffer->IsLineSeparator(0))
2228 simple_cut_buffer->Erase(0);
2230 /* set the end for redoing later */
2231 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2234 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2235 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2237 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2238 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2240 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2241 lastbuffer = cursor.par;
2243 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2245 /* store the new cursor position */
2246 tmpcursor.par = lastbuffer;
2247 tmpcursor.pos = lastbuffer->Last();
2249 /* maybe some pasting */
2250 if (lastbuffer->Next() && paste_the_end) {
2251 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2253 /* be careful witth double spaces */
2254 if ((!lastbuffer->Last()
2255 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2256 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2257 && lastbuffer->Next()->Last()
2258 && lastbuffer->Next()->IsLineSeparator(0))
2259 lastbuffer->Next()->Erase(0);
2261 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2264 else if (!lastbuffer->Next()->Last()) {
2265 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2267 /* be careful witth double spaces */
2268 if ((!lastbuffer->Last()
2269 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2270 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2271 && lastbuffer->Next()->Last()
2272 && lastbuffer->Next()->IsLineSeparator(0))
2273 lastbuffer->Next()->Erase(0);
2275 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2278 else if (!lastbuffer->Last()) {
2279 lastbuffer->MakeSameLayout(lastbuffer->next);
2281 /* be careful witth double spaces */
2282 if ((!lastbuffer->Last()
2283 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2284 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2285 && lastbuffer->Next()->Last()
2286 && lastbuffer->Next()->IsLineSeparator(0))
2287 lastbuffer->Next()->Erase(0);
2289 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2292 else lastbuffer->Next()->ClearParagraph();
2295 /* restore the simple cut buffer */
2296 simple_cut_buffer = simple_cut_clone;
2299 RedoParagraphs(cursor, endpar);
2301 SetCursor(cursor.par, cursor.pos);
2304 sel_cursor = cursor;
2305 SetCursor(tmpcursor.par, tmpcursor.pos);
2307 UpdateCounters(cursor.row);
2311 /* returns a pointer to the very first LyXParagraph */
2312 LyXParagraph * LyXText::FirstParagraph()
2314 return params->paragraph;
2318 /* returns true if the specified string is at the specified position */
2319 bool LyXText::IsStringInText(LyXParagraph * par,
2320 LyXParagraph::size_type pos,
2325 while (pos + i < par->Last() && str[i] &&
2326 str[i] == par->GetChar(pos + i)) {
2336 /* sets the selection over the number of characters of string, no check!! */
2337 void LyXText::SetSelectionOverString(char const * string)
2339 sel_cursor = cursor;
2340 for (int i = 0; string[i]; ++i)
2346 /* simple replacing. The font of the first selected character is used */
2347 void LyXText::ReplaceSelectionWithString(char const * str)
2352 if (!selection) { /* create a dummy selection */
2353 sel_end_cursor = cursor;
2354 sel_start_cursor = cursor;
2357 // Get font setting before we cut
2358 LyXParagraph::size_type pos = sel_end_cursor.pos;
2359 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2361 // Insert the new string
2362 for (int i = 0; str[i]; ++i) {
2363 sel_end_cursor.par->InsertChar(pos, str[i]);
2364 sel_end_cursor.par->SetFont(pos, font);
2368 // Cut the selection
2375 /* if the string can be found: return true and set the cursor to
2376 * the new position */
2377 bool LyXText::SearchForward(char const * str)
2379 LyXParagraph * par = cursor.par;
2380 LyXParagraph::size_type pos = cursor.pos;
2381 while (par && !IsStringInText(par, pos, str)) {
2382 if (pos < par->Last() - 1)
2390 SetCursor(par, pos);
2398 bool LyXText::SearchBackward(char const * string)
2400 LyXParagraph * par = cursor.par;
2401 int pos = cursor.pos;
2407 // We skip empty paragraphs (Asger)
2409 par = par->Previous();
2411 pos = par->Last()-1;
2412 } while (par && pos<0);
2414 } while (par && !IsStringInText(par, pos, string));
2417 SetCursor(par, pos);
2425 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2427 char * str = new char[text.size() + 1];
2428 copy(text.begin(), text.end(), str);
2429 str[text.size()] = '\0';
2435 /* needed to insert the selection */
2436 void LyXText::InsertStringA(char const * s)
2439 LyXParagraph * par = cursor.par;
2440 LyXParagraph::size_type pos = cursor.pos;
2441 LyXParagraph::size_type a = 0;
2443 LyXParagraph * endpar = cursor.par->Next();
2447 char flag = textclasslist.Style(parameters->textclass,
2448 cursor.par->GetLayout()).isEnvironment();
2449 /* only to be sure, should not be neccessary */
2452 /* insert the string, don't insert doublespace */
2453 string::size_type i = 0;
2454 while (i < str.length()) {
2455 if (str[i] != '\n') {
2457 && i+1<str.length() && str[i+1]!= ' '
2458 && pos && par->GetChar(pos-1)!= ' ') {
2459 par->InsertChar(pos,' ');
2462 else if (par->table) {
2463 if (str[i] == '\t') {
2464 while((pos < par->size()) &&
2465 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2467 if (pos < par->size())
2469 else // no more fields to fill skip the rest
2471 } else if ((str[i] != 13) &&
2472 ((str[i] & 127) >= ' ')) {
2473 par->InsertChar(pos, str[i]);
2477 else if (str[i] == ' ') {
2478 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2481 else if (str[i] == '\t') {
2482 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2483 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2487 else if (str[i]!= 13 &&
2488 // Ignore unprintables
2489 (str[i] & 127) >= ' ') {
2490 par->InsertChar(pos, str[i]);
2495 if (i+1>=str.length()) {
2499 while((pos < par->size()) &&
2500 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2503 cell = NumberOfCell(par, pos);
2504 while((pos < par->size()) &&
2505 !(par->table->IsFirstCell(cell))) {
2506 while((pos < par->size()) &&
2507 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2510 cell = NumberOfCell(par, pos);
2512 if (pos >= par->size())
2513 // no more fields to fill skip the rest
2516 if (!par->text.size()) {
2517 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2520 par->BreakParagraph(pos, flag);
2529 RedoParagraphs(cursor, endpar);
2530 SetCursor(cursor.par, cursor.pos);
2531 sel_cursor = cursor;
2532 SetCursor(par, pos);
2537 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2539 char * str = new char[text.size() + 1];
2540 copy(text.begin(), text.end(), str);
2541 str[text.size()] = '\0';
2547 /* turns double-CR to single CR, others where converted into one blank and 13s
2548 * that are ignored .Double spaces are also converted into one. Spaces at
2549 * the beginning of a paragraph are forbidden. tabs are converted into one
2550 * space. then InsertStringA is called */
2551 void LyXText::InsertStringB(char const * s)
2554 LyXParagraph * par = cursor.par;
2555 string::size_type i = 1;
2556 while (i < str.length()) {
2557 if (str[i] == '\t' && !par->table)
2559 if (str[i] == ' ' && i+1 < str.length() && str[i + 1] == ' ')
2561 if (str[i] == '\n' && i+1 < str.length() && !par->table){
2562 if (str[i + 1] != '\n') {
2563 if (str[i - 1] != ' ')
2568 while (i+1 < str.length()
2569 && (str[i + 1] == ' '
2570 || str[i + 1] == '\t'
2571 || str[i + 1] == '\n'
2572 || str[i + 1] == 13)) {
2579 InsertStringA(str.c_str());
2583 bool LyXText::GotoNextError()
2585 LyXCursor res = cursor;
2587 if (res.pos < res.par->Last() - 1) {
2591 res.par = res.par->Next();
2596 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2597 && res.par->GetInset(res.pos)->AutoDelete()));
2600 SetCursor(res.par, res.pos);
2608 bool LyXText::GotoNextNote()
2610 LyXCursor res = cursor;
2612 if (res.pos < res.par->Last()-1) {
2616 res.par = res.par->Next();
2621 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2622 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2625 SetCursor(res.par, res.pos);
2633 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2636 InsetError * new_inset = 0;
2638 if (!par || class1 == class2)
2640 par = par->FirstPhysicalPar();
2642 string name = textclasslist.NameOfLayout(class1, par->layout);
2644 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2645 textclasslist.NumberOfLayout(class2, name);
2648 } else { // layout not found
2649 // use default layout "Standard" (0)
2654 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2656 string s = "Layout had to be changed from\n"
2657 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2658 + "\nbecause of class conversion from\n"
2659 + textclasslist.NameOfClass(class1) + " to "
2660 + textclasslist.NameOfClass(class2);
2661 new_inset = new InsetError(s);
2662 par->InsertChar(0, LyXParagraph::META_INSET);
2663 par->InsertInset(0, new_inset);
2672 void LyXText::CheckParagraph(LyXParagraph * par,
2673 LyXParagraph::size_type pos)
2676 LyXCursor tmpcursor;
2678 /* table stuff -- begin*/
2681 CheckParagraphInTable(par, pos);
2684 /* table stuff -- end*/
2687 LyXParagraph::size_type z;
2688 Row * row = GetRow(par, pos, y);
2690 /* is there a break one row above */
2691 if (row->previous && row->previous->par == row->par) {
2692 z = NextBreakPoint(row->previous, paperwidth);
2693 if ( z >= row->pos) {
2694 /* set the dimensions of the row above */
2695 y -= row->previous->height;
2697 refresh_row = row->previous;
2698 status = LyXText::NEED_MORE_REFRESH;
2700 BreakAgain(row->previous);
2702 /* set the cursor again. Otherwise dungling pointers are possible */
2703 SetCursor(cursor.par, cursor.pos);
2704 sel_cursor = cursor;
2709 int tmpheight = row->height;
2710 LyXParagraph::size_type tmplast = RowLast(row);
2715 if (row->height == tmpheight && RowLast(row) == tmplast)
2716 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2718 status = LyXText::NEED_MORE_REFRESH;
2720 /* check the special right address boxes */
2721 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2722 tmpcursor.par = par;
2723 tmpcursor.row = row;
2726 tmpcursor.x_fix = 0;
2727 tmpcursor.pos = pos;
2728 RedoDrawingOfParagraph(tmpcursor);
2733 /* set the cursor again. Otherwise dangling pointers are possible */
2734 // also set the selection
2738 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2739 sel_cursor = cursor;
2740 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2741 sel_start_cursor = cursor;
2742 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2743 sel_end_cursor = cursor;
2744 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2745 last_sel_cursor = cursor;
2748 SetCursorIntern(cursor.par, cursor.pos);
2752 /* returns 0 if inset wasn't found */
2753 int LyXText::UpdateInset(Inset * inset)
2755 /* first check the current paragraph */
2756 int pos = cursor.par->GetPositionOfInset(inset);
2758 CheckParagraph(cursor.par, pos);
2762 /* check every paragraph */
2764 LyXParagraph * par = FirstParagraph();
2766 /* make sure the paragraph is open */
2767 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2768 pos = par->GetPositionOfInset(inset);
2770 CheckParagraph(par, pos);
2781 void LyXText::SetCursor(LyXParagraph * par,
2782 LyXParagraph::size_type pos)
2784 LyXCursor old_cursor = cursor;
2785 SetCursorIntern(par, pos);
2786 DeleteEmptyParagraphMechanism(old_cursor);
2790 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2795 LyXParagraph * tmppar;
2797 /* correct the cursor position if impossible */
2798 if (pos > par->Last()){
2799 tmppar = par->ParFromPos(pos);
2800 pos = par->PositionInParFromPos(pos);
2803 if (par->IsDummy() && par->previous &&
2804 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2805 while (par->previous &&
2806 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2807 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2808 par = par->previous ;
2809 if (par->IsDummy() &&
2810 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2811 pos += par->text.size() + 1;
2813 if (par->previous) {
2814 par = par->previous;
2816 pos += par->text.size() + 1;
2822 /* get the cursor y position in text */
2823 row = GetRow(par, pos, y);
2824 /* y is now the beginning of the cursor row */
2826 /* y is now the cursor baseline */
2829 /* now get the cursors x position */
2832 float fill_separator, fill_hfill, fill_label_hfill;
2833 left_margin = LabelEnd(row);
2834 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2835 LyXParagraph::size_type main_body =
2836 BeginningOfMainBody(row->par);
2837 /* table stuff -- begin*/
2838 if (row->par->table) {
2839 int cell = NumberOfCell(row->par, row->pos);
2841 x += row->par->table->GetBeginningOfTextInCell(cell);
2842 for (pos = row->pos; pos < cursor.pos; pos++) {
2843 if (row->par->IsNewline(pos)) {
2844 x = x_old + row->par->table->WidthOfColumn(cell);
2847 x += row->par->table->GetBeginningOfTextInCell(cell);
2849 x += SingleWidth(row->par, pos);
2853 /* table stuff -- end*/
2855 for (pos = row->pos; pos < cursor.pos; pos++) {
2856 if (pos && pos == main_body
2857 && !row->par->IsLineSeparator(pos - 1)) {
2858 x += GetFont(row->par, -2).stringWidth(
2859 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2860 if (x < left_margin)
2864 x += SingleWidth(row->par, pos);
2865 if (HfillExpansion(row, pos)) {
2866 if (pos >= main_body)
2869 x += fill_label_hfill;
2871 else if (pos >= main_body && row->par->IsSeparator(pos)) {
2875 if (pos + 1 == main_body
2876 && row->par->IsLineSeparator(pos)) {
2877 x += GetFont(row->par, -2).stringWidth(
2878 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2879 if (row->par->IsLineSeparator(pos))
2880 x -= SingleWidth(row->par, pos);
2881 if (x < left_margin)
2888 cursor.x_fix = cursor.x;
2892 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2893 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2894 && !cursor.par->IsSeparator(cursor.pos))
2896 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2897 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2899 current_font = cursor.par->GetFontSettings(cursor.pos);
2900 real_current_font = GetFont(cursor.par, cursor.pos);
2905 void LyXText::SetCursorFromCoordinates(int x, long y)
2907 LyXCursor old_cursor = cursor;
2909 /* get the row first */
2911 Row * row = GetRowNearY(y);
2913 cursor.par = row->par;
2915 int column = GetColumnNearX(row, x);
2916 cursor.pos = row->pos + column;
2918 cursor.y = y + row->baseline;
2923 (cursor.pos == cursor.par->Last()
2924 || cursor.par->IsSeparator(cursor.pos)
2925 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2926 && !cursor.par->IsSeparator(cursor.pos))
2928 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2929 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2931 current_font = cursor.par->GetFontSettings(cursor.pos);
2932 real_current_font = GetFont(cursor.par, cursor.pos);
2934 DeleteEmptyParagraphMechanism(old_cursor);
2938 void LyXText::CursorLeft()
2941 if (cursor.par->table) {
2942 int cell = NumberOfCell(cursor.par, cursor.pos);
2943 if (cursor.par->table->IsContRow(cell) &&
2944 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2951 void LyXText::CursorLeftIntern()
2953 if (cursor.pos > 0) {
2954 SetCursor(cursor.par, cursor.pos - 1);
2956 else if (cursor.par->Previous()) {
2957 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2962 void LyXText::CursorRight()
2964 CursorRightIntern();
2965 if (cursor.par->table) {
2966 int cell = NumberOfCell(cursor.par, cursor.pos);
2967 if (cursor.par->table->IsContRow(cell) &&
2968 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2975 void LyXText::CursorRightIntern()
2977 if (cursor.pos < cursor.par->Last()) {
2978 SetCursor(cursor.par, cursor.pos + 1);
2980 else if (cursor.par->Next()) {
2981 SetCursor(cursor.par->Next(), 0);
2986 void LyXText::CursorUp()
2988 SetCursorFromCoordinates(cursor.x_fix,
2989 cursor.y - cursor.row->baseline - 1);
2990 if (cursor.par->table) {
2991 int cell = NumberOfCell(cursor.par, cursor.pos);
2992 if (cursor.par->table->IsContRow(cell) &&
2993 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3000 void LyXText::CursorDown()
3002 if (cursor.par->table &&
3003 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3006 SetCursorFromCoordinates(cursor.x_fix,
3007 cursor.y - cursor.row->baseline
3008 + cursor.row->height + 1);
3009 if (cursor.par->table) {
3010 int cell = NumberOfCell(cursor.par, cursor.pos);
3011 int cell_above = cursor.par->table->GetCellAbove(cell);
3012 while(cursor.par->table &&
3013 cursor.par->table->IsContRow(cell) &&
3014 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3015 SetCursorFromCoordinates(cursor.x_fix,
3016 cursor.y - cursor.row->baseline
3017 + cursor.row->height + 1);
3018 if (cursor.par->table) {
3019 cell = NumberOfCell(cursor.par, cursor.pos);
3020 cell_above = cursor.par->table->GetCellAbove(cell);
3027 void LyXText::CursorUpParagraph()
3029 if (cursor.pos > 0) {
3030 SetCursor(cursor.par, 0);
3032 else if (cursor.par->Previous()) {
3033 SetCursor(cursor.par->Previous(), 0);
3038 void LyXText::CursorDownParagraph()
3040 if (cursor.par->Next()) {
3041 SetCursor(cursor.par->Next(), 0);
3043 SetCursor(cursor.par, cursor.par->Last());
3049 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3051 bool deleted = false;
3053 /* this is the delete-empty-paragraph-mechanism. */
3057 // Paragraph should not be deleted if empty
3058 if ((textclasslist.Style(parameters->textclass,
3059 old_cursor.par->GetLayout())).keepempty)
3062 LyXCursor tmpcursor;
3064 if (old_cursor.par != cursor.par) {
3065 if ( (old_cursor.par->Last() == 0
3066 || (old_cursor.par->Last() == 1
3067 && (old_cursor.par->IsLineSeparator(0))))
3068 && old_cursor.par->FirstPhysicalPar()
3069 == old_cursor.par->LastPhysicalPar()) {
3071 /* ok, we will delete anything */
3073 // make sure that you do not delete any environments
3074 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3075 !(old_cursor.row->previous
3076 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3077 && !(old_cursor.row->next
3078 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3080 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3081 ((old_cursor.row->previous
3082 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3084 (old_cursor.row->next
3085 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3087 status = LyXText::NEED_MORE_REFRESH;
3090 if (old_cursor.row->previous) {
3091 refresh_row = old_cursor.row->previous;
3092 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3094 cursor = old_cursor; // that undo can restore the right cursor position
3095 LyXParagraph *endpar = old_cursor.par->next;
3096 if (endpar && endpar->GetDepth()) {
3097 while (endpar && endpar->GetDepth()) {
3098 endpar = endpar->LastPhysicalPar()->Next();
3101 SetUndo(Undo::DELETE,
3102 old_cursor.par->previous,
3106 /* delete old row */
3107 RemoveRow(old_cursor.row);
3108 if (params->paragraph == old_cursor.par) {
3109 params->paragraph = params->paragraph->next;
3111 /* delete old par */
3112 delete old_cursor.par;
3114 /* Breakagain the next par. Needed
3115 * because of the parindent that
3116 * can occur or dissappear. The
3117 * next row can change its height,
3118 * if there is another layout before */
3119 if (refresh_row->next) {
3120 BreakAgain(refresh_row->next);
3121 UpdateCounters(refresh_row);
3123 SetHeightOfRow(refresh_row);
3126 refresh_row = old_cursor.row->next;
3127 refresh_y = old_cursor.y - old_cursor.row->baseline;
3130 cursor = old_cursor; // that undo can restore the right cursor position
3131 LyXParagraph *endpar = old_cursor.par->next;
3132 if (endpar && endpar->GetDepth()) {
3133 while (endpar && endpar->GetDepth()) {
3134 endpar = endpar->LastPhysicalPar()->Next();
3137 SetUndo(Undo::DELETE,
3138 old_cursor.par->previous,
3142 /* delete old row */
3143 RemoveRow(old_cursor.row);
3144 /* delete old par */
3145 if (params->paragraph == old_cursor.par) {
3146 params->paragraph = params->paragraph->next;
3148 delete old_cursor.par;
3150 /* Breakagain the next par. Needed because of
3151 * the parindent that can occur or dissappear.
3152 * The next row can change its height, if there
3153 * is another layout before */
3155 BreakAgain(refresh_row);
3156 UpdateCounters(refresh_row->previous);
3160 /* correct cursor y */
3161 SetCursor(cursor.par, cursor.pos);
3163 /* if (cursor.y > old_cursor.y)
3164 cursor.y -= old_cursor.row->height; */
3166 if (sel_cursor.par == old_cursor.par
3167 && sel_cursor.pos == sel_cursor.pos) {
3168 /* correct selection*/
3169 sel_cursor = cursor;
3175 if (old_cursor.par->ClearParagraph()){
3176 RedoParagraphs(old_cursor, old_cursor.par->Next());
3177 /* correct cursor y */
3178 SetCursor(cursor.par, cursor.pos);
3179 sel_cursor = cursor;
3182 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3183 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3184 if (old_cursor.par->table->IsContRow(cell) &&
3185 IsEmptyTableRow(&old_cursor)) {
3186 RemoveTableRow(&old_cursor);
3193 LyXParagraph * LyXText::GetParFromID(int id)
3195 LyXParagraph * result = FirstParagraph();
3196 while (result && result->GetID() != id)
3197 result = result->next;
3203 bool LyXText::TextUndo()
3204 { // returns false if no undo possible
3205 Undo * undo = params->undostack.Pop();
3209 params->redostack.Push(CreateUndo(undo->kind,
3210 GetParFromID(undo->number_of_before_par),
3211 GetParFromID(undo->number_of_behind_par)));
3213 return TextHandleUndo(undo);
3217 bool LyXText::TextRedo()
3218 { // returns false if no redo possible
3219 Undo * undo = params->redostack.Pop();
3223 params->undostack.Push(CreateUndo(undo->kind,
3224 GetParFromID(undo->number_of_before_par),
3225 GetParFromID(undo->number_of_behind_par)));
3227 return TextHandleUndo(undo);
3231 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3232 bool result = false;
3234 LyXParagraph * before = GetParFromID(undo->number_of_before_par);
3235 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par);
3236 LyXParagraph * tmppar;
3237 LyXParagraph * tmppar2;
3238 LyXParagraph * tmppar3;
3239 LyXParagraph * tmppar4;
3240 LyXParagraph * endpar;
3241 LyXParagraph * tmppar5;
3243 // if there's no before take the beginning of the document for redoing
3245 SetCursorIntern(FirstParagraph(), 0);
3247 // replace the paragraphs with the undo informations
3249 tmppar3 = undo->par;
3250 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3253 while (tmppar4->next)
3254 tmppar4 = tmppar4->next;
3255 } // get last undo par
3257 // now remove the old text if there is any
3258 if (before != behind || (!behind && !before)){
3260 tmppar5 = before->next;
3262 tmppar5 = params->paragraph;
3264 while (tmppar5 && tmppar5 != behind){
3266 tmppar5 = tmppar5->next;
3267 // a memory optimization for edit: Only layout information
3268 // is stored in the undo. So restore the text informations.
3269 if (undo->kind == Undo::EDIT){
3270 tmppar2->text = tmppar->text;
3271 tmppar->text.clear();
3272 //tmppar->text.erase(tmppar->text.begin(),
3273 // tmppar->text.end());
3274 tmppar2 = tmppar2->next;
3276 if ( currentrow && currentrow->par == tmppar )
3277 currentrow = currentrow -> previous;
3282 // put the new stuff in the list if there is one
3285 before->next = tmppar3;
3287 params->paragraph = tmppar3;
3288 tmppar3->previous = before;
3292 params->paragraph = behind;
3295 tmppar4->next = behind;
3297 behind->previous = tmppar4;
3301 // Set the cursor for redoing
3303 SetCursorIntern(before->FirstSelfrowPar(), 0);
3304 // check wether before points to a closed float and open it if necessary
3305 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3306 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3308 while (tmppar4->previous &&
3309 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3310 tmppar4 = tmppar4->previous;
3311 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3312 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3313 tmppar4 = tmppar4->next;
3318 // open a cosed footnote at the end if necessary
3319 if (behind && behind->previous &&
3320 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3321 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3322 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3323 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3324 behind = behind->next;
3328 // calculate the endpar for redoing the paragraphs.
3330 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3331 endpar = behind->LastPhysicalPar()->Next();
3333 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3338 tmppar = GetParFromID(undo->number_of_cursor_par);
3339 RedoParagraphs(cursor, endpar);
3341 SetCursorIntern(tmppar, undo->cursor_pos);
3342 UpdateCounters(cursor.row);
3352 void LyXText::FinishUndo()
3353 { // makes sure the next operation will be stored
3354 undo_finished = True;
3358 void LyXText::FreezeUndo()
3359 { // this is dangerous and for internal use only
3364 void LyXText::UnFreezeUndo()
3365 { // this is dangerous and for internal use only
3366 undo_frozen = false;
3370 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3371 LyXParagraph * behind)
3374 params->undostack.Push(CreateUndo(kind, before, behind));
3375 params->redostack.Clear();
3379 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3380 LyXParagraph * behind)
3382 params->redostack.Push(CreateUndo(kind, before, behind));
3386 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3387 LyXParagraph * behind)
3389 int before_number = -1;
3390 int behind_number = -1;
3392 before_number = before->GetID();
3394 behind_number = behind->GetID();
3395 // Undo::EDIT and Undo::FINISH are
3396 // always finished. (no overlapping there)
3397 // overlapping only with insert and delete inside one paragraph:
3398 // Nobody wants all removed character
3399 // appear one by one when undoing.
3400 // EDIT is special since only layout information, not the
3401 // contents of a paragaph are stored.
3402 if (!undo_finished && kind != Undo::EDIT &&
3403 kind != Undo::FINISH){
3404 // check wether storing is needed
3405 if (params->undostack.Top() &&
3406 params->undostack.Top()->kind == kind &&
3407 params->undostack.Top()->number_of_before_par == before_number &&
3408 params->undostack.Top()->number_of_behind_par == behind_number ){
3413 // create a new Undo
3414 LyXParagraph * undopar;
3415 LyXParagraph * tmppar;
3416 LyXParagraph * tmppar2;
3418 LyXParagraph * start = 0;
3419 LyXParagraph * end = 0;
3422 start = before->next;
3424 start = FirstParagraph();
3426 end = behind->previous;
3428 end = FirstParagraph();
3433 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3435 tmppar2 = tmppar->Clone();
3436 tmppar2->SetID(tmppar->GetID());
3438 // a memory optimization: Just store the layout information when only edit
3439 if (kind == Undo::EDIT){
3440 tmppar2->text.clear();
3441 //tmppar2->text.erase(tmppar2->text.begin(),
3442 // tmppar2->text.end());
3447 while (tmppar != end && tmppar->next) {
3448 tmppar = tmppar->next;
3449 tmppar2->next = tmppar->Clone();
3450 tmppar2->next->SetID(tmppar->GetID());
3451 // a memory optimization: Just store the layout information when only edit
3452 if (kind == Undo::EDIT){
3453 tmppar2->next->text.clear();
3454 //tmppar2->next->text.erase(tmppar2->next->text.begin(), tmppar2->next->text.end());
3456 tmppar2->next->previous = tmppar2;
3457 tmppar2 = tmppar2->next;
3462 undopar = 0; // nothing to replace (undo of delete maybe)
3464 int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3465 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3467 Undo * undo = new Undo(kind,
3468 before_number, behind_number,
3469 cursor_par, cursor_pos,
3472 undo_finished = false;
3477 void LyXText::SetCursorParUndo()
3479 SetUndo(Undo::FINISH,
3480 cursor.par->ParFromPos(cursor.pos)->previous,
3481 cursor.par->ParFromPos(cursor.pos)->next);
3484 void LyXText::RemoveTableRow(LyXCursor * cursor)
3492 /* move to the previous row */
3493 cell_act = NumberOfCell(cursor->par, cursor->pos);
3496 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3498 while (cursor->pos &&
3499 !cursor->par->table->IsFirstCell(cell_act)){
3501 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3506 /* now we have to pay attention if the actual table is the
3507 main row of TableContRows and if yes to delete all of them */
3512 /* delete up to the next row */
3513 while (cursor->pos < cursor->par->Last() &&
3515 || !cursor->par->table->IsFirstCell(cell_act))){
3516 while (cursor->pos < cursor->par->Last() &&
3517 !cursor->par->IsNewline(cursor->pos))
3518 cursor->par->Erase(cursor->pos);
3521 if (cursor->pos < cursor->par->Last())
3522 cursor->par-> Erase(cursor->pos);
3524 if (cursor->pos && cursor->pos == cursor->par->Last()){
3526 cursor->par->Erase(cursor->pos); // no newline at the very end!
3528 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3529 !cursor->par->table->IsContRow(cell_org) &&
3530 cursor->par->table->IsContRow(cell));
3531 cursor->par->table->DeleteRow(cell_org);
3536 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor)
3538 if (!old_cursor->par->table)
3540 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3542 pos = old_cursor->pos,
3543 cell = NumberOfCell(old_cursor->par, pos);
3545 // search first charater of this table row
3546 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3548 while (pos && !old_cursor->par->IsNewline(pos-1))
3552 if (!old_cursor->par->IsNewline(pos))
3556 while ((pos < old_cursor->par->Last()) &&
3557 !old_cursor->par->table->IsFirstCell(cell)) {
3558 if (!old_cursor->par->IsNewline(pos))
3569 bool LyXText::IsEmptyTableCell()
3571 LyXParagraph::size_type pos = cursor.pos - 1;
3572 while (pos >= 0 && pos < cursor.par->Last()
3573 && !cursor.par->IsNewline(pos))
3575 return cursor.par->IsNewline(pos + 1);
3579 void LyXText::toggleAppendix(){
3580 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3581 bool start = !par->start_of_appendix;
3583 /* ensure that we have only one start_of_appendix in this document */
3584 LyXParagraph * tmp = FirstParagraph();
3585 for (;tmp;tmp = tmp->next)
3586 tmp->start_of_appendix = 0;
3587 par->start_of_appendix = start;
3589 /* we can set the refreshing parameters now */
3590 status = LyXText::NEED_MORE_REFRESH;
3592 refresh_row = 0; // not needed for full update
3594 SetCursor(cursor.par, cursor.pos);