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.
102 LyXFont LyXText::GetFont(LyXParagraph * par,
103 LyXParagraph::size_type pos)
105 LyXFont LyXText::GetFont(LyXParagraph * par, int pos)
108 LyXLayout const & layout =
109 textclasslist.Style(parameters->textclass, par->GetLayout());
111 char par_depth = par->GetDepth();
112 // We specialize the 95% common case:
113 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
116 if (layout.labeltype == LABEL_MANUAL
117 && pos < BeginningOfMainBody(par)) {
119 return par->GetFontSettings(pos).
120 realize(layout.reslabelfont);
122 return par->GetFontSettings(pos).
123 realize(layout.resfont);
126 // process layoutfont for pos == -1 and labelfont for pos < -1
128 return layout.resfont;
130 return layout.reslabelfont;
134 // The uncommon case need not be optimized as much
136 LyXFont layoutfont, tmpfont;
140 if (pos < BeginningOfMainBody(par)) {
142 layoutfont = layout.labelfont;
145 layoutfont = layout.font;
147 tmpfont = par->GetFontSettings(pos);
148 tmpfont.realize(layoutfont);
151 // process layoutfont for pos == -1 and labelfont for pos < -1
153 tmpfont = layout.font;
155 tmpfont = layout.labelfont;
158 // Resolve against environment font information
159 while (par && par_depth && !tmpfont.resolved()) {
160 par = par->DepthHook(par_depth - 1);
162 tmpfont.realize(textclasslist.
163 Style(parameters->textclass,
164 par->GetLayout()).font);
165 par_depth = par->GetDepth();
169 tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
171 // Cosmetic improvement: If this is an open footnote, make the font
173 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
174 && par->footnotekind == LyXParagraph::FOOTNOTE) {
183 void LyXText::SetCharFont(LyXParagraph * par,
184 LyXParagraph::size_type pos,
187 void LyXText::SetCharFont(LyXParagraph * par, int pos, LyXFont font)
190 /* let the insets convert their font */
191 if (par->GetChar(pos) == LYX_META_INSET) {
192 if (par->GetInset(pos))
193 font = par->GetInset(pos)->ConvertFont(font);
196 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
199 // Get concrete layout font to reduce against
202 if (pos < BeginningOfMainBody(par))
203 layoutfont = layout.labelfont;
205 layoutfont = layout.font;
207 // Realize against environment font information
208 if (par->GetDepth()){
209 LyXParagraph * tp = par;
210 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
211 tp = tp->DepthHook(tp->GetDepth()-1);
213 layoutfont.realize(textclasslist.
214 Style(parameters->textclass,
215 tp->GetLayout()).font);
219 layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
221 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
222 && par->footnotekind == LyXParagraph::FOOTNOTE) {
223 layoutfont.decSize();
226 // Now, reduce font against full layout font
227 font.reduce(layoutfont);
229 par->SetFont(pos, font);
233 /* inserts a new row behind the specified row, increments
234 * the touched counters */
236 void LyXText::InsertRow(Row * row, LyXParagraph * par,
237 LyXParagraph::size_type pos)
239 void LyXText::InsertRow(Row * row, LyXParagraph * par, int pos)
242 Row * tmprow = new Row;
244 tmprow->previous = 0;
245 tmprow->next = firstrow;
249 tmprow->previous = row;
250 tmprow->next = row->next;
255 tmprow->next->previous = tmprow;
257 if (tmprow->previous)
258 tmprow->previous->next = tmprow;
266 number_of_rows++; /* one more row */
270 /* removes the row and reset the touched counters */
271 void LyXText::RemoveRow(Row * row)
273 /* this must not happen before the currentrow for clear reasons.
274 so the trick is just to set the current row onto the previous
277 GetRow(row->par, row->pos, unused_y);
278 currentrow = currentrow->previous;
280 currentrow_y -= currentrow->height;
285 row->next->previous = row->previous;
286 if (!row->previous) {
287 firstrow = row->next;
290 row->previous->next = row->next;
293 lastrow = row->previous;
295 height -= row->height; /* the text becomes smaller */
298 --number_of_rows; /* one row less */
302 /* remove all following rows of the paragraph of the specified row. */
303 void LyXText::RemoveParagraph(Row * row)
307 LyXParagraph * tmppar = row->par;
310 while (row && row->par == tmppar) {
318 /* insert the specified paragraph behind the specified row */
319 void LyXText::InsertParagraph(LyXParagraph * par, Row * row)
321 InsertRow(row, par, 0); /* insert a new row, starting
324 SetCounter(par); /* set the counters */
326 /* and now append the whole paragraph behind the new row */
328 firstrow->height = 0;
329 AppendParagraph(firstrow);
332 row->next->height = 0;
333 AppendParagraph(row->next);
338 void LyXText::ToggleFootnote()
340 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
341 if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
343 minibuffer->Set(_("Opened float"));
346 minibuffer->Set(_("Closed float"));
352 void LyXText::OpenStuff()
354 if (cursor.pos == 0 && cursor.par->bibkey){
355 cursor.par->bibkey->Edit(0,0);
357 else if (cursor.pos < cursor.par->Last()
358 && cursor.par->GetChar(cursor.pos) == LYX_META_INSET
359 && cursor.par->GetInset(cursor.pos)->Editable()) {
360 minibuffer->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
361 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
363 cursor.par->GetInset(cursor.pos)->Edit(0,0);
371 void LyXText::CloseFootnote()
373 LyXParagraph * endpar, * tmppar;
376 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
378 /* if the cursor is not in an open footnote, or
379 * there is no open footnote in this paragraph, just return. */
380 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
383 || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
384 minibuffer->Set(_("Nothing to do"));
388 /* ok, move the cursor right before the footnote */
390 /* just a little faster than using CursorRight() */
391 for (cursor.pos=0; cursor.par->ParFromPos(cursor.pos)!=par; cursor.pos++);
392 /* now the cursor is at the beginning of the physical par */
394 SetCursor(cursor.par,
396 cursor.par->ParFromPos(cursor.pos)->text.size());
398 SetCursor(cursor.par, cursor.pos + cursor.par->ParFromPos(cursor.pos)->last);
402 /* we are in a footnote, so let us move at the beginning */
403 /* this is just faster than using just CursorLeft() */
406 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
407 /* just a little bit faster than movin the cursor */
408 tmppar = tmppar->Previous();
410 SetCursor(tmppar, tmppar->Last());
413 /* the cursor must be exactly before the footnote */
414 par = cursor.par->ParFromPos(cursor.pos);
416 status = LyXText::NEED_MORE_REFRESH;
417 refresh_row = cursor.row;
418 refresh_y = cursor.y - cursor.row->baseline;
421 endpar = par->NextAfterFootnote()->Next();
424 tmppar->CloseFootnote(cursor.pos);
426 while (tmppar != endpar) {
427 RemoveRow(row->next);
429 tmppar = row->next->par;
434 AppendParagraph(cursor.row);
436 SetCursor(cursor.par, cursor.pos);
440 if (cursor.row->next)
441 SetHeightOfRow(cursor.row->next);
445 /* used in setlayout */
446 // Asger is not sure we want to do this...
447 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
449 LyXFont layoutfont, tmpfont;
451 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
454 for (LyXParagraph::size_type pos = 0;
455 pos < par->Last(); ++pos) {
457 for (int pos = 0; pos < par->Last(); pos++) {
459 if (pos < BeginningOfMainBody(par))
460 layoutfont = layout.labelfont;
462 layoutfont = layout.font;
464 tmpfont = par->GetFontSettings(pos);
465 tmpfont.reduce(layoutfont);
466 par->SetFont(pos, tmpfont);
471 /* set layout over selection and make a total rebreak of those paragraphs */
472 void LyXText::SetLayout(char layout)
476 /* if there is no selection just set the layout of the current paragraph */
478 sel_start_cursor = cursor; /* dummy selection */
479 sel_end_cursor = cursor;
482 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
483 LyXParagraph * undoendpar = endpar;
485 if (endpar && endpar->GetDepth()) {
486 while (endpar && endpar->GetDepth()) {
487 endpar = endpar->LastPhysicalPar()->Next();
492 endpar = endpar->Next(); /* because of parindents etc. */
496 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
499 tmpcursor = cursor; /* store the current cursor */
501 /* ok we have a selection. This is always between sel_start_cursor
502 * and sel_end cursor */
503 cursor = sel_start_cursor;
505 LyXLayout const & lyxlayout = textclasslist.Style(parameters->textclass, layout);
507 while (cursor.par != sel_end_cursor.par) {
508 if (cursor.par->footnoteflag ==
509 sel_start_cursor.par->footnoteflag) {
510 cursor.par->SetLayout(layout);
511 MakeFontEntriesLayoutSpecific(cursor.par);
512 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
513 fppar->added_space_top = lyxlayout.fill_top ?
514 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
515 fppar->added_space_bottom = lyxlayout.fill_bottom ?
516 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
517 if (lyxlayout.margintype == MARGIN_MANUAL)
518 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
519 if (lyxlayout.labeltype != LABEL_BIBLIO
521 delete fppar->bibkey;
525 cursor.par = cursor.par->Next();
527 if (cursor.par->footnoteflag ==
528 sel_start_cursor.par->footnoteflag) {
529 cursor.par->SetLayout(layout);
530 MakeFontEntriesLayoutSpecific(cursor.par);
531 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
532 fppar->added_space_top = lyxlayout.fill_top ?
533 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
534 fppar->added_space_bottom = lyxlayout.fill_bottom ?
535 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
536 if (lyxlayout.margintype == MARGIN_MANUAL)
537 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
538 if (lyxlayout.labeltype != LABEL_BIBLIO
540 delete fppar->bibkey;
545 RedoParagraphs(sel_start_cursor, endpar);
547 /* we have to reset the selection, because the
548 * geometry could have changed */
549 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
551 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
552 UpdateCounters(cursor.row);
555 SetCursor(tmpcursor.par, tmpcursor.pos);
559 /* increment depth over selection and
560 * make a total rebreak of those paragraphs */
561 void LyXText::IncDepth()
563 // If there is no selection, just use the current paragraph
565 sel_start_cursor = cursor; /* dummy selection */
566 sel_end_cursor = cursor;
569 // We end at the next paragraph with depth 0
570 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
571 LyXParagraph * undoendpar = endpar;
573 if (endpar && endpar->GetDepth()) {
574 while (endpar && endpar->GetDepth()) {
575 endpar = endpar->LastPhysicalPar()->Next();
580 endpar = endpar->Next(); /* because of parindents etc. */
584 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
587 LyXCursor tmpcursor = cursor; /* store the current cursor */
589 /* ok we have a selection. This is always between sel_start_cursor
590 * and sel_end cursor */
591 cursor = sel_start_cursor;
593 bool anything_changed = false;
596 // NOTE: you can't change the depth of a bibliography entry
597 if (cursor.par->footnoteflag ==
598 sel_start_cursor.par->footnoteflag
599 && textclasslist.Style(parameters->textclass,
600 cursor.par->GetLayout()
601 ).labeltype != LABEL_BIBLIO) {
602 LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
604 && (prev->GetDepth() - cursor.par->GetDepth() > 0
605 || (prev->GetDepth() == cursor.par->GetDepth()
606 && textclasslist.Style(parameters->textclass,
607 prev->GetLayout()).isEnvironment()))) {
608 cursor.par->FirstPhysicalPar()->depth++;
609 anything_changed = true;
612 if (cursor.par == sel_end_cursor.par)
614 cursor.par = cursor.par->Next();
617 /* if nothing changed set all depth to 0 */
618 if (!anything_changed) {
619 cursor = sel_start_cursor;
620 while (cursor.par != sel_end_cursor.par) {
621 cursor.par->FirstPhysicalPar()->depth = 0;
622 cursor.par = cursor.par->Next();
624 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
625 cursor.par->FirstPhysicalPar()->depth = 0;
628 RedoParagraphs(sel_start_cursor, endpar);
630 /* we have to reset the selection, because the
631 * geometry could have changed */
632 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
634 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
635 UpdateCounters(cursor.row);
638 SetCursor(tmpcursor.par, tmpcursor.pos);
642 /* decrement depth over selection and
643 * make a total rebreak of those paragraphs */
644 void LyXText::DecDepth()
646 /* if there is no selection just set the layout of the current paragraph */
648 sel_start_cursor = cursor; /* dummy selection */
649 sel_end_cursor = cursor;
652 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
653 LyXParagraph * undoendpar = endpar;
655 if (endpar && endpar->GetDepth()) {
656 while (endpar && endpar->GetDepth()) {
657 endpar = endpar->LastPhysicalPar()->Next();
662 endpar = endpar->Next(); /* because of parindents etc. */
666 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
669 LyXCursor tmpcursor = cursor; /* store the current cursor */
671 /* ok we have a selection. This is always between sel_start_cursor
672 * and sel_end cursor */
673 cursor = sel_start_cursor;
676 if (cursor.par->footnoteflag ==
677 sel_start_cursor.par->footnoteflag) {
678 if (cursor.par->FirstPhysicalPar()->depth)
679 cursor.par->FirstPhysicalPar()->depth--;
681 if (cursor.par == sel_end_cursor.par)
683 cursor.par = cursor.par->Next();
686 RedoParagraphs(sel_start_cursor, endpar);
688 /* we have to reset the selection, because the
689 * geometry could have changed */
690 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
692 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
693 UpdateCounters(cursor.row);
696 SetCursor(tmpcursor.par, tmpcursor.pos);
700 /* set font over selection and make a total rebreak of those paragraphs */
701 void LyXText::SetFont(LyXFont font, bool toggleall)
703 /* if there is no selection just set the current_font */
705 // Determine basis font
707 if (cursor.pos < BeginningOfMainBody(cursor.par))
708 layoutfont = GetFont(cursor.par, -2);
710 layoutfont = GetFont(cursor.par, -1);
711 // Update current font
712 real_current_font.update(font,toggleall);
714 // Reduce to implicit settings
715 current_font = real_current_font;
716 current_font.reduce(layoutfont);
717 // And resolve it completely
718 real_current_font.realize(layoutfont);
722 LyXCursor tmpcursor = cursor; /* store the current cursor */
724 /* ok we have a selection. This is always between sel_start_cursor
725 * and sel_end cursor */
728 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
729 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
730 cursor = sel_start_cursor;
731 while (cursor.par != sel_end_cursor.par ||
732 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
733 && cursor.pos < sel_end_cursor.pos))
735 if (cursor.pos < cursor.par->Last()
736 && cursor.par->footnoteflag
737 == sel_start_cursor.par->footnoteflag) { /* an open footnote
740 LyXFont newfont = GetFont(cursor.par,cursor.pos);
741 newfont.update(font,toggleall);
742 SetCharFont(cursor.par, cursor.pos, newfont);
746 cursor.par = cursor.par->Next();
750 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
752 /* we have to reset the selection, because the
753 * geometry could have changed */
754 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
756 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
759 SetCursor(tmpcursor.par, tmpcursor.pos);
763 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
765 Row * tmprow = cursor.row;
766 long y = cursor.y - tmprow->baseline;
768 SetHeightOfRow(tmprow);
769 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
770 /* find the first row of the paragraph */
771 if (first_phys_par != tmprow->par)
772 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
773 tmprow = tmprow->previous;
775 SetHeightOfRow(tmprow);
777 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
778 tmprow = tmprow->previous;
780 SetHeightOfRow(tmprow);
783 /* we can set the refreshing parameters now */
784 status = LyXText::NEED_MORE_REFRESH;
786 refresh_row = tmprow;
787 SetCursor(cursor.par, cursor.pos);
791 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
793 Row * tmprow = cursor.row;
795 long y = cursor.y - tmprow->baseline;
796 SetHeightOfRow(tmprow);
797 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
798 /* find the first row of the paragraph */
799 if (first_phys_par != tmprow->par)
800 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
801 tmprow = tmprow->previous;
804 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
805 tmprow = tmprow->previous;
810 /* we can set the refreshing parameters now */
811 if (status == LyXText::UNCHANGED || y < refresh_y) {
813 refresh_row = tmprow;
815 status = LyXText::NEED_MORE_REFRESH;
816 SetCursor(cursor.par, cursor.pos);
820 /* deletes and inserts again all paragaphs between the cursor
821 * and the specified par
822 * This function is needed after SetLayout and SetFont etc. */
823 void LyXText::RedoParagraphs(LyXCursor cursor, LyXParagraph * endpar)
826 LyXParagraph * tmppar, * first_phys_par;
828 Row * tmprow = cursor.row;
830 long y = cursor.y - tmprow->baseline;
832 if (!tmprow->previous){
833 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
836 first_phys_par = tmprow->par->FirstPhysicalPar();
837 /* find the first row of the paragraph */
838 if (first_phys_par != tmprow->par)
839 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
840 tmprow = tmprow->previous;
843 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
844 tmprow = tmprow->previous;
849 /* we can set the refreshing parameters now */
850 status = LyXText::NEED_MORE_REFRESH;
852 refresh_row = tmprow->previous; /* the real refresh row will
853 * be deleted, so I store
854 * the previous here */
857 tmppar = tmprow->next->par;
860 while (tmppar != endpar) {
861 RemoveRow(tmprow->next);
863 tmppar = tmprow->next->par;
868 /* remove the first one */
869 tmprow2 = tmprow; /* this is because tmprow->previous
871 tmprow = tmprow->previous;
874 tmppar = first_phys_par;
878 InsertParagraph(tmppar, tmprow);
881 while (tmprow->next && tmprow->next->par == tmppar)
882 tmprow = tmprow->next;
883 tmppar = tmppar->Next();
887 while (tmppar != endpar);
889 /* this is because of layout changes */
891 refresh_y -= refresh_row->height;
892 SetHeightOfRow(refresh_row);
895 refresh_row = firstrow;
897 SetHeightOfRow(refresh_row);
900 if (tmprow && tmprow->next)
901 SetHeightOfRow(tmprow->next);
905 int LyXText::FullRebreak()
907 if (need_break_row) {
908 BreakAgain(need_break_row);
916 /* important for the screen */
919 /* the cursor set functions have a special mechanism. When they
920 * realize, that you left an empty paragraph, they will delete it.
921 * They also delet the corresponding row */
923 /* need the selection cursor: */
924 void LyXText::SetSelection()
927 last_sel_cursor = sel_cursor;
928 sel_start_cursor = sel_cursor;
929 sel_end_cursor = sel_cursor;
934 /* first the toggling area */
935 if (cursor.y < last_sel_cursor.y ||
936 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
937 toggle_end_cursor = last_sel_cursor;
938 toggle_cursor = cursor;
941 toggle_end_cursor = cursor;
942 toggle_cursor = last_sel_cursor;
945 last_sel_cursor = cursor;
947 /* and now the whole selection */
949 if (sel_cursor.y < cursor.y ||
950 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
951 sel_end_cursor = cursor;
952 sel_start_cursor = sel_cursor;
955 sel_end_cursor = sel_cursor;
956 sel_start_cursor = cursor;
959 /* a selection with no contents is not a selection */
960 if (sel_start_cursor.x == sel_end_cursor.x &&
961 sel_start_cursor.y == sel_end_cursor.y)
966 void LyXText::ClearSelection()
973 void LyXText::CursorHome()
975 SetCursor(cursor.par, cursor.row->pos);
979 void LyXText::CursorEnd()
981 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
982 SetCursor(cursor.par, RowLast(cursor.row) + 1);
984 if (cursor.par->Last() &&
985 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
986 || cursor.par->IsNewline(RowLast(cursor.row))))
987 SetCursor(cursor.par, RowLast(cursor.row));
989 SetCursor(cursor.par, RowLast(cursor.row) + 1);
991 if (cursor.par->table) {
992 int cell = NumberOfCell(cursor.par, cursor.pos);
993 if (cursor.par->table->RowHasContRow(cell) &&
994 cursor.par->table->CellHasContRow(cell)<0) {
995 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
996 SetCursor(cursor.par, RowLast(cursor.row) + 1);
998 if (cursor.par->Last() &&
999 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1000 || cursor.par->IsNewline(RowLast(cursor.row))))
1001 SetCursor(cursor.par, RowLast(cursor.row));
1003 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1010 void LyXText::CursorTop()
1012 while (cursor.par->Previous())
1013 cursor.par = cursor.par->Previous();
1014 SetCursor(cursor.par, 0);
1018 void LyXText::CursorBottom()
1020 while (cursor.par->Next())
1021 cursor.par = cursor.par->Next();
1022 SetCursor(cursor.par, cursor.par->Last());
1026 /* returns a pointer to the row near the specified y-coordinate
1027 * (relative to the whole text). y is set to the real beginning
1029 Row * LyXText::GetRowNearY(long & y)
1035 tmprow = currentrow;
1036 tmpy = currentrow_y;
1044 while (tmprow->next && tmpy + tmprow->height <= y) {
1045 tmpy += tmprow->height;
1046 tmprow = tmprow->next;
1049 while (tmprow->previous && tmpy > y) {
1050 tmprow = tmprow->previous;
1051 tmpy -= tmprow->height;
1054 currentrow = tmprow;
1055 currentrow_y = tmpy;
1057 y = tmpy; /* return the real y */
1062 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1064 // If the mask is completely neutral, tell user
1065 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1066 // Could only happen with user style
1067 minibuffer->Set(_("No font change defined. Use Character under"
1068 " the Layout menu to define font change."));
1072 // Try implicit word selection
1073 LyXCursor resetCursor = cursor;
1074 int implicitSelection = SelectWordWhenUnderCursor();
1077 SetFont(font,toggleall);
1078 //minibuffer->Set(_("Font style changed"));
1080 /* Implicit selections are cleared afterwards and cursor is set to the
1081 original position. */
1082 if (implicitSelection) {
1084 cursor = resetCursor;
1085 SetCursor( cursor.par, cursor.pos );
1086 sel_cursor = cursor;
1092 LyXParagraph::size_type
1093 LyXText::BeginningOfMainBody(LyXParagraph * par)
1095 int LyXText::BeginningOfMainBody(LyXParagraph * par)
1098 if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1101 return par->BeginningOfMainBody();
1105 /* if there is a selection, reset every environment you can find
1106 * in the selection, otherwise just the environment you are in */
1107 void LyXText::MeltFootnoteEnvironment()
1109 LyXParagraph * tmppar, * firsttmppar;
1113 /* is is only allowed, if the cursor is IN an open footnote.
1114 * Otherwise it is too dangerous */
1115 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1118 SetUndo(Undo::FINISH,
1119 cursor.par->PreviousBeforeFootnote()->previous,
1120 cursor.par->NextAfterFootnote()->next);
1122 /* ok, move to the beginning of the footnote. */
1123 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1124 cursor.par = cursor.par->Previous();
1126 SetCursor(cursor.par, cursor.par->Last());
1127 /* this is just faster than using CursorLeft(); */
1129 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1130 tmppar = firsttmppar;
1131 /* tmppar is now the paragraph right before the footnote */
1134 char first_footnote_par_is_not_empty = tmppar->next->text.size();
1136 char first_footnote_par_is_not_empty = tmppar->next->last;
1139 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1140 tmppar = tmppar->next; /* I use next instead of Next(),
1141 * because there cannot be any
1142 * footnotes in a footnote
1144 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1146 /* remember the captions and empty paragraphs */
1147 if ((textclasslist.Style(parameters->textclass,
1148 tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1150 tmppar->SetLayout(0);
1153 /* now we will paste the ex-footnote, if the layouts allow it */
1154 /* first restore the layout of the paragraph right behind the footnote*/
1156 tmppar->next->MakeSameLayout(cursor.par);
1159 if ((!tmppar->GetLayout() && !tmppar->table)
1160 || (tmppar->Next() && (!tmppar->Next()->Last()
1161 || tmppar->Next()->HasSameLayout(tmppar)))) {
1162 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1163 tmppar->Next()->Erase(0);
1164 tmppar->PasteParagraph();
1167 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1168 * by the pasting of the beginning */
1170 /* then the beginning */
1171 /* if there is no space between the text and the footnote, so we insert
1173 * (only if the previous par and the footnotepar are not empty!) */
1174 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1175 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1177 if (firsttmppar->text.size()
1178 && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1180 if (firsttmppar->last
1181 && !firsttmppar->IsSeparator(firsttmppar->last - 1)
1183 && first_footnote_par_is_not_empty) {
1184 firsttmppar->next->InsertChar(0, ' ');
1186 firsttmppar->PasteParagraph();
1189 /* now redo the paragaphs */
1190 RedoParagraphs(cursor, tmppar);
1192 SetCursor(cursor.par, cursor.pos);
1194 /* sometimes it can happen, that there is a counter change */
1195 Row * row = cursor.row;
1196 while (row->next && row->par != tmppar && row->next->par != tmppar)
1198 UpdateCounters(row);
1205 /* the DTP switches for paragraphs. LyX will store them in the
1206 * first physicla paragraph. When a paragraph is broken, the top settings
1207 * rest, the bottom settings are given to the new one. So I can make shure,
1208 * they do not duplicate themself and you cannnot make dirty things with
1211 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1212 bool pagebreak_top, bool pagebreak_bottom,
1213 VSpace space_top, VSpace space_bottom,
1215 string labelwidthstring,
1218 LyXCursor tmpcursor = cursor;
1220 sel_start_cursor = cursor;
1221 sel_end_cursor = cursor;
1224 // make sure that the depth behind the selection are restored, too
1225 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1226 LyXParagraph * undoendpar = endpar;
1228 if (endpar && endpar->GetDepth()) {
1229 while (endpar && endpar->GetDepth()) {
1230 endpar = endpar->LastPhysicalPar()->Next();
1231 undoendpar = endpar;
1235 endpar = endpar->Next(); /* because of parindents etc. */
1239 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1243 LyXParagraph * tmppar = sel_end_cursor.par;
1244 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1245 SetCursor(tmppar->FirstPhysicalPar(), 0);
1246 status = LyXText::NEED_MORE_REFRESH;
1247 refresh_row = cursor.row;
1248 refresh_y = cursor.y - cursor.row->baseline;
1249 if (cursor.par->footnoteflag ==
1250 sel_start_cursor.par->footnoteflag) {
1251 cursor.par->line_top = line_top;
1252 cursor.par->line_bottom = line_bottom;
1253 cursor.par->pagebreak_top = pagebreak_top;
1254 cursor.par->pagebreak_bottom = pagebreak_bottom;
1255 cursor.par->added_space_top = space_top;
1256 cursor.par->added_space_bottom = space_bottom;
1257 /* does the layout allow the new alignment? */
1258 if (align == LYX_ALIGN_LAYOUT)
1259 align = textclasslist
1260 .Style(parameters->textclass,
1261 cursor.par->GetLayout()).align;
1262 if (align & textclasslist
1263 .Style(parameters->textclass,
1264 cursor.par->GetLayout()).alignpossible) {
1265 if (align == textclasslist
1266 .Style(parameters->textclass,
1267 cursor.par->GetLayout()).align)
1268 cursor.par->align = LYX_ALIGN_LAYOUT;
1270 cursor.par->align = align;
1272 cursor.par->SetLabelWidthString(labelwidthstring);
1273 cursor.par->noindent = noindent;
1276 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1279 RedoParagraphs(sel_start_cursor, endpar);
1282 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1283 sel_cursor = cursor;
1284 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1286 SetCursor(tmpcursor.par, tmpcursor.pos);
1290 void LyXText::SetParagraphExtraOpt(int type,
1292 char const * widthp,
1293 int alignment, bool hfill,
1294 bool start_minipage)
1296 LyXCursor tmpcursor = cursor;
1297 LyXParagraph * tmppar;
1299 sel_start_cursor = cursor;
1300 sel_end_cursor = cursor;
1303 // make sure that the depth behind the selection are restored, too
1304 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1305 LyXParagraph * undoendpar = endpar;
1307 if (endpar && endpar->GetDepth()) {
1308 while (endpar && endpar->GetDepth()) {
1309 endpar = endpar->LastPhysicalPar()->Next();
1310 undoendpar = endpar;
1314 endpar = endpar->Next(); /* because of parindents etc. */
1318 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1321 tmppar = sel_end_cursor.par;
1322 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1323 SetCursor(tmppar->FirstPhysicalPar(), 0);
1324 status = LyXText::NEED_MORE_REFRESH;
1325 refresh_row = cursor.row;
1326 refresh_y = cursor.y - cursor.row->baseline;
1327 if (cursor.par->footnoteflag ==
1328 sel_start_cursor.par->footnoteflag) {
1329 if (type == PEXTRA_NONE) {
1330 if (cursor.par->pextra_type != PEXTRA_NONE) {
1331 cursor.par->UnsetPExtraType();
1332 cursor.par->pextra_type=PEXTRA_NONE;
1335 cursor.par->SetPExtraType(type,width,widthp);
1336 cursor.par->pextra_hfill = hfill;
1337 cursor.par->pextra_start_minipage = start_minipage;
1338 cursor.par->pextra_alignment = alignment;
1341 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1343 RedoParagraphs(sel_start_cursor, endpar);
1345 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1346 sel_cursor = cursor;
1347 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1349 SetCursor(tmpcursor.par, tmpcursor.pos);
1353 static char const * alphaCounter(int n){
1354 static char result[2];
1367 /* set the counter of a paragraph. This includes the labels */
1368 void LyXText::SetCounter(LyXParagraph * par)
1372 /* this is only relevant for the beginning of paragraph */
1373 par = par->FirstPhysicalPar();
1375 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1378 LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1380 /* copy the prev-counters to this one, unless this is the start of a
1381 footnote or of a bibliography or the very first paragraph */
1383 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1384 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1385 && par->footnotekind == LyXParagraph::FOOTNOTE)
1386 && !(textclasslist.Style(parameters->textclass,
1387 par->Previous()->GetLayout()
1388 ).labeltype != LABEL_BIBLIO
1389 && layout.labeltype == LABEL_BIBLIO)) {
1390 for (i=0; i<10; i++) {
1391 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1393 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1394 if (!par->appendix && par->start_of_appendix){
1395 par->appendix = true;
1396 for (i=0; i<10; i++) {
1397 par->setCounter(i, 0);
1400 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1401 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1404 for (i=0; i<10; i++) {
1405 par->setCounter(i, 0);
1407 par->appendix = par->start_of_appendix;
1412 // if this is an open marginnote and this is the first
1413 // entry in the marginnote and the enclosing
1414 // environment is an enum/item then correct for the
1415 // LaTeX behaviour (ARRae)
1416 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1417 && par->footnotekind == LyXParagraph::MARGIN
1419 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1420 && (par->PreviousBeforeFootnote()
1421 && textclasslist.Style(parameters->textclass,
1422 par->PreviousBeforeFootnote()->GetLayout()
1423 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1424 // Any itemize or enumerate environment in a marginnote
1425 // that is embedded in an itemize or enumerate
1426 // paragraph is seen by LaTeX as being at a deeper
1427 // level within that enclosing itemization/enumeration
1428 // even if there is a "standard" layout at the start of
1434 /* Maybe we have to increment the enumeration depth.
1435 * BUT, enumeration in a footnote is considered in isolation from its
1436 * surrounding paragraph so don't increment if this is the
1437 * first line of the footnote
1438 * AND, bibliographies can't have their depth changed ie. they
1439 * are always of depth 0
1442 && par->Previous()->GetDepth() < par->GetDepth()
1443 && textclasslist.Style(parameters->textclass,
1444 par->Previous()->GetLayout()
1445 ).labeltype == LABEL_COUNTER_ENUMI
1446 && par->enumdepth < 3
1447 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1448 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1449 && par->footnotekind == LyXParagraph::FOOTNOTE)
1450 && layout.labeltype != LABEL_BIBLIO) {
1454 /* Maybe we have to decrement the enumeration depth, see note above */
1456 && par->Previous()->GetDepth() > par->GetDepth()
1457 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1458 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1459 && par->footnotekind == LyXParagraph::FOOTNOTE)
1460 && layout.labeltype != LABEL_BIBLIO) {
1461 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1462 par->setCounter(6 + par->enumdepth,
1463 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1464 /* reset the counters.
1465 * A depth change is like a breaking layout
1467 for (i=6 + par->enumdepth + 1; i<10;i++)
1468 par->setCounter(i, 0);
1471 if (!par->labelstring.empty()) {
1472 par->labelstring.clear();
1475 if (layout.margintype == MARGIN_MANUAL) {
1476 if (par->labelwidthstring.empty()) {
1477 par->SetLabelWidthString(layout.labelstring());
1481 par->SetLabelWidthString(string());
1484 /* is it a layout that has an automatic label ? */
1485 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1487 i = layout.labeltype - LABEL_FIRST_COUNTER;
1488 if (i >= 0 && i<=parameters->secnumdepth) {
1489 par->incCounter(i); // increment the counter
1491 char * s = new char[50];
1493 // Is there a label? Useful for Chapter layout
1494 if (!par->appendix){
1495 if (!layout.labelstring().empty())
1496 par->labelstring = layout.labelstring();
1498 par->labelstring.clear();
1501 if (!layout.labelstring_appendix().empty())
1502 par->labelstring = layout.labelstring_appendix();
1504 par->labelstring.clear();
1507 if (!par->appendix){
1508 switch (2 * LABEL_FIRST_COUNTER -
1509 textclass.maxcounter() + i) {
1510 case LABEL_COUNTER_CHAPTER:
1512 par->getCounter(i));
1514 case LABEL_COUNTER_SECTION:
1516 par->getCounter(i - 1),
1517 par->getCounter(i));
1519 case LABEL_COUNTER_SUBSECTION:
1520 sprintf(s, "%d.%d.%d",
1521 par->getCounter(i-2),
1522 par->getCounter(i-1),
1523 par->getCounter(i));
1525 case LABEL_COUNTER_SUBSUBSECTION:
1526 sprintf(s, "%d.%d.%d.%d",
1527 par->getCounter(i-3),
1528 par->getCounter(i-2),
1529 par->getCounter(i-1),
1530 par->getCounter(i));
1532 case LABEL_COUNTER_PARAGRAPH:
1533 sprintf(s, "%d.%d.%d.%d.%d",
1534 par->getCounter(i-4),
1535 par->getCounter(i-3),
1536 par->getCounter(i-2),
1537 par->getCounter(i-1),
1538 par->getCounter(i));
1540 case LABEL_COUNTER_SUBPARAGRAPH:
1541 sprintf(s, "%d.%d.%d.%d.%d.%d",
1542 par->getCounter(i-5),
1543 par->getCounter(i-4),
1544 par->getCounter(i-3),
1545 par->getCounter(i-2),
1546 par->getCounter(i-1),
1547 par->getCounter(i));
1550 sprintf(s, "%d.", par->getCounter(i));
1555 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1556 case LABEL_COUNTER_CHAPTER:
1558 alphaCounter(par->getCounter(i)));
1560 case LABEL_COUNTER_SECTION:
1562 alphaCounter(par->getCounter(i - 1)),
1563 par->getCounter(i));
1565 case LABEL_COUNTER_SUBSECTION:
1566 sprintf(s, "%s.%d.%d",
1567 alphaCounter(par->getCounter(i-2)),
1568 par->getCounter(i-1),
1569 par->getCounter(i));
1571 case LABEL_COUNTER_SUBSUBSECTION:
1572 sprintf(s, "%s.%d.%d.%d",
1573 alphaCounter(par->getCounter(i-3)),
1574 par->getCounter(i-2),
1575 par->getCounter(i-1),
1576 par->getCounter(i));
1578 case LABEL_COUNTER_PARAGRAPH:
1579 sprintf(s, "%s.%d.%d.%d.%d",
1580 alphaCounter(par->getCounter(i-4)),
1581 par->getCounter(i-3),
1582 par->getCounter(i-2),
1583 par->getCounter(i-1),
1584 par->getCounter(i));
1586 case LABEL_COUNTER_SUBPARAGRAPH:
1587 sprintf(s, "%s.%d.%d.%d.%d.%d",
1588 alphaCounter(par->getCounter(i-5)),
1589 par->getCounter(i-4),
1590 par->getCounter(i-3),
1591 par->getCounter(i-2),
1592 par->getCounter(i-1),
1593 par->getCounter(i));
1596 sprintf(s, "%c.", par->getCounter(i));
1601 par->labelstring += s;
1604 for (i++; i<10; i++) {
1605 /* reset the following counters */
1606 par->setCounter(i, 0);
1608 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1609 for (i++; i<10; i++) {
1610 /* reset the following counters */
1611 par->setCounter(i, 0);
1613 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1614 par->incCounter(i + par->enumdepth);
1615 char * s = new char[25];
1616 int number = par->getCounter(i + par->enumdepth);
1617 switch (par->enumdepth) {
1619 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1623 case 1: sprintf(s, "i."); break;
1624 case 2: sprintf(s, "ii."); break;
1625 case 3: sprintf(s, "iii."); break;
1626 case 4: sprintf(s, "iv."); break;
1627 case 5: sprintf(s, "v."); break;
1628 case 6: sprintf(s, "vi."); break;
1629 case 7: sprintf(s, "vii."); break;
1630 case 8: sprintf(s, "viii."); break;
1631 case 9: sprintf(s, "ix."); break;
1632 case 10: sprintf(s, "x."); break;
1633 case 11: sprintf(s, "xi."); break;
1634 case 12: sprintf(s, "xii."); break;
1635 case 13: sprintf(s, "xiii."); break;
1637 sprintf(s, "\\roman{%d}.", number);
1642 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1645 sprintf(s, "%d.", number);
1648 par->labelstring = s;
1651 for (i += par->enumdepth + 1;i<10;i++)
1652 par->setCounter(i, 0); /* reset the following counters */
1655 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1656 i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1658 int number = par->getCounter(i);
1660 par->bibkey = new InsetBibKey();
1661 par->bibkey->setCounter(number);
1662 par->labelstring = layout.labelstring();
1664 // In biblio should't be following counters but...
1667 string s = layout.labelstring();
1669 /* the caption hack: */
1671 if (layout.labeltype == LABEL_SENSITIVE) {
1672 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1673 && (par->footnotekind == LyXParagraph::FIG
1674 || par->footnotekind == LyXParagraph::WIDE_FIG))
1676 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1677 && (par->footnotekind == LyXParagraph::TAB
1678 || par->footnotekind == LyXParagraph::WIDE_TAB))
1680 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1681 && par->footnotekind == LyXParagraph::ALGORITHM)
1684 /* par->SetLayout(0);
1685 s = layout->labelstring; */
1690 par->labelstring = s;
1692 /* reset the enumeration counter. They are always resetted
1693 * when there is any other layout between */
1694 for (i=6 + par->enumdepth; i<10;i++)
1695 par->setCounter(i, 0);
1700 /* Updates all counters BEHIND the row. Changed paragraphs
1701 * with a dynamic left margin will be rebroken. */
1702 void LyXText::UpdateCounters(Row * row)
1710 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1711 par = row->par->LastPhysicalPar()->Next();
1713 par = row->par->next;
1718 while (row->par != par)
1723 /* now check for the headline layouts. remember that they
1724 * have a dynamic left margin */
1726 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1727 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1730 /* Rebreak the paragraph */
1731 RemoveParagraph(row);
1732 AppendParagraph(row);
1734 /* think about the damned open footnotes! */
1735 while (par->Next() &&
1736 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1737 || par->Next()->IsDummy())){
1739 if (par->IsDummy()) {
1740 while (row->par != par)
1742 RemoveParagraph(row);
1743 AppendParagraph(row);
1748 par = par->LastPhysicalPar()->Next();
1754 /* insets an inset. */
1755 void LyXText::InsertInset(Inset *inset)
1757 SetUndo(Undo::INSERT,
1758 cursor.par->ParFromPos(cursor.pos)->previous,
1759 cursor.par->ParFromPos(cursor.pos)->next);
1760 cursor.par->InsertChar(cursor.pos, LYX_META_INSET);
1761 cursor.par->InsertInset(cursor.pos, inset);
1762 InsertChar(LYX_META_INSET); /* just to rebreak and refresh correctly.
1763 * The character will not be inserted a
1768 /* this is for the simple cut and paste mechanism */
1769 static LyXParagraph * simple_cut_buffer = 0;
1770 static char simple_cut_buffer_textclass = 0;
1772 void DeleteSimpleCutBuffer()
1774 if (!simple_cut_buffer)
1776 LyXParagraph *tmppar;
1778 while (simple_cut_buffer) {
1779 tmppar = simple_cut_buffer;
1780 simple_cut_buffer = simple_cut_buffer->next;
1783 simple_cut_buffer = 0;
1787 void LyXText::copyEnvironmentType()
1789 copylayouttype = cursor.par->GetLayout();
1793 void LyXText::pasteEnvironmentType()
1795 SetLayout(copylayouttype);
1799 void LyXText::CutSelection(bool doclear)
1801 /* This doesn't make sense, if there is no selection */
1806 /* OK, we have a selection. This is always between sel_start_cursor
1807 * and sel_end cursor */
1808 LyXParagraph * tmppar;
1810 /* Check whether there are half footnotes in the selection */
1811 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1812 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1813 tmppar = sel_start_cursor.par;
1814 while (tmppar != sel_end_cursor.par){
1815 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1816 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1819 tmppar = tmppar->Next();
1823 /* table stuff -- begin*/
1824 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1825 if ( sel_start_cursor.par != sel_end_cursor.par){
1826 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1829 sel_start_cursor.par->table->Reinit();
1831 /* table stuff -- end*/
1833 // make sure that the depth behind the selection are restored, too
1834 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1835 LyXParagraph * undoendpar = endpar;
1837 if (endpar && endpar->GetDepth()) {
1838 while (endpar && endpar->GetDepth()) {
1839 endpar = endpar->LastPhysicalPar()->Next();
1840 undoendpar = endpar;
1844 endpar = endpar->Next(); /* because of parindents etc. */
1847 SetUndo(Undo::DELETE,
1848 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1851 /* delete the simple_cut_buffer */
1852 DeleteSimpleCutBuffer();
1854 /* set the textclass */
1855 simple_cut_buffer_textclass = parameters->textclass;
1857 #ifdef WITH_WARNINGS
1858 #warning Asger: Make cut more intelligent here.
1861 White paper for "intelligent" cutting:
1863 Example: "This is our text."
1864 Using " our " as selection, cutting will give "This istext.".
1865 Using "our" as selection, cutting will give "This is text.".
1866 Using " our" as selection, cutting will give "This is text.".
1867 Using "our " as selection, cutting will give "This is text.".
1869 All those four selections will (however) paste identically:
1870 Pasting with the cursor right after the "is" will give the
1871 original text with all four selections.
1873 The rationale is to be intelligent such that words are copied,
1874 cut and pasted in a functional manner.
1876 This is not implemented yet.
1879 bool space_wrapped =
1880 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1881 if (sel_end_cursor.pos > 0
1882 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1883 sel_end_cursor.pos--; /* please break before a space at
1885 space_wrapped = true;
1888 // cut behind a space if there is one
1889 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1890 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1891 && (sel_start_cursor.par != sel_end_cursor.par
1892 || sel_start_cursor.pos < sel_end_cursor.pos))
1893 sel_start_cursor.pos++;
1895 /* there are two cases: cut only within one paragraph or
1896 * more than one paragraph */
1898 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1899 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1900 /* only within one paragraph */
1901 simple_cut_buffer = new LyXParagraph;
1903 simple_cut_buffer->text.reserve(500);
1904 LyXParagraph::size_type i =
1905 sel_start_cursor.pos;
1907 int i = sel_start_cursor.pos;
1909 for (; i< sel_end_cursor.pos; i++){
1910 /* table stuff -- begin*/
1911 if (sel_start_cursor.par->table
1912 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1913 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1914 sel_start_cursor.pos++;
1916 /* table stuff -- end*/
1917 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1918 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1920 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1922 /* check for double spaces */
1923 if (sel_start_cursor.pos &&
1924 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1925 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1926 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1927 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1930 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1931 endpar = sel_end_cursor.par->Next();
1934 /* cut more than one paragraph */
1936 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1937 /* insert a space at the end if there was one */
1939 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1941 sel_end_cursor.par = sel_end_cursor.par->Next();
1942 sel_end_cursor.pos = 0;
1944 cursor = sel_end_cursor;
1946 /* please break behind a space, if there is one. The space should
1948 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1949 sel_start_cursor.pos++;
1951 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1952 if (!sel_start_cursor.pos
1953 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1954 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1955 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1958 /* store the endparagraph for redoing later */
1959 endpar = sel_end_cursor.par->Next(); /* needed because
1964 /*store the selection */
1965 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1966 simple_cut_buffer->previous = 0;
1967 sel_end_cursor.par->previous->next = 0;
1969 /* cut the selection */
1970 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1971 = sel_end_cursor.par;
1973 sel_end_cursor.par->previous
1974 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1976 /* care about footnotes */
1977 if (simple_cut_buffer->footnoteflag) {
1978 LyXParagraph *tmppar = simple_cut_buffer;
1980 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1981 tmppar = tmppar->next;
1985 /* the cut selection should begin with standard layout */
1986 simple_cut_buffer->Clear();
1988 /* paste the paragraphs again, if possible */
1990 sel_start_cursor.par->Next()->ClearParagraph();
1991 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1993 !sel_start_cursor.par->Next()->Last())
1994 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1997 /* maybe a forgotten blank */
1998 if (sel_start_cursor.pos
1999 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2000 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
2001 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2006 /* sometimes necessary */
2008 sel_start_cursor.par->ClearParagraph();
2010 RedoParagraphs(sel_start_cursor, endpar);
2013 cursor = sel_start_cursor;
2014 SetCursor(cursor.par, cursor.pos);
2015 sel_cursor = cursor;
2016 UpdateCounters(cursor.row);
2020 void LyXText::CopySelection()
2023 LyXParagraph::size_type i = 0;
2027 /* this doesnt make sense, if there is no selection */
2032 /* ok we have a selection. This is always between sel_start_cursor
2033 * and sel_end cursor */
2034 LyXParagraph * tmppar;
2036 /* check wether there are half footnotes in the selection */
2037 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2038 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2039 tmppar = sel_start_cursor.par;
2040 while (tmppar != sel_end_cursor.par){
2041 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2042 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2045 tmppar = tmppar->Next();
2049 /* table stuff -- begin*/
2050 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2051 if ( sel_start_cursor.par != sel_end_cursor.par){
2052 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2056 /* table stuff -- end*/
2058 /* delete the simple_cut_buffer */
2059 DeleteSimpleCutBuffer();
2061 /* set the textclass */
2062 simple_cut_buffer_textclass = parameters->textclass;
2064 // copy behind a space if there is one
2065 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2066 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2067 && (sel_start_cursor.par != sel_end_cursor.par
2068 || sel_start_cursor.pos < sel_end_cursor.pos))
2069 sel_start_cursor.pos++;
2071 /* there are two cases: copy only within one paragraph or more than one paragraph */
2072 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2073 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2074 /* only within one paragraph */
2075 simple_cut_buffer = new LyXParagraph;
2077 simple_cut_buffer->text.reserve(500);
2079 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2080 sel_start_cursor.par->CopyIntoMinibuffer(i);
2081 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2085 /* copy more than one paragraph */
2086 /* clone the paragraphs within the selection*/
2087 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2088 simple_cut_buffer = tmppar->Clone();
2089 LyXParagraph *tmppar2 = simple_cut_buffer;
2091 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2093 tmppar = tmppar->next;
2094 tmppar2->next = tmppar->Clone();
2095 tmppar2->next->previous = tmppar2;
2096 tmppar2=tmppar2->next;
2100 /* care about footnotes */
2101 if (simple_cut_buffer->footnoteflag) {
2102 tmppar = simple_cut_buffer;
2104 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2105 tmppar = tmppar->next;
2109 /* the simple_cut_buffer paragraph is too big */
2111 LyXParagraph::size_type tmpi2 =
2112 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2115 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2117 for (;tmpi2;tmpi2--)
2118 simple_cut_buffer->Erase(0);
2120 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2122 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2124 while (tmppar2->size() > tmpi2) {
2125 tmppar2->Erase(tmppar2->text.size() - 1);
2128 while (tmppar2->last > tmpi2) {
2129 tmppar2->Erase(tmppar2->last-1);
2136 void LyXText::PasteSelection()
2138 /* this does not make sense, if there is nothing to paste */
2139 if (!simple_cut_buffer)
2142 LyXParagraph * tmppar;
2143 LyXParagraph * endpar;
2145 LyXCursor tmpcursor;
2147 /* be carefull with footnotes in footnotes */
2148 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2150 /* check whether the cut_buffer includes a footnote */
2151 tmppar = simple_cut_buffer;
2152 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2153 tmppar = tmppar->next;
2156 WriteAlert(_("Impossible operation"),
2157 _("Can't paste float into float!"), _("Sorry."));
2162 /* table stuff -- begin*/
2163 if (cursor.par->table){
2164 if (simple_cut_buffer->next){
2165 WriteAlert(_("Impossible operation"),
2166 _("Table cell cannot include more than one paragraph!"),
2171 /* table stuff -- end*/
2173 SetUndo(Undo::INSERT,
2174 cursor.par->ParFromPos(cursor.pos)->previous,
2175 cursor.par->ParFromPos(cursor.pos)->next);
2179 /* There are two cases: cutbuffer only one paragraph or many */
2180 if (!simple_cut_buffer->next) {
2181 /* only within a paragraph */
2183 /* please break behind a space, if there is one */
2184 while (tmpcursor.par->Last() > tmpcursor.pos
2185 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2188 tmppar = simple_cut_buffer->Clone();
2189 /* table stuff -- begin*/
2190 bool table_too_small = false;
2191 if (tmpcursor.par->table) {
2193 while (simple_cut_buffer->text.size()
2194 && !table_too_small) {
2196 while (simple_cut_buffer->last && !table_too_small){
2198 if (simple_cut_buffer->IsNewline(0)){
2199 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2201 simple_cut_buffer->Erase(0);
2202 if (tmpcursor.pos < tmpcursor.par->Last())
2205 table_too_small = true;
2207 simple_cut_buffer->CutIntoMinibuffer(0);
2208 simple_cut_buffer->Erase(0);
2209 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2214 /* table stuff -- end*/
2216 while (simple_cut_buffer->text.size()){
2218 while (simple_cut_buffer->last){
2220 simple_cut_buffer->CutIntoMinibuffer(0);
2221 simple_cut_buffer->Erase(0);
2222 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2227 delete simple_cut_buffer;
2228 simple_cut_buffer = tmppar;
2229 endpar = tmpcursor.par->Next();
2231 /* many paragraphs */
2233 /* make a copy of the simple cut_buffer */
2234 tmppar = simple_cut_buffer;
2235 LyXParagraph * simple_cut_clone = tmppar->Clone();
2236 LyXParagraph * tmppar2 = simple_cut_clone;
2237 if (cursor.par->footnoteflag){
2238 tmppar->footnoteflag = cursor.par->footnoteflag;
2239 tmppar->footnotekind = cursor.par->footnotekind;
2241 while (tmppar->next) {
2242 tmppar = tmppar->next;
2243 tmppar2->next = tmppar->Clone();
2244 tmppar2->next->previous = tmppar2;
2245 tmppar2=tmppar2->next;
2246 if (cursor.par->footnoteflag){
2247 tmppar->footnoteflag = cursor.par->footnoteflag;
2248 tmppar->footnotekind = cursor.par->footnotekind;
2252 /* make sure there is no class difference */
2253 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2254 parameters->textclass,
2257 /* make the simple_cut_buffer exactly the same layout than
2258 the cursor paragraph */
2259 simple_cut_buffer->MakeSameLayout(cursor.par);
2261 /* find the end of the buffer */
2262 LyXParagraph *lastbuffer = simple_cut_buffer;
2263 while (lastbuffer->Next())
2264 lastbuffer=lastbuffer->Next();
2266 /* find the physical end of the buffer */
2267 lastbuffer = simple_cut_buffer;
2268 while (lastbuffer->Next())
2269 lastbuffer=lastbuffer->Next();
2271 /* please break behind a space, if there is one. The space
2272 * should be copied too */
2273 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2276 bool paste_the_end = false;
2278 /* open the paragraph for inserting the simple_cut_buffer
2280 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2281 cursor.par->BreakParagraphConservative(cursor.pos);
2282 paste_the_end = true;
2285 /* be careful with double spaces */
2286 if ((!cursor.par->Last()
2287 || cursor.par->IsLineSeparator(cursor.pos - 1)
2288 || cursor.par->IsNewline(cursor.pos - 1))
2290 && simple_cut_buffer->text.size()
2292 && simple_cut_buffer->last
2294 && simple_cut_buffer->IsLineSeparator(0))
2295 simple_cut_buffer->Erase(0);
2297 /* set the end for redoing later */
2298 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2301 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2302 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2304 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2305 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2307 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2308 lastbuffer = cursor.par;
2310 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2312 /* store the new cursor position */
2313 tmpcursor.par = lastbuffer;
2314 tmpcursor.pos = lastbuffer->Last();
2316 /* maybe some pasting */
2317 if (lastbuffer->Next() && paste_the_end) {
2318 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2320 /* be careful witth double spaces */
2321 if ((!lastbuffer->Last()
2322 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2323 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2324 && lastbuffer->Next()->Last()
2325 && lastbuffer->Next()->IsLineSeparator(0))
2326 lastbuffer->Next()->Erase(0);
2328 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2331 else if (!lastbuffer->Next()->Last()) {
2332 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2334 /* be careful witth double spaces */
2335 if ((!lastbuffer->Last()
2336 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2337 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2338 && lastbuffer->Next()->Last()
2339 && lastbuffer->Next()->IsLineSeparator(0))
2340 lastbuffer->Next()->Erase(0);
2342 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2345 else if (!lastbuffer->Last()) {
2346 lastbuffer->MakeSameLayout(lastbuffer->next);
2348 /* be careful witth double spaces */
2349 if ((!lastbuffer->Last()
2350 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2351 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2352 && lastbuffer->Next()->Last()
2353 && lastbuffer->Next()->IsLineSeparator(0))
2354 lastbuffer->Next()->Erase(0);
2356 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2359 else lastbuffer->Next()->ClearParagraph();
2362 /* restore the simple cut buffer */
2363 simple_cut_buffer = simple_cut_clone;
2366 RedoParagraphs(cursor, endpar);
2368 SetCursor(cursor.par, cursor.pos);
2371 sel_cursor = cursor;
2372 SetCursor(tmpcursor.par, tmpcursor.pos);
2374 UpdateCounters(cursor.row);
2378 /* returns a pointer to the very first LyXParagraph */
2379 LyXParagraph * LyXText::FirstParagraph()
2381 return params->paragraph;
2385 /* returns true if the specified string is at the specified position */
2387 bool LyXText::IsStringInText(LyXParagraph * par,
2388 LyXParagraph::size_type pos,
2391 bool LyXText::IsStringInText(LyXParagraph * par, int pos, char const * str)
2396 while (pos + i < par->Last() && str[i] &&
2397 str[i] == par->GetChar(pos + i)) {
2407 /* sets the selection over the number of characters of string, no check!! */
2408 void LyXText::SetSelectionOverString(char const * string)
2410 sel_cursor = cursor;
2411 for (int i = 0; string[i]; ++i)
2417 /* simple replacing. The font of the first selected character is used */
2418 void LyXText::ReplaceSelectionWithString(char const * str)
2423 if (!selection) { /* create a dummy selection */
2424 sel_end_cursor = cursor;
2425 sel_start_cursor = cursor;
2428 // Get font setting before we cut
2430 LyXParagraph::size_type pos = sel_end_cursor.pos;
2432 int pos = sel_end_cursor.pos;
2434 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2436 // Insert the new string
2437 for (int i = 0; str[i]; ++i) {
2438 sel_end_cursor.par->InsertChar(pos, str[i]);
2439 sel_end_cursor.par->SetFont(pos, font);
2443 // Cut the selection
2450 /* if the string can be found: return true and set the cursor to
2451 * the new position */
2452 bool LyXText::SearchForward(char const * str)
2454 LyXParagraph * par = cursor.par;
2456 LyXParagraph::size_type pos = cursor.pos;
2458 int pos = cursor.pos;
2460 while (par && !IsStringInText(par, pos, str)) {
2461 if (pos < par->Last() - 1)
2477 bool LyXText::SearchBackward(char const * string)
2479 LyXParagraph * par = cursor.par;
2480 int pos = cursor.pos;
2486 // We skip empty paragraphs (Asger)
2488 par = par->Previous();
2490 pos = par->Last()-1;
2491 } while (par && pos<0);
2493 } while (par && !IsStringInText(par,pos,string));
2505 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2507 char * str = new char[text.size() + 1];
2508 copy(text.begin(), text.end(), str);
2509 str[text.size()] = '\0';
2515 /* needed to insert the selection */
2516 void LyXText::InsertStringA(char const * str)
2518 LyXParagraph * par = cursor.par;
2520 LyXParagraph::size_type pos = cursor.pos;
2521 LyXParagraph::size_type a = 0;
2523 int pos = cursor.pos;
2527 LyXParagraph * endpar = cursor.par->Next();
2531 char flag = textclasslist.Style(parameters->textclass,
2532 cursor.par->GetLayout()).isEnvironment();
2533 /* only to be sure, should not be neccessary */
2536 /* insert the string, don't insert doublespace */
2540 for (i2 = i; str[i2] && str[i2] != '\n'; ++i2);
2541 par->Enlarge(pos, i2 - i);
2545 if (str[i]==' ' && (str[i+1]!=' ')
2546 && pos && par->GetChar(pos-1)!=' ') {
2547 par->InsertChar(pos,' ');
2550 else if (par->table) {
2551 if (str[i] == '\t') {
2553 while((pos < par->size()) &&
2554 (par->GetChar(pos) != LYX_META_NEWLINE))
2556 if (pos < par->size())
2559 while((pos < par->last) &&
2560 (par->GetChar(pos) != LYX_META_NEWLINE))
2562 if (pos < par->last)
2565 else // no more fields to fill skip the rest
2567 } else if ((str[i] != 13) &&
2568 ((str[i] & 127) >= ' ')) {
2569 par->InsertChar(pos,str[i]);
2573 else if (str[i]==' ') {
2574 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2577 else if (str[i]=='\t') {
2578 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2579 par->InsertChar(a, LYX_META_PROTECTED_SEPARATOR);
2583 else if (str[i]!=13 &&
2584 // Ignore unprintables
2585 (str[i] & 127) >= ' ') {
2586 par->InsertChar(pos,str[i]);
2596 while((pos < par->size()) &&
2598 while((pos < par->last) &&
2600 (par->GetChar(pos) != LYX_META_NEWLINE))
2603 cell=NumberOfCell(par,pos);
2605 while((pos < par->size()) &&
2606 !(par->table->IsFirstCell(cell))) {
2607 while((pos < par->size()) &&
2608 (par->GetChar(pos) != LYX_META_NEWLINE))
2611 cell=NumberOfCell(par,pos);
2613 if (pos >= par->size())
2614 // no more fields to fill skip the rest
2617 while((pos < par->last) &&
2618 !(par->table->IsFirstCell(cell))) {
2619 while((pos < par->last) &&
2620 (par->GetChar(pos) != LYX_META_NEWLINE))
2623 cell=NumberOfCell(par,pos);
2625 if (pos >= par->last)
2626 // no more fields to fill skip the rest
2631 if (!par->text.size()) {
2635 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2638 par->BreakParagraph(pos, flag);
2643 for (i2 = i; str[i2] && str[i2] != '\n'; i2++);
2644 par->Enlarge(pos, i2 - i);
2651 RedoParagraphs(cursor,endpar);
2652 SetCursor(cursor.par, cursor.pos);
2653 sel_cursor = cursor;
2654 SetCursor(par, pos);
2660 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2662 char * str = new char[text.size() + 1];
2663 copy(text.begin(), text.end(), str);
2664 str[text.size()] = '\0';
2670 /* turns double-CR to single CR, others where converted into one blank and 13s
2671 * that are ignored .Double spaces are also converted into one. Spaces at
2672 * the beginning of a paragraph are forbidden. tabs are converted into one
2673 * space. then InsertStringA is called */
2674 void LyXText::InsertStringB(char const * s)
2677 LyXParagraph * par = cursor.par;
2680 if (str[i] == '\t' && !par->table)
2682 if (str[i] == ' ' && str[i + 1] == ' ')
2684 if (str[i] == '\n' && str[i + 1] && !par->table){
2685 if (str[i + 1] != '\n') {
2686 if (str[i - 1] != ' ')
2691 while (str[i + 1] && (str[i + 1] == ' '
2692 || str[i + 1] == '\t'
2693 || str[i + 1] == '\n'
2694 || str[i + 1] == 13)) {
2701 InsertStringA(str.c_str());
2705 bool LyXText::GotoNextError()
2707 LyXCursor res=cursor;
2709 if (res.pos < res.par->Last() - 1) {
2713 res.par=res.par->Next();
2718 !(res.par->GetChar(res.pos)==LYX_META_INSET
2719 && res.par->GetInset(res.pos)->AutoDelete()));
2722 SetCursor(res.par, res.pos);
2730 bool LyXText::GotoNextNote()
2732 LyXCursor res=cursor;
2734 if (res.pos < res.par->Last()-1) {
2738 res.par=res.par->Next();
2743 !(res.par->GetChar(res.pos)==LYX_META_INSET
2744 && res.par->GetInset(res.pos)->LyxCode()==Inset::IGNORE_CODE));
2747 SetCursor(res.par, res.pos);
2755 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2758 InsetError * new_inset = 0;
2760 if (!par || class1 == class2)
2762 par = par->FirstPhysicalPar();
2764 string name = textclasslist.NameOfLayout(class1, par->layout);
2766 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2767 textclasslist.NumberOfLayout(class2, name);
2770 } else { // layout not found
2771 // use default layout "Standard" (0)
2776 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2778 string s = "Layout had to be changed from\n"
2779 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2780 + "\nbecause of class conversion from\n"
2781 + textclasslist.NameOfClass(class1) + " to "
2782 + textclasslist.NameOfClass(class2);
2783 new_inset = new InsetError(s);
2784 par->InsertChar(0, LYX_META_INSET);
2785 par->InsertInset(0, new_inset);
2795 void LyXText::CheckParagraph(LyXParagraph * par,
2796 LyXParagraph::size_type pos)
2798 void LyXText::CheckParagraph(LyXParagraph * par, int pos)
2802 LyXCursor tmpcursor;
2804 /* table stuff -- begin*/
2807 CheckParagraphInTable(par, pos);
2810 /* table stuff -- end*/
2814 LyXParagraph::size_type z;
2818 Row * row = GetRow(par, pos, y);
2820 /* is there a break one row above */
2821 if (row->previous && row->previous->par == row->par) {
2822 z = NextBreakPoint(row->previous, paperwidth);
2823 if ( z >= row->pos) {
2824 /* set the dimensions of the row above */
2825 y -= row->previous->height;
2827 refresh_row = row->previous;
2828 status = LyXText::NEED_MORE_REFRESH;
2830 BreakAgain(row->previous);
2832 /* set the cursor again. Otherwise dungling pointers are possible */
2833 SetCursor(cursor.par, cursor.pos);
2834 sel_cursor = cursor;
2839 int tmpheight = row->height;
2841 LyXParagraph::size_type tmplast = RowLast(row);
2843 int tmplast = RowLast(row);
2849 if (row->height == tmpheight && RowLast(row) == tmplast)
2850 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2852 status = LyXText::NEED_MORE_REFRESH;
2854 /* check the special right address boxes */
2855 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2856 tmpcursor.par = par;
2857 tmpcursor.row = row;
2860 tmpcursor.x_fix = 0;
2861 tmpcursor.pos = pos;
2862 RedoDrawingOfParagraph(tmpcursor);
2867 /* set the cursor again. Otherwise dangling pointers are possible */
2868 // also set the selection
2872 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2873 sel_cursor = cursor;
2874 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2875 sel_start_cursor = cursor;
2876 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2877 sel_end_cursor = cursor;
2878 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2879 last_sel_cursor = cursor;
2882 SetCursorIntern(cursor.par, cursor.pos);
2886 /* returns 0 if inset wasn't found */
2887 int LyXText::UpdateInset(Inset * inset)
2889 /* first check the current paragraph */
2890 int pos = cursor.par->GetPositionOfInset(inset);
2892 CheckParagraph(cursor.par, pos);
2896 /* check every paragraph */
2898 LyXParagraph * par = FirstParagraph();
2900 /* make sure the paragraph is open */
2901 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2902 pos = par->GetPositionOfInset(inset);
2904 CheckParagraph(par, pos);
2916 void LyXText::SetCursor(LyXParagraph * par,
2917 LyXParagraph::size_type pos)
2919 void LyXText::SetCursor(LyXParagraph * par, int pos)
2922 LyXCursor old_cursor = cursor;
2923 SetCursorIntern(par, pos);
2924 DeleteEmptyParagraphMechanism(old_cursor);
2929 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2931 void LyXText::SetCursorIntern(LyXParagraph * par, int pos)
2937 LyXParagraph * tmppar;
2939 /* correct the cursor position if impossible */
2940 if (pos > par->Last()){
2941 tmppar = par->ParFromPos(pos);
2942 pos = par->PositionInParFromPos(pos);
2945 if (par->IsDummy() && par->previous &&
2946 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2947 while (par->previous &&
2948 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2949 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2950 par = par->previous ;
2951 if (par->IsDummy() &&
2952 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2954 pos += par->text.size() + 1;
2956 pos += par->last + 1;
2959 if (par->previous) {
2960 par = par->previous;
2963 pos += par->text.size() + 1;
2965 pos += par->last + 1;
2972 /* get the cursor y position in text */
2973 row = GetRow(par, pos, y);
2974 /* y is now the beginning of the cursor row */
2976 /* y is now the cursor baseline */
2979 /* now get the cursors x position */
2982 float fill_separator, fill_hfill, fill_label_hfill;
2983 left_margin = LabelEnd(row);
2984 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2986 LyXParagraph::size_type main_body =
2987 BeginningOfMainBody(row->par);
2989 int main_body = BeginningOfMainBody(row->par);
2991 /* table stuff -- begin*/
2992 if (row->par->table) {
2993 int cell = NumberOfCell(row->par, row->pos);
2995 x += row->par->table->GetBeginningOfTextInCell(cell);
2996 for (pos = row->pos; pos < cursor.pos; pos++) {
2997 if (row->par->IsNewline(pos)) {
2998 x = x_old + row->par->table->WidthOfColumn(cell);
3001 x += row->par->table->GetBeginningOfTextInCell(cell);
3003 x += SingleWidth(row->par, pos);
3007 /* table stuff -- end*/
3009 for (pos = row->pos; pos < cursor.pos; pos++) {
3010 if (pos && pos == main_body
3011 && !row->par->IsLineSeparator(pos - 1)) {
3012 x += GetFont(row->par, -2).stringWidth(
3013 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3014 if (x < left_margin)
3018 x += SingleWidth(row->par, pos);
3019 if (HfillExpansion(row, pos)) {
3020 if (pos >= main_body)
3023 x += fill_label_hfill;
3025 else if (pos >= main_body && row->par->IsSeparator(pos)) {
3029 if (pos + 1 == main_body
3030 && row->par->IsLineSeparator(pos)) {
3031 x += GetFont(row->par, -2).stringWidth(
3032 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3033 if (row->par->IsLineSeparator(pos))
3034 x-= SingleWidth(row->par, pos);
3035 if (x < left_margin)
3042 cursor.x_fix = cursor.x;
3046 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3047 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3048 && !cursor.par->IsSeparator(cursor.pos))
3050 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3051 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3053 current_font = cursor.par->GetFontSettings(cursor.pos);
3054 real_current_font = GetFont(cursor.par, cursor.pos);
3059 void LyXText::SetCursorFromCoordinates(int x, long y)
3061 LyXCursor old_cursor = cursor;
3063 /* get the row first */
3065 Row * row = GetRowNearY(y);
3067 cursor.par = row->par;
3069 int column = GetColumnNearX(row, x);
3070 cursor.pos = row->pos + column;
3072 cursor.y = y + row->baseline;
3077 (cursor.pos == cursor.par->Last()
3078 || cursor.par->IsSeparator(cursor.pos)
3079 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3080 && !cursor.par->IsSeparator(cursor.pos))
3082 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3083 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3085 current_font = cursor.par->GetFontSettings(cursor.pos);
3086 real_current_font = GetFont(cursor.par, cursor.pos);
3088 DeleteEmptyParagraphMechanism(old_cursor);
3092 void LyXText::CursorLeft()
3095 if (cursor.par->table) {
3096 int cell = NumberOfCell(cursor.par, cursor.pos);
3097 if (cursor.par->table->IsContRow(cell) &&
3098 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3105 void LyXText::CursorLeftIntern()
3107 if (cursor.pos > 0) {
3108 SetCursor(cursor.par, cursor.pos - 1);
3110 else if (cursor.par->Previous()) {
3111 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3116 void LyXText::CursorRight()
3118 CursorRightIntern();
3119 if (cursor.par->table) {
3120 int cell = NumberOfCell(cursor.par, cursor.pos);
3121 if (cursor.par->table->IsContRow(cell) &&
3122 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3129 void LyXText::CursorRightIntern()
3131 if (cursor.pos < cursor.par->Last()) {
3132 SetCursor(cursor.par, cursor.pos + 1);
3134 else if (cursor.par->Next()) {
3135 SetCursor(cursor.par->Next(), 0);
3140 void LyXText::CursorUp()
3142 SetCursorFromCoordinates(cursor.x_fix,
3143 cursor.y - cursor.row->baseline - 1);
3144 if (cursor.par->table) {
3145 int cell = NumberOfCell(cursor.par, cursor.pos);
3146 if (cursor.par->table->IsContRow(cell) &&
3147 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3154 void LyXText::CursorDown()
3156 if (cursor.par->table &&
3157 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3160 SetCursorFromCoordinates(cursor.x_fix,
3161 cursor.y - cursor.row->baseline
3162 + cursor.row->height + 1);
3163 if (cursor.par->table) {
3164 int cell = NumberOfCell(cursor.par, cursor.pos);
3165 int cell_above = cursor.par->table->GetCellAbove(cell);
3166 while(cursor.par->table &&
3167 cursor.par->table->IsContRow(cell) &&
3168 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3169 SetCursorFromCoordinates(cursor.x_fix,
3170 cursor.y - cursor.row->baseline
3171 + cursor.row->height + 1);
3172 if (cursor.par->table) {
3173 cell = NumberOfCell(cursor.par, cursor.pos);
3174 cell_above = cursor.par->table->GetCellAbove(cell);
3181 void LyXText::CursorUpParagraph()
3183 if (cursor.pos > 0) {
3184 SetCursor(cursor.par, 0);
3186 else if (cursor.par->Previous()) {
3187 SetCursor(cursor.par->Previous(), 0);
3192 void LyXText::CursorDownParagraph()
3194 if (cursor.par->Next()) {
3195 SetCursor(cursor.par->Next(), 0);
3197 SetCursor(cursor.par,cursor.par->Last());
3203 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3205 bool deleted = false;
3207 /* this is the delete-empty-paragraph-mechanism. */
3211 // Paragraph should not be deleted if empty
3212 if ((textclasslist.Style(parameters->textclass,
3213 old_cursor.par->GetLayout())).keepempty)
3216 LyXCursor tmpcursor;
3218 if (old_cursor.par != cursor.par) {
3219 if ( (old_cursor.par->Last() == 0
3220 || (old_cursor.par->Last() == 1
3221 && (old_cursor.par->IsLineSeparator(0))))
3222 && old_cursor.par->FirstPhysicalPar()
3223 == old_cursor.par->LastPhysicalPar()) {
3225 /* ok, we will delete anything */
3227 // make sure that you do not delete any environments
3228 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3229 !(old_cursor.row->previous
3230 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3231 && !(old_cursor.row->next
3232 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3234 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3235 ((old_cursor.row->previous
3236 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3238 (old_cursor.row->next
3239 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3241 status = LyXText::NEED_MORE_REFRESH;
3244 if (old_cursor.row->previous) {
3245 refresh_row = old_cursor.row->previous;
3246 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3248 cursor = old_cursor; // that undo can restore the right cursor position
3249 LyXParagraph *endpar = old_cursor.par->next;
3250 if (endpar && endpar->GetDepth()) {
3251 while (endpar && endpar->GetDepth()) {
3252 endpar = endpar->LastPhysicalPar()->Next();
3255 SetUndo(Undo::DELETE,
3256 old_cursor.par->previous,
3260 /* delete old row */
3261 RemoveRow(old_cursor.row);
3262 if (params->paragraph == old_cursor.par) {
3263 params->paragraph = params->paragraph->next;
3265 /* delete old par */
3266 delete old_cursor.par;
3268 /* Breakagain the next par. Needed
3269 * because of the parindent that
3270 * can occur or dissappear. The
3271 * next row can change its height,
3272 * if there is another layout before */
3273 if (refresh_row->next) {
3274 BreakAgain(refresh_row->next);
3275 UpdateCounters(refresh_row);
3277 SetHeightOfRow(refresh_row);
3280 refresh_row = old_cursor.row->next;
3281 refresh_y = old_cursor.y - old_cursor.row->baseline;
3284 cursor = old_cursor; // that undo can restore the right cursor position
3285 LyXParagraph *endpar = old_cursor.par->next;
3286 if (endpar && endpar->GetDepth()) {
3287 while (endpar && endpar->GetDepth()) {
3288 endpar = endpar->LastPhysicalPar()->Next();
3291 SetUndo(Undo::DELETE,
3292 old_cursor.par->previous,
3296 /* delete old row */
3297 RemoveRow(old_cursor.row);
3298 /* delete old par */
3299 if (params->paragraph == old_cursor.par) {
3300 params->paragraph = params->paragraph->next;
3302 delete old_cursor.par;
3304 /* Breakagain the next par. Needed because of
3305 * the parindent that can occur or dissappear.
3306 * The next row can change its height, if there
3307 * is another layout before */
3309 BreakAgain(refresh_row);
3310 UpdateCounters(refresh_row->previous);
3314 /* correct cursor y */
3315 SetCursor(cursor.par, cursor.pos);
3317 /* if (cursor.y > old_cursor.y)
3318 cursor.y -= old_cursor.row->height; */
3320 if (sel_cursor.par == old_cursor.par
3321 && sel_cursor.pos == sel_cursor.pos) {
3322 /* correct selection*/
3323 sel_cursor = cursor;
3329 if (old_cursor.par->ClearParagraph()){
3330 RedoParagraphs(old_cursor, old_cursor.par->Next());
3331 /* correct cursor y */
3332 SetCursor(cursor.par, cursor.pos);
3333 sel_cursor = cursor;
3336 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3337 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3338 if (old_cursor.par->table->IsContRow(cell) &&
3339 IsEmptyTableRow(&old_cursor)) {
3340 RemoveTableRow(&old_cursor);
3347 LyXParagraph * LyXText::GetParFromID(int id)
3349 LyXParagraph * result = FirstParagraph();
3350 while (result && result->GetID() != id)
3351 result = result->next;
3357 bool LyXText::TextUndo()
3358 { // returns false if no undo possible
3359 Undo * undo = params->undostack.Pop();
3363 params->redostack.Push(CreateUndo(undo->kind,
3364 GetParFromID(undo->number_of_before_par),
3365 GetParFromID(undo->number_of_behind_par)));
3367 return TextHandleUndo(undo);
3371 bool LyXText::TextRedo()
3372 { // returns false if no redo possible
3373 Undo * undo = params->redostack.Pop();
3377 params->undostack.Push(CreateUndo(undo->kind,
3378 GetParFromID(undo->number_of_before_par),
3379 GetParFromID(undo->number_of_behind_par)));
3381 return TextHandleUndo(undo);
3385 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3386 bool result = false;
3388 LyXParagraph * before = GetParFromID(undo->number_of_before_par);
3389 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par);
3390 LyXParagraph * tmppar;
3391 LyXParagraph * tmppar2;
3392 LyXParagraph * tmppar3;
3393 LyXParagraph * tmppar4;
3394 LyXParagraph * endpar;
3395 LyXParagraph * tmppar5;
3397 // if there's no before take the beginning of the document for redoing
3399 SetCursorIntern(FirstParagraph(), 0);
3401 // replace the paragraphs with the undo informations
3403 tmppar3 = undo->par;
3404 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3407 while (tmppar4->next)
3408 tmppar4 = tmppar4->next;
3409 } // get last undo par
3411 // now remove the old text if there is any
3412 if (before != behind || (!behind && !before)){
3414 tmppar5 = before->next;
3416 tmppar5 = params->paragraph;
3418 while (tmppar5 && tmppar5 != behind){
3420 tmppar5 = tmppar5->next;
3421 // a memory optimization for edit: Only layout information
3422 // is stored in the undo. So restore the text informations.
3423 if (undo->kind == Undo::EDIT){
3424 tmppar2->text = tmppar->text;
3426 //tmppar->text.clear();
3427 tmppar->text.erase(tmppar->text.begin(),
3428 tmppar->text.end());
3432 tmppar2 = tmppar2->next;
3434 if ( currentrow && currentrow->par == tmppar )
3435 currentrow = currentrow -> previous;
3440 // put the new stuff in the list if there is one
3443 before->next = tmppar3;
3445 params->paragraph = tmppar3;
3446 tmppar3->previous = before;
3450 params->paragraph = behind;
3453 tmppar4->next = behind;
3455 behind->previous = tmppar4;
3459 // Set the cursor for redoing
3461 SetCursorIntern(before->FirstSelfrowPar(), 0);
3462 // check wether before points to a closed float and open it if necessary
3463 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3464 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3466 while (tmppar4->previous &&
3467 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3468 tmppar4 = tmppar4->previous;
3469 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3470 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3471 tmppar4 = tmppar4->next;
3476 // open a cosed footnote at the end if necessary
3477 if (behind && behind->previous &&
3478 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3479 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3480 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3481 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3482 behind = behind->next;
3486 // calculate the endpar for redoing the paragraphs.
3488 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3489 endpar = behind->LastPhysicalPar()->Next();
3491 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3496 tmppar = GetParFromID(undo->number_of_cursor_par);
3497 RedoParagraphs(cursor, endpar);
3499 SetCursorIntern(tmppar, undo->cursor_pos);
3500 UpdateCounters(cursor.row);
3510 void LyXText::FinishUndo()
3511 { // makes sure the next operation will be stored
3512 undo_finished = True;
3516 void LyXText::FreezeUndo()
3517 { // this is dangerous and for internal use only
3522 void LyXText::UnFreezeUndo()
3523 { // this is dangerous and for internal use only
3524 undo_frozen = false;
3528 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3529 LyXParagraph * behind)
3532 params->undostack.Push(CreateUndo(kind, before, behind));
3533 params->redostack.Clear();
3537 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3538 LyXParagraph * behind)
3540 params->redostack.Push(CreateUndo(kind, before, behind));
3544 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3545 LyXParagraph * behind)
3547 int before_number = -1;
3548 int behind_number = -1;
3550 before_number = before->GetID();
3552 behind_number = behind->GetID();
3553 // Undo::EDIT and Undo::FINISH are
3554 // always finished. (no overlapping there)
3555 // overlapping only with insert and delete inside one paragraph:
3556 // Nobody wants all removed character
3557 // appear one by one when undoing.
3558 // EDIT is special since only layout information, not the
3559 // contents of a paragaph are stored.
3560 if (!undo_finished && kind != Undo::EDIT &&
3561 kind != Undo::FINISH){
3562 // check wether storing is needed
3563 if (params->undostack.Top() &&
3564 params->undostack.Top()->kind == kind &&
3565 params->undostack.Top()->number_of_before_par == before_number &&
3566 params->undostack.Top()->number_of_behind_par == behind_number ){
3571 // create a new Undo
3572 LyXParagraph * undopar;
3573 LyXParagraph * tmppar;
3574 LyXParagraph * tmppar2;
3576 LyXParagraph * start = 0;
3577 LyXParagraph * end = 0;
3580 start = before->next;
3582 start = FirstParagraph();
3584 end = behind->previous;
3586 end = FirstParagraph();
3591 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3593 tmppar2 = tmppar->Clone();
3594 tmppar2->SetID(tmppar->GetID());
3596 // a memory optimization: Just store the layout information when only edit
3597 if (kind == Undo::EDIT){
3599 //tmppar2->text.clear();
3600 tmppar2->text.erase(tmppar2->text.begin(),
3601 tmppar2->text.end());
3604 delete[] tmppar2->text;
3611 while (tmppar != end && tmppar->next) {
3612 tmppar = tmppar->next;
3613 tmppar2->next = tmppar->Clone();
3614 tmppar2->next->SetID(tmppar->GetID());
3615 // a memory optimization: Just store the layout information when only edit
3616 if (kind == Undo::EDIT){
3618 //tmppar2->next->text.clear();
3619 tmppar2->next->text.erase(tmppar2->next->text.begin(), tmppar2->next->text.end());
3621 if (tmppar2->next->text)
3622 delete[] tmppar2->next->text;
3623 tmppar2->next->text = 0;
3626 tmppar2->next->previous = tmppar2;
3627 tmppar2=tmppar2->next;
3632 undopar = 0; // nothing to replace (undo of delete maybe)
3634 int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3635 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3637 Undo * undo = new Undo(kind,
3638 before_number, behind_number,
3639 cursor_par, cursor_pos,
3642 undo_finished = false;
3647 void LyXText::SetCursorParUndo()
3649 SetUndo(Undo::FINISH,
3650 cursor.par->ParFromPos(cursor.pos)->previous,
3651 cursor.par->ParFromPos(cursor.pos)->next);
3654 void LyXText::RemoveTableRow(LyXCursor * cursor)
3662 /* move to the previous row */
3663 cell_act = NumberOfCell(cursor->par, cursor->pos);
3666 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3668 while (cursor->pos &&
3669 !cursor->par->table->IsFirstCell(cell_act)){
3671 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3676 /* now we have to pay attention if the actual table is the
3677 main row of TableContRows and if yes to delete all of them */
3682 /* delete up to the next row */
3683 while (cursor->pos < cursor->par->Last() &&
3685 || !cursor->par->table->IsFirstCell(cell_act))){
3686 while (cursor->pos < cursor->par->Last() &&
3687 !cursor->par->IsNewline(cursor->pos))
3688 cursor->par->Erase(cursor->pos);
3691 if (cursor->pos < cursor->par->Last())
3692 cursor->par-> Erase(cursor->pos);
3694 if (cursor->pos && cursor->pos == cursor->par->Last()){
3696 cursor->par->Erase(cursor->pos); // no newline at the very end!
3698 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3699 !cursor->par->table->IsContRow(cell_org) &&
3700 cursor->par->table->IsContRow(cell));
3701 cursor->par->table->DeleteRow(cell_org);
3706 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor)
3708 if (!old_cursor->par->table)
3710 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3712 pos = old_cursor->pos,
3713 cell = NumberOfCell(old_cursor->par, pos);
3715 // search first charater of this table row
3716 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3718 while (pos && !old_cursor->par->IsNewline(pos-1))
3722 if (!old_cursor->par->IsNewline(pos))
3726 while ((pos < old_cursor->par->Last()) &&
3727 !old_cursor->par->table->IsFirstCell(cell)) {
3728 if (!old_cursor->par->IsNewline(pos))
3739 bool LyXText::IsEmptyTableCell()
3742 LyXParagraph::size_type pos = cursor.pos - 1;
3744 int pos = cursor.pos - 1;
3746 while (pos >= 0 && pos < cursor.par->Last()
3747 && !cursor.par->IsNewline(pos))
3749 return cursor.par->IsNewline(pos + 1);
3752 void LyXText::toggleAppendix(){
3753 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3754 bool start = !par->start_of_appendix;
3756 /* ensure that we have only one start_of_appendix in this document */
3757 LyXParagraph * tmp = FirstParagraph();
3758 for (;tmp;tmp=tmp->next)
3759 tmp->start_of_appendix = 0;
3760 par->start_of_appendix = start;
3762 /* we can set the refreshing parameters now */
3763 status = LyXText::NEED_MORE_REFRESH;
3765 refresh_row = 0; // not needed for full update
3767 SetCursor(cursor.par, cursor.pos);