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"
35 #include "BufferView.h"
38 extern BufferView * current_view;
43 LyXText::LyXText(int pw, Buffer * p)
50 parameters = &p->params;
54 status = LyXText::UNCHANGED;
55 LyXParagraph * par = p->paragraph;
56 current_font = GetFont(par, 0);
61 InsertParagraph(par, lastrow);
64 /* set cursor at the very top position */
65 selection = true; /* these setting is necessary
66 * because of the delete-empty-
67 * paragraph mechanism in
69 SetCursor(firstrow->par, 0);
74 /* no rebreak necessary */
80 // Default layouttype for copy environment type
88 // Delete all rows, this does not touch the paragraphs!
89 Row * tmprow = firstrow;
91 tmprow = firstrow->next;
98 // Gets the fully instantiated font at a given position in a paragraph
99 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
100 // The difference is that this one is used for displaying, and thus we
101 // are allowed to make cosmetic improvements. For instance make footnotes
103 // If position is -1, we get the layout font of the paragraph.
104 // If position is -2, we get the font of the manual label of the paragraph.
105 LyXFont LyXText::GetFont(LyXParagraph * par,
106 LyXParagraph::size_type pos)
108 LyXLayout const & layout =
109 textclasslist.Style(parameters->textclass, par->GetLayout());
111 char par_depth = par->GetDepth();
112 // We specialize the 95% common case:
113 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
116 if (layout.labeltype == LABEL_MANUAL
117 && pos < BeginningOfMainBody(par)) {
119 return par->GetFontSettings(pos).
120 realize(layout.reslabelfont);
122 return par->GetFontSettings(pos).
123 realize(layout.resfont);
126 // process layoutfont for pos == -1 and labelfont for pos < -1
128 return layout.resfont;
130 return layout.reslabelfont;
134 // The uncommon case need not be optimized as much
136 LyXFont layoutfont, tmpfont;
140 if (pos < BeginningOfMainBody(par)) {
142 layoutfont = layout.labelfont;
145 layoutfont = layout.font;
147 tmpfont = par->GetFontSettings(pos);
148 tmpfont.realize(layoutfont);
151 // process layoutfont for pos == -1 and labelfont for pos < -1
153 tmpfont = layout.font;
155 tmpfont = layout.labelfont;
158 // Resolve against environment font information
159 while (par && par_depth && !tmpfont.resolved()) {
160 par = par->DepthHook(par_depth - 1);
162 tmpfont.realize(textclasslist.
163 Style(parameters->textclass,
164 par->GetLayout()).font);
165 par_depth = par->GetDepth();
169 tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
171 // Cosmetic improvement: If this is an open footnote, make the font
173 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
174 && par->footnotekind == LyXParagraph::FOOTNOTE) {
182 void LyXText::SetCharFont(LyXParagraph * par,
183 LyXParagraph::size_type pos,
186 // Let the insets convert their font
187 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
188 if (par->GetInset(pos))
189 font = par->GetInset(pos)->ConvertFont(font);
192 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
195 // Get concrete layout font to reduce against
198 if (pos < BeginningOfMainBody(par))
199 layoutfont = layout.labelfont;
201 layoutfont = layout.font;
203 // Realize against environment font information
204 if (par->GetDepth()){
205 LyXParagraph * tp = par;
206 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
207 tp = tp->DepthHook(tp->GetDepth()-1);
209 layoutfont.realize(textclasslist.
210 Style(parameters->textclass,
211 tp->GetLayout()).font);
215 layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
217 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
218 && par->footnotekind == LyXParagraph::FOOTNOTE) {
219 layoutfont.decSize();
222 // Now, reduce font against full layout font
223 font.reduce(layoutfont);
225 par->SetFont(pos, font);
229 /* inserts a new row behind the specified row, increments
230 * the touched counters */
231 void LyXText::InsertRow(Row * row, LyXParagraph * par,
232 LyXParagraph::size_type pos)
234 Row * tmprow = new Row;
236 tmprow->previous = 0;
237 tmprow->next = firstrow;
241 tmprow->previous = row;
242 tmprow->next = row->next;
247 tmprow->next->previous = tmprow;
249 if (tmprow->previous)
250 tmprow->previous->next = tmprow;
258 number_of_rows++; /* one more row */
262 /* removes the row and reset the touched counters */
263 void LyXText::RemoveRow(Row * row)
265 /* this must not happen before the currentrow for clear reasons.
266 so the trick is just to set the current row onto the previous
269 GetRow(row->par, row->pos, unused_y);
270 currentrow = currentrow->previous;
272 currentrow_y -= currentrow->height;
277 row->next->previous = row->previous;
278 if (!row->previous) {
279 firstrow = row->next;
282 row->previous->next = row->next;
285 lastrow = row->previous;
287 height -= row->height; /* the text becomes smaller */
290 --number_of_rows; /* one row less */
294 /* remove all following rows of the paragraph of the specified row. */
295 void LyXText::RemoveParagraph(Row * row)
299 LyXParagraph * tmppar = row->par;
302 while (row && row->par == tmppar) {
310 /* insert the specified paragraph behind the specified row */
311 void LyXText::InsertParagraph(LyXParagraph * par, Row * row)
313 InsertRow(row, par, 0); /* insert a new row, starting
316 SetCounter(par); /* set the counters */
318 /* and now append the whole paragraph behind the new row */
320 firstrow->height = 0;
321 AppendParagraph(firstrow);
324 row->next->height = 0;
325 AppendParagraph(row->next);
330 void LyXText::ToggleFootnote()
332 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
333 if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
335 current_view->owner()->getMiniBuffer()->Set(_("Opened float"));
338 current_view->owner()->getMiniBuffer()->Set(_("Closed float"));
344 void LyXText::OpenStuff()
346 if (cursor.pos == 0 && cursor.par->bibkey){
347 cursor.par->bibkey->Edit(0, 0);
349 else if (cursor.pos < cursor.par->Last()
350 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
351 && cursor.par->GetInset(cursor.pos)->Editable()) {
352 current_view->owner()->getMiniBuffer()->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
353 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
355 cursor.par->GetInset(cursor.pos)->Edit(0, 0);
363 void LyXText::CloseFootnote()
365 LyXParagraph * endpar, * tmppar;
368 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
370 /* if the cursor is not in an open footnote, or
371 * there is no open footnote in this paragraph, just return. */
372 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
375 || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
376 current_view->owner()->getMiniBuffer()->Set(_("Nothing to do"));
380 /* ok, move the cursor right before the footnote */
382 /* just a little faster than using CursorRight() */
383 for (cursor.pos = 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
384 /* now the cursor is at the beginning of the physical par */
385 SetCursor(cursor.par,
387 cursor.par->ParFromPos(cursor.pos)->text.size());
390 /* we are in a footnote, so let us move at the beginning */
391 /* this is just faster than using just CursorLeft() */
394 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
395 /* just a little bit faster than movin the cursor */
396 tmppar = tmppar->Previous();
398 SetCursor(tmppar, tmppar->Last());
401 /* the cursor must be exactly before the footnote */
402 par = cursor.par->ParFromPos(cursor.pos);
404 status = LyXText::NEED_MORE_REFRESH;
405 refresh_row = cursor.row;
406 refresh_y = cursor.y - cursor.row->baseline;
409 endpar = par->NextAfterFootnote()->Next();
412 tmppar->CloseFootnote(cursor.pos);
414 while (tmppar != endpar) {
415 RemoveRow(row->next);
417 tmppar = row->next->par;
422 AppendParagraph(cursor.row);
424 SetCursor(cursor.par, cursor.pos);
428 if (cursor.row->next)
429 SetHeightOfRow(cursor.row->next);
433 /* used in setlayout */
434 // Asger is not sure we want to do this...
435 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
437 LyXFont layoutfont, tmpfont;
439 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
441 for (LyXParagraph::size_type pos = 0;
442 pos < par->Last(); ++pos) {
443 if (pos < BeginningOfMainBody(par))
444 layoutfont = layout.labelfont;
446 layoutfont = layout.font;
448 tmpfont = par->GetFontSettings(pos);
449 tmpfont.reduce(layoutfont);
450 par->SetFont(pos, tmpfont);
455 /* set layout over selection and make a total rebreak of those paragraphs */
456 void LyXText::SetLayout(char layout)
460 /* if there is no selection just set the layout of the current paragraph */
462 sel_start_cursor = cursor; /* dummy selection */
463 sel_end_cursor = cursor;
466 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
467 LyXParagraph * undoendpar = endpar;
469 if (endpar && endpar->GetDepth()) {
470 while (endpar && endpar->GetDepth()) {
471 endpar = endpar->LastPhysicalPar()->Next();
476 endpar = endpar->Next(); /* because of parindents etc. */
480 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
483 tmpcursor = cursor; /* store the current cursor */
485 /* ok we have a selection. This is always between sel_start_cursor
486 * and sel_end cursor */
487 cursor = sel_start_cursor;
489 LyXLayout const & lyxlayout = textclasslist.Style(parameters->textclass, layout);
491 while (cursor.par != sel_end_cursor.par) {
492 if (cursor.par->footnoteflag ==
493 sel_start_cursor.par->footnoteflag) {
494 cursor.par->SetLayout(layout);
495 MakeFontEntriesLayoutSpecific(cursor.par);
496 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
497 fppar->added_space_top = lyxlayout.fill_top ?
498 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
499 fppar->added_space_bottom = lyxlayout.fill_bottom ?
500 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
501 if (lyxlayout.margintype == MARGIN_MANUAL)
502 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
503 if (lyxlayout.labeltype != LABEL_BIBLIO
505 delete fppar->bibkey;
509 cursor.par = cursor.par->Next();
511 if (cursor.par->footnoteflag ==
512 sel_start_cursor.par->footnoteflag) {
513 cursor.par->SetLayout(layout);
514 MakeFontEntriesLayoutSpecific(cursor.par);
515 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
516 fppar->added_space_top = lyxlayout.fill_top ?
517 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
518 fppar->added_space_bottom = lyxlayout.fill_bottom ?
519 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
520 if (lyxlayout.margintype == MARGIN_MANUAL)
521 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
522 if (lyxlayout.labeltype != LABEL_BIBLIO
524 delete fppar->bibkey;
529 RedoParagraphs(sel_start_cursor, endpar);
531 /* we have to reset the selection, because the
532 * geometry could have changed */
533 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
535 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
536 UpdateCounters(cursor.row);
539 SetCursor(tmpcursor.par, tmpcursor.pos);
543 /* increment depth over selection and
544 * make a total rebreak of those paragraphs */
545 void LyXText::IncDepth()
547 // If there is no selection, just use the current paragraph
549 sel_start_cursor = cursor; /* dummy selection */
550 sel_end_cursor = cursor;
553 // We end at the next paragraph with depth 0
554 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
555 LyXParagraph * undoendpar = endpar;
557 if (endpar && endpar->GetDepth()) {
558 while (endpar && endpar->GetDepth()) {
559 endpar = endpar->LastPhysicalPar()->Next();
564 endpar = endpar->Next(); /* because of parindents etc. */
568 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
571 LyXCursor tmpcursor = cursor; /* store the current cursor */
573 /* ok we have a selection. This is always between sel_start_cursor
574 * and sel_end cursor */
575 cursor = sel_start_cursor;
577 bool anything_changed = false;
580 // NOTE: you can't change the depth of a bibliography entry
581 if (cursor.par->footnoteflag ==
582 sel_start_cursor.par->footnoteflag
583 && textclasslist.Style(parameters->textclass,
584 cursor.par->GetLayout()
585 ).labeltype != LABEL_BIBLIO) {
586 LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
588 && (prev->GetDepth() - cursor.par->GetDepth() > 0
589 || (prev->GetDepth() == cursor.par->GetDepth()
590 && textclasslist.Style(parameters->textclass,
591 prev->GetLayout()).isEnvironment()))) {
592 cursor.par->FirstPhysicalPar()->depth++;
593 anything_changed = true;
596 if (cursor.par == sel_end_cursor.par)
598 cursor.par = cursor.par->Next();
601 /* if nothing changed set all depth to 0 */
602 if (!anything_changed) {
603 cursor = sel_start_cursor;
604 while (cursor.par != sel_end_cursor.par) {
605 cursor.par->FirstPhysicalPar()->depth = 0;
606 cursor.par = cursor.par->Next();
608 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
609 cursor.par->FirstPhysicalPar()->depth = 0;
612 RedoParagraphs(sel_start_cursor, endpar);
614 /* we have to reset the selection, because the
615 * geometry could have changed */
616 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
618 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
619 UpdateCounters(cursor.row);
622 SetCursor(tmpcursor.par, tmpcursor.pos);
626 /* decrement depth over selection and
627 * make a total rebreak of those paragraphs */
628 void LyXText::DecDepth()
630 /* if there is no selection just set the layout of the current paragraph */
632 sel_start_cursor = cursor; /* dummy selection */
633 sel_end_cursor = cursor;
636 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
637 LyXParagraph * undoendpar = endpar;
639 if (endpar && endpar->GetDepth()) {
640 while (endpar && endpar->GetDepth()) {
641 endpar = endpar->LastPhysicalPar()->Next();
646 endpar = endpar->Next(); /* because of parindents etc. */
650 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
653 LyXCursor tmpcursor = cursor; /* store the current cursor */
655 /* ok we have a selection. This is always between sel_start_cursor
656 * and sel_end cursor */
657 cursor = sel_start_cursor;
660 if (cursor.par->footnoteflag ==
661 sel_start_cursor.par->footnoteflag) {
662 if (cursor.par->FirstPhysicalPar()->depth)
663 cursor.par->FirstPhysicalPar()->depth--;
665 if (cursor.par == sel_end_cursor.par)
667 cursor.par = cursor.par->Next();
670 RedoParagraphs(sel_start_cursor, endpar);
672 /* we have to reset the selection, because the
673 * geometry could have changed */
674 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
676 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
677 UpdateCounters(cursor.row);
680 SetCursor(tmpcursor.par, tmpcursor.pos);
684 /* set font over selection and make a total rebreak of those paragraphs */
685 void LyXText::SetFont(LyXFont font, bool toggleall)
687 /* if there is no selection just set the current_font */
689 // Determine basis font
691 if (cursor.pos < BeginningOfMainBody(cursor.par))
692 layoutfont = GetFont(cursor.par, -2);
694 layoutfont = GetFont(cursor.par, -1);
695 // Update current font
696 real_current_font.update(font, toggleall);
698 // Reduce to implicit settings
699 current_font = real_current_font;
700 current_font.reduce(layoutfont);
701 // And resolve it completely
702 real_current_font.realize(layoutfont);
706 LyXCursor tmpcursor = cursor; /* store the current cursor */
708 /* ok we have a selection. This is always between sel_start_cursor
709 * and sel_end cursor */
712 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
713 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
714 cursor = sel_start_cursor;
715 while (cursor.par != sel_end_cursor.par ||
716 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
717 && cursor.pos < sel_end_cursor.pos))
719 if (cursor.pos < cursor.par->Last()
720 && cursor.par->footnoteflag
721 == sel_start_cursor.par->footnoteflag) { /* an open footnote
724 LyXFont newfont = GetFont(cursor.par, cursor.pos);
725 newfont.update(font, toggleall);
726 SetCharFont(cursor.par, cursor.pos, newfont);
730 cursor.par = cursor.par->Next();
734 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
736 /* we have to reset the selection, because the
737 * geometry could have changed */
738 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
740 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
743 SetCursor(tmpcursor.par, tmpcursor.pos);
747 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
749 Row * tmprow = cursor.row;
750 long y = cursor.y - tmprow->baseline;
752 SetHeightOfRow(tmprow);
753 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
754 /* find the first row of the paragraph */
755 if (first_phys_par != tmprow->par)
756 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
757 tmprow = tmprow->previous;
759 SetHeightOfRow(tmprow);
761 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
762 tmprow = tmprow->previous;
764 SetHeightOfRow(tmprow);
767 /* we can set the refreshing parameters now */
768 status = LyXText::NEED_MORE_REFRESH;
770 refresh_row = tmprow;
771 SetCursor(cursor.par, cursor.pos);
775 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
777 Row * tmprow = cursor.row;
779 long y = cursor.y - tmprow->baseline;
780 SetHeightOfRow(tmprow);
781 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
782 /* find the first row of the paragraph */
783 if (first_phys_par != tmprow->par)
784 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
785 tmprow = tmprow->previous;
788 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
789 tmprow = tmprow->previous;
794 /* we can set the refreshing parameters now */
795 if (status == LyXText::UNCHANGED || y < refresh_y) {
797 refresh_row = tmprow;
799 status = LyXText::NEED_MORE_REFRESH;
800 SetCursor(cursor.par, cursor.pos);
804 /* deletes and inserts again all paragaphs between the cursor
805 * and the specified par
806 * This function is needed after SetLayout and SetFont etc. */
807 void LyXText::RedoParagraphs(LyXCursor cursor, LyXParagraph * endpar)
810 LyXParagraph * tmppar, * first_phys_par;
812 Row * tmprow = cursor.row;
814 long y = cursor.y - tmprow->baseline;
816 if (!tmprow->previous){
817 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
820 first_phys_par = tmprow->par->FirstPhysicalPar();
821 /* find the first row of the paragraph */
822 if (first_phys_par != tmprow->par)
823 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
824 tmprow = tmprow->previous;
827 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
828 tmprow = tmprow->previous;
833 /* we can set the refreshing parameters now */
834 status = LyXText::NEED_MORE_REFRESH;
836 refresh_row = tmprow->previous; /* the real refresh row will
837 * be deleted, so I store
838 * the previous here */
841 tmppar = tmprow->next->par;
844 while (tmppar != endpar) {
845 RemoveRow(tmprow->next);
847 tmppar = tmprow->next->par;
852 /* remove the first one */
853 tmprow2 = tmprow; /* this is because tmprow->previous
855 tmprow = tmprow->previous;
858 tmppar = first_phys_par;
862 InsertParagraph(tmppar, tmprow);
865 while (tmprow->next && tmprow->next->par == tmppar)
866 tmprow = tmprow->next;
867 tmppar = tmppar->Next();
871 while (tmppar != endpar);
873 /* this is because of layout changes */
875 refresh_y -= refresh_row->height;
876 SetHeightOfRow(refresh_row);
879 refresh_row = firstrow;
881 SetHeightOfRow(refresh_row);
884 if (tmprow && tmprow->next)
885 SetHeightOfRow(tmprow->next);
889 int LyXText::FullRebreak()
891 if (need_break_row) {
892 BreakAgain(need_break_row);
900 /* important for the screen */
903 /* the cursor set functions have a special mechanism. When they
904 * realize, that you left an empty paragraph, they will delete it.
905 * They also delet the corresponding row */
907 /* need the selection cursor: */
908 void LyXText::SetSelection()
911 last_sel_cursor = sel_cursor;
912 sel_start_cursor = sel_cursor;
913 sel_end_cursor = sel_cursor;
918 /* first the toggling area */
919 if (cursor.y < last_sel_cursor.y ||
920 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
921 toggle_end_cursor = last_sel_cursor;
922 toggle_cursor = cursor;
925 toggle_end_cursor = cursor;
926 toggle_cursor = last_sel_cursor;
929 last_sel_cursor = cursor;
931 /* and now the whole selection */
933 if (sel_cursor.y < cursor.y ||
934 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
935 sel_end_cursor = cursor;
936 sel_start_cursor = sel_cursor;
939 sel_end_cursor = sel_cursor;
940 sel_start_cursor = cursor;
943 /* a selection with no contents is not a selection */
944 if (sel_start_cursor.x == sel_end_cursor.x &&
945 sel_start_cursor.y == sel_end_cursor.y)
950 void LyXText::ClearSelection()
957 void LyXText::CursorHome()
959 SetCursor(cursor.par, cursor.row->pos);
963 void LyXText::CursorEnd()
965 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
966 SetCursor(cursor.par, RowLast(cursor.row) + 1);
968 if (cursor.par->Last() &&
969 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
970 || cursor.par->IsNewline(RowLast(cursor.row))))
971 SetCursor(cursor.par, RowLast(cursor.row));
973 SetCursor(cursor.par, RowLast(cursor.row) + 1);
975 if (cursor.par->table) {
976 int cell = NumberOfCell(cursor.par, cursor.pos);
977 if (cursor.par->table->RowHasContRow(cell) &&
978 cursor.par->table->CellHasContRow(cell)<0) {
979 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
980 SetCursor(cursor.par, RowLast(cursor.row) + 1);
982 if (cursor.par->Last() &&
983 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
984 || cursor.par->IsNewline(RowLast(cursor.row))))
985 SetCursor(cursor.par, RowLast(cursor.row));
987 SetCursor(cursor.par, RowLast(cursor.row) + 1);
994 void LyXText::CursorTop()
996 while (cursor.par->Previous())
997 cursor.par = cursor.par->Previous();
998 SetCursor(cursor.par, 0);
1002 void LyXText::CursorBottom()
1004 while (cursor.par->Next())
1005 cursor.par = cursor.par->Next();
1006 SetCursor(cursor.par, cursor.par->Last());
1010 /* returns a pointer to the row near the specified y-coordinate
1011 * (relative to the whole text). y is set to the real beginning
1013 Row * LyXText::GetRowNearY(long & y)
1019 tmprow = currentrow;
1020 tmpy = currentrow_y;
1028 while (tmprow->next && tmpy + tmprow->height <= y) {
1029 tmpy += tmprow->height;
1030 tmprow = tmprow->next;
1033 while (tmprow->previous && tmpy > y) {
1034 tmprow = tmprow->previous;
1035 tmpy -= tmprow->height;
1038 currentrow = tmprow;
1039 currentrow_y = tmpy;
1041 y = tmpy; /* return the real y */
1046 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1048 // If the mask is completely neutral, tell user
1049 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1050 // Could only happen with user style
1051 current_view->owner()->getMiniBuffer()->Set(_("No font change defined. Use Character under"
1052 " the Layout menu to define font change."));
1056 // Try implicit word selection
1057 LyXCursor resetCursor = cursor;
1058 int implicitSelection = SelectWordWhenUnderCursor();
1061 SetFont(font, toggleall);
1062 //current_view->owner()->getMiniBuffer()->Set(_("Font style changed"));
1064 /* Implicit selections are cleared afterwards and cursor is set to the
1065 original position. */
1066 if (implicitSelection) {
1068 cursor = resetCursor;
1069 SetCursor( cursor.par, cursor.pos );
1070 sel_cursor = cursor;
1075 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1077 if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1080 return par->BeginningOfMainBody();
1084 /* if there is a selection, reset every environment you can find
1085 * in the selection, otherwise just the environment you are in */
1086 void LyXText::MeltFootnoteEnvironment()
1088 LyXParagraph * tmppar, * firsttmppar;
1092 /* is is only allowed, if the cursor is IN an open footnote.
1093 * Otherwise it is too dangerous */
1094 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1097 SetUndo(Undo::FINISH,
1098 cursor.par->PreviousBeforeFootnote()->previous,
1099 cursor.par->NextAfterFootnote()->next);
1101 /* ok, move to the beginning of the footnote. */
1102 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1103 cursor.par = cursor.par->Previous();
1105 SetCursor(cursor.par, cursor.par->Last());
1106 /* this is just faster than using CursorLeft(); */
1108 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1109 tmppar = firsttmppar;
1110 /* tmppar is now the paragraph right before the footnote */
1112 char first_footnote_par_is_not_empty = tmppar->next->text.size();
1114 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1115 tmppar = tmppar->next; /* I use next instead of Next(),
1116 * because there cannot be any
1117 * footnotes in a footnote
1119 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1121 /* remember the captions and empty paragraphs */
1122 if ((textclasslist.Style(parameters->textclass,
1123 tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1125 tmppar->SetLayout(0);
1128 /* now we will paste the ex-footnote, if the layouts allow it */
1129 /* first restore the layout of the paragraph right behind the footnote*/
1131 tmppar->next->MakeSameLayout(cursor.par);
1134 if ((!tmppar->GetLayout() && !tmppar->table)
1135 || (tmppar->Next() && (!tmppar->Next()->Last()
1136 || tmppar->Next()->HasSameLayout(tmppar)))) {
1137 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1138 tmppar->Next()->Erase(0);
1139 tmppar->PasteParagraph();
1142 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1143 * by the pasting of the beginning */
1145 /* then the beginning */
1146 /* if there is no space between the text and the footnote, so we insert
1148 * (only if the previous par and the footnotepar are not empty!) */
1149 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1150 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1151 if (firsttmppar->text.size()
1152 && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1153 && first_footnote_par_is_not_empty) {
1154 firsttmppar->next->InsertChar(0, ' ');
1156 firsttmppar->PasteParagraph();
1159 /* now redo the paragaphs */
1160 RedoParagraphs(cursor, tmppar);
1162 SetCursor(cursor.par, cursor.pos);
1164 /* sometimes it can happen, that there is a counter change */
1165 Row * row = cursor.row;
1166 while (row->next && row->par != tmppar && row->next->par != tmppar)
1168 UpdateCounters(row);
1175 /* the DTP switches for paragraphs. LyX will store them in the
1176 * first physicla paragraph. When a paragraph is broken, the top settings
1177 * rest, the bottom settings are given to the new one. So I can make shure,
1178 * they do not duplicate themself and you cannnot make dirty things with
1181 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1182 bool pagebreak_top, bool pagebreak_bottom,
1183 VSpace space_top, VSpace space_bottom,
1185 string labelwidthstring,
1188 LyXCursor tmpcursor = cursor;
1190 sel_start_cursor = cursor;
1191 sel_end_cursor = cursor;
1194 // make sure that the depth behind the selection are restored, too
1195 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1196 LyXParagraph * undoendpar = endpar;
1198 if (endpar && endpar->GetDepth()) {
1199 while (endpar && endpar->GetDepth()) {
1200 endpar = endpar->LastPhysicalPar()->Next();
1201 undoendpar = endpar;
1205 endpar = endpar->Next(); /* because of parindents etc. */
1209 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1213 LyXParagraph * tmppar = sel_end_cursor.par;
1214 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1215 SetCursor(tmppar->FirstPhysicalPar(), 0);
1216 status = LyXText::NEED_MORE_REFRESH;
1217 refresh_row = cursor.row;
1218 refresh_y = cursor.y - cursor.row->baseline;
1219 if (cursor.par->footnoteflag ==
1220 sel_start_cursor.par->footnoteflag) {
1221 cursor.par->line_top = line_top;
1222 cursor.par->line_bottom = line_bottom;
1223 cursor.par->pagebreak_top = pagebreak_top;
1224 cursor.par->pagebreak_bottom = pagebreak_bottom;
1225 cursor.par->added_space_top = space_top;
1226 cursor.par->added_space_bottom = space_bottom;
1227 /* does the layout allow the new alignment? */
1228 if (align == LYX_ALIGN_LAYOUT)
1229 align = textclasslist
1230 .Style(parameters->textclass,
1231 cursor.par->GetLayout()).align;
1232 if (align & textclasslist
1233 .Style(parameters->textclass,
1234 cursor.par->GetLayout()).alignpossible) {
1235 if (align == textclasslist
1236 .Style(parameters->textclass,
1237 cursor.par->GetLayout()).align)
1238 cursor.par->align = LYX_ALIGN_LAYOUT;
1240 cursor.par->align = align;
1242 cursor.par->SetLabelWidthString(labelwidthstring);
1243 cursor.par->noindent = noindent;
1246 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1249 RedoParagraphs(sel_start_cursor, endpar);
1252 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1253 sel_cursor = cursor;
1254 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1256 SetCursor(tmpcursor.par, tmpcursor.pos);
1260 void LyXText::SetParagraphExtraOpt(int type,
1262 char const * widthp,
1263 int alignment, bool hfill,
1264 bool start_minipage)
1266 LyXCursor tmpcursor = cursor;
1267 LyXParagraph * tmppar;
1269 sel_start_cursor = cursor;
1270 sel_end_cursor = cursor;
1273 // make sure that the depth behind the selection are restored, too
1274 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1275 LyXParagraph * undoendpar = endpar;
1277 if (endpar && endpar->GetDepth()) {
1278 while (endpar && endpar->GetDepth()) {
1279 endpar = endpar->LastPhysicalPar()->Next();
1280 undoendpar = endpar;
1284 endpar = endpar->Next(); /* because of parindents etc. */
1288 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1291 tmppar = sel_end_cursor.par;
1292 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1293 SetCursor(tmppar->FirstPhysicalPar(), 0);
1294 status = LyXText::NEED_MORE_REFRESH;
1295 refresh_row = cursor.row;
1296 refresh_y = cursor.y - cursor.row->baseline;
1297 if (cursor.par->footnoteflag ==
1298 sel_start_cursor.par->footnoteflag) {
1299 if (type == LyXParagraph::PEXTRA_NONE) {
1300 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1301 cursor.par->UnsetPExtraType();
1302 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1305 cursor.par->SetPExtraType(type, width, widthp);
1306 cursor.par->pextra_hfill = hfill;
1307 cursor.par->pextra_start_minipage = start_minipage;
1308 cursor.par->pextra_alignment = alignment;
1311 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1313 RedoParagraphs(sel_start_cursor, endpar);
1315 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1316 sel_cursor = cursor;
1317 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1319 SetCursor(tmpcursor.par, tmpcursor.pos);
1323 static char const * alphaCounter(int n){
1324 static char result[2];
1337 /* set the counter of a paragraph. This includes the labels */
1338 void LyXText::SetCounter(LyXParagraph * par)
1342 /* this is only relevant for the beginning of paragraph */
1343 par = par->FirstPhysicalPar();
1345 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1348 LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1350 /* copy the prev-counters to this one, unless this is the start of a
1351 footnote or of a bibliography or the very first paragraph */
1353 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1354 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1355 && par->footnotekind == LyXParagraph::FOOTNOTE)
1356 && !(textclasslist.Style(parameters->textclass,
1357 par->Previous()->GetLayout()
1358 ).labeltype != LABEL_BIBLIO
1359 && layout.labeltype == LABEL_BIBLIO)) {
1360 for (i = 0; i<10; i++) {
1361 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1363 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1364 if (!par->appendix && par->start_of_appendix){
1365 par->appendix = true;
1366 for (i = 0; i<10; i++) {
1367 par->setCounter(i, 0);
1370 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1371 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1374 for (i = 0; i<10; i++) {
1375 par->setCounter(i, 0);
1377 par->appendix = par->start_of_appendix;
1382 // if this is an open marginnote and this is the first
1383 // entry in the marginnote and the enclosing
1384 // environment is an enum/item then correct for the
1385 // LaTeX behaviour (ARRae)
1386 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1387 && par->footnotekind == LyXParagraph::MARGIN
1389 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1390 && (par->PreviousBeforeFootnote()
1391 && textclasslist.Style(parameters->textclass,
1392 par->PreviousBeforeFootnote()->GetLayout()
1393 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1394 // Any itemize or enumerate environment in a marginnote
1395 // that is embedded in an itemize or enumerate
1396 // paragraph is seen by LaTeX as being at a deeper
1397 // level within that enclosing itemization/enumeration
1398 // even if there is a "standard" layout at the start of
1404 /* Maybe we have to increment the enumeration depth.
1405 * BUT, enumeration in a footnote is considered in isolation from its
1406 * surrounding paragraph so don't increment if this is the
1407 * first line of the footnote
1408 * AND, bibliographies can't have their depth changed ie. they
1409 * are always of depth 0
1412 && par->Previous()->GetDepth() < par->GetDepth()
1413 && textclasslist.Style(parameters->textclass,
1414 par->Previous()->GetLayout()
1415 ).labeltype == LABEL_COUNTER_ENUMI
1416 && par->enumdepth < 3
1417 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1418 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1419 && par->footnotekind == LyXParagraph::FOOTNOTE)
1420 && layout.labeltype != LABEL_BIBLIO) {
1424 /* Maybe we have to decrement the enumeration depth, see note above */
1426 && par->Previous()->GetDepth() > par->GetDepth()
1427 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1428 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1429 && par->footnotekind == LyXParagraph::FOOTNOTE)
1430 && layout.labeltype != LABEL_BIBLIO) {
1431 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1432 par->setCounter(6 + par->enumdepth,
1433 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1434 /* reset the counters.
1435 * A depth change is like a breaking layout
1437 for (i = 6 + par->enumdepth + 1; i<10;i++)
1438 par->setCounter(i, 0);
1441 if (!par->labelstring.empty()) {
1442 par->labelstring.clear();
1445 if (layout.margintype == MARGIN_MANUAL) {
1446 if (par->labelwidthstring.empty()) {
1447 par->SetLabelWidthString(layout.labelstring());
1451 par->SetLabelWidthString(string());
1454 /* is it a layout that has an automatic label ? */
1455 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1457 i = layout.labeltype - LABEL_FIRST_COUNTER;
1458 if (i >= 0 && i<= parameters->secnumdepth) {
1459 par->incCounter(i); // increment the counter
1461 char * s = new char[50];
1463 // Is there a label? Useful for Chapter layout
1464 if (!par->appendix){
1465 if (!layout.labelstring().empty())
1466 par->labelstring = layout.labelstring();
1468 par->labelstring.clear();
1471 if (!layout.labelstring_appendix().empty())
1472 par->labelstring = layout.labelstring_appendix();
1474 par->labelstring.clear();
1477 if (!par->appendix){
1478 switch (2 * LABEL_FIRST_COUNTER -
1479 textclass.maxcounter() + i) {
1480 case LABEL_COUNTER_CHAPTER:
1482 par->getCounter(i));
1484 case LABEL_COUNTER_SECTION:
1486 par->getCounter(i - 1),
1487 par->getCounter(i));
1489 case LABEL_COUNTER_SUBSECTION:
1490 sprintf(s, "%d.%d.%d",
1491 par->getCounter(i-2),
1492 par->getCounter(i-1),
1493 par->getCounter(i));
1495 case LABEL_COUNTER_SUBSUBSECTION:
1496 sprintf(s, "%d.%d.%d.%d",
1497 par->getCounter(i-3),
1498 par->getCounter(i-2),
1499 par->getCounter(i-1),
1500 par->getCounter(i));
1502 case LABEL_COUNTER_PARAGRAPH:
1503 sprintf(s, "%d.%d.%d.%d.%d",
1504 par->getCounter(i-4),
1505 par->getCounter(i-3),
1506 par->getCounter(i-2),
1507 par->getCounter(i-1),
1508 par->getCounter(i));
1510 case LABEL_COUNTER_SUBPARAGRAPH:
1511 sprintf(s, "%d.%d.%d.%d.%d.%d",
1512 par->getCounter(i-5),
1513 par->getCounter(i-4),
1514 par->getCounter(i-3),
1515 par->getCounter(i-2),
1516 par->getCounter(i-1),
1517 par->getCounter(i));
1520 sprintf(s, "%d.", par->getCounter(i));
1525 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1526 case LABEL_COUNTER_CHAPTER:
1528 alphaCounter(par->getCounter(i)));
1530 case LABEL_COUNTER_SECTION:
1532 alphaCounter(par->getCounter(i - 1)),
1533 par->getCounter(i));
1535 case LABEL_COUNTER_SUBSECTION:
1536 sprintf(s, "%s.%d.%d",
1537 alphaCounter(par->getCounter(i-2)),
1538 par->getCounter(i-1),
1539 par->getCounter(i));
1541 case LABEL_COUNTER_SUBSUBSECTION:
1542 sprintf(s, "%s.%d.%d.%d",
1543 alphaCounter(par->getCounter(i-3)),
1544 par->getCounter(i-2),
1545 par->getCounter(i-1),
1546 par->getCounter(i));
1548 case LABEL_COUNTER_PARAGRAPH:
1549 sprintf(s, "%s.%d.%d.%d.%d",
1550 alphaCounter(par->getCounter(i-4)),
1551 par->getCounter(i-3),
1552 par->getCounter(i-2),
1553 par->getCounter(i-1),
1554 par->getCounter(i));
1556 case LABEL_COUNTER_SUBPARAGRAPH:
1557 sprintf(s, "%s.%d.%d.%d.%d.%d",
1558 alphaCounter(par->getCounter(i-5)),
1559 par->getCounter(i-4),
1560 par->getCounter(i-3),
1561 par->getCounter(i-2),
1562 par->getCounter(i-1),
1563 par->getCounter(i));
1566 sprintf(s, "%c.", par->getCounter(i));
1571 par->labelstring += s;
1574 for (i++; i<10; i++) {
1575 /* reset the following counters */
1576 par->setCounter(i, 0);
1578 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1579 for (i++; i<10; i++) {
1580 /* reset the following counters */
1581 par->setCounter(i, 0);
1583 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1584 par->incCounter(i + par->enumdepth);
1585 char * s = new char[25];
1586 int number = par->getCounter(i + par->enumdepth);
1587 switch (par->enumdepth) {
1589 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1593 case 1: sprintf(s, "i."); break;
1594 case 2: sprintf(s, "ii."); break;
1595 case 3: sprintf(s, "iii."); break;
1596 case 4: sprintf(s, "iv."); break;
1597 case 5: sprintf(s, "v."); break;
1598 case 6: sprintf(s, "vi."); break;
1599 case 7: sprintf(s, "vii."); break;
1600 case 8: sprintf(s, "viii."); break;
1601 case 9: sprintf(s, "ix."); break;
1602 case 10: sprintf(s, "x."); break;
1603 case 11: sprintf(s, "xi."); break;
1604 case 12: sprintf(s, "xii."); break;
1605 case 13: sprintf(s, "xiii."); break;
1607 sprintf(s, "\\roman{%d}.", number);
1612 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1615 sprintf(s, "%d.", number);
1618 par->labelstring = s;
1621 for (i += par->enumdepth + 1;i<10;i++)
1622 par->setCounter(i, 0); /* reset the following counters */
1625 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1626 i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1628 int number = par->getCounter(i);
1630 par->bibkey = new InsetBibKey();
1631 par->bibkey->setCounter(number);
1632 par->labelstring = layout.labelstring();
1634 // In biblio should't be following counters but...
1637 string s = layout.labelstring();
1639 /* the caption hack: */
1641 if (layout.labeltype == LABEL_SENSITIVE) {
1642 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1643 && (par->footnotekind == LyXParagraph::FIG
1644 || par->footnotekind == LyXParagraph::WIDE_FIG))
1646 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1647 && (par->footnotekind == LyXParagraph::TAB
1648 || par->footnotekind == LyXParagraph::WIDE_TAB))
1650 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1651 && par->footnotekind == LyXParagraph::ALGORITHM)
1654 /* par->SetLayout(0);
1655 s = layout->labelstring; */
1660 par->labelstring = s;
1662 /* reset the enumeration counter. They are always resetted
1663 * when there is any other layout between */
1664 for (i = 6 + par->enumdepth; i<10;i++)
1665 par->setCounter(i, 0);
1670 /* Updates all counters BEHIND the row. Changed paragraphs
1671 * with a dynamic left margin will be rebroken. */
1672 void LyXText::UpdateCounters(Row * row)
1680 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1681 par = row->par->LastPhysicalPar()->Next();
1683 par = row->par->next;
1688 while (row->par != par)
1693 /* now check for the headline layouts. remember that they
1694 * have a dynamic left margin */
1696 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1697 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1700 /* Rebreak the paragraph */
1701 RemoveParagraph(row);
1702 AppendParagraph(row);
1704 /* think about the damned open footnotes! */
1705 while (par->Next() &&
1706 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1707 || par->Next()->IsDummy())){
1709 if (par->IsDummy()) {
1710 while (row->par != par)
1712 RemoveParagraph(row);
1713 AppendParagraph(row);
1718 par = par->LastPhysicalPar()->Next();
1724 /* insets an inset. */
1725 void LyXText::InsertInset(Inset *inset)
1727 SetUndo(Undo::INSERT,
1728 cursor.par->ParFromPos(cursor.pos)->previous,
1729 cursor.par->ParFromPos(cursor.pos)->next);
1730 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1731 cursor.par->InsertInset(cursor.pos, inset);
1732 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1733 * The character will not be inserted a
1738 /* this is for the simple cut and paste mechanism */
1739 static LyXParagraph * simple_cut_buffer = 0;
1740 static char simple_cut_buffer_textclass = 0;
1742 void DeleteSimpleCutBuffer()
1744 if (!simple_cut_buffer)
1746 LyXParagraph *tmppar;
1748 while (simple_cut_buffer) {
1749 tmppar = simple_cut_buffer;
1750 simple_cut_buffer = simple_cut_buffer->next;
1753 simple_cut_buffer = 0;
1757 void LyXText::copyEnvironmentType()
1759 copylayouttype = cursor.par->GetLayout();
1763 void LyXText::pasteEnvironmentType()
1765 SetLayout(copylayouttype);
1769 void LyXText::CutSelection(bool doclear)
1771 /* This doesn't make sense, if there is no selection */
1776 /* OK, we have a selection. This is always between sel_start_cursor
1777 * and sel_end cursor */
1778 LyXParagraph * tmppar;
1780 /* Check whether there are half footnotes in the selection */
1781 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1782 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1783 tmppar = sel_start_cursor.par;
1784 while (tmppar != sel_end_cursor.par){
1785 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1786 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1789 tmppar = tmppar->Next();
1793 /* table stuff -- begin*/
1794 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1795 if ( sel_start_cursor.par != sel_end_cursor.par){
1796 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1799 sel_start_cursor.par->table->Reinit();
1801 /* table stuff -- end*/
1803 // make sure that the depth behind the selection are restored, too
1804 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1805 LyXParagraph * undoendpar = endpar;
1807 if (endpar && endpar->GetDepth()) {
1808 while (endpar && endpar->GetDepth()) {
1809 endpar = endpar->LastPhysicalPar()->Next();
1810 undoendpar = endpar;
1814 endpar = endpar->Next(); /* because of parindents etc. */
1817 SetUndo(Undo::DELETE,
1818 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1821 /* delete the simple_cut_buffer */
1822 DeleteSimpleCutBuffer();
1824 /* set the textclass */
1825 simple_cut_buffer_textclass = parameters->textclass;
1827 #ifdef WITH_WARNINGS
1828 #warning Asger: Make cut more intelligent here.
1831 White paper for "intelligent" cutting:
1833 Example: "This is our text."
1834 Using " our " as selection, cutting will give "This istext.".
1835 Using "our" as selection, cutting will give "This is text.".
1836 Using " our" as selection, cutting will give "This is text.".
1837 Using "our " as selection, cutting will give "This is text.".
1839 All those four selections will (however) paste identically:
1840 Pasting with the cursor right after the "is" will give the
1841 original text with all four selections.
1843 The rationale is to be intelligent such that words are copied,
1844 cut and pasted in a functional manner.
1846 This is not implemented yet.
1849 bool space_wrapped =
1850 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1851 if (sel_end_cursor.pos > 0
1852 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1853 sel_end_cursor.pos--; /* please break before a space at
1855 space_wrapped = true;
1858 // cut behind a space if there is one
1859 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1860 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1861 && (sel_start_cursor.par != sel_end_cursor.par
1862 || sel_start_cursor.pos < sel_end_cursor.pos))
1863 sel_start_cursor.pos++;
1865 /* there are two cases: cut only within one paragraph or
1866 * more than one paragraph */
1868 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1869 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1870 /* only within one paragraph */
1871 simple_cut_buffer = new LyXParagraph;
1872 LyXParagraph::size_type i =
1873 sel_start_cursor.pos;
1874 for (; i< sel_end_cursor.pos; i++){
1875 /* table stuff -- begin*/
1876 if (sel_start_cursor.par->table
1877 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1878 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1879 sel_start_cursor.pos++;
1881 /* table stuff -- end*/
1882 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1883 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1885 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1887 /* check for double spaces */
1888 if (sel_start_cursor.pos &&
1889 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1890 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1891 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1892 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1895 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1896 endpar = sel_end_cursor.par->Next();
1899 /* cut more than one paragraph */
1901 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1902 /* insert a space at the end if there was one */
1904 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1906 sel_end_cursor.par = sel_end_cursor.par->Next();
1907 sel_end_cursor.pos = 0;
1909 cursor = sel_end_cursor;
1911 /* please break behind a space, if there is one. The space should
1913 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1914 sel_start_cursor.pos++;
1916 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1917 if (!sel_start_cursor.pos
1918 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1919 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1920 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1923 /* store the endparagraph for redoing later */
1924 endpar = sel_end_cursor.par->Next(); /* needed because
1929 /*store the selection */
1930 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1931 simple_cut_buffer->previous = 0;
1932 sel_end_cursor.par->previous->next = 0;
1934 /* cut the selection */
1935 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1936 = sel_end_cursor.par;
1938 sel_end_cursor.par->previous
1939 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1941 /* care about footnotes */
1942 if (simple_cut_buffer->footnoteflag) {
1943 LyXParagraph *tmppar = simple_cut_buffer;
1945 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1946 tmppar = tmppar->next;
1950 /* the cut selection should begin with standard layout */
1951 simple_cut_buffer->Clear();
1953 /* paste the paragraphs again, if possible */
1955 sel_start_cursor.par->Next()->ClearParagraph();
1956 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1958 !sel_start_cursor.par->Next()->Last())
1959 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1962 /* maybe a forgotten blank */
1963 if (sel_start_cursor.pos
1964 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1965 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1966 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1971 /* sometimes necessary */
1973 sel_start_cursor.par->ClearParagraph();
1975 RedoParagraphs(sel_start_cursor, endpar);
1978 cursor = sel_start_cursor;
1979 SetCursor(cursor.par, cursor.pos);
1980 sel_cursor = cursor;
1981 UpdateCounters(cursor.row);
1985 void LyXText::CopySelection()
1987 LyXParagraph::size_type i = 0;
1988 /* this doesnt make sense, if there is no selection */
1993 /* ok we have a selection. This is always between sel_start_cursor
1994 * and sel_end cursor */
1995 LyXParagraph * tmppar;
1997 /* check wether there are half footnotes in the selection */
1998 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1999 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2000 tmppar = sel_start_cursor.par;
2001 while (tmppar != sel_end_cursor.par){
2002 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2003 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2006 tmppar = tmppar->Next();
2010 /* table stuff -- begin*/
2011 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2012 if ( sel_start_cursor.par != sel_end_cursor.par){
2013 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2017 /* table stuff -- end*/
2019 /* delete the simple_cut_buffer */
2020 DeleteSimpleCutBuffer();
2022 /* set the textclass */
2023 simple_cut_buffer_textclass = parameters->textclass;
2025 // copy behind a space if there is one
2026 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2027 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2028 && (sel_start_cursor.par != sel_end_cursor.par
2029 || sel_start_cursor.pos < sel_end_cursor.pos))
2030 sel_start_cursor.pos++;
2032 /* there are two cases: copy only within one paragraph or more than one paragraph */
2033 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2034 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2035 /* only within one paragraph */
2036 simple_cut_buffer = new LyXParagraph;
2037 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2038 sel_start_cursor.par->CopyIntoMinibuffer(i);
2039 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2043 /* copy more than one paragraph */
2044 /* clone the paragraphs within the selection*/
2045 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2046 simple_cut_buffer = tmppar->Clone();
2047 LyXParagraph *tmppar2 = simple_cut_buffer;
2049 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2051 tmppar = tmppar->next;
2052 tmppar2->next = tmppar->Clone();
2053 tmppar2->next->previous = tmppar2;
2054 tmppar2 = tmppar2->next;
2058 /* care about footnotes */
2059 if (simple_cut_buffer->footnoteflag) {
2060 tmppar = simple_cut_buffer;
2062 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2063 tmppar = tmppar->next;
2067 /* the simple_cut_buffer paragraph is too big */
2068 LyXParagraph::size_type tmpi2 =
2069 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2070 for (;tmpi2;tmpi2--)
2071 simple_cut_buffer->Erase(0);
2073 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2075 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2076 while (tmppar2->size() > tmpi2) {
2077 tmppar2->Erase(tmppar2->text.size() - 1);
2083 void LyXText::PasteSelection()
2085 /* this does not make sense, if there is nothing to paste */
2086 if (!simple_cut_buffer)
2089 LyXParagraph * tmppar;
2090 LyXParagraph * endpar;
2092 LyXCursor tmpcursor;
2094 /* be carefull with footnotes in footnotes */
2095 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2097 /* check whether the cut_buffer includes a footnote */
2098 tmppar = simple_cut_buffer;
2099 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2100 tmppar = tmppar->next;
2103 WriteAlert(_("Impossible operation"),
2104 _("Can't paste float into float!"), _("Sorry."));
2109 /* table stuff -- begin*/
2110 if (cursor.par->table){
2111 if (simple_cut_buffer->next){
2112 WriteAlert(_("Impossible operation"),
2113 _("Table cell cannot include more than one paragraph!"),
2118 /* table stuff -- end*/
2120 SetUndo(Undo::INSERT,
2121 cursor.par->ParFromPos(cursor.pos)->previous,
2122 cursor.par->ParFromPos(cursor.pos)->next);
2126 /* There are two cases: cutbuffer only one paragraph or many */
2127 if (!simple_cut_buffer->next) {
2128 /* only within a paragraph */
2130 /* please break behind a space, if there is one */
2131 while (tmpcursor.par->Last() > tmpcursor.pos
2132 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2135 tmppar = simple_cut_buffer->Clone();
2136 /* table stuff -- begin*/
2137 bool table_too_small = false;
2138 if (tmpcursor.par->table) {
2139 while (simple_cut_buffer->text.size()
2140 && !table_too_small) {
2141 if (simple_cut_buffer->IsNewline(0)){
2142 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2144 simple_cut_buffer->Erase(0);
2145 if (tmpcursor.pos < tmpcursor.par->Last())
2148 table_too_small = true;
2150 simple_cut_buffer->CutIntoMinibuffer(0);
2151 simple_cut_buffer->Erase(0);
2152 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2157 /* table stuff -- end*/
2158 while (simple_cut_buffer->text.size()){
2159 simple_cut_buffer->CutIntoMinibuffer(0);
2160 simple_cut_buffer->Erase(0);
2161 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2166 delete simple_cut_buffer;
2167 simple_cut_buffer = tmppar;
2168 endpar = tmpcursor.par->Next();
2170 /* many paragraphs */
2172 /* make a copy of the simple cut_buffer */
2173 tmppar = simple_cut_buffer;
2174 LyXParagraph * simple_cut_clone = tmppar->Clone();
2175 LyXParagraph * tmppar2 = simple_cut_clone;
2176 if (cursor.par->footnoteflag){
2177 tmppar->footnoteflag = cursor.par->footnoteflag;
2178 tmppar->footnotekind = cursor.par->footnotekind;
2180 while (tmppar->next) {
2181 tmppar = tmppar->next;
2182 tmppar2->next = tmppar->Clone();
2183 tmppar2->next->previous = tmppar2;
2184 tmppar2 = tmppar2->next;
2185 if (cursor.par->footnoteflag){
2186 tmppar->footnoteflag = cursor.par->footnoteflag;
2187 tmppar->footnotekind = cursor.par->footnotekind;
2191 /* make sure there is no class difference */
2192 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2193 parameters->textclass,
2196 /* make the simple_cut_buffer exactly the same layout than
2197 the cursor paragraph */
2198 simple_cut_buffer->MakeSameLayout(cursor.par);
2200 /* find the end of the buffer */
2201 LyXParagraph *lastbuffer = simple_cut_buffer;
2202 while (lastbuffer->Next())
2203 lastbuffer = lastbuffer->Next();
2205 /* find the physical end of the buffer */
2206 lastbuffer = simple_cut_buffer;
2207 while (lastbuffer->Next())
2208 lastbuffer = lastbuffer->Next();
2210 /* please break behind a space, if there is one. The space
2211 * should be copied too */
2212 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2215 bool paste_the_end = false;
2217 /* open the paragraph for inserting the simple_cut_buffer
2219 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2220 cursor.par->BreakParagraphConservative(cursor.pos);
2221 paste_the_end = true;
2224 /* be careful with double spaces */
2225 if ((!cursor.par->Last()
2226 || cursor.par->IsLineSeparator(cursor.pos - 1)
2227 || cursor.par->IsNewline(cursor.pos - 1))
2228 && simple_cut_buffer->text.size()
2229 && simple_cut_buffer->IsLineSeparator(0))
2230 simple_cut_buffer->Erase(0);
2232 /* set the end for redoing later */
2233 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2236 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2237 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2239 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2240 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2242 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2243 lastbuffer = cursor.par;
2245 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2247 /* store the new cursor position */
2248 tmpcursor.par = lastbuffer;
2249 tmpcursor.pos = lastbuffer->Last();
2251 /* maybe some pasting */
2252 if (lastbuffer->Next() && paste_the_end) {
2253 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2255 /* be careful witth double spaces */
2256 if ((!lastbuffer->Last()
2257 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2258 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2259 && lastbuffer->Next()->Last()
2260 && lastbuffer->Next()->IsLineSeparator(0))
2261 lastbuffer->Next()->Erase(0);
2263 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2266 else if (!lastbuffer->Next()->Last()) {
2267 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2269 /* be careful witth double spaces */
2270 if ((!lastbuffer->Last()
2271 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2272 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2273 && lastbuffer->Next()->Last()
2274 && lastbuffer->Next()->IsLineSeparator(0))
2275 lastbuffer->Next()->Erase(0);
2277 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2280 else if (!lastbuffer->Last()) {
2281 lastbuffer->MakeSameLayout(lastbuffer->next);
2283 /* be careful witth double spaces */
2284 if ((!lastbuffer->Last()
2285 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2286 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2287 && lastbuffer->Next()->Last()
2288 && lastbuffer->Next()->IsLineSeparator(0))
2289 lastbuffer->Next()->Erase(0);
2291 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2294 else lastbuffer->Next()->ClearParagraph();
2297 /* restore the simple cut buffer */
2298 simple_cut_buffer = simple_cut_clone;
2301 RedoParagraphs(cursor, endpar);
2303 SetCursor(cursor.par, cursor.pos);
2306 sel_cursor = cursor;
2307 SetCursor(tmpcursor.par, tmpcursor.pos);
2309 UpdateCounters(cursor.row);
2313 /* returns a pointer to the very first LyXParagraph */
2314 LyXParagraph * LyXText::FirstParagraph()
2316 return params->paragraph;
2320 /* returns true if the specified string is at the specified position */
2321 bool LyXText::IsStringInText(LyXParagraph * par,
2322 LyXParagraph::size_type pos,
2327 while (pos + i < par->Last() && str[i] &&
2328 str[i] == par->GetChar(pos + i)) {
2338 /* sets the selection over the number of characters of string, no check!! */
2339 void LyXText::SetSelectionOverString(char const * string)
2341 sel_cursor = cursor;
2342 for (int i = 0; string[i]; ++i)
2348 /* simple replacing. The font of the first selected character is used */
2349 void LyXText::ReplaceSelectionWithString(char const * str)
2354 if (!selection) { /* create a dummy selection */
2355 sel_end_cursor = cursor;
2356 sel_start_cursor = cursor;
2359 // Get font setting before we cut
2360 LyXParagraph::size_type pos = sel_end_cursor.pos;
2361 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2363 // Insert the new string
2364 for (int i = 0; str[i]; ++i) {
2365 sel_end_cursor.par->InsertChar(pos, str[i]);
2366 sel_end_cursor.par->SetFont(pos, font);
2370 // Cut the selection
2377 /* if the string can be found: return true and set the cursor to
2378 * the new position */
2379 bool LyXText::SearchForward(char const * str)
2381 LyXParagraph * par = cursor.par;
2382 LyXParagraph::size_type pos = cursor.pos;
2383 while (par && !IsStringInText(par, pos, str)) {
2384 if (pos < par->Last() - 1)
2392 SetCursor(par, pos);
2400 bool LyXText::SearchBackward(char const * string)
2402 LyXParagraph * par = cursor.par;
2403 int pos = cursor.pos;
2409 // We skip empty paragraphs (Asger)
2411 par = par->Previous();
2413 pos = par->Last()-1;
2414 } while (par && pos<0);
2416 } while (par && !IsStringInText(par, pos, string));
2419 SetCursor(par, pos);
2427 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2429 char * str = new char[text.size() + 1];
2430 copy(text.begin(), text.end(), str);
2431 str[text.size()] = '\0';
2437 /* needed to insert the selection */
2438 void LyXText::InsertStringA(char const * s)
2441 LyXParagraph * par = cursor.par;
2442 LyXParagraph::size_type pos = cursor.pos;
2443 LyXParagraph::size_type a = 0;
2445 LyXParagraph * endpar = cursor.par->Next();
2449 char flag = textclasslist.Style(parameters->textclass,
2450 cursor.par->GetLayout()).isEnvironment();
2451 /* only to be sure, should not be neccessary */
2454 /* insert the string, don't insert doublespace */
2455 string::size_type i = 0;
2456 while (i < str.length()) {
2457 if (str[i] != '\n') {
2459 && i+1<str.length() && str[i+1]!= ' '
2460 && pos && par->GetChar(pos-1)!= ' ') {
2461 par->InsertChar(pos,' ');
2464 else if (par->table) {
2465 if (str[i] == '\t') {
2466 while((pos < par->size()) &&
2467 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2469 if (pos < par->size())
2471 else // no more fields to fill skip the rest
2473 } else if ((str[i] != 13) &&
2474 ((str[i] & 127) >= ' ')) {
2475 par->InsertChar(pos, str[i]);
2479 else if (str[i] == ' ') {
2480 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2483 else if (str[i] == '\t') {
2484 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2485 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2489 else if (str[i]!= 13 &&
2490 // Ignore unprintables
2491 (str[i] & 127) >= ' ') {
2492 par->InsertChar(pos, str[i]);
2497 if (i+1>=str.length()) {
2501 while((pos < par->size()) &&
2502 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2505 cell = NumberOfCell(par, pos);
2506 while((pos < par->size()) &&
2507 !(par->table->IsFirstCell(cell))) {
2508 while((pos < par->size()) &&
2509 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2512 cell = NumberOfCell(par, pos);
2514 if (pos >= par->size())
2515 // no more fields to fill skip the rest
2518 if (!par->text.size()) {
2519 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2522 par->BreakParagraph(pos, flag);
2531 RedoParagraphs(cursor, endpar);
2532 SetCursor(cursor.par, cursor.pos);
2533 sel_cursor = cursor;
2534 SetCursor(par, pos);
2539 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2541 char * str = new char[text.size() + 1];
2542 copy(text.begin(), text.end(), str);
2543 str[text.size()] = '\0';
2549 /* turns double-CR to single CR, others where converted into one blank and 13s
2550 * that are ignored .Double spaces are also converted into one. Spaces at
2551 * the beginning of a paragraph are forbidden. tabs are converted into one
2552 * space. then InsertStringA is called */
2553 void LyXText::InsertStringB(char const * s)
2556 LyXParagraph * par = cursor.par;
2557 string::size_type i = 1;
2558 while (i < str.length()) {
2559 if (str[i] == '\t' && !par->table)
2561 if (str[i] == ' ' && i+1 < str.length() && str[i + 1] == ' ')
2563 if (str[i] == '\n' && i+1 < str.length() && !par->table){
2564 if (str[i + 1] != '\n') {
2565 if (str[i - 1] != ' ')
2570 while (i+1 < str.length()
2571 && (str[i + 1] == ' '
2572 || str[i + 1] == '\t'
2573 || str[i + 1] == '\n'
2574 || str[i + 1] == 13)) {
2581 InsertStringA(str.c_str());
2585 bool LyXText::GotoNextError()
2587 LyXCursor res = cursor;
2589 if (res.pos < res.par->Last() - 1) {
2593 res.par = res.par->Next();
2598 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2599 && res.par->GetInset(res.pos)->AutoDelete()));
2602 SetCursor(res.par, res.pos);
2610 bool LyXText::GotoNextNote()
2612 LyXCursor res = cursor;
2614 if (res.pos < res.par->Last()-1) {
2618 res.par = res.par->Next();
2623 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2624 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2627 SetCursor(res.par, res.pos);
2635 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2639 if (!par || class1 == class2)
2641 par = par->FirstPhysicalPar();
2643 string name = textclasslist.NameOfLayout(class1, par->layout);
2645 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2646 textclasslist.NumberOfLayout(class2, name);
2649 } else { // layout not found
2650 // use default layout "Standard" (0)
2655 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2657 string s = "Layout had to be changed from\n"
2658 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2659 + "\nbecause of class conversion from\n"
2660 + textclasslist.NameOfClass(class1) + " to "
2661 + textclasslist.NameOfClass(class2);
2662 InsetError * new_inset = new InsetError(s);
2663 par->InsertChar(0, LyXParagraph::META_INSET);
2664 par->InsertInset(0, new_inset);
2673 void LyXText::CheckParagraph(LyXParagraph * par,
2674 LyXParagraph::size_type pos)
2677 LyXCursor tmpcursor;
2679 /* table stuff -- begin*/
2682 CheckParagraphInTable(par, pos);
2685 /* table stuff -- end*/
2688 LyXParagraph::size_type z;
2689 Row * row = GetRow(par, pos, y);
2691 /* is there a break one row above */
2692 if (row->previous && row->previous->par == row->par) {
2693 z = NextBreakPoint(row->previous, paperwidth);
2694 if ( z >= row->pos) {
2695 /* set the dimensions of the row above */
2696 y -= row->previous->height;
2698 refresh_row = row->previous;
2699 status = LyXText::NEED_MORE_REFRESH;
2701 BreakAgain(row->previous);
2703 /* set the cursor again. Otherwise dungling pointers are possible */
2704 SetCursor(cursor.par, cursor.pos);
2705 sel_cursor = cursor;
2710 int tmpheight = row->height;
2711 LyXParagraph::size_type tmplast = RowLast(row);
2716 if (row->height == tmpheight && RowLast(row) == tmplast)
2717 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2719 status = LyXText::NEED_MORE_REFRESH;
2721 /* check the special right address boxes */
2722 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2723 tmpcursor.par = par;
2724 tmpcursor.row = row;
2727 tmpcursor.x_fix = 0;
2728 tmpcursor.pos = pos;
2729 RedoDrawingOfParagraph(tmpcursor);
2734 /* set the cursor again. Otherwise dangling pointers are possible */
2735 // also set the selection
2739 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2740 sel_cursor = cursor;
2741 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2742 sel_start_cursor = cursor;
2743 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2744 sel_end_cursor = cursor;
2745 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2746 last_sel_cursor = cursor;
2749 SetCursorIntern(cursor.par, cursor.pos);
2753 /* returns 0 if inset wasn't found */
2754 int LyXText::UpdateInset(Inset * inset)
2756 /* first check the current paragraph */
2757 int pos = cursor.par->GetPositionOfInset(inset);
2759 CheckParagraph(cursor.par, pos);
2763 /* check every paragraph */
2765 LyXParagraph * par = FirstParagraph();
2767 /* make sure the paragraph is open */
2768 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2769 pos = par->GetPositionOfInset(inset);
2771 CheckParagraph(par, pos);
2782 void LyXText::SetCursor(LyXParagraph * par,
2783 LyXParagraph::size_type pos)
2785 LyXCursor old_cursor = cursor;
2786 SetCursorIntern(par, pos);
2787 DeleteEmptyParagraphMechanism(old_cursor);
2791 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2796 LyXParagraph * tmppar;
2798 /* correct the cursor position if impossible */
2799 if (pos > par->Last()){
2800 tmppar = par->ParFromPos(pos);
2801 pos = par->PositionInParFromPos(pos);
2804 if (par->IsDummy() && par->previous &&
2805 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2806 while (par->previous &&
2807 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2808 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2809 par = par->previous ;
2810 if (par->IsDummy() &&
2811 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2812 pos += par->text.size() + 1;
2814 if (par->previous) {
2815 par = par->previous;
2817 pos += par->text.size() + 1;
2823 /* get the cursor y position in text */
2824 row = GetRow(par, pos, y);
2825 /* y is now the beginning of the cursor row */
2827 /* y is now the cursor baseline */
2830 /* now get the cursors x position */
2833 float fill_separator, fill_hfill, fill_label_hfill;
2834 left_margin = LabelEnd(row);
2835 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2836 LyXParagraph::size_type main_body =
2837 BeginningOfMainBody(row->par);
2838 /* table stuff -- begin*/
2839 if (row->par->table) {
2840 int cell = NumberOfCell(row->par, row->pos);
2842 x += row->par->table->GetBeginningOfTextInCell(cell);
2843 for (pos = row->pos; pos < cursor.pos; pos++) {
2844 if (row->par->IsNewline(pos)) {
2845 x = x_old + row->par->table->WidthOfColumn(cell);
2848 x += row->par->table->GetBeginningOfTextInCell(cell);
2850 x += SingleWidth(row->par, pos);
2854 /* table stuff -- end*/
2856 for (pos = row->pos; pos < cursor.pos; pos++) {
2857 if (pos && pos == main_body
2858 && !row->par->IsLineSeparator(pos - 1)) {
2859 x += GetFont(row->par, -2).stringWidth(
2860 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2861 if (x < left_margin)
2865 x += SingleWidth(row->par, pos);
2866 if (HfillExpansion(row, pos)) {
2867 if (pos >= main_body)
2870 x += fill_label_hfill;
2872 else if (pos >= main_body && row->par->IsSeparator(pos)) {
2876 if (pos + 1 == main_body
2877 && row->par->IsLineSeparator(pos)) {
2878 x += GetFont(row->par, -2).stringWidth(
2879 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2880 if (row->par->IsLineSeparator(pos))
2881 x -= SingleWidth(row->par, pos);
2882 if (x < left_margin)
2889 cursor.x_fix = cursor.x;
2893 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2894 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2895 && !cursor.par->IsSeparator(cursor.pos))
2897 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2898 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2900 current_font = cursor.par->GetFontSettings(cursor.pos);
2901 real_current_font = GetFont(cursor.par, cursor.pos);
2906 void LyXText::SetCursorFromCoordinates(int x, long y)
2908 LyXCursor old_cursor = cursor;
2910 /* get the row first */
2912 Row * row = GetRowNearY(y);
2914 cursor.par = row->par;
2916 int column = GetColumnNearX(row, x);
2917 cursor.pos = row->pos + column;
2919 cursor.y = y + row->baseline;
2924 (cursor.pos == cursor.par->Last()
2925 || cursor.par->IsSeparator(cursor.pos)
2926 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2927 && !cursor.par->IsSeparator(cursor.pos))
2929 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2930 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2932 current_font = cursor.par->GetFontSettings(cursor.pos);
2933 real_current_font = GetFont(cursor.par, cursor.pos);
2935 DeleteEmptyParagraphMechanism(old_cursor);
2939 void LyXText::CursorLeft()
2942 if (cursor.par->table) {
2943 int cell = NumberOfCell(cursor.par, cursor.pos);
2944 if (cursor.par->table->IsContRow(cell) &&
2945 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2952 void LyXText::CursorLeftIntern()
2954 if (cursor.pos > 0) {
2955 SetCursor(cursor.par, cursor.pos - 1);
2957 else if (cursor.par->Previous()) {
2958 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2963 void LyXText::CursorRight()
2965 CursorRightIntern();
2966 if (cursor.par->table) {
2967 int cell = NumberOfCell(cursor.par, cursor.pos);
2968 if (cursor.par->table->IsContRow(cell) &&
2969 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2976 void LyXText::CursorRightIntern()
2978 if (cursor.pos < cursor.par->Last()) {
2979 SetCursor(cursor.par, cursor.pos + 1);
2981 else if (cursor.par->Next()) {
2982 SetCursor(cursor.par->Next(), 0);
2987 void LyXText::CursorUp()
2989 SetCursorFromCoordinates(cursor.x_fix,
2990 cursor.y - cursor.row->baseline - 1);
2991 if (cursor.par->table) {
2992 int cell = NumberOfCell(cursor.par, cursor.pos);
2993 if (cursor.par->table->IsContRow(cell) &&
2994 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3001 void LyXText::CursorDown()
3003 if (cursor.par->table &&
3004 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3007 SetCursorFromCoordinates(cursor.x_fix,
3008 cursor.y - cursor.row->baseline
3009 + cursor.row->height + 1);
3010 if (cursor.par->table) {
3011 int cell = NumberOfCell(cursor.par, cursor.pos);
3012 int cell_above = cursor.par->table->GetCellAbove(cell);
3013 while(cursor.par->table &&
3014 cursor.par->table->IsContRow(cell) &&
3015 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3016 SetCursorFromCoordinates(cursor.x_fix,
3017 cursor.y - cursor.row->baseline
3018 + cursor.row->height + 1);
3019 if (cursor.par->table) {
3020 cell = NumberOfCell(cursor.par, cursor.pos);
3021 cell_above = cursor.par->table->GetCellAbove(cell);
3028 void LyXText::CursorUpParagraph()
3030 if (cursor.pos > 0) {
3031 SetCursor(cursor.par, 0);
3033 else if (cursor.par->Previous()) {
3034 SetCursor(cursor.par->Previous(), 0);
3039 void LyXText::CursorDownParagraph()
3041 if (cursor.par->Next()) {
3042 SetCursor(cursor.par->Next(), 0);
3044 SetCursor(cursor.par, cursor.par->Last());
3050 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3052 bool deleted = false;
3054 /* this is the delete-empty-paragraph-mechanism. */
3058 // Paragraph should not be deleted if empty
3059 if ((textclasslist.Style(parameters->textclass,
3060 old_cursor.par->GetLayout())).keepempty)
3063 LyXCursor tmpcursor;
3065 if (old_cursor.par != cursor.par) {
3066 if ( (old_cursor.par->Last() == 0
3067 || (old_cursor.par->Last() == 1
3068 && (old_cursor.par->IsLineSeparator(0))))
3069 && old_cursor.par->FirstPhysicalPar()
3070 == old_cursor.par->LastPhysicalPar()) {
3072 /* ok, we will delete anything */
3074 // make sure that you do not delete any environments
3075 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3076 !(old_cursor.row->previous
3077 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3078 && !(old_cursor.row->next
3079 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3081 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3082 ((old_cursor.row->previous
3083 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3085 (old_cursor.row->next
3086 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3088 status = LyXText::NEED_MORE_REFRESH;
3091 if (old_cursor.row->previous) {
3092 refresh_row = old_cursor.row->previous;
3093 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3095 cursor = old_cursor; // that undo can restore the right cursor position
3096 LyXParagraph *endpar = old_cursor.par->next;
3097 if (endpar && endpar->GetDepth()) {
3098 while (endpar && endpar->GetDepth()) {
3099 endpar = endpar->LastPhysicalPar()->Next();
3102 SetUndo(Undo::DELETE,
3103 old_cursor.par->previous,
3107 /* delete old row */
3108 RemoveRow(old_cursor.row);
3109 if (params->paragraph == old_cursor.par) {
3110 params->paragraph = params->paragraph->next;
3112 /* delete old par */
3113 delete old_cursor.par;
3115 /* Breakagain the next par. Needed
3116 * because of the parindent that
3117 * can occur or dissappear. The
3118 * next row can change its height,
3119 * if there is another layout before */
3120 if (refresh_row->next) {
3121 BreakAgain(refresh_row->next);
3122 UpdateCounters(refresh_row);
3124 SetHeightOfRow(refresh_row);
3127 refresh_row = old_cursor.row->next;
3128 refresh_y = old_cursor.y - old_cursor.row->baseline;
3131 cursor = old_cursor; // that undo can restore the right cursor position
3132 LyXParagraph *endpar = old_cursor.par->next;
3133 if (endpar && endpar->GetDepth()) {
3134 while (endpar && endpar->GetDepth()) {
3135 endpar = endpar->LastPhysicalPar()->Next();
3138 SetUndo(Undo::DELETE,
3139 old_cursor.par->previous,
3143 /* delete old row */
3144 RemoveRow(old_cursor.row);
3145 /* delete old par */
3146 if (params->paragraph == old_cursor.par) {
3147 params->paragraph = params->paragraph->next;
3149 delete old_cursor.par;
3151 /* Breakagain the next par. Needed because of
3152 * the parindent that can occur or dissappear.
3153 * The next row can change its height, if there
3154 * is another layout before */
3156 BreakAgain(refresh_row);
3157 UpdateCounters(refresh_row->previous);
3161 /* correct cursor y */
3162 SetCursor(cursor.par, cursor.pos);
3164 /* if (cursor.y > old_cursor.y)
3165 cursor.y -= old_cursor.row->height; */
3167 if (sel_cursor.par == old_cursor.par
3168 && sel_cursor.pos == sel_cursor.pos) {
3169 /* correct selection*/
3170 sel_cursor = cursor;
3176 if (old_cursor.par->ClearParagraph()){
3177 RedoParagraphs(old_cursor, old_cursor.par->Next());
3178 /* correct cursor y */
3179 SetCursor(cursor.par, cursor.pos);
3180 sel_cursor = cursor;
3183 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3184 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3185 if (old_cursor.par->table->IsContRow(cell) &&
3186 IsEmptyTableRow(&old_cursor)) {
3187 RemoveTableRow(&old_cursor);
3194 LyXParagraph * LyXText::GetParFromID(int id)
3196 LyXParagraph * result = FirstParagraph();
3197 while (result && result->id() != id)
3198 result = result->next;
3204 bool LyXText::TextUndo()
3205 { // returns false if no undo possible
3206 Undo * undo = params->undostack.pop();
3210 params->redostack.push(CreateUndo(undo->kind,
3211 GetParFromID(undo->number_of_before_par),
3212 GetParFromID(undo->number_of_behind_par)));
3214 return TextHandleUndo(undo);
3218 bool LyXText::TextRedo()
3219 { // returns false if no redo possible
3220 Undo * undo = params->redostack.pop();
3224 params->undostack.push(CreateUndo(undo->kind,
3225 GetParFromID(undo->number_of_before_par),
3226 GetParFromID(undo->number_of_behind_par)));
3228 return TextHandleUndo(undo);
3232 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3233 bool result = false;
3235 LyXParagraph * before = GetParFromID(undo->number_of_before_par);
3236 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par);
3237 LyXParagraph * tmppar;
3238 LyXParagraph * tmppar2;
3239 LyXParagraph * tmppar3;
3240 LyXParagraph * tmppar4;
3241 LyXParagraph * endpar;
3242 LyXParagraph * tmppar5;
3244 // if there's no before take the beginning of the document for redoing
3246 SetCursorIntern(FirstParagraph(), 0);
3248 // replace the paragraphs with the undo informations
3250 tmppar3 = undo->par;
3251 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3254 while (tmppar4->next)
3255 tmppar4 = tmppar4->next;
3256 } // get last undo par
3258 // now remove the old text if there is any
3259 if (before != behind || (!behind && !before)){
3261 tmppar5 = before->next;
3263 tmppar5 = params->paragraph;
3265 while (tmppar5 && tmppar5 != behind){
3267 tmppar5 = tmppar5->next;
3268 // a memory optimization for edit: Only layout information
3269 // is stored in the undo. So restore the text informations.
3270 if (undo->kind == Undo::EDIT){
3271 tmppar2->text = tmppar->text;
3272 tmppar->text.clear();
3273 //tmppar->text.erase(tmppar->text.begin(),
3274 // tmppar->text.end());
3275 tmppar2 = tmppar2->next;
3277 if ( currentrow && currentrow->par == tmppar )
3278 currentrow = currentrow -> previous;
3283 // put the new stuff in the list if there is one
3286 before->next = tmppar3;
3288 params->paragraph = tmppar3;
3289 tmppar3->previous = before;
3293 params->paragraph = behind;
3296 tmppar4->next = behind;
3298 behind->previous = tmppar4;
3302 // Set the cursor for redoing
3304 SetCursorIntern(before->FirstSelfrowPar(), 0);
3305 // check wether before points to a closed float and open it if necessary
3306 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3307 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3309 while (tmppar4->previous &&
3310 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3311 tmppar4 = tmppar4->previous;
3312 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3313 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3314 tmppar4 = tmppar4->next;
3319 // open a cosed footnote at the end if necessary
3320 if (behind && behind->previous &&
3321 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3322 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3323 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3324 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3325 behind = behind->next;
3329 // calculate the endpar for redoing the paragraphs.
3331 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3332 endpar = behind->LastPhysicalPar()->Next();
3334 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3339 tmppar = GetParFromID(undo->number_of_cursor_par);
3340 RedoParagraphs(cursor, endpar);
3342 SetCursorIntern(tmppar, undo->cursor_pos);
3343 UpdateCounters(cursor.row);
3353 void LyXText::FinishUndo()
3354 { // makes sure the next operation will be stored
3355 undo_finished = True;
3359 void LyXText::FreezeUndo()
3360 { // this is dangerous and for internal use only
3365 void LyXText::UnFreezeUndo()
3366 { // this is dangerous and for internal use only
3367 undo_frozen = false;
3371 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3372 LyXParagraph * behind)
3375 params->undostack.push(CreateUndo(kind, before, behind));
3376 params->redostack.clear();
3380 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3381 LyXParagraph * behind)
3383 params->redostack.push(CreateUndo(kind, before, behind));
3387 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3388 LyXParagraph * behind)
3390 int before_number = -1;
3391 int behind_number = -1;
3393 before_number = before->id();
3395 behind_number = behind->id();
3396 // Undo::EDIT and Undo::FINISH are
3397 // always finished. (no overlapping there)
3398 // overlapping only with insert and delete inside one paragraph:
3399 // Nobody wants all removed character
3400 // appear one by one when undoing.
3401 // EDIT is special since only layout information, not the
3402 // contents of a paragaph are stored.
3403 if (!undo_finished && kind != Undo::EDIT &&
3404 kind != Undo::FINISH){
3405 // check wether storing is needed
3406 if (!params->undostack.empty() &&
3407 params->undostack.top()->kind == kind &&
3408 params->undostack.top()->number_of_before_par == before_number &&
3409 params->undostack.top()->number_of_behind_par == behind_number ){
3414 // create a new Undo
3415 LyXParagraph * undopar;
3416 LyXParagraph * tmppar;
3417 LyXParagraph * tmppar2;
3419 LyXParagraph * start = 0;
3420 LyXParagraph * end = 0;
3423 start = before->next;
3425 start = FirstParagraph();
3427 end = behind->previous;
3429 end = FirstParagraph();
3434 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3436 tmppar2 = tmppar->Clone();
3437 tmppar2->id(tmppar->id());
3439 // a memory optimization: Just store the layout information when only edit
3440 if (kind == Undo::EDIT){
3441 tmppar2->text.clear();
3442 //tmppar2->text.erase(tmppar2->text.begin(),
3443 // tmppar2->text.end());
3448 while (tmppar != end && tmppar->next) {
3449 tmppar = tmppar->next;
3450 tmppar2->next = tmppar->Clone();
3451 tmppar2->next->id(tmppar->id());
3452 // a memory optimization: Just store the layout information when only edit
3453 if (kind == Undo::EDIT){
3454 tmppar2->next->text.clear();
3455 //tmppar2->next->text.erase(tmppar2->next->text.begin(), tmppar2->next->text.end());
3457 tmppar2->next->previous = tmppar2;
3458 tmppar2 = tmppar2->next;
3463 undopar = 0; // nothing to replace (undo of delete maybe)
3465 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3466 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3468 Undo * undo = new Undo(kind,
3469 before_number, behind_number,
3470 cursor_par, cursor_pos,
3473 undo_finished = false;
3478 void LyXText::SetCursorParUndo()
3480 SetUndo(Undo::FINISH,
3481 cursor.par->ParFromPos(cursor.pos)->previous,
3482 cursor.par->ParFromPos(cursor.pos)->next);
3485 void LyXText::RemoveTableRow(LyXCursor * cursor)
3493 /* move to the previous row */
3494 cell_act = NumberOfCell(cursor->par, cursor->pos);
3497 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3499 while (cursor->pos &&
3500 !cursor->par->table->IsFirstCell(cell_act)){
3502 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3507 /* now we have to pay attention if the actual table is the
3508 main row of TableContRows and if yes to delete all of them */
3513 /* delete up to the next row */
3514 while (cursor->pos < cursor->par->Last() &&
3516 || !cursor->par->table->IsFirstCell(cell_act))){
3517 while (cursor->pos < cursor->par->Last() &&
3518 !cursor->par->IsNewline(cursor->pos))
3519 cursor->par->Erase(cursor->pos);
3522 if (cursor->pos < cursor->par->Last())
3523 cursor->par-> Erase(cursor->pos);
3525 if (cursor->pos && cursor->pos == cursor->par->Last()){
3527 cursor->par->Erase(cursor->pos); // no newline at the very end!
3529 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3530 !cursor->par->table->IsContRow(cell_org) &&
3531 cursor->par->table->IsContRow(cell));
3532 cursor->par->table->DeleteRow(cell_org);
3537 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor) const
3539 if (!old_cursor->par->table)
3541 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3542 int pos = old_cursor->pos;
3543 int 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() const
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);