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 cur)
749 Row * tmprow = cur.row;
750 long y = cur.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(cur.par, cur.pos);
775 void LyXText::RedoDrawingOfParagraph(LyXCursor cur)
777 Row * tmprow = cur.row;
779 long y = cur.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(cur.par, cur.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 cur, LyXParagraph * endpar)
810 LyXParagraph * tmppar, * first_phys_par;
812 Row * tmprow = cur.row;
814 long y = cur.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);
1063 /* Implicit selections are cleared afterwards and cursor is set to the
1064 original position. */
1065 if (implicitSelection) {
1067 cursor = resetCursor;
1068 SetCursor( cursor.par, cursor.pos );
1069 sel_cursor = cursor;
1074 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1076 if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1079 return par->BeginningOfMainBody();
1083 /* if there is a selection, reset every environment you can find
1084 * in the selection, otherwise just the environment you are in */
1085 void LyXText::MeltFootnoteEnvironment()
1087 LyXParagraph * tmppar, * firsttmppar;
1091 /* is is only allowed, if the cursor is IN an open footnote.
1092 * Otherwise it is too dangerous */
1093 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1096 SetUndo(Undo::FINISH,
1097 cursor.par->PreviousBeforeFootnote()->previous,
1098 cursor.par->NextAfterFootnote()->next);
1100 /* ok, move to the beginning of the footnote. */
1101 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1102 cursor.par = cursor.par->Previous();
1104 SetCursor(cursor.par, cursor.par->Last());
1105 /* this is just faster than using CursorLeft(); */
1107 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1108 tmppar = firsttmppar;
1109 /* tmppar is now the paragraph right before the footnote */
1111 char first_footnote_par_is_not_empty = tmppar->next->text.size();
1113 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1114 tmppar = tmppar->next; /* I use next instead of Next(),
1115 * because there cannot be any
1116 * footnotes in a footnote
1118 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1120 /* remember the captions and empty paragraphs */
1121 if ((textclasslist.Style(parameters->textclass,
1122 tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1124 tmppar->SetLayout(0);
1127 /* now we will paste the ex-footnote, if the layouts allow it */
1128 /* first restore the layout of the paragraph right behind the footnote*/
1130 tmppar->next->MakeSameLayout(cursor.par);
1133 if ((!tmppar->GetLayout() && !tmppar->table)
1134 || (tmppar->Next() && (!tmppar->Next()->Last()
1135 || tmppar->Next()->HasSameLayout(tmppar)))) {
1136 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1137 tmppar->Next()->Erase(0);
1138 tmppar->PasteParagraph();
1141 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1142 * by the pasting of the beginning */
1144 /* then the beginning */
1145 /* if there is no space between the text and the footnote, so we insert
1147 * (only if the previous par and the footnotepar are not empty!) */
1148 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1149 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1150 if (firsttmppar->text.size()
1151 && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1152 && first_footnote_par_is_not_empty) {
1153 firsttmppar->next->InsertChar(0, ' ');
1155 firsttmppar->PasteParagraph();
1158 /* now redo the paragaphs */
1159 RedoParagraphs(cursor, tmppar);
1161 SetCursor(cursor.par, cursor.pos);
1163 /* sometimes it can happen, that there is a counter change */
1164 Row * row = cursor.row;
1165 while (row->next && row->par != tmppar && row->next->par != tmppar)
1167 UpdateCounters(row);
1174 /* the DTP switches for paragraphs. LyX will store them in the
1175 * first physicla paragraph. When a paragraph is broken, the top settings
1176 * rest, the bottom settings are given to the new one. So I can make shure,
1177 * they do not duplicate themself and you cannnot make dirty things with
1180 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1181 bool pagebreak_top, bool pagebreak_bottom,
1182 VSpace space_top, VSpace space_bottom,
1184 string labelwidthstring,
1187 LyXCursor tmpcursor = cursor;
1189 sel_start_cursor = cursor;
1190 sel_end_cursor = cursor;
1193 // make sure that the depth behind the selection are restored, too
1194 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1195 LyXParagraph * undoendpar = endpar;
1197 if (endpar && endpar->GetDepth()) {
1198 while (endpar && endpar->GetDepth()) {
1199 endpar = endpar->LastPhysicalPar()->Next();
1200 undoendpar = endpar;
1204 endpar = endpar->Next(); /* because of parindents etc. */
1208 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1212 LyXParagraph * tmppar = sel_end_cursor.par;
1213 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1214 SetCursor(tmppar->FirstPhysicalPar(), 0);
1215 status = LyXText::NEED_MORE_REFRESH;
1216 refresh_row = cursor.row;
1217 refresh_y = cursor.y - cursor.row->baseline;
1218 if (cursor.par->footnoteflag ==
1219 sel_start_cursor.par->footnoteflag) {
1220 cursor.par->line_top = line_top;
1221 cursor.par->line_bottom = line_bottom;
1222 cursor.par->pagebreak_top = pagebreak_top;
1223 cursor.par->pagebreak_bottom = pagebreak_bottom;
1224 cursor.par->added_space_top = space_top;
1225 cursor.par->added_space_bottom = space_bottom;
1226 /* does the layout allow the new alignment? */
1227 if (align == LYX_ALIGN_LAYOUT)
1228 align = textclasslist
1229 .Style(parameters->textclass,
1230 cursor.par->GetLayout()).align;
1231 if (align & textclasslist
1232 .Style(parameters->textclass,
1233 cursor.par->GetLayout()).alignpossible) {
1234 if (align == textclasslist
1235 .Style(parameters->textclass,
1236 cursor.par->GetLayout()).align)
1237 cursor.par->align = LYX_ALIGN_LAYOUT;
1239 cursor.par->align = align;
1241 cursor.par->SetLabelWidthString(labelwidthstring);
1242 cursor.par->noindent = noindent;
1245 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1248 RedoParagraphs(sel_start_cursor, endpar);
1251 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1252 sel_cursor = cursor;
1253 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1255 SetCursor(tmpcursor.par, tmpcursor.pos);
1259 void LyXText::SetParagraphExtraOpt(int type,
1261 char const * widthp,
1262 int alignment, bool hfill,
1263 bool start_minipage)
1265 LyXCursor tmpcursor = cursor;
1266 LyXParagraph * tmppar;
1268 sel_start_cursor = cursor;
1269 sel_end_cursor = cursor;
1272 // make sure that the depth behind the selection are restored, too
1273 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1274 LyXParagraph * undoendpar = endpar;
1276 if (endpar && endpar->GetDepth()) {
1277 while (endpar && endpar->GetDepth()) {
1278 endpar = endpar->LastPhysicalPar()->Next();
1279 undoendpar = endpar;
1283 endpar = endpar->Next(); /* because of parindents etc. */
1287 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1290 tmppar = sel_end_cursor.par;
1291 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1292 SetCursor(tmppar->FirstPhysicalPar(), 0);
1293 status = LyXText::NEED_MORE_REFRESH;
1294 refresh_row = cursor.row;
1295 refresh_y = cursor.y - cursor.row->baseline;
1296 if (cursor.par->footnoteflag ==
1297 sel_start_cursor.par->footnoteflag) {
1298 if (type == LyXParagraph::PEXTRA_NONE) {
1299 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1300 cursor.par->UnsetPExtraType();
1301 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1304 cursor.par->SetPExtraType(type, width, widthp);
1305 cursor.par->pextra_hfill = hfill;
1306 cursor.par->pextra_start_minipage = start_minipage;
1307 cursor.par->pextra_alignment = alignment;
1310 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1312 RedoParagraphs(sel_start_cursor, endpar);
1314 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1315 sel_cursor = cursor;
1316 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1318 SetCursor(tmpcursor.par, tmpcursor.pos);
1322 static char const * alphaCounter(int n){
1323 static char result[2];
1336 /* set the counter of a paragraph. This includes the labels */
1337 void LyXText::SetCounter(LyXParagraph * par)
1341 /* this is only relevant for the beginning of paragraph */
1342 par = par->FirstPhysicalPar();
1344 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1347 LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1349 /* copy the prev-counters to this one, unless this is the start of a
1350 footnote or of a bibliography or the very first paragraph */
1352 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1353 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1354 && par->footnotekind == LyXParagraph::FOOTNOTE)
1355 && !(textclasslist.Style(parameters->textclass,
1356 par->Previous()->GetLayout()
1357 ).labeltype != LABEL_BIBLIO
1358 && layout.labeltype == LABEL_BIBLIO)) {
1359 for (i = 0; i<10; i++) {
1360 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1362 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1363 if (!par->appendix && par->start_of_appendix){
1364 par->appendix = true;
1365 for (i = 0; i<10; i++) {
1366 par->setCounter(i, 0);
1369 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1370 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1373 for (i = 0; i<10; i++) {
1374 par->setCounter(i, 0);
1376 par->appendix = par->start_of_appendix;
1381 // if this is an open marginnote and this is the first
1382 // entry in the marginnote and the enclosing
1383 // environment is an enum/item then correct for the
1384 // LaTeX behaviour (ARRae)
1385 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1386 && par->footnotekind == LyXParagraph::MARGIN
1388 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1389 && (par->PreviousBeforeFootnote()
1390 && textclasslist.Style(parameters->textclass,
1391 par->PreviousBeforeFootnote()->GetLayout()
1392 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1393 // Any itemize or enumerate environment in a marginnote
1394 // that is embedded in an itemize or enumerate
1395 // paragraph is seen by LaTeX as being at a deeper
1396 // level within that enclosing itemization/enumeration
1397 // even if there is a "standard" layout at the start of
1403 /* Maybe we have to increment the enumeration depth.
1404 * BUT, enumeration in a footnote is considered in isolation from its
1405 * surrounding paragraph so don't increment if this is the
1406 * first line of the footnote
1407 * AND, bibliographies can't have their depth changed ie. they
1408 * are always of depth 0
1411 && par->Previous()->GetDepth() < par->GetDepth()
1412 && textclasslist.Style(parameters->textclass,
1413 par->Previous()->GetLayout()
1414 ).labeltype == LABEL_COUNTER_ENUMI
1415 && par->enumdepth < 3
1416 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1417 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1418 && par->footnotekind == LyXParagraph::FOOTNOTE)
1419 && layout.labeltype != LABEL_BIBLIO) {
1423 /* Maybe we have to decrement the enumeration depth, see note above */
1425 && par->Previous()->GetDepth() > par->GetDepth()
1426 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1427 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1428 && par->footnotekind == LyXParagraph::FOOTNOTE)
1429 && layout.labeltype != LABEL_BIBLIO) {
1430 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1431 par->setCounter(6 + par->enumdepth,
1432 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1433 /* reset the counters.
1434 * A depth change is like a breaking layout
1436 for (i = 6 + par->enumdepth + 1; i<10;i++)
1437 par->setCounter(i, 0);
1440 if (!par->labelstring.empty()) {
1441 par->labelstring.clear();
1444 if (layout.margintype == MARGIN_MANUAL) {
1445 if (par->labelwidthstring.empty()) {
1446 par->SetLabelWidthString(layout.labelstring());
1450 par->SetLabelWidthString(string());
1453 /* is it a layout that has an automatic label ? */
1454 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1456 i = layout.labeltype - LABEL_FIRST_COUNTER;
1457 if (i >= 0 && i<= parameters->secnumdepth) {
1458 par->incCounter(i); // increment the counter
1460 char * s = new char[50];
1462 // Is there a label? Useful for Chapter layout
1463 if (!par->appendix){
1464 if (!layout.labelstring().empty())
1465 par->labelstring = layout.labelstring();
1467 par->labelstring.clear();
1470 if (!layout.labelstring_appendix().empty())
1471 par->labelstring = layout.labelstring_appendix();
1473 par->labelstring.clear();
1476 if (!par->appendix){
1477 switch (2 * LABEL_FIRST_COUNTER -
1478 textclass.maxcounter() + i) {
1479 case LABEL_COUNTER_CHAPTER:
1481 par->getCounter(i));
1483 case LABEL_COUNTER_SECTION:
1485 par->getCounter(i - 1),
1486 par->getCounter(i));
1488 case LABEL_COUNTER_SUBSECTION:
1489 sprintf(s, "%d.%d.%d",
1490 par->getCounter(i-2),
1491 par->getCounter(i-1),
1492 par->getCounter(i));
1494 case LABEL_COUNTER_SUBSUBSECTION:
1495 sprintf(s, "%d.%d.%d.%d",
1496 par->getCounter(i-3),
1497 par->getCounter(i-2),
1498 par->getCounter(i-1),
1499 par->getCounter(i));
1501 case LABEL_COUNTER_PARAGRAPH:
1502 sprintf(s, "%d.%d.%d.%d.%d",
1503 par->getCounter(i-4),
1504 par->getCounter(i-3),
1505 par->getCounter(i-2),
1506 par->getCounter(i-1),
1507 par->getCounter(i));
1509 case LABEL_COUNTER_SUBPARAGRAPH:
1510 sprintf(s, "%d.%d.%d.%d.%d.%d",
1511 par->getCounter(i-5),
1512 par->getCounter(i-4),
1513 par->getCounter(i-3),
1514 par->getCounter(i-2),
1515 par->getCounter(i-1),
1516 par->getCounter(i));
1519 sprintf(s, "%d.", par->getCounter(i));
1524 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1525 case LABEL_COUNTER_CHAPTER:
1527 alphaCounter(par->getCounter(i)));
1529 case LABEL_COUNTER_SECTION:
1531 alphaCounter(par->getCounter(i - 1)),
1532 par->getCounter(i));
1534 case LABEL_COUNTER_SUBSECTION:
1535 sprintf(s, "%s.%d.%d",
1536 alphaCounter(par->getCounter(i-2)),
1537 par->getCounter(i-1),
1538 par->getCounter(i));
1540 case LABEL_COUNTER_SUBSUBSECTION:
1541 sprintf(s, "%s.%d.%d.%d",
1542 alphaCounter(par->getCounter(i-3)),
1543 par->getCounter(i-2),
1544 par->getCounter(i-1),
1545 par->getCounter(i));
1547 case LABEL_COUNTER_PARAGRAPH:
1548 sprintf(s, "%s.%d.%d.%d.%d",
1549 alphaCounter(par->getCounter(i-4)),
1550 par->getCounter(i-3),
1551 par->getCounter(i-2),
1552 par->getCounter(i-1),
1553 par->getCounter(i));
1555 case LABEL_COUNTER_SUBPARAGRAPH:
1556 sprintf(s, "%s.%d.%d.%d.%d.%d",
1557 alphaCounter(par->getCounter(i-5)),
1558 par->getCounter(i-4),
1559 par->getCounter(i-3),
1560 par->getCounter(i-2),
1561 par->getCounter(i-1),
1562 par->getCounter(i));
1565 sprintf(s, "%c.", par->getCounter(i));
1570 par->labelstring += s;
1573 for (i++; i<10; i++) {
1574 /* reset the following counters */
1575 par->setCounter(i, 0);
1577 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1578 for (i++; i<10; i++) {
1579 /* reset the following counters */
1580 par->setCounter(i, 0);
1582 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1583 par->incCounter(i + par->enumdepth);
1584 char * s = new char[25];
1585 int number = par->getCounter(i + par->enumdepth);
1586 switch (par->enumdepth) {
1588 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1592 case 1: sprintf(s, "i."); break;
1593 case 2: sprintf(s, "ii."); break;
1594 case 3: sprintf(s, "iii."); break;
1595 case 4: sprintf(s, "iv."); break;
1596 case 5: sprintf(s, "v."); break;
1597 case 6: sprintf(s, "vi."); break;
1598 case 7: sprintf(s, "vii."); break;
1599 case 8: sprintf(s, "viii."); break;
1600 case 9: sprintf(s, "ix."); break;
1601 case 10: sprintf(s, "x."); break;
1602 case 11: sprintf(s, "xi."); break;
1603 case 12: sprintf(s, "xii."); break;
1604 case 13: sprintf(s, "xiii."); break;
1606 sprintf(s, "\\roman{%d}.", number);
1611 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1614 sprintf(s, "%d.", number);
1617 par->labelstring = s;
1620 for (i += par->enumdepth + 1;i<10;i++)
1621 par->setCounter(i, 0); /* reset the following counters */
1624 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1625 i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1627 int number = par->getCounter(i);
1629 par->bibkey = new InsetBibKey();
1630 par->bibkey->setCounter(number);
1631 par->labelstring = layout.labelstring();
1633 // In biblio should't be following counters but...
1636 string s = layout.labelstring();
1638 /* the caption hack: */
1640 if (layout.labeltype == LABEL_SENSITIVE) {
1641 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1642 && (par->footnotekind == LyXParagraph::FIG
1643 || par->footnotekind == LyXParagraph::WIDE_FIG))
1645 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1646 && (par->footnotekind == LyXParagraph::TAB
1647 || par->footnotekind == LyXParagraph::WIDE_TAB))
1649 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1650 && par->footnotekind == LyXParagraph::ALGORITHM)
1653 /* par->SetLayout(0);
1654 s = layout->labelstring; */
1659 par->labelstring = s;
1661 /* reset the enumeration counter. They are always resetted
1662 * when there is any other layout between */
1663 for (i = 6 + par->enumdepth; i<10;i++)
1664 par->setCounter(i, 0);
1669 /* Updates all counters BEHIND the row. Changed paragraphs
1670 * with a dynamic left margin will be rebroken. */
1671 void LyXText::UpdateCounters(Row * row)
1679 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1680 par = row->par->LastPhysicalPar()->Next();
1682 par = row->par->next;
1687 while (row->par != par)
1692 /* now check for the headline layouts. remember that they
1693 * have a dynamic left margin */
1695 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1696 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1699 /* Rebreak the paragraph */
1700 RemoveParagraph(row);
1701 AppendParagraph(row);
1703 /* think about the damned open footnotes! */
1704 while (par->Next() &&
1705 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1706 || par->Next()->IsDummy())){
1708 if (par->IsDummy()) {
1709 while (row->par != par)
1711 RemoveParagraph(row);
1712 AppendParagraph(row);
1717 par = par->LastPhysicalPar()->Next();
1723 /* insets an inset. */
1724 void LyXText::InsertInset(Inset *inset)
1726 SetUndo(Undo::INSERT,
1727 cursor.par->ParFromPos(cursor.pos)->previous,
1728 cursor.par->ParFromPos(cursor.pos)->next);
1729 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1730 cursor.par->InsertInset(cursor.pos, inset);
1731 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1732 * The character will not be inserted a
1737 /* this is for the simple cut and paste mechanism */
1738 static LyXParagraph * simple_cut_buffer = 0;
1739 static char simple_cut_buffer_textclass = 0;
1741 void DeleteSimpleCutBuffer()
1743 if (!simple_cut_buffer)
1745 LyXParagraph *tmppar;
1747 while (simple_cut_buffer) {
1748 tmppar = simple_cut_buffer;
1749 simple_cut_buffer = simple_cut_buffer->next;
1752 simple_cut_buffer = 0;
1756 void LyXText::copyEnvironmentType()
1758 copylayouttype = cursor.par->GetLayout();
1762 void LyXText::pasteEnvironmentType()
1764 SetLayout(copylayouttype);
1768 void LyXText::CutSelection(bool doclear)
1770 /* This doesn't make sense, if there is no selection */
1775 /* OK, we have a selection. This is always between sel_start_cursor
1776 * and sel_end cursor */
1777 LyXParagraph * tmppar;
1779 /* Check whether there are half footnotes in the selection */
1780 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1781 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1782 tmppar = sel_start_cursor.par;
1783 while (tmppar != sel_end_cursor.par){
1784 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1785 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1788 tmppar = tmppar->Next();
1792 /* table stuff -- begin*/
1793 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1794 if ( sel_start_cursor.par != sel_end_cursor.par){
1795 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1798 sel_start_cursor.par->table->Reinit();
1800 /* table stuff -- end*/
1802 // make sure that the depth behind the selection are restored, too
1803 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1804 LyXParagraph * undoendpar = endpar;
1806 if (endpar && endpar->GetDepth()) {
1807 while (endpar && endpar->GetDepth()) {
1808 endpar = endpar->LastPhysicalPar()->Next();
1809 undoendpar = endpar;
1813 endpar = endpar->Next(); /* because of parindents etc. */
1816 SetUndo(Undo::DELETE,
1817 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1820 /* delete the simple_cut_buffer */
1821 DeleteSimpleCutBuffer();
1823 /* set the textclass */
1824 simple_cut_buffer_textclass = parameters->textclass;
1826 #ifdef WITH_WARNINGS
1827 #warning Asger: Make cut more intelligent here.
1830 White paper for "intelligent" cutting:
1832 Example: "This is our text."
1833 Using " our " as selection, cutting will give "This istext.".
1834 Using "our" as selection, cutting will give "This is text.".
1835 Using " our" as selection, cutting will give "This is text.".
1836 Using "our " as selection, cutting will give "This is text.".
1838 All those four selections will (however) paste identically:
1839 Pasting with the cursor right after the "is" will give the
1840 original text with all four selections.
1842 The rationale is to be intelligent such that words are copied,
1843 cut and pasted in a functional manner.
1845 This is not implemented yet.
1848 bool space_wrapped =
1849 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1850 if (sel_end_cursor.pos > 0
1851 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1852 sel_end_cursor.pos--; /* please break before a space at
1854 space_wrapped = true;
1857 // cut behind a space if there is one
1858 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1859 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1860 && (sel_start_cursor.par != sel_end_cursor.par
1861 || sel_start_cursor.pos < sel_end_cursor.pos))
1862 sel_start_cursor.pos++;
1864 /* there are two cases: cut only within one paragraph or
1865 * more than one paragraph */
1867 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1868 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1869 /* only within one paragraph */
1870 simple_cut_buffer = new LyXParagraph;
1871 LyXParagraph::size_type i =
1872 sel_start_cursor.pos;
1873 for (; i< sel_end_cursor.pos; i++){
1874 /* table stuff -- begin*/
1875 if (sel_start_cursor.par->table
1876 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1877 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1878 sel_start_cursor.pos++;
1880 /* table stuff -- end*/
1881 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1882 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1884 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1886 /* check for double spaces */
1887 if (sel_start_cursor.pos &&
1888 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1889 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1890 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1891 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1894 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1895 endpar = sel_end_cursor.par->Next();
1898 /* cut more than one paragraph */
1900 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1901 /* insert a space at the end if there was one */
1903 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1905 sel_end_cursor.par = sel_end_cursor.par->Next();
1906 sel_end_cursor.pos = 0;
1908 cursor = sel_end_cursor;
1910 /* please break behind a space, if there is one. The space should
1912 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1913 sel_start_cursor.pos++;
1915 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1916 if (!sel_start_cursor.pos
1917 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1918 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1919 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1922 /* store the endparagraph for redoing later */
1923 endpar = sel_end_cursor.par->Next(); /* needed because
1928 /*store the selection */
1929 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1930 simple_cut_buffer->previous = 0;
1931 sel_end_cursor.par->previous->next = 0;
1933 /* cut the selection */
1934 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1935 = sel_end_cursor.par;
1937 sel_end_cursor.par->previous
1938 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1940 /* care about footnotes */
1941 if (simple_cut_buffer->footnoteflag) {
1942 LyXParagraph *tmppar = simple_cut_buffer;
1944 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1945 tmppar = tmppar->next;
1949 /* the cut selection should begin with standard layout */
1950 simple_cut_buffer->Clear();
1952 /* paste the paragraphs again, if possible */
1954 sel_start_cursor.par->Next()->ClearParagraph();
1955 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1957 !sel_start_cursor.par->Next()->Last())
1958 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1961 /* maybe a forgotten blank */
1962 if (sel_start_cursor.pos
1963 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1964 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1965 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1970 /* sometimes necessary */
1972 sel_start_cursor.par->ClearParagraph();
1974 RedoParagraphs(sel_start_cursor, endpar);
1977 cursor = sel_start_cursor;
1978 SetCursor(cursor.par, cursor.pos);
1979 sel_cursor = cursor;
1980 UpdateCounters(cursor.row);
1984 void LyXText::CopySelection()
1986 LyXParagraph::size_type i = 0;
1987 /* this doesnt make sense, if there is no selection */
1992 /* ok we have a selection. This is always between sel_start_cursor
1993 * and sel_end cursor */
1994 LyXParagraph * tmppar;
1996 /* check wether there are half footnotes in the selection */
1997 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1998 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1999 tmppar = sel_start_cursor.par;
2000 while (tmppar != sel_end_cursor.par){
2001 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2002 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2005 tmppar = tmppar->Next();
2009 /* table stuff -- begin*/
2010 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2011 if ( sel_start_cursor.par != sel_end_cursor.par){
2012 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2016 /* table stuff -- end*/
2018 /* delete the simple_cut_buffer */
2019 DeleteSimpleCutBuffer();
2021 /* set the textclass */
2022 simple_cut_buffer_textclass = parameters->textclass;
2024 // copy behind a space if there is one
2025 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2026 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2027 && (sel_start_cursor.par != sel_end_cursor.par
2028 || sel_start_cursor.pos < sel_end_cursor.pos))
2029 sel_start_cursor.pos++;
2031 /* there are two cases: copy only within one paragraph or more than one paragraph */
2032 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2033 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2034 /* only within one paragraph */
2035 simple_cut_buffer = new LyXParagraph;
2036 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2037 sel_start_cursor.par->CopyIntoMinibuffer(i);
2038 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2042 /* copy more than one paragraph */
2043 /* clone the paragraphs within the selection*/
2044 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2045 simple_cut_buffer = tmppar->Clone();
2046 LyXParagraph *tmppar2 = simple_cut_buffer;
2048 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2050 tmppar = tmppar->next;
2051 tmppar2->next = tmppar->Clone();
2052 tmppar2->next->previous = tmppar2;
2053 tmppar2 = tmppar2->next;
2057 /* care about footnotes */
2058 if (simple_cut_buffer->footnoteflag) {
2059 tmppar = simple_cut_buffer;
2061 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2062 tmppar = tmppar->next;
2066 /* the simple_cut_buffer paragraph is too big */
2067 LyXParagraph::size_type tmpi2 =
2068 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2069 for (;tmpi2;tmpi2--)
2070 simple_cut_buffer->Erase(0);
2072 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2074 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2075 while (tmppar2->size() > tmpi2) {
2076 tmppar2->Erase(tmppar2->text.size() - 1);
2082 void LyXText::PasteSelection()
2084 /* this does not make sense, if there is nothing to paste */
2085 if (!simple_cut_buffer)
2088 LyXParagraph * tmppar;
2089 LyXParagraph * endpar;
2091 LyXCursor tmpcursor;
2093 /* be carefull with footnotes in footnotes */
2094 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2096 /* check whether the cut_buffer includes a footnote */
2097 tmppar = simple_cut_buffer;
2098 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2099 tmppar = tmppar->next;
2102 WriteAlert(_("Impossible operation"),
2103 _("Can't paste float into float!"), _("Sorry."));
2108 /* table stuff -- begin*/
2109 if (cursor.par->table){
2110 if (simple_cut_buffer->next){
2111 WriteAlert(_("Impossible operation"),
2112 _("Table cell cannot include more than one paragraph!"),
2117 /* table stuff -- end*/
2119 SetUndo(Undo::INSERT,
2120 cursor.par->ParFromPos(cursor.pos)->previous,
2121 cursor.par->ParFromPos(cursor.pos)->next);
2125 /* There are two cases: cutbuffer only one paragraph or many */
2126 if (!simple_cut_buffer->next) {
2127 /* only within a paragraph */
2129 /* please break behind a space, if there is one */
2130 while (tmpcursor.par->Last() > tmpcursor.pos
2131 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2134 tmppar = simple_cut_buffer->Clone();
2135 /* table stuff -- begin*/
2136 bool table_too_small = false;
2137 if (tmpcursor.par->table) {
2138 while (simple_cut_buffer->text.size()
2139 && !table_too_small) {
2140 if (simple_cut_buffer->IsNewline(0)){
2141 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2143 simple_cut_buffer->Erase(0);
2144 if (tmpcursor.pos < tmpcursor.par->Last())
2147 table_too_small = true;
2149 simple_cut_buffer->CutIntoMinibuffer(0);
2150 simple_cut_buffer->Erase(0);
2151 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2156 /* table stuff -- end*/
2157 while (simple_cut_buffer->text.size()){
2158 simple_cut_buffer->CutIntoMinibuffer(0);
2159 simple_cut_buffer->Erase(0);
2160 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2165 delete simple_cut_buffer;
2166 simple_cut_buffer = tmppar;
2167 endpar = tmpcursor.par->Next();
2169 /* many paragraphs */
2171 /* make a copy of the simple cut_buffer */
2172 tmppar = simple_cut_buffer;
2173 LyXParagraph * simple_cut_clone = tmppar->Clone();
2174 LyXParagraph * tmppar2 = simple_cut_clone;
2175 if (cursor.par->footnoteflag){
2176 tmppar->footnoteflag = cursor.par->footnoteflag;
2177 tmppar->footnotekind = cursor.par->footnotekind;
2179 while (tmppar->next) {
2180 tmppar = tmppar->next;
2181 tmppar2->next = tmppar->Clone();
2182 tmppar2->next->previous = tmppar2;
2183 tmppar2 = tmppar2->next;
2184 if (cursor.par->footnoteflag){
2185 tmppar->footnoteflag = cursor.par->footnoteflag;
2186 tmppar->footnotekind = cursor.par->footnotekind;
2190 /* make sure there is no class difference */
2191 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2192 parameters->textclass,
2195 /* make the simple_cut_buffer exactly the same layout than
2196 the cursor paragraph */
2197 simple_cut_buffer->MakeSameLayout(cursor.par);
2199 /* find the end of the buffer */
2200 LyXParagraph *lastbuffer = simple_cut_buffer;
2201 while (lastbuffer->Next())
2202 lastbuffer = lastbuffer->Next();
2204 /* find the physical end of the buffer */
2205 lastbuffer = simple_cut_buffer;
2206 while (lastbuffer->Next())
2207 lastbuffer = lastbuffer->Next();
2209 /* please break behind a space, if there is one. The space
2210 * should be copied too */
2211 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2214 bool paste_the_end = false;
2216 /* open the paragraph for inserting the simple_cut_buffer
2218 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2219 cursor.par->BreakParagraphConservative(cursor.pos);
2220 paste_the_end = true;
2223 /* be careful with double spaces */
2224 if ((!cursor.par->Last()
2225 || cursor.par->IsLineSeparator(cursor.pos - 1)
2226 || cursor.par->IsNewline(cursor.pos - 1))
2227 && simple_cut_buffer->text.size()
2228 && simple_cut_buffer->IsLineSeparator(0))
2229 simple_cut_buffer->Erase(0);
2231 /* set the end for redoing later */
2232 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2235 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2236 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2238 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2239 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2241 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2242 lastbuffer = cursor.par;
2244 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2246 /* store the new cursor position */
2247 tmpcursor.par = lastbuffer;
2248 tmpcursor.pos = lastbuffer->Last();
2250 /* maybe some pasting */
2251 if (lastbuffer->Next() && paste_the_end) {
2252 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2254 /* be careful witth double spaces */
2255 if ((!lastbuffer->Last()
2256 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2257 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2258 && lastbuffer->Next()->Last()
2259 && lastbuffer->Next()->IsLineSeparator(0))
2260 lastbuffer->Next()->Erase(0);
2262 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2265 else if (!lastbuffer->Next()->Last()) {
2266 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2268 /* be careful witth double spaces */
2269 if ((!lastbuffer->Last()
2270 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2271 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2272 && lastbuffer->Next()->Last()
2273 && lastbuffer->Next()->IsLineSeparator(0))
2274 lastbuffer->Next()->Erase(0);
2276 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2279 else if (!lastbuffer->Last()) {
2280 lastbuffer->MakeSameLayout(lastbuffer->next);
2282 /* be careful witth double spaces */
2283 if ((!lastbuffer->Last()
2284 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2285 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2286 && lastbuffer->Next()->Last()
2287 && lastbuffer->Next()->IsLineSeparator(0))
2288 lastbuffer->Next()->Erase(0);
2290 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2293 else lastbuffer->Next()->ClearParagraph();
2296 /* restore the simple cut buffer */
2297 simple_cut_buffer = simple_cut_clone;
2300 RedoParagraphs(cursor, endpar);
2302 SetCursor(cursor.par, cursor.pos);
2305 sel_cursor = cursor;
2306 SetCursor(tmpcursor.par, tmpcursor.pos);
2308 UpdateCounters(cursor.row);
2312 /* returns a pointer to the very first LyXParagraph */
2313 LyXParagraph * LyXText::FirstParagraph()
2315 return params->paragraph;
2319 /* returns true if the specified string is at the specified position */
2320 bool LyXText::IsStringInText(LyXParagraph * par,
2321 LyXParagraph::size_type pos,
2326 while (pos + i < par->Last() && str[i] &&
2327 str[i] == par->GetChar(pos + i)) {
2337 /* sets the selection over the number of characters of string, no check!! */
2338 void LyXText::SetSelectionOverString(char const * string)
2340 sel_cursor = cursor;
2341 for (int i = 0; string[i]; ++i)
2347 /* simple replacing. The font of the first selected character is used */
2348 void LyXText::ReplaceSelectionWithString(char const * str)
2353 if (!selection) { /* create a dummy selection */
2354 sel_end_cursor = cursor;
2355 sel_start_cursor = cursor;
2358 // Get font setting before we cut
2359 LyXParagraph::size_type pos = sel_end_cursor.pos;
2360 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2362 // Insert the new string
2363 for (int i = 0; str[i]; ++i) {
2364 sel_end_cursor.par->InsertChar(pos, str[i]);
2365 sel_end_cursor.par->SetFont(pos, font);
2369 // Cut the selection
2376 /* if the string can be found: return true and set the cursor to
2377 * the new position */
2378 bool LyXText::SearchForward(char const * str)
2380 LyXParagraph * par = cursor.par;
2381 LyXParagraph::size_type pos = cursor.pos;
2382 while (par && !IsStringInText(par, pos, str)) {
2383 if (pos < par->Last() - 1)
2391 SetCursor(par, pos);
2399 bool LyXText::SearchBackward(char const * string)
2401 LyXParagraph * par = cursor.par;
2402 int pos = cursor.pos;
2408 // We skip empty paragraphs (Asger)
2410 par = par->Previous();
2412 pos = par->Last()-1;
2413 } while (par && pos<0);
2415 } while (par && !IsStringInText(par, pos, string));
2418 SetCursor(par, pos);
2426 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2428 char * str = new char[text.size() + 1];
2429 copy(text.begin(), text.end(), str);
2430 str[text.size()] = '\0';
2436 /* needed to insert the selection */
2437 void LyXText::InsertStringA(char const * s)
2440 LyXParagraph * par = cursor.par;
2441 LyXParagraph::size_type pos = cursor.pos;
2442 LyXParagraph::size_type a = 0;
2444 LyXParagraph * endpar = cursor.par->Next();
2448 char flag = textclasslist.Style(parameters->textclass,
2449 cursor.par->GetLayout()).isEnvironment();
2450 /* only to be sure, should not be neccessary */
2453 /* insert the string, don't insert doublespace */
2454 string::size_type i = 0;
2455 while (i < str.length()) {
2456 if (str[i] != '\n') {
2458 && i+1<str.length() && str[i+1]!= ' '
2459 && pos && par->GetChar(pos-1)!= ' ') {
2460 par->InsertChar(pos,' ');
2463 else if (par->table) {
2464 if (str[i] == '\t') {
2465 while((pos < par->size()) &&
2466 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2468 if (pos < par->size())
2470 else // no more fields to fill skip the rest
2472 } else if ((str[i] != 13) &&
2473 ((str[i] & 127) >= ' ')) {
2474 par->InsertChar(pos, str[i]);
2478 else if (str[i] == ' ') {
2479 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2482 else if (str[i] == '\t') {
2483 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2484 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2488 else if (str[i]!= 13 &&
2489 // Ignore unprintables
2490 (str[i] & 127) >= ' ') {
2491 par->InsertChar(pos, str[i]);
2496 if (i+1>=str.length()) {
2500 while((pos < par->size()) &&
2501 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2504 cell = NumberOfCell(par, pos);
2505 while((pos < par->size()) &&
2506 !(par->table->IsFirstCell(cell))) {
2507 while((pos < par->size()) &&
2508 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2511 cell = NumberOfCell(par, pos);
2513 if (pos >= par->size())
2514 // no more fields to fill skip the rest
2517 if (!par->text.size()) {
2518 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2521 par->BreakParagraph(pos, flag);
2530 RedoParagraphs(cursor, endpar);
2531 SetCursor(cursor.par, cursor.pos);
2532 sel_cursor = cursor;
2533 SetCursor(par, pos);
2538 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2540 char * str = new char[text.size() + 1];
2541 copy(text.begin(), text.end(), str);
2542 str[text.size()] = '\0';
2548 /* turns double-CR to single CR, others where converted into one blank and 13s
2549 * that are ignored .Double spaces are also converted into one. Spaces at
2550 * the beginning of a paragraph are forbidden. tabs are converted into one
2551 * space. then InsertStringA is called */
2552 void LyXText::InsertStringB(char const * s)
2555 LyXParagraph * par = cursor.par;
2556 string::size_type i = 1;
2557 while (i < str.length()) {
2558 if (str[i] == '\t' && !par->table)
2560 if (str[i] == ' ' && i+1 < str.length() && str[i + 1] == ' ')
2562 if (str[i] == '\n' && i+1 < str.length() && !par->table){
2563 if (str[i + 1] != '\n') {
2564 if (str[i - 1] != ' ')
2569 while (i+1 < str.length()
2570 && (str[i + 1] == ' '
2571 || str[i + 1] == '\t'
2572 || str[i + 1] == '\n'
2573 || str[i + 1] == 13)) {
2580 InsertStringA(str.c_str());
2584 bool LyXText::GotoNextError()
2586 LyXCursor res = cursor;
2588 if (res.pos < res.par->Last() - 1) {
2592 res.par = res.par->Next();
2597 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2598 && res.par->GetInset(res.pos)->AutoDelete()));
2601 SetCursor(res.par, res.pos);
2609 bool LyXText::GotoNextNote()
2611 LyXCursor res = cursor;
2613 if (res.pos < res.par->Last()-1) {
2617 res.par = res.par->Next();
2622 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2623 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2626 SetCursor(res.par, res.pos);
2634 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
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 InsetError * 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->id() != 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->id();
3394 behind_number = behind->id();
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.empty() &&
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->id(tmppar->id());
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->id(tmppar->id());
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)->id();
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 * cur)
3490 /* move to the previous row */
3491 int cell_act = NumberOfCell(cur->par, cur->pos);
3494 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3497 !cur->par->table->IsFirstCell(cell_act)) {
3499 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3504 /* now we have to pay attention if the actual table is the
3505 main row of TableContRows and if yes to delete all of them */
3510 /* delete up to the next row */
3511 while (cur->pos < cur->par->Last() &&
3513 || !cur->par->table->IsFirstCell(cell_act))) {
3514 while (cur->pos < cur->par->Last() &&
3515 !cur->par->IsNewline(cur->pos))
3516 cur->par->Erase(cur->pos);
3519 if (cur->pos < cur->par->Last())
3520 cur->par->Erase(cur->pos);
3522 if (cur->pos && cur->pos == cur->par->Last()) {
3524 cur->par->Erase(cur->pos); // no newline at the very end!
3526 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3527 !cur->par->table->IsContRow(cell_org) &&
3528 cur->par->table->IsContRow(cell));
3529 cur->par->table->DeleteRow(cell_org);
3534 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor) const
3536 if (!old_cursor->par->table)
3538 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3539 int pos = old_cursor->pos;
3540 int cell = NumberOfCell(old_cursor->par, pos);
3542 // search first charater of this table row
3543 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3545 while (pos && !old_cursor->par->IsNewline(pos-1))
3549 if (!old_cursor->par->IsNewline(pos))
3553 while ((pos < old_cursor->par->Last()) &&
3554 !old_cursor->par->table->IsFirstCell(cell)) {
3555 if (!old_cursor->par->IsNewline(pos))
3566 bool LyXText::IsEmptyTableCell() const
3568 LyXParagraph::size_type pos = cursor.pos - 1;
3569 while (pos >= 0 && pos < cursor.par->Last()
3570 && !cursor.par->IsNewline(pos))
3572 return cursor.par->IsNewline(pos + 1);
3576 void LyXText::toggleAppendix(){
3577 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3578 bool start = !par->start_of_appendix;
3580 /* ensure that we have only one start_of_appendix in this document */
3581 LyXParagraph * tmp = FirstParagraph();
3582 for (;tmp;tmp = tmp->next)
3583 tmp->start_of_appendix = 0;
3584 par->start_of_appendix = start;
3586 /* we can set the refreshing parameters now */
3587 status = LyXText::NEED_MORE_REFRESH;
3589 refresh_row = 0; // not needed for full update
3591 SetCursor(cursor.par, cursor.pos);