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 LyXParagraph::size_type i =
1904 sel_start_cursor.pos;
1906 int i = sel_start_cursor.pos;
1908 for (; i< sel_end_cursor.pos; i++){
1909 /* table stuff -- begin*/
1910 if (sel_start_cursor.par->table
1911 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1912 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1913 sel_start_cursor.pos++;
1915 /* table stuff -- end*/
1916 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1917 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1919 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1921 /* check for double spaces */
1922 if (sel_start_cursor.pos &&
1923 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1924 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1925 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1926 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1929 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1930 endpar = sel_end_cursor.par->Next();
1933 /* cut more than one paragraph */
1935 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1936 /* insert a space at the end if there was one */
1938 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1940 sel_end_cursor.par = sel_end_cursor.par->Next();
1941 sel_end_cursor.pos = 0;
1943 cursor = sel_end_cursor;
1945 /* please break behind a space, if there is one. The space should
1947 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1948 sel_start_cursor.pos++;
1950 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1951 if (!sel_start_cursor.pos
1952 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1953 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1954 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1957 /* store the endparagraph for redoing later */
1958 endpar = sel_end_cursor.par->Next(); /* needed because
1963 /*store the selection */
1964 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1965 simple_cut_buffer->previous = 0;
1966 sel_end_cursor.par->previous->next = 0;
1968 /* cut the selection */
1969 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1970 = sel_end_cursor.par;
1972 sel_end_cursor.par->previous
1973 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1975 /* care about footnotes */
1976 if (simple_cut_buffer->footnoteflag) {
1977 LyXParagraph *tmppar = simple_cut_buffer;
1979 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1980 tmppar = tmppar->next;
1984 /* the cut selection should begin with standard layout */
1985 simple_cut_buffer->Clear();
1987 /* paste the paragraphs again, if possible */
1989 sel_start_cursor.par->Next()->ClearParagraph();
1990 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1992 !sel_start_cursor.par->Next()->Last())
1993 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1996 /* maybe a forgotten blank */
1997 if (sel_start_cursor.pos
1998 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1999 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
2000 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2005 /* sometimes necessary */
2007 sel_start_cursor.par->ClearParagraph();
2009 RedoParagraphs(sel_start_cursor, endpar);
2012 cursor = sel_start_cursor;
2013 SetCursor(cursor.par, cursor.pos);
2014 sel_cursor = cursor;
2015 UpdateCounters(cursor.row);
2019 void LyXText::CopySelection()
2022 LyXParagraph::size_type i = 0;
2026 /* this doesnt make sense, if there is no selection */
2031 /* ok we have a selection. This is always between sel_start_cursor
2032 * and sel_end cursor */
2033 LyXParagraph * tmppar;
2035 /* check wether there are half footnotes in the selection */
2036 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2037 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2038 tmppar = sel_start_cursor.par;
2039 while (tmppar != sel_end_cursor.par){
2040 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2041 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2044 tmppar = tmppar->Next();
2048 /* table stuff -- begin*/
2049 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2050 if ( sel_start_cursor.par != sel_end_cursor.par){
2051 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2055 /* table stuff -- end*/
2057 /* delete the simple_cut_buffer */
2058 DeleteSimpleCutBuffer();
2060 /* set the textclass */
2061 simple_cut_buffer_textclass = parameters->textclass;
2063 // copy behind a space if there is one
2064 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2065 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2066 && (sel_start_cursor.par != sel_end_cursor.par
2067 || sel_start_cursor.pos < sel_end_cursor.pos))
2068 sel_start_cursor.pos++;
2070 /* there are two cases: copy only within one paragraph or more than one paragraph */
2071 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2072 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2073 /* only within one paragraph */
2074 simple_cut_buffer = new LyXParagraph;
2075 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2076 sel_start_cursor.par->CopyIntoMinibuffer(i);
2077 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2081 /* copy more than one paragraph */
2082 /* clone the paragraphs within the selection*/
2083 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2084 simple_cut_buffer = tmppar->Clone();
2085 LyXParagraph *tmppar2 = simple_cut_buffer;
2087 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2089 tmppar = tmppar->next;
2090 tmppar2->next = tmppar->Clone();
2091 tmppar2->next->previous = tmppar2;
2092 tmppar2=tmppar2->next;
2096 /* care about footnotes */
2097 if (simple_cut_buffer->footnoteflag) {
2098 tmppar = simple_cut_buffer;
2100 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2101 tmppar = tmppar->next;
2105 /* the simple_cut_buffer paragraph is too big */
2107 LyXParagraph::size_type tmpi2 =
2108 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2111 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2113 for (;tmpi2;tmpi2--)
2114 simple_cut_buffer->Erase(0);
2116 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2118 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2120 while (tmppar2->size() > tmpi2) {
2121 tmppar2->Erase(tmppar2->text.size() - 1);
2124 while (tmppar2->last > tmpi2) {
2125 tmppar2->Erase(tmppar2->last-1);
2132 void LyXText::PasteSelection()
2134 /* this does not make sense, if there is nothing to paste */
2135 if (!simple_cut_buffer)
2138 LyXParagraph * tmppar;
2139 LyXParagraph * endpar;
2141 LyXCursor tmpcursor;
2143 /* be carefull with footnotes in footnotes */
2144 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2146 /* check whether the cut_buffer includes a footnote */
2147 tmppar = simple_cut_buffer;
2148 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2149 tmppar = tmppar->next;
2152 WriteAlert(_("Impossible operation"),
2153 _("Can't paste float into float!"), _("Sorry."));
2158 /* table stuff -- begin*/
2159 if (cursor.par->table){
2160 if (simple_cut_buffer->next){
2161 WriteAlert(_("Impossible operation"),
2162 _("Table cell cannot include more than one paragraph!"),
2167 /* table stuff -- end*/
2169 SetUndo(Undo::INSERT,
2170 cursor.par->ParFromPos(cursor.pos)->previous,
2171 cursor.par->ParFromPos(cursor.pos)->next);
2175 /* There are two cases: cutbuffer only one paragraph or many */
2176 if (!simple_cut_buffer->next) {
2177 /* only within a paragraph */
2179 /* please break behind a space, if there is one */
2180 while (tmpcursor.par->Last() > tmpcursor.pos
2181 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2184 tmppar = simple_cut_buffer->Clone();
2185 /* table stuff -- begin*/
2186 bool table_too_small = false;
2187 if (tmpcursor.par->table) {
2189 while (simple_cut_buffer->text.size()
2190 && !table_too_small) {
2192 while (simple_cut_buffer->last && !table_too_small){
2194 if (simple_cut_buffer->IsNewline(0)){
2195 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2197 simple_cut_buffer->Erase(0);
2198 if (tmpcursor.pos < tmpcursor.par->Last())
2201 table_too_small = true;
2203 simple_cut_buffer->CutIntoMinibuffer(0);
2204 simple_cut_buffer->Erase(0);
2205 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2210 /* table stuff -- end*/
2212 while (simple_cut_buffer->text.size()){
2214 while (simple_cut_buffer->last){
2216 simple_cut_buffer->CutIntoMinibuffer(0);
2217 simple_cut_buffer->Erase(0);
2218 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2223 delete simple_cut_buffer;
2224 simple_cut_buffer = tmppar;
2225 endpar = tmpcursor.par->Next();
2227 /* many paragraphs */
2229 /* make a copy of the simple cut_buffer */
2230 tmppar = simple_cut_buffer;
2231 LyXParagraph * simple_cut_clone = tmppar->Clone();
2232 LyXParagraph * tmppar2 = simple_cut_clone;
2233 if (cursor.par->footnoteflag){
2234 tmppar->footnoteflag = cursor.par->footnoteflag;
2235 tmppar->footnotekind = cursor.par->footnotekind;
2237 while (tmppar->next) {
2238 tmppar = tmppar->next;
2239 tmppar2->next = tmppar->Clone();
2240 tmppar2->next->previous = tmppar2;
2241 tmppar2=tmppar2->next;
2242 if (cursor.par->footnoteflag){
2243 tmppar->footnoteflag = cursor.par->footnoteflag;
2244 tmppar->footnotekind = cursor.par->footnotekind;
2248 /* make sure there is no class difference */
2249 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2250 parameters->textclass,
2253 /* make the simple_cut_buffer exactly the same layout than
2254 the cursor paragraph */
2255 simple_cut_buffer->MakeSameLayout(cursor.par);
2257 /* find the end of the buffer */
2258 LyXParagraph *lastbuffer = simple_cut_buffer;
2259 while (lastbuffer->Next())
2260 lastbuffer=lastbuffer->Next();
2262 /* find the physical end of the buffer */
2263 lastbuffer = simple_cut_buffer;
2264 while (lastbuffer->Next())
2265 lastbuffer=lastbuffer->Next();
2267 /* please break behind a space, if there is one. The space
2268 * should be copied too */
2269 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2272 bool paste_the_end = false;
2274 /* open the paragraph for inserting the simple_cut_buffer
2276 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2277 cursor.par->BreakParagraphConservative(cursor.pos);
2278 paste_the_end = true;
2281 /* be careful with double spaces */
2282 if ((!cursor.par->Last()
2283 || cursor.par->IsLineSeparator(cursor.pos - 1)
2284 || cursor.par->IsNewline(cursor.pos - 1))
2286 && simple_cut_buffer->text.size()
2288 && simple_cut_buffer->last
2290 && simple_cut_buffer->IsLineSeparator(0))
2291 simple_cut_buffer->Erase(0);
2293 /* set the end for redoing later */
2294 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2297 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2298 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2300 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2301 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2303 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2304 lastbuffer = cursor.par;
2306 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2308 /* store the new cursor position */
2309 tmpcursor.par = lastbuffer;
2310 tmpcursor.pos = lastbuffer->Last();
2312 /* maybe some pasting */
2313 if (lastbuffer->Next() && paste_the_end) {
2314 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2316 /* be careful witth double spaces */
2317 if ((!lastbuffer->Last()
2318 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2319 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2320 && lastbuffer->Next()->Last()
2321 && lastbuffer->Next()->IsLineSeparator(0))
2322 lastbuffer->Next()->Erase(0);
2324 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2327 else if (!lastbuffer->Next()->Last()) {
2328 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2330 /* be careful witth double spaces */
2331 if ((!lastbuffer->Last()
2332 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2333 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2334 && lastbuffer->Next()->Last()
2335 && lastbuffer->Next()->IsLineSeparator(0))
2336 lastbuffer->Next()->Erase(0);
2338 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2341 else if (!lastbuffer->Last()) {
2342 lastbuffer->MakeSameLayout(lastbuffer->next);
2344 /* be careful witth double spaces */
2345 if ((!lastbuffer->Last()
2346 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2347 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2348 && lastbuffer->Next()->Last()
2349 && lastbuffer->Next()->IsLineSeparator(0))
2350 lastbuffer->Next()->Erase(0);
2352 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2355 else lastbuffer->Next()->ClearParagraph();
2358 /* restore the simple cut buffer */
2359 simple_cut_buffer = simple_cut_clone;
2362 RedoParagraphs(cursor, endpar);
2364 SetCursor(cursor.par, cursor.pos);
2367 sel_cursor = cursor;
2368 SetCursor(tmpcursor.par, tmpcursor.pos);
2370 UpdateCounters(cursor.row);
2374 /* returns a pointer to the very first LyXParagraph */
2375 LyXParagraph * LyXText::FirstParagraph()
2377 return params->paragraph;
2381 /* returns true if the specified string is at the specified position */
2383 bool LyXText::IsStringInText(LyXParagraph * par,
2384 LyXParagraph::size_type pos,
2387 bool LyXText::IsStringInText(LyXParagraph * par, int pos, char const * str)
2392 while (pos + i < par->Last() && str[i] &&
2393 str[i]==par->GetChar(pos+i)) {
2403 /* sets the selection over the number of characters of string, no check!! */
2404 void LyXText::SetSelectionOverString(char const * string)
2406 sel_cursor = cursor;
2407 for (int i = 0; string[i]; ++i)
2413 /* simple replacing. The font of the first selected character is used */
2414 void LyXText::ReplaceSelectionWithString(char const * str)
2419 if (!selection) { /* create a dummy selection */
2420 sel_end_cursor = cursor;
2421 sel_start_cursor = cursor;
2424 // Get font setting before we cut
2426 LyXParagraph::size_type pos = sel_end_cursor.pos;
2428 int pos = sel_end_cursor.pos;
2430 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2432 // Insert the new string
2433 for (int i = 0; str[i]; ++i) {
2434 sel_end_cursor.par->InsertChar(pos, str[i]);
2435 sel_end_cursor.par->SetFont(pos, font);
2439 // Cut the selection
2446 /* if the string can be found: return true and set the cursor to
2447 * the new position */
2448 bool LyXText::SearchForward(char const * str)
2450 LyXParagraph * par = cursor.par;
2452 LyXParagraph::size_type pos = cursor.pos;
2454 int pos = cursor.pos;
2456 while (par && !IsStringInText(par, pos, str)) {
2457 if (pos < par->Last() - 1)
2473 bool LyXText::SearchBackward(char const * string)
2475 LyXParagraph * par = cursor.par;
2476 int pos = cursor.pos;
2482 // We skip empty paragraphs (Asger)
2484 par = par->Previous();
2486 pos = par->Last()-1;
2487 } while (par && pos<0);
2489 } while (par && !IsStringInText(par,pos,string));
2501 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2503 char * str = new char[text.size() + 1];
2504 // shoudl use std::copy or something
2505 for (LyXParagraph::size_type i = 0; i < static_cast<int>(text.size());
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 // should use std::copy or something
2664 for(LyXParagraph::size_type i = 0; i < static_cast<int>(text.size());
2668 str[text.size()] = '\0';
2674 /* turns double-CR to single CR, others where converted into one blank and 13s
2675 * that are ignored .Double spaces are also converted into one. Spaces at
2676 * the beginning of a paragraph are forbidden. tabs are converted into one
2677 * space. then InsertStringA is called */
2678 void LyXText::InsertStringB(char const * s)
2681 LyXParagraph * par = cursor.par;
2684 if (str[i] == '\t' && !par->table)
2686 if (str[i] == ' ' && str[i + 1] == ' ')
2688 if (str[i] == '\n' && str[i + 1] && !par->table){
2689 if (str[i + 1] != '\n') {
2690 if (str[i - 1] != ' ')
2695 while (str[i + 1] && (str[i + 1] == ' '
2696 || str[i + 1] == '\t'
2697 || str[i + 1] == '\n'
2698 || str[i + 1] == 13)) {
2705 InsertStringA(str.c_str());
2709 bool LyXText::GotoNextError()
2711 LyXCursor res=cursor;
2713 if (res.pos < res.par->Last() - 1) {
2717 res.par=res.par->Next();
2722 !(res.par->GetChar(res.pos)==LYX_META_INSET
2723 && res.par->GetInset(res.pos)->AutoDelete()));
2726 SetCursor(res.par, res.pos);
2734 bool LyXText::GotoNextNote()
2736 LyXCursor res=cursor;
2738 if (res.pos < res.par->Last()-1) {
2742 res.par=res.par->Next();
2747 !(res.par->GetChar(res.pos)==LYX_META_INSET
2748 && res.par->GetInset(res.pos)->LyxCode()==Inset::IGNORE_CODE));
2751 SetCursor(res.par, res.pos);
2759 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2762 InsetError * new_inset = 0;
2764 if (!par || class1 == class2)
2766 par = par->FirstPhysicalPar();
2768 string name = textclasslist.NameOfLayout(class1, par->layout);
2770 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2771 textclasslist.NumberOfLayout(class2, name);
2774 } else { // layout not found
2775 // use default layout "Standard" (0)
2780 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2782 string s = "Layout had to be changed from\n"
2783 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2784 + "\nbecause of class conversion from\n"
2785 + textclasslist.NameOfClass(class1) + " to "
2786 + textclasslist.NameOfClass(class2);
2787 new_inset = new InsetError(s);
2788 par->InsertChar(0, LYX_META_INSET);
2789 par->InsertInset(0, new_inset);
2799 void LyXText::CheckParagraph(LyXParagraph * par,
2800 LyXParagraph::size_type pos)
2802 void LyXText::CheckParagraph(LyXParagraph * par, int pos)
2806 LyXCursor tmpcursor;
2808 /* table stuff -- begin*/
2811 CheckParagraphInTable(par, pos);
2814 /* table stuff -- end*/
2818 LyXParagraph::size_type z;
2822 Row * row = GetRow(par, pos, y);
2824 /* is there a break one row above */
2825 if (row->previous && row->previous->par == row->par) {
2826 z = NextBreakPoint(row->previous, paperwidth);
2827 if ( z >= row->pos) {
2828 /* set the dimensions of the row above */
2829 y -= row->previous->height;
2831 refresh_row = row->previous;
2832 status = LyXText::NEED_MORE_REFRESH;
2834 BreakAgain(row->previous);
2836 /* set the cursor again. Otherwise dungling pointers are possible */
2837 SetCursor(cursor.par, cursor.pos);
2838 sel_cursor = cursor;
2843 int tmpheight = row->height;
2845 LyXParagraph::size_type tmplast = RowLast(row);
2847 int tmplast = RowLast(row);
2853 if (row->height == tmpheight && RowLast(row) == tmplast)
2854 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2856 status = LyXText::NEED_MORE_REFRESH;
2858 /* check the special right address boxes */
2859 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2860 tmpcursor.par = par;
2861 tmpcursor.row = row;
2864 tmpcursor.x_fix = 0;
2865 tmpcursor.pos = pos;
2866 RedoDrawingOfParagraph(tmpcursor);
2871 /* set the cursor again. Otherwise dangling pointers are possible */
2872 // also set the selection
2876 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2877 sel_cursor = cursor;
2878 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2879 sel_start_cursor = cursor;
2880 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2881 sel_end_cursor = cursor;
2882 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2883 last_sel_cursor = cursor;
2886 SetCursorIntern(cursor.par, cursor.pos);
2890 /* returns 0 if inset wasn't found */
2891 int LyXText::UpdateInset(Inset * inset)
2893 /* first check the current paragraph */
2894 int pos = cursor.par->GetPositionOfInset(inset);
2896 CheckParagraph(cursor.par, pos);
2900 /* check every paragraph */
2902 LyXParagraph * par = FirstParagraph();
2904 /* make sure the paragraph is open */
2905 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2906 pos = par->GetPositionOfInset(inset);
2908 CheckParagraph(par, pos);
2920 void LyXText::SetCursor(LyXParagraph * par,
2921 LyXParagraph::size_type pos)
2923 void LyXText::SetCursor(LyXParagraph * par, int pos)
2926 LyXCursor old_cursor = cursor;
2927 SetCursorIntern(par, pos);
2928 DeleteEmptyParagraphMechanism(old_cursor);
2933 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2935 void LyXText::SetCursorIntern(LyXParagraph * par, int pos)
2941 LyXParagraph * tmppar;
2943 /* correct the cursor position if impossible */
2944 if (pos > par->Last()){
2945 tmppar = par->ParFromPos(pos);
2946 pos = par->PositionInParFromPos(pos);
2949 if (par->IsDummy() && par->previous &&
2950 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2951 while (par->previous &&
2952 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2953 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2954 par = par->previous ;
2955 if (par->IsDummy() &&
2956 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2958 pos += par->text.size() + 1;
2960 pos += par->last + 1;
2963 if (par->previous) {
2964 par = par->previous;
2967 pos += par->text.size() + 1;
2969 pos += par->last + 1;
2976 /* get the cursor y position in text */
2977 row = GetRow(par, pos, y);
2978 /* y is now the beginning of the cursor row */
2980 /* y is now the cursor baseline */
2983 /* now get the cursors x position */
2986 float fill_separator, fill_hfill, fill_label_hfill;
2987 left_margin = LabelEnd(row);
2988 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2990 LyXParagraph::size_type main_body =
2991 BeginningOfMainBody(row->par);
2993 int main_body = BeginningOfMainBody(row->par);
2995 /* table stuff -- begin*/
2996 if (row->par->table) {
2997 int cell = NumberOfCell(row->par, row->pos);
2999 x += row->par->table->GetBeginningOfTextInCell(cell);
3000 for (pos = row->pos; pos < cursor.pos; pos++) {
3001 if (row->par->IsNewline(pos)) {
3002 x = x_old + row->par->table->WidthOfColumn(cell);
3005 x += row->par->table->GetBeginningOfTextInCell(cell);
3007 x += SingleWidth(row->par, pos);
3011 /* table stuff -- end*/
3013 for (pos = row->pos; pos < cursor.pos; pos++) {
3014 if (pos && pos == main_body
3015 && !row->par->IsLineSeparator(pos - 1)) {
3016 x += GetFont(row->par, -2).stringWidth(
3017 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3018 if (x < left_margin)
3022 x += SingleWidth(row->par, pos);
3023 if (HfillExpansion(row, pos)) {
3024 if (pos >= main_body)
3027 x += fill_label_hfill;
3029 else if (pos >= main_body && row->par->IsSeparator(pos)) {
3033 if (pos + 1 == main_body
3034 && row->par->IsLineSeparator(pos)) {
3035 x += GetFont(row->par, -2).stringWidth(
3036 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3037 if (row->par->IsLineSeparator(pos))
3038 x-= SingleWidth(row->par, pos);
3039 if (x < left_margin)
3046 cursor.x_fix = cursor.x;
3050 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3051 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3052 && !cursor.par->IsSeparator(cursor.pos))
3054 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3055 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3057 current_font = cursor.par->GetFontSettings(cursor.pos);
3058 real_current_font = GetFont(cursor.par, cursor.pos);
3063 void LyXText::SetCursorFromCoordinates(int x, long y)
3065 LyXCursor old_cursor = cursor;
3067 /* get the row first */
3069 Row * row = GetRowNearY(y);
3071 cursor.par = row->par;
3073 int column = GetColumnNearX(row, x);
3074 cursor.pos = row->pos + column;
3076 cursor.y = y + row->baseline;
3081 (cursor.pos == cursor.par->Last()
3082 || cursor.par->IsSeparator(cursor.pos)
3083 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3084 && !cursor.par->IsSeparator(cursor.pos))
3086 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3087 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3089 current_font = cursor.par->GetFontSettings(cursor.pos);
3090 real_current_font = GetFont(cursor.par, cursor.pos);
3092 DeleteEmptyParagraphMechanism(old_cursor);
3096 void LyXText::CursorLeft()
3099 if (cursor.par->table) {
3100 int cell = NumberOfCell(cursor.par, cursor.pos);
3101 if (cursor.par->table->IsContRow(cell) &&
3102 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3109 void LyXText::CursorLeftIntern()
3111 if (cursor.pos > 0) {
3112 SetCursor(cursor.par, cursor.pos - 1);
3114 else if (cursor.par->Previous()) {
3115 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3120 void LyXText::CursorRight()
3122 CursorRightIntern();
3123 if (cursor.par->table) {
3124 int cell = NumberOfCell(cursor.par, cursor.pos);
3125 if (cursor.par->table->IsContRow(cell) &&
3126 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3133 void LyXText::CursorRightIntern()
3135 if (cursor.pos < cursor.par->Last()) {
3136 SetCursor(cursor.par, cursor.pos + 1);
3138 else if (cursor.par->Next()) {
3139 SetCursor(cursor.par->Next(), 0);
3144 void LyXText::CursorUp()
3146 SetCursorFromCoordinates(cursor.x_fix,
3147 cursor.y - cursor.row->baseline - 1);
3148 if (cursor.par->table) {
3149 int cell = NumberOfCell(cursor.par, cursor.pos);
3150 if (cursor.par->table->IsContRow(cell) &&
3151 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3158 void LyXText::CursorDown()
3160 if (cursor.par->table &&
3161 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3164 SetCursorFromCoordinates(cursor.x_fix,
3165 cursor.y - cursor.row->baseline
3166 + cursor.row->height + 1);
3167 if (cursor.par->table) {
3168 int cell = NumberOfCell(cursor.par, cursor.pos);
3169 int cell_above = cursor.par->table->GetCellAbove(cell);
3170 while(cursor.par->table &&
3171 cursor.par->table->IsContRow(cell) &&
3172 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3173 SetCursorFromCoordinates(cursor.x_fix,
3174 cursor.y - cursor.row->baseline
3175 + cursor.row->height + 1);
3176 if (cursor.par->table) {
3177 cell = NumberOfCell(cursor.par, cursor.pos);
3178 cell_above = cursor.par->table->GetCellAbove(cell);
3185 void LyXText::CursorUpParagraph()
3187 if (cursor.pos > 0) {
3188 SetCursor(cursor.par, 0);
3190 else if (cursor.par->Previous()) {
3191 SetCursor(cursor.par->Previous(), 0);
3196 void LyXText::CursorDownParagraph()
3198 if (cursor.par->Next()) {
3199 SetCursor(cursor.par->Next(), 0);
3201 SetCursor(cursor.par,cursor.par->Last());
3207 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3209 bool deleted = false;
3211 /* this is the delete-empty-paragraph-mechanism. */
3215 // Paragraph should not be deleted if empty
3216 if ((textclasslist.Style(parameters->textclass,
3217 old_cursor.par->GetLayout())).keepempty)
3220 LyXCursor tmpcursor;
3222 if (old_cursor.par != cursor.par) {
3223 if ( (old_cursor.par->Last() == 0
3224 || (old_cursor.par->Last() == 1
3225 && (old_cursor.par->IsLineSeparator(0))))
3226 && old_cursor.par->FirstPhysicalPar()
3227 == old_cursor.par->LastPhysicalPar()) {
3229 /* ok, we will delete anything */
3231 // make sure that you do not delete any environments
3232 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3233 !(old_cursor.row->previous
3234 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3235 && !(old_cursor.row->next
3236 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3238 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3239 ((old_cursor.row->previous
3240 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3242 (old_cursor.row->next
3243 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3245 status = LyXText::NEED_MORE_REFRESH;
3248 if (old_cursor.row->previous) {
3249 refresh_row = old_cursor.row->previous;
3250 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3252 cursor = old_cursor; // that undo can restore the right cursor position
3253 LyXParagraph *endpar = old_cursor.par->next;
3254 if (endpar && endpar->GetDepth()) {
3255 while (endpar && endpar->GetDepth()) {
3256 endpar = endpar->LastPhysicalPar()->Next();
3259 SetUndo(Undo::DELETE,
3260 old_cursor.par->previous,
3264 /* delete old row */
3265 RemoveRow(old_cursor.row);
3266 if (params->paragraph == old_cursor.par) {
3267 params->paragraph = params->paragraph->next;
3269 /* delete old par */
3270 delete old_cursor.par;
3272 /* Breakagain the next par. Needed
3273 * because of the parindent that
3274 * can occur or dissappear. The
3275 * next row can change its height,
3276 * if there is another layout before */
3277 if (refresh_row->next) {
3278 BreakAgain(refresh_row->next);
3279 UpdateCounters(refresh_row);
3281 SetHeightOfRow(refresh_row);
3284 refresh_row = old_cursor.row->next;
3285 refresh_y = old_cursor.y - old_cursor.row->baseline;
3288 cursor = old_cursor; // that undo can restore the right cursor position
3289 LyXParagraph *endpar = old_cursor.par->next;
3290 if (endpar && endpar->GetDepth()) {
3291 while (endpar && endpar->GetDepth()) {
3292 endpar = endpar->LastPhysicalPar()->Next();
3295 SetUndo(Undo::DELETE,
3296 old_cursor.par->previous,
3300 /* delete old row */
3301 RemoveRow(old_cursor.row);
3302 /* delete old par */
3303 if (params->paragraph == old_cursor.par) {
3304 params->paragraph = params->paragraph->next;
3306 delete old_cursor.par;
3308 /* Breakagain the next par. Needed because of
3309 * the parindent that can occur or dissappear.
3310 * The next row can change its height, if there
3311 * is another layout before */
3313 BreakAgain(refresh_row);
3314 UpdateCounters(refresh_row->previous);
3318 /* correct cursor y */
3319 SetCursor(cursor.par, cursor.pos);
3321 /* if (cursor.y > old_cursor.y)
3322 cursor.y -= old_cursor.row->height; */
3324 if (sel_cursor.par == old_cursor.par
3325 && sel_cursor.pos == sel_cursor.pos) {
3326 /* correct selection*/
3327 sel_cursor = cursor;
3333 if (old_cursor.par->ClearParagraph()){
3334 RedoParagraphs(old_cursor, old_cursor.par->Next());
3335 /* correct cursor y */
3336 SetCursor(cursor.par, cursor.pos);
3337 sel_cursor = cursor;
3340 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3341 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3342 if (old_cursor.par->table->IsContRow(cell) &&
3343 IsEmptyTableRow(&old_cursor)) {
3344 RemoveTableRow(&old_cursor);
3351 LyXParagraph * LyXText::GetParFromID(int id)
3353 LyXParagraph * result = FirstParagraph();
3354 while (result && result->GetID() != id)
3355 result = result->next;
3361 bool LyXText::TextUndo()
3362 { // returns false if no undo possible
3363 Undo * undo = params->undostack.Pop();
3367 params->redostack.Push(CreateUndo(undo->kind,
3368 GetParFromID(undo->number_of_before_par),
3369 GetParFromID(undo->number_of_behind_par)));
3371 return TextHandleUndo(undo);
3375 bool LyXText::TextRedo()
3376 { // returns false if no redo possible
3377 Undo * undo = params->redostack.Pop();
3381 params->undostack.Push(CreateUndo(undo->kind,
3382 GetParFromID(undo->number_of_before_par),
3383 GetParFromID(undo->number_of_behind_par)));
3385 return TextHandleUndo(undo);
3389 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3390 bool result = false;
3392 LyXParagraph * before = GetParFromID(undo->number_of_before_par);
3393 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par);
3394 LyXParagraph * tmppar;
3395 LyXParagraph * tmppar2;
3396 LyXParagraph * tmppar3;
3397 LyXParagraph * tmppar4;
3398 LyXParagraph * endpar;
3399 LyXParagraph * tmppar5;
3401 // if there's no before take the beginning of the document for redoing
3403 SetCursorIntern(FirstParagraph(), 0);
3405 // replace the paragraphs with the undo informations
3407 tmppar3 = undo->par;
3408 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3411 while (tmppar4->next)
3412 tmppar4 = tmppar4->next;
3413 } // get last undo par
3415 // now remove the old text if there is any
3416 if (before != behind || (!behind && !before)){
3418 tmppar5 = before->next;
3420 tmppar5 = params->paragraph;
3422 while (tmppar5 && tmppar5 != behind){
3424 tmppar5 = tmppar5->next;
3425 // a memory optimization for edit: Only layout information
3426 // is stored in the undo. So restore the text informations.
3427 if (undo->kind == Undo::EDIT){
3428 tmppar2->text = tmppar->text;
3430 tmppar->text.clear();
3434 tmppar2 = tmppar2->next;
3436 if ( currentrow && currentrow->par == tmppar )
3437 currentrow = currentrow -> previous;
3442 // put the new stuff in the list if there is one
3445 before->next = tmppar3;
3447 params->paragraph = tmppar3;
3448 tmppar3->previous = before;
3452 params->paragraph = behind;
3455 tmppar4->next = behind;
3457 behind->previous = tmppar4;
3461 // Set the cursor for redoing
3463 SetCursorIntern(before->FirstSelfrowPar(), 0);
3464 // check wether before points to a closed float and open it if necessary
3465 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3466 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3468 while (tmppar4->previous &&
3469 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3470 tmppar4 = tmppar4->previous;
3471 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3472 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3473 tmppar4 = tmppar4->next;
3478 // open a cosed footnote at the end if necessary
3479 if (behind && behind->previous &&
3480 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3481 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3482 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3483 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3484 behind = behind->next;
3488 // calculate the endpar for redoing the paragraphs.
3490 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3491 endpar = behind->LastPhysicalPar()->Next();
3493 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3498 tmppar = GetParFromID(undo->number_of_cursor_par);
3499 RedoParagraphs(cursor, endpar);
3501 SetCursorIntern(tmppar, undo->cursor_pos);
3502 UpdateCounters(cursor.row);
3512 void LyXText::FinishUndo()
3513 { // makes sure the next operation will be stored
3514 undo_finished = True;
3518 void LyXText::FreezeUndo()
3519 { // this is dangerous and for internal use only
3524 void LyXText::UnFreezeUndo()
3525 { // this is dangerous and for internal use only
3526 undo_frozen = false;
3530 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3531 LyXParagraph * behind)
3534 params->undostack.Push(CreateUndo(kind, before, behind));
3535 params->redostack.Clear();
3539 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3540 LyXParagraph * behind)
3542 params->redostack.Push(CreateUndo(kind, before, behind));
3546 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3547 LyXParagraph * behind)
3549 int before_number = -1;
3550 int behind_number = -1;
3552 before_number = before->GetID();
3554 behind_number = behind->GetID();
3555 // Undo::EDIT and Undo::FINISH are
3556 // always finished. (no overlapping there)
3557 // overlapping only with insert and delete inside one paragraph:
3558 // Nobody wants all removed character
3559 // appear one by one when undoing.
3560 // EDIT is special since only layout information, not the
3561 // contents of a paragaph are stored.
3562 if (!undo_finished && kind != Undo::EDIT &&
3563 kind != Undo::FINISH){
3564 // check wether storing is needed
3565 if (params->undostack.Top() &&
3566 params->undostack.Top()->kind == kind &&
3567 params->undostack.Top()->number_of_before_par == before_number &&
3568 params->undostack.Top()->number_of_behind_par == behind_number ){
3573 // create a new Undo
3574 LyXParagraph * undopar;
3575 LyXParagraph * tmppar;
3576 LyXParagraph * tmppar2;
3578 LyXParagraph * start = 0;
3579 LyXParagraph * end = 0;
3582 start = before->next;
3584 start = FirstParagraph();
3586 end = behind->previous;
3588 end = FirstParagraph();
3593 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3595 tmppar2 = tmppar->Clone();
3596 tmppar2->SetID(tmppar->GetID());
3598 // a memory optimization: Just store the layout information when only edit
3599 if (kind == Undo::EDIT){
3601 tmppar2->text.clear();
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();
3620 if (tmppar2->next->text)
3621 delete[] tmppar2->next->text;
3622 tmppar2->next->text = 0;
3625 tmppar2->next->previous = tmppar2;
3626 tmppar2=tmppar2->next;
3631 undopar = 0; // nothing to replace (undo of delete maybe)
3633 int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3634 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3636 Undo * undo = new Undo(kind,
3637 before_number, behind_number,
3638 cursor_par, cursor_pos,
3641 undo_finished = false;
3646 void LyXText::SetCursorParUndo()
3648 SetUndo(Undo::FINISH,
3649 cursor.par->ParFromPos(cursor.pos)->previous,
3650 cursor.par->ParFromPos(cursor.pos)->next);
3653 void LyXText::RemoveTableRow(LyXCursor * cursor)
3661 /* move to the previous row */
3662 cell_act = NumberOfCell(cursor->par, cursor->pos);
3665 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3667 while (cursor->pos &&
3668 !cursor->par->table->IsFirstCell(cell_act)){
3670 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3675 /* now we have to pay attention if the actual table is the
3676 main row of TableContRows and if yes to delete all of them */
3681 /* delete up to the next row */
3682 while (cursor->pos < cursor->par->Last() &&
3684 || !cursor->par->table->IsFirstCell(cell_act))){
3685 while (cursor->pos < cursor->par->Last() &&
3686 !cursor->par->IsNewline(cursor->pos))
3687 cursor->par->Erase(cursor->pos);
3690 if (cursor->pos < cursor->par->Last())
3691 cursor->par-> Erase(cursor->pos);
3693 if (cursor->pos && cursor->pos == cursor->par->Last()){
3695 cursor->par->Erase(cursor->pos); // no newline at the very end!
3697 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3698 !cursor->par->table->IsContRow(cell_org) &&
3699 cursor->par->table->IsContRow(cell));
3700 cursor->par->table->DeleteRow(cell_org);
3705 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor)
3707 if (!old_cursor->par->table)
3709 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3711 pos = old_cursor->pos,
3712 cell = NumberOfCell(old_cursor->par, pos);
3714 // search first charater of this table row
3715 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3717 while (pos && !old_cursor->par->IsNewline(pos-1))
3721 if (!old_cursor->par->IsNewline(pos))
3725 while ((pos < old_cursor->par->Last()) &&
3726 !old_cursor->par->table->IsFirstCell(cell)) {
3727 if (!old_cursor->par->IsNewline(pos))
3738 bool LyXText::IsEmptyTableCell()
3741 LyXParagraph::size_type pos = cursor.pos - 1;
3743 int pos = cursor.pos - 1;
3745 while (pos >= 0 && pos < cursor.par->Last()
3746 && !cursor.par->IsNewline(pos))
3748 return cursor.par->IsNewline(pos + 1);
3751 void LyXText::toggleAppendix(){
3752 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3753 bool start = !par->start_of_appendix;
3755 /* ensure that we have only one start_of_appendix in this document */
3756 LyXParagraph * tmp = FirstParagraph();
3757 for (;tmp;tmp=tmp->next)
3758 tmp->start_of_appendix = 0;
3759 par->start_of_appendix = start;
3761 /* we can set the refreshing parameters now */
3762 status = LyXText::NEED_MORE_REFRESH;
3764 refresh_row = 0; // not needed for full update
3766 SetCursor(cursor.par, cursor.pos);