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 #define FIX_DOUBLE_SPACE 1
40 extern BufferView * current_view;
44 LyXText::LyXText(int pw, Buffer * p)
51 parameters = &p->params;
55 status = LyXText::UNCHANGED;
56 LyXParagraph * par = p->paragraph;
57 current_font = GetFont(par, 0);
62 InsertParagraph(par, lastrow);
65 // set cursor at the very top position
66 selection = true; /* these setting is necessary
67 because of the delete-empty-
68 paragraph mechanism in
70 SetCursor(firstrow->par, 0);
75 // no rebreak necessary
81 // 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) const
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,
187 // Let the insets convert their font
188 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
189 if (par->GetInset(pos))
190 font = par->GetInset(pos)->ConvertFont(font);
193 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
196 // Get concrete layout font to reduce against
199 if (pos < BeginningOfMainBody(par))
200 layoutfont = layout.labelfont;
202 layoutfont = layout.font;
204 // Realize against environment font information
205 if (par->GetDepth()){
206 LyXParagraph * tp = par;
207 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
208 tp = tp->DepthHook(tp->GetDepth()-1);
210 layoutfont.realize(textclasslist.
211 Style(parameters->textclass,
212 tp->GetLayout()).font);
216 layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
218 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
219 && par->footnotekind == LyXParagraph::FOOTNOTE) {
220 layoutfont.decSize();
223 // Now, reduce font against full layout font
224 font.reduce(layoutfont);
226 par->SetFont(pos, font);
230 /* inserts a new row behind the specified row, increments
231 * the touched counters */
232 void LyXText::InsertRow(Row * row, LyXParagraph * par,
233 LyXParagraph::size_type pos) const
235 Row * tmprow = new Row;
237 tmprow->previous = 0;
238 tmprow->next = firstrow;
242 tmprow->previous = row;
243 tmprow->next = row->next;
248 tmprow->next->previous = tmprow;
250 if (tmprow->previous)
251 tmprow->previous->next = tmprow;
259 number_of_rows++; // one more row
263 // removes the row and reset the touched counters
264 void LyXText::RemoveRow(Row * row) const
266 /* this must not happen before the currentrow for clear reasons.
267 so the trick is just to set the current row onto the previous
270 GetRow(row->par, row->pos, unused_y);
271 currentrow = currentrow->previous;
273 currentrow_y -= currentrow->height;
278 row->next->previous = row->previous;
279 if (!row->previous) {
280 firstrow = row->next;
283 row->previous->next = row->next;
286 lastrow = row->previous;
288 height -= row->height; // the text becomes smaller
291 --number_of_rows; // one row less
295 // remove all following rows of the paragraph of the specified row.
296 void LyXText::RemoveParagraph(Row * row) const
298 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) const
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);
334 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
336 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()
353 ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
354 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
356 cursor.par->GetInset(cursor.pos)->Edit(0, 0);
363 void LyXText::CloseFootnote()
365 LyXParagraph * tmppar;
366 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
368 // if the cursor is not in an open footnote, or
369 // there is no open footnote in this paragraph, just return.
370 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
373 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
374 current_view->owner()->getMiniBuffer()
375 ->Set(_("Nothing to do"));
379 // ok, move the cursor right before the footnote
380 // just a little faster than using CursorRight()
382 cursor.par->ParFromPos(cursor.pos) != par;
386 // now the cursor is at the beginning of the physical par
387 SetCursor(cursor.par,
389 cursor.par->ParFromPos(cursor.pos)->text.size());
391 /* we are in a footnote, so let us move at the beginning */
392 /* this is just faster than using just CursorLeft() */
395 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
396 // just a little bit faster than movin the cursor
397 tmppar = tmppar->Previous();
399 SetCursor(tmppar, tmppar->Last());
402 // the cursor must be exactly before the footnote
403 par = cursor.par->ParFromPos(cursor.pos);
405 status = LyXText::NEED_MORE_REFRESH;
406 refresh_row = cursor.row;
407 refresh_y = cursor.y - cursor.row->baseline;
410 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
411 Row * row = cursor.row;
413 tmppar->CloseFootnote(cursor.pos);
415 while (tmppar != endpar) {
416 RemoveRow(row->next);
418 tmppar = row->next->par;
423 AppendParagraph(cursor.row);
425 SetCursor(cursor.par, cursor.pos);
429 if (cursor.row->next)
430 SetHeightOfRow(cursor.row->next);
434 /* used in setlayout */
435 // Asger is not sure we want to do this...
436 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
438 LyXFont layoutfont, tmpfont;
440 LyXLayout const & layout =
441 textclasslist.Style(parameters->textclass, par->GetLayout());
443 for (LyXParagraph::size_type pos = 0;
444 pos < par->Last(); ++pos) {
445 if (pos < BeginningOfMainBody(par))
446 layoutfont = layout.labelfont;
448 layoutfont = layout.font;
450 tmpfont = par->GetFontSettings(pos);
451 tmpfont.reduce(layoutfont);
452 par->SetFont(pos, tmpfont);
457 // set layout over selection and make a total rebreak of those paragraphs
458 void LyXText::SetLayout(char layout)
462 // if there is no selection just set the layout
463 // of the current paragraph */
465 sel_start_cursor = cursor; // dummy selection
466 sel_end_cursor = cursor;
469 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
470 LyXParagraph * undoendpar = endpar;
472 if (endpar && endpar->GetDepth()) {
473 while (endpar && endpar->GetDepth()) {
474 endpar = endpar->LastPhysicalPar()->Next();
479 endpar = endpar->Next(); // because of parindents etc.
483 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
486 tmpcursor = cursor; /* store the current cursor */
488 /* ok we have a selection. This is always between sel_start_cursor
489 * and sel_end cursor */
490 cursor = sel_start_cursor;
492 LyXLayout const & lyxlayout =
493 textclasslist.Style(parameters->textclass, layout);
495 while (cursor.par != sel_end_cursor.par) {
496 if (cursor.par->footnoteflag ==
497 sel_start_cursor.par->footnoteflag) {
498 cursor.par->SetLayout(layout);
499 MakeFontEntriesLayoutSpecific(cursor.par);
500 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
501 fppar->added_space_top = lyxlayout.fill_top ?
502 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
503 fppar->added_space_bottom = lyxlayout.fill_bottom ?
504 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
505 if (lyxlayout.margintype == MARGIN_MANUAL)
506 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
507 if (lyxlayout.labeltype != LABEL_BIBLIO
509 delete fppar->bibkey;
513 cursor.par = cursor.par->Next();
515 if (cursor.par->footnoteflag ==
516 sel_start_cursor.par->footnoteflag) {
517 cursor.par->SetLayout(layout);
518 MakeFontEntriesLayoutSpecific(cursor.par);
519 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
520 fppar->added_space_top = lyxlayout.fill_top ?
521 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
522 fppar->added_space_bottom = lyxlayout.fill_bottom ?
523 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
524 if (lyxlayout.margintype == MARGIN_MANUAL)
525 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
526 if (lyxlayout.labeltype != LABEL_BIBLIO
528 delete fppar->bibkey;
533 RedoParagraphs(sel_start_cursor, endpar);
535 // we have to reset the selection, because the
536 // geometry could have changed */
537 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
539 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
540 UpdateCounters(cursor.row);
543 SetCursor(tmpcursor.par, tmpcursor.pos);
547 // increment depth over selection and
548 // make a total rebreak of those paragraphs
549 void LyXText::IncDepth()
551 // If there is no selection, just use the current paragraph
553 sel_start_cursor = cursor; // dummy selection
554 sel_end_cursor = cursor;
557 // We end at the next paragraph with depth 0
558 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
559 LyXParagraph * undoendpar = endpar;
561 if (endpar && endpar->GetDepth()) {
562 while (endpar && endpar->GetDepth()) {
563 endpar = endpar->LastPhysicalPar()->Next();
568 endpar = endpar->Next(); // because of parindents etc.
573 .par->ParFromPos(sel_start_cursor.pos)->previous,
576 LyXCursor tmpcursor = cursor; // store the current cursor
578 // ok we have a selection. This is always between sel_start_cursor
579 // and sel_end cursor
580 cursor = sel_start_cursor;
582 bool anything_changed = false;
585 // NOTE: you can't change the depth of a bibliography entry
586 if (cursor.par->footnoteflag ==
587 sel_start_cursor.par->footnoteflag
588 && textclasslist.Style(parameters->textclass,
589 cursor.par->GetLayout()
590 ).labeltype != LABEL_BIBLIO) {
591 LyXParagraph * prev =
592 cursor.par->FirstPhysicalPar()->Previous();
594 && (prev->GetDepth() - cursor.par->GetDepth() > 0
595 || (prev->GetDepth() == cursor.par->GetDepth()
596 && textclasslist.Style(parameters->textclass,
597 prev->GetLayout()).isEnvironment()))) {
598 cursor.par->FirstPhysicalPar()->depth++;
599 anything_changed = true;
602 if (cursor.par == sel_end_cursor.par)
604 cursor.par = cursor.par->Next();
607 // if nothing changed set all depth to 0
608 if (!anything_changed) {
609 cursor = sel_start_cursor;
610 while (cursor.par != sel_end_cursor.par) {
611 cursor.par->FirstPhysicalPar()->depth = 0;
612 cursor.par = cursor.par->Next();
614 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
615 cursor.par->FirstPhysicalPar()->depth = 0;
618 RedoParagraphs(sel_start_cursor, endpar);
620 // we have to reset the selection, because the
621 // geometry could have changed
622 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
624 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
625 UpdateCounters(cursor.row);
628 SetCursor(tmpcursor.par, tmpcursor.pos);
632 // decrement depth over selection and
633 // make a total rebreak of those paragraphs
634 void LyXText::DecDepth()
636 // if there is no selection just set the layout
637 // of the current paragraph
639 sel_start_cursor = cursor; // dummy selection
640 sel_end_cursor = cursor;
643 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
644 LyXParagraph * undoendpar = endpar;
646 if (endpar && endpar->GetDepth()) {
647 while (endpar && endpar->GetDepth()) {
648 endpar = endpar->LastPhysicalPar()->Next();
653 endpar = endpar->Next(); // because of parindents etc.
658 .par->ParFromPos(sel_start_cursor.pos)->previous,
661 LyXCursor tmpcursor = cursor; // store the current cursor
663 // ok we have a selection. This is always between sel_start_cursor
664 // and sel_end cursor
665 cursor = sel_start_cursor;
668 if (cursor.par->footnoteflag ==
669 sel_start_cursor.par->footnoteflag) {
670 if (cursor.par->FirstPhysicalPar()->depth)
671 cursor.par->FirstPhysicalPar()->depth--;
673 if (cursor.par == sel_end_cursor.par)
675 cursor.par = cursor.par->Next();
678 RedoParagraphs(sel_start_cursor, endpar);
680 // we have to reset the selection, because the
681 // geometry could have changed
682 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
684 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
685 UpdateCounters(cursor.row);
688 SetCursor(tmpcursor.par, tmpcursor.pos);
692 // set font over selection and make a total rebreak of those paragraphs
693 void LyXText::SetFont(LyXFont const & font, bool toggleall)
695 // if there is no selection just set the current_font
697 // Determine basis font
699 if (cursor.pos < BeginningOfMainBody(cursor.par))
700 layoutfont = GetFont(cursor.par, -2);
702 layoutfont = GetFont(cursor.par, -1);
703 // Update current font
704 real_current_font.update(font, toggleall);
706 // Reduce to implicit settings
707 current_font = real_current_font;
708 current_font.reduce(layoutfont);
709 // And resolve it completely
710 real_current_font.realize(layoutfont);
714 LyXCursor tmpcursor = cursor; // store the current cursor
716 // ok we have a selection. This is always between sel_start_cursor
717 // and sel_end cursor
720 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
721 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
722 cursor = sel_start_cursor;
723 while (cursor.par != sel_end_cursor.par ||
724 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
725 && cursor.pos < sel_end_cursor.pos))
727 if (cursor.pos < cursor.par->Last()
728 && cursor.par->footnoteflag
729 == sel_start_cursor.par->footnoteflag) {
730 // an open footnote should behave
732 LyXFont newfont = GetFont(cursor.par, cursor.pos);
733 newfont.update(font, toggleall);
734 SetCharFont(cursor.par, cursor.pos, newfont);
738 cursor.par = cursor.par->Next();
742 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
744 // we have to reset the selection, because the
745 // geometry could have changed
746 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
748 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
751 SetCursor(tmpcursor.par, tmpcursor.pos);
755 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
757 Row * tmprow = cur.row;
758 long y = cur.y - tmprow->baseline;
760 SetHeightOfRow(tmprow);
761 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
762 // find the first row of the paragraph
763 if (first_phys_par != tmprow->par)
764 while (tmprow->previous
765 && tmprow->previous->par != first_phys_par) {
766 tmprow = tmprow->previous;
768 SetHeightOfRow(tmprow);
770 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
771 tmprow = tmprow->previous;
773 SetHeightOfRow(tmprow);
776 // we can set the refreshing parameters now
777 status = LyXText::NEED_MORE_REFRESH;
779 refresh_row = tmprow;
780 SetCursor(cur.par, cur.pos);
784 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
786 Row * tmprow = cur.row;
788 long y = cur.y - tmprow->baseline;
789 SetHeightOfRow(tmprow);
790 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
791 // find the first row of the paragraph
792 if (first_phys_par != tmprow->par)
793 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
794 tmprow = tmprow->previous;
797 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
798 tmprow = tmprow->previous;
802 // we can set the refreshing parameters now
803 if (status == LyXText::UNCHANGED || y < refresh_y) {
805 refresh_row = tmprow;
807 status = LyXText::NEED_MORE_REFRESH;
808 SetCursor(cur.par, cur.pos);
812 /* deletes and inserts again all paragaphs between the cursor
813 * and the specified par
814 * This function is needed after SetLayout and SetFont etc. */
815 void LyXText::RedoParagraphs(LyXCursor const & cur,
816 LyXParagraph const * endpar) const
819 LyXParagraph * tmppar, * first_phys_par;
821 Row * tmprow = cur.row;
823 long y = cur.y - tmprow->baseline;
825 if (!tmprow->previous){
826 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
828 first_phys_par = tmprow->par->FirstPhysicalPar();
829 // find the first row of the paragraph
830 if (first_phys_par != tmprow->par)
831 while (tmprow->previous
832 && tmprow->previous->par != first_phys_par) {
833 tmprow = tmprow->previous;
836 while (tmprow->previous
837 && tmprow->previous->par == first_phys_par) {
838 tmprow = tmprow->previous;
843 // we can set the refreshing parameters now
844 status = LyXText::NEED_MORE_REFRESH;
846 refresh_row = tmprow->previous; /* the real refresh row will
847 be deleted, so I store
851 tmppar = tmprow->next->par;
854 while (tmppar != endpar) {
855 RemoveRow(tmprow->next);
857 tmppar = tmprow->next->par;
862 // remove the first one
863 tmprow2 = tmprow; /* this is because tmprow->previous
865 tmprow = tmprow->previous;
868 tmppar = first_phys_par;
872 InsertParagraph(tmppar, tmprow);
875 while (tmprow->next && tmprow->next->par == tmppar)
876 tmprow = tmprow->next;
877 tmppar = tmppar->Next();
879 } while (tmppar != endpar);
881 // this is because of layout changes
883 refresh_y -= refresh_row->height;
884 SetHeightOfRow(refresh_row);
886 refresh_row = firstrow;
888 SetHeightOfRow(refresh_row);
891 if (tmprow && tmprow->next)
892 SetHeightOfRow(tmprow->next);
896 int LyXText::FullRebreak()
898 if (need_break_row) {
899 BreakAgain(need_break_row);
907 /* important for the screen */
910 /* the cursor set functions have a special mechanism. When they
911 * realize, that you left an empty paragraph, they will delete it.
912 * They also delet the corresponding row */
914 // need the selection cursor:
915 void LyXText::SetSelection()
918 last_sel_cursor = sel_cursor;
919 sel_start_cursor = sel_cursor;
920 sel_end_cursor = sel_cursor;
925 // first the toggling area
926 if (cursor.y < last_sel_cursor.y ||
927 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
928 toggle_end_cursor = last_sel_cursor;
929 toggle_cursor = cursor;
932 toggle_end_cursor = cursor;
933 toggle_cursor = last_sel_cursor;
936 last_sel_cursor = cursor;
938 // and now the whole selection
940 if (sel_cursor.y < cursor.y ||
941 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
942 sel_end_cursor = cursor;
943 sel_start_cursor = sel_cursor;
946 sel_end_cursor = sel_cursor;
947 sel_start_cursor = cursor;
950 // a selection with no contents is not a selection
951 if (sel_start_cursor.x == sel_end_cursor.x &&
952 sel_start_cursor.y == sel_end_cursor.y)
957 void LyXText::ClearSelection() const
964 void LyXText::CursorHome() const
966 SetCursor(cursor.par, cursor.row->pos);
970 void LyXText::CursorEnd() const
972 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
973 SetCursor(cursor.par, RowLast(cursor.row) + 1);
975 if (cursor.par->Last() &&
976 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
977 || cursor.par->IsNewline(RowLast(cursor.row))))
978 SetCursor(cursor.par, RowLast(cursor.row));
980 SetCursor(cursor.par, RowLast(cursor.row) + 1);
982 if (cursor.par->table) {
983 int cell = NumberOfCell(cursor.par, cursor.pos);
984 if (cursor.par->table->RowHasContRow(cell) &&
985 cursor.par->table->CellHasContRow(cell)<0) {
986 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
987 SetCursor(cursor.par, RowLast(cursor.row) + 1);
989 if (cursor.par->Last() &&
990 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
991 || cursor.par->IsNewline(RowLast(cursor.row))))
992 SetCursor(cursor.par, RowLast(cursor.row));
994 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1001 void LyXText::CursorTop() const
1003 while (cursor.par->Previous())
1004 cursor.par = cursor.par->Previous();
1005 SetCursor(cursor.par, 0);
1009 void LyXText::CursorBottom() const
1011 while (cursor.par->Next())
1012 cursor.par = cursor.par->Next();
1013 SetCursor(cursor.par, cursor.par->Last());
1017 /* returns a pointer to the row near the specified y-coordinate
1018 * (relative to the whole text). y is set to the real beginning
1020 Row * LyXText::GetRowNearY(long & y) const
1026 tmprow = currentrow;
1027 tmpy = currentrow_y;
1034 while (tmprow->next && tmpy + tmprow->height <= y) {
1035 tmpy += tmprow->height;
1036 tmprow = tmprow->next;
1039 while (tmprow->previous && tmpy > y) {
1040 tmprow = tmprow->previous;
1041 tmpy -= tmprow->height;
1044 currentrow = tmprow;
1045 currentrow_y = tmpy;
1047 y = tmpy; // return the real y
1052 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1054 // If the mask is completely neutral, tell user
1055 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1056 // Could only happen with user style
1057 current_view->owner()->getMiniBuffer()
1058 ->Set(_("No font change defined. Use Character under"
1059 " the Layout menu to define font change."));
1063 // Try implicit word selection
1064 LyXCursor resetCursor = cursor;
1065 int implicitSelection = SelectWordWhenUnderCursor();
1068 SetFont(font, toggleall);
1070 /* Implicit selections are cleared afterwards and cursor is set to the
1071 original position. */
1072 if (implicitSelection) {
1074 cursor = resetCursor;
1075 SetCursor( cursor.par, cursor.pos );
1076 sel_cursor = cursor;
1081 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1083 if (textclasslist.Style(parameters->textclass,
1084 par->GetLayout()).labeltype != LABEL_MANUAL)
1087 return par->BeginningOfMainBody();
1091 /* if there is a selection, reset every environment you can find
1092 * in the selection, otherwise just the environment you are in */
1093 void LyXText::MeltFootnoteEnvironment()
1095 LyXParagraph * tmppar, * firsttmppar;
1099 /* is is only allowed, if the cursor is IN an open footnote.
1100 * Otherwise it is too dangerous */
1101 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1104 SetUndo(Undo::FINISH,
1105 cursor.par->PreviousBeforeFootnote()->previous,
1106 cursor.par->NextAfterFootnote()->next);
1108 /* ok, move to the beginning of the footnote. */
1109 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1110 cursor.par = cursor.par->Previous();
1112 SetCursor(cursor.par, cursor.par->Last());
1113 /* this is just faster than using CursorLeft(); */
1115 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1116 tmppar = firsttmppar;
1117 /* tmppar is now the paragraph right before the footnote */
1119 char first_footnote_par_is_not_empty = tmppar->next->text.size();
1122 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1123 tmppar = tmppar->next; /* I use next instead of Next(),
1124 * because there cannot be any
1125 * footnotes in a footnote
1127 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1129 /* remember the captions and empty paragraphs */
1130 if ((textclasslist.Style(parameters->textclass,
1131 tmppar->GetLayout())
1132 .labeltype == LABEL_SENSITIVE)
1134 tmppar->SetLayout(0);
1137 // now we will paste the ex-footnote, if the layouts allow it
1138 // first restore the layout of the paragraph right behind
1141 tmppar->next->MakeSameLayout(cursor.par);
1144 if ((!tmppar->GetLayout() && !tmppar->table)
1146 && (!tmppar->Next()->Last()
1147 || tmppar->Next()->HasSameLayout(tmppar)))) {
1148 if (tmppar->Next()->Last()
1149 && tmppar->Next()->IsLineSeparator(0))
1150 tmppar->Next()->Erase(0);
1151 tmppar->PasteParagraph();
1154 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1155 * by the pasting of the beginning */
1157 /* then the beginning */
1158 /* if there is no space between the text and the footnote, so we insert
1160 * (only if the previous par and the footnotepar are not empty!) */
1161 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1162 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1163 if (firsttmppar->text.size()
1164 && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1165 && first_footnote_par_is_not_empty) {
1166 firsttmppar->next->InsertChar(0, ' ');
1168 firsttmppar->PasteParagraph();
1171 /* now redo the paragaphs */
1172 RedoParagraphs(cursor, tmppar);
1174 SetCursor(cursor.par, cursor.pos);
1176 /* sometimes it can happen, that there is a counter change */
1177 Row * row = cursor.row;
1178 while (row->next && row->par != tmppar && row->next->par != tmppar)
1180 UpdateCounters(row);
1187 /* the DTP switches for paragraphs. LyX will store them in the
1188 * first physicla paragraph. When a paragraph is broken, the top settings
1189 * rest, the bottom settings are given to the new one. So I can make shure,
1190 * they do not duplicate themself and you cannnot make dirty things with
1193 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1194 bool pagebreak_top, bool pagebreak_bottom,
1195 VSpace const & space_top,
1196 VSpace const & space_bottom,
1198 string labelwidthstring,
1201 LyXCursor tmpcursor = cursor;
1203 sel_start_cursor = cursor;
1204 sel_end_cursor = cursor;
1207 // make sure that the depth behind the selection are restored, too
1208 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1209 LyXParagraph * undoendpar = endpar;
1211 if (endpar && endpar->GetDepth()) {
1212 while (endpar && endpar->GetDepth()) {
1213 endpar = endpar->LastPhysicalPar()->Next();
1214 undoendpar = endpar;
1218 endpar = endpar->Next(); // because of parindents etc.
1223 .par->ParFromPos(sel_start_cursor.pos)->previous,
1227 LyXParagraph * tmppar = sel_end_cursor.par;
1228 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1229 SetCursor(tmppar->FirstPhysicalPar(), 0);
1230 status = LyXText::NEED_MORE_REFRESH;
1231 refresh_row = cursor.row;
1232 refresh_y = cursor.y - cursor.row->baseline;
1233 if (cursor.par->footnoteflag ==
1234 sel_start_cursor.par->footnoteflag) {
1235 cursor.par->line_top = line_top;
1236 cursor.par->line_bottom = line_bottom;
1237 cursor.par->pagebreak_top = pagebreak_top;
1238 cursor.par->pagebreak_bottom = pagebreak_bottom;
1239 cursor.par->added_space_top = space_top;
1240 cursor.par->added_space_bottom = space_bottom;
1241 // does the layout allow the new alignment?
1242 if (align == LYX_ALIGN_LAYOUT)
1243 align = textclasslist
1244 .Style(parameters->textclass,
1245 cursor.par->GetLayout()).align;
1246 if (align & textclasslist
1247 .Style(parameters->textclass,
1248 cursor.par->GetLayout()).alignpossible) {
1249 if (align == textclasslist
1250 .Style(parameters->textclass,
1251 cursor.par->GetLayout()).align)
1252 cursor.par->align = LYX_ALIGN_LAYOUT;
1254 cursor.par->align = align;
1256 cursor.par->SetLabelWidthString(labelwidthstring);
1257 cursor.par->noindent = noindent;
1260 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1263 RedoParagraphs(sel_start_cursor, endpar);
1266 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1267 sel_cursor = cursor;
1268 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1270 SetCursor(tmpcursor.par, tmpcursor.pos);
1274 void LyXText::SetParagraphExtraOpt(int type,
1276 char const * widthp,
1277 int alignment, bool hfill,
1278 bool start_minipage)
1280 LyXCursor tmpcursor = cursor;
1281 LyXParagraph * tmppar;
1283 sel_start_cursor = cursor;
1284 sel_end_cursor = cursor;
1287 // make sure that the depth behind the selection are restored, too
1288 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1289 LyXParagraph * undoendpar = endpar;
1291 if (endpar && endpar->GetDepth()) {
1292 while (endpar && endpar->GetDepth()) {
1293 endpar = endpar->LastPhysicalPar()->Next();
1294 undoendpar = endpar;
1298 endpar = endpar->Next(); // because of parindents etc.
1303 .par->ParFromPos(sel_start_cursor.pos)->previous,
1306 tmppar = sel_end_cursor.par;
1307 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1308 SetCursor(tmppar->FirstPhysicalPar(), 0);
1309 status = LyXText::NEED_MORE_REFRESH;
1310 refresh_row = cursor.row;
1311 refresh_y = cursor.y - cursor.row->baseline;
1312 if (cursor.par->footnoteflag ==
1313 sel_start_cursor.par->footnoteflag) {
1314 if (type == LyXParagraph::PEXTRA_NONE) {
1315 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1316 cursor.par->UnsetPExtraType();
1317 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1320 cursor.par->SetPExtraType(type, width, widthp);
1321 cursor.par->pextra_hfill = hfill;
1322 cursor.par->pextra_start_minipage = start_minipage;
1323 cursor.par->pextra_alignment = alignment;
1326 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1328 RedoParagraphs(sel_start_cursor, endpar);
1330 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1331 sel_cursor = cursor;
1332 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1334 SetCursor(tmpcursor.par, tmpcursor.pos);
1338 static char const * alphaCounter(int n) {
1339 static char result[2];
1344 result[0] = 'A' + n;
1352 // set the counter of a paragraph. This includes the labels
1353 void LyXText::SetCounter(LyXParagraph * par) const
1355 // this is only relevant for the beginning of paragraph
1356 par = par->FirstPhysicalPar();
1358 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1361 LyXTextClass const & textclass =
1362 textclasslist.TextClass(parameters->textclass);
1364 /* copy the prev-counters to this one, unless this is the start of a
1365 footnote or of a bibliography or the very first paragraph */
1367 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1368 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1369 && par->footnotekind == LyXParagraph::FOOTNOTE)
1370 && !(textclasslist.Style(parameters->textclass,
1371 par->Previous()->GetLayout()
1372 ).labeltype != LABEL_BIBLIO
1373 && layout.labeltype == LABEL_BIBLIO)) {
1374 for (int i = 0; i<10; i++) {
1375 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1377 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1378 if (!par->appendix && par->start_of_appendix){
1379 par->appendix = true;
1380 for (int i = 0; i<10; i++) {
1381 par->setCounter(i, 0);
1384 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1385 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1388 for (int i = 0; i<10; i++) {
1389 par->setCounter(i, 0);
1391 par->appendix = par->start_of_appendix;
1396 // if this is an open marginnote and this is the first
1397 // entry in the marginnote and the enclosing
1398 // environment is an enum/item then correct for the
1399 // LaTeX behaviour (ARRae)
1400 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1401 && par->footnotekind == LyXParagraph::MARGIN
1403 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1404 && (par->PreviousBeforeFootnote()
1405 && textclasslist.Style(parameters->textclass,
1406 par->PreviousBeforeFootnote()->GetLayout()
1407 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1408 // Any itemize or enumerate environment in a marginnote
1409 // that is embedded in an itemize or enumerate
1410 // paragraph is seen by LaTeX as being at a deeper
1411 // level within that enclosing itemization/enumeration
1412 // even if there is a "standard" layout at the start of
1418 /* Maybe we have to increment the enumeration depth.
1419 * BUT, enumeration in a footnote is considered in isolation from its
1420 * surrounding paragraph so don't increment if this is the
1421 * first line of the footnote
1422 * AND, bibliographies can't have their depth changed ie. they
1423 * are always of depth 0
1426 && par->Previous()->GetDepth() < par->GetDepth()
1427 && textclasslist.Style(parameters->textclass,
1428 par->Previous()->GetLayout()
1429 ).labeltype == LABEL_COUNTER_ENUMI
1430 && par->enumdepth < 3
1431 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1432 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1433 && par->footnotekind == LyXParagraph::FOOTNOTE)
1434 && layout.labeltype != LABEL_BIBLIO) {
1438 /* Maybe we have to decrement the enumeration depth, see note above */
1440 && par->Previous()->GetDepth() > par->GetDepth()
1441 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1442 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1443 && par->footnotekind == LyXParagraph::FOOTNOTE)
1444 && layout.labeltype != LABEL_BIBLIO) {
1445 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1446 par->setCounter(6 + par->enumdepth,
1447 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1448 /* reset the counters.
1449 * A depth change is like a breaking layout
1451 for (int i = 6 + par->enumdepth + 1; i<10;i++)
1452 par->setCounter(i, 0);
1455 if (!par->labelstring.empty()) {
1456 par->labelstring.clear();
1459 if (layout.margintype == MARGIN_MANUAL) {
1460 if (par->labelwidthstring.empty()) {
1461 par->SetLabelWidthString(layout.labelstring());
1465 par->SetLabelWidthString(string());
1468 /* is it a layout that has an automatic label ? */
1469 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1471 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1472 if (i >= 0 && i<= parameters->secnumdepth) {
1473 par->incCounter(i); // increment the counter
1475 char * s = new char[50];
1477 // Is there a label? Useful for Chapter layout
1478 if (!par->appendix){
1479 if (!layout.labelstring().empty())
1480 par->labelstring = layout.labelstring();
1482 par->labelstring.clear();
1484 if (!layout.labelstring_appendix().empty())
1485 par->labelstring = layout.labelstring_appendix();
1487 par->labelstring.clear();
1490 if (!par->appendix){
1491 switch (2 * LABEL_FIRST_COUNTER -
1492 textclass.maxcounter() + i) {
1493 case LABEL_COUNTER_CHAPTER:
1495 par->getCounter(i));
1497 case LABEL_COUNTER_SECTION:
1499 par->getCounter(i - 1),
1500 par->getCounter(i));
1502 case LABEL_COUNTER_SUBSECTION:
1503 sprintf(s, "%d.%d.%d",
1504 par->getCounter(i-2),
1505 par->getCounter(i-1),
1506 par->getCounter(i));
1508 case LABEL_COUNTER_SUBSUBSECTION:
1509 sprintf(s, "%d.%d.%d.%d",
1510 par->getCounter(i-3),
1511 par->getCounter(i-2),
1512 par->getCounter(i-1),
1513 par->getCounter(i));
1515 case LABEL_COUNTER_PARAGRAPH:
1516 sprintf(s, "%d.%d.%d.%d.%d",
1517 par->getCounter(i-4),
1518 par->getCounter(i-3),
1519 par->getCounter(i-2),
1520 par->getCounter(i-1),
1521 par->getCounter(i));
1523 case LABEL_COUNTER_SUBPARAGRAPH:
1524 sprintf(s, "%d.%d.%d.%d.%d.%d",
1525 par->getCounter(i-5),
1526 par->getCounter(i-4),
1527 par->getCounter(i-3),
1528 par->getCounter(i-2),
1529 par->getCounter(i-1),
1530 par->getCounter(i));
1533 sprintf(s, "%d.", par->getCounter(i));
1537 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1538 case LABEL_COUNTER_CHAPTER:
1540 alphaCounter(par->getCounter(i)));
1542 case LABEL_COUNTER_SECTION:
1544 alphaCounter(par->getCounter(i - 1)),
1545 par->getCounter(i));
1547 case LABEL_COUNTER_SUBSECTION:
1548 sprintf(s, "%s.%d.%d",
1549 alphaCounter(par->getCounter(i-2)),
1550 par->getCounter(i-1),
1551 par->getCounter(i));
1553 case LABEL_COUNTER_SUBSUBSECTION:
1554 sprintf(s, "%s.%d.%d.%d",
1555 alphaCounter(par->getCounter(i-3)),
1556 par->getCounter(i-2),
1557 par->getCounter(i-1),
1558 par->getCounter(i));
1560 case LABEL_COUNTER_PARAGRAPH:
1561 sprintf(s, "%s.%d.%d.%d.%d",
1562 alphaCounter(par->getCounter(i-4)),
1563 par->getCounter(i-3),
1564 par->getCounter(i-2),
1565 par->getCounter(i-1),
1566 par->getCounter(i));
1568 case LABEL_COUNTER_SUBPARAGRAPH:
1569 sprintf(s, "%s.%d.%d.%d.%d.%d",
1570 alphaCounter(par->getCounter(i-5)),
1571 par->getCounter(i-4),
1572 par->getCounter(i-3),
1573 par->getCounter(i-2),
1574 par->getCounter(i-1),
1575 par->getCounter(i));
1578 sprintf(s, "%c.", par->getCounter(i));
1583 par->labelstring += s;
1586 for (i++; i < 10; ++i) {
1587 // reset the following counters
1588 par->setCounter(i, 0);
1590 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1591 for (i++; i < 10; ++i) {
1592 // reset the following counters
1593 par->setCounter(i, 0);
1595 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1596 par->incCounter(i + par->enumdepth);
1597 char * s = new char[25];
1598 int number = par->getCounter(i + par->enumdepth);
1599 switch (par->enumdepth) {
1601 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1605 case 1: sprintf(s, "i."); break;
1606 case 2: sprintf(s, "ii."); break;
1607 case 3: sprintf(s, "iii."); break;
1608 case 4: sprintf(s, "iv."); break;
1609 case 5: sprintf(s, "v."); break;
1610 case 6: sprintf(s, "vi."); break;
1611 case 7: sprintf(s, "vii."); break;
1612 case 8: sprintf(s, "viii."); break;
1613 case 9: sprintf(s, "ix."); break;
1614 case 10: sprintf(s, "x."); break;
1615 case 11: sprintf(s, "xi."); break;
1616 case 12: sprintf(s, "xii."); break;
1617 case 13: sprintf(s, "xiii."); break;
1619 sprintf(s, "\\roman{%d}.", number);
1624 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1627 sprintf(s, "%d.", number);
1630 par->labelstring = s;
1633 for (i += par->enumdepth + 1; i < 10; ++i)
1634 par->setCounter(i, 0); /* reset the following counters */
1637 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1638 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1640 int number = par->getCounter(i);
1642 par->bibkey = new InsetBibKey();
1643 par->bibkey->setCounter(number);
1644 par->labelstring = layout.labelstring();
1646 // In biblio should't be following counters but...
1648 string s = layout.labelstring();
1650 // the caption hack:
1652 if (layout.labeltype == LABEL_SENSITIVE) {
1653 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1654 && (par->footnotekind == LyXParagraph::FIG
1655 || par->footnotekind == LyXParagraph::WIDE_FIG))
1657 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1658 && (par->footnotekind == LyXParagraph::TAB
1659 || par->footnotekind == LyXParagraph::WIDE_TAB))
1661 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1662 && par->footnotekind == LyXParagraph::ALGORITHM)
1665 /* par->SetLayout(0);
1666 s = layout->labelstring; */
1670 par->labelstring = s;
1672 /* reset the enumeration counter. They are always resetted
1673 * when there is any other layout between */
1674 for (int i = 6 + par->enumdepth; i < 10; ++i)
1675 par->setCounter(i, 0);
1680 /* Updates all counters BEHIND the row. Changed paragraphs
1681 * with a dynamic left margin will be rebroken. */
1682 void LyXText::UpdateCounters(Row * row) const
1691 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1692 par = row->par->LastPhysicalPar()->Next();
1694 par = row->par->next;
1699 while (row->par != par)
1704 /* now check for the headline layouts. remember that they
1705 * have a dynamic left margin */
1707 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1708 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1711 /* Rebreak the paragraph */
1712 RemoveParagraph(row);
1713 AppendParagraph(row);
1715 /* think about the damned open footnotes! */
1716 while (par->Next() &&
1717 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1718 || par->Next()->IsDummy())){
1720 if (par->IsDummy()) {
1721 while (row->par != par)
1723 RemoveParagraph(row);
1724 AppendParagraph(row);
1729 par = par->LastPhysicalPar()->Next();
1735 /* insets an inset. */
1736 void LyXText::InsertInset(Inset *inset)
1738 SetUndo(Undo::INSERT,
1739 cursor.par->ParFromPos(cursor.pos)->previous,
1740 cursor.par->ParFromPos(cursor.pos)->next);
1741 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1742 cursor.par->InsertInset(cursor.pos, inset);
1743 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1744 * The character will not be inserted a
1749 /* this is for the simple cut and paste mechanism */
1750 static LyXParagraph * simple_cut_buffer = 0;
1751 static char simple_cut_buffer_textclass = 0;
1753 void DeleteSimpleCutBuffer()
1755 if (!simple_cut_buffer)
1757 LyXParagraph *tmppar;
1759 while (simple_cut_buffer) {
1760 tmppar = simple_cut_buffer;
1761 simple_cut_buffer = simple_cut_buffer->next;
1764 simple_cut_buffer = 0;
1768 void LyXText::copyEnvironmentType()
1770 copylayouttype = cursor.par->GetLayout();
1774 void LyXText::pasteEnvironmentType()
1776 SetLayout(copylayouttype);
1780 void LyXText::CutSelection(bool doclear)
1782 // This doesn't make sense, if there is no selection
1786 // OK, we have a selection. This is always between sel_start_cursor
1787 // and sel_end cursor
1788 LyXParagraph * tmppar;
1790 // Check whether there are half footnotes in the selection
1791 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1792 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1793 tmppar = sel_start_cursor.par;
1794 while (tmppar != sel_end_cursor.par){
1795 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1796 WriteAlert(_("Impossible operation"),
1797 _("Don't know what to do with half floats."),
1801 tmppar = tmppar->Next();
1805 /* table stuff -- begin */
1806 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1807 if ( sel_start_cursor.par != sel_end_cursor.par) {
1808 WriteAlert(_("Impossible operation"),
1809 _("Don't know what to do with half tables."),
1813 sel_start_cursor.par->table->Reinit();
1815 /* table stuff -- end */
1817 // make sure that the depth behind the selection are restored, too
1818 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1819 LyXParagraph * undoendpar = endpar;
1821 if (endpar && endpar->GetDepth()) {
1822 while (endpar && endpar->GetDepth()) {
1823 endpar = endpar->LastPhysicalPar()->Next();
1824 undoendpar = endpar;
1826 } else if (endpar) {
1827 endpar = endpar->Next(); // because of parindents etc.
1830 SetUndo(Undo::DELETE,
1832 .par->ParFromPos(sel_start_cursor.pos)->previous,
1835 // delete the simple_cut_buffer
1836 DeleteSimpleCutBuffer();
1838 // set the textclass
1839 simple_cut_buffer_textclass = parameters->textclass;
1841 #ifdef WITH_WARNINGS
1842 #warning Asger: Make cut more intelligent here.
1845 White paper for "intelligent" cutting:
1847 Example: "This is our text."
1848 Using " our " as selection, cutting will give "This istext.".
1849 Using "our" as selection, cutting will give "This is text.".
1850 Using " our" as selection, cutting will give "This is text.".
1851 Using "our " as selection, cutting will give "This is text.".
1853 All those four selections will (however) paste identically:
1854 Pasting with the cursor right after the "is" will give the
1855 original text with all four selections.
1857 The rationale is to be intelligent such that words are copied,
1858 cut and pasted in a functional manner.
1860 This is not implemented yet. (Asger)
1862 The changes below sees to do a lot of what you want. However
1863 I have not verified that all cases work as they should:
1865 - cut in multiple row
1867 - cut across footnotes and paragraph
1868 My simplistic tests show that the idea are basically sound but
1869 there are some items to fix up...we only need to find them
1873 #ifndef FIX_DOUBLE_SPACE
1874 bool space_wrapped =
1875 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1876 if (sel_end_cursor.pos > 0
1877 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1878 // please break before a space at the end
1879 sel_end_cursor.pos--;
1880 space_wrapped = true;
1882 // cut behind a space if there is one
1883 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1884 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1885 && (sel_start_cursor.par != sel_end_cursor.par
1886 || sel_start_cursor.pos < sel_end_cursor.pos))
1887 sel_start_cursor.pos++;
1889 // there are two cases: cut only within one paragraph or
1890 // more than one paragraph
1892 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1893 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1894 // only within one paragraph
1895 simple_cut_buffer = new LyXParagraph;
1896 LyXParagraph::size_type i =
1897 sel_start_cursor.pos;
1898 for (; i < sel_end_cursor.pos; ++i) {
1899 /* table stuff -- begin */
1900 if (sel_start_cursor.par->table
1901 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1902 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1903 sel_start_cursor.pos++;
1905 /* table stuff -- end */
1906 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1907 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1909 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1911 #ifdef FIX_DOUBLE_SPACES
1912 // check for double spaces
1913 if (sel_start_cursor.pos &&
1914 sel_start_cursor.par->Last() > sel_start_cursor.pos &&
1915 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1916 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
1917 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1920 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1922 endpar = sel_end_cursor.par->Next();
1925 // cut more than one paragraph
1927 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1928 #ifndef FIX_DOUBLE_SPACE
1929 // insert a space at the end if there was one
1931 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1933 sel_end_cursor.par = sel_end_cursor.par->Next();
1934 sel_end_cursor.pos = 0;
1936 cursor = sel_end_cursor;
1938 #ifndef FIX_DOUBLE_SPACE
1939 // please break behind a space, if there is one.
1940 // The space should be copied too
1941 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1942 sel_start_cursor.pos++;
1944 sel_start_cursor.par
1945 ->BreakParagraphConservative(sel_start_cursor.pos);
1946 if (!sel_start_cursor.pos
1947 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1948 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1949 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1952 // store the endparagraph for redoing later
1953 endpar = sel_end_cursor.par->Next(); /* needed because
1958 // store the selection
1959 simple_cut_buffer = sel_start_cursor.par
1960 ->ParFromPos(sel_start_cursor.pos)->next;
1961 simple_cut_buffer->previous = 0;
1962 sel_end_cursor.par->previous->next = 0;
1964 // cut the selection
1965 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1966 = sel_end_cursor.par;
1968 sel_end_cursor.par->previous
1969 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1971 // care about footnotes
1972 if (simple_cut_buffer->footnoteflag) {
1973 LyXParagraph *tmppar = simple_cut_buffer;
1975 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1976 tmppar = tmppar->next;
1980 // the cut selection should begin with standard layout
1981 simple_cut_buffer->Clear();
1983 // paste the paragraphs again, if possible
1985 sel_start_cursor.par->Next()->ClearParagraph();
1986 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1988 !sel_start_cursor.par->Next()->Last())
1989 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1991 #ifdef FIX_DOUBLE_SPACE
1992 // maybe a forgotten blank
1993 if (sel_start_cursor.pos
1994 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1995 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1996 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2001 // sometimes necessary
2003 sel_start_cursor.par->ClearParagraph();
2005 RedoParagraphs(sel_start_cursor, endpar);
2008 cursor = sel_start_cursor;
2009 SetCursor(cursor.par, cursor.pos);
2010 sel_cursor = cursor;
2011 UpdateCounters(cursor.row);
2015 void LyXText::CopySelection()
2017 // this doesnt make sense, if there is no selection
2021 // ok we have a selection. This is always between sel_start_cursor
2022 // and sel_end cursor
2023 LyXParagraph * tmppar;
2025 /* check wether there are half footnotes in the selection */
2026 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2027 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2028 tmppar = sel_start_cursor.par;
2029 while (tmppar != sel_end_cursor.par){
2030 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2031 WriteAlert(_("Impossible operation"),
2032 _("Don't know what to do with half floats."),
2036 tmppar = tmppar->Next();
2040 /* table stuff -- begin */
2041 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2042 if ( sel_start_cursor.par != sel_end_cursor.par){
2043 WriteAlert(_("Impossible operation"),
2044 _("Don't know what to do with half tables."),
2049 /* table stuff -- end */
2051 // delete the simple_cut_buffer
2052 DeleteSimpleCutBuffer();
2054 // set the textclass
2055 simple_cut_buffer_textclass = parameters->textclass;
2057 #ifdef FIX_DOUBLE_SPACE
2058 // copy behind a space if there is one
2059 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2060 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2061 && (sel_start_cursor.par != sel_end_cursor.par
2062 || sel_start_cursor.pos < sel_end_cursor.pos))
2063 sel_start_cursor.pos++;
2065 // there are two cases: copy only within one paragraph
2066 // or more than one paragraph
2067 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2068 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2069 // only within one paragraph
2070 simple_cut_buffer = new LyXParagraph;
2071 LyXParagraph::size_type i = 0;
2072 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2073 sel_start_cursor.par->CopyIntoMinibuffer(i);
2074 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2077 // copy more than one paragraph
2078 // clone the paragraphs within the selection
2080 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2081 simple_cut_buffer = tmppar->Clone();
2082 LyXParagraph *tmppar2 = simple_cut_buffer;
2084 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2086 tmppar = tmppar->next;
2087 tmppar2->next = tmppar->Clone();
2088 tmppar2->next->previous = tmppar2;
2089 tmppar2 = tmppar2->next;
2093 // care about footnotes
2094 if (simple_cut_buffer->footnoteflag) {
2095 tmppar = simple_cut_buffer;
2097 tmppar->footnoteflag =
2098 LyXParagraph::NO_FOOTNOTE;
2099 tmppar = tmppar->next;
2103 // the simple_cut_buffer paragraph is too big
2104 LyXParagraph::size_type tmpi2 =
2105 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2106 for (; tmpi2; --tmpi2)
2107 simple_cut_buffer->Erase(0);
2109 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2111 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2112 while (tmppar2->size() > tmpi2) {
2113 tmppar2->Erase(tmppar2->text.size() - 1);
2119 void LyXText::PasteSelection()
2121 // this does not make sense, if there is nothing to paste
2122 if (!simple_cut_buffer)
2125 LyXParagraph * tmppar;
2126 LyXParagraph * endpar;
2128 LyXCursor tmpcursor;
2130 // be carefull with footnotes in footnotes
2131 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2133 // check whether the cut_buffer includes a footnote
2134 tmppar = simple_cut_buffer;
2136 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2137 tmppar = tmppar->next;
2140 WriteAlert(_("Impossible operation"),
2141 _("Can't paste float into float!"),
2147 /* table stuff -- begin */
2148 if (cursor.par->table){
2149 if (simple_cut_buffer->next){
2150 WriteAlert(_("Impossible operation"),
2151 _("Table cell cannot include more than one paragraph!"),
2156 /* table stuff -- end */
2158 SetUndo(Undo::INSERT,
2159 cursor.par->ParFromPos(cursor.pos)->previous,
2160 cursor.par->ParFromPos(cursor.pos)->next);
2164 // There are two cases: cutbuffer only one paragraph or many
2165 if (!simple_cut_buffer->next) {
2166 // only within a paragraph
2168 #ifndef FIX_DOUBLE_SPACE
2169 // please break behind a space, if there is one
2170 while (tmpcursor.par->Last() > tmpcursor.pos
2171 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2174 tmppar = simple_cut_buffer->Clone();
2175 /* table stuff -- begin */
2176 bool table_too_small = false;
2177 if (tmpcursor.par->table) {
2178 while (simple_cut_buffer->text.size()
2179 && !table_too_small) {
2180 if (simple_cut_buffer->IsNewline(0)){
2181 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2183 simple_cut_buffer->Erase(0);
2184 if (tmpcursor.pos < tmpcursor.par->Last())
2187 table_too_small = true;
2189 simple_cut_buffer->CutIntoMinibuffer(0);
2190 simple_cut_buffer->Erase(0);
2191 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2196 /* table stuff -- end */
2197 // Some provisions should be done here for checking if we
2198 // are inserting at the beginning of a paragraph. If there
2199 // are a space at the beginning of the text to insert and we are
2200 // inserting at the beginning of the paragraph the space should
2202 while (simple_cut_buffer->text.size()) {
2203 simple_cut_buffer->CutIntoMinibuffer(0);
2204 simple_cut_buffer->Erase(0);
2205 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2209 delete simple_cut_buffer;
2210 simple_cut_buffer = tmppar;
2211 endpar = tmpcursor.par->Next();
2215 // make a copy of the simple cut_buffer
2216 tmppar = simple_cut_buffer;
2217 LyXParagraph * simple_cut_clone = tmppar->Clone();
2218 LyXParagraph * tmppar2 = simple_cut_clone;
2219 if (cursor.par->footnoteflag){
2220 tmppar->footnoteflag = cursor.par->footnoteflag;
2221 tmppar->footnotekind = cursor.par->footnotekind;
2223 while (tmppar->next) {
2224 tmppar = tmppar->next;
2225 tmppar2->next = tmppar->Clone();
2226 tmppar2->next->previous = tmppar2;
2227 tmppar2 = tmppar2->next;
2228 if (cursor.par->footnoteflag){
2229 tmppar->footnoteflag = cursor.par->footnoteflag;
2230 tmppar->footnotekind = cursor.par->footnotekind;
2234 // make sure there is no class difference
2235 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2236 parameters->textclass,
2239 // make the simple_cut_buffer exactly the same layout than
2240 // the cursor paragraph
2241 simple_cut_buffer->MakeSameLayout(cursor.par);
2243 // find the end of the buffer
2244 LyXParagraph *lastbuffer = simple_cut_buffer;
2245 while (lastbuffer->Next())
2246 lastbuffer = lastbuffer->Next();
2248 // find the physical end of the buffer
2249 lastbuffer = simple_cut_buffer;
2250 while (lastbuffer->Next())
2251 lastbuffer = lastbuffer->Next();
2253 #ifndef FIX_DOUBLE_SPACE
2254 // Please break behind a space, if there is one. The space
2255 // should be copied too.
2256 if (cursor.par->Last() > cursor.pos
2257 && cursor.par->IsLineSeparator(cursor.pos))
2260 bool paste_the_end = false;
2262 // open the paragraph for inserting the simple_cut_buffer
2264 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2265 cursor.par->BreakParagraphConservative(cursor.pos);
2266 paste_the_end = true;
2269 #ifndef FIX_DOUBLE_SPACE
2270 // be careful with double spaces
2271 if ((!cursor.par->Last()
2272 || cursor.par->IsLineSeparator(cursor.pos - 1)
2273 || cursor.par->IsNewline(cursor.pos - 1))
2274 && simple_cut_buffer->text.size()
2275 && simple_cut_buffer->IsLineSeparator(0))
2276 simple_cut_buffer->Erase(0);
2278 // set the end for redoing later
2279 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2282 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2283 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2285 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2286 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2288 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2289 lastbuffer = cursor.par;
2291 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2293 // store the new cursor position
2294 tmpcursor.par = lastbuffer;
2295 tmpcursor.pos = lastbuffer->Last();
2297 // maybe some pasting
2298 if (lastbuffer->Next() && paste_the_end) {
2299 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2300 #ifndef FIX_DOUBLE_SPACE
2301 // be careful with double spaces
2302 if ((!lastbuffer->Last()
2303 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2304 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2305 && lastbuffer->Next()->Last()
2306 && lastbuffer->Next()->IsLineSeparator(0))
2307 lastbuffer->Next()->Erase(0);
2309 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2311 } else if (!lastbuffer->Next()->Last()) {
2312 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2313 #ifndef FIX_DOUBLE_SPACE
2314 // be careful witth double spaces
2315 if ((!lastbuffer->Last()
2316 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2317 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2318 && lastbuffer->Next()->Last()
2319 && lastbuffer->Next()->IsLineSeparator(0))
2320 lastbuffer->Next()->Erase(0);
2322 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2324 } else if (!lastbuffer->Last()) {
2325 lastbuffer->MakeSameLayout(lastbuffer->next);
2326 #ifndef FIX_DOUBLE_SPACE
2327 // be careful witth double spaces
2328 if ((!lastbuffer->Last()
2329 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2330 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2331 && lastbuffer->Next()->Last()
2332 && lastbuffer->Next()->IsLineSeparator(0))
2333 lastbuffer->Next()->Erase(0);
2335 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2338 else lastbuffer->Next()->ClearParagraph();
2341 // restore the simple cut buffer
2342 simple_cut_buffer = simple_cut_clone;
2345 RedoParagraphs(cursor, endpar);
2347 SetCursor(cursor.par, cursor.pos);
2350 sel_cursor = cursor;
2351 SetCursor(tmpcursor.par, tmpcursor.pos);
2353 UpdateCounters(cursor.row);
2357 // returns a pointer to the very first LyXParagraph
2358 LyXParagraph * LyXText::FirstParagraph() const
2360 return params->paragraph;
2364 // returns true if the specified string is at the specified position
2365 bool LyXText::IsStringInText(LyXParagraph * par,
2366 LyXParagraph::size_type pos,
2367 char const * str) const
2371 while (pos + i < par->Last() && str[i] &&
2372 str[i] == par->GetChar(pos + i)) {
2382 // sets the selection over the number of characters of string, no check!!
2383 void LyXText::SetSelectionOverString(char const * string)
2385 sel_cursor = cursor;
2386 for (int i = 0; string[i]; ++i)
2392 // simple replacing. The font of the first selected character is used
2393 void LyXText::ReplaceSelectionWithString(char const * str)
2398 if (!selection) { // create a dummy selection
2399 sel_end_cursor = cursor;
2400 sel_start_cursor = cursor;
2403 // Get font setting before we cut
2404 LyXParagraph::size_type pos = sel_end_cursor.pos;
2405 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2407 // Insert the new string
2408 for (int i = 0; str[i]; ++i) {
2409 sel_end_cursor.par->InsertChar(pos, str[i]);
2410 sel_end_cursor.par->SetFont(pos, font);
2414 // Cut the selection
2421 // if the string can be found: return true and set the cursor to
2423 bool LyXText::SearchForward(char const * str) const
2425 LyXParagraph * par = cursor.par;
2426 LyXParagraph::size_type pos = cursor.pos;
2427 while (par && !IsStringInText(par, pos, str)) {
2428 if (pos < par->Last() - 1)
2436 SetCursor(par, pos);
2444 bool LyXText::SearchBackward(char const * string) const
2446 LyXParagraph * par = cursor.par;
2447 int pos = cursor.pos;
2453 // We skip empty paragraphs (Asger)
2455 par = par->Previous();
2457 pos = par->Last() - 1;
2458 } while (par && pos < 0);
2460 } while (par && !IsStringInText(par, pos, string));
2463 SetCursor(par, pos);
2470 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2472 char * str = new char[text.size() + 1];
2473 copy(text.begin(), text.end(), str);
2474 str[text.size()] = '\0';
2480 // needed to insert the selection
2481 void LyXText::InsertStringA(char const * s)
2484 LyXParagraph * par = cursor.par;
2485 LyXParagraph::size_type pos = cursor.pos;
2486 LyXParagraph::size_type a = 0;
2488 LyXParagraph * endpar = cursor.par->Next();
2493 textclasslist.Style(parameters->textclass,
2494 cursor.par->GetLayout()).isEnvironment();
2495 // only to be sure, should not be neccessary
2498 // insert the string, don't insert doublespace
2499 string::size_type i = 0;
2500 while (i < str.length()) {
2501 if (str[i] != '\n') {
2503 && i + 1 < str.length() && str[i + 1] != ' '
2504 && pos && par->GetChar(pos - 1)!= ' ') {
2505 par->InsertChar(pos,' ');
2507 } else if (par->table) {
2508 if (str[i] == '\t') {
2509 while((pos < par->size()) &&
2510 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2512 if (pos < par->size())
2514 else // no more fields to fill skip the rest
2516 } else if ((str[i] != 13) &&
2517 ((str[i] & 127) >= ' ')) {
2518 par->InsertChar(pos, str[i]);
2521 } else if (str[i] == ' ') {
2522 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2524 } else if (str[i] == '\t') {
2525 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2526 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2529 } else if (str[i]!= 13 &&
2530 // Ignore unprintables
2531 (str[i] & 127) >= ' ') {
2532 par->InsertChar(pos, str[i]);
2537 if (i + 1 >= str.length()) {
2541 while((pos < par->size()) &&
2542 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2545 cell = NumberOfCell(par, pos);
2546 while((pos < par->size()) &&
2547 !(par->table->IsFirstCell(cell))) {
2548 while((pos < par->size()) &&
2549 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2552 cell = NumberOfCell(par, pos);
2554 if (pos >= par->size())
2555 // no more fields to fill skip the rest
2558 if (!par->text.size()) {
2559 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2562 par->BreakParagraph(pos, flag);
2570 RedoParagraphs(cursor, endpar);
2571 SetCursor(cursor.par, cursor.pos);
2572 sel_cursor = cursor;
2573 SetCursor(par, pos);
2578 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2580 char * str = new char[text.size() + 1];
2581 copy(text.begin(), text.end(), str);
2582 str[text.size()] = '\0';
2588 /* turns double-CR to single CR, others where converted into one blank and 13s
2589 * that are ignored .Double spaces are also converted into one. Spaces at
2590 * the beginning of a paragraph are forbidden. tabs are converted into one
2591 * space. then InsertStringA is called */
2592 void LyXText::InsertStringB(char const * s)
2595 LyXParagraph * par = cursor.par;
2596 string::size_type i = 1;
2597 while (i < str.length()) {
2598 if (str[i] == '\t' && !par->table)
2600 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2602 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2603 if (str[i + 1] != '\n') {
2604 if (str[i - 1] != ' ')
2609 while (i + 1 < str.length()
2610 && (str[i + 1] == ' '
2611 || str[i + 1] == '\t'
2612 || str[i + 1] == '\n'
2613 || str[i + 1] == 13)) {
2620 InsertStringA(str.c_str());
2624 bool LyXText::GotoNextError() const
2626 LyXCursor res = cursor;
2628 if (res.pos < res.par->Last() - 1) {
2632 res.par = res.par->Next();
2637 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2638 && res.par->GetInset(res.pos)->AutoDelete()));
2641 SetCursor(res.par, res.pos);
2648 bool LyXText::GotoNextNote() const
2650 LyXCursor res = cursor;
2652 if (res.pos < res.par->Last() - 1) {
2655 res.par = res.par->Next();
2660 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2661 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2664 SetCursor(res.par, res.pos);
2671 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2675 if (!par || class1 == class2)
2677 par = par->FirstPhysicalPar();
2679 string name = textclasslist.NameOfLayout(class1, par->layout);
2681 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2682 textclasslist.NumberOfLayout(class2, name);
2685 } else { // layout not found
2686 // use default layout "Standard" (0)
2691 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2693 string s = "Layout had to be changed from\n"
2694 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2695 + "\nbecause of class conversion from\n"
2696 + textclasslist.NameOfClass(class1) + " to "
2697 + textclasslist.NameOfClass(class2);
2698 InsetError * new_inset = new InsetError(s);
2699 par->InsertChar(0, LyXParagraph::META_INSET);
2700 par->InsertInset(0, new_inset);
2709 void LyXText::CheckParagraph(LyXParagraph * par,
2710 LyXParagraph::size_type pos)
2713 LyXCursor tmpcursor;
2715 /* table stuff -- begin*/
2718 CheckParagraphInTable(par, pos);
2721 /* table stuff -- end*/
2724 LyXParagraph::size_type z;
2725 Row * row = GetRow(par, pos, y);
2727 // is there a break one row above
2728 if (row->previous && row->previous->par == row->par) {
2729 z = NextBreakPoint(row->previous, paperwidth);
2730 if ( z >= row->pos) {
2731 // set the dimensions of the row above
2732 y -= row->previous->height;
2734 refresh_row = row->previous;
2735 status = LyXText::NEED_MORE_REFRESH;
2737 BreakAgain(row->previous);
2739 // set the cursor again. Otherwise
2740 // dangling pointers are possible
2741 SetCursor(cursor.par, cursor.pos);
2742 sel_cursor = cursor;
2747 int tmpheight = row->height;
2748 LyXParagraph::size_type tmplast = RowLast(row);
2753 if (row->height == tmpheight && RowLast(row) == tmplast)
2754 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2756 status = LyXText::NEED_MORE_REFRESH;
2758 // check the special right address boxes
2759 if (textclasslist.Style(parameters->textclass,
2760 par->GetLayout()).margintype
2761 == MARGIN_RIGHT_ADDRESS_BOX) {
2762 tmpcursor.par = par;
2763 tmpcursor.row = row;
2766 tmpcursor.x_fix = 0;
2767 tmpcursor.pos = pos;
2768 RedoDrawingOfParagraph(tmpcursor);
2773 // set the cursor again. Otherwise dangling pointers are possible
2774 // also set the selection
2778 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2779 sel_cursor = cursor;
2780 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2781 sel_start_cursor = cursor;
2782 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2783 sel_end_cursor = cursor;
2784 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2785 last_sel_cursor = cursor;
2788 SetCursorIntern(cursor.par, cursor.pos);
2792 // returns 0 if inset wasn't found
2793 int LyXText::UpdateInset(Inset * inset)
2795 // first check the current paragraph
2796 int pos = cursor.par->GetPositionOfInset(inset);
2798 CheckParagraph(cursor.par, pos);
2802 // check every paragraph
2804 LyXParagraph * par = FirstParagraph();
2806 // make sure the paragraph is open
2807 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2808 pos = par->GetPositionOfInset(inset);
2810 CheckParagraph(par, pos);
2821 void LyXText::SetCursor(LyXParagraph * par,
2822 LyXParagraph::size_type pos) const
2824 LyXCursor old_cursor = cursor;
2825 SetCursorIntern(par, pos);
2826 DeleteEmptyParagraphMechanism(old_cursor);
2830 void LyXText::SetCursorIntern(LyXParagraph * par,
2831 LyXParagraph::size_type pos) const
2836 LyXParagraph * tmppar;
2838 // correct the cursor position if impossible
2839 if (pos > par->Last()){
2840 tmppar = par->ParFromPos(pos);
2841 pos = par->PositionInParFromPos(pos);
2844 if (par->IsDummy() && par->previous &&
2845 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2846 while (par->previous &&
2847 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2848 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2849 par = par->previous ;
2850 if (par->IsDummy() &&
2851 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2852 pos += par->text.size() + 1;
2854 if (par->previous) {
2855 par = par->previous;
2857 pos += par->text.size() + 1;
2863 /* get the cursor y position in text */
2864 row = GetRow(par, pos, y);
2865 /* y is now the beginning of the cursor row */
2867 /* y is now the cursor baseline */
2870 /* now get the cursors x position */
2873 float fill_separator, fill_hfill, fill_label_hfill;
2874 left_margin = LabelEnd(row);
2875 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2876 LyXParagraph::size_type main_body =
2877 BeginningOfMainBody(row->par);
2878 /* table stuff -- begin*/
2879 if (row->par->table) {
2880 int cell = NumberOfCell(row->par, row->pos);
2882 x += row->par->table->GetBeginningOfTextInCell(cell);
2883 for (pos = row->pos; pos < cursor.pos; pos++) {
2884 if (row->par->IsNewline(pos)) {
2885 x = x_old + row->par->table->WidthOfColumn(cell);
2888 x += row->par->table->GetBeginningOfTextInCell(cell);
2890 x += SingleWidth(row->par, pos);
2894 /* table stuff -- end*/
2896 for (pos = row->pos; pos < cursor.pos; pos++) {
2897 if (pos && pos == main_body
2898 && !row->par->IsLineSeparator(pos - 1)) {
2899 x += GetFont(row->par, -2).stringWidth(
2900 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2901 if (x < left_margin)
2905 x += SingleWidth(row->par, pos);
2906 if (HfillExpansion(row, pos)) {
2907 if (pos >= main_body)
2910 x += fill_label_hfill;
2912 else if (pos >= main_body && row->par->IsSeparator(pos)) {
2916 if (pos + 1 == main_body
2917 && row->par->IsLineSeparator(pos)) {
2918 x += GetFont(row->par, -2).stringWidth(
2919 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2920 if (row->par->IsLineSeparator(pos))
2921 x -= SingleWidth(row->par, pos);
2922 if (x < left_margin)
2929 cursor.x_fix = cursor.x;
2933 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2934 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2935 && !cursor.par->IsSeparator(cursor.pos))
2937 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2938 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2940 current_font = cursor.par->GetFontSettings(cursor.pos);
2941 real_current_font = GetFont(cursor.par, cursor.pos);
2946 void LyXText::SetCursorFromCoordinates(int x, long y) const
2948 LyXCursor old_cursor = cursor;
2950 /* get the row first */
2952 Row * row = GetRowNearY(y);
2954 cursor.par = row->par;
2956 int column = GetColumnNearX(row, x);
2957 cursor.pos = row->pos + column;
2959 cursor.y = y + row->baseline;
2964 (cursor.pos == cursor.par->Last()
2965 || cursor.par->IsSeparator(cursor.pos)
2966 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2967 && !cursor.par->IsSeparator(cursor.pos))
2969 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2970 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2972 current_font = cursor.par->GetFontSettings(cursor.pos);
2973 real_current_font = GetFont(cursor.par, cursor.pos);
2975 DeleteEmptyParagraphMechanism(old_cursor);
2979 void LyXText::CursorLeft() const
2982 if (cursor.par->table) {
2983 int cell = NumberOfCell(cursor.par, cursor.pos);
2984 if (cursor.par->table->IsContRow(cell) &&
2985 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2992 void LyXText::CursorLeftIntern() const
2994 if (cursor.pos > 0) {
2995 SetCursor(cursor.par, cursor.pos - 1);
2997 else if (cursor.par->Previous()) {
2998 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3003 void LyXText::CursorRight() const
3005 CursorRightIntern();
3006 if (cursor.par->table) {
3007 int cell = NumberOfCell(cursor.par, cursor.pos);
3008 if (cursor.par->table->IsContRow(cell) &&
3009 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3016 void LyXText::CursorRightIntern() const
3018 if (cursor.pos < cursor.par->Last()) {
3019 SetCursor(cursor.par, cursor.pos + 1);
3021 else if (cursor.par->Next()) {
3022 SetCursor(cursor.par->Next(), 0);
3027 void LyXText::CursorUp() const
3029 SetCursorFromCoordinates(cursor.x_fix,
3030 cursor.y - cursor.row->baseline - 1);
3031 if (cursor.par->table) {
3032 int cell = NumberOfCell(cursor.par, cursor.pos);
3033 if (cursor.par->table->IsContRow(cell) &&
3034 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3041 void LyXText::CursorDown() const
3043 if (cursor.par->table &&
3044 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3047 SetCursorFromCoordinates(cursor.x_fix,
3048 cursor.y - cursor.row->baseline
3049 + cursor.row->height + 1);
3050 if (cursor.par->table) {
3051 int cell = NumberOfCell(cursor.par, cursor.pos);
3052 int cell_above = cursor.par->table->GetCellAbove(cell);
3053 while(cursor.par->table &&
3054 cursor.par->table->IsContRow(cell) &&
3055 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3056 SetCursorFromCoordinates(cursor.x_fix,
3057 cursor.y - cursor.row->baseline
3058 + cursor.row->height + 1);
3059 if (cursor.par->table) {
3060 cell = NumberOfCell(cursor.par, cursor.pos);
3061 cell_above = cursor.par->table->GetCellAbove(cell);
3068 void LyXText::CursorUpParagraph() const
3070 if (cursor.pos > 0) {
3071 SetCursor(cursor.par, 0);
3073 else if (cursor.par->Previous()) {
3074 SetCursor(cursor.par->Previous(), 0);
3079 void LyXText::CursorDownParagraph() const
3081 if (cursor.par->Next()) {
3082 SetCursor(cursor.par->Next(), 0);
3084 SetCursor(cursor.par, cursor.par->Last());
3090 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3092 bool deleted = false;
3094 // this is the delete-empty-paragraph-mechanism.
3095 if (selection) return;
3097 #ifdef FIX_DOUBLE_SPACE
3098 /* Ok I'll put some comments here about what is missing.
3099 I have fixed BackSpace (and thus Delete) to not delete
3100 double-spaces automagically. I have also changed Cut,
3101 Copy and Paste to hopefully do some sensible things.
3102 There are still some small problems that can lead to
3103 double spaces stored in the document file or space at
3104 the beginning of paragraphs. This happens if you have
3105 the cursor betwenn to spaces and then save. Or if you
3106 cut and paste and the selection have a space at the
3107 beginning and then save right after the paste. I am
3108 sure none of these are very hard to fix, but I will
3109 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3110 that I can get some feedback. (Lgb)
3113 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3114 // delete the LineSeparator.
3117 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3118 // delete the LineSeparator.
3121 // If the pos around the old_cursor were spaces, delete one of them.
3122 if (!(old_cursor.par == cursor.par && old_cursor.pos == cursor.pos)
3123 && old_cursor.pos > 0
3124 && old_cursor.pos < old_cursor.par->Last()
3125 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3126 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3127 old_cursor.par->Erase(old_cursor.pos - 1);
3128 RedoParagraphs(old_cursor, old_cursor.par->Next());
3129 // or RedoDrawingOfParagraph(old_cursor);
3131 if (old_cursor.par == cursor.par &&
3132 cursor.pos > old_cursor.pos)
3133 SetCursor(cursor.par, cursor.pos - 1);
3135 SetCursor(cursor.par, cursor.pos);
3140 // Paragraph should not be deleted if empty
3141 if ((textclasslist.Style(parameters->textclass,
3142 old_cursor.par->GetLayout())).keepempty)
3145 LyXCursor tmpcursor;
3147 if (old_cursor.par != cursor.par) {
3148 if ( (old_cursor.par->Last() == 0
3149 || (old_cursor.par->Last() == 1
3150 && (old_cursor.par->IsLineSeparator(0))))
3151 && old_cursor.par->FirstPhysicalPar()
3152 == old_cursor.par->LastPhysicalPar()) {
3154 // ok, we will delete anything
3156 // make sure that you do not delete any environments
3157 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3158 !(old_cursor.row->previous
3159 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3160 && !(old_cursor.row->next
3161 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3163 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3164 ((old_cursor.row->previous
3165 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3167 (old_cursor.row->next
3168 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3170 status = LyXText::NEED_MORE_REFRESH;
3173 if (old_cursor.row->previous) {
3174 refresh_row = old_cursor.row->previous;
3175 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3177 cursor = old_cursor; // that undo can restore the right cursor position
3178 LyXParagraph * endpar = old_cursor.par->next;
3179 if (endpar && endpar->GetDepth()) {
3180 while (endpar && endpar->GetDepth()) {
3181 endpar = endpar->LastPhysicalPar()->Next();
3184 SetUndo(Undo::DELETE,
3185 old_cursor.par->previous,
3190 RemoveRow(old_cursor.row);
3191 if (params->paragraph == old_cursor.par) {
3192 params->paragraph = params->paragraph->next;
3195 delete old_cursor.par;
3197 /* Breakagain the next par. Needed
3198 * because of the parindent that
3199 * can occur or dissappear. The
3200 * next row can change its height,
3201 * if there is another layout before */
3202 if (refresh_row->next) {
3203 BreakAgain(refresh_row->next);
3204 UpdateCounters(refresh_row);
3206 SetHeightOfRow(refresh_row);
3208 refresh_row = old_cursor.row->next;
3209 refresh_y = old_cursor.y - old_cursor.row->baseline;
3212 cursor = old_cursor; // that undo can restore the right cursor position
3213 LyXParagraph *endpar = old_cursor.par->next;
3214 if (endpar && endpar->GetDepth()) {
3215 while (endpar && endpar->GetDepth()) {
3216 endpar = endpar->LastPhysicalPar()->Next();
3219 SetUndo(Undo::DELETE,
3220 old_cursor.par->previous,
3225 RemoveRow(old_cursor.row);
3227 if (params->paragraph == old_cursor.par) {
3228 params->paragraph = params->paragraph->next;
3230 delete old_cursor.par;
3232 /* Breakagain the next par. Needed
3233 because of the parindent that can
3234 occur or dissappear.
3235 The next row can change its height,
3236 if there is another layout before
3239 BreakAgain(refresh_row);
3240 UpdateCounters(refresh_row->previous);
3245 SetCursor(cursor.par, cursor.pos);
3247 /* if (cursor.y > old_cursor.y)
3248 cursor.y -= old_cursor.row->height; */
3250 if (sel_cursor.par == old_cursor.par
3251 && sel_cursor.pos == sel_cursor.pos) {
3252 // correct selection
3253 sel_cursor = cursor;
3258 if (old_cursor.par->ClearParagraph()){
3259 RedoParagraphs(old_cursor, old_cursor.par->Next());
3261 SetCursor(cursor.par, cursor.pos);
3262 sel_cursor = cursor;
3267 else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3268 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3269 if (old_cursor.par->table->IsContRow(cell) &&
3270 IsEmptyTableRow(old_cursor)) {
3271 RemoveTableRow(const_cast<LyXCursor*>(&old_cursor));
3279 LyXParagraph * LyXText::GetParFromID(int id)
3281 LyXParagraph * result = FirstParagraph();
3282 while (result && result->id() != id)
3283 result = result->next;
3289 bool LyXText::TextUndo()
3291 // returns false if no undo possible
3292 Undo * undo = params->undostack.pop();
3297 .push(CreateUndo(undo->kind,
3298 GetParFromID(undo->number_of_before_par),
3299 GetParFromID(undo->number_of_behind_par)));
3301 return TextHandleUndo(undo);
3305 bool LyXText::TextRedo()
3307 // returns false if no redo possible
3308 Undo * undo = params->redostack.pop();
3313 .push(CreateUndo(undo->kind,
3314 GetParFromID(undo->number_of_before_par),
3315 GetParFromID(undo->number_of_behind_par)));
3317 return TextHandleUndo(undo);
3321 bool LyXText::TextHandleUndo(Undo * undo)
3323 // returns false if no undo possible
3324 bool result = false;
3326 LyXParagraph * before =
3327 GetParFromID(undo->number_of_before_par);
3328 LyXParagraph * behind =
3329 GetParFromID(undo->number_of_behind_par);
3330 LyXParagraph * tmppar;
3331 LyXParagraph * tmppar2;
3332 LyXParagraph * tmppar3;
3333 LyXParagraph * tmppar4;
3334 LyXParagraph * endpar;
3335 LyXParagraph * tmppar5;
3337 // if there's no before take the beginning
3338 // of the document for redoing
3340 SetCursorIntern(FirstParagraph(), 0);
3342 // replace the paragraphs with the undo informations
3344 tmppar3 = undo->par;
3345 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3348 while (tmppar4->next)
3349 tmppar4 = tmppar4->next;
3350 } // get last undo par
3352 // now remove the old text if there is any
3353 if (before != behind || (!behind && !before)){
3355 tmppar5 = before->next;
3357 tmppar5 = params->paragraph;
3359 while (tmppar5 && tmppar5 != behind){
3361 tmppar5 = tmppar5->next;
3362 // a memory optimization for edit: Only layout information
3363 // is stored in the undo. So restore the text informations.
3364 if (undo->kind == Undo::EDIT){
3365 tmppar2->text = tmppar->text;
3366 tmppar->text.clear();
3367 //tmppar->text.erase(tmppar->text.begin(),
3368 // tmppar->text.end());
3369 tmppar2 = tmppar2->next;
3371 if ( currentrow && currentrow->par == tmppar )
3372 currentrow = currentrow -> previous;
3377 // put the new stuff in the list if there is one
3380 before->next = tmppar3;
3382 params->paragraph = tmppar3;
3383 tmppar3->previous = before;
3387 params->paragraph = behind;
3390 tmppar4->next = behind;
3392 behind->previous = tmppar4;
3396 // Set the cursor for redoing
3398 SetCursorIntern(before->FirstSelfrowPar(), 0);
3399 // check wether before points to a closed float and open it if necessary
3400 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3401 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3403 while (tmppar4->previous &&
3404 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3405 tmppar4 = tmppar4->previous;
3406 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3407 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3408 tmppar4 = tmppar4->next;
3413 // open a cosed footnote at the end if necessary
3414 if (behind && behind->previous &&
3415 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3416 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3417 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3418 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3419 behind = behind->next;
3423 // calculate the endpar for redoing the paragraphs.
3425 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3426 endpar = behind->LastPhysicalPar()->Next();
3428 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3433 tmppar = GetParFromID(undo->number_of_cursor_par);
3434 RedoParagraphs(cursor, endpar);
3436 SetCursorIntern(tmppar, undo->cursor_pos);
3437 UpdateCounters(cursor.row);
3447 void LyXText::FinishUndo()
3449 // makes sure the next operation will be stored
3450 undo_finished = True;
3454 void LyXText::FreezeUndo()
3456 // this is dangerous and for internal use only
3461 void LyXText::UnFreezeUndo()
3463 // this is dangerous and for internal use only
3464 undo_frozen = false;
3468 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3469 LyXParagraph const * behind) const
3472 params->undostack.push(CreateUndo(kind, before, behind));
3473 params->redostack.clear();
3477 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3478 LyXParagraph const * behind)
3480 params->redostack.push(CreateUndo(kind, before, behind));
3484 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3485 LyXParagraph const * behind) const
3487 int before_number = -1;
3488 int behind_number = -1;
3490 before_number = before->id();
3492 behind_number = behind->id();
3493 // Undo::EDIT and Undo::FINISH are
3494 // always finished. (no overlapping there)
3495 // overlapping only with insert and delete inside one paragraph:
3496 // Nobody wants all removed character
3497 // appear one by one when undoing.
3498 // EDIT is special since only layout information, not the
3499 // contents of a paragaph are stored.
3500 if (!undo_finished && kind != Undo::EDIT &&
3501 kind != Undo::FINISH){
3502 // check wether storing is needed
3503 if (!params->undostack.empty() &&
3504 params->undostack.top()->kind == kind &&
3505 params->undostack.top()->number_of_before_par == before_number &&
3506 params->undostack.top()->number_of_behind_par == behind_number ){
3511 // create a new Undo
3512 LyXParagraph * undopar;
3513 LyXParagraph * tmppar;
3514 LyXParagraph * tmppar2;
3516 LyXParagraph * start = 0;
3517 LyXParagraph * end = 0;
3520 start = before->next;
3522 start = FirstParagraph();
3524 end = behind->previous;
3526 end = FirstParagraph();
3532 && start != end->next
3533 && (before != behind || (!before && !behind))) {
3535 tmppar2 = tmppar->Clone();
3536 tmppar2->id(tmppar->id());
3538 // a memory optimization: Just store the layout information
3540 if (kind == Undo::EDIT){
3541 tmppar2->text.clear();
3546 while (tmppar != end && tmppar->next) {
3547 tmppar = tmppar->next;
3548 tmppar2->next = tmppar->Clone();
3549 tmppar2->next->id(tmppar->id());
3550 // a memory optimization: Just store the layout
3551 // information when only edit
3552 if (kind == Undo::EDIT){
3553 tmppar2->next->text.clear();
3555 tmppar2->next->previous = tmppar2;
3556 tmppar2 = tmppar2->next;
3560 undopar = 0; // nothing to replace (undo of delete maybe)
3562 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3563 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3565 Undo * undo = new Undo(kind,
3566 before_number, behind_number,
3567 cursor_par, cursor_pos,
3570 undo_finished = false;
3575 void LyXText::SetCursorParUndo()
3577 SetUndo(Undo::FINISH,
3578 cursor.par->ParFromPos(cursor.pos)->previous,
3579 cursor.par->ParFromPos(cursor.pos)->next);
3583 void LyXText::RemoveTableRow(LyXCursor * cur) const
3589 // move to the previous row
3590 int cell_act = NumberOfCell(cur->par, cur->pos);
3593 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3596 !cur->par->table->IsFirstCell(cell_act)) {
3598 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3603 // now we have to pay attention if the actual table is the
3604 // main row of TableContRows and if yes to delete all of them
3609 // delete up to the next row
3610 while (cur->pos < cur->par->Last() &&
3612 || !cur->par->table->IsFirstCell(cell_act))) {
3613 while (cur->pos < cur->par->Last() &&
3614 !cur->par->IsNewline(cur->pos))
3615 cur->par->Erase(cur->pos);
3618 if (cur->pos < cur->par->Last())
3619 cur->par->Erase(cur->pos);
3621 if (cur->pos && cur->pos == cur->par->Last()) {
3623 cur->par->Erase(cur->pos); // no newline at very end!
3625 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3626 !cur->par->table->IsContRow(cell_org) &&
3627 cur->par->table->IsContRow(cell));
3628 cur->par->table->DeleteRow(cell_org);
3634 bool LyXText::IsEmptyTableRow(LyXCursor const & old_cursor) const
3636 if (!old_cursor.par->table)
3638 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3639 int pos = old_cursor.pos;
3640 int cell = NumberOfCell(old_cursor.par, pos);
3642 // search first charater of this table row
3643 while (pos && !old_cursor.par->table->IsFirstCell(cell)) {
3645 while (pos && !old_cursor.par->IsNewline(pos-1))
3649 if (!old_cursor.par->IsNewline(pos))
3653 while ((pos < old_cursor.par->Last()) &&
3654 !old_cursor.par->table->IsFirstCell(cell)) {
3655 if (!old_cursor.par->IsNewline(pos))
3667 bool LyXText::IsEmptyTableCell() const
3669 LyXParagraph::size_type pos = cursor.pos - 1;
3670 while (pos >= 0 && pos < cursor.par->Last()
3671 && !cursor.par->IsNewline(pos))
3673 return cursor.par->IsNewline(pos + 1);
3677 void LyXText::toggleAppendix(){
3678 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3679 bool start = !par->start_of_appendix;
3681 // ensure that we have only one start_of_appendix in this document
3682 LyXParagraph * tmp = FirstParagraph();
3683 for (; tmp; tmp = tmp->next)
3684 tmp->start_of_appendix = 0;
3685 par->start_of_appendix = start;
3687 // we can set the refreshing parameters now
3688 status = LyXText::NEED_MORE_REFRESH;
3690 refresh_row = 0; // not needed for full update
3692 SetCursor(cursor.par, cursor.pos);