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
17 #pragma implementation "lyxtext.h"
18 #pragma implementation "undo.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"
36 extern MiniBuffer *minibuffer;
39 LyXText::LyXText(int pw, Buffer *p)
46 parameters = &p->params;
50 status = LyXText::UNCHANGED;
51 LyXParagraph *par = p->paragraph;
52 current_font = GetFont(par, 0);
57 InsertParagraph(par, lastrow);
60 /* set cursor at the very top position */
61 selection = true; /* these setting is necessary
62 * because of the delete-empty-
63 * paragraph mechanism in
65 SetCursor(firstrow->par, 0);
70 /* no rebreak necessary */
76 // Default layouttype for copy environment type
84 // Delete all rows, this does not touch the paragraphs!
85 Row *tmprow = firstrow;
87 tmprow = firstrow->next;
94 // Gets the fully instantiated font at a given position in a paragraph
95 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
96 // The difference is that this one is used for displaying, and thus we
97 // are allowed to make cosmetic improvements. For instance make footnotes
99 // If position is -1, we get the layout font of the paragraph.
100 // If position is -2, we get the font of the manual label of the paragraph.
101 LyXFont LyXText::GetFont(LyXParagraph* par, int pos)
104 lyxstyle.Style(parameters->textclass, par->GetLayout());
106 char par_depth = par->GetDepth();
107 // We specialize the 95% common case:
108 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
111 if (layout->labeltype == LABEL_MANUAL
112 && pos < BeginningOfMainBody(par)) {
114 return par->GetFontSettings(pos).
115 realize(layout->reslabelfont);
117 return par->GetFontSettings(pos).
118 realize(layout->resfont);
121 // process layoutfont for pos == -1 and labelfont for pos < -1
123 return layout->resfont;
125 return layout->reslabelfont;
129 // The uncommon case need not be optimized as much
131 LyXFont layoutfont, tmpfont;
135 if (pos < BeginningOfMainBody(par)) {
137 layoutfont = layout->labelfont;
140 layoutfont = layout->font;
142 tmpfont = par->GetFontSettings(pos);
143 tmpfont.realize(layoutfont);
146 // process layoutfont for pos == -1 and labelfont for pos < -1
148 tmpfont = layout->font;
150 tmpfont = layout->labelfont;
153 // Resolve against environment font information
154 //if (par->GetDepth()){ // already in while condition
155 while (par && par_depth && !tmpfont.resolved()) {
156 par = par->DepthHook(par_depth - 1);
158 tmpfont.realize(lyxstyle.
159 Style(parameters->textclass,
160 par->GetLayout())->font);
161 par_depth = par->GetDepth();
166 tmpfont.realize(lyxstyle.TextClass(parameters->textclass)->defaultfont);
168 // Cosmetic improvement: If this is an open footnote, make the font
170 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
171 && par->footnotekind == LyXParagraph::FOOTNOTE) {
179 void LyXText::SetCharFont(LyXParagraph *par, int pos, LyXFont font)
181 /* let the insets convert their font */
182 if (par->GetChar(pos) == LYX_META_INSET) {
183 if (par->GetInset(pos))
184 font = par->GetInset(pos)->ConvertFont(font);
187 LyXLayout *layout = lyxstyle.Style(parameters->textclass,
190 // Get concrete layout font to reduce against
193 if (pos < BeginningOfMainBody(par))
194 layoutfont = layout->labelfont;
196 layoutfont = layout->font;
198 // Realize against environment font information
199 if (par->GetDepth()){
200 LyXParagraph * tp = par;
201 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
202 tp = tp->DepthHook(tp->GetDepth()-1);
204 layoutfont.realize(lyxstyle.
205 Style(parameters->textclass,
206 tp->GetLayout())->font);
210 layoutfont.realize(lyxstyle.TextClass(parameters->textclass)->defaultfont);
212 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
213 && par->footnotekind == LyXParagraph::FOOTNOTE) {
214 layoutfont.decSize();
217 // Now, reduce font against full layout font
218 font.reduce(layoutfont);
220 par->SetFont(pos, font);
224 /* inserts a new row behind the specified row, increments
225 * the touched counters */
226 void LyXText::InsertRow(Row *row, LyXParagraph *par, int pos)
228 Row *tmprow = new Row;
230 tmprow->previous = 0;
231 tmprow->next = firstrow;
235 tmprow->previous = row;
236 tmprow->next = row->next;
241 tmprow->next->previous = tmprow;
243 if (tmprow->previous)
244 tmprow->previous->next = tmprow;
252 number_of_rows++; /* one more row */
256 /* removes the row and reset the touched counters */
257 void LyXText::RemoveRow(Row *row)
259 /* this must not happen before the currentrow for clear reasons.
260 so the trick is just to set the current row onto the previous
263 GetRow(row->par, row->pos, unused_y);
264 currentrow = currentrow->previous;
266 currentrow_y -= currentrow->height;
271 row->next->previous = row->previous;
272 if (!row->previous) {
273 firstrow = row->next;
276 row->previous->next = row->next;
279 lastrow = row->previous;
281 height -= row->height; /* the text becomes smaller */
284 number_of_rows--; /* one row less */
287 /* remove all following rows of the paragraph of the specified row. */
288 void LyXText::RemoveParagraph(Row *row)
290 LyXParagraph *tmppar;
296 while (row && row->par == tmppar) {
304 /* insert the specified paragraph behind the specified row */
305 void LyXText::InsertParagraph(LyXParagraph *par, Row *row)
307 InsertRow(row, par, 0); /* insert a new row, starting
310 SetCounter(par); /* set the counters */
312 /* and now append the whole paragraph behind the new row */
314 firstrow->height = 0;
315 AppendParagraph(firstrow);
318 row->next->height = 0;
319 AppendParagraph(row->next);
324 void LyXText::ToggleFootnote()
328 par = cursor.par->ParFromPos(cursor.pos);
329 if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
331 minibuffer->Set(_("Opened float"));
334 minibuffer->Set(_("Closed float"));
340 void LyXText::OpenStuff()
342 if (cursor.pos == 0 && cursor.par->bibkey){
343 cursor.par->bibkey->Edit(0,0);
345 else if (cursor.pos < cursor.par->Last()
346 && cursor.par->GetChar(cursor.pos) == LYX_META_INSET
347 && cursor.par->GetInset(cursor.pos)->Editable()) {
348 minibuffer->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
349 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
351 cursor.par->GetInset(cursor.pos)->Edit(0,0);
359 void LyXText::CloseFootnote()
361 LyXParagraph *par, *endpar,*tmppar;
364 par = cursor.par->ParFromPos(cursor.pos);
366 /* if the cursor is not in an open footnote, or
367 * there is no open footnote in this paragraph, just return. */
368 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
371 || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
372 minibuffer->Set(_("Nothing to do"));
376 /* ok, move the cursor right before the footnote */
378 /* just a little faster than using CursorRight() */
379 for (cursor.pos=0; cursor.par->ParFromPos(cursor.pos)!=par; cursor.pos++);
380 /* now the cursor is at the beginning of the physical par */
381 SetCursor(cursor.par, cursor.pos + cursor.par->ParFromPos(cursor.pos)->last);
384 /* we are in a footnote, so let us move at the beginning */
385 /* while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
386 cursor.par = cursor.par->Previous();
388 SetCursor(cursor.par, cursor.par->Last()); */
389 /* this is just faster than using just CursorLeft() */
392 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
393 /* just a little bit faster than movin the cursor */
394 tmppar = tmppar->Previous();
396 SetCursor(tmppar, tmppar->Last());
399 /* the cursor must be exactly before the footnote */
400 par = cursor.par->ParFromPos(cursor.pos);
402 status = LyXText::NEED_MORE_REFRESH;
403 refresh_row = cursor.row;
404 refresh_y = cursor.y - cursor.row->baseline;
407 endpar = par->NextAfterFootnote()->Next();
410 tmppar->CloseFootnote(cursor.pos);
412 /* set the dimensions of the cursor row */
413 /* row->fill = Fill(row, paperwidth);
414 SetHeightOfRow(row); */
416 while (tmppar != endpar) {
417 RemoveRow(row->next);
419 tmppar = row->next->par;
424 AppendParagraph(cursor.row);
426 SetCursor(cursor.par, cursor.pos);
430 if (cursor.row->next)
431 SetHeightOfRow(cursor.row->next);
435 /* used in setlayout */
436 // Asger is not sure we want to do this...
437 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph *par)
439 LyXFont layoutfont, tmpfont;
443 LyXLayout* layout = lyxstyle.Style(parameters->textclass, par->GetLayout());
445 for (pos = 0; pos < par->Last(); pos++) {
446 if (pos < BeginningOfMainBody(par))
447 layoutfont = layout->labelfont;
449 layoutfont = layout->font;
451 tmpfont = par->GetFontSettings(pos);
452 tmpfont.reduce(layoutfont);
453 par->SetFont(pos, tmpfont);
458 /* set layout over selection and make a total rebreak of those paragraphs */
459 void LyXText::SetLayout(char layout)
463 /* if there is no selection just set the layout 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()) {
475 endpar = endpar->LastPhysicalPar()->Next();
480 endpar = endpar->Next(); /* because of parindents etc. */
484 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
487 tmpcursor = cursor; /* store the current cursor */
489 /* ok we have a selection. This is always between sel_start_cursor
490 * and sel_end cursor */
491 cursor = sel_start_cursor;
493 LyXLayout * lyxlayout = lyxstyle.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. */
572 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
575 LyXCursor tmpcursor = cursor; /* store the current cursor */
577 /* ok we have a selection. This is always between sel_start_cursor
578 * and sel_end cursor */
579 cursor = sel_start_cursor;
581 bool anything_changed = false;
584 // NOTE: you can't change the depth of a bibliography entry
585 if (cursor.par->footnoteflag ==
586 sel_start_cursor.par->footnoteflag
587 && lyxstyle.Style(parameters->textclass,
588 cursor.par->GetLayout()
589 )->labeltype != LABEL_BIBLIO) {
590 LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
592 && (prev->GetDepth() - cursor.par->GetDepth() > 0
593 || (prev->GetDepth() == cursor.par->GetDepth()
594 && lyxstyle.Style(parameters->textclass,
595 prev->GetLayout())->isEnvironment()))) {
596 cursor.par->FirstPhysicalPar()->depth++;
597 anything_changed = true;
600 if (cursor.par == sel_end_cursor.par)
602 cursor.par = cursor.par->Next();
605 /* if nothing changed set all depth to 0 */
606 if (!anything_changed) {
607 cursor = sel_start_cursor;
608 while (cursor.par != sel_end_cursor.par) {
609 cursor.par->FirstPhysicalPar()->depth = 0;
610 cursor.par = cursor.par->Next();
612 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
613 cursor.par->FirstPhysicalPar()->depth = 0;
616 RedoParagraphs(sel_start_cursor, endpar);
618 /* we have to reset the selection, because the
619 * geometry could have changed */
620 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
622 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
623 UpdateCounters(cursor.row);
626 SetCursor(tmpcursor.par, tmpcursor.pos);
630 /* decrement depth over selection and
631 * make a total rebreak of those paragraphs */
632 void LyXText::DecDepth()
634 /* if there is no selection just set the layout of the current paragraph */
636 sel_start_cursor = cursor; /* dummy selection */
637 sel_end_cursor = cursor;
640 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
641 LyXParagraph *undoendpar = endpar;
643 if (endpar && endpar->GetDepth()) {
644 while (endpar && endpar->GetDepth()) {
645 endpar = endpar->LastPhysicalPar()->Next();
650 endpar = endpar->Next(); /* because of parindents etc. */
654 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
657 LyXCursor tmpcursor = cursor; /* store the current cursor */
659 /* ok we have a selection. This is always between sel_start_cursor
660 * and sel_end cursor */
661 cursor = sel_start_cursor;
664 if (cursor.par->footnoteflag ==
665 sel_start_cursor.par->footnoteflag) {
666 if (cursor.par->FirstPhysicalPar()->depth)
667 cursor.par->FirstPhysicalPar()->depth--;
669 if (cursor.par == sel_end_cursor.par)
671 cursor.par = cursor.par->Next();
674 RedoParagraphs(sel_start_cursor, endpar);
676 /* we have to reset the selection, because the
677 * geometry could have changed */
678 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
680 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
681 UpdateCounters(cursor.row);
684 SetCursor(tmpcursor.par, tmpcursor.pos);
688 /* set font over selection and make a total rebreak of those paragraphs */
689 void LyXText::SetFont(LyXFont font, bool toggleall)
691 /* if there is no selection just set the current_font */
693 // Determine basis font
695 if (cursor.pos < BeginningOfMainBody(cursor.par))
696 layoutfont = GetFont(cursor.par, -2);
698 layoutfont = GetFont(cursor.par, -1);
700 // Update current font
701 real_current_font.update(font,toggleall);
703 // Reduce to implicit settings
704 current_font = real_current_font;
705 current_font.reduce(layoutfont);
706 // And resolve it completely
707 real_current_font.realize(layoutfont);
711 LyXCursor tmpcursor = cursor; /* store the current cursor */
713 /* ok we have a selection. This is always between sel_start_cursor
714 * and sel_end cursor */
717 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
718 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
719 cursor = sel_start_cursor;
720 while (cursor.par != sel_end_cursor.par ||
721 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
722 && cursor.pos < sel_end_cursor.pos))
724 if (cursor.pos < cursor.par->Last()
725 && cursor.par->footnoteflag
726 == sel_start_cursor.par->footnoteflag) { /* an open footnote
729 LyXFont newfont = GetFont(cursor.par,cursor.pos);
730 newfont.update(font,toggleall);
731 SetCharFont(cursor.par, cursor.pos, newfont);
735 cursor.par = cursor.par->Next();
739 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
741 /* we have to reset the selection, because the
742 * geometry could have changed */
743 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
745 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
748 SetCursor(tmpcursor.par, tmpcursor.pos);
752 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
755 LyXParagraph *first_phys_par;
760 y = cursor.y - tmprow->baseline;
761 SetHeightOfRow(tmprow);
762 first_phys_par = tmprow->par->FirstPhysicalPar();
763 /* find the first row of the paragraph */
764 if (first_phys_par != tmprow->par)
765 while (tmprow->previous && 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(cursor.par, cursor.pos);
784 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
787 LyXParagraph *first_phys_par;
792 y = cursor.y - tmprow->baseline;
793 SetHeightOfRow(tmprow);
794 first_phys_par = tmprow->par->FirstPhysicalPar();
795 /* find the first row of the paragraph */
796 if (first_phys_par != tmprow->par)
797 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
798 tmprow = tmprow->previous;
801 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
802 tmprow = tmprow->previous;
807 /* we can set the refreshing parameters now */
808 if (status == LyXText::UNCHANGED || y < refresh_y) {
810 refresh_row = tmprow;
812 status = LyXText::NEED_MORE_REFRESH;
813 SetCursor(cursor.par, cursor.pos);
817 /* deletes and inserts again all paragaphs between the cursor
818 * and the specified par
819 * This function is needed after SetLayout and SetFont etc. */
820 void LyXText::RedoParagraphs(LyXCursor cursor, LyXParagraph *endpar)
822 Row *tmprow, *tmprow2;
823 LyXParagraph *tmppar, *first_phys_par;
828 y = cursor.y - tmprow->baseline;
830 if (!tmprow->previous){
831 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
834 first_phys_par = tmprow->par->FirstPhysicalPar();
835 /* find the first row of the paragraph */
836 if (first_phys_par != tmprow->par)
837 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
838 tmprow = tmprow->previous;
841 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
842 tmprow = tmprow->previous;
847 /* we can set the refreshing parameters now */
848 status = LyXText::NEED_MORE_REFRESH;
850 refresh_row = tmprow->previous; /* the real refresh row will
851 * be deleted, so I store
852 * the previous here */
855 tmppar = tmprow->next->par;
858 while (tmppar != endpar) {
859 RemoveRow(tmprow->next);
861 tmppar = tmprow->next->par;
866 /* remove the first one */
867 tmprow2 = tmprow; /* this is because tmprow->previous
869 tmprow = tmprow->previous;
872 tmppar = first_phys_par;
876 InsertParagraph(tmppar, tmprow);
879 while (tmprow->next && tmprow->next->par == tmppar)
880 tmprow = tmprow->next;
881 tmppar = tmppar->Next();
885 while (tmppar != endpar);
887 /* this is because of layout changes */
889 refresh_y -= refresh_row->height;
890 SetHeightOfRow(refresh_row);
893 refresh_row = firstrow;
895 SetHeightOfRow(refresh_row);
898 if (tmprow && tmprow->next)
899 SetHeightOfRow(tmprow->next);
901 /* restore the correct refresh row */
903 refresh_row = refresh_row->next;
905 refresh_row = firstrow;*/
909 int LyXText::FullRebreak()
911 if (need_break_row) {
912 BreakAgain(need_break_row);
920 /* important for the screen */
923 /* the cursor set functions have a special mechanism. When they
924 * realize, that you left an empty paragraph, they will delete it.
925 * They also delet the corresponding row */
927 /* need the selection cursor: */
928 void LyXText::SetSelection()
931 last_sel_cursor = sel_cursor;
932 sel_start_cursor = sel_cursor;
933 sel_end_cursor = sel_cursor;
938 /* first the toggling area */
939 if (cursor.y < last_sel_cursor.y ||
940 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
941 toggle_end_cursor = last_sel_cursor;
942 toggle_cursor = cursor;
945 toggle_end_cursor = cursor;
946 toggle_cursor = last_sel_cursor;
949 last_sel_cursor = cursor;
951 /* and now the whole selection */
953 if (sel_cursor.y < cursor.y ||
954 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
955 sel_end_cursor = cursor;
956 sel_start_cursor = sel_cursor;
959 sel_end_cursor = sel_cursor;
960 sel_start_cursor = cursor;
963 /* a selection with no contents is not a selection */
964 if (sel_start_cursor.x == sel_end_cursor.x &&
965 sel_start_cursor.y == sel_end_cursor.y)
970 void LyXText::ClearSelection()
977 void LyXText::CursorHome()
979 SetCursor(cursor.par, cursor.row->pos);
983 void LyXText::CursorEnd()
985 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
986 SetCursor(cursor.par, RowLast(cursor.row) + 1);
988 if (cursor.par->Last() &&
989 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
990 || cursor.par->IsNewline(RowLast(cursor.row))))
991 SetCursor(cursor.par, RowLast(cursor.row));
993 SetCursor(cursor.par, RowLast(cursor.row) + 1);
995 if (cursor.par->table) {
996 int cell = NumberOfCell(cursor.par, cursor.pos);
997 if (cursor.par->table->RowHasContRow(cell) &&
998 cursor.par->table->CellHasContRow(cell)<0) {
999 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1000 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1002 if (cursor.par->Last() &&
1003 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1004 || cursor.par->IsNewline(RowLast(cursor.row))))
1005 SetCursor(cursor.par, RowLast(cursor.row));
1007 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1014 void LyXText::CursorTop()
1016 while (cursor.par->Previous())
1017 cursor.par = cursor.par->Previous();
1018 SetCursor(cursor.par, 0);
1022 void LyXText::CursorBottom()
1024 while (cursor.par->Next())
1025 cursor.par = cursor.par->Next();
1026 SetCursor(cursor.par, cursor.par->Last());
1030 /* returns a pointer to the row near the specified y-coordinate
1031 * (relative to the whole text). y is set to the real beginning
1033 Row* LyXText::GetRowNearY(long& y)
1039 tmprow = currentrow;
1040 tmpy = currentrow_y;
1048 while (tmprow->next && tmpy + tmprow->height <= y) {
1049 tmpy += tmprow->height;
1050 tmprow = tmprow->next;
1053 while (tmprow->previous && tmpy > y) {
1054 tmprow = tmprow->previous;
1055 tmpy -= tmprow->height;
1058 currentrow = tmprow;
1059 currentrow_y = tmpy;
1061 y = tmpy; /* return the real y */
1066 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1068 // If the mask is completely neutral, tell user
1069 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1070 // Could only happen with user style
1071 minibuffer->Set(_("No font change defined. Use Character under"
1072 " the Layout menu to define font change."));
1076 // Try implicit word selection
1077 LyXCursor resetCursor = cursor;
1078 int implicitSelection = SelectWordWhenUnderCursor();
1081 SetFont(font,toggleall);
1082 //minibuffer->Set(_("Font style changed"));
1084 /* Implicit selections are cleared afterwards and cursor is set to the
1085 original position. */
1086 if (implicitSelection) {
1088 cursor = resetCursor;
1089 SetCursor( cursor.par, cursor.pos );
1090 sel_cursor = cursor;
1095 int LyXText::BeginningOfMainBody(LyXParagraph *par)
1097 if (lyxstyle.Style(parameters->textclass, par->GetLayout())->labeltype != LABEL_MANUAL)
1100 return par->BeginningOfMainBody();
1104 /* if there is a selection, reset every environment you can find
1105 * in the selection, otherwise just the environment you are in */
1106 void LyXText::MeltFootnoteEnvironment()
1108 LyXParagraph *tmppar, *firsttmppar;
1112 /* is is only allowed, if the cursor is IN an open footnote.
1113 * Otherwise it is too dangerous */
1114 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1117 SetUndo(Undo::FINISH,
1118 cursor.par->PreviousBeforeFootnote()->previous,
1119 cursor.par->NextAfterFootnote()->next);
1121 /* ok, move to the beginning of the footnote. */
1122 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1123 cursor.par = cursor.par->Previous();
1125 SetCursor(cursor.par, cursor.par->Last());
1126 /* this is just faster than using CursorLeft(); */
1128 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1129 tmppar = firsttmppar;
1130 /* tmppar is now the paragraph right before the footnote */
1132 char first_footnote_par_is_not_empty = tmppar->next->last;
1134 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1135 tmppar = tmppar->next; /* I use next instead of Next(),
1136 * because there cannot be any
1137 * footnotes in a footnote
1139 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1141 /* remember the captions and empty paragraphs */
1142 if ((lyxstyle.Style(parameters->textclass,
1143 tmppar->GetLayout())->labeltype == LABEL_SENSITIVE)
1145 tmppar->SetLayout(0);
1148 /* now we will paste the ex-footnote, if the layouts allow it */
1149 /* first restore the layout of the paragraph right behind the footnote*/
1151 tmppar->next->MakeSameLayout(cursor.par);
1154 if ((!tmppar->GetLayout() && !tmppar->table)
1155 || (tmppar->Next() && (!tmppar->Next()->Last()
1156 || tmppar->Next()->HasSameLayout(tmppar)))) {
1157 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1158 tmppar->Next()->Erase(0);
1159 tmppar->PasteParagraph();
1162 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1163 * by the pasting of the beginning */
1165 /* then the beginning */
1166 /* if there is no space between the text and the footnote, so we insert
1168 * (only if the previous par and the footnotepar are not empty!) */
1169 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1170 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1171 if (firsttmppar->last
1172 && !firsttmppar->IsSeparator(firsttmppar->last - 1)
1173 && first_footnote_par_is_not_empty) {
1174 firsttmppar->next->InsertChar(0, ' ');
1176 firsttmppar->PasteParagraph();
1179 /* now redo the paragaphs */
1180 RedoParagraphs(cursor, tmppar);
1182 SetCursor(cursor.par, cursor.pos);
1184 /* sometimes it can happen, that there is a counter change */
1185 Row *row = cursor.row;
1186 while (row->next && row->par != tmppar && row->next->par != tmppar)
1188 UpdateCounters(row);
1195 /* the DTP switches for paragraphs. LyX will store them in the
1196 * first physicla paragraph. When a paragraph is broken, the top settings
1197 * rest, the bottom settings are given to the new one. So I can make shure,
1198 * they do not duplicate themself and you cannnot make dirty things with
1201 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1202 bool pagebreak_top, bool pagebreak_bottom,
1203 VSpace space_top, VSpace space_bottom,
1205 string labelwidthstring,
1208 LyXCursor tmpcursor;
1210 LyXParagraph *tmppar;
1212 sel_start_cursor = cursor;
1213 sel_end_cursor = cursor;
1216 // make sure that the depth behind the selection are restored, too
1217 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1218 LyXParagraph *undoendpar = endpar;
1220 if (endpar && endpar->GetDepth()) {
1221 while (endpar && endpar->GetDepth()) {
1222 endpar = endpar->LastPhysicalPar()->Next();
1223 undoendpar = endpar;
1227 endpar = endpar->Next(); /* because of parindents etc. */
1231 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1235 tmppar = sel_end_cursor.par;
1236 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous())
1238 SetCursor(tmppar->FirstPhysicalPar(), 0);
1239 status = LyXText::NEED_MORE_REFRESH;
1240 refresh_row = cursor.row;
1241 refresh_y = cursor.y - cursor.row->baseline;
1242 if (cursor.par->footnoteflag ==
1243 sel_start_cursor.par->footnoteflag) {
1244 cursor.par->line_top = line_top;
1245 cursor.par->line_bottom = line_bottom;
1246 cursor.par->pagebreak_top = pagebreak_top;
1247 cursor.par->pagebreak_bottom = pagebreak_bottom;
1248 cursor.par->added_space_top = space_top;
1249 cursor.par->added_space_bottom = space_bottom;
1250 /* does the layout allow the new alignment? */
1251 if (align == LYX_ALIGN_LAYOUT)
1252 align = lyxstyle.Style(parameters->textclass, cursor.par->GetLayout())->align;
1253 if (align & lyxstyle.Style(parameters->textclass, cursor.par->GetLayout())->alignpossible) {
1254 if (align == lyxstyle.Style(parameters->textclass, cursor.par->GetLayout())->align)
1255 cursor.par->align = LYX_ALIGN_LAYOUT;
1257 cursor.par->align = align;
1259 cursor.par->SetLabelWidthString(labelwidthstring);
1260 cursor.par->noindent = noindent;
1264 tmprow = cursor.row;
1265 while (tmprow->next && tmprow->next->par->previous != cursor.par->LastPhysicalPar())
1266 tmprow = tmprow->next;
1267 SetHeightOfRow(tmprow);
1268 SetHeightOfRow(cursor.row); */
1269 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1272 RedoParagraphs(sel_start_cursor, endpar);
1275 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1276 sel_cursor = cursor;
1277 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1279 SetCursor(tmpcursor.par, tmpcursor.pos);
1283 void LyXText::SetParagraphExtraOpt(int type,
1286 int alignment, bool hfill,
1287 bool start_minipage)
1289 LyXCursor tmpcursor;
1291 LyXParagraph *tmppar;
1293 sel_start_cursor = cursor;
1294 sel_end_cursor = cursor;
1297 // make sure that the depth behind the selection are restored, too
1298 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1299 LyXParagraph *undoendpar = endpar;
1301 if (endpar && endpar->GetDepth()) {
1302 while (endpar && endpar->GetDepth()) {
1303 endpar = endpar->LastPhysicalPar()->Next();
1304 undoendpar = endpar;
1308 endpar = endpar->Next(); /* because of parindents etc. */
1312 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1315 tmppar = sel_end_cursor.par;
1316 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1317 SetCursor(tmppar->FirstPhysicalPar(), 0);
1318 status = LyXText::NEED_MORE_REFRESH;
1319 refresh_row = cursor.row;
1320 refresh_y = cursor.y - cursor.row->baseline;
1321 if (cursor.par->footnoteflag ==
1322 sel_start_cursor.par->footnoteflag) {
1323 if (type == PEXTRA_NONE) {
1324 if (cursor.par->pextra_type != PEXTRA_NONE) {
1325 cursor.par->UnsetPExtraType();
1326 cursor.par->pextra_type=PEXTRA_NONE;
1329 cursor.par->SetPExtraType(type,width,widthp);
1330 cursor.par->pextra_hfill = hfill;
1331 cursor.par->pextra_start_minipage = start_minipage;
1332 cursor.par->pextra_alignment = alignment;
1335 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1337 RedoParagraphs(sel_start_cursor, endpar);
1339 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1340 sel_cursor = cursor;
1341 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1343 SetCursor(tmpcursor.par, tmpcursor.pos);
1347 static char* alphaCounter(int n){
1348 static char result[2];
1361 /* set the counter of a paragraph. This includes the labels */
1362 void LyXText::SetCounter(LyXParagraph *par)
1366 /* this is only relevant for the beginning of paragraph */
1367 par = par->FirstPhysicalPar();
1369 LyXLayout* layout = lyxstyle.Style(parameters->textclass,
1372 LyXTextClass *textclass = lyxstyle.TextClass(parameters->textclass);
1374 /* copy the prev-counters to this one, unless this is the start of a
1375 footnote or of a bibliography or the very first paragraph */
1377 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1378 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1379 && par->footnotekind == LyXParagraph::FOOTNOTE)
1380 && !(lyxstyle.Style(parameters->textclass,
1381 par->Previous()->GetLayout()
1382 )->labeltype != LABEL_BIBLIO
1383 && layout->labeltype == LABEL_BIBLIO)) {
1384 for (i=0; i<10; i++) {
1385 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1387 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1388 if (!par->appendix && par->start_of_appendix){
1389 par->appendix = true;
1390 for (i=0; i<10; i++) {
1391 par->setCounter(i, 0);
1394 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1395 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1398 for (i=0; i<10; i++) {
1399 par->setCounter(i, 0);
1401 par->appendix = par->start_of_appendix;
1406 // if this is an open marginnote and this is the first
1407 // entry in the marginnote and the enclosing
1408 // environment is an enum/item then correct for the
1409 // LaTeX behaviour (ARRae)
1410 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1411 && par->footnotekind == LyXParagraph::MARGIN
1413 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1414 && (par->PreviousBeforeFootnote()
1415 && lyxstyle.Style(parameters->textclass,
1416 par->PreviousBeforeFootnote()->GetLayout()
1417 )->labeltype >= LABEL_COUNTER_ENUMI)) {
1418 // Any itemize or enumerate environment in a marginnote
1419 // that is embedded in an itemize or enumerate
1420 // paragraph is seen by LaTeX as being at a deeper
1421 // level within that enclosing itemization/enumeration
1422 // even if there is a "standard" layout at the start of
1428 /* Maybe we have to increment the enumeration depth.
1429 * BUT, enumeration in a footnote is considered in isolation from its
1430 * surrounding paragraph so don't increment if this is the
1431 * first line of the footnote
1432 * AND, bibliographies can't have their depth changed ie. they
1433 * are always of depth 0
1436 && par->Previous()->GetDepth() < par->GetDepth()
1437 && lyxstyle.Style(parameters->textclass,
1438 par->Previous()->GetLayout()
1439 )->labeltype == LABEL_COUNTER_ENUMI
1440 && par->enumdepth < 3
1441 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1442 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1443 && par->footnotekind == LyXParagraph::FOOTNOTE)
1444 && layout->labeltype != LABEL_BIBLIO) {
1448 /* Maybe we have to decrement the enumeration depth, see note above */
1450 && par->Previous()->GetDepth() > par->GetDepth()
1451 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1452 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1453 && par->footnotekind == LyXParagraph::FOOTNOTE)
1454 && layout->labeltype != LABEL_BIBLIO) {
1455 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1456 par->setCounter(6 + par->enumdepth,
1457 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1458 /* reset the counters.
1459 * A depth change is like a breaking layout
1461 for (i=6 + par->enumdepth + 1; i<10;i++)
1462 par->setCounter(i, 0);
1465 if (!par->labelstring.empty()) {
1466 par->labelstring.clear();
1469 if (layout->margintype == MARGIN_MANUAL) {
1470 if (par->labelwidthstring.empty()) {
1471 par->SetLabelWidthString(layout->labelstring);
1475 par->SetLabelWidthString(string());
1478 /* is it a layout that has an automatic label ? */
1479 if (layout->labeltype >= LABEL_FIRST_COUNTER) {
1481 i = layout->labeltype - LABEL_FIRST_COUNTER;
1482 if (i>=0 && i<=parameters->secnumdepth) {
1483 par->incCounter(i); // increment the counter
1485 char * s = new char[50];
1487 // Is there a label? Useful for Chapter layout
1488 if (!par->appendix){
1489 if (!layout->labelstring.empty())
1490 par->labelstring = layout->labelstring;
1492 par->labelstring.clear();
1495 if (!layout->labelstring_appendix.empty())
1496 par->labelstring = layout->labelstring_appendix;
1498 par->labelstring.clear();
1501 if (!par->appendix){
1502 switch (2 * LABEL_FIRST_COUNTER -
1503 textclass->maxcounter + i) {
1504 case LABEL_COUNTER_CHAPTER:
1506 par->getCounter(i));
1508 case LABEL_COUNTER_SECTION:
1510 par->getCounter(i - 1),
1511 par->getCounter(i));
1513 case LABEL_COUNTER_SUBSECTION:
1514 sprintf(s, "%d.%d.%d",
1515 par->getCounter(i-2),
1516 par->getCounter(i-1),
1517 par->getCounter(i));
1519 case LABEL_COUNTER_SUBSUBSECTION:
1520 sprintf(s, "%d.%d.%d.%d",
1521 par->getCounter(i-3),
1522 par->getCounter(i-2),
1523 par->getCounter(i-1),
1524 par->getCounter(i));
1526 case LABEL_COUNTER_PARAGRAPH:
1527 sprintf(s, "%d.%d.%d.%d.%d",
1528 par->getCounter(i-4),
1529 par->getCounter(i-3),
1530 par->getCounter(i-2),
1531 par->getCounter(i-1),
1532 par->getCounter(i));
1534 case LABEL_COUNTER_SUBPARAGRAPH:
1535 sprintf(s, "%d.%d.%d.%d.%d.%d",
1536 par->getCounter(i-5),
1537 par->getCounter(i-4),
1538 par->getCounter(i-3),
1539 par->getCounter(i-2),
1540 par->getCounter(i-1),
1541 par->getCounter(i));
1544 sprintf(s, "%d.", par->getCounter(i));
1549 switch (2 * LABEL_FIRST_COUNTER - textclass->maxcounter+ i) {
1550 case LABEL_COUNTER_CHAPTER:
1552 alphaCounter(par->getCounter(i)));
1554 case LABEL_COUNTER_SECTION:
1556 alphaCounter(par->getCounter(i - 1)),
1557 par->getCounter(i));
1559 case LABEL_COUNTER_SUBSECTION:
1560 sprintf(s, "%s.%d.%d",
1561 alphaCounter(par->getCounter(i-2)),
1562 par->getCounter(i-1),
1563 par->getCounter(i));
1565 case LABEL_COUNTER_SUBSUBSECTION:
1566 sprintf(s, "%s.%d.%d.%d",
1567 alphaCounter(par->getCounter(i-3)),
1568 par->getCounter(i-2),
1569 par->getCounter(i-1),
1570 par->getCounter(i));
1572 case LABEL_COUNTER_PARAGRAPH:
1573 sprintf(s, "%s.%d.%d.%d.%d",
1574 alphaCounter(par->getCounter(i-4)),
1575 par->getCounter(i-3),
1576 par->getCounter(i-2),
1577 par->getCounter(i-1),
1578 par->getCounter(i));
1580 case LABEL_COUNTER_SUBPARAGRAPH:
1581 sprintf(s, "%s.%d.%d.%d.%d.%d",
1582 alphaCounter(par->getCounter(i-5)),
1583 par->getCounter(i-4),
1584 par->getCounter(i-3),
1585 par->getCounter(i-2),
1586 par->getCounter(i-1),
1587 par->getCounter(i));
1590 sprintf(s, "%c.", par->getCounter(i));
1595 par->labelstring += s;
1598 for (i++; i<10; i++) {
1599 /* reset the following counters */
1600 par->setCounter(i, 0);
1602 } else if (layout->labeltype < LABEL_COUNTER_ENUMI) {
1603 for (i++; i<10; i++) {
1604 /* reset the following counters */
1605 par->setCounter(i, 0);
1607 } else if (layout->labeltype == LABEL_COUNTER_ENUMI) {
1608 par->incCounter(i + par->enumdepth);
1609 char * s = new char[25];
1610 int number = par->getCounter(i + par->enumdepth);
1611 switch (par->enumdepth) {
1613 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1617 case 1: sprintf(s, "i."); break;
1618 case 2: sprintf(s, "ii."); break;
1619 case 3: sprintf(s, "iii."); break;
1620 case 4: sprintf(s, "iv."); break;
1621 case 5: sprintf(s, "v."); break;
1622 case 6: sprintf(s, "vi."); break;
1623 case 7: sprintf(s, "vii."); break;
1624 case 8: sprintf(s, "viii."); break;
1625 case 9: sprintf(s, "ix."); break;
1626 case 10: sprintf(s, "x."); break;
1627 case 11: sprintf(s, "xi."); break;
1628 case 12: sprintf(s, "xii."); break;
1629 case 13: sprintf(s, "xiii."); break;
1631 sprintf(s, "\\roman{%d}.", number);
1636 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1639 sprintf(s, "%d.", number);
1642 par->labelstring = s;
1645 for (i += par->enumdepth + 1;i<10;i++)
1646 par->setCounter(i, 0); /* reset the following counters */
1649 } else if (layout->labeltype == LABEL_BIBLIO) {// ale970302
1650 i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1652 int number = par->getCounter(i);
1654 par->bibkey = new InsetBibKey();
1655 par->bibkey->setCounter(number);
1656 par->labelstring = layout->labelstring;
1658 // In biblio should't be following counters but...
1661 string s = layout->labelstring;
1663 /* the caption hack: */
1665 if (layout->labeltype == LABEL_SENSITIVE) {
1666 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1667 && (par->footnotekind == LyXParagraph::FIG
1668 || par->footnotekind == LyXParagraph::WIDE_FIG))
1670 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1671 && (par->footnotekind == LyXParagraph::TAB
1672 || par->footnotekind == LyXParagraph::WIDE_TAB))
1674 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1675 && par->footnotekind == LyXParagraph::ALGORITHM)
1678 /* par->SetLayout(0);
1679 s = layout->labelstring; */
1684 par->labelstring = s;
1686 /* reset the enumeration counter. They are always resetted
1687 * when there is any other layout between */
1688 for (i=6 + par->enumdepth; i<10;i++)
1689 par->setCounter(i, 0);
1694 /* Updates all counters BEHIND the row. Changed paragraphs
1695 * with a dynamic left margin will be rebroken. */
1696 void LyXText::UpdateCounters(Row *row)
1704 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1705 par = row->par->LastPhysicalPar()->Next();
1707 par = row->par->next;
1712 while (row->par != par)
1717 /* now check for the headline layouts. remember that they
1718 * have a dynamic left margin */
1720 && ( lyxstyle.Style(parameters->textclass, par->layout)->margintype == MARGIN_DYNAMIC
1721 || lyxstyle.Style(parameters->textclass, par->layout)->labeltype == LABEL_SENSITIVE)
1724 /* Rebreak the paragraph */
1725 RemoveParagraph(row);
1726 AppendParagraph(row);
1728 /* think about the damned open footnotes! */
1729 while (par->Next() &&
1730 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1731 || par->Next()->IsDummy())){
1733 if (par->IsDummy()) {
1734 while (row->par != par)
1736 RemoveParagraph(row);
1737 AppendParagraph(row);
1742 par = par->LastPhysicalPar()->Next();
1748 /* insets an inset. */
1749 void LyXText::InsertInset(Inset *inset)
1751 SetUndo(Undo::INSERT,
1752 cursor.par->ParFromPos(cursor.pos)->previous,
1753 cursor.par->ParFromPos(cursor.pos)->next);
1754 cursor.par->InsertChar(cursor.pos, LYX_META_INSET);
1755 cursor.par->InsertInset(cursor.pos, inset);
1756 InsertChar(LYX_META_INSET); /* just to rebreak and refresh correctly.
1757 * The character will not be inserted a
1762 /* this is for the simple cut and paste mechanism */
1763 static LyXParagraph *simple_cut_buffer = 0;
1764 static char simple_cut_buffer_textclass = 0;
1766 void DeleteSimpleCutBuffer()
1768 if (!simple_cut_buffer)
1770 LyXParagraph *tmppar;
1772 while (simple_cut_buffer) {
1773 tmppar = simple_cut_buffer;
1774 simple_cut_buffer = simple_cut_buffer->next;
1777 simple_cut_buffer = 0;
1781 void LyXText::copyEnvironmentType()
1783 copylayouttype = cursor.par->GetLayout();
1787 void LyXText::pasteEnvironmentType()
1789 SetLayout(copylayouttype);
1793 void LyXText::CutSelection(bool doclear)
1795 /* This doesn't make sense, if there is no selection */
1800 /* OK, we have a selection. This is always between sel_start_cursor
1801 * and sel_end cursor */
1802 LyXParagraph *tmppar;
1805 /* Check whether there are half footnotes in the selection */
1806 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1807 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1808 tmppar = sel_start_cursor.par;
1809 while (tmppar != sel_end_cursor.par){
1810 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1811 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1814 tmppar = tmppar->Next();
1818 /* table stuff -- begin*/
1819 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1820 if ( sel_start_cursor.par != sel_end_cursor.par){
1821 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1824 sel_start_cursor.par->table->Reinit();
1826 /* table stuff -- end*/
1828 // make sure that the depth behind the selection are restored, too
1829 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1830 LyXParagraph *undoendpar = endpar;
1832 if (endpar && endpar->GetDepth()) {
1833 while (endpar && endpar->GetDepth()) {
1834 endpar = endpar->LastPhysicalPar()->Next();
1835 undoendpar = endpar;
1839 endpar = endpar->Next(); /* because of parindents etc. */
1842 SetUndo(Undo::DELETE,
1843 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1846 /* delete the simple_cut_buffer */
1847 DeleteSimpleCutBuffer();
1849 /* set the textclass */
1850 simple_cut_buffer_textclass = parameters->textclass;
1852 #ifdef WITH_WARNINGS
1853 #warning Asger: Make cut more intelligent here.
1856 White paper for "intelligent" cutting:
1858 Example: "This is our text."
1859 Using " our " as selection, cutting will give "This istext.".
1860 Using "our" as selection, cutting will give "This is text.".
1861 Using " our" as selection, cutting will give "This is text.".
1862 Using "our " as selection, cutting will give "This is text.".
1864 All those four selections will (however) paste identically:
1865 Pasting with the cursor right after the "is" will give the
1866 original text with all four selections.
1868 The rationale is to be intelligent such that words are copied,
1869 cut and pasted in a functional manner.
1871 This is not implemented yet.
1874 char 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 sel_end_cursor.pos--; /* please break before a space at
1880 space_wrapped = True;
1883 // cut behind a space if there is one
1884 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1885 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1886 && (sel_start_cursor.par != sel_end_cursor.par
1887 || sel_start_cursor.pos < sel_end_cursor.pos))
1888 sel_start_cursor.pos++;
1890 /* there are two cases: cut only within one paragraph or
1891 * more than one paragraph */
1893 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1894 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1895 /* only within one paragraph */
1896 simple_cut_buffer = new LyXParagraph();
1897 for (i=sel_start_cursor.pos; i< sel_end_cursor.pos; i++){
1898 /* table stuff -- begin*/
1899 if (sel_start_cursor.par->table
1900 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1901 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1902 sel_start_cursor.pos++;
1904 /* table stuff -- end*/
1905 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1906 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1908 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1910 /* check for double spaces */
1911 if (sel_start_cursor.pos &&
1912 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1913 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1914 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1915 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1918 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1919 endpar = sel_end_cursor.par->Next();
1922 /* cut more than one paragraph */
1924 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1925 /* insert a space at the end if there was one */
1927 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1929 sel_end_cursor.par = sel_end_cursor.par->Next();
1930 sel_end_cursor.pos = 0;
1932 cursor = sel_end_cursor;
1934 /* please break behind a space, if there is one. The space should
1936 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1937 sel_start_cursor.pos++;
1939 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1940 if (!sel_start_cursor.pos
1941 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1942 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1943 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1946 /* store the endparagraph for redoing later */
1947 endpar = sel_end_cursor.par->Next(); /* needed because
1952 /*store the selection */
1953 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1954 simple_cut_buffer->previous = 0;
1955 sel_end_cursor.par->previous->next = 0;
1957 /* cut the selection */
1958 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1959 = sel_end_cursor.par;
1961 sel_end_cursor.par->previous
1962 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1964 /* care about footnotes */
1965 if (simple_cut_buffer->footnoteflag) {
1966 LyXParagraph *tmppar = simple_cut_buffer;
1968 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1969 tmppar = tmppar->next;
1973 /* the cut selection should begin with standard layout */
1974 simple_cut_buffer->Clear();
1976 /* paste the paragraphs again, if possible */
1978 sel_start_cursor.par->Next()->ClearParagraph();
1979 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1981 !sel_start_cursor.par->Next()->Last())
1982 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1985 /* maybe a forgotten blank */
1986 if (sel_start_cursor.pos
1987 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1988 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1989 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1994 /* sometimes necessary */
1996 sel_start_cursor.par->ClearParagraph();
1998 RedoParagraphs(sel_start_cursor, endpar);
2001 cursor = sel_start_cursor;
2002 SetCursor(cursor.par, cursor.pos);
2003 sel_cursor = cursor;
2004 UpdateCounters(cursor.row);
2008 void LyXText::CopySelection()
2012 /* this doesnt make sense, if there is no selection */
2017 /* ok we have a selection. This is always between sel_start_cursor
2018 * and sel_end cursor */
2019 LyXParagraph *tmppar;
2021 /* check wether there are half footnotes in the selection */
2022 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2023 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2024 tmppar = sel_start_cursor.par;
2025 while (tmppar != sel_end_cursor.par){
2026 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2027 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2030 tmppar = tmppar->Next();
2034 /* table stuff -- begin*/
2035 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2036 if ( sel_start_cursor.par != sel_end_cursor.par){
2037 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2041 /* table stuff -- end*/
2043 /* delete the simple_cut_buffer */
2044 DeleteSimpleCutBuffer();
2046 /* set the textclass */
2047 simple_cut_buffer_textclass = parameters->textclass;
2049 // copy behind a space if there is one
2050 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2051 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2052 && (sel_start_cursor.par != sel_end_cursor.par
2053 || sel_start_cursor.pos < sel_end_cursor.pos))
2054 sel_start_cursor.pos++;
2056 /* there are two cases: copy only within one paragraph or more than one paragraph */
2057 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2058 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2059 /* only within one paragraph */
2060 simple_cut_buffer = new LyXParagraph();
2061 for (i=sel_start_cursor.pos; i< sel_end_cursor.pos; i++){
2062 sel_start_cursor.par->CopyIntoMinibuffer(i);
2063 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2067 /* copy more than one paragraph */
2068 /* clone the paragraphs within the selection*/
2069 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2070 simple_cut_buffer = tmppar->Clone();
2071 LyXParagraph *tmppar2 = simple_cut_buffer;
2073 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2075 tmppar = tmppar->next;
2076 tmppar2->next = tmppar->Clone();
2077 tmppar2->next->previous = tmppar2;
2078 tmppar2=tmppar2->next;
2082 /* care about footnotes */
2083 if (simple_cut_buffer->footnoteflag) {
2084 tmppar = simple_cut_buffer;
2086 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2087 tmppar = tmppar->next;
2091 /* the simple_cut_buffer paragraph is too big */
2094 tmpi2 = sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2095 for (;tmpi2;tmpi2--)
2096 simple_cut_buffer->Erase(0);
2098 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2100 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2101 while (tmppar2->last > tmpi2) {
2102 tmppar2->Erase(tmppar2->last-1);
2109 void LyXText::PasteSelection()
2111 /* this does not make sense, if there is nothing to paste */
2112 if (!simple_cut_buffer)
2115 LyXParagraph *tmppar;
2116 LyXParagraph *endpar;
2118 LyXCursor tmpcursor;
2120 /* be carefull with footnotes in footnotes */
2121 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2123 /* check whether the cut_buffer includes a footnote */
2124 tmppar = simple_cut_buffer;
2125 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2126 tmppar = tmppar->next;
2129 WriteAlert(_("Impossible operation"),
2130 _("Can't paste float into float!"), _("Sorry."));
2135 /* table stuff -- begin*/
2136 if (cursor.par->table){
2137 if (simple_cut_buffer->next){
2138 WriteAlert(_("Impossible operation"),
2139 _("Table cell cannot include more than one paragraph!"),
2144 /* table stuff -- end*/
2146 SetUndo(Undo::INSERT,
2147 cursor.par->ParFromPos(cursor.pos)->previous,
2148 cursor.par->ParFromPos(cursor.pos)->next);
2152 /* There are two cases: cutbuffer only one paragraph or many */
2153 if (!simple_cut_buffer->next) {
2154 /* only within a paragraph */
2156 /* please break behind a space, if there is one */
2157 while (tmpcursor.par->Last() > tmpcursor.pos
2158 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2161 tmppar = simple_cut_buffer->Clone();
2162 /* table stuff -- begin*/
2163 bool table_too_small = false;
2164 if (tmpcursor.par->table) {
2165 while (simple_cut_buffer->last && !table_too_small){
2166 if (simple_cut_buffer->IsNewline(0)){
2167 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2169 simple_cut_buffer->Erase(0);
2170 if (tmpcursor.pos < tmpcursor.par->Last())
2173 table_too_small = true;
2175 simple_cut_buffer->CutIntoMinibuffer(0);
2176 simple_cut_buffer->Erase(0);
2177 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2182 /* table stuff -- end*/
2183 while (simple_cut_buffer->last){
2184 simple_cut_buffer->CutIntoMinibuffer(0);
2185 simple_cut_buffer->Erase(0);
2186 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2191 delete simple_cut_buffer;
2192 simple_cut_buffer = tmppar;
2193 endpar = tmpcursor.par->Next();
2195 /* many paragraphs */
2197 /* make a copy of the simple cut_buffer */
2198 tmppar = simple_cut_buffer;
2199 LyXParagraph *simple_cut_clone = tmppar->Clone();
2200 LyXParagraph *tmppar2 = simple_cut_clone;
2201 if (cursor.par->footnoteflag){
2202 tmppar->footnoteflag = cursor.par->footnoteflag;
2203 tmppar->footnotekind = cursor.par->footnotekind;
2205 while (tmppar->next) {
2206 tmppar = tmppar->next;
2207 tmppar2->next = tmppar->Clone();
2208 tmppar2->next->previous = tmppar2;
2209 tmppar2=tmppar2->next;
2210 if (cursor.par->footnoteflag){
2211 tmppar->footnoteflag = cursor.par->footnoteflag;
2212 tmppar->footnotekind = cursor.par->footnotekind;
2216 /* make sure there is no class difference */
2217 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2218 parameters->textclass,
2221 /* make the simple_cut_buffer exactly the same layout than
2222 the cursor paragraph */
2223 simple_cut_buffer->MakeSameLayout(cursor.par);
2225 /* find the end of the buffer */
2226 LyXParagraph *lastbuffer = simple_cut_buffer;
2227 while (lastbuffer->Next())
2228 lastbuffer=lastbuffer->Next();
2230 /* find the physical end of the buffer */
2231 lastbuffer = simple_cut_buffer;
2232 while (lastbuffer->Next())
2233 lastbuffer=lastbuffer->Next();
2235 /* please break behind a space, if there is one. The space
2236 * should be copied too */
2237 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2240 bool paste_the_end = false;
2242 /* open the paragraph for inserting the simple_cut_buffer
2244 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2245 cursor.par->BreakParagraphConservative(cursor.pos);
2246 paste_the_end = true;
2249 /* be careful with double spaces */
2250 if ((!cursor.par->Last()
2251 || cursor.par->IsLineSeparator(cursor.pos - 1)
2252 || cursor.par->IsNewline(cursor.pos - 1))
2253 && simple_cut_buffer->last
2254 && simple_cut_buffer->IsLineSeparator(0))
2255 simple_cut_buffer->Erase(0);
2257 /* set the end for redoing later */
2258 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2261 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2262 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2264 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2265 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2267 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2268 lastbuffer = cursor.par;
2270 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2272 /* store the new cursor position */
2273 tmpcursor.par = lastbuffer;
2274 tmpcursor.pos = lastbuffer->Last();
2276 /* maybe some pasting */
2277 if (lastbuffer->Next() && paste_the_end) {
2278 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2280 /* be careful witth double spaces */
2281 if ((!lastbuffer->Last()
2282 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2283 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2284 && lastbuffer->Next()->Last()
2285 && lastbuffer->Next()->IsLineSeparator(0))
2286 lastbuffer->Next()->Erase(0);
2288 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2291 else if (!lastbuffer->Next()->Last()) {
2292 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2294 /* be careful witth double spaces */
2295 if ((!lastbuffer->Last()
2296 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2297 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2298 && lastbuffer->Next()->Last()
2299 && lastbuffer->Next()->IsLineSeparator(0))
2300 lastbuffer->Next()->Erase(0);
2302 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2305 else if (!lastbuffer->Last()) {
2306 lastbuffer->MakeSameLayout(lastbuffer->next);
2308 /* be careful witth double spaces */
2309 if ((!lastbuffer->Last()
2310 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2311 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2312 && lastbuffer->Next()->Last()
2313 && lastbuffer->Next()->IsLineSeparator(0))
2314 lastbuffer->Next()->Erase(0);
2316 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2319 else lastbuffer->Next()->ClearParagraph();
2322 /* restore the simple cut buffer */
2323 simple_cut_buffer = simple_cut_clone;
2326 RedoParagraphs(cursor, endpar);
2328 SetCursor(cursor.par, cursor.pos);
2331 sel_cursor = cursor;
2332 SetCursor(tmpcursor.par, tmpcursor.pos);
2334 UpdateCounters(cursor.row);
2338 /* returns a pointer to the very first LyXParagraph */
2339 LyXParagraph* LyXText::FirstParagraph()
2341 return params->paragraph;
2345 /* returns true if the specified string is at the specified position */
2346 bool LyXText::IsStringInText(LyXParagraph *par, int pos, char const* string)
2350 while (pos+i < par->Last() && string[i] &&
2351 string[i]==par->GetChar(pos+i))
2363 /* sets the selection over the number of characters of string, no check!! */
2364 void LyXText::SetSelectionOverString(char const* string)
2366 sel_cursor = cursor;
2368 for (i=0; string[i]; i++)
2374 /* simple replacing. The font of the first selected character is used */
2375 void LyXText::ReplaceSelectionWithString(char const* string)
2380 if (!selection) { /* create a dummy selection */
2381 sel_end_cursor = cursor;
2382 sel_start_cursor = cursor;
2385 // Get font setting before we cut
2386 int pos = sel_end_cursor.pos;
2387 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2389 // Insert the new string
2390 for (int i=0; string[i];i++) {
2391 sel_end_cursor.par->InsertChar(pos, string[i]);
2392 sel_end_cursor.par->SetFont(pos, font);
2396 // Cut the selection
2403 /* if the string can be found: return true and set the cursor to
2404 * the new position */
2405 bool LyXText::SearchForward(char const* string)
2407 LyXParagraph *par = cursor.par;
2408 int pos = cursor.pos;
2410 while (par && !IsStringInText(par,pos,string)) {
2411 if (pos<par->Last()-1)
2427 bool LyXText::SearchBackward(char const* string)
2429 LyXParagraph *par = cursor.par;
2430 int pos = cursor.pos;
2436 // We skip empty paragraphs (Asger)
2438 par = par->Previous();
2440 pos = par->Last()-1;
2441 } while (par && pos<0);
2443 } while (par && !IsStringInText(par,pos,string));
2454 /* needed to insert the selection */
2455 void LyXText::InsertStringA(char* string)
2457 LyXParagraph *par = cursor.par;
2458 int pos = cursor.pos;
2461 LyXParagraph *endpar = cursor.par->Next();
2465 char flag = lyxstyle.Style(parameters->textclass,
2466 cursor.par->GetLayout())->isEnvironment();
2467 /* only to be sure, should not be neccessary */
2470 /* insert the string, don't insert doublespace */
2474 for (i2=i;string[i2]&&string[i2]!='\n';i2++);
2475 par->Enlarge(pos, i2 - i);
2477 if (string[i]!='\n') {
2478 if (string[i]==' ' && (string[i+1]!=' ')
2479 && pos && par->GetChar(pos-1)!=' ') {
2480 par->InsertChar(pos,' ');
2483 else if (par->table) {
2484 if (string[i] == '\t') {
2485 while((pos < par->last) &&
2486 (par->GetChar(pos) != LYX_META_NEWLINE))
2488 if (pos < par->last)
2490 else // no more fields to fill skip the rest
2492 } else if ((string[i] != 13) &&
2493 (((unsigned char) string[i] & 127) >= ' ')) {
2494 par->InsertChar(pos,string[i]);
2498 else if (string[i]==' ') {
2499 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2502 else if (string[i]=='\t') {
2503 for (a=pos; a<(pos/8+1)*8 ; a++) {
2504 par->InsertChar(a,LYX_META_PROTECTED_SEPARATOR);
2508 else if (string[i]!=13 &&
2509 // Ignore unprintables
2510 ((unsigned char) string[i] & 127) >= ' ') {
2511 par->InsertChar(pos,string[i]);
2520 while((pos < par->last) &&
2521 (par->GetChar(pos) != LYX_META_NEWLINE))
2524 cell=NumberOfCell(par,pos);
2525 while((pos < par->last) &&
2526 !(par->table->IsFirstCell(cell))) {
2527 while((pos < par->last) &&
2528 (par->GetChar(pos) != LYX_META_NEWLINE))
2531 cell=NumberOfCell(par,pos);
2533 if (pos >= par->last)
2534 // no more fields to fill skip the rest
2538 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2541 par->BreakParagraph(pos, flag);
2545 for (i2=i;string[i2]&&string[i2]!='\n';i2++);
2546 par->Enlarge(pos, i2 - i);
2552 RedoParagraphs(cursor,endpar);
2553 SetCursor(cursor.par, cursor.pos);
2554 sel_cursor = cursor;
2555 SetCursor(par, pos);
2559 /* turns double-CR to single CR, others where converted into one blank and 13s
2560 * that are ignored .Double spaces are also converted into one. Spaces at
2561 * the beginning of a paragraph are forbidden. tabs are converted into one
2562 * space. then InsertStringA is called */
2563 void LyXText::InsertStringB(char* string)
2565 LyXParagraph *par = cursor.par;
2568 if (string[i]=='\t' && !par->table)
2570 if (string[i]==' ' && string[i+1]==' ')
2572 if (string[i]=='\n' && string[i+1] && !par->table){
2573 if (string[i+1]!='\n') {
2574 if (string[i-1]!=' ')
2579 while (string[i+1] && (string[i+1]==' '
2580 || string[i+1]=='\t'
2581 || string[i+1]=='\n'
2582 || string[i+1]==13)) {
2589 InsertStringA(string);
2593 bool LyXText::GotoNextError()
2595 LyXCursor res=cursor;
2597 if (res.pos < res.par->Last()-1) {
2601 res.par=res.par->Next();
2606 !(res.par->GetChar(res.pos)==LYX_META_INSET
2607 && res.par->GetInset(res.pos)->AutoDelete()));
2610 SetCursor(res.par, res.pos);
2618 bool LyXText::GotoNextNote()
2620 LyXCursor res=cursor;
2622 if (res.pos < res.par->Last()-1) {
2626 res.par=res.par->Next();
2631 !(res.par->GetChar(res.pos)==LYX_META_INSET
2632 && res.par->GetInset(res.pos)->LyxCode()==Inset::IGNORE_CODE));
2635 SetCursor(res.par, res.pos);
2643 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2646 InsetError * new_inset = 0;
2648 if (!par || class1 == class2)
2650 par = par->FirstPhysicalPar();
2652 string name = lyxstyle.NameOfLayout(class1, par->layout);
2653 int lay = lyxstyle.NumberOfLayout(class2, name);
2654 if (lay == -1) // layout not found
2655 // use default layout "Stadard" (0)
2659 if (name != lyxstyle.NameOfLayout(class2, par->layout)) {
2661 string s= "Layout had to be changed from\n"
2662 + name + " to " + lyxstyle.NameOfLayout(class2, par->layout)
2663 + "\nbecause of class conversion from\n"
2664 + lyxstyle.NameOfClass(class1) + " to "
2665 + lyxstyle.NameOfClass(class2);
2666 new_inset = new InsetError(s);
2667 par->InsertChar(0, LYX_META_INSET);
2668 par->InsertInset(0, new_inset);
2677 void LyXText::CheckParagraph(LyXParagraph* par, int pos)
2680 LyXCursor tmpcursor;
2682 /* table stuff -- begin*/
2685 CheckParagraphInTable(par, pos);
2688 /* table stuff -- end*/
2693 Row* row = GetRow(par, pos, y);
2695 /* is there a break one row above */
2696 if (row->previous && row->previous->par == row->par) {
2697 z = NextBreakPoint(row->previous, paperwidth);
2698 if ( z >= row->pos) {
2699 /* set the dimensions of the row above */
2700 y -= row->previous->height;
2702 refresh_row = row->previous;
2703 status = LyXText::NEED_MORE_REFRESH;
2705 BreakAgain(row->previous);
2707 /* set the cursor again. Otherwise dungling pointers are possible */
2708 SetCursor(cursor.par, cursor.pos);
2709 sel_cursor = cursor;
2714 int tmpheight = row->height;
2715 int tmplast = RowLast(row);
2720 if (row->height == tmpheight && RowLast(row) == tmplast)
2721 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2723 status = LyXText::NEED_MORE_REFRESH;
2725 /* check the special right address boxes */
2726 if (lyxstyle.Style(parameters->textclass, par->GetLayout())->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2727 tmpcursor.par = par;
2728 tmpcursor.row = row;
2731 tmpcursor.x_fix = 0;
2732 tmpcursor.pos = pos;
2733 RedoDrawingOfParagraph(tmpcursor);
2738 /* set the cursor again. Otherwise dangling pointers are possible */
2739 // also set the selection
2743 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2744 sel_cursor = cursor;
2745 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2746 sel_start_cursor = cursor;
2747 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2748 sel_end_cursor = cursor;
2749 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2750 last_sel_cursor = cursor;
2753 SetCursorIntern(cursor.par, cursor.pos);
2757 /* returns 0 if inset wasn't found */
2758 int LyXText::UpdateInset(Inset* inset)
2763 /* first check the current paragraph */
2764 pos = cursor.par->GetPositionOfInset(inset);
2766 CheckParagraph(cursor.par, pos);
2770 /* check every paragraph */
2772 par = FirstParagraph();
2774 /* make sure the paragraph is open */
2775 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2776 pos = par->GetPositionOfInset(inset);
2778 CheckParagraph(par, pos);
2789 void LyXText::SetCursor(LyXParagraph *par, int pos)
2791 LyXCursor old_cursor = cursor;
2792 SetCursorIntern(par, pos);
2793 DeleteEmptyParagraphMechanism(old_cursor);
2797 void LyXText::SetCursorIntern(LyXParagraph *par, int pos)
2802 LyXParagraph *tmppar;
2804 /* correct the cursor position if impossible */
2805 if (pos > par->Last()){
2806 tmppar = par->ParFromPos(pos);
2807 pos = par->PositionInParFromPos(pos);
2810 if (par->IsDummy() && par->previous &&
2811 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2812 while (par->previous &&
2813 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2814 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2815 par = par->previous ;
2816 if (par->IsDummy() &&
2817 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2818 pos += par->last + 1;
2820 if (par->previous) {
2821 par = par->previous;
2823 pos += par->last + 1;
2829 /* get the cursor y position in text */
2830 row = GetRow(par, pos, y);
2831 /* y is now the beginning of the cursor row */
2833 /* y is now the cursor baseline */
2836 /* now get the cursors x position */
2839 float fill_separator, fill_hfill, fill_label_hfill;
2840 left_margin = LabelEnd(row);
2841 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2842 int main_body = BeginningOfMainBody(row->par);
2844 /* table stuff -- begin*/
2845 if (row->par->table) {
2846 int cell = NumberOfCell(row->par, row->pos);
2848 x += row->par->table->GetBeginningOfTextInCell(cell);
2849 for (pos = row->pos; pos < cursor.pos; pos++) {
2850 if (row->par->IsNewline(pos)) {
2851 x = x_old + row->par->table->WidthOfColumn(cell);
2854 x += row->par->table->GetBeginningOfTextInCell(cell);
2856 x += SingleWidth(row->par, pos);
2860 /* table stuff -- end*/
2862 for (pos = row->pos; pos < cursor.pos; pos++) {
2863 if (pos && pos == main_body
2864 && !row->par->IsLineSeparator(pos - 1)) {
2865 x += GetFont(row->par, -2).stringWidth(
2866 lyxstyle.Style(parameters->textclass, row->par->GetLayout())->labelsep);
2867 if (x < left_margin)
2871 x += SingleWidth(row->par, pos);
2872 if (HfillExpansion(row, pos)) {
2873 if (pos >= main_body)
2876 x += fill_label_hfill;
2878 else if (pos >= main_body && row->par->IsSeparator(pos)) {
2882 if (pos + 1 == main_body
2883 && row->par->IsLineSeparator(pos)) {
2884 x += GetFont(row->par, -2).stringWidth(
2885 lyxstyle.Style(parameters->textclass, row->par->GetLayout())->labelsep);
2886 if (row->par->IsLineSeparator(pos))
2887 x-= SingleWidth(row->par, pos);
2888 if (x < left_margin)
2895 cursor.x_fix = cursor.x;
2899 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2900 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2901 && !cursor.par->IsSeparator(cursor.pos))
2903 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2904 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2906 current_font = cursor.par->GetFontSettings(cursor.pos);
2907 real_current_font = GetFont(cursor.par, cursor.pos);
2912 void LyXText::SetCursorFromCoordinates(int x, long y)
2917 LyXCursor old_cursor;
2919 old_cursor = cursor;
2921 /* get the row first */
2923 row = GetRowNearY(y);
2925 cursor.par = row->par;
2927 column = GetColumnNearX(row, x);
2928 cursor.pos = row->pos + column;
2930 cursor.y = y + row->baseline;
2935 (cursor.pos == cursor.par->Last()
2936 || cursor.par->IsSeparator(cursor.pos)
2937 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2938 && !cursor.par->IsSeparator(cursor.pos))
2940 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2941 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2943 current_font = cursor.par->GetFontSettings(cursor.pos);
2944 real_current_font = GetFont(cursor.par, cursor.pos);
2946 DeleteEmptyParagraphMechanism(old_cursor);
2950 void LyXText::CursorLeft()
2953 if (cursor.par->table) {
2954 int cell = NumberOfCell(cursor.par, cursor.pos);
2955 if (cursor.par->table->IsContRow(cell) &&
2956 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2963 void LyXText::CursorLeftIntern()
2965 if (cursor.pos > 0) {
2966 SetCursor(cursor.par, cursor.pos - 1);
2968 else if (cursor.par->Previous()) {
2969 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2974 void LyXText::CursorRight()
2976 CursorRightIntern();
2977 if (cursor.par->table) {
2978 int cell = NumberOfCell(cursor.par, cursor.pos);
2979 if (cursor.par->table->IsContRow(cell) &&
2980 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2987 void LyXText::CursorRightIntern()
2989 if (cursor.pos < cursor.par->Last()) {
2990 SetCursor(cursor.par, cursor.pos + 1);
2992 else if (cursor.par->Next()) {
2993 SetCursor(cursor.par->Next(), 0);
2998 void LyXText::CursorUp()
3000 SetCursorFromCoordinates(cursor.x_fix,
3001 cursor.y - cursor.row->baseline - 1);
3002 if (cursor.par->table) {
3003 int cell = NumberOfCell(cursor.par, cursor.pos);
3004 if (cursor.par->table->IsContRow(cell) &&
3005 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3012 void LyXText::CursorDown()
3014 if (cursor.par->table &&
3015 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3018 SetCursorFromCoordinates(cursor.x_fix,
3019 cursor.y - cursor.row->baseline
3020 + cursor.row->height + 1);
3021 if (cursor.par->table) {
3022 int cell = NumberOfCell(cursor.par, cursor.pos);
3023 int cell_above = cursor.par->table->GetCellAbove(cell);
3024 while(cursor.par->table &&
3025 cursor.par->table->IsContRow(cell) &&
3026 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3027 SetCursorFromCoordinates(cursor.x_fix,
3028 cursor.y - cursor.row->baseline
3029 + cursor.row->height + 1);
3030 if (cursor.par->table) {
3031 cell = NumberOfCell(cursor.par, cursor.pos);
3032 cell_above = cursor.par->table->GetCellAbove(cell);
3039 void LyXText::CursorUpParagraph()
3041 if (cursor.pos > 0) {
3042 SetCursor(cursor.par, 0);
3044 else if (cursor.par->Previous()) {
3045 SetCursor(cursor.par->Previous(), 0);
3050 void LyXText::CursorDownParagraph()
3052 if (cursor.par->Next()) {
3053 SetCursor(cursor.par->Next(), 0);
3055 SetCursor(cursor.par,cursor.par->Last());
3061 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3063 bool deleted = false;
3065 /* this is the delete-empty-paragraph-mechanism. */
3069 // Paragraph should not be deleted if empty
3070 if ((lyxstyle.Style(parameters->textclass,
3071 old_cursor.par->GetLayout()))->keepempty)
3074 LyXCursor tmpcursor;
3076 if (old_cursor.par != cursor.par) {
3077 if ( (old_cursor.par->Last() == 0
3078 || (old_cursor.par->Last() == 1
3079 && (old_cursor.par->IsLineSeparator(0))))
3080 && old_cursor.par->FirstPhysicalPar()
3081 == old_cursor.par->LastPhysicalPar()
3083 // impossible to insert your own \caption with
3084 // this set. made it impossible to use the
3085 // optional argument...
3086 // also empty pars in fig or tab never was removed(?)(Lgb)
3087 //lyxstyle.Style(parameters->textclass,
3088 // old_cursor.par->GetLayout())->labeltype!=LABEL_SENSITIVE ||
3089 // (old_cursor.par->footnoteflag == LyXParagraph::NO_FOOTNOTE
3090 //|| (old_cursor.par->footnotekind != LyXParagraph::FIG
3091 // && old_cursor.par->footnotekind != LyXParagraph::TAB)))
3094 /* ok, we will delete anything */
3096 // make sure that you do not delete any environments
3097 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3098 !(old_cursor.row->previous
3099 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3100 && !(old_cursor.row->next
3101 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3103 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3104 ((old_cursor.row->previous
3105 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3107 (old_cursor.row->next
3108 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3110 status = LyXText::NEED_MORE_REFRESH;
3113 if (old_cursor.row->previous) {
3114 refresh_row = old_cursor.row->previous;
3115 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3117 cursor = old_cursor; // that undo can restore the right cursor position
3118 LyXParagraph *endpar = old_cursor.par->next;
3119 if (endpar && endpar->GetDepth()) {
3120 while (endpar && endpar->GetDepth()) {
3121 endpar = endpar->LastPhysicalPar()->Next();
3124 SetUndo(Undo::DELETE,
3125 old_cursor.par->previous,
3129 /* delete old row */
3130 RemoveRow(old_cursor.row);
3131 if (params->paragraph == old_cursor.par) {
3132 params->paragraph = params->paragraph->next;
3134 /* delete old par */
3135 delete old_cursor.par;
3137 /* Breakagain the next par. Needed
3138 * because of the parindent that
3139 * can occur or dissappear. The
3140 * next row can change its height,
3141 * if there is another layout before */
3142 if (refresh_row->next) {
3143 BreakAgain(refresh_row->next);
3144 UpdateCounters(refresh_row);
3146 SetHeightOfRow(refresh_row);
3149 refresh_row = old_cursor.row->next;
3150 refresh_y = old_cursor.y - old_cursor.row->baseline;
3153 cursor = old_cursor; // that undo can restore the right cursor position
3154 LyXParagraph *endpar = old_cursor.par->next;
3155 if (endpar && endpar->GetDepth()) {
3156 while (endpar && endpar->GetDepth()) {
3157 endpar = endpar->LastPhysicalPar()->Next();
3160 SetUndo(Undo::DELETE,
3161 old_cursor.par->previous,
3165 /* delete old row */
3166 RemoveRow(old_cursor.row);
3167 /* delete old par */
3168 if (params->paragraph == old_cursor.par) {
3169 params->paragraph = params->paragraph->next;
3171 delete old_cursor.par;
3173 /* Breakagain the next par. Needed because of
3174 * the parindent that can occur or dissappear.
3175 * The next row can change its height, if there
3176 * is another layout before */
3178 BreakAgain(refresh_row);
3179 UpdateCounters(refresh_row->previous);
3183 /* correct cursor y */
3184 SetCursor(cursor.par, cursor.pos);
3186 /* if (cursor.y > old_cursor.y)
3187 cursor.y -= old_cursor.row->height; */
3189 if (sel_cursor.par == old_cursor.par
3190 && sel_cursor.pos == sel_cursor.pos) {
3191 /* correct selection*/
3192 sel_cursor = cursor;
3198 if (old_cursor.par->ClearParagraph()){
3199 RedoParagraphs(old_cursor, old_cursor.par->Next());
3200 /* correct cursor y */
3201 SetCursor(cursor.par, cursor.pos);
3202 sel_cursor = cursor;
3205 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3206 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3207 if (old_cursor.par->table->IsContRow(cell) &&
3208 IsEmptyTableRow(&old_cursor)) {
3209 RemoveTableRow(&old_cursor);
3216 LyXParagraph* LyXText::GetParFromID(int id)
3218 LyXParagraph* result = FirstParagraph();
3219 while (result && result->GetID() != id)
3220 result = result->next;
3226 bool LyXText::TextUndo()
3227 { // returns false if no undo possible
3228 Undo *undo = params->undostack.Pop();
3232 params->redostack.Push(CreateUndo(undo->kind,
3233 GetParFromID(undo->number_of_before_par),
3234 GetParFromID(undo->number_of_behind_par)));
3236 return TextHandleUndo(undo);
3240 bool LyXText::TextRedo()
3241 { // returns false if no redo possible
3242 Undo *undo = params->redostack.Pop();
3246 params->undostack.Push(CreateUndo(undo->kind,
3247 GetParFromID(undo->number_of_before_par),
3248 GetParFromID(undo->number_of_behind_par)));
3250 return TextHandleUndo(undo);
3254 bool LyXText::TextHandleUndo(Undo* undo){ // returns false if no undo possible
3255 bool result = false;
3257 LyXParagraph* before = GetParFromID(undo->number_of_before_par);
3258 LyXParagraph* behind = GetParFromID(undo->number_of_behind_par);
3259 LyXParagraph* tmppar;
3260 LyXParagraph* tmppar2;
3261 LyXParagraph* tmppar3;
3262 LyXParagraph* tmppar4;
3263 LyXParagraph* endpar;
3264 LyXParagraph* tmppar5;
3268 before->text[before->last] = 0;
3269 printf("before: %s\n", before->text);
3272 behind->text[behind->last] = 0;
3273 printf("behind: %s\n", behind->text);
3277 // if there's no before take the beginning of the document for redoing
3279 SetCursorIntern(FirstParagraph(), 0);
3281 // replace the paragraphs with the undo informations
3283 tmppar3 = undo->par;
3284 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3287 while (tmppar4->next)
3288 tmppar4 = tmppar4->next;
3289 } // get last undo par
3291 // now remove the old text if there is any
3292 if (before != behind || (!behind && !before)){
3294 tmppar5 = before->next;
3296 tmppar5 = params->paragraph;
3298 while (tmppar5 && tmppar5 != behind){
3300 tmppar5 = tmppar5->next;
3301 // a memory optimization for edit: Only layout information
3302 // is stored in the undo. So restore the text informations.
3303 if (undo->kind == Undo::EDIT){
3304 tmppar2->text = tmppar->text;
3306 tmppar2 = tmppar2->next;
3308 if ( currentrow && currentrow->par == tmppar )
3309 currentrow = currentrow -> previous;
3314 // put the new stuff in the list if there is one
3317 before->next = tmppar3;
3319 params->paragraph = tmppar3;
3320 tmppar3->previous = before;
3324 params->paragraph = behind;
3327 tmppar4->next = behind;
3329 behind->previous = tmppar4;
3333 // Set the cursor for redoing
3335 SetCursorIntern(before->FirstSelfrowPar(), 0);
3336 // check wether before points to a closed float and open it if necessary
3337 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3338 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3340 while (tmppar4->previous &&
3341 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3342 tmppar4 = tmppar4->previous;
3343 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3344 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3345 tmppar4 = tmppar4->next;
3350 // open a cosed footnote at the end if necessary
3351 if (behind && behind->previous &&
3352 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3353 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3354 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3355 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3356 behind = behind->next;
3360 // calculate the endpar for redoing the paragraphs.
3362 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3363 endpar = behind->LastPhysicalPar()->Next();
3365 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3370 tmppar = GetParFromID(undo->number_of_cursor_par);
3371 RedoParagraphs(cursor, endpar);
3373 SetCursorIntern(tmppar, undo->cursor_pos);
3374 UpdateCounters(cursor.row);
3384 void LyXText::FinishUndo()
3385 { // makes sure the next operation will be stored
3386 undo_finished = True;
3390 void LyXText::FreezeUndo()
3391 { // this is dangerous and for internal use only
3396 void LyXText::UnFreezeUndo()
3397 { // this is dangerous and for internal use only
3398 undo_frozen = false;
3402 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph *before, LyXParagraph *behind)
3405 params->undostack.Push(CreateUndo(kind, before, behind));
3406 params->redostack.Clear();
3410 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph *before, LyXParagraph *behind)
3412 params->redostack.Push(CreateUndo(kind, before, behind));
3416 Undo* LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph *before,
3417 LyXParagraph *behind)
3419 int before_number = -1;
3420 int behind_number = -1;
3422 before_number = before->GetID();
3424 behind_number = behind->GetID();
3425 // Undo::EDIT and Undo::FINISH are
3426 // always finished. (no overlapping there)
3427 // overlapping only with insert and delete inside one paragraph:
3428 // Nobody wants all removed character
3429 // appear one by one when undoing.
3430 // EDIT is special since only layout information, not the
3431 // contents of a paragaph are stored.
3432 if (!undo_finished && kind != Undo::EDIT &&
3433 kind != Undo::FINISH){
3434 // check wether storing is needed
3435 if (params->undostack.Top() &&
3436 params->undostack.Top()->kind == kind &&
3437 params->undostack.Top()->number_of_before_par == before_number &&
3438 params->undostack.Top()->number_of_behind_par == behind_number ){
3443 // create a new Undo
3444 LyXParagraph* undopar;
3445 LyXParagraph* tmppar;
3446 LyXParagraph *tmppar2;
3448 LyXParagraph* start = 0;
3449 LyXParagraph* end = 0;
3452 start = before->next;
3454 start = FirstParagraph();
3456 end = behind->previous;
3458 end = FirstParagraph();
3463 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3465 tmppar2 = tmppar->Clone();
3466 tmppar2->SetID(tmppar->GetID());
3468 // a memory optimization: Just store the layout information when only edit
3469 if (kind == Undo::EDIT){
3471 delete[] tmppar2->text;
3477 while (tmppar != end && tmppar->next) {
3478 tmppar = tmppar->next;
3479 tmppar2->next = tmppar->Clone();
3480 tmppar2->next->SetID(tmppar->GetID());
3481 // a memory optimization: Just store the layout information when only edit
3482 if (kind == Undo::EDIT){
3483 if (tmppar2->next->text)
3484 delete[] tmppar2->next->text;
3485 tmppar2->next->text = 0;
3487 tmppar2->next->previous = tmppar2;
3488 tmppar2=tmppar2->next;
3493 undopar = 0; // nothing to replace (undo of delete maybe)
3495 int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3496 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3498 Undo* undo = new Undo(kind,
3499 before_number, behind_number,
3500 cursor_par, cursor_pos,
3503 undo_finished = false;
3508 void LyXText::SetCursorParUndo()
3510 SetUndo(Undo::FINISH,
3511 cursor.par->ParFromPos(cursor.pos)->previous,
3512 cursor.par->ParFromPos(cursor.pos)->next);
3515 void LyXText::RemoveTableRow(LyXCursor *cursor)
3523 /* move to the previous row */
3524 cell_act = NumberOfCell(cursor->par, cursor->pos);
3527 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3529 while (cursor->pos &&
3530 !cursor->par->table->IsFirstCell(cell_act)){
3532 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3537 /* now we have to pay attention if the actual table is the
3538 main row of TableContRows and if yes to delete all of them */
3543 /* delete up to the next row */
3544 while (cursor->pos < cursor->par->Last() &&
3546 || !cursor->par->table->IsFirstCell(cell_act))){
3547 while (cursor->pos < cursor->par->Last() &&
3548 !cursor->par->IsNewline(cursor->pos))
3549 cursor->par->Erase(cursor->pos);
3552 if (cursor->pos < cursor->par->Last())
3553 cursor->par-> Erase(cursor->pos);
3555 if (cursor->pos && cursor->pos == cursor->par->Last()){
3557 cursor->par->Erase(cursor->pos); // no newline at the very end!
3559 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3560 !cursor->par->table->IsContRow(cell_org) &&
3561 cursor->par->table->IsContRow(cell));
3562 cursor->par->table->DeleteRow(cell_org);
3566 bool LyXText::IsEmptyTableRow(LyXCursor *old_cursor)
3568 if (!old_cursor->par->table)
3570 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3572 pos = old_cursor->pos,
3573 cell = NumberOfCell(old_cursor->par, pos);
3575 // search first charater of this table row
3576 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3578 while (pos && !old_cursor->par->IsNewline(pos-1))
3582 if (!old_cursor->par->IsNewline(pos))
3586 while ((pos < old_cursor->par->Last()) &&
3587 !old_cursor->par->table->IsFirstCell(cell)) {
3588 if (!old_cursor->par->IsNewline(pos))
3599 bool LyXText::IsEmptyTableCell()
3601 int pos = cursor.pos - 1;
3603 while ((pos>=0) && (pos < cursor.par->Last()) &&
3604 !cursor.par->IsNewline(pos))
3606 return cursor.par->IsNewline(pos+1);
3609 void LyXText::toggleAppendix(){
3610 LyXParagraph* par = cursor.par->FirstPhysicalPar();
3611 bool start = !par->start_of_appendix;
3613 /* ensure that we have only one start_of_appendix in this document */
3614 LyXParagraph* tmp = FirstParagraph();
3615 for (;tmp;tmp=tmp->next)
3616 tmp->start_of_appendix = 0;
3617 par->start_of_appendix = start;
3619 /* we can set the refreshing parameters now */
3620 status = LyXText::NEED_MORE_REFRESH;
3622 refresh_row = 0; // not needed for full update
3624 SetCursor(cursor.par, cursor.pos);